summaryrefslogtreecommitdiff
path: root/drivers/infiniband/hw
ModeNameSize
-rw-r--r--Makefile755logplain
d---------bng_re481logplain
d---------bnxt_re761logplain
d---------cxgb4531logplain
d---------efa559logplain
d---------erdma496logplain
d---------hfi13355logplain
d---------hns1061logplain
d---------ionic615logplain
d---------irdma1516logplain
d---------mana488logplain
d---------mlx4514logplain
d---------mlx51589logplain
d---------mthca1128logplain
d---------ocrdma512logplain
d---------qedr416logplain
d---------usnic1150logplain
d---------vmw_pvrdma600logplain
BI/testing/sysfs-devices-sun2
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-cpu15
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-wiimote39
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-acpi10
-rw-r--r--Documentation/CodingStyle3
-rw-r--r--Documentation/DocBook/80211.tmpl13
-rw-r--r--Documentation/DocBook/device-drivers.tmpl6
-rw-r--r--Documentation/DocBook/drm.tmpl277
-rw-r--r--Documentation/DocBook/kernel-locking.tmpl7
-rw-r--r--Documentation/DocBook/media/dvb/frontend.xml2
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml2
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml2
-rw-r--r--Documentation/DocBook/writing_usb_driver.tmpl2
-rw-r--r--Documentation/accounting/getdelays.c4
-rw-r--r--Documentation/acpi/namespace.txt395
-rw-r--r--Documentation/acpi/video_extension.txt106
-rw-r--r--Documentation/arm/IXP4xx2
-rw-r--r--Documentation/arm64/memory.txt7
-rw-r--r--Documentation/bcache.txt10
-rw-r--r--Documentation/block/queue-sysfs.txt2
-rw-r--r--Documentation/cgroups/blkio-controller.txt29
-rw-r--r--Documentation/cgroups/memory.txt13
-rw-r--r--Documentation/clk.txt2
-rw-r--r--Documentation/coccinelle.txt63
-rw-r--r--Documentation/cpu-freq/cpu-drivers.txt10
-rw-r--r--Documentation/cpu-hotplug.txt6
-rw-r--r--Documentation/crypto/async-tx-api.txt1
-rw-r--r--Documentation/device-mapper/cache.txt2
-rw-r--r--Documentation/device-mapper/dm-raid.txt2
-rw-r--r--Documentation/device-mapper/switch.txt126
-rw-r--r--Documentation/devices.txt3
-rw-r--r--Documentation/devicetree/bindings/arm/l2cc.txt3
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/spear/shirq.txt2
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt5
-rw-r--r--Documentation/devicetree/bindings/clock/nspire-clock.txt24
-rw-r--r--Documentation/devicetree/bindings/clock/rockchip.txt74
-rw-r--r--Documentation/devicetree/bindings/clock/silabs,si5351.txt7
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi.txt117
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt93
-rw-r--r--Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt58
-rw-r--r--Documentation/devicetree/bindings/clock/vt8500.txt2
-rw-r--r--Documentation/devicetree/bindings/dma/atmel-dma.txt7
-rw-r--r--Documentation/devicetree/bindings/dma/fsl-imx-dma.txt48
-rw-r--r--Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt56
-rw-r--r--Documentation/devicetree/bindings/dma/shdma.txt75
-rw-r--r--Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt8
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-xilinx.txt48
-rw-r--r--Documentation/devicetree/bindings/hwmon/g762.txt47
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-designware.txt15
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt6
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-vt8500.txt24
-rw-r--r--Documentation/devicetree/bindings/i2c/ina2xx.txt22
-rw-r--r--Documentation/devicetree/bindings/input/pxa27x-keypad.txt60
-rw-r--r--Documentation/devicetree/bindings/input/samsung-keypad.txt24
-rw-r--r--Documentation/devicetree/bindings/input/ti,nspire-keypad.txt60
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt44
-rw-r--r--Documentation/devicetree/bindings/iommu/arm,smmu.txt70
-rw-r--r--Documentation/devicetree/bindings/leds/leds-lp55xx.txt147
-rw-r--r--Documentation/devicetree/bindings/metag/meta.txt30
-rw-r--r--Documentation/devicetree/bindings/mfd/arizona.txt62
-rw-r--r--Documentation/devicetree/bindings/mfd/max77693.txt55
-rw-r--r--Documentation/devicetree/bindings/mfd/max8998.txt119
-rw-r--r--Documentation/devicetree/bindings/mfd/palmas.txt49
-rw-r--r--Documentation/devicetree/bindings/mfd/twl4030-power.txt28
-rw-r--r--Documentation/devicetree/bindings/mmc/mmc.txt1
-rw-r--r--Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt23
-rw-r--r--Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt22
-rw-r--r--Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt22
-rw-r--r--Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt26
-rw-r--r--Documentation/devicetree/bindings/net/arc_emac.txt38
-rw-r--r--Documentation/devicetree/bindings/net/can/fsl-flexcan.txt2
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt6
-rw-r--r--Documentation/devicetree/bindings/net/davicom-dm9000.txt26
-rw-r--r--Documentation/devicetree/bindings/net/marvell-orion-net.txt85
-rw-r--r--Documentation/devicetree/bindings/net/micrel-ks8851.txt9
-rw-r--r--Documentation/devicetree/bindings/net/stmmac.txt10
-rw-r--r--Documentation/devicetree/bindings/net/via-velocity.txt20
-rw-r--r--Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt41
-rw-r--r--Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt127
-rw-r--r--Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt227
-rw-r--r--Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt49
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt48
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt3
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt110
-rw-r--r--Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt153
-rw-r--r--Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt97
-rw-r--r--Documentation/devicetree/bindings/pinctrl/ste,abx500.txt352
-rw-r--r--Documentation/devicetree/bindings/power_supply/lp8727_charger.txt44
-rw-r--r--Documentation/devicetree/bindings/powerpc/4xx/emac.txt2
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt309
-rw-r--r--Documentation/devicetree/bindings/pps/pps-gpio.txt20
-rw-r--r--Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt27
-rw-r--r--Documentation/devicetree/bindings/regulator/lp872x.txt160
-rw-r--r--Documentation/devicetree/bindings/regulator/max8973-regulator.txt21
-rw-r--r--Documentation/devicetree/bindings/regulator/max8997-regulator.txt2
-rw-r--r--Documentation/devicetree/bindings/regulator/palmas-pmic.txt72
-rw-r--r--Documentation/devicetree/bindings/regulator/regulator.txt1
-rw-r--r--Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt14
-rw-r--r--Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt128
-rw-r--r--Documentation/devicetree/bindings/regulator/twl-regulator.txt26
-rw-r--r--Documentation/devicetree/bindings/serio/olpc,ap-sp.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/adi,adau1701.txt35
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt46
-rw-r--r--Documentation/devicetree/bindings/sound/mxs-saif.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt71
-rw-r--r--Documentation/devicetree/bindings/sound/rt5640.txt30
-rw-r--r--Documentation/devicetree/bindings/sound/sgtl5000.txt3
-rw-r--r--Documentation/devicetree/bindings/sound/spdif-receiver.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/spdif-transmitter.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/ssm2518.txt20
-rw-r--r--Documentation/devicetree/bindings/sound/ti,tas5086.txt11
-rw-r--r--Documentation/devicetree/bindings/sound/wm8962.txt23
-rw-r--r--Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt2
-rw-r--r--Documentation/devicetree/bindings/spi/omap-spi.txt27
-rw-r--r--Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt (renamed from drivers/staging/ti-soc-thermal/ti_soc_thermal.txt)21
-rw-r--r--Documentation/devicetree/bindings/timer/lsi,zevio-timer.txt33
-rw-r--r--Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt2
-rw-r--r--Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt16
-rw-r--r--Documentation/devicetree/bindings/usb/am33xx-usb.txt2
-rw-r--r--Documentation/devicetree/bindings/usb/omap-usb.txt2
-rw-r--r--Documentation/devicetree/bindings/usb/twlxxxx-usb.txt2
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt2
-rw-r--r--Documentation/devicetree/bindings/video/display-timing.txt1
-rw-r--r--Documentation/devicetree/bindings/video/exynos_hdmi.txt13
-rw-r--r--Documentation/devicetree/bindings/video/exynos_hdmiddc.txt7
-rw-r--r--Documentation/devicetree/bindings/video/exynos_hdmiphy.txt7
-rw-r--r--Documentation/devicetree/bindings/video/exynos_mixer.txt9
-rw-r--r--Documentation/devicetree/bindings/video/fsl,imx-fb.txt51
-rw-r--r--Documentation/devicetree/bindings/video/ssd1307fb.txt10
-rw-r--r--Documentation/devicetree/usage-model.txt11
-rw-r--r--Documentation/dynamic-debug-howto.txt2
-rw-r--r--Documentation/early-userspace/README2
-rw-r--r--Documentation/fb/cirrusfb.txt2
-rw-r--r--Documentation/fb/uvesafb.txt16
-rw-r--r--Documentation/filesystems/Locking35
-rw-r--r--Documentation/filesystems/jfs.txt2
-rw-r--r--Documentation/filesystems/proc.txt7
-rw-r--r--Documentation/filesystems/qnx6.txt2
-rw-r--r--Documentation/filesystems/vfat.txt2
-rw-r--r--Documentation/filesystems/vfs.txt49
-rw-r--r--Documentation/hwmon/ds1621144
-rw-r--r--Documentation/hwmon/g76265
-rw-r--r--Documentation/hwmon/ina2xx4
-rw-r--r--Documentation/i2c/busses/i2c-i8011
-rw-r--r--Documentation/i2c/busses/i2c-piix42
-rw-r--r--Documentation/input/multi-touch-protocol.txt2
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--Documentation/kbuild/kconfig.txt13
-rw-r--r--Documentation/kdump/kdump.txt39
-rw-r--r--Documentation/kernel-doc-nano-HOWTO.txt11
-rw-r--r--Documentation/kernel-parameters.txt65
-rw-r--r--Documentation/kernel-per-CPU-kthreads.txt2
-rw-r--r--Documentation/laptops/dslm.c2
-rw-r--r--Documentation/md.txt13
-rw-r--r--Documentation/media-framework.txt2
-rw-r--r--Documentation/metag/kernel-ABI.txt2
-rw-r--r--Documentation/misc-devices/mei/mei.txt2
-rw-r--r--Documentation/networking/.gitignore1
-rw-r--r--Documentation/networking/00-INDEX2
-rw-r--r--Documentation/networking/Makefile5
-rw-r--r--Documentation/networking/arcnet.txt7
-rw-r--r--Documentation/networking/bonding.txt79
-rw-r--r--Documentation/networking/ieee802154.txt2
-rw-r--r--Documentation/networking/ifenslave.c1105
-rw-r--r--Documentation/networking/ip-sysctl.txt13
-rw-r--r--Documentation/networking/ipvs-sysctl.txt13
-rw-r--r--Documentation/networking/netlink_mmap.txt18
-rw-r--r--Documentation/networking/packet_mmap.txt133
-rw-r--r--Documentation/networking/scaling.txt58
-rw-r--r--Documentation/networking/vortex.txt2
-rw-r--r--Documentation/parisc/registers8
-rw-r--r--Documentation/pinctrl.txt41
-rw-r--r--Documentation/power/pm_qos_interface.txt50
-rw-r--r--Documentation/power/runtime_pm.txt20
-rw-r--r--Documentation/power/video_extension.txt37
-rw-r--r--Documentation/powerpc/00-INDEX2
-rw-r--r--Documentation/powerpc/pmu-ebb.txt137
-rw-r--r--Documentation/printk-formats.txt32
-rw-r--r--Documentation/pwm.txt37
-rw-r--r--Documentation/rapidio/rapidio.txt98
-rw-r--r--Documentation/rapidio/sysfs.txt1
-rw-r--r--Documentation/rtc.txt7
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas22
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt40
-rw-r--r--Documentation/sysctl/net.txt49
-rw-r--r--Documentation/sysctl/vm.txt2
-rw-r--r--Documentation/thermal/exynos_thermal_emulation2
-rw-r--r--Documentation/thermal/x86_pkg_temperature_thermal47
-rw-r--r--Documentation/trace/events-power.txt31
-rw-r--r--Documentation/trace/events.txt15
-rw-r--r--Documentation/trace/ftrace.txt13
-rw-r--r--Documentation/vfio.txt69
-rw-r--r--Documentation/video4linux/si476x.txt2
-rw-r--r--Documentation/video4linux/soc-camera.txt2
-rw-r--r--Documentation/virtual/kvm/api.txt74
-rw-r--r--Documentation/virtual/kvm/mmu.txt91
-rw-r--r--Documentation/vm/pagemap.txt5
-rw-r--r--Documentation/vm/soft-dirty.txt36
-rw-r--r--Documentation/vm/transhuge.txt4
-rw-r--r--Documentation/vm/zswap.txt68
-rw-r--r--Documentation/w1/slaves/w1_ds28e042
-rw-r--r--Documentation/x86/boot.txt7
-rw-r--r--MAINTAINERS150
-rw-r--r--Makefile8
-rw-r--r--arch/Kconfig3
-rw-r--r--arch/alpha/include/asm/mmzone.h2
-rw-r--r--arch/alpha/include/uapi/asm/fcntl.h1
-rw-r--r--arch/alpha/include/uapi/asm/socket.h2
-rw-r--r--arch/alpha/kernel/sys_nautilus.c4
-rw-r--r--arch/alpha/mm/init.c41
-rw-r--r--arch/alpha/mm/numa.c40
-rw-r--r--arch/arc/Kconfig9
-rw-r--r--arch/arc/Kconfig.debug7
-rw-r--r--arch/arc/Makefile28
-rw-r--r--arch/arc/boot/dts/abilis_tb100.dtsi32
-rw-r--r--arch/arc/boot/dts/abilis_tb100_dvk.dts10
-rw-r--r--arch/arc/boot/dts/abilis_tb101.dtsi32
-rw-r--r--arch/arc/boot/dts/abilis_tb101_dvk.dts10
-rw-r--r--arch/arc/boot/dts/abilis_tb10x.dtsi32
-rw-r--r--arch/arc/boot/dts/angel4.dts16
-rw-r--r--arch/arc/configs/fpga_defconfig5
-rw-r--r--arch/arc/configs/nsimosci_defconfig2
-rw-r--r--arch/arc/configs/tb10x_defconfig2
-rw-r--r--arch/arc/include/asm/arcregs.h127
-rw-r--r--arch/arc/include/asm/bug.h5
-rw-r--r--arch/arc/include/asm/cache.h26
-rw-r--r--arch/arc/include/asm/cacheflush.h13
-rw-r--r--arch/arc/include/asm/defines.h56
-rw-r--r--arch/arc/include/asm/entry.h521
-rw-r--r--arch/arc/include/asm/irq.h2
-rw-r--r--arch/arc/include/asm/irqflags.h20
-rw-r--r--arch/arc/include/asm/kgdb.h4
-rw-r--r--arch/arc/include/asm/kprobes.h6
-rw-r--r--arch/arc/include/asm/mmu.h44
-rw-r--r--arch/arc/include/asm/page.h7
-rw-r--r--arch/arc/include/asm/pgtable.h6
-rw-r--r--arch/arc/include/asm/processor.h17
-rw-r--r--arch/arc/include/asm/ptrace.h47
-rw-r--r--arch/arc/include/asm/syscall.h5
-rw-r--r--arch/arc/include/asm/tlb-mmu1.h4
-rw-r--r--arch/arc/include/asm/tlb.h26
-rw-r--r--arch/arc/include/asm/unaligned.h4
-rw-r--r--arch/arc/include/uapi/asm/ptrace.h15
-rw-r--r--arch/arc/kernel/asm-offsets.c7
-rw-r--r--arch/arc/kernel/ctx_sw.c14
-rw-r--r--arch/arc/kernel/entry.S103
-rw-r--r--arch/arc/kernel/head.S2
-rw-r--r--arch/arc/kernel/irq.c16
-rw-r--r--arch/arc/kernel/kgdb.c4
-rw-r--r--arch/arc/kernel/kprobes.c5
-rw-r--r--arch/arc/kernel/process.c9
-rw-r--r--arch/arc/kernel/ptrace.c14
-rw-r--r--arch/arc/kernel/setup.c18
-rw-r--r--arch/arc/kernel/smp.c4
-rw-r--r--arch/arc/kernel/stacktrace.c2
-rw-r--r--arch/arc/kernel/time.c17
-rw-r--r--arch/arc/kernel/traps.c52
-rw-r--r--arch/arc/kernel/troubleshoot.c33
-rw-r--r--arch/arc/kernel/unaligned.c2
-rw-r--r--arch/arc/kernel/unwind.c2
-rw-r--r--arch/arc/kernel/vmlinux.lds.S24
-rw-r--r--arch/arc/mm/cache_arc700.c126
-rw-r--r--arch/arc/mm/fault.c18
-rw-r--r--arch/arc/mm/init.c42
-rw-r--r--arch/arc/mm/tlb.c38
-rw-r--r--arch/arc/mm/tlbex.S35
-rw-r--r--arch/arc/plat-arcfpga/include/plat/irq.h2
-rw-r--r--arch/arc/plat-arcfpga/include/plat/memmap.h2
-rw-r--r--arch/arc/plat-arcfpga/platform.c12
-rw-r--r--arch/arc/plat-tb10x/Kconfig1
-rw-r--r--arch/arm/Kconfig17
-rw-r--r--arch/arm/Kconfig-nommu12
-rw-r--r--arch/arm/Kconfig.debug10
-rw-r--r--arch/arm/Makefile61
-rw-r--r--arch/arm/boot/compressed/.gitignore1
-rw-r--r--arch/arm/boot/compressed/Makefile5
-rw-r--r--arch/arm/boot/compressed/atags_to_fdt.c44
-rw-r--r--arch/arm/boot/compressed/decompress.c4
-rw-r--r--arch/arm/boot/compressed/head.S40
-rw-r--r--arch/arm/boot/compressed/piggy.lz4.S6
-rw-r--r--arch/arm/boot/dts/am335x-bone.dts2
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts16
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts10
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi17
-rw-r--r--arch/arm/boot/dts/atlas6.dtsi2
-rw-r--r--arch/arm/boot/dts/bcm11351.dtsi8
-rw-r--r--arch/arm/boot/dts/cros5250-common.dtsi4
-rw-r--r--arch/arm/boot/dts/ecx-common.dtsi2
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts4
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi4
-rw-r--r--arch/arm/boot/dts/imx28-evk.dts12
-rw-r--r--arch/arm/boot/dts/imx28.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000.dts29
-rw-r--r--arch/arm/boot/dts/prima2.dtsi2
-rw-r--r--arch/arm/boot/dts/sun4i-a10-cubieboard.dts15
-rw-r--r--arch/arm/boot/dts/sun4i-a10-hackberry.dts41
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi27
-rw-r--r--arch/arm/common/mcpm_head.S4
-rw-r--r--arch/arm/common/mcpm_platsmp.c5
-rw-r--r--arch/arm/common/timer-sp.c2
-rw-r--r--arch/arm/configs/bcm_defconfig7
-rw-r--r--arch/arm/configs/omap2plus_defconfig1
-rw-r--r--arch/arm/include/asm/arch_timer.h9
-rw-r--r--arch/arm/include/asm/cp15.h5
-rw-r--r--arch/arm/include/asm/cputype.h1
-rw-r--r--arch/arm/include/asm/div64.h2
-rw-r--r--arch/arm/include/asm/glue-proc.h8
-rw-r--r--arch/arm/include/asm/hardware/iop3xx.h3
-rw-r--r--arch/arm/include/asm/hugetlb-3level.h71
-rw-r--r--arch/arm/include/asm/hugetlb.h84
-rw-r--r--arch/arm/include/asm/io.h8
-rw-r--r--arch/arm/include/asm/kvm_arm.h1
-rw-r--r--arch/arm/include/asm/kvm_asm.h24
-rw-r--r--arch/arm/include/asm/kvm_emulate.h5
-rw-r--r--arch/arm/include/asm/kvm_host.h13
-rw-r--r--arch/arm/include/asm/mach/arch.h5
-rw-r--r--arch/arm/include/asm/memory.h24
-rw-r--r--arch/arm/include/asm/mmu_context.h23
-rw-r--r--arch/arm/include/asm/mpu.h76
-rw-r--r--arch/arm/include/asm/page.h2
-rw-r--r--arch/arm/include/asm/pgtable-3level-hwdef.h24
-rw-r--r--arch/arm/include/asm/pgtable-3level.h96
-rw-r--r--arch/arm/include/asm/pgtable.h3
-rw-r--r--arch/arm/include/asm/proc-fns.h30
-rw-r--r--arch/arm/include/asm/sched_clock.h18
-rw-r--r--arch/arm/include/asm/smp.h5
-rw-r--r--arch/arm/include/asm/smp_plat.h22
-rw-r--r--arch/arm/include/asm/spinlock.h25
-rw-r--r--arch/arm/include/asm/suspend.h5
-rw-r--r--arch/arm/include/asm/system_misc.h3
-rw-r--r--arch/arm/include/asm/thread_info.h2
-rw-r--r--arch/arm/include/asm/tlb.h6
-rw-r--r--arch/arm/include/asm/tlbflush.h27
-rw-r--r--arch/arm/include/asm/tls.h40
-rw-r--r--arch/arm/include/asm/xen/hypercall.h1
-rw-r--r--arch/arm/include/asm/xen/page.h3
-rw-r--r--arch/arm/include/debug/vexpress.S10
-rw-r--r--arch/arm/include/uapi/asm/hwcap.h2
-rw-r--r--arch/arm/kernel/Makefile7
-rw-r--r--arch/arm/kernel/arch_timer.c2
-rw-r--r--arch/arm/kernel/asm-offsets.c6
-rw-r--r--arch/arm/kernel/entry-armv.S5
-rw-r--r--arch/arm/kernel/entry-common.S42
-rw-r--r--arch/arm/kernel/head-nommu.S160
-rw-r--r--arch/arm/kernel/head.S10
-rw-r--r--arch/arm/kernel/hyp-stub.S7
-rw-r--r--arch/arm/kernel/perf_event.c1
-rw-r--r--arch/arm/kernel/process.c19
-rw-r--r--arch/arm/kernel/psci_smp.c4
-rw-r--r--arch/arm/kernel/ptrace.c10
-rw-r--r--arch/arm/kernel/setup.c88
-rw-r--r--arch/arm/kernel/signal.c9
-rw-r--r--arch/arm/kernel/sleep.S97
-rw-r--r--arch/arm/kernel/smp.c21
-rw-r--r--arch/arm/kernel/smp_tlb.c18
-rw-r--r--arch/arm/kernel/suspend.c76
-rw-r--r--arch/arm/kernel/time.c4
-rw-r--r--arch/arm/kernel/traps.c4
-rw-r--r--arch/arm/kvm/Kconfig8
-rw-r--r--arch/arm/kvm/Makefile7
-rw-r--r--arch/arm/kvm/arm.c8
-rw-r--r--arch/arm/kvm/coproc.c4
-rw-r--r--arch/arm/kvm/handle_exit.c3
-rw-r--r--arch/arm/kvm/interrupts.S16
-rw-r--r--arch/arm/kvm/interrupts_head.S14
-rw-r--r--arch/arm/kvm/mmio.c6
-rw-r--r--arch/arm/kvm/mmu.c3
-rw-r--r--arch/arm/kvm/psci.c2
-rw-r--r--arch/arm/kvm/reset.c12
-rw-r--r--arch/arm/mach-at91/at91rm9200.c3
-rw-r--r--arch/arm/mach-at91/generic.h5
-rw-r--r--arch/arm/mach-bcm2835/bcm2835.c4
-rw-r--r--arch/arm/mach-clps711x/common.c2
-rw-r--r--arch/arm/mach-clps711x/common.h4
-rw-r--r--arch/arm/mach-cns3xxx/core.h4
-rw-r--r--arch/arm/mach-cns3xxx/pm.c2
-rw-r--r--arch/arm/mach-davinci/Kconfig1
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c1
-rw-r--r--arch/arm/mach-davinci/da850.c8
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c3
-rw-r--r--arch/arm/mach-davinci/devices.c3
-rw-r--r--arch/arm/mach-davinci/include/mach/common.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/tnetv107x.h3
-rw-r--r--arch/arm/mach-davinci/time.c2
-rw-r--r--arch/arm/mach-davinci/tnetv107x.c3
-rw-r--r--arch/arm/mach-dove/common.c2
-rw-r--r--arch/arm/mach-dove/common.h4
-rw-r--r--arch/arm/mach-ebsa110/core.c5
-rw-r--r--arch/arm/mach-ep93xx/core.c3
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h4
-rw-r--r--arch/arm/mach-exynos/Kconfig2
-rw-r--r--arch/arm/mach-exynos/common.c4
-rw-r--r--arch/arm/mach-exynos/common.h5
-rw-r--r--arch/arm/mach-footbridge/cats-hw.c2
-rw-r--r--arch/arm/mach-footbridge/common.c4
-rw-r--r--arch/arm/mach-footbridge/common.h3
-rw-r--r--arch/arm/mach-footbridge/netwinder-hw.c4
-rw-r--r--arch/arm/mach-highbank/core.h4
-rw-r--r--arch/arm/mach-highbank/system.c5
-rw-r--r--arch/arm/mach-imx/Kconfig4
-rw-r--r--arch/arm/mach-imx/common.h4
-rw-r--r--arch/arm/mach-imx/devices-imx25.h8
-rw-r--r--arch/arm/mach-imx/devices-imx35.h8
-rw-r--r--arch/arm/mach-imx/devices/Kconfig1
-rw-r--r--arch/arm/mach-imx/devices/devices-common.h4
-rw-r--r--arch/arm/mach-imx/devices/platform-flexcan.c5
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c2
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c2
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c3
-rw-r--r--arch/arm/mach-imx/mach-mx25_3ds.c2
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c9
-rw-r--r--arch/arm/mach-imx/mach-pcm043.c2
-rw-r--r--arch/arm/mach-imx/mm-imx3.c2
-rw-r--r--arch/arm/mach-imx/system.c2
-rw-r--r--arch/arm/mach-imx/time.c2
-rw-r--r--arch/arm/mach-integrator/common.h3
-rw-r--r--arch/arm/mach-integrator/core.c2
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c2
-rw-r--r--arch/arm/mach-iop13xx/include/mach/iop13xx.h5
-rw-r--r--arch/arm/mach-iop13xx/io.c2
-rw-r--r--arch/arm/mach-iop13xx/setup.c5
-rw-r--r--arch/arm/mach-iop32x/n2100.c2
-rw-r--r--arch/arm/mach-ixp4xx/common.c8
-rw-r--r--arch/arm/mach-ixp4xx/dsmg600-setup.c1
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/platform.h4
-rw-r--r--arch/arm/mach-kirkwood/common.c3
-rw-r--r--arch/arm/mach-kirkwood/common.h4
-rw-r--r--arch/arm/mach-ks8695/generic.h2
-rw-r--r--arch/arm/mach-ks8695/time.c4
-rw-r--r--arch/arm/mach-lpc32xx/common.c6
-rw-r--r--arch/arm/mach-lpc32xx/common.h3
-rw-r--r--arch/arm/mach-lpc32xx/phy3250.c4
-rw-r--r--arch/arm/mach-mmp/aspenite.c10
-rw-r--r--arch/arm/mach-mmp/common.c2
-rw-r--r--arch/arm/mach-mmp/common.h3
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa168.h4
-rw-r--r--arch/arm/mach-mmp/pxa168.c2
-rw-r--r--arch/arm/mach-mmp/teton_bga.c8
-rw-r--r--arch/arm/mach-mmp/time.c2
-rw-r--r--arch/arm/mach-msm/common.h2
-rw-r--r--arch/arm/mach-msm/io.c2
-rw-r--r--arch/arm/mach-msm/timer.c2
-rw-r--r--arch/arm/mach-mv78xx0/common.c2
-rw-r--r--arch/arm/mach-mv78xx0/common.h4
-rw-r--r--arch/arm/mach-mvebu/common.h4
-rw-r--r--arch/arm/mach-mvebu/system-controller.c3
-rw-r--r--arch/arm/mach-mxs/Kconfig1
-rw-r--r--arch/arm/mach-mxs/mach-mxs.c53
-rw-r--r--arch/arm/mach-netx/generic.c3
-rw-r--r--arch/arm/mach-netx/generic.h4
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c2
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c3
-rw-r--r--arch/arm/mach-omap1/common.h3
-rw-r--r--arch/arm/mach-omap1/reset.c3
-rw-r--r--arch/arm/mach-omap1/time.c2
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/am33xx-restart.c3
-rw-r--r--arch/arm/mach-omap2/common.h17
-rw-r--r--arch/arm/mach-omap2/omap2-restart.c2
-rw-r--r--arch/arm/mach-omap2/omap3-restart.c3
-rw-r--r--arch/arm/mach-omap2/omap4-common.c1
-rw-r--r--arch/arm/mach-omap2/omap4-restart.c3
-rw-r--r--arch/arm/mach-omap2/omap_device.c7
-rw-r--r--arch/arm/mach-omap2/smartreflex-class3.c8
-rw-r--r--arch/arm/mach-omap2/timer.c2
-rw-r--r--arch/arm/mach-orion5x/common.c2
-rw-r--r--arch/arm/mach-orion5x/common.h4
-rw-r--r--arch/arm/mach-orion5x/ls-chl-setup.c2
-rw-r--r--arch/arm/mach-orion5x/ls_hgl-setup.c2
-rw-r--r--arch/arm/mach-orion5x/lsmini-setup.c2
-rw-r--r--arch/arm/mach-picoxcell/common.c3
-rw-r--r--arch/arm/mach-prima2/common.h4
-rw-r--r--arch/arm/mach-prima2/rstc.c3
-rw-r--r--arch/arm/mach-pxa/Kconfig3
-rw-r--r--arch/arm/mach-pxa/corgi.c6
-rw-r--r--arch/arm/mach-pxa/em-x270.c20
-rw-r--r--arch/arm/mach-pxa/ezx.c60
-rw-r--r--arch/arm/mach-pxa/generic.h4
-rw-r--r--arch/arm/mach-pxa/littleton.c10
-rw-r--r--arch/arm/mach-pxa/mainstone.c10
-rw-r--r--arch/arm/mach-pxa/mioa701.c19
-rw-r--r--arch/arm/mach-pxa/palmld.c10
-rw-r--r--arch/arm/mach-pxa/palmt5.c10
-rw-r--r--arch/arm/mach-pxa/palmtreo.c23
-rw-r--r--arch/arm/mach-pxa/palmtx.c10
-rw-r--r--arch/arm/mach-pxa/palmz72.c10
-rw-r--r--arch/arm/mach-pxa/poodle.c2
-rw-r--r--arch/arm/mach-pxa/reset.c8
-rw-r--r--arch/arm/mach-pxa/spitz.c8
-rw-r--r--arch/arm/mach-pxa/tavorevb.c10
-rw-r--r--arch/arm/mach-pxa/time.c2
-rw-r--r--arch/arm/mach-pxa/tosa.c6
-rw-r--r--arch/arm/mach-pxa/z2.c10
-rw-r--r--arch/arm/mach-pxa/zylonite.c10
-rw-r--r--arch/arm/mach-realview/realview_eb.c3
-rw-r--r--arch/arm/mach-realview/realview_pb1176.c3
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c3
-rw-r--r--arch/arm/mach-realview/realview_pba8.c3
-rw-r--r--arch/arm/mach-realview/realview_pbx.c3
-rw-r--r--arch/arm/mach-rpc/riscpc.c3
-rw-r--r--arch/arm/mach-s3c24xx/common.h12
-rw-r--r--arch/arm/mach-s3c24xx/cpufreq-utils.c2
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2410.c54
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c54
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c110
-rw-r--r--arch/arm/mach-s3c24xx/s3c2410.c5
-rw-r--r--arch/arm/mach-s3c24xx/s3c2412.c5
-rw-r--r--arch/arm/mach-s3c24xx/s3c2416.c5
-rw-r--r--arch/arm/mach-s3c24xx/s3c2443.c5
-rw-r--r--arch/arm/mach-s3c24xx/s3c244x.c5
-rw-r--r--arch/arm/mach-s3c64xx/common.c5
-rw-r--r--arch/arm/mach-s3c64xx/common.h4
-rw-r--r--arch/arm/mach-s5p64x0/common.c5
-rw-r--r--arch/arm/mach-s5p64x0/common.h4
-rw-r--r--arch/arm/mach-s5pc100/common.c5
-rw-r--r--arch/arm/mach-s5pc100/common.h4
-rw-r--r--arch/arm/mach-s5pv210/common.c2
-rw-r--r--arch/arm/mach-s5pv210/common.h4
-rw-r--r--arch/arm/mach-s5pv210/mach-aquila.c8
-rw-r--r--arch/arm/mach-s5pv210/mach-goni.c8
-rw-r--r--arch/arm/mach-sa1100/generic.c5
-rw-r--r--arch/arm/mach-sa1100/generic.h3
-rw-r--r--arch/arm/mach-sa1100/time.c2
-rw-r--r--arch/arm/mach-shark/core.c3
-rw-r--r--arch/arm/mach-shmobile/Kconfig4
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c5
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c3
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7740.c2
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7778.c2
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7779.c2
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c6
-rw-r--r--arch/arm/mach-socfpga/socfpga.c5
-rw-r--r--arch/arm/mach-spear/generic.h4
-rw-r--r--arch/arm/mach-spear/restart.c5
-rw-r--r--arch/arm/mach-spear/spear3xx.c4
-rw-r--r--arch/arm/mach-spear/spear6xx.c4
-rw-r--r--arch/arm/mach-sunxi/sunxi.c3
-rw-r--r--arch/arm/mach-tegra/Kconfig5
-rw-r--r--arch/arm/mach-tegra/board.h3
-rw-r--r--arch/arm/mach-tegra/common.c7
-rw-r--r--arch/arm/mach-u300/core.c6
-rw-r--r--arch/arm/mach-u300/timer.c2
-rw-r--r--arch/arm/mach-ux500/cpu.c6
-rw-r--r--arch/arm/mach-versatile/core.c3
-rw-r--r--arch/arm/mach-versatile/core.h3
-rw-r--r--arch/arm/mach-virt/Kconfig2
-rw-r--r--arch/arm/mach-vt8500/vt8500.c3
-rw-r--r--arch/arm/mach-w90x900/cpu.c4
-rw-r--r--arch/arm/mach-w90x900/nuc9xx.h5
-rw-r--r--arch/arm/mm/Kconfig3
-rw-r--r--arch/arm/mm/Makefile1
-rw-r--r--arch/arm/mm/cache-l2x0.c158
-rw-r--r--arch/arm/mm/context.c64
-rw-r--r--arch/arm/mm/dma-mapping.c62
-rw-r--r--arch/arm/mm/fault.c2
-rw-r--r--arch/arm/mm/flush.c27
-rw-r--r--arch/arm/mm/fsr-3level.c4
-rw-r--r--arch/arm/mm/hugetlbpage.c101
-rw-r--r--arch/arm/mm/init.c77
-rw-r--r--arch/arm/mm/ioremap.c10
-rw-r--r--arch/arm/mm/mmap.c2
-rw-r--r--arch/arm/mm/mmu.c49
-rw-r--r--arch/arm/mm/nommu.c263
-rw-r--r--arch/arm/mm/proc-v6.S6
-rw-r--r--arch/arm/mm/proc-v7-3level.S53
-rw-r--r--arch/arm/mm/proc-v7.S27
-rw-r--r--arch/arm/net/bpf_jit_32.c18
-rw-r--r--arch/arm/plat-iop/adma.c2
-rw-r--r--arch/arm/plat-iop/gpio.c1
-rw-r--r--arch/arm/plat-iop/restart.c2
-rw-r--r--arch/arm/plat-iop/time.c2
-rw-r--r--arch/arm/plat-omap/counter_32k.c2
-rw-r--r--arch/arm/plat-orion/common.c10
-rw-r--r--arch/arm/plat-orion/time.c2
-rw-r--r--arch/arm/plat-samsung/include/plat/cpu-freq-core.h2
-rw-r--r--arch/arm/plat-samsung/samsung-time.c2
-rw-r--r--arch/arm/plat-versatile/headsmp.S2
-rw-r--r--arch/arm/plat-versatile/sched-clock.c2
-rw-r--r--arch/arm/xen/enlighten.c1
-rw-r--r--arch/arm/xen/hypercall.S1
-rw-r--r--arch/arm64/Kconfig37
-rw-r--r--arch/arm64/Makefile6
-rw-r--r--arch/arm64/boot/dts/Makefile1
-rw-r--r--arch/arm64/boot/dts/apm-mustang.dts26
-rw-r--r--arch/arm64/boot/dts/apm-storm.dtsi116
-rw-r--r--arch/arm64/configs/defconfig4
-rw-r--r--arch/arm64/include/asm/arch_timer.h10
-rw-r--r--arch/arm64/include/asm/cacheflush.h3
-rw-r--r--arch/arm64/include/asm/cputype.h3
-rw-r--r--arch/arm64/include/asm/debug-monitors.h9
-rw-r--r--arch/arm64/include/asm/device.h3
-rw-r--r--arch/arm64/include/asm/dma-mapping.h17
-rw-r--r--arch/arm64/include/asm/hugetlb.h117
-rw-r--r--arch/arm64/include/asm/hypervisor.h6
-rw-r--r--arch/arm64/include/asm/io.h2
-rw-r--r--arch/arm64/include/asm/kvm_arm.h245
-rw-r--r--arch/arm64/include/asm/kvm_asm.h104
-rw-r--r--arch/arm64/include/asm/kvm_coproc.h56
-rw-r--r--arch/arm64/include/asm/kvm_emulate.h180
-rw-r--r--arch/arm64/include/asm/kvm_host.h202
-rw-r--r--arch/arm64/include/asm/kvm_mmio.h59
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h135
-rw-r--r--arch/arm64/include/asm/kvm_psci.h23
-rw-r--r--arch/arm64/include/asm/memory.h6
-rw-r--r--arch/arm64/include/asm/mmu_context.h6
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h30
-rw-r--r--arch/arm64/include/asm/pgtable.h112
-rw-r--r--arch/arm64/include/asm/ptrace.h2
-rw-r--r--arch/arm64/include/asm/spinlock.h3
-rw-r--r--arch/arm64/include/asm/sync_bitops.h26
-rw-r--r--arch/arm64/include/asm/timex.h6
-rw-r--r--arch/arm64/include/asm/tlb.h6
-rw-r--r--arch/arm64/include/asm/tlbflush.h2
-rw-r--r--arch/arm64/include/asm/xen/events.h21
-rw-r--r--arch/arm64/include/asm/xen/hypercall.h1
-rw-r--r--arch/arm64/include/asm/xen/hypervisor.h1
-rw-r--r--arch/arm64/include/asm/xen/interface.h1
-rw-r--r--arch/arm64/include/asm/xen/page.h1
-rw-r--r--arch/arm64/include/uapi/asm/kvm.h168
-rw-r--r--arch/arm64/kernel/asm-offsets.c34
-rw-r--r--arch/arm64/kernel/debug-monitors.c66
-rw-r--r--arch/arm64/kernel/ptrace.c59
-rw-r--r--arch/arm64/kernel/time.c6
-rw-r--r--arch/arm64/kernel/traps.c5
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S30
-rw-r--r--arch/arm64/kvm/Kconfig51
-rw-r--r--arch/arm64/kvm/Makefile23
-rw-r--r--arch/arm64/kvm/emulate.c158
-rw-r--r--arch/arm64/kvm/guest.c265
-rw-r--r--arch/arm64/kvm/handle_exit.c124
-rw-r--r--arch/arm64/kvm/hyp-init.S107
-rw-r--r--arch/arm64/kvm/hyp.S831
-rw-r--r--arch/arm64/kvm/inject_fault.c203
-rw-r--r--arch/arm64/kvm/regmap.c168
-rw-r--r--arch/arm64/kvm/reset.c112
-rw-r--r--arch/arm64/kvm/sys_regs.c1050
-rw-r--r--arch/arm64/kvm/sys_regs.h138
-rw-r--r--arch/arm64/kvm/sys_regs_generic_v8.c95
-rw-r--r--arch/arm64/mm/Makefile1
-rw-r--r--arch/arm64/mm/fault.c19
-rw-r--r--arch/arm64/mm/flush.c37
-rw-r--r--arch/arm64/mm/hugetlbpage.c70
-rw-r--r--arch/arm64/mm/init.c65
-rw-r--r--arch/arm64/mm/mm.h1
-rw-r--r--arch/arm64/mm/mmap.c2
-rw-r--r--arch/arm64/mm/mmu.c20
-rw-r--r--arch/arm64/xen/Makefile2
-rw-r--r--arch/arm64/xen/hypercall.S93
-rw-r--r--arch/avr32/include/uapi/asm/socket.h2
-rw-r--r--arch/avr32/kernel/setup.c2
-rw-r--r--arch/avr32/kernel/vmlinux.lds.S4
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c2
-rw-r--r--arch/avr32/mm/init.c52
-rw-r--r--arch/blackfin/Kconfig3
-rw-r--r--arch/blackfin/Kconfig.debug7
-rw-r--r--arch/blackfin/include/asm/bfin_spi3.h (renamed from arch/blackfin/include/asm/bfin6xx_spi.h)4
-rw-r--r--arch/blackfin/kernel/kgdb.c1
-rw-r--r--arch/blackfin/mach-bf527/boards/ad7160eval.c12
-rw-r--r--arch/blackfin/mach-bf527/boards/ezkit.c32
-rw-r--r--arch/blackfin/mach-bf533/boards/ezkit.c12
-rw-r--r--arch/blackfin/mach-bf533/boards/stamp.c35
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c30
-rw-r--r--arch/blackfin/mach-bf548/boards/ezkit.c28
-rw-r--r--arch/blackfin/mach-bf561/boards/ezkit.c14
-rw-r--r--arch/blackfin/mach-bf561/smp.c7
-rw-r--r--arch/blackfin/mach-bf609/boards/ezkit.c21
-rw-r--r--arch/blackfin/mach-common/smp.c18
-rw-r--r--arch/blackfin/mm/init.c44
-rw-r--r--arch/c6x/include/asm/Kbuild1
-rw-r--r--arch/c6x/kernel/vmlinux.lds.S4
-rw-r--r--arch/c6x/mm/init.c18
-rw-r--r--arch/cris/Kconfig34
-rw-r--r--arch/cris/arch-v10/drivers/Kconfig4
-rw-r--r--arch/cris/arch-v10/kernel/kgdb.c870
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig11
-rw-r--r--arch/cris/include/asm/Kbuild4
-rw-r--r--arch/cris/include/asm/io.h3
-rw-r--r--arch/cris/include/asm/linkage.h6
-rw-r--r--arch/cris/include/asm/page.h1
-rw-r--r--arch/cris/include/uapi/asm/socket.h2
-rw-r--r--arch/cris/mm/init.c37
-rw-r--r--arch/frv/Kconfig1
-rw-r--r--arch/frv/Kconfig.debug4
-rw-r--r--arch/frv/include/uapi/asm/socket.h2
-rw-r--r--arch/frv/kernel/head.S5
-rw-r--r--arch/frv/kernel/pm.c8
-rw-r--r--arch/frv/kernel/setup.c15
-rw-r--r--arch/frv/kernel/sysctl.c4
-rw-r--r--arch/frv/kernel/traps.c2
-rw-r--r--arch/frv/mm/init.c57
-rw-r--r--arch/h8300/Kconfig118
-rw-r--r--arch/h8300/Kconfig.cpu4
-rw-r--r--arch/h8300/boot/compressed/Makefile2
-rw-r--r--arch/h8300/boot/compressed/misc.c1
-rw-r--r--arch/h8300/include/asm/Kbuild2
-rw-r--r--arch/h8300/include/asm/barrier.h2
-rw-r--r--arch/h8300/include/asm/linkage.h6
-rw-r--r--arch/h8300/include/asm/tlb.h15
-rw-r--r--arch/h8300/include/uapi/asm/socket.h2
-rw-r--r--arch/h8300/kernel/entry.S118
-rw-r--r--arch/h8300/kernel/syscalls.S648
-rw-r--r--arch/h8300/kernel/vmlinux.lds.S2
-rw-r--r--arch/h8300/lib/abs.S4
-rw-r--r--arch/h8300/lib/memcpy.S4
-rw-r--r--arch/h8300/lib/memset.S4
-rw-r--r--arch/h8300/mm/init.c44
-rw-r--r--arch/h8300/platform/h8300h/aki3068net/crt0_ram.S16
-rw-r--r--arch/h8300/platform/h8300h/generic/crt0_ram.S14
-rw-r--r--arch/h8300/platform/h8300h/generic/crt0_rom.S14
-rw-r--r--arch/h8300/platform/h8300h/h8max/crt0_ram.S16
-rw-r--r--arch/h8300/platform/h8s/edosk2674/crt0_ram.S16
-rw-r--r--arch/h8300/platform/h8s/edosk2674/crt0_rom.S14
-rw-r--r--arch/h8300/platform/h8s/generic/crt0_ram.S16
-rw-r--r--arch/h8300/platform/h8s/generic/crt0_rom.S12
-rw-r--r--arch/hexagon/mm/init.c6
-rw-r--r--arch/ia64/hp/common/sba_iommu.c24
-rw-r--r--arch/ia64/hp/sim/boot/fw-emu.c20
-rw-r--r--arch/ia64/hp/sim/simeth.c2
-rw-r--r--arch/ia64/hp/sim/simscsi.c4
-rw-r--r--arch/ia64/include/asm/pci.h10
-rw-r--r--arch/ia64/include/uapi/asm/socket.h2
-rw-r--r--arch/ia64/kernel/acpi.c4
-rw-r--r--arch/ia64/kernel/efi.c5
-rw-r--r--arch/ia64/kernel/err_inject.c8
-rw-r--r--arch/ia64/kernel/mca.c12
-rw-r--r--arch/ia64/kernel/numa.c4
-rw-r--r--arch/ia64/kernel/palinfo.c4
-rw-r--r--arch/ia64/kernel/pci-dma.c9
-rw-r--r--arch/ia64/kernel/perfmon.c20
-rw-r--r--arch/ia64/kernel/salinfo.c4
-rw-r--r--arch/ia64/kernel/setup.c10
-rw-r--r--arch/ia64/kernel/smpboot.c8
-rw-r--r--arch/ia64/kernel/topology.c18
-rw-r--r--arch/ia64/kernel/traps.c2
-rw-r--r--arch/ia64/kvm/Makefile7
-rw-r--r--arch/ia64/mm/contig.c14
-rw-r--r--arch/ia64/mm/discontig.c5
-rw-r--r--arch/ia64/mm/init.c41
-rw-r--r--arch/ia64/mm/numa.c2
-rw-r--r--arch/ia64/pci/pci.c239
-rw-r--r--arch/ia64/sn/kernel/io_init.c122
-rw-r--r--arch/ia64/sn/kernel/setup.c8
-rw-r--r--arch/ia64/xen/hypervisor.c2
-rw-r--r--arch/m32r/Kconfig1
-rw-r--r--arch/m32r/Kconfig.debug7
-rw-r--r--arch/m32r/include/uapi/asm/socket.h2
-rw-r--r--arch/m32r/mm/discontig.c6
-rw-r--r--arch/m32r/mm/init.c68
-rw-r--r--arch/m68k/Kconfig.debug3
-rw-r--r--arch/m68k/configs/multi_defconfig2
-rw-r--r--arch/m68k/configs/q40_defconfig6
-rw-r--r--arch/m68k/include/asm/parport.h2
-rw-r--r--arch/m68k/include/asm/string.h32
-rw-r--r--arch/m68k/include/asm/uaccess_mm.h8
-rw-r--r--arch/m68k/kernel/asm-offsets.c2
-rw-r--r--arch/m68k/kernel/ints.c2
-rw-r--r--arch/m68k/lib/Makefile2
-rw-r--r--arch/m68k/lib/string.c22
-rw-r--r--arch/m68k/lib/uaccess.c6
-rw-r--r--arch/m68k/math-emu/fp_arith.c2
-rw-r--r--arch/m68k/mm/init.c48
-rw-r--r--arch/m68k/platform/coldfire/pci.c1
-rw-r--r--arch/m68k/sun3/sun3dvma.c2
-rw-r--r--arch/metag/Kconfig1
-rw-r--r--arch/metag/Kconfig.debug7
-rw-r--r--arch/metag/Kconfig.soc12
-rw-r--r--arch/metag/Makefile2
-rw-r--r--arch/metag/boot/.gitignore2
-rw-r--r--arch/metag/boot/dts/Makefile2
l---------arch/metag/boot/dts/include/dt-bindings1
-rw-r--r--arch/metag/boot/dts/skeleton.dts2
-rw-r--r--arch/metag/boot/dts/tz1090.dtsi41
-rw-r--r--arch/metag/boot/dts/tz1090_generic.dts10
-rw-r--r--arch/metag/configs/tz1090_defconfig42
-rw-r--r--arch/metag/include/asm/bug.h4
-rw-r--r--arch/metag/include/asm/checksum.h3
-rw-r--r--arch/metag/include/asm/clock.h8
-rw-r--r--arch/metag/include/asm/irq.h1
-rw-r--r--arch/metag/include/asm/processor.h2
-rw-r--r--arch/metag/kernel/cachepart.c13
-rw-r--r--arch/metag/kernel/clock.c59
-rw-r--r--arch/metag/kernel/irq.c7
-rw-r--r--arch/metag/kernel/kick.c9
-rw-r--r--arch/metag/kernel/metag_ksyms.c5
-rw-r--r--arch/metag/kernel/setup.c16
-rw-r--r--arch/metag/kernel/smp.c35
-rw-r--r--arch/metag/kernel/time.c14
-rw-r--r--arch/metag/kernel/traps.c5
-rw-r--r--arch/metag/lib/checksum.c1
-rw-r--r--arch/metag/mm/cache.c2
-rw-r--r--arch/metag/mm/fault.c6
-rw-r--r--arch/metag/mm/init.c32
-rw-r--r--arch/microblaze/configs/mmu_defconfig4
-rw-r--r--arch/microblaze/include/asm/page.h1
-rw-r--r--arch/microblaze/include/asm/unistd.h3
-rw-r--r--arch/microblaze/include/uapi/asm/unistd.h2
-rw-r--r--arch/microblaze/kernel/kgdb.c2
-rw-r--r--arch/microblaze/mm/init.c57
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/Kconfig.debug9
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c4
-rw-r--r--arch/mips/bcm63xx/dev-enet.c181
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h7
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h122
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h93
-rw-r--r--arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h2
-rw-r--r--arch/mips/include/asm/mach-jz4740/dma.h56
-rw-r--r--arch/mips/include/asm/mach-jz4740/platform.h1
-rw-r--r--arch/mips/include/uapi/asm/socket.h2
-rw-r--r--arch/mips/jz4740/Makefile2
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c1
-rw-r--r--arch/mips/jz4740/clock.c2
-rw-r--r--arch/mips/jz4740/dma.c287
-rw-r--r--arch/mips/jz4740/platform.c21
-rw-r--r--arch/mips/kernel/crash_dump.c10
-rw-r--r--arch/mips/loongson/lemote-2f/clock.c3
-rw-r--r--arch/mips/mm/init.c62
-rw-r--r--arch/mips/mm/mmap.c2
-rw-r--r--arch/mips/pci/pci-lantiq.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-memory.c33
-rw-r--r--arch/mips/txx9/generic/setup_tx4939.c3
-rw-r--r--arch/mn10300/Kconfig1
-rw-r--r--arch/mn10300/Kconfig.debug4
-rw-r--r--arch/mn10300/include/uapi/asm/socket.h2
-rw-r--r--arch/mn10300/mm/fault.c7
-rw-r--r--arch/mn10300/mm/init.c33
-rw-r--r--arch/openrisc/Kconfig11
-rw-r--r--arch/openrisc/include/asm/Kbuild1
-rw-r--r--arch/openrisc/mm/fault.c8
-rw-r--r--arch/openrisc/mm/init.c48
-rw-r--r--arch/parisc/Kconfig1
-rw-r--r--arch/parisc/Kconfig.debug11
-rw-r--r--arch/parisc/Makefile15
-rw-r--r--arch/parisc/defpalo.conf8
-rw-r--r--arch/parisc/include/asm/special_insns.h9
-rw-r--r--arch/parisc/include/asm/tlbflush.h5
-rw-r--r--arch/parisc/include/uapi/asm/fcntl.h1
-rw-r--r--arch/parisc/include/uapi/asm/socket.h2
-rw-r--r--arch/parisc/install.sh6
-rw-r--r--arch/parisc/kernel/cache.c2
-rw-r--r--arch/parisc/kernel/processor.c19
-rw-r--r--arch/parisc/lib/memcpy.c79
-rw-r--r--arch/parisc/mm/init.c60
-rw-r--r--arch/powerpc/Kconfig19
-rw-r--r--arch/powerpc/Kconfig.debug14
-rw-r--r--arch/powerpc/boot/dts/currituck.dts5
-rw-r--r--arch/powerpc/boot/dts/fsl/interlaken-lac-portals.dtsi156
-rw-r--r--arch/powerpc/boot/dts/fsl/interlaken-lac.dtsi45
-rw-r--r--arch/powerpc/configs/c2k_defconfig2
-rw-r--r--arch/powerpc/configs/g5_defconfig2
-rw-r--r--arch/powerpc/configs/maple_defconfig2
-rw-r--r--arch/powerpc/configs/mpc512x_defconfig27
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig1
-rw-r--r--arch/powerpc/configs/pmac32_defconfig2
-rw-r--r--arch/powerpc/configs/ppc64_defconfig2
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig2
-rw-r--r--arch/powerpc/configs/pseries_defconfig1
-rw-r--r--arch/powerpc/include/asm/eeh.h36
-rw-r--r--arch/powerpc/include/asm/eeh_event.h2
-rw-r--r--arch/powerpc/include/asm/exception-64s.h8
-rw-r--r--arch/powerpc/include/asm/hugetlb.h8
-rw-r--r--arch/powerpc/include/asm/ibmebus.h4
-rw-r--r--arch/powerpc/include/asm/iommu.h33
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h6
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_64.h58
-rw-r--r--arch/powerpc/include/asm/lppaca.h3
-rw-r--r--arch/powerpc/include/asm/machdep.h11
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h14
-rw-r--r--arch/powerpc/include/asm/mpc5121.h1
-rw-r--r--arch/powerpc/include/asm/mpic.h5
-rw-r--r--arch/powerpc/include/asm/mpic_timer.h46
-rw-r--r--arch/powerpc/include/asm/opal.h140
-rw-r--r--arch/powerpc/include/asm/perf_event_server.h6
-rw-r--r--arch/powerpc/include/asm/pgalloc-64.h6
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64-64k.h3
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h241
-rw-r--r--arch/powerpc/include/asm/pgtable.h6
-rw-r--r--arch/powerpc/include/asm/probes.h25
-rw-r--r--arch/powerpc/include/asm/processor.h16
-rw-r--r--arch/powerpc/include/asm/reg.h9
-rw-r--r--arch/powerpc/include/asm/rtas.h4
-rw-r--r--arch/powerpc/include/asm/switch_to.h14
-rw-r--r--arch/powerpc/include/asm/tlbflush.h3
-rw-r--r--arch/powerpc/include/asm/vdso.h2
-rw-r--r--arch/powerpc/include/uapi/asm/socket.h2
-rw-r--r--arch/powerpc/kernel/Makefile4
-rw-r--r--arch/powerpc/kernel/asm-offsets.c7
-rw-r--r--arch/powerpc/kernel/cacheinfo.c36
-rw-r--r--arch/powerpc/kernel/crash_dump.c10
-rw-r--r--arch/powerpc/kernel/eeh.c (renamed from arch/powerpc/platforms/pseries/eeh.c)196
-rw-r--r--arch/powerpc/kernel/eeh_cache.c (renamed from arch/powerpc/platforms/pseries/eeh_cache.c)5
-rw-r--r--arch/powerpc/kernel/eeh_dev.c (renamed from arch/powerpc/platforms/pseries/eeh_dev.c)0
-rw-r--r--arch/powerpc/kernel/eeh_driver.c (renamed from arch/powerpc/platforms/pseries/eeh_driver.c)169
-rw-r--r--arch/powerpc/kernel/eeh_event.c (renamed from arch/powerpc/platforms/pseries/eeh_event.c)134
-rw-r--r--arch/powerpc/kernel/eeh_pe.c (renamed from arch/powerpc/platforms/pseries/eeh_pe.c)237
-rw-r--r--arch/powerpc/kernel/eeh_sysfs.c (renamed from arch/powerpc/platforms/pseries/eeh_sysfs.c)1
-rw-r--r--arch/powerpc/kernel/entry_64.S30
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S56
-rw-r--r--arch/powerpc/kernel/hw_breakpoint.c3
-rw-r--r--arch/powerpc/kernel/ibmebus.c22
-rw-r--r--arch/powerpc/kernel/idle.c4
-rw-r--r--arch/powerpc/kernel/io-workarounds.c11
-rw-r--r--arch/powerpc/kernel/iommu.c323
-rw-r--r--arch/powerpc/kernel/irq.c2
-rw-r--r--arch/powerpc/kernel/kprobes.c20
-rw-r--r--arch/powerpc/kernel/kvm.c9
-rw-r--r--arch/powerpc/kernel/nvram_64.c20
-rw-r--r--arch/powerpc/kernel/pci-hotplug.c111
-rw-r--r--arch/powerpc/kernel/pci_of_scan.c5
-rw-r--r--arch/powerpc/kernel/proc_powerpc.c20
-rw-r--r--arch/powerpc/kernel/process.c4
-rw-r--r--arch/powerpc/kernel/prom.c42
-rw-r--r--arch/powerpc/kernel/ptrace.c30
-rw-r--r--arch/powerpc/kernel/reloc_32.S3
-rw-r--r--arch/powerpc/kernel/rtas.c4
-rw-r--r--arch/powerpc/kernel/setup_64.c2
-rw-r--r--arch/powerpc/kernel/signal_32.c70
-rw-r--r--arch/powerpc/kernel/signal_64.c8
-rw-r--r--arch/powerpc/kernel/smp.c12
-rw-r--r--arch/powerpc/kernel/sysfs.c6
-rw-r--r--arch/powerpc/kernel/time.c1
-rw-r--r--arch/powerpc/kernel/tm.S18
-rw-r--r--arch/powerpc/kernel/traps.c79
-rw-r--r--arch/powerpc/kernel/udbg.c2
-rw-r--r--arch/powerpc/kernel/vdso.c2
-rw-r--r--arch/powerpc/kvm/Makefile13
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu.c81
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_host.c23
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c8
-rw-r--r--arch/powerpc/kvm/book3s_64_slb.S13
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_mmu.c14
-rw-r--r--arch/powerpc/kvm/book3s_pr.c3
-rw-r--r--arch/powerpc/kvm/booke.c2
-rw-r--r--arch/powerpc/kvm/emulate.c3
-rw-r--r--arch/powerpc/lib/sstep.c2
-rw-r--r--arch/powerpc/math-emu/Makefile3
-rw-r--r--arch/powerpc/math-emu/fre.c11
-rw-r--r--arch/powerpc/math-emu/frsqrtes.c11
-rw-r--r--arch/powerpc/math-emu/math.c14
-rw-r--r--arch/powerpc/mm/44x_mmu.c6
-rw-r--r--arch/powerpc/mm/Makefile8
-rw-r--r--arch/powerpc/mm/gup.c18
-rw-r--r--arch/powerpc/mm/hash_low_64.S21
-rw-r--r--arch/powerpc/mm/hash_native_64.c195
-rw-r--r--arch/powerpc/mm/hash_utils_64.c67
-rw-r--r--arch/powerpc/mm/hugepage-hash64.c175
-rw-r--r--arch/powerpc/mm/hugetlbpage-hash64.c2
-rw-r--r--arch/powerpc/mm/hugetlbpage.c301
-rw-r--r--arch/powerpc/mm/init_64.c9
-rw-r--r--arch/powerpc/mm/mem.c63
-rw-r--r--arch/powerpc/mm/mmap.c (renamed from arch/powerpc/mm/mmap_64.c)2
-rw-r--r--arch/powerpc/mm/mmu_context_nohash.c15
-rw-r--r--arch/powerpc/mm/numa.c12
-rw-r--r--arch/powerpc/mm/pgtable.c8
-rw-r--r--arch/powerpc/mm/pgtable_64.c414
-rw-r--r--arch/powerpc/mm/subpage-prot.c48
-rw-r--r--arch/powerpc/mm/tlb_hash64.c36
-rw-r--r--arch/powerpc/mm/tlb_nohash.c2
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c19
-rw-r--r--arch/powerpc/perf/core-book3s.c201
-rw-r--r--arch/powerpc/perf/power8-pmu.c62
-rw-r--r--arch/powerpc/platforms/44x/currituck.c43
-rw-r--r--arch/powerpc/platforms/44x/iss4xx.c4
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads.c6
-rw-r--r--arch/powerpc/platforms/512x/mpc512x.h12
-rw-r--r--arch/powerpc/platforms/512x/mpc512x_generic.c4
-rw-r--r--arch/powerpc/platforms/512x/mpc512x_shared.c31
-rw-r--r--arch/powerpc/platforms/512x/pdm360ng.c4
-rw-r--r--arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c12
-rw-r--r--arch/powerpc/platforms/85xx/p5020_ds.c5
-rw-r--r--arch/powerpc/platforms/85xx/p5040_ds.c5
-rw-r--r--arch/powerpc/platforms/85xx/smp.c6
-rw-r--r--arch/powerpc/platforms/85xx/t4240_qds.c5
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c14
-rw-r--r--arch/powerpc/platforms/Kconfig57
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype2
-rw-r--r--arch/powerpc/platforms/cell/beat_htab.c16
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c2
-rw-r--r--arch/powerpc/platforms/cell/smp.c2
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile1
-rw-r--r--arch/powerpc/platforms/powermac/Makefile2
-rw-r--r--arch/powerpc/platforms/powermac/smp.c4
-rw-r--r--arch/powerpc/platforms/powernv/Makefile1
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c916
-rw-r--r--arch/powerpc/platforms/powernv/eeh-powernv.c379
-rw-r--r--arch/powerpc/platforms/powernv/opal-wrappers.S3
-rw-r--r--arch/powerpc/platforms/powernv/opal.c69
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c62
-rw-r--r--arch/powerpc/platforms/powernv/pci-p5ioc2.c11
-rw-r--r--arch/powerpc/platforms/powernv/pci.c139
-rw-r--r--arch/powerpc/platforms/powernv/pci.h35
-rw-r--r--arch/powerpc/platforms/powernv/setup.c4
-rw-r--r--arch/powerpc/platforms/powernv/smp.c4
-rw-r--r--arch/powerpc/platforms/ps3/htab.c5
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig5
-rw-r--r--arch/powerpc/platforms/pseries/Makefile4
-rw-r--r--arch/powerpc/platforms/pseries/io_event_irq.c2
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c4
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c142
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c554
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c85
-rw-r--r--arch/powerpc/platforms/pseries/ras.c8
-rw-r--r--arch/powerpc/platforms/pseries/smp.c2
-rwxr-xr-xarch/powerpc/relocs_check.pl10
-rw-r--r--arch/powerpc/sysdev/Makefile2
-rw-r--r--arch/powerpc/sysdev/cpm1.c1
-rw-r--r--arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c161
-rw-r--r--arch/powerpc/sysdev/mpic.c58
-rw-r--r--arch/powerpc/sysdev/mpic_timer.c593
-rw-r--r--arch/s390/appldata/appldata_mem.c18
-rw-r--r--arch/s390/appldata/appldata_net_sum.c18
-rw-r--r--arch/s390/hypfs/hypfs_diag.c8
-rw-r--r--arch/s390/include/asm/airq.h15
-rw-r--r--arch/s390/include/asm/dma-mapping.h2
-rw-r--r--arch/s390/include/asm/facility.h17
-rw-r--r--arch/s390/include/asm/io.h22
-rw-r--r--arch/s390/include/asm/kvm_host.h18
-rw-r--r--arch/s390/include/asm/pci.h2
-rw-r--r--arch/s390/include/asm/perf_event.h10
-rw-r--r--arch/s390/include/asm/pgalloc.h3
-rw-r--r--arch/s390/include/asm/pgtable.h88
-rw-r--r--arch/s390/include/asm/ptrace.h1
-rw-r--r--arch/s390/include/uapi/asm/Kbuild1
-rw-r--r--arch/s390/include/uapi/asm/chsc.h13
-rw-r--r--arch/s390/include/uapi/asm/dasd.h4
-rw-r--r--arch/s390/include/uapi/asm/sclp_ctl.h24
-rw-r--r--arch/s390/include/uapi/asm/socket.h2
-rw-r--r--arch/s390/kernel/asm-offsets.c4
-rw-r--r--arch/s390/kernel/entry.S12
-rw-r--r--arch/s390/kernel/entry.h2
-rw-r--r--arch/s390/kernel/entry64.S97
-rw-r--r--arch/s390/kernel/irq.c8
-rw-r--r--arch/s390/kernel/perf_event.c52
-rw-r--r--arch/s390/kernel/s390_ksyms.c1
-rw-r--r--arch/s390/kernel/setup.c4
-rw-r--r--arch/s390/kernel/smp.c5
-rw-r--r--arch/s390/kvm/Makefile3
-rw-r--r--arch/s390/kvm/diag.c3
-rw-r--r--arch/s390/kvm/intercept.c124
-rw-r--r--arch/s390/kvm/interrupt.c18
-rw-r--r--arch/s390/kvm/kvm-s390.c105
-rw-r--r--arch/s390/kvm/kvm-s390.h14
-rw-r--r--arch/s390/kvm/priv.c274
-rw-r--r--arch/s390/kvm/sigp.c19
-rw-r--r--arch/s390/mm/init.c24
-rw-r--r--arch/s390/mm/mmap.c4
-rw-r--r--arch/s390/mm/pgtable.c55
-rw-r--r--arch/s390/oprofile/hwsampler.h4
-rw-r--r--arch/s390/pci/pci.c83
-rw-r--r--arch/s390/pci/pci_clp.c1
-rw-r--r--arch/s390/pci/pci_debug.c29
-rw-r--r--arch/s390/pci/pci_dma.c6
-rw-r--r--arch/s390/pci/pci_sysfs.c20
-rw-r--r--arch/score/include/asm/Kbuild1
-rw-r--r--arch/score/include/asm/dma-mapping.h6
-rw-r--r--arch/score/kernel/vmlinux.lds.S1
-rw-r--r--arch/score/mm/fault.c8
-rw-r--r--arch/score/mm/init.c31
-rw-r--r--arch/sh/boards/board-espt.c2
-rw-r--r--arch/sh/boards/board-sh7757lcr.c8
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c4
-rw-r--r--arch/sh/boards/mach-se/770x/setup.c8
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c4
-rw-r--r--arch/sh/boards/mach-sh7763rdp/setup.c2
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7724.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7734.c2
-rw-r--r--arch/sh/kernel/ptrace_32.c4
-rw-r--r--arch/sh/mm/init.c43
-rw-r--r--arch/sparc/include/asm/leon.h2
-rw-r--r--arch/sparc/include/asm/pgtable_64.h5
-rw-r--r--arch/sparc/include/uapi/asm/fcntl.h1
-rw-r--r--arch/sparc/include/uapi/asm/socket.h2
-rw-r--r--arch/sparc/kernel/asm-offsets.c2
-rw-r--r--arch/sparc/kernel/ds.c10
-rw-r--r--arch/sparc/kernel/leon_smp.c3
-rw-r--r--arch/sparc/kernel/pci.c5
-rw-r--r--arch/sparc/kernel/sys_sparc_64.c2
-rw-r--r--arch/sparc/mm/hypersparc.S8
-rw-r--r--arch/sparc/mm/init_32.c37
-rw-r--r--arch/sparc/mm/init_64.c26
-rw-r--r--arch/sparc/mm/swift.S8
-rw-r--r--arch/sparc/mm/tlb.c5
-rw-r--r--arch/sparc/mm/tsunami.S6
-rw-r--r--arch/sparc/mm/viking.S10
-rw-r--r--arch/sparc/net/bpf_jit_comp.c20
-rw-r--r--arch/tile/Kconfig1
-rw-r--r--arch/tile/Kconfig.debug7
-rw-r--r--arch/tile/include/asm/sections.h2
-rw-r--r--arch/tile/kernel/setup.c20
-rw-r--r--arch/tile/kernel/vmlinux.lds.S4
-rw-r--r--arch/tile/mm/fault.c8
-rw-r--r--arch/tile/mm/init.c26
-rw-r--r--arch/tile/mm/mmap.c2
-rw-r--r--arch/um/include/asm/common.lds.S1
-rw-r--r--arch/um/kernel/dyn.lds.S6
-rw-r--r--arch/um/kernel/mem.c8
-rw-r--r--arch/um/kernel/uml.lds.S7
-rw-r--r--arch/unicore32/boot/compressed/Makefile2
-rw-r--r--arch/unicore32/include/asm/memory.h6
-rw-r--r--arch/unicore32/kernel/pci.c5
-rw-r--r--arch/unicore32/kernel/process.c14
-rw-r--r--arch/unicore32/kernel/setup.h2
-rw-r--r--arch/unicore32/mm/init.c55
-rw-r--r--arch/unicore32/mm/mmu.c2
-rw-r--r--arch/x86/Kconfig13
-rw-r--r--arch/x86/Kconfig.debug10
-rw-r--r--arch/x86/boot/compressed/Makefile6
-rw-r--r--arch/x86/boot/compressed/misc.c4
-rw-r--r--arch/x86/crypto/Makefile8
-rw-r--r--arch/x86/crypto/blowfish-avx2-asm_64.S449
-rw-r--r--arch/x86/crypto/blowfish_avx2_glue.c585
-rw-r--r--arch/x86/crypto/blowfish_glue.c32
-rw-r--r--arch/x86/crypto/camellia-aesni-avx2-asm_64.S160
-rw-r--r--arch/x86/crypto/crct10dif-pcl-asm_64.S643
-rw-r--r--arch/x86/crypto/crct10dif-pclmul_glue.c151
-rw-r--r--arch/x86/crypto/sha256_ssse3_glue.c57
-rw-r--r--arch/x86/crypto/sha512_ssse3_glue.c58
-rw-r--r--arch/x86/crypto/twofish-avx2-asm_64.S600
-rw-r--r--arch/x86/crypto/twofish_avx2_glue.c584
-rw-r--r--arch/x86/crypto/twofish_avx_glue.c14
-rw-r--r--arch/x86/ia32/ia32_aout.c2
-rw-r--r--arch/x86/include/asm/acpi.h2
-rw-r--r--arch/x86/include/asm/crypto/blowfish.h43
-rw-r--r--arch/x86/include/asm/crypto/twofish.h18
-rw-r--r--arch/x86/include/asm/emergency-restart.h12
-rw-r--r--arch/x86/include/asm/io.h7
-rw-r--r--arch/x86/include/asm/kvm_host.h15
-rw-r--r--arch/x86/include/asm/mc146818rtc.h4
-rw-r--r--arch/x86/include/asm/mce.h7
-rw-r--r--arch/x86/include/asm/mrst-vrtc.h4
-rw-r--r--arch/x86/include/asm/mtrr.h10
-rw-r--r--arch/x86/include/asm/pgtable.h24
-rw-r--r--arch/x86/include/asm/pgtable_types.h12
-rw-r--r--arch/x86/include/asm/thread_info.h4
-rw-r--r--arch/x86/include/asm/x86_init.h6
-rw-r--r--arch/x86/kernel/acpi/boot.c7
-rw-r--r--arch/x86/kernel/acpi/sleep.c4
-rw-r--r--arch/x86/kernel/acpi/sleep.h2
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c2
-rw-r--r--arch/x86/kernel/cpu/amd.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c106
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c71
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_iommu.c4
-rw-r--r--arch/x86/kernel/cpu/powerflags.c8
-rw-r--r--arch/x86/kernel/devicetree.c4
-rw-r--r--arch/x86/kernel/hw_breakpoint.c3
-rw-r--r--arch/x86/kernel/kvmclock.c9
-rw-r--r--arch/x86/kernel/ptrace.c204
-rw-r--r--arch/x86/kernel/reboot.c117
-rw-r--r--arch/x86/kernel/rtc.c17
-rw-r--r--arch/x86/kernel/setup.c2
-rw-r--r--arch/x86/kernel/smp.c29
-rw-r--r--arch/x86/kvm/Makefile13
-rw-r--r--arch/x86/kvm/emulate.c391
-rw-r--r--arch/x86/kvm/lapic.c4
-rw-r--r--arch/x86/kvm/mmu.c301
-rw-r--r--arch/x86/kvm/mmu.h18
-rw-r--r--arch/x86/kvm/mmutrace.h76
-rw-r--r--arch/x86/kvm/paging_tmpl.h10
-rw-r--r--arch/x86/kvm/svm.c10
-rw-r--r--arch/x86/kvm/trace.h21
-rw-r--r--arch/x86/kvm/vmx.c30
-rw-r--r--arch/x86/kvm/x86.c80
-rw-r--r--arch/x86/lguest/Makefile2
-rw-r--r--arch/x86/lguest/boot.c4
-rw-r--r--arch/x86/lguest/head_32.S (renamed from arch/x86/lguest/i386_head.S)0
-rw-r--r--arch/x86/mm/highmem_32.c6
-rw-r--r--arch/x86/mm/hugetlbpage.c187
-rw-r--r--arch/x86/mm/init.c14
-rw-r--r--arch/x86/mm/init_32.c32
-rw-r--r--arch/x86/mm/init_64.c45
-rw-r--r--arch/x86/mm/mmap.c2
-rw-r--r--arch/x86/mm/numa_32.c2
-rw-r--r--arch/x86/mm/pgtable.c4
-rw-r--r--arch/x86/net/bpf_jit_comp.c61
-rw-r--r--arch/x86/pci/acpi.c7
-rw-r--r--arch/x86/platform/efi/efi.c10
-rw-r--r--arch/x86/platform/mrst/vrtc.c11
-rw-r--r--arch/x86/xen/smp.c91
-rw-r--r--arch/x86/xen/spinlock.c7
-rw-r--r--arch/x86/xen/time.c116
-rw-r--r--arch/xtensa/Kconfig3
-rw-r--r--arch/xtensa/Kconfig.debug10
-rw-r--r--arch/xtensa/boot/.gitignore3
-rw-r--r--arch/xtensa/boot/boot-elf/.gitignore1
-rw-r--r--arch/xtensa/boot/lib/.gitignore3
-rw-r--r--arch/xtensa/boot/lib/Makefile7
-rw-r--r--arch/xtensa/include/asm/bootparam.h2
-rw-r--r--arch/xtensa/include/asm/cmpxchg.h1
-rw-r--r--arch/xtensa/include/asm/delay.h13
-rw-r--r--arch/xtensa/include/asm/ftrace.h17
-rw-r--r--arch/xtensa/include/asm/pgtable.h140
-rw-r--r--arch/xtensa/include/asm/platform.h5
-rw-r--r--arch/xtensa/include/asm/timex.h12
-rw-r--r--arch/xtensa/include/uapi/asm/socket.h2
-rw-r--r--arch/xtensa/kernel/.gitignore1
-rw-r--r--arch/xtensa/kernel/Makefile1
-rw-r--r--arch/xtensa/kernel/entry.S16
-rw-r--r--arch/xtensa/kernel/head.S9
-rw-r--r--arch/xtensa/kernel/mcount.S50
-rw-r--r--arch/xtensa/kernel/pci.c10
-rw-r--r--arch/xtensa/kernel/platform.c3
-rw-r--r--arch/xtensa/kernel/setup.c8
-rw-r--r--arch/xtensa/kernel/time.c123
-rw-r--r--arch/xtensa/kernel/xtensa_ksyms.c4
-rw-r--r--arch/xtensa/mm/init.c33
-rw-r--r--arch/xtensa/mm/tlb.c120
-rw-r--r--arch/xtensa/platforms/iss/network.c2
-rw-r--r--arch/xtensa/platforms/iss/simdisk.c4
-rw-r--r--arch/xtensa/platforms/xtfpga/setup.c5
-rw-r--r--arch/xtensa/variants/s6000/delay.c6
-rw-r--r--block/blk-cgroup.c105
-rw-r--r--block/blk-cgroup.h38
-rw-r--r--block/blk-core.c6
-rw-r--r--block/blk-ioc.c3
-rw-r--r--block/blk-tag.c11
-rw-r--r--block/blk-throttle.c1064
-rw-r--r--block/blk-timeout.c5
-rw-r--r--block/cfq-iosched.c17
-rw-r--r--block/compat_ioctl.c1
-rw-r--r--block/deadline-iosched.c16
-rw-r--r--block/elevator.c25
-rw-r--r--block/genhd.c14
-rw-r--r--block/noop-iosched.c17
-rw-r--r--block/partitions/Kconfig11
-rw-r--r--block/partitions/Makefile1
-rw-r--r--block/partitions/aix.c293
-rw-r--r--block/partitions/aix.h1
-rw-r--r--block/partitions/msdos.c17
-rw-r--r--crypto/Kconfig79
-rw-r--r--crypto/Makefile3
-rw-r--r--crypto/algapi.c3
-rw-r--r--crypto/async_tx/Kconfig4
-rw-r--r--crypto/async_tx/Makefile1
-rw-r--r--crypto/async_tx/async_memset.c89
-rw-r--r--crypto/crct10dif.c178
-rw-r--r--crypto/lz4.c106
-rw-r--r--crypto/lz4hc.c106
-rw-r--r--crypto/pcrypt.c4
-rw-r--r--crypto/sha512_generic.c2
-rw-r--r--crypto/tcrypt.c8
-rw-r--r--crypto/testmgr.c176
-rw-r--r--crypto/testmgr.h33
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c92
-rw-r--r--drivers/acpi/acpi_lpss.c125
-rw-r--r--drivers/acpi/acpi_memhotplug.c62
-rw-r--r--drivers/acpi/acpi_processor.c494
-rw-r--r--drivers/acpi/acpica/Makefile4
-rw-r--r--drivers/acpi/acpica/acglobal.h6
-rw-r--r--drivers/acpi/acpica/aclocal.h17
-rw-r--r--drivers/acpi/acpica/acmacros.h10
-rw-r--r--drivers/acpi/acpica/acnamesp.h43
-rw-r--r--drivers/acpi/acpica/acpredef.h4
-rw-r--r--drivers/acpi/acpica/acstruct.h40
-rw-r--r--drivers/acpi/acpica/acutils.h50
-rw-r--r--drivers/acpi/acpica/dscontrol.c4
-rw-r--r--drivers/acpi/acpica/dsfield.c4
-rw-r--r--drivers/acpi/acpica/dsinit.c1
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c3
-rw-r--r--drivers/acpi/acpica/dsopcode.c1
-rw-r--r--drivers/acpi/acpica/dsutils.c5
-rw-r--r--drivers/acpi/acpica/dswexec.c3
-rw-r--r--drivers/acpi/acpica/dswload.c7
-rw-r--r--drivers/acpi/acpica/dswload2.c4
-rw-r--r--drivers/acpi/acpica/evglock.c1
-rw-r--r--drivers/acpi/acpica/evgpe.c7
-rw-r--r--drivers/acpi/acpica/evgpeblk.c2
-rw-r--r--drivers/acpi/acpica/evgpeinit.c3
-rw-r--r--drivers/acpi/acpica/evhandler.c7
-rw-r--r--drivers/acpi/acpica/evmisc.c3
-rw-r--r--drivers/acpi/acpica/evregion.c63
-rw-r--r--drivers/acpi/acpica/evrgnini.c2
-rw-r--r--drivers/acpi/acpica/evxfgpe.c3
-rw-r--r--drivers/acpi/acpica/evxfregn.c1
-rw-r--r--drivers/acpi/acpica/exconfig.c3
-rw-r--r--drivers/acpi/acpica/exconvrt.c13
-rw-r--r--drivers/acpi/acpica/excreate.c3
-rw-r--r--drivers/acpi/acpica/exdebug.c2
-rw-r--r--drivers/acpi/acpica/exdump.c2
-rw-r--r--drivers/acpi/acpica/exfield.c4
-rw-r--r--drivers/acpi/acpica/exfldio.c2
-rw-r--r--drivers/acpi/acpica/exmisc.c12
-rw-r--r--drivers/acpi/acpica/exoparg1.c16
-rw-r--r--drivers/acpi/acpica/exoparg2.c1
-rw-r--r--drivers/acpi/acpica/exoparg3.c1
-rw-r--r--drivers/acpi/acpica/exoparg6.c5
-rw-r--r--drivers/acpi/acpica/exprep.c7
-rw-r--r--drivers/acpi/acpica/exregion.c27
-rw-r--r--drivers/acpi/acpica/exresnte.c1
-rw-r--r--drivers/acpi/acpica/exresolv.c6
-rw-r--r--drivers/acpi/acpica/exresop.c9
-rw-r--r--drivers/acpi/acpica/exstore.c4
-rw-r--r--drivers/acpi/acpica/exstoren.c4
-rw-r--r--drivers/acpi/acpica/hwacpi.c2
-rw-r--r--drivers/acpi/acpica/hwgpe.c3
-rw-r--r--drivers/acpi/acpica/hwregs.c4
-rw-r--r--drivers/acpi/acpica/hwxface.c9
-rw-r--r--drivers/acpi/acpica/hwxfsleep.c12
-rw-r--r--drivers/acpi/acpica/nsaccess.c1
-rw-r--r--drivers/acpi/acpica/nsarguments.c294
-rw-r--r--drivers/acpi/acpica/nsconvert.c3
-rw-r--r--drivers/acpi/acpica/nsdump.c10
-rw-r--r--drivers/acpi/acpica/nseval.c247
-rw-r--r--drivers/acpi/acpica/nsinit.c16
-rw-r--r--drivers/acpi/acpica/nspredef.c216
-rw-r--r--drivers/acpi/acpica/nsprepkg.c81
-rw-r--r--drivers/acpi/acpica/nsrepair.c51
-rw-r--r--drivers/acpi/acpica/nsrepair2.c358
-rw-r--r--drivers/acpi/acpica/nsutils.c3
-rw-r--r--drivers/acpi/acpica/nsxfeval.c163
-rw-r--r--drivers/acpi/acpica/psargs.c4
-rw-r--r--drivers/acpi/acpica/psloop.c2
-rw-r--r--drivers/acpi/acpica/psobject.c1
-rw-r--r--drivers/acpi/acpica/psparse.c3
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psxface.c14
-rw-r--r--drivers/acpi/acpica/rscalc.c7
-rw-r--r--drivers/acpi/acpica/rscreate.c27
-rw-r--r--drivers/acpi/acpica/rsdump.c10
-rw-r--r--drivers/acpi/acpica/rsmisc.c3
-rw-r--r--drivers/acpi/acpica/rsutils.c7
-rw-r--r--drivers/acpi/acpica/rsxface.c1
-rw-r--r--drivers/acpi/acpica/tbinstal.c7
-rw-r--r--drivers/acpi/acpica/tbprint.c237
-rw-r--r--drivers/acpi/acpica/tbutils.c191
-rw-r--r--drivers/acpi/acpica/tbxfload.c25
-rw-r--r--drivers/acpi/acpica/utbuffer.c201
-rw-r--r--drivers/acpi/acpica/utcopy.c11
-rw-r--r--drivers/acpi/acpica/utdebug.c148
-rw-r--r--drivers/acpi/acpica/utdelete.c3
-rw-r--r--drivers/acpi/acpica/uterror.c289
-rw-r--r--drivers/acpi/acpica/uteval.c9
-rw-r--r--drivers/acpi/acpica/utexcep.c1
-rw-r--r--drivers/acpi/acpica/utids.c3
-rw-r--r--drivers/acpi/acpica/utmisc.c2
-rw-r--r--drivers/acpi/acpica/utobject.c5
-rw-r--r--drivers/acpi/acpica/utpredef.c16
-rw-r--r--drivers/acpi/acpica/utstring.c19
-rw-r--r--drivers/acpi/acpica/uttrack.c8
-rw-r--r--drivers/acpi/acpica/utxferror.c234
-rw-r--r--drivers/acpi/apei/erst.c24
-rw-r--r--drivers/acpi/apei/ghes.c10
-rw-r--r--drivers/acpi/battery.c18
-rw-r--r--drivers/acpi/bus.c17
-rw-r--r--drivers/acpi/device_pm.c193
-rw-r--r--drivers/acpi/dock.c7
-rw-r--r--drivers/acpi/ec.c4
-rw-r--r--drivers/acpi/ec_sys.c18
-rw-r--r--drivers/acpi/fan.c2
-rw-r--r--drivers/acpi/glue.c12
-rw-r--r--drivers/acpi/internal.h10
-rw-r--r--drivers/acpi/osl.c27
-rw-r--r--drivers/acpi/pci_root.c101
-rw-r--r--drivers/acpi/power.c4
-rw-r--r--drivers/acpi/processor_driver.c818
-rw-r--r--drivers/acpi/processor_idle.c4
-rw-r--r--drivers/acpi/processor_perflib.c4
-rw-r--r--drivers/acpi/scan.c206
-rw-r--r--drivers/acpi/sleep.c2
-rw-r--r--drivers/acpi/sysfs.c34
-rw-r--r--drivers/acpi/video.c3
-rw-r--r--drivers/amba/bus.c2
-rw-r--r--drivers/ata/Kconfig1
-rw-r--r--drivers/ata/acard-ahci.c4
-rw-r--r--drivers/ata/ahci.c12
-rw-r--r--drivers/ata/ahci.h2
-rw-r--r--drivers/ata/ahci_platform.c1
-rw-r--r--drivers/ata/ata_piix.c8
-rw-r--r--drivers/ata/libahci.c26
-rw-r--r--drivers/ata/libata-core.c11
-rw-r--r--drivers/ata/libata-pmp.c33
-rw-r--r--drivers/ata/libata-scsi.c37
-rw-r--r--drivers/ata/libata-transport.c4
-rw-r--r--drivers/ata/libata-zpodd.c7
-rw-r--r--drivers/ata/pata_ali.c2
-rw-r--r--drivers/ata/pata_amd.c2
-rw-r--r--drivers/ata/pata_arasan_cf.c2
-rw-r--r--drivers/ata/pata_artop.c2
-rw-r--r--drivers/ata/pata_at91.c2
-rw-r--r--drivers/ata/pata_atp867x.c2
-rw-r--r--drivers/ata/pata_bf54x.c10
-rw-r--r--drivers/ata/pata_cmd640.c2
-rw-r--r--drivers/ata/pata_cmd64x.c2
-rw-r--r--drivers/ata/pata_cs5520.c4
-rw-r--r--drivers/ata/pata_cs5530.c2
-rw-r--r--drivers/ata/pata_hpt366.c2
-rw-r--r--drivers/ata/pata_hpt3x3.c2
-rw-r--r--drivers/ata/pata_imx.c2
-rw-r--r--drivers/ata/pata_it821x.c2
-rw-r--r--drivers/ata/pata_macio.c6
-rw-r--r--drivers/ata/pata_mpc52xx.c4
-rw-r--r--drivers/ata/pata_ninja32.c2
-rw-r--r--drivers/ata/pata_ns87415.c2
-rw-r--r--drivers/ata/pata_pdc2027x.c2
-rw-r--r--drivers/ata/pata_pxa.c2
-rw-r--r--drivers/ata/pata_rdc.c2
-rw-r--r--drivers/ata/pata_rz1000.c2
-rw-r--r--drivers/ata/pata_serverworks.c2
-rw-r--r--drivers/ata/pata_sil680.c2
-rw-r--r--drivers/ata/pata_sis.c2
-rw-r--r--drivers/ata/pata_sl82c105.c2
-rw-r--r--drivers/ata/pata_triflex.c2
-rw-r--r--drivers/ata/pata_via.c2
-rw-r--r--drivers/ata/sata_fsl.c14
-rw-r--r--drivers/ata/sata_highbank.c181
-rw-r--r--drivers/ata/sata_inic162x.c2
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/ata/sata_rcar.c138
-rw-r--r--drivers/ata/sata_sil.c2
-rw-r--r--drivers/ata/sata_sil24.c2
-rw-r--r--drivers/atm/ambassador.c2
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/attribute_container.c2
-rw-r--r--drivers/base/core.c130
-rw-r--r--drivers/base/cpu.c101
-rw-r--r--drivers/base/memory.c114
-rw-r--r--drivers/base/pinctrl.c19
-rw-r--r--drivers/base/platform.c4
-rw-r--r--drivers/base/power/domain.c1
-rw-r--r--drivers/base/power/generic_ops.c23
-rw-r--r--drivers/base/power/opp.c4
-rw-r--r--drivers/base/power/qos.c6
-rw-r--r--drivers/base/power/runtime.c12
-rw-r--r--drivers/base/power/wakeup.c9
-rw-r--r--drivers/base/regmap/internal.h10
-rw-r--r--drivers/base/regmap/regcache-rbtree.c62
-rw-r--r--drivers/base/regmap/regcache.c83
-rw-r--r--drivers/base/regmap/regmap-debugfs.c8
-rw-r--r--drivers/base/regmap/regmap.c156
-rw-r--r--drivers/base/reservation.c39
-rw-r--r--drivers/bcma/Kconfig1
-rw-r--r--drivers/bcma/bcma_private.h2
-rw-r--r--drivers/bcma/core.c28
-rw-r--r--drivers/bcma/driver_chipcommon.c11
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c123
-rw-r--r--drivers/bcma/driver_chipcommon_sflash.c8
-rw-r--r--drivers/bcma/host_pci.c1
-rw-r--r--drivers/bcma/main.c19
-rw-r--r--drivers/bcma/sprom.c72
-rw-r--r--drivers/block/aoe/aoe.h11
-rw-r--r--drivers/block/aoe/aoecmd.c156
-rw-r--r--drivers/block/aoe/aoedev.c3
-rw-r--r--drivers/block/aoe/aoenet.c7
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c3
-rw-r--r--drivers/block/nbd.c11
-rw-r--r--drivers/block/rbd.c174
-rw-r--r--drivers/block/swim.c2
-rw-r--r--drivers/block/virtio_blk.c2
-rw-r--r--drivers/block/xen-blkback/xenbus.c2
-rw-r--r--drivers/block/xsysace.c4
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c1
-rw-r--r--drivers/bluetooth/btusb.c4
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/cdrom/gdrom.c2
-rw-r--r--drivers/char/agp/alpha-agp.c2
-rw-r--r--drivers/char/agp/ati-agp.c4
-rw-r--r--drivers/char/agp/frontend.c8
-rw-r--r--drivers/char/agp/nvidia-agp.c6
-rw-r--r--drivers/char/agp/parisc-agp.c2
-rw-r--r--drivers/char/hw_random/atmel-rng.c2
-rw-r--r--drivers/char/hw_random/bcm63xx-rng.c2
-rw-r--r--drivers/char/hw_random/n2-drv.c6
-rw-r--r--drivers/char/hw_random/nomadik-rng.c2
-rw-r--r--drivers/char/hw_random/octeon-rng.c4
-rw-r--r--drivers/char/hw_random/omap-rng.c6
-rw-r--r--drivers/char/hw_random/timeriomem-rng.c2
-rw-r--r--drivers/char/hw_random/tx4939-rng.c1
-rw-r--r--drivers/char/mem.c47
-rw-r--r--drivers/char/mwave/tp3780i.c1
-rw-r--r--drivers/char/ps3flash.c28
-rw-r--r--drivers/char/tile-srom.c28
-rw-r--r--drivers/char/tpm/tpm.c2
-rw-r--r--drivers/char/tpm/tpm.h2
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c4
-rw-r--r--drivers/char/tpm/tpm_tis.c17
-rw-r--r--drivers/clk/Kconfig10
-rw-r--r--drivers/clk/Makefile3
-rw-r--r--drivers/clk/clk-divider.c25
-rw-r--r--drivers/clk/clk-gate.c25
-rw-r--r--drivers/clk/clk-mux.c17
-rw-r--r--drivers/clk/clk-nspire.c153
-rw-r--r--drivers/clk/clk-ppc-corenet.c280
-rw-r--r--drivers/clk/clk-si5351.c79
-rw-r--r--drivers/clk/clk-si5351.h1
-rw-r--r--drivers/clk/clk-twl6040.c4
-rw-r--r--drivers/clk/clk-vt8500.c75
-rw-r--r--drivers/clk/clk-wm831x.c14
-rw-r--r--drivers/clk/clk.c100
-rw-r--r--drivers/clk/rockchip/Makefile5
-rw-r--r--drivers/clk/rockchip/clk-rockchip.c94
-rw-r--r--drivers/clk/samsung/clk-exynos4.c21
-rw-r--r--drivers/clk/samsung/clk.h3
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c35
-rw-r--r--drivers/clk/tegra/clk-pll.c281
-rw-r--r--drivers/clk/tegra/clk-tegra114.c270
-rw-r--r--drivers/clk/tegra/clk-tegra20.c3
-rw-r--r--drivers/clk/tegra/clk-tegra30.c25
-rw-r--r--drivers/clk/tegra/clk.c12
-rw-r--r--drivers/clk/tegra/clk.h62
-rw-r--r--drivers/clk/ux500/abx500-clk.c8
-rw-r--r--drivers/clk/ux500/u8540_clk.c564
-rw-r--r--drivers/clk/ux500/u9540_clk.c4
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c4
-rw-r--r--drivers/clk/x86/clk-lpt.c4
-rw-r--r--drivers/clocksource/Kconfig5
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/arm_arch_timer.c23
-rw-r--r--drivers/clocksource/bcm2835_timer.c2
-rw-r--r--drivers/clocksource/clksrc-dbx500-prcmu.c3
-rw-r--r--drivers/clocksource/dummy_timer.c69
-rw-r--r--drivers/clocksource/dw_apb_timer.c12
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c6
-rw-r--r--drivers/clocksource/metag_generic.c2
-rw-r--r--drivers/clocksource/mxs_timer.c2
-rw-r--r--drivers/clocksource/nomadik-mtu.c2
-rw-r--r--drivers/clocksource/samsung_pwm_timer.c2
-rw-r--r--drivers/clocksource/tegra20_timer.c2
-rw-r--r--drivers/clocksource/time-armada-370-xp.c2
-rw-r--r--drivers/clocksource/timer-marco.c2
-rw-r--r--drivers/clocksource/timer-prima2.c2
-rw-r--r--drivers/clocksource/vf_pit_timer.c194
-rw-r--r--drivers/clocksource/zevio-timer.c215
-rw-r--r--drivers/cpufreq/Kconfig.arm17
-rw-r--r--drivers/cpufreq/Kconfig.powerpc37
-rw-r--r--drivers/cpufreq/Kconfig.x861
-rw-r--r--drivers/cpufreq/Makefile8
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c46
-rw-r--r--drivers/cpufreq/arm_big_little.c4
-rw-r--r--drivers/cpufreq/blackfin-cpufreq.c10
-rw-r--r--drivers/cpufreq/cpufreq.c224
-rw-r--r--drivers/cpufreq/cpufreq_governor.c51
-rw-r--r--drivers/cpufreq/cpufreq_governor.h5
-rw-r--r--drivers/cpufreq/cpufreq_performance.c4
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c6
-rw-r--r--drivers/cpufreq/cpufreq_stats.c5
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c112
-rw-r--r--drivers/cpufreq/davinci-cpufreq.c3
-rw-r--r--drivers/cpufreq/dbx500-cpufreq.c4
-rw-r--r--drivers/cpufreq/e_powersaver.c11
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c10
-rw-r--r--drivers/cpufreq/freq_table.c26
-rw-r--r--drivers/cpufreq/ia64-acpi-cpufreq.c2
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c17
-rw-r--r--drivers/cpufreq/kirkwood-cpufreq.c2
-rw-r--r--drivers/cpufreq/longhaul.c16
-rw-r--r--drivers/cpufreq/loongson2_cpufreq.c2
-rw-r--r--drivers/cpufreq/omap-cpufreq.c6
-rw-r--r--drivers/cpufreq/p4-clockmod.c4
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c (renamed from arch/powerpc/platforms/pasemi/cpufreq.c)5
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c2
-rw-r--r--drivers/cpufreq/pmac32-cpufreq.c (renamed from arch/powerpc/platforms/powermac/cpufreq_32.c)0
-rw-r--r--drivers/cpufreq/pmac64-cpufreq.c (renamed from arch/powerpc/platforms/powermac/cpufreq_64.c)0
-rw-r--r--drivers/cpufreq/powernow-k6.c8
-rw-r--r--drivers/cpufreq/powernow-k7.c16
-rw-r--r--drivers/cpufreq/powernow-k8.c24
-rw-r--r--drivers/cpufreq/ppc-corenet-cpufreq.c380
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c4
-rw-r--r--drivers/cpufreq/pxa2xx-cpufreq.c8
-rw-r--r--drivers/cpufreq/pxa3xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c8
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c4
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c10
-rw-r--r--drivers/cpufreq/sc520_freq.c2
-rw-r--r--drivers/cpufreq/sparc-us2e-cpufreq.c12
-rw-r--r--drivers/cpufreq/sparc-us3-cpufreq.c8
-rw-r--r--drivers/cpufreq/spear-cpufreq.c4
-rw-r--r--drivers/cpufreq/speedstep-centrino.c8
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c23
-rw-r--r--drivers/cpuidle/Kconfig27
-rw-r--r--drivers/cpuidle/Makefile1
-rw-r--r--drivers/cpuidle/cpuidle-zynq.c83
-rw-r--r--drivers/cpuidle/cpuidle.c4
-rw-r--r--drivers/cpuidle/driver.c324
-rw-r--r--drivers/crypto/Kconfig12
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/caam/ctrl.c10
-rw-r--r--drivers/crypto/caam/desc.h22
-rw-r--r--drivers/crypto/caam/desc_constr.h81
-rw-r--r--drivers/crypto/caam/pdb.h1
-rw-r--r--drivers/crypto/caam/regs.h42
-rw-r--r--drivers/crypto/dcp.c912
-rw-r--r--drivers/crypto/hifn_795x.c4
-rw-r--r--drivers/crypto/mv_cesa.c1
-rw-r--r--drivers/crypto/omap-aes.c36
-rw-r--r--drivers/crypto/omap-sham.c7
-rw-r--r--drivers/crypto/picoxcell_crypto.c2
-rw-r--r--drivers/crypto/s5p-sss.c2
-rw-r--r--drivers/crypto/talitos.c60
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c2
-rw-r--r--drivers/devfreq/Kconfig12
-rw-r--r--drivers/devfreq/Makefile3
-rw-r--r--drivers/devfreq/devfreq.c27
-rw-r--r--drivers/devfreq/exynos/Makefile3
-rw-r--r--drivers/devfreq/exynos/exynos4_bus.c (renamed from drivers/devfreq/exynos4_bus.c)1
-rw-r--r--drivers/devfreq/exynos/exynos5_bus.c503
-rw-r--r--drivers/devfreq/exynos/exynos_ppmu.c56
-rw-r--r--drivers/devfreq/exynos/exynos_ppmu.h78
-rw-r--r--drivers/dma/Kconfig26
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/amba-pl08x.c8
-rw-r--r--drivers/dma/at_hdmac.c211
-rw-r--r--drivers/dma/at_hdmac_regs.h5
-rw-r--r--drivers/dma/dma-jz4740.c617
-rw-r--r--drivers/dma/dmaengine.c7
-rw-r--r--drivers/dma/dw/Kconfig29
-rw-r--r--drivers/dma/dw/Makefile8
-rw-r--r--drivers/dma/dw/core.c (renamed from drivers/dma/dw_dmac.c)320
-rw-r--r--drivers/dma/dw/internal.h70
-rw-r--r--drivers/dma/dw/pci.c101
-rw-r--r--drivers/dma/dw/platform.c317
-rw-r--r--drivers/dma/dw/regs.h (renamed from drivers/dma/dw_dmac_regs.h)7
-rw-r--r--drivers/dma/fsldma.c5
-rw-r--r--drivers/dma/imx-dma.c77
-rw-r--r--drivers/dma/imx-sdma.c40
-rw-r--r--drivers/dma/intel_mid_dma.c2
-rw-r--r--drivers/dma/ioat/dma.c3
-rw-r--r--drivers/dma/ioat/dma_v2.h1
-rw-r--r--drivers/dma/ioat/dma_v3.c114
-rw-r--r--drivers/dma/ioat/hw.h27
-rw-r--r--drivers/dma/iop-adma.c70
-rw-r--r--drivers/dma/mmp_tdma.c4
-rw-r--r--drivers/dma/mv_xor.c85
-rw-r--r--drivers/dma/mv_xor.h1
-rw-r--r--drivers/dma/mxs-dma.c2
-rw-r--r--drivers/dma/of-dma.c17
-rw-r--r--drivers/dma/pl330.c33
-rw-r--r--drivers/dma/ppc4xx/adma.c52
-rw-r--r--drivers/dma/sh/Makefile2
-rw-r--r--drivers/dma/sh/shdma-base.c26
-rw-r--r--drivers/dma/sh/shdma-of.c82
-rw-r--r--drivers/dma/sh/shdma.c33
-rw-r--r--drivers/dma/sirf-dma.c17
-rw-r--r--drivers/dma/tegra20-apb-dma.c3
-rw-r--r--drivers/dma/timb_dma.c2
-rw-r--r--drivers/edac/amd64_edac_inj.c10
-rw-r--r--drivers/edac/edac_mc_sysfs.c2
-rw-r--r--drivers/edac/i7core_edac.c10
-rw-r--r--drivers/edac/mce_amd.c5
-rw-r--r--drivers/edac/mce_amd_inj.c4
-rw-r--r--drivers/extcon/extcon-class.c2
-rw-r--r--drivers/firewire/core-device.c39
-rw-r--r--drivers/firewire/net.c50
-rw-r--r--drivers/firewire/sbp2.c17
-rw-r--r--drivers/firmware/dmi_scan.c12
-rw-r--r--drivers/firmware/efi/efi-pstore.c11
-rw-r--r--drivers/gpio/Kconfig4
-rw-r--r--drivers/gpio/devres.c14
-rw-r--r--drivers/gpio/gpio-bt8xx.c2
-rw-r--r--drivers/gpio/gpio-grgpio.c6
-rw-r--r--drivers/gpio/gpio-ich.c8
-rw-r--r--drivers/gpio/gpio-langwell.c170
-rw-r--r--drivers/gpio/gpio-lynxpoint.c1
-rw-r--r--drivers/gpio/gpio-ml-ioh.c1
-rw-r--r--drivers/gpio/gpio-msm-v1.c12
-rw-r--r--drivers/gpio/gpio-omap.c2
-rw-r--r--drivers/gpio/gpio-rcar.c9
-rw-r--r--drivers/gpio/gpio-rdc321x.c7
-rw-r--r--drivers/gpio/gpio-sta2x11.c6
-rw-r--r--drivers/gpio/gpio-stmpe.c7
-rw-r--r--drivers/gpio/gpio-sx150x.c18
-rw-r--r--drivers/gpio/gpio-tc3589x.c1
-rw-r--r--drivers/gpio/gpio-timberdale.c2
-rw-r--r--drivers/gpio/gpio-vx855.c2
-rw-r--r--drivers/gpio/gpio-xilinx.c144
-rw-r--r--drivers/gpio/gpiolib.c8
-rw-r--r--drivers/gpu/drm/Kconfig3
-rw-r--r--drivers/gpu/drm/Makefile4
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h20
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c5
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c31
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h21
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c5
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c33
-rw-r--r--drivers/gpu/drm/drm_bufs.c26
-rw-r--r--drivers/gpu/drm/drm_crtc.c191
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c45
-rw-r--r--drivers/gpu/drm/drm_drv.c1
-rw-r--r--drivers/gpu/drm/drm_edid.c115
-rw-r--r--drivers/gpu/drm/drm_edid_load.c9
-rw-r--r--drivers/gpu/drm/drm_fb_cma_helper.c4
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c43
-rw-r--r--drivers/gpu/drm/drm_fops.c25
-rw-r--r--drivers/gpu/drm/drm_gem.c113
-rw-r--r--drivers/gpu/drm/drm_gem_cma_helper.c205
-rw-r--r--drivers/gpu/drm/drm_ioctl.c15
-rw-r--r--drivers/gpu/drm/drm_mm.c45
-rw-r--r--drivers/gpu/drm/drm_modes.c14
-rw-r--r--drivers/gpu/drm/drm_pci.c8
-rw-r--r--drivers/gpu/drm/drm_prime.c188
-rw-r--r--drivers/gpu/drm/drm_rect.c295
-rw-r--r--drivers/gpu/drm/drm_stub.c14
-rw-r--r--drivers/gpu/drm/drm_sysfs.c33
-rw-r--r--drivers/gpu/drm/drm_trace.h6
-rw-r--r--drivers/gpu/drm/drm_vm.c24
-rw-r--r--drivers/gpu/drm/exynos/exynos_ddc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.c20
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.c51
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_core.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c39
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c29
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c28
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c129
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c146
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c18
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c38
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c102
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c63
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.h6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c202
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c16
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c53
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c53
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c131
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmiphy.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c124
-rw-r--r--drivers/gpu/drm/exynos/regs-mixer.h7
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/dvo_ch7xxx.c28
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c473
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c90
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c116
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h359
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c293
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c118
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c18
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c114
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c31
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c1034
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h708
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c10
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c74
-rw-r--r--drivers/gpu/drm/i915/i915_ums.c90
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c100
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c35
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c754
-rw-r--r--drivers/gpu/drm/i915/intel_display.c3130
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c670
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h186
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c31
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c28
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c158
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c313
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c110
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c17
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c296
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c1387
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c236
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h31
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c168
-rw-r--r--drivers/gpu/drm/i915/intel_sideband.c177
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c229
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c11
-rw-r--r--drivers/gpu/drm/mgag200/Makefile2
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_cursor.c275
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h44
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c5
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c25
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c72
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_reg.h6
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c32
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig7
-rw-r--r--drivers/gpu/drm/nouveau/Makefile34
-rw-r--r--drivers/gpu/drm/nouveau/core/core/mm.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c27
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c93
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nva3.c21
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nve0.c47
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv50.c36
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nvc0.c36
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nve0.c23
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c12
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c14
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/falcon.c (renamed from drivers/gpu/drm/nouveau/core/core/falcon.c)3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c57
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c4073
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c823
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c99
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c370
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c290
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c515
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c2793
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c1018
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c328
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc)69
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc404
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc530
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h664
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc42
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h475
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc442
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h576
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc42
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h475
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc724
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc855
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h1173
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h921
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc779
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h1124
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h918
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc89
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc400
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.c18
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c1116
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h225
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c144
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c141
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c167
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c165
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nve0.c807
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nve4.c354
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c248
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nv84.c27
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nv98.c93
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nve0.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/xtensa.c170
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/device.h5
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/mm.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/bsp.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/copy.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/falcon.h (renamed from drivers/gpu/drm/nouveau/core/include/core/falcon.h)0
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/graph.h10
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/mpeg.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/vp.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/xtensa.h38
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/clock.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/devinit.h21
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/fb.h95
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/vm.h5
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c13
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c274
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c45
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c37
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c36
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pll.h4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c17
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c18
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/base.c23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c329
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c5
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c78
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c87
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c90
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h25
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/base.c125
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c54
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c20
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c32
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c26
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c25
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c7
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c25
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c199
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c143
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/priv.h87
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c95
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c61
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c63
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c65
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c62
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c55
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c232
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c186
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/base.c44
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c56
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c57
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c116
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c27
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c73
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c84
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_prime.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c28
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c18
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nva3_pm.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_pm.c8
-rw-r--r--drivers/gpu/drm/omapdrm/Kconfig2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c51
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c27
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c14
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c35
-rw-r--r--drivers/gpu/drm/qxl/qxl_cmd.c17
-rw-r--r--drivers/gpu/drm/qxl/qxl_display.c252
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.c138
-rw-r--r--drivers/gpu/drm/qxl/qxl_drv.h18
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c16
-rw-r--r--drivers/gpu/drm/qxl/qxl_ioctl.c6
-rw-r--r--drivers/gpu/drm/qxl/qxl_kms.c24
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.c10
-rw-r--r--drivers/gpu/drm/qxl/qxl_object.h5
-rw-r--r--drivers/gpu/drm/radeon/Makefile5
-rw-r--r--drivers/gpu/drm/radeon/ObjectID.h40
-rw-r--r--drivers/gpu/drm/radeon/atombios.h547
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c91
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c51
-rw-r--r--drivers/gpu/drm/radeon/btc_dpm.c2751
-rw-r--r--drivers/gpu/drm/radeon/btc_dpm.h57
-rw-r--r--drivers/gpu/drm/radeon/btcd.h181
-rw-r--r--drivers/gpu/drm/radeon/cik.c6987
-rw-r--r--drivers/gpu/drm/radeon/cik_blit_shaders.c246
-rw-r--r--drivers/gpu/drm/radeon/cik_blit_shaders.h32
-rw-r--r--drivers/gpu/drm/radeon/cik_reg.h147
-rw-r--r--drivers/gpu/drm/radeon/cikd.h1297
-rw-r--r--drivers/gpu/drm/radeon/clearstate_cayman.h1081
-rw-r--r--drivers/gpu/drm/radeon/clearstate_defs.h44
-rw-r--r--drivers/gpu/drm/radeon/clearstate_evergreen.h1080
-rw-r--r--drivers/gpu/drm/radeon/clearstate_si.h941
-rw-r--r--drivers/gpu/drm/radeon/cypress_dpm.c2189
-rw-r--r--drivers/gpu/drm/radeon/cypress_dpm.h160
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c650
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c11
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h12
-rw-r--r--drivers/gpu/drm/radeon/evergreen_smc.h67
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h389
-rw-r--r--drivers/gpu/drm/radeon/mkregtable.c13
-rw-r--r--drivers/gpu/drm/radeon/ni.c198
-rw-r--r--drivers/gpu/drm/radeon/ni_dpm.c4370
-rw-r--r--drivers/gpu/drm/radeon/ni_dpm.h250
-rw-r--r--drivers/gpu/drm/radeon/nid.h565
-rw-r--r--drivers/gpu/drm/radeon/nislands_smc.h329
-rw-r--r--drivers/gpu/drm/radeon/ppsmc.h116
-rw-r--r--drivers/gpu/drm/radeon/r100.c11
-rw-r--r--drivers/gpu/drm/radeon/r600.c147
-rw-r--r--drivers/gpu/drm/radeon/r600_dpm.c1048
-rw-r--r--drivers/gpu/drm/radeon/r600_dpm.h227
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c11
-rw-r--r--drivers/gpu/drm/radeon/r600_reg.h6
-rw-r--r--drivers/gpu/drm/radeon/r600d.h232
-rw-r--r--drivers/gpu/drm/radeon/radeon.h535
-rw-r--r--drivers/gpu/drm/radeon/radeon_acpi.c145
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c718
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h204
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c885
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c19
-rw-r--r--drivers/gpu/drm/radeon/radeon_cursor.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c106
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_family.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c20
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c41
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h94
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c41
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h30
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c721
-rw-r--r--drivers/gpu/drm/radeon/radeon_prime.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_reg.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c51
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c75
-rw-r--r--drivers/gpu/drm/radeon/radeon_ucode.h129
-rw-r--r--drivers/gpu/drm/radeon/radeon_uvd.c59
-rw-r--r--drivers/gpu/drm/radeon/rs690.c291
-rw-r--r--drivers/gpu/drm/radeon/rs780_dpm.c963
-rw-r--r--drivers/gpu/drm/radeon/rs780_dpm.h109
-rw-r--r--drivers/gpu/drm/radeon/rs780d.h168
-rw-r--r--drivers/gpu/drm/radeon/rv515.c224
-rw-r--r--drivers/gpu/drm/radeon/rv6xx_dpm.c2085
-rw-r--r--drivers/gpu/drm/radeon/rv6xx_dpm.h95
-rw-r--r--drivers/gpu/drm/radeon/rv6xxd.h246
-rw-r--r--drivers/gpu/drm/radeon/rv730_dpm.c508
-rw-r--r--drivers/gpu/drm/radeon/rv730d.h165
-rw-r--r--drivers/gpu/drm/radeon/rv740_dpm.c416
-rw-r--r--drivers/gpu/drm/radeon/rv740d.h117
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.c2521
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.h289
-rw-r--r--drivers/gpu/drm/radeon/rv770_smc.c621
-rw-r--r--drivers/gpu/drm/radeon/rv770_smc.h209
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h283
-rw-r--r--drivers/gpu/drm/radeon/si.c1337
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c6432
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.h227
-rw-r--r--drivers/gpu/drm/radeon/si_smc.c284
-rw-r--r--drivers/gpu/drm/radeon/sid.h603
-rw-r--r--drivers/gpu/drm/radeon/sislands_smc.h397
-rw-r--r--drivers/gpu/drm/radeon/sumo_dpm.c1876
-rw-r--r--drivers/gpu/drm/radeon/sumo_dpm.h220
-rw-r--r--drivers/gpu/drm/radeon/sumo_smc.c222
-rw-r--r--drivers/gpu/drm/radeon/sumod.h372
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.c1949
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.h132
-rw-r--r--drivers/gpu/drm/radeon/trinity_smc.c122
-rw-r--r--drivers/gpu/drm/radeon/trinityd.h228
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig9
-rw-r--r--drivers/gpu/drm/rcar-du/Makefile8
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c595
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h50
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c325
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h66
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c265
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.h62
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_lvds.c216
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_lvds.h24
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c507
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.h67
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_regs.h445
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vga.c149
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vga.h24
-rw-r--r--drivers/gpu/drm/savage/savage_bci.c43
-rw-r--r--drivers/gpu/drm/savage/savage_drv.h5
-rw-r--r--drivers/gpu/drm/shmobile/Kconfig2
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_drv.c35
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_kms.c2
-rw-r--r--drivers/gpu/drm/shmobile/shmob_drm_plane.c9
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c122
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c37
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h25
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_panel.c2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_regs.h1
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_slave.c51
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_tfp410.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c239
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_manager.c8
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo_util.c6
-rw-r--r--drivers/gpu/drm/ttm/ttm_execbuf_util.c86
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c15
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c5
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c10
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c14
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c3
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c27
-rw-r--r--drivers/gpu/host1x/dev.h8
-rw-r--r--drivers/gpu/host1x/drm/dc.c5
-rw-r--r--drivers/gpu/host1x/drm/drm.c14
-rw-r--r--drivers/gpu/host1x/drm/gr2d.c12
-rw-r--r--drivers/gpu/host1x/hw/cdma_hw.c2
-rw-r--r--drivers/gpu/host1x/hw/syncpt_hw.c12
-rw-r--r--drivers/gpu/host1x/job.c135
-rw-r--r--drivers/gpu/host1x/syncpt.c26
-rw-r--r--drivers/gpu/host1x/syncpt.h13
-rw-r--r--drivers/hid/Kconfig63
-rw-r--r--drivers/hid/Makefile9
-rw-r--r--drivers/hid/hid-apple.c6
-rw-r--r--drivers/hid/hid-core.c18
-rw-r--r--drivers/hid/hid-elo.c273
-rw-r--r--drivers/hid/hid-holtek-mouse.c77
-rw-r--r--drivers/hid/hid-huion.c177
-rw-r--r--drivers/hid/hid-hyperv.c4
-rw-r--r--drivers/hid/hid-ids.h25
-rw-r--r--drivers/hid/hid-input.c11
-rw-r--r--drivers/hid/hid-kye.c21
-rw-r--r--drivers/hid/hid-multitouch.c34
-rw-r--r--drivers/hid/hid-ps3remote.c204
-rw-r--r--drivers/hid/hid-roccat.c16
-rw-r--r--drivers/hid/hid-sony.c473
-rw-r--r--drivers/hid/hid-wacom.c14
-rw-r--r--drivers/hid/hid-wiimote-core.c1658
-rw-r--r--drivers/hid/hid-wiimote-debug.c14
-rw-r--r--drivers/hid/hid-wiimote-ext.c849
-rw-r--r--drivers/hid/hid-wiimote-modules.c2086
-rw-r--r--drivers/hid/hid-wiimote.h217
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c20
-rw-r--r--drivers/hsi/hsi.c2
-rw-r--r--drivers/hwmon/Kconfig21
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/abituguru3.c1
-rw-r--r--drivers/hwmon/adm1021.c32
-rw-r--r--drivers/hwmon/adt7470.c2
-rw-r--r--drivers/hwmon/coretemp.c2
-rw-r--r--drivers/hwmon/ds1621.c226
-rw-r--r--drivers/hwmon/g762.c1149
-rw-r--r--drivers/hwmon/i5k_amb.c2
-rw-r--r--drivers/hwmon/iio_hwmon.c1
-rw-r--r--drivers/hwmon/ina2xx.c5
-rw-r--r--drivers/hwmon/lm63.c5
-rw-r--r--drivers/hwmon/lm90.c4
-rw-r--r--drivers/hwmon/nct6775.c92
-rw-r--r--drivers/hwmon/ntc_thermistor.c1
-rw-r--r--drivers/hwmon/w83627ehf.c2
-rw-r--r--drivers/i2c/busses/Kconfig35
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c47
-rw-r--r--drivers/i2c/busses/i2c-cpm.c12
-rw-r--r--drivers/i2c/busses/i2c-davinci.c8
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c30
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h1
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c19
-rw-r--r--drivers/i2c/busses/i2c-i801.c3
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c4
-rw-r--r--drivers/i2c/busses/i2c-imx.c15
-rw-r--r--drivers/i2c/busses/i2c-intel-mid.c1121
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c2
-rw-r--r--drivers/i2c/busses/i2c-kempld.c410
-rw-r--r--drivers/i2c/busses/i2c-mpc.c4
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c321
-rw-r--r--drivers/i2c/busses/i2c-mxs.c6
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c142
-rw-r--r--drivers/i2c/busses/i2c-omap.c23
-rw-r--r--drivers/i2c/busses/i2c-piix4.c3
-rw-r--r--drivers/i2c/busses/i2c-pxa.c6
-rw-r--r--drivers/i2c/busses/i2c-rcar.c7
-rw-r--r--drivers/i2c/busses/i2c-wmt.c479
-rw-r--r--drivers/i2c/i2c-core.c2
-rw-r--r--drivers/ide/delkin_cb.c13
-rw-r--r--drivers/ide/gayle.c15
-rw-r--r--drivers/ide/ide-cd.c2
-rw-r--r--drivers/ide/ide-gd.c2
-rw-r--r--drivers/ide/ide-probe.c4
-rw-r--r--drivers/ide/ide-tape.c2
-rw-r--r--drivers/ide/ide-taskfile.c5
-rw-r--r--drivers/ide/tx4938ide.c13
-rw-r--r--drivers/ide/tx4939ide.c13
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c132
-rw-r--r--drivers/infiniband/core/cma.c4
-rw-r--r--drivers/infiniband/core/sysfs.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c5
-rw-r--r--drivers/infiniband/hw/mlx4/main.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c2
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c270
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.h5
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c27
-rw-r--r--drivers/input/evdev.c133
-rw-r--r--drivers/input/keyboard/Kconfig11
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/amikbd.c1
-rw-r--r--drivers/input/keyboard/bf54x-keys.c2
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c54
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c2
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c7
-rw-r--r--drivers/input/keyboard/gpio_keys.c1
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c2
-rw-r--r--drivers/input/keyboard/jornada680_kbd.c2
-rw-r--r--drivers/input/keyboard/jornada720_kbd.c2
-rw-r--r--drivers/input/keyboard/matrix_keypad.c2
-rw-r--r--drivers/input/keyboard/nspire-keypad.c283
-rw-r--r--drivers/input/keyboard/omap4-keypad.c2
-rw-r--r--drivers/input/keyboard/opencores-kbd.c2
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c2
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c312
-rw-r--r--drivers/input/keyboard/pxa930_rotary.c1
-rw-r--r--drivers/input/keyboard/samsung-keypad.c54
-rw-r--r--drivers/input/keyboard/sh_keysc.c2
-rw-r--r--drivers/input/keyboard/spear-keyboard.c1
-rw-r--r--drivers/input/keyboard/tnetv107x-keypad.c2
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c3
-rw-r--r--drivers/input/keyboard/w90p910_keypad.c5
-rw-r--r--drivers/input/misc/Kconfig10
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/ab8500-ponkey.c2
-rw-r--r--drivers/input/misc/bfin_rotary.c1
-rw-r--r--drivers/input/misc/da9055_onkey.c2
-rw-r--r--drivers/input/misc/gpio_tilt_polled.c2
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c5
-rw-r--r--drivers/input/misc/m68kspkr.c1
-rw-r--r--drivers/input/misc/max8925_onkey.c2
-rw-r--r--drivers/input/misc/mc13783-pwrbutton.c1
-rw-r--r--drivers/input/misc/pcspkr.c1
-rw-r--r--drivers/input/misc/pm8xxx-vibrator.c2
-rw-r--r--drivers/input/misc/pmic8xxx-pwrkey.c4
-rw-r--r--drivers/input/misc/pwm-beeper.c1
-rw-r--r--drivers/input/misc/rotary_encoder.c2
-rw-r--r--drivers/input/misc/sgi_btns.c7
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c165
-rw-r--r--drivers/input/misc/sparcspkr.c14
-rw-r--r--drivers/input/mouse/amimouse.c1
-rw-r--r--drivers/input/mouse/bcm5974.c36
-rw-r--r--drivers/input/mouse/gpio_mouse.c3
-rw-r--r--drivers/input/mouse/navpoint.c2
-rw-r--r--drivers/input/serio/Kconfig10
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/altera_ps2.c1
-rw-r--r--drivers/input/serio/at32psif.c2
-rw-r--r--drivers/input/serio/olpc_apsp.c287
-rw-r--r--drivers/input/serio/q40kbd.c1
-rw-r--r--drivers/input/serio/xilinx_ps2.c2
-rw-r--r--drivers/input/touchscreen/88pm860x-ts.c3
-rw-r--r--drivers/input/touchscreen/Kconfig31
-rw-r--r--drivers/input/touchscreen/Makefile5
-rw-r--r--drivers/input/touchscreen/atmel-wm97xx.c2
-rw-r--r--drivers/input/touchscreen/atmel_tsadcc.c10
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c2166
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.h472
-rw-r--r--drivers/input/touchscreen/cyttsp4_i2c.c90
-rw-r--r--drivers/input/touchscreen/cyttsp4_spi.c205
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c6
-rw-r--r--drivers/input/touchscreen/cyttsp_core.h11
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c50
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c_common.c79
-rw-r--r--drivers/input/touchscreen/cyttsp_spi.c38
-rw-r--r--drivers/input/touchscreen/da9052_tsi.c2
-rw-r--r--drivers/input/touchscreen/egalax_ts.c53
-rw-r--r--drivers/input/touchscreen/intel-mid-touch.c2
-rw-r--r--drivers/input/touchscreen/jornada720_ts.c2
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c2
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c289
-rw-r--r--drivers/input/touchscreen/tnetv107x-ts.c2
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c158
-rw-r--r--drivers/input/touchscreen/w90p910_ts.c2
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c14
-rw-r--r--drivers/iommu/Kconfig21
-rw-r--r--drivers/iommu/Makefile1
-rw-r--r--drivers/iommu/amd_iommu.c104
-rw-r--r--drivers/iommu/arm-smmu.c1969
-rw-r--r--drivers/iommu/dmar.c4
-rw-r--r--drivers/iommu/intel-iommu.c25
-rw-r--r--drivers/iommu/intel_irq_remapping.c3
-rw-r--r--drivers/iommu/iommu.c86
-rw-r--r--drivers/iommu/irq_remapping.c12
-rw-r--r--drivers/iommu/msm_iommu_dev.c24
-rw-r--r--drivers/iommu/omap-iommu.c15
-rw-r--r--drivers/iommu/omap-iopgtable.h2
-rw-r--r--drivers/iommu/omap-iovmm.c4
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/isdn/mISDN/dsp_pipeline.c2
-rw-r--r--drivers/leds/Kconfig6
-rw-r--r--drivers/leds/led-class.c10
-rw-r--r--drivers/leds/leds-88pm860x.c2
-rw-r--r--drivers/leds/leds-atmel-pwm.c1
-rw-r--r--drivers/leds/leds-gpio.c8
-rw-r--r--drivers/leds/leds-lp5521.c28
-rw-r--r--drivers/leds/leds-lp5523.c28
-rw-r--r--drivers/leds/leds-lp5562.c28
-rw-r--r--drivers/leds/leds-lp55xx-common.c45
-rw-r--r--drivers/leds/leds-lp55xx-common.h4
-rw-r--r--drivers/leds/leds-mc13783.c467
-rw-r--r--drivers/leds/leds-ns2.c2
-rw-r--r--drivers/leds/leds-renesas-tpu.c8
-rw-r--r--drivers/leds/leds-sunfire.c4
-rw-r--r--drivers/leds/leds-wm831x-status.c2
-rw-r--r--drivers/lguest/page_tables.c2
-rw-r--r--drivers/macintosh/adb.c2
-rw-r--r--drivers/macintosh/mac_hid.c8
-rw-r--r--drivers/macintosh/via-cuda.c2
-rw-r--r--drivers/macintosh/windfarm_pm121.c6
-rw-r--r--drivers/macintosh/windfarm_pm81.c6
-rw-r--r--drivers/macintosh/windfarm_pm91.c6
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c1
-rw-r--r--drivers/md/Kconfig14
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/bcache/bset.c4
-rw-r--r--drivers/md/bitmap.c8
-rw-r--r--drivers/md/dm-bufio.c75
-rw-r--r--drivers/md/dm-cache-target.c4
-rw-r--r--drivers/md/dm-flakey.c2
-rw-r--r--drivers/md/dm-ioctl.c127
-rw-r--r--drivers/md/dm-mpath.c8
-rw-r--r--drivers/md/dm-raid.c76
-rw-r--r--drivers/md/dm-switch.c538
-rw-r--r--drivers/md/dm-table.c35
-rw-r--r--drivers/md/dm-verity.c17
-rw-r--r--drivers/md/dm.c177
-rw-r--r--drivers/md/md.c53
-rw-r--r--drivers/md/md.h8
-rw-r--r--drivers/md/raid0.c1
-rw-r--r--drivers/md/raid1.c7
-rw-r--r--drivers/md/raid10.c83
-rw-r--r--drivers/md/raid5.c6
-rw-r--r--drivers/media/dvb-frontends/stv0367.c2
-rw-r--r--drivers/media/firewire/firedtv-fw.c19
-rw-r--r--drivers/media/i2c/tvaudio.c3
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c2
-rw-r--r--drivers/media/platform/Kconfig2
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c2
-rw-r--r--drivers/media/platform/vivi.c3
-rw-r--r--drivers/memstick/host/jmb38x_ms.c13
-rw-r--r--drivers/memstick/host/r592.c13
-rw-r--r--drivers/message/i2o/driver.c4
-rw-r--r--drivers/mfd/88pm800.c238
-rw-r--r--drivers/mfd/88pm805.c20
-rw-r--r--drivers/mfd/88pm80x.c47
-rw-r--r--drivers/mfd/88pm860x-core.c8
-rw-r--r--drivers/mfd/Kconfig36
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/aat2870-core.c5
-rw-r--r--drivers/mfd/ab3100-core.c28
-rw-r--r--drivers/mfd/ab3100-otp.c14
-rw-r--r--drivers/mfd/ab8500-core.c79
-rw-r--r--drivers/mfd/ab8500-debugfs.c36
-rw-r--r--drivers/mfd/ab8500-gpadc.c14
-rw-r--r--drivers/mfd/abx500-core.c10
-rw-r--r--drivers/mfd/adp5520.c8
-rw-r--r--drivers/mfd/arizona-core.c261
-rw-r--r--drivers/mfd/arizona-i2c.c16
-rw-r--r--drivers/mfd/arizona-irq.c8
-rw-r--r--drivers/mfd/arizona-spi.c10
-rw-r--r--drivers/mfd/arizona.h17
-rw-r--r--drivers/mfd/asic3.c14
-rw-r--r--drivers/mfd/cros_ec.c28
-rw-r--r--drivers/mfd/davinci_voicecodec.c58
-rw-r--r--drivers/mfd/db8500-prcmu.c11
-rw-r--r--drivers/mfd/dbx500-prcmu-regs.h5
-rw-r--r--drivers/mfd/htc-egpio.c13
-rw-r--r--drivers/mfd/htc-i2cpld.c15
-rw-r--r--drivers/mfd/htc-pasic3.c4
-rw-r--r--drivers/mfd/intel_msic.c1
-rw-r--r--drivers/mfd/janz-cmodio.c12
-rw-r--r--drivers/mfd/jz4740-adc.c7
-rw-r--r--drivers/mfd/kempld-core.c641
-rw-r--r--drivers/mfd/lpc_ich.c30
-rw-r--r--drivers/mfd/max77686.c26
-rw-r--r--drivers/mfd/max8925-i2c.c4
-rw-r--r--drivers/mfd/max8998-irq.c65
-rw-r--r--drivers/mfd/max8998.c67
-rw-r--r--drivers/mfd/mcp-sa11x0.c3
-rw-r--r--drivers/mfd/palmas.c146
-rw-r--r--drivers/mfd/rtl8411.c132
-rw-r--r--drivers/mfd/rtsx_pcr.c5
-rw-r--r--drivers/mfd/rtsx_pcr.h1
-rw-r--r--drivers/mfd/sec-core.c44
-rw-r--r--drivers/mfd/ssbi.c (renamed from drivers/ssbi/ssbi.c)0
-rw-r--r--drivers/mfd/t7l66xb.c1
-rw-r--r--drivers/mfd/tc6387xb.c1
-rw-r--r--drivers/mfd/tc6393xb.c1
-rw-r--r--drivers/mfd/ti_am335x_tscadc.c112
-rw-r--r--drivers/mfd/timberdale.c1
-rw-r--r--drivers/mfd/tps65912-core.c2
-rw-r--r--drivers/mfd/tps65912-i2c.c3
-rw-r--r--drivers/mfd/tps65912-spi.c3
-rw-r--r--drivers/mfd/twl-core.c70
-rw-r--r--drivers/mfd/twl4030-audio.c5
-rw-r--r--drivers/mfd/twl4030-irq.c1
-rw-r--r--drivers/mfd/twl4030-madc.c5
-rw-r--r--drivers/mfd/twl4030-power.c148
-rw-r--r--drivers/mfd/vexpress-sysreg.c10
-rw-r--r--drivers/mfd/wm5102-tables.c9
-rw-r--r--drivers/mfd/wm5110-tables.c8
-rw-r--r--drivers/mfd/wm8994-core.c25
-rw-r--r--drivers/mfd/wm8994-irq.c100
-rw-r--r--drivers/mfd/wm8997-tables.c1525
-rw-r--r--drivers/misc/atmel-ssc.c8
-rw-r--r--drivers/misc/dummy-irq.c2
-rw-r--r--drivers/misc/lattice-ecp3-config.c2
-rw-r--r--drivers/misc/mei/hbm.c2
-rw-r--r--drivers/misc/mei/init.c2
-rw-r--r--drivers/misc/sgi-gru/grufault.c5
-rw-r--r--drivers/misc/sgi-xp/xpc_main.c6
-rw-r--r--drivers/mmc/card/block.c130
-rw-r--r--drivers/mmc/card/mmc_test.c5
-rw-r--r--drivers/mmc/card/queue.c2
-rw-r--r--drivers/mmc/core/bus.c54
-rw-r--r--drivers/mmc/core/core.c200
-rw-r--r--drivers/mmc/core/core.h7
-rw-r--r--drivers/mmc/core/debugfs.c8
-rw-r--r--drivers/mmc/core/host.c32
-rw-r--r--drivers/mmc/core/mmc.c249
-rw-r--r--drivers/mmc/core/mmc_ops.c36
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/sd.c68
-rw-r--r--drivers/mmc/core/sdio.c76
-rw-r--r--drivers/mmc/core/sdio_bus.c2
-rw-r--r--drivers/mmc/host/Kconfig19
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/android-goldfish.c2
-rw-r--r--drivers/mmc/host/atmel-mci.c14
-rw-r--r--drivers/mmc/host/au1xmmc.c1
-rw-r--r--drivers/mmc/host/bfin_sdh.c2
-rw-r--r--drivers/mmc/host/cb710-mmc.c2
-rw-r--r--drivers/mmc/host/cb710-mmc.h2
-rw-r--r--drivers/mmc/host/davinci_mmc.c1
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c2
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c58
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c73
-rw-r--r--drivers/mmc/host/dw_mmc-socfpga.c140
-rw-r--r--drivers/mmc/host/dw_mmc.c65
-rw-r--r--drivers/mmc/host/dw_mmc.h3
-rw-r--r--drivers/mmc/host/jz4740_mmc.c180
-rw-r--r--drivers/mmc/host/mmci.c165
-rw-r--r--drivers/mmc/host/mmci.h4
-rw-r--r--drivers/mmc/host/mvsdio.c74
-rw-r--r--drivers/mmc/host/mxcmmc.c6
-rw-r--r--drivers/mmc/host/mxs-mmc.c11
-rw-r--r--drivers/mmc/host/omap.c18
-rw-r--r--drivers/mmc/host/omap_hsmmc.c2
-rw-r--r--drivers/mmc/host/pxamci.c2
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c2
-rw-r--r--drivers/mmc/host/sdhci-acpi.c96
-rw-r--r--drivers/mmc/host/sdhci-bcm-kona.c348
-rw-r--r--drivers/mmc/host/sdhci-bcm2835.c2
-rw-r--r--drivers/mmc/host/sdhci-cns3xxx.c2
-rw-r--r--drivers/mmc/host/sdhci-dove.c2
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c30
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h16
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c63
-rw-r--r--drivers/mmc/host/sdhci-of-hlwd.c2
-rw-r--r--drivers/mmc/host/sdhci-pci.c43
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c23
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h14
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c4
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c18
-rw-r--r--drivers/mmc/host/sdhci-s3c.c1
-rw-r--r--drivers/mmc/host/sdhci-sirf.c59
-rw-r--r--drivers/mmc/host/sdhci-spear.c2
-rw-r--r--drivers/mmc/host/sdhci-tegra.c11
-rw-r--r--drivers/mmc/host/sdhci.c63
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mmc/host/sh_mmcif.c12
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c34
-rw-r--r--drivers/mmc/host/tmio_mmc.c2
-rw-r--r--drivers/mmc/host/tmio_mmc.h21
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c48
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c40
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c2
-rw-r--r--drivers/mtd/mtdchar.c20
-rw-r--r--drivers/mtd/mtdcore.c2
-rw-r--r--drivers/mtd/ubi/build.c61
-rw-r--r--drivers/mtd/ubi/cdev.c26
-rw-r--r--drivers/mtd/ubi/fastmap.c4
-rw-r--r--drivers/net/Kconfig20
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/bonding/bond_alb.c99
-rw-r--r--drivers/net/bonding/bond_main.c290
-rw-r--r--drivers/net/bonding/bond_sysfs.c133
-rw-r--r--drivers/net/bonding/bonding.h49
-rw-r--r--drivers/net/caif/caif_serial.c61
-rw-r--r--drivers/net/can/Kconfig5
-rw-r--r--drivers/net/can/at91_can.c8
-rw-r--r--drivers/net/can/bfin_can.c10
-rw-r--r--drivers/net/can/c_can/c_can_platform.c6
-rw-r--r--drivers/net/can/cc770/cc770_isa.c5
-rw-r--r--drivers/net/can/cc770/cc770_platform.c4
-rw-r--r--drivers/net/can/flexcan.c52
-rw-r--r--drivers/net/can/grcan.c12
-rw-r--r--drivers/net/can/janz-ican3.c2
-rw-r--r--drivers/net/can/led.c4
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c10
-rw-r--r--drivers/net/can/sja1000/sja1000_isa.c5
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c6
-rw-r--r--drivers/net/can/sja1000/sja1000_platform.c5
-rw-r--r--drivers/net/can/slcan.c2
-rw-r--r--drivers/net/can/softing/softing_main.c2
-rw-r--r--drivers/net/can/ti_hecc.c1
-rw-r--r--drivers/net/ethernet/3com/3c509.c19
-rw-r--r--drivers/net/ethernet/3com/3c59x.c42
-rw-r--r--drivers/net/ethernet/3com/Kconfig1
-rw-r--r--drivers/net/ethernet/8390/ne.c1
-rw-r--r--drivers/net/ethernet/8390/ne2k-pci.c2
-rw-r--r--drivers/net/ethernet/Kconfig6
-rw-r--r--drivers/net/ethernet/Makefile2
-rw-r--r--drivers/net/ethernet/adaptec/Kconfig1
-rw-r--r--drivers/net/ethernet/adi/Kconfig1
-rw-r--r--drivers/net/ethernet/adi/bfin_mac.c4
-rw-r--r--drivers/net/ethernet/aeroflex/greth.c4
-rw-r--r--drivers/net/ethernet/allwinner/Kconfig35
-rw-r--r--drivers/net/ethernet/allwinner/Makefile5
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.c954
-rw-r--r--drivers/net/ethernet/allwinner/sun4i-emac.h108
-rw-r--r--drivers/net/ethernet/alteon/acenic.c15
-rw-r--r--drivers/net/ethernet/amd/Kconfig2
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c19
-rw-r--r--drivers/net/ethernet/amd/au1000_eth.c2
-rw-r--r--drivers/net/ethernet/amd/sunlance.c6
-rw-r--r--drivers/net/ethernet/apple/bmac.c5
-rw-r--r--drivers/net/ethernet/arc/Kconfig31
-rw-r--r--drivers/net/ethernet/arc/Makefile6
-rw-r--r--drivers/net/ethernet/arc/emac.h214
-rw-r--r--drivers/net/ethernet/arc/emac_main.c819
-rw-r--r--drivers/net/ethernet/arc/emac_mdio.c152
-rw-r--r--drivers/net/ethernet/atheros/Kconfig5
-rw-r--r--drivers/net/ethernet/atheros/alx/alx.h8
-rw-r--r--drivers/net/ethernet/atheros/alx/ethtool.c132
-rw-r--r--drivers/net/ethernet/atheros/alx/hw.c212
-rw-r--r--drivers/net/ethernet/atheros/alx/hw.h25
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c173
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c25
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c25
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c27
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig2
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.c1152
-rw-r--r--drivers/net/ethernet/broadcom/bcm63xx_enet.h86
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c18
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h185
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c211
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h75
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c52
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h3
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c115
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h5
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c687
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c284
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h55
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c89
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h9
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c33
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h5
-rw-r--r--drivers/net/ethernet/broadcom/cnic.c2
-rw-r--r--drivers/net/ethernet/broadcom/sb1250-mac.c9
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c425
-rw-r--r--drivers/net/ethernet/broadcom/tg3.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_defs.h3
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bfa_ioc.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bna.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_enet.c7
-rw-r--r--drivers/net/ethernet/brocade/bna/bna_tx_rx.c15
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c3
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.h2
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad_debugfs.c22
-rw-r--r--drivers/net/ethernet/brocade/bna/cna.h4
-rw-r--r--drivers/net/ethernet/cadence/Kconfig1
-rw-r--r--drivers/net/ethernet/cadence/at91_ether.c1
-rw-r--r--drivers/net/ethernet/cadence/macb.c327
-rw-r--r--drivers/net/ethernet/cadence/macb.h14
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/cxgb2.c15
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/cxgb3_offload.c9
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c116
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c27
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c10
-rw-r--r--drivers/net/ethernet/cirrus/Kconfig1
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c1
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c2
-rw-r--r--drivers/net/ethernet/davicom/Kconfig1
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c53
-rw-r--r--drivers/net/ethernet/dec/tulip/Kconfig1
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip_core.c6
-rw-r--r--drivers/net/ethernet/dec/tulip/xircom_cb.c14
-rw-r--r--drivers/net/ethernet/dlink/Kconfig1
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h4
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c66
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h3
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c37
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c150
-rw-r--r--drivers/net/ethernet/ethoc.c2
-rw-r--r--drivers/net/ethernet/faraday/Kconfig1
-rw-r--r--drivers/net/ethernet/faraday/ftgmac100.c2
-rw-r--r--drivers/net/ethernet/faraday/ftmac100.c2
-rw-r--r--drivers/net/ethernet/freescale/fec.h61
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c254
-rw-r--r--drivers/net/ethernet/freescale/fec_mpc52xx.c9
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c3
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/Kconfig1
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c5
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c6
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mii-fec.c6
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c57
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c4
-rw-r--r--drivers/net/ethernet/freescale/ucc_geth.c4
-rw-r--r--drivers/net/ethernet/freescale/xgmac_mdio.c4
-rw-r--r--drivers/net/ethernet/ibm/Kconfig3
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c12
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c6
-rw-r--r--drivers/net/ethernet/ibm/emac/rgmii.c18
-rw-r--r--drivers/net/ethernet/ibm/emac/tah.c14
-rw-r--r--drivers/net/ethernet/ibm/emac/zmii.c18
-rw-r--r--drivers/net/ethernet/icplus/Kconfig1
-rw-r--r--drivers/net/ethernet/icplus/ipg.c13
-rw-r--r--drivers/net/ethernet/intel/Kconfig1
-rw-r--r--drivers/net/ethernet/intel/e100.c4
-rw-r--r--drivers/net/ethernet/intel/e1000e/80003es2lan.c24
-rw-r--r--drivers/net/ethernet/intel/e1000e/82571.c30
-rw-r--r--drivers/net/ethernet/intel/e1000e/ethtool.c34
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h34
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c62
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c55
-rw-r--r--drivers/net/ethernet/intel/e1000e/nvm.c1
-rw-r--r--drivers/net/ethernet/intel/e1000e/phy.c22
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_82575.c120
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_defines.h36
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_hw.h2
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_i210.h6
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_mac.c45
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.c126
-rw-r--r--drivers/net/ethernet/intel/igb/e1000_phy.h20
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h14
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ethtool.c74
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c9
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h134
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.c23
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb.h2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82599.h1
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c40
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c2
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c69
-rw-r--r--drivers/net/ethernet/jme.c1
-rw-r--r--drivers/net/ethernet/korina.c7
-rw-r--r--drivers/net/ethernet/marvell/mv643xx_eth.c209
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c46
-rw-r--r--drivers/net/ethernet/marvell/pxa168_eth.c3
-rw-r--r--drivers/net/ethernet/marvell/skge.c2
-rw-r--r--drivers/net/ethernet/marvell/sky2.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c196
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c88
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c184
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h22
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h145
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c163
-rw-r--r--drivers/net/ethernet/micrel/Kconfig4
-rw-r--r--drivers/net/ethernet/micrel/ks8695net.c1
-rw-r--r--drivers/net/ethernet/micrel/ks8842.c1
-rw-r--r--drivers/net/ethernet/micrel/ks8851_mll.c34
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c2
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c2
-rw-r--r--drivers/net/ethernet/netx-eth.c5
-rw-r--r--drivers/net/ethernet/nuvoton/Kconfig1
-rw-r--r--drivers/net/ethernet/nuvoton/w90p910_ether.c2
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c17
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c2
-rw-r--r--drivers/net/ethernet/octeon/octeon_mgmt.c4
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/Kconfig1
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe.h2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_api.c70
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_ethtool.c2
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c327
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c63
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_phy.c26
-rw-r--r--drivers/net/ethernet/packetengines/Kconfig1
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic.h14
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_hdr.h3
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c133
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h59
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c346
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h13
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c59
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c62
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c172
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c6
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c103
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c226
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c225
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov.h4
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c62
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c36
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c126
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c13
-rw-r--r--drivers/net/ethernet/rdc/Kconfig1
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c2
-rw-r--r--drivers/net/ethernet/realtek/Kconfig3
-rw-r--r--drivers/net/ethernet/renesas/Kconfig7
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c521
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h29
-rw-r--r--drivers/net/ethernet/s6gmac.c1
-rw-r--r--drivers/net/ethernet/seeq/sgiseeq.c1
-rw-r--r--drivers/net/ethernet/sfc/efx.c42
-rw-r--r--drivers/net/ethernet/sfc/efx.h1
-rw-r--r--drivers/net/ethernet/sfc/ethtool.c16
-rw-r--r--drivers/net/ethernet/sfc/filter.c15
-rw-r--r--drivers/net/ethernet/sfc/net_driver.h5
-rw-r--r--drivers/net/ethernet/sfc/nic.c74
-rw-r--r--drivers/net/ethernet/sfc/nic.h4
-rw-r--r--drivers/net/ethernet/sfc/ptp.c13
-rw-r--r--drivers/net/ethernet/sfc/rx.c35
-rw-r--r--drivers/net/ethernet/sfc/siena.c2
-rw-r--r--drivers/net/ethernet/sgi/Kconfig1
-rw-r--r--drivers/net/ethernet/sgi/ioc3-eth.c14
-rw-r--r--drivers/net/ethernet/sgi/meth.c1
-rw-r--r--drivers/net/ethernet/silan/sc92031.c14
-rw-r--r--drivers/net/ethernet/sis/Kconfig2
-rw-r--r--drivers/net/ethernet/sis/sis190.c13
-rw-r--r--drivers/net/ethernet/smsc/Kconfig7
-rw-r--r--drivers/net/ethernet/smsc/smc911x.c2
-rw-r--r--drivers/net/ethernet/smsc/smc91x.c3
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Kconfig1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c57
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c72
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/enh_desc.c95
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/norm_desc.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c160
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c48
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c34
-rw-r--r--drivers/net/ethernet/sun/cassini.c18
-rw-r--r--drivers/net/ethernet/sun/niu.c5
-rw-r--r--drivers/net/ethernet/sun/sunbmac.c6
-rw-r--r--drivers/net/ethernet/sun/sungem.c13
-rw-r--r--drivers/net/ethernet/sun/sunhme.c4
-rw-r--r--drivers/net/ethernet/sun/sunqe.c10
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw.c18
-rw-r--r--drivers/net/ethernet/ti/davinci_cpdma.c5
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c119
-rw-r--r--drivers/net/ethernet/ti/davinci_mdio.c15
-rw-r--r--drivers/net/ethernet/ti/tlan.c3
-rw-r--r--drivers/net/ethernet/ti/tlan.h1
-rw-r--r--drivers/net/ethernet/toshiba/tc35815.c14
-rw-r--r--drivers/net/ethernet/tundra/tsi108_eth.c1
-rw-r--r--drivers/net/ethernet/via/Kconfig5
-rw-r--r--drivers/net/ethernet/via/via-velocity.c507
-rw-r--r--drivers/net/ethernet/via/via-velocity.h8
-rw-r--r--drivers/net/ethernet/wiznet/w5100.c2
-rw-r--r--drivers/net/ethernet/wiznet/w5300.c2
-rw-r--r--drivers/net/ethernet/xilinx/Kconfig4
-rw-r--r--drivers/net/ethernet/xilinx/ll_temac_main.c5
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c6
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_emaclite.c236
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c2
-rw-r--r--drivers/net/fddi/skfp/skfddi.c13
-rw-r--r--drivers/net/hamradio/bpqether.c7
-rw-r--r--drivers/net/hippi/rrunner.c13
-rw-r--r--drivers/net/irda/bfin_sir.c1
-rw-r--r--drivers/net/irda/sh_irda.c1
-rw-r--r--drivers/net/irda/sh_sir.c1
-rw-r--r--drivers/net/macvlan.c12
-rw-r--r--drivers/net/macvtap.c341
-rw-r--r--drivers/net/netconsole.c5
-rw-r--r--drivers/net/nlmon.c181
-rw-r--r--drivers/net/phy/Kconfig10
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/at803x.c128
-rw-r--r--drivers/net/phy/bcm63xx.c4
-rw-r--r--drivers/net/phy/marvell.c108
-rw-r--r--drivers/net/phy/mdio-sun4i.c194
-rw-r--r--drivers/net/phy/phy.c35
-rw-r--r--drivers/net/phy/phy_device.c11
-rw-r--r--drivers/net/phy/spi_ks8995.c14
-rw-r--r--drivers/net/phy/vitesse.c38
-rw-r--r--drivers/net/ppp/pppoe.c2
-rw-r--r--drivers/net/rionet.c103
-rw-r--r--drivers/net/team/team.c86
-rw-r--r--drivers/net/team/team_mode_loadbalance.c3
-rw-r--r--drivers/net/team/team_mode_roundrobin.c3
-rw-r--r--drivers/net/tun.c12
-rw-r--r--drivers/net/usb/Kconfig4
-rw-r--r--drivers/net/usb/ax88179_178a.c5
-rw-r--r--drivers/net/usb/cdc_ether.c22
-rw-r--r--drivers/net/usb/ipheth.c5
-rw-r--r--drivers/net/usb/kalmia.c45
-rw-r--r--drivers/net/usb/qmi_wwan.c4
-rw-r--r--drivers/net/usb/r8152.c14
-rw-r--r--drivers/net/veth.c7
-rw-r--r--drivers/net/virtio_net.c10
-rw-r--r--drivers/net/vxlan.c788
-rw-r--r--drivers/net/wan/dlci.c2
-rw-r--r--drivers/net/wan/hdlc.c2
-rw-r--r--drivers/net/wan/ixp4xx_hss.c1
-rw-r--r--drivers/net/wan/lapbether.c2
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/airo.c3
-rw-r--r--drivers/net/wireless/ath/Kconfig1
-rw-r--r--drivers/net/wireless/ath/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath.h13
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig39
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile20
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.c295
-rw-r--r--drivers/net/wireless/ath/ath10k/bmi.h224
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c1189
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h516
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c665
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h369
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c503
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h90
-rw-r--r--drivers/net/wireless/ath/ath10k/hif.h137
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c1000
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.h368
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c152
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h1338
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c1167
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c510
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h304
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c3069
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.h61
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c2507
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h355
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h990
-rw-r--r--drivers/net/wireless/ath/ath10k/targaddrs.h449
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.c20
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h170
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c417
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.h39
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c2081
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h3052
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c79
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h14
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c51
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c8
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c14
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c12
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig10
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c89
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h23
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_initvals.h14
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c33
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c80
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c107
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h345
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9462_2p1_initvals.h1774
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h16
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c31
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c430
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h59
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h24
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c99
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c81
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c28
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h20
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c66
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c55
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c101
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h13
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c168
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c343
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h3
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c3
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c182
-rw-r--r--drivers/net/wireless/ath/regd.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig12
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile21
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c38
-rw-r--r--drivers/net/wireless/ath/wil6210/debug.c69
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c29
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c64
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c54
-rw-r--r--drivers/net/wireless/ath/wil6210/trace.c20
-rw-r--r--drivers/net/wireless/ath/wil6210/trace.h235
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c205
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h36
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h28
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c60
-rw-r--r--drivers/net/wireless/b43/Kconfig12
-rw-r--r--drivers/net/wireless/b43/main.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c302
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c117
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c18
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c52
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c176
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fweh.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c943
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h20
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/tracepoint.h21
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c8
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c18
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/ampdu.c2
-rw-r--r--drivers/net/wireless/cw1200/Kconfig30
-rw-r--r--drivers/net/wireless/cw1200/Makefile21
-rw-r--r--drivers/net/wireless/cw1200/bh.c619
-rw-r--r--drivers/net/wireless/cw1200/bh.h28
-rw-r--r--drivers/net/wireless/cw1200/cw1200.h323
-rw-r--r--drivers/net/wireless/cw1200/cw1200_sdio.c425
-rw-r--r--drivers/net/wireless/cw1200/cw1200_spi.c471
-rw-r--r--drivers/net/wireless/cw1200/debug.c428
-rw-r--r--drivers/net/wireless/cw1200/debug.h93
-rw-r--r--drivers/net/wireless/cw1200/fwio.c520
-rw-r--r--drivers/net/wireless/cw1200/fwio.h39
-rw-r--r--drivers/net/wireless/cw1200/hwbus.h33
-rw-r--r--drivers/net/wireless/cw1200/hwio.c312
-rw-r--r--drivers/net/wireless/cw1200/hwio.h247
-rw-r--r--drivers/net/wireless/cw1200/main.c605
-rw-r--r--drivers/net/wireless/cw1200/pm.c367
-rw-r--r--drivers/net/wireless/cw1200/pm.h43
-rw-r--r--drivers/net/wireless/cw1200/queue.c583
-rw-r--r--drivers/net/wireless/cw1200/queue.h116
-rw-r--r--drivers/net/wireless/cw1200/scan.c461
-rw-r--r--drivers/net/wireless/cw1200/scan.h56
-rw-r--r--drivers/net/wireless/cw1200/sta.c2403
-rw-r--r--drivers/net/wireless/cw1200/sta.h123
-rw-r--r--drivers/net/wireless/cw1200/txrx.c1473
-rw-r--r--drivers/net/wireless/cw1200/txrx.h106
-rw-r--r--drivers/net/wireless/cw1200/wsm.c1822
-rw-r--r--drivers/net/wireless/cw1200/wsm.h1870
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c2
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c3
-rw-r--r--drivers/net/wireless/ipw2x00/libipw_rx.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c5
-rw-r--r--drivers/net/wireless/iwlegacy/3945.c18
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c25
-rw-r--r--drivers/net/wireless/iwlegacy/commands.h8
-rw-r--r--drivers/net/wireless/iwlegacy/common.c11
-rw-r--r--drivers/net/wireless/iwlegacy/common.h41
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig10
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile7
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/agn.h58
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/calib.c8
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/commands.h12
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/dev.h73
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/devices.c107
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/lib.c26
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c37
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c67
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/power.c6
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rs.c51
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rx.c42
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/scan.c12
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/testmode.c471
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tt.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c24
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/ucode.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c32
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c65
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h54
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c20
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-phy-db.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.c852
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-test.h161
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h309
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h21
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/Makefile2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/bt-coex.c29
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c197
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c453
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h98
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h233
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c37
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c97
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c299
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h204
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c212
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c37
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c76
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/power.c218
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/quota.c25
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c171
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h17
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c22
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c6
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c24
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c530
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c7
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c41
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c54
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c115
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c68
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c40
-rw-r--r--drivers/net/wireless/libertas/mesh.c2
-rw-r--r--drivers/net/wireless/mwifiex/11h.c101
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig4
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c122
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c1
-rw-r--r--drivers/net/wireless/mwifiex/fw.h33
-rw-r--r--drivers/net/wireless/mwifiex/init.c115
-rw-r--r--drivers/net/wireless/mwifiex/join.c7
-rw-r--r--drivers/net/wireless/mwifiex/main.c101
-rw-r--r--drivers/net/wireless/mwifiex/main.h32
-rw-r--r--drivers/net/wireless/mwifiex/scan.c60
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c463
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h340
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c62
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c17
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c11
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c52
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c21
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c25
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c5
-rw-r--r--drivers/net/wireless/mwl8k.c11
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.h2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c3
-rw-r--r--drivers/net/wireless/p54/p54spi.c37
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c66
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c66
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c66
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h12
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c835
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c68
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c127
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c56
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c9
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c32
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h21
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c60
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c58
-rw-r--r--drivers/net/wireless/rtlwifi/base.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/sw.c6
-rw-r--r--drivers/net/wireless/ti/wl1251/spi.c30
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c47
-rw-r--r--drivers/net/wireless/ti/wl18xx/reg.h15
-rw-r--r--drivers/net/wireless/ti/wlcore/Makefile2
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c4
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c284
-rw-r--r--drivers/net/wireless/ti/wlcore/ps.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/spi.c14
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.c216
-rw-r--r--drivers/net/wireless/ti/wlcore/sysfs.h28
-rw-r--r--drivers/net/wireless/ti/wlcore/tx.c2
-rw-r--r--drivers/net/xen-netback/common.h14
-rw-r--r--drivers/net/xen-netback/interface.c102
-rw-r--r--drivers/net/xen-netback/netback.c42
-rw-r--r--drivers/net/xen-netback/xenbus.c53
-rw-r--r--drivers/net/xen-netfront.c253
-rw-r--r--drivers/nfc/Kconfig10
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/mei_phy.c6
-rw-r--r--drivers/nfc/microread/microread.c6
-rw-r--r--drivers/nfc/nfcsim.c541
-rw-r--r--drivers/nfc/nfcwilink.c18
-rw-r--r--drivers/nfc/pn533.c33
-rw-r--r--drivers/nfc/pn544/pn544.c40
-rw-r--r--drivers/of/Kconfig3
-rw-r--r--drivers/of/Makefile3
-rw-r--r--drivers/of/address.c8
-rw-r--r--drivers/of/base.c12
-rw-r--r--drivers/of/fdt.c2
-rw-r--r--drivers/of/of_net.c1
-rw-r--r--drivers/of/pdt.c2
-rw-r--r--drivers/parisc/eisa_eeprom.c15
-rw-r--r--drivers/parisc/lba_pci.c56
-rw-r--r--drivers/parport/Kconfig4
-rw-r--r--drivers/parport/share.c3
-rw-r--r--drivers/pci/bus.c15
-rw-r--r--drivers/pci/hotplug/cpqphp_sysfs.c22
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c4
-rw-r--r--drivers/pci/hotplug/s390_pci_hpc.c60
-rw-r--r--drivers/pci/hotplug/shpchp_core.c3
-rw-r--r--drivers/pci/ioapic.c13
-rw-r--r--drivers/pci/iov.c65
-rw-r--r--drivers/pci/msi.c10
-rw-r--r--drivers/pci/pci-acpi.c10
-rw-r--r--drivers/pci/pci-driver.c14
-rw-r--r--drivers/pci/pci-sysfs.c48
-rw-r--r--drivers/pci/pci.c14
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h4
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c47
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c17
-rw-r--r--drivers/pci/pcie/aspm.c29
-rw-r--r--drivers/pci/pcie/pme.c2
-rw-r--r--drivers/pci/probe.c115
-rw-r--r--drivers/pci/proc.c23
-rw-r--r--drivers/pci/quirks.c33
-rw-r--r--drivers/pci/xen-pcifront.c7
-rw-r--r--drivers/pinctrl/Kconfig44
-rw-r--r--drivers/pinctrl/Makefile9
-rw-r--r--drivers/pinctrl/core.c171
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-dove.c244
-rw-r--r--drivers/pinctrl/pinconf-generic.c104
-rw-r--r--drivers/pinctrl/pinconf.c174
-rw-r--r--drivers/pinctrl/pinconf.h6
-rw-r--r--drivers/pinctrl/pinctrl-abx500.c481
-rw-r--r--drivers/pinctrl/pinctrl-at91.c7
-rw-r--r--drivers/pinctrl/pinctrl-baytrail.c543
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c2
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c1
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c86
-rw-r--r--drivers/pinctrl/pinctrl-exynos5440.c13
-rw-r--r--drivers/pinctrl/pinctrl-imx.c53
-rw-r--r--drivers/pinctrl/pinctrl-imx.h4
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c2
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c6
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c1394
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/pinctrl-single.c242
-rw-r--r--drivers/pinctrl/pinctrl-st.c1403
-rw-r--r--drivers/pinctrl/pinctrl-sunxi-pins.h2023
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.c1520
-rw-r--r--drivers/pinctrl/pinctrl-sunxi.h68
-rw-r--r--drivers/pinctrl/pinctrl-tz1090-pdc.c1024
-rw-r--r--drivers/pinctrl/pinctrl-tz1090.c2072
-rw-r--r--drivers/pinctrl/pinctrl-u300.c1
-rw-r--r--drivers/pinctrl/pinctrl-vf610.c338
-rw-r--r--drivers/pinctrl/sh-pfc/core.c65
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c205
-rw-r--r--drivers/pinctrl/sirf/Makefile5
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas6.c947
-rw-r--r--drivers/pinctrl/sirf/pinctrl-prima2.c (renamed from drivers/pinctrl/pinctrl-sirf.c)949
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c929
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.h116
-rw-r--r--drivers/pinctrl/spear/pinctrl-plgpio.c9
-rw-r--r--drivers/pinctrl/vt8500/pinctrl-wmt.c8
-rw-r--r--drivers/platform/x86/wmi.c2
-rw-r--r--drivers/pnp/isapnp/proc.c22
-rw-r--r--drivers/pnp/manager.c14
-rw-r--r--drivers/power/88pm860x_battery.c1
-rw-r--r--drivers/power/88pm860x_charger.c1
-rw-r--r--drivers/power/ab8500_btemp.c1
-rw-r--r--drivers/power/ab8500_charger.c2
-rw-r--r--drivers/power/ab8500_fg.c7
-rw-r--r--drivers/power/abx500_chargalg.c1
-rw-r--r--drivers/power/avs/smartreflex.c154
-rw-r--r--drivers/power/bq27x00_battery.c2
-rw-r--r--drivers/power/charger-manager.c146
-rw-r--r--drivers/power/generic-adc-battery.c4
-rw-r--r--drivers/power/gpio-charger.c2
-rw-r--r--drivers/power/intel_mid_battery.c2
-rw-r--r--drivers/power/jz4740-battery.c4
-rw-r--r--drivers/power/lp8727_charger.c68
-rw-r--r--drivers/power/pcf50633-charger.c8
-rw-r--r--drivers/power/pm2301_charger.c11
-rw-r--r--drivers/power/power_supply_core.c4
-rw-r--r--drivers/power/reset/Kconfig3
-rw-r--r--drivers/power/reset/restart-poweroff.c3
-rw-r--r--drivers/power/reset/vexpress-poweroff.c2
-rw-r--r--drivers/power/rx51_battery.c5
-rw-r--r--drivers/power/sbs-battery.c1
-rw-r--r--drivers/power/tps65090-charger.c40
-rw-r--r--drivers/power/twl4030_charger.c2
-rw-r--r--drivers/pps/clients/pps-gpio.c165
-rw-r--r--drivers/pwm/Kconfig23
-rw-r--r--drivers/pwm/Makefile3
-rw-r--r--drivers/pwm/core.c29
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c5
-rw-r--r--drivers/pwm/pwm-bfin.c1
-rw-r--r--drivers/pwm/pwm-imx.c1
-rw-r--r--drivers/pwm/pwm-lpc32xx.c1
-rw-r--r--drivers/pwm/pwm-mxs.c7
-rw-r--r--drivers/pwm/pwm-pca9685.c300
-rw-r--r--drivers/pwm/pwm-puv3.c1
-rw-r--r--drivers/pwm/pwm-renesas-tpu.c474
-rw-r--r--drivers/pwm/pwm-spear.c1
-rw-r--r--drivers/pwm/pwm-tegra.c1
-rw-r--r--drivers/pwm/pwm-tiehrpwm.c13
-rw-r--r--drivers/pwm/sysfs.c352
-rw-r--r--drivers/rapidio/Kconfig5
-rw-r--r--drivers/rapidio/Makefile4
-rw-r--r--drivers/rapidio/devices/Kconfig2
-rw-r--r--drivers/rapidio/devices/Makefile7
-rw-r--r--drivers/rapidio/devices/tsi721.c9
-rw-r--r--drivers/rapidio/rio-driver.c18
-rw-r--r--drivers/rapidio/rio-scan.c181
-rw-r--r--drivers/rapidio/rio-sysfs.c31
-rw-r--r--drivers/rapidio/rio.c490
-rw-r--r--drivers/rapidio/rio.h44
-rw-r--r--drivers/rapidio/switches/Kconfig19
-rw-r--r--drivers/rapidio/switches/Makefile1
-rw-r--r--drivers/rapidio/switches/idt_gen2.c98
-rw-r--r--drivers/rapidio/switches/idtcps.c86
-rw-r--r--drivers/rapidio/switches/tsi500.c78
-rw-r--r--drivers/rapidio/switches/tsi568.c71
-rw-r--r--drivers/rapidio/switches/tsi57x.c81
-rw-r--r--drivers/regulator/88pm8607.c1
-rw-r--r--drivers/regulator/Kconfig19
-rw-r--r--drivers/regulator/Makefile4
-rw-r--r--drivers/regulator/ab8500-ext.c82
-rw-r--r--drivers/regulator/ab8500.c20
-rw-r--r--drivers/regulator/core.c15
-rw-r--r--drivers/regulator/isl6271a-regulator.c2
-rw-r--r--drivers/regulator/lp3971.c11
-rw-r--r--drivers/regulator/lp3972.c11
-rw-r--r--drivers/regulator/lp872x.c116
-rw-r--r--drivers/regulator/lp8755.c1
-rw-r--r--drivers/regulator/lp8788-buck.c1
-rw-r--r--drivers/regulator/lp8788-ldo.c2
-rw-r--r--drivers/regulator/max77686.c1
-rw-r--r--drivers/regulator/max77693.c322
-rw-r--r--drivers/regulator/max8925-regulator.c1
-rw-r--r--drivers/regulator/max8973-regulator.c49
-rw-r--r--drivers/regulator/max8998.c227
-rw-r--r--drivers/regulator/mc13783-regulator.c2
-rw-r--r--drivers/regulator/mc13892-regulator.c2
-rw-r--r--drivers/regulator/of_regulator.c3
-rw-r--r--drivers/regulator/palmas-regulator.c4
-rw-r--r--drivers/regulator/pcap-regulator.c1
-rw-r--r--drivers/regulator/pcf50633-regulator.c1
-rw-r--r--drivers/regulator/s2mps11.c8
-rw-r--r--drivers/regulator/ti-abb-regulator.c910
-rw-r--r--drivers/regulator/tps62360-regulator.c8
-rw-r--r--drivers/regulator/tps65217-regulator.c2
-rw-r--r--drivers/regulator/twl-regulator.c76
-rw-r--r--drivers/regulator/virtual.c2
-rw-r--r--drivers/regulator/wm831x-dcdc.c7
-rw-r--r--drivers/regulator/wm831x-isink.c2
-rw-r--r--drivers/regulator/wm831x-ldo.c2
-rw-r--r--drivers/regulator/wm8400-regulator.c1
-rw-r--r--drivers/regulator/wm8994-regulator.c2
-rw-r--r--drivers/remoteproc/remoteproc_core.c24
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c3
-rw-r--r--drivers/remoteproc/remoteproc_internal.h4
-rw-r--r--drivers/rtc/Kconfig16
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/class.c12
-rw-r--r--drivers/rtc/interface.c26
-rw-r--r--drivers/rtc/rtc-88pm80x.c1
-rw-r--r--drivers/rtc/rtc-88pm860x.c1
-rw-r--r--drivers/rtc/rtc-ab3100.c7
-rw-r--r--drivers/rtc/rtc-ab8500.c65
-rw-r--r--drivers/rtc/rtc-at32ap700x.c22
-rw-r--r--drivers/rtc/rtc-at91rm9200.c4
-rw-r--r--drivers/rtc/rtc-at91sam9.c19
-rw-r--r--drivers/rtc/rtc-au1xxx.c8
-rw-r--r--drivers/rtc/rtc-bfin.c1
-rw-r--r--drivers/rtc/rtc-bq32k.c6
-rw-r--r--drivers/rtc/rtc-bq4802.c8
-rw-r--r--drivers/rtc/rtc-cmos.c41
-rw-r--r--drivers/rtc/rtc-coh901331.c9
-rw-r--r--drivers/rtc/rtc-da9052.c14
-rw-r--r--drivers/rtc/rtc-da9055.c8
-rw-r--r--drivers/rtc/rtc-davinci.c13
-rw-r--r--drivers/rtc/rtc-dm355evm.c7
-rw-r--r--drivers/rtc/rtc-ds1216.c19
-rw-r--r--drivers/rtc/rtc-ds1286.c6
-rw-r--r--drivers/rtc/rtc-ds1302.c15
-rw-r--r--drivers/rtc/rtc-ds1305.c32
-rw-r--r--drivers/rtc/rtc-ds1307.c43
-rw-r--r--drivers/rtc/rtc-ds1374.c11
-rw-r--r--drivers/rtc/rtc-ds1390.c6
-rw-r--r--drivers/rtc/rtc-ds1511.c93
-rw-r--r--drivers/rtc/rtc-ds1672.c6
-rw-r--r--drivers/rtc/rtc-ds3234.c8
-rw-r--r--drivers/rtc/rtc-efi.c6
-rw-r--r--drivers/rtc/rtc-em3027.c6
-rw-r--r--drivers/rtc/rtc-ep93xx.c2
-rw-r--r--drivers/rtc/rtc-fm3130.c8
-rw-r--r--drivers/rtc/rtc-generic.c6
-rw-r--r--drivers/rtc/rtc-hid-sensor-time.c48
-rw-r--r--drivers/rtc/rtc-isl12022.c12
-rw-r--r--drivers/rtc/rtc-jz4740.c68
-rw-r--r--drivers/rtc/rtc-lp8788.c8
-rw-r--r--drivers/rtc/rtc-lpc32xx.c3
-rw-r--r--drivers/rtc/rtc-ls1x.c8
-rw-r--r--drivers/rtc/rtc-m41t80.c2
-rw-r--r--drivers/rtc/rtc-m41t93.c7
-rw-r--r--drivers/rtc/rtc-m41t94.c6
-rw-r--r--drivers/rtc/rtc-m48t35.c12
-rw-r--r--drivers/rtc/rtc-m48t59.c54
-rw-r--r--drivers/rtc/rtc-m48t86.c8
-rw-r--r--drivers/rtc/rtc-max6900.c6
-rw-r--r--drivers/rtc/rtc-max6902.c12
-rw-r--r--drivers/rtc/rtc-max77686.c8
-rw-r--r--drivers/rtc/rtc-max8907.c6
-rw-r--r--drivers/rtc/rtc-max8925.c13
-rw-r--r--drivers/rtc/rtc-max8997.c8
-rw-r--r--drivers/rtc/rtc-max8998.c26
-rw-r--r--drivers/rtc/rtc-mc13xxx.c4
-rw-r--r--drivers/rtc/rtc-mpc5121.c20
-rw-r--r--drivers/rtc/rtc-msm6242.c21
-rw-r--r--drivers/rtc/rtc-mxc.c7
-rw-r--r--drivers/rtc/rtc-nuc900.c8
-rw-r--r--drivers/rtc/rtc-omap.c6
-rw-r--r--drivers/rtc/rtc-palmas.c2
-rw-r--r--drivers/rtc/rtc-pcap.c13
-rw-r--r--drivers/rtc/rtc-pcf2123.c25
-rw-r--r--drivers/rtc/rtc-pcf2127.c241
-rw-r--r--drivers/rtc/rtc-pcf8523.c6
-rw-r--r--drivers/rtc/rtc-pcf8563.c12
-rw-r--r--drivers/rtc/rtc-pcf8583.c15
-rw-r--r--drivers/rtc/rtc-pm8xxx.c29
-rw-r--r--drivers/rtc/rtc-ps3.c6
-rw-r--r--drivers/rtc/rtc-puv3.c1
-rw-r--r--drivers/rtc/rtc-pxa.c43
-rw-r--r--drivers/rtc/rtc-rc5t583.c2
-rw-r--r--drivers/rtc/rtc-rp5c01.c12
-rw-r--r--drivers/rtc/rtc-rs5c313.c24
-rw-r--r--drivers/rtc/rtc-rs5c348.c6
-rw-r--r--drivers/rtc/rtc-rv3029c2.c8
-rw-r--r--drivers/rtc/rtc-rx4581.c6
-rw-r--r--drivers/rtc/rtc-rx8025.c18
-rw-r--r--drivers/rtc/rtc-rx8581.c6
-rw-r--r--drivers/rtc/rtc-s3c.c9
-rw-r--r--drivers/rtc/rtc-sa1100.c8
-rw-r--r--drivers/rtc/rtc-sh.c74
-rw-r--r--drivers/rtc/rtc-sirfsoc.c475
-rw-r--r--drivers/rtc/rtc-snvs.c6
-rw-r--r--drivers/rtc/rtc-spear.c1
-rw-r--r--drivers/rtc/rtc-starfire.c6
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c20
-rw-r--r--drivers/rtc/rtc-sun4v.c6
-rw-r--r--drivers/rtc/rtc-sysfs.c20
-rw-r--r--drivers/rtc/rtc-tile.c11
-rw-r--r--drivers/rtc/rtc-tps80031.c6
-rw-r--r--drivers/rtc/rtc-twl.c40
-rw-r--r--drivers/rtc/rtc-v3020.c18
-rw-r--r--drivers/rtc/rtc-vr41xx.c16
-rw-r--r--drivers/rtc/rtc-vt8500.c2
-rw-r--r--drivers/rtc/rtc-wm831x.c6
-rw-r--r--drivers/rtc/rtc-x1205.c33
-rw-r--r--drivers/s390/block/dasd.c115
-rw-r--r--drivers/s390/block/dasd_devmap.c97
-rw-r--r--drivers/s390/block/dasd_diag.c8
-rw-r--r--drivers/s390/block/dasd_eckd.c17
-rw-r--r--drivers/s390/block/dasd_erp.c8
-rw-r--r--drivers/s390/block/dasd_fba.c10
-rw-r--r--drivers/s390/block/dasd_int.h10
-rw-r--r--drivers/s390/block/dasd_ioctl.c59
-rw-r--r--drivers/s390/char/Makefile2
-rw-r--r--drivers/s390/char/sclp.c86
-rw-r--r--drivers/s390/char/sclp.h7
-rw-r--r--drivers/s390/char/sclp_cmd.c20
-rw-r--r--drivers/s390/char/sclp_con.c31
-rw-r--r--drivers/s390/char/sclp_ctl.c144
-rw-r--r--drivers/s390/char/sclp_vt220.c39
-rw-r--r--drivers/s390/char/tape_class.c2
-rw-r--r--drivers/s390/char/vmur.c2
-rw-r--r--drivers/s390/char/vmwatchdog.c5
-rw-r--r--drivers/s390/cio/airq.c167
-rw-r--r--drivers/s390/cio/chsc.c60
-rw-r--r--drivers/s390/cio/chsc.h44
-rw-r--r--drivers/s390/cio/chsc_sch.c155
-rw-r--r--drivers/s390/cio/cio.c68
-rw-r--r--drivers/s390/cio/qdio.h34
-rw-r--r--drivers/s390/cio/qdio_main.c44
-rw-r--r--drivers/s390/cio/qdio_setup.c47
-rw-r--r--drivers/s390/cio/qdio_thinint.c79
-rw-r--r--drivers/s390/crypto/ap_bus.c64
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcm_main.c2
-rw-r--r--drivers/s390/net/lcs.c2
-rw-r--r--drivers/s390/net/netiucv.c20
-rw-r--r--drivers/s390/net/qeth_core.h2
-rw-r--r--drivers/s390/net/qeth_core_main.c25
-rw-r--r--drivers/s390/net/qeth_l3_sys.c6
-rw-r--r--drivers/s390/scsi/Makefile2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c36
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c13
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c446
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c11
-rw-r--r--drivers/s390/scsi/zfcp_def.h4
-rw-r--r--drivers/s390/scsi/zfcp_erp.c3
-rw-r--r--drivers/s390/scsi/zfcp_ext.h20
-rw-r--r--drivers/s390/scsi/zfcp_fc.c2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c154
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h26
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c10
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c27
-rw-r--r--drivers/s390/scsi/zfcp_unit.c9
-rw-r--r--drivers/scsi/3w-xxxx.c4
-rw-r--r--drivers/scsi/BusLogic.c4452
-rw-r--r--drivers/scsi/BusLogic.h1487
-rw-r--r--drivers/scsi/FlashPoint.c626
-rw-r--r--drivers/scsi/Kconfig2
-rw-r--r--drivers/scsi/a3000.c13
-rw-r--r--drivers/scsi/a4000t.c15
-rw-r--r--drivers/scsi/aacraid/commctrl.c3
-rw-r--r--drivers/scsi/aacraid/commsup.c3
-rw-r--r--drivers/scsi/aacraid/src.c3
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx.seq2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c3
-rw-r--r--drivers/scsi/be2iscsi/be_main.c2
-rw-r--r--drivers/scsi/bfa/bfa_core.c3
-rw-r--r--drivers/scsi/bfa/bfa_defs.h103
-rw-r--r--drivers/scsi/bfa/bfa_defs_svc.h77
-rw-r--r--drivers/scsi/bfa/bfa_fc.h15
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c2
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c62
-rw-r--r--drivers/scsi/bfa/bfa_fcs.h34
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c209
-rw-r--r--drivers/scsi/bfa/bfa_fcs_rport.c11
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c74
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h9
-rw-r--r--drivers/scsi/bfa/bfa_ioc_cb.c86
-rw-r--r--drivers/scsi/bfa/bfa_ioc_ct.c46
-rw-r--r--drivers/scsi/bfa/bfa_svc.c700
-rw-r--r--drivers/scsi/bfa/bfa_svc.h34
-rw-r--r--drivers/scsi/bfa/bfad.c14
-rw-r--r--drivers/scsi/bfa/bfad_attr.c33
-rw-r--r--drivers/scsi/bfa/bfad_bsg.c137
-rw-r--r--drivers/scsi/bfa/bfad_bsg.h52
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c28
-rw-r--r--drivers/scsi/bfa/bfad_drv.h2
-rw-r--r--drivers/scsi/bfa/bfad_im.c10
-rw-r--r--drivers/scsi/bfa/bfi.h78
-rw-r--r--drivers/scsi/bfa/bfi_ms.h5
-rw-r--r--drivers/scsi/csiostor/csio_hw.c91
-rw-r--r--drivers/scsi/csiostor/csio_hw.h11
-rw-r--r--drivers/scsi/csiostor/csio_mb.c77
-rw-r--r--drivers/scsi/csiostor/csio_mb.h11
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c4
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c161
-rw-r--r--drivers/scsi/fcoe/fcoe.c2
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c2
-rw-r--r--drivers/scsi/fnic/fnic_debugfs.c16
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c6
-rw-r--r--drivers/scsi/ipr.c58
-rw-r--r--drivers/scsi/isci/request.c4
-rw-r--r--drivers/scsi/libfc/fc_fcp.c2
-rw-r--r--drivers/scsi/libiscsi.c18
-rw-r--r--drivers/scsi/libiscsi_tcp.c3
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c2
-rw-r--r--drivers/scsi/lpfc/lpfc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c23
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c4
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c18
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c38
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c129
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c125
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c52
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h6
-rw-r--r--drivers/scsi/megaraid.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h186
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c226
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c784
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c148
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h35
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h6
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h4
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h8
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h9
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h10
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c59
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h7
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c143
-rw-r--r--drivers/scsi/mvsas/mv_sas.c3
-rw-r--r--drivers/scsi/osd/osd_uld.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c5
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c23
-rw-r--r--drivers/scsi/pmcraid.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c151
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c10
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c4
-rw-r--r--drivers/scsi/scsi.c8
-rw-r--r--drivers/scsi/scsi_debug.c48
-rw-r--r--drivers/scsi/scsi_devinfo.c1
-rw-r--r--drivers/scsi/scsi_error.c9
-rw-r--r--drivers/scsi/scsi_pm.c11
-rw-r--r--drivers/scsi/scsi_scan.c5
-rw-r--r--drivers/scsi/scsi_sysfs.c30
-rw-r--r--drivers/scsi/scsi_transport_fc.c6
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c12
-rw-r--r--drivers/scsi/sd.c79
-rw-r--r--drivers/scsi/sd.h1
-rw-r--r--drivers/scsi/storvsc_drv.c210
-rw-r--r--drivers/scsi/ufs/Kconfig2
-rw-r--r--drivers/scsi/ufs/ufshcd-pci.c1
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c76
-rw-r--r--drivers/scsi/ufs/ufshcd.c537
-rw-r--r--drivers/scsi/ufs/ufshcd.h21
-rw-r--r--drivers/scsi/ufs/ufshci.h5
-rw-r--r--drivers/sh/clk/core.c4
-rw-r--r--drivers/sh/pm_runtime.c2
-rw-r--r--drivers/spi/spi-altera.c14
-rw-r--r--drivers/spi/spi-ath79.c6
-rw-r--r--drivers/spi/spi-atmel.c51
-rw-r--r--drivers/spi/spi-au1550.c14
-rw-r--r--drivers/spi/spi-bcm2835.c7
-rw-r--r--drivers/spi/spi-bcm63xx.c23
-rw-r--r--drivers/spi/spi-bfin-sport.c13
-rw-r--r--drivers/spi/spi-bfin5xx.c24
-rw-r--r--drivers/spi/spi-clps711x.c9
-rw-r--r--drivers/spi/spi-coldfire-qspi.c23
-rw-r--r--drivers/spi/spi-davinci.c12
-rw-r--r--drivers/spi/spi-dw-mmio.c2
-rw-r--r--drivers/spi/spi-dw.c26
-rw-r--r--drivers/spi/spi-ep93xx.c14
-rw-r--r--drivers/spi/spi-fsl-espi.c9
-rw-r--r--drivers/spi/spi-fsl-lib.c2
-rw-r--r--drivers/spi/spi-fsl-spi.c2
-rw-r--r--drivers/spi/spi-gpio.c6
-rw-r--r--drivers/spi/spi-imx.c17
-rw-r--r--drivers/spi/spi-mpc512x-psc.c341
-rw-r--r--drivers/spi/spi-mpc52xx-psc.c2
-rw-r--r--drivers/spi/spi-mpc52xx.c4
-rw-r--r--drivers/spi/spi-mxs.c13
-rw-r--r--drivers/spi/spi-nuc900.c15
-rw-r--r--drivers/spi/spi-oc-tiny.c2
-rw-r--r--drivers/spi/spi-omap-100k.c16
-rw-r--r--drivers/spi/spi-omap-uwire.c4
-rw-r--r--drivers/spi/spi-omap2-mcspi.c254
-rw-r--r--drivers/spi/spi-orion.c4
-rw-r--r--drivers/spi/spi-pl022.c70
-rw-r--r--drivers/spi/spi-ppc4xx.c19
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c11
-rw-r--r--drivers/spi/spi-pxa2xx.c60
-rw-r--r--drivers/spi/spi-rspi.c4
-rw-r--r--drivers/spi/spi-s3c24xx.c2
-rw-r--r--drivers/spi/spi-s3c64xx.c207
-rw-r--r--drivers/spi/spi-sh-hspi.c4
-rw-r--r--drivers/spi/spi-sh.c4
-rw-r--r--drivers/spi/spi-sirf.c61
-rw-r--r--drivers/spi/spi-tegra114.c4
-rw-r--r--drivers/spi/spi-tegra20-sflash.c4
-rw-r--r--drivers/spi/spi-tegra20-slink.c4
-rw-r--r--drivers/spi/spi-ti-ssp.c16
-rw-r--r--drivers/spi/spi-topcliff-pch.c25
-rw-r--r--drivers/spi/spi-txx9.c10
-rw-r--r--drivers/spi/spi-xcomm.c12
-rw-r--r--drivers/spi/spi-xilinx.c48
-rw-r--r--drivers/spi/spi.c4
-rw-r--r--drivers/ssb/driver_chipcommon_sflash.c34
-rw-r--r--drivers/ssb/main.c8
-rw-r--r--drivers/ssb/pcihost_wrapper.c2
-rw-r--r--drivers/ssb/sprom.c2
-rw-r--r--drivers/ssb/ssb_private.h4
-rw-r--r--drivers/ssbi/Kconfig16
-rw-r--r--drivers/ssbi/Makefile1
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/android/binder.c5
-rw-r--r--drivers/staging/android/logger.c2
-rw-r--r--drivers/staging/android/timed_output.c2
-rw-r--r--drivers/staging/comedi/comedi_fops.c3
-rw-r--r--drivers/staging/csr/netdev.c2
-rw-r--r--drivers/staging/dgrp/dgrp_sysfs.c2
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_proc.c2
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_proc.c2
-rw-r--r--drivers/staging/fwserial/fwserial.c14
-rw-r--r--drivers/staging/imx-drm/ipuv3-crtc.c5
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lustre_patchless_compat.h2
-rw-r--r--drivers/staging/lustre/lustre/include/linux/lvfs.h2
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h6
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h4
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c4
-rw-r--r--drivers/staging/lustre/lustre/lvfs/lvfs_linux.c4
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c8
-rw-r--r--drivers/staging/media/solo6x10/Kconfig3
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c4
-rw-r--r--drivers/staging/rtl8712/os_intfs.c2
-rw-r--r--drivers/staging/silicom/Kconfig7
-rw-r--r--drivers/staging/silicom/bpctl_mod.c2
-rw-r--r--drivers/staging/tidspbridge/rmgr/drv_interface.c3
-rw-r--r--drivers/target/iscsi/iscsi_target.c768
-rw-r--r--drivers/target/iscsi/iscsi_target.h2
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c184
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h11
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c8
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c26
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c13
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c3
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c28
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h3
-rw-r--r--drivers/target/loopback/tcm_loop.c3
-rw-r--r--drivers/target/sbp/sbp_target.c3
-rw-r--r--drivers/target/target_core_configfs.c13
-rw-r--r--drivers/target/target_core_device.c5
-rw-r--r--drivers/target/target_core_fabric_configfs.c21
-rw-r--r--drivers/target/target_core_pr.c499
-rw-r--r--drivers/target/target_core_pr.h2
-rw-r--r--drivers/target/target_core_rd.c5
-rw-r--r--drivers/target/target_core_sbc.c18
-rw-r--r--drivers/target/target_core_tmr.c12
-rw-r--r--drivers/target/target_core_transport.c87
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h2
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c8
-rw-r--r--drivers/thermal/Kconfig15
-rw-r--r--drivers/thermal/Makefile3
-rw-r--r--drivers/thermal/armada_thermal.c3
-rw-r--r--drivers/thermal/cpu_cooling.c2
-rw-r--r--drivers/thermal/dove_thermal.c10
-rw-r--r--drivers/thermal/exynos_thermal.c3
-rw-r--r--drivers/thermal/kirkwood_thermal.c10
-rw-r--r--drivers/thermal/rcar_thermal.c10
-rw-r--r--drivers/thermal/spear_thermal.c20
-rw-r--r--drivers/thermal/thermal_core.c11
-rw-r--r--drivers/thermal/ti-soc-thermal/Kconfig (renamed from drivers/staging/ti-soc-thermal/Kconfig)12
-rw-r--r--drivers/thermal/ti-soc-thermal/Makefile (renamed from drivers/staging/ti-soc-thermal/Makefile)1
-rw-r--r--drivers/thermal/ti-soc-thermal/TODO (renamed from drivers/staging/ti-soc-thermal/TODO)0
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-bandgap.h280
-rw-r--r--drivers/thermal/ti-soc-thermal/dra752-thermal-data.c476
-rw-r--r--drivers/thermal/ti-soc-thermal/omap4-thermal-data.c (renamed from drivers/staging/ti-soc-thermal/omap4-thermal-data.c)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap4xxx-bandgap.h (renamed from drivers/staging/ti-soc-thermal/omap4xxx-bandgap.h)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap5-thermal-data.c (renamed from drivers/staging/ti-soc-thermal/omap5-thermal-data.c)0
-rw-r--r--drivers/thermal/ti-soc-thermal/omap5xxx-bandgap.h (renamed from drivers/staging/ti-soc-thermal/omap5xxx-bandgap.h)0
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c (renamed from drivers/staging/ti-soc-thermal/ti-bandgap.c)36
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.h (renamed from drivers/staging/ti-soc-thermal/ti-bandgap.h)5
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c (renamed from drivers/staging/ti-soc-thermal/ti-thermal-common.c)15
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal.h (renamed from drivers/staging/ti-soc-thermal/ti-thermal.h)6
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c642
-rw-r--r--drivers/tty/serial/amba-pl011.c42
-rw-r--r--drivers/tty/serial/mfd.c9
-rw-r--r--drivers/tty/serial/serial-tegra.c2
-rw-r--r--drivers/tty/sysrq.c19
-rw-r--r--drivers/tty/vt/vc_screen.c17
-rw-r--r--drivers/uio/uio.c2
-rw-r--r--drivers/usb/atm/usbatm.c5
-rw-r--r--drivers/usb/chipidea/Makefile2
-rw-r--r--drivers/usb/core/driver.c3
-rw-r--r--drivers/usb/core/port.c1
-rw-r--r--drivers/usb/gadget/tcm_usb_gadget.c3
-rw-r--r--drivers/usb/misc/sisusbvga/Kconfig1
-rw-r--r--drivers/usb/musb/musb_dsps.c2
-rw-r--r--drivers/usb/musb/omap2430.c2
-rw-r--r--drivers/usb/phy/phy-twl6030-usb.c2
-rw-r--r--drivers/uwb/lc-dev.c2
-rw-r--r--drivers/vfio/Kconfig6
-rw-r--r--drivers/vfio/Makefile1
-rw-r--r--drivers/vfio/vfio.c15
-rw-r--r--drivers/vfio/vfio_iommu_spapr_tce.c377
-rw-r--r--drivers/vfio/vfio_iommu_type1.c626
-rw-r--r--drivers/vhost/Kconfig8
-rw-r--r--drivers/vhost/Makefile3
-rw-r--r--drivers/vhost/net.c13
-rw-r--r--drivers/vhost/scsi.c495
-rw-r--r--drivers/vhost/test.c33
-rw-r--r--drivers/vhost/vhost.c86
-rw-r--r--drivers/vhost/vhost.h2
-rw-r--r--drivers/video/Kconfig4
-rw-r--r--drivers/video/aty/aty128fb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c9
-rw-r--r--drivers/video/aty/radeon_pm.c2
-rw-r--r--drivers/video/au1100fb.c1
-rw-r--r--drivers/video/backlight/atmel-pwm-bl.c2
-rw-r--r--drivers/video/backlight/backlight.c87
-rw-r--r--drivers/video/backlight/ep93xx_bl.c1
-rw-r--r--drivers/video/backlight/lcd.c72
-rw-r--r--drivers/video/backlight/lp8788_bl.c1
-rw-r--r--drivers/video/backlight/pcf50633-backlight.c2
-rw-r--r--drivers/video/bf54x-lq043fb.c1
-rw-r--r--drivers/video/bfin-lq035q1-fb.c24
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c2
-rw-r--r--drivers/video/console/Kconfig116
-rw-r--r--drivers/video/console/Makefile32
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/console/vgacon.c17
-rw-r--r--drivers/video/ep93xx-fb.c2
-rw-r--r--drivers/video/fbmem.c6
-rw-r--r--drivers/video/fsl-diu-fb.c4
-rw-r--r--drivers/video/i740fb.c2
-rw-r--r--drivers/video/imxfb.c201
-rw-r--r--drivers/video/jz4740_fb.c2
-rw-r--r--drivers/video/mmp/fb/mmpfb.c1
-rw-r--r--drivers/video/mmp/hw/mmp_ctrl.c9
-rw-r--r--drivers/video/mxsfb.c3
-rw-r--r--drivers/video/nuc900fb.c1
-rw-r--r--drivers/video/of_display_timing.c59
-rw-r--r--drivers/video/omap2/Kconfig1
-rw-r--r--drivers/video/omap2/Makefile1
-rw-r--r--drivers/video/omap2/displays-new/Kconfig73
-rw-r--r--drivers/video/omap2/displays-new/Makefile12
-rw-r--r--drivers/video/omap2/displays-new/connector-analog-tv.c265
-rw-r--r--drivers/video/omap2/displays-new/connector-dvi.c351
-rw-r--r--drivers/video/omap2/displays-new/connector-hdmi.c375
-rw-r--r--drivers/video/omap2/displays-new/encoder-tfp410.c267
-rw-r--r--drivers/video/omap2/displays-new/encoder-tpd12s015.c395
-rw-r--r--drivers/video/omap2/displays-new/panel-dpi.c270
-rw-r--r--drivers/video/omap2/displays-new/panel-dsi-cm.c1336
-rw-r--r--drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c358
-rw-r--r--drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c394
-rw-r--r--drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c324
-rw-r--r--drivers/video/omap2/displays-new/panel-sony-acx565akm.c865
-rw-r--r--drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c646
-rw-r--r--drivers/video/omap2/displays/Kconfig2
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c16
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c26
-rw-r--r--drivers/video/omap2/displays/panel-lgphilips-lb035q02.c10
-rw-r--r--drivers/video/omap2/displays/panel-n8x0.c30
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c4
-rw-r--r--drivers/video/omap2/displays/panel-picodlp.c34
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c10
-rw-r--r--drivers/video/omap2/displays/panel-taal.c170
-rw-r--r--drivers/video/omap2/displays/panel-tfp410.c32
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c36
-rw-r--r--drivers/video/omap2/dss/Kconfig1
-rw-r--r--drivers/video/omap2/dss/apply.c59
-rw-r--r--drivers/video/omap2/dss/core.c108
-rw-r--r--drivers/video/omap2/dss/dispc-compat.c3
-rw-r--r--drivers/video/omap2/dss/dispc.c24
-rw-r--r--drivers/video/omap2/dss/display-sysfs.c154
-rw-r--r--drivers/video/omap2/dss/display.c247
-rw-r--r--drivers/video/omap2/dss/dpi.c209
-rw-r--r--drivers/video/omap2/dss/dsi.c232
-rw-r--r--drivers/video/omap2/dss/dss.c3
-rw-r--r--drivers/video/omap2/dss/dss.h35
-rw-r--r--drivers/video/omap2/dss/dss_features.c1
-rw-r--r--drivers/video/omap2/dss/hdmi.c345
-rw-r--r--drivers/video/omap2/dss/manager-sysfs.c47
-rw-r--r--drivers/video/omap2/dss/manager.c29
-rw-r--r--drivers/video/omap2/dss/output.c87
-rw-r--r--drivers/video/omap2/dss/rfbi.c43
-rw-r--r--drivers/video/omap2/dss/sdi.c143
-rw-r--r--drivers/video/omap2/dss/ti_hdmi.h5
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c87
-rw-r--r--drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h1
-rw-r--r--drivers/video/omap2/dss/venc.c163
-rw-r--r--drivers/video/omap2/dss/venc_panel.c16
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c9
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c27
-rw-r--r--drivers/video/output.c2
-rw-r--r--drivers/video/pxa3xx-gcu.c2
-rw-r--r--drivers/video/pxafb.c1
-rw-r--r--drivers/video/s3c2410fb.c2
-rw-r--r--drivers/video/sa1100fb.c1
-rw-r--r--drivers/video/sh7760fb.c1
-rw-r--r--drivers/video/sh_mipi_dsi.c1
-rw-r--r--drivers/video/smscufx.c2
-rw-r--r--drivers/video/ssd1307fb.c392
-rw-r--r--drivers/video/tmiofb.c3
-rw-r--r--drivers/video/udlfb.c12
-rw-r--r--drivers/video/uvesafb.c74
-rw-r--r--drivers/video/vga16fb.c1
-rw-r--r--drivers/video/vt8500lcdfb.c1
-rw-r--r--drivers/video/wm8505fb.c2
-rw-r--r--drivers/video/xilinxfb.c135
-rw-r--r--drivers/virtio/virtio_balloon.c10
-rw-r--r--drivers/virtio/virtio_pci.c5
-rw-r--r--drivers/virtio/virtio_ring.c93
-rw-r--r--drivers/w1/slaves/w1_ds2408.c30
-rw-r--r--drivers/watchdog/Kconfig11
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/booke_wdt.c8
-rw-r--r--drivers/watchdog/kempld_wdt.c581
-rw-r--r--drivers/xen/balloon.c29
-rw-r--r--drivers/xen/cpu_hotplug.c6
-rw-r--r--drivers/xen/events.c23
-rw-r--r--drivers/xen/evtchn.c6
-rw-r--r--drivers/xen/gntalloc.c6
-rw-r--r--drivers/xen/gntdev.c8
-rw-r--r--drivers/xen/grant-table.c17
-rw-r--r--drivers/xen/manage.c28
-rw-r--r--drivers/xen/mcelog.c36
-rw-r--r--drivers/xen/pcpu.c12
-rw-r--r--drivers/xen/privcmd.c4
-rw-r--r--drivers/xen/swiotlb-xen.c12
-rw-r--r--drivers/xen/tmem.c10
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-memhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-pad.c2
-rw-r--r--drivers/xen/xen-acpi-processor.c25
-rw-r--r--drivers/xen/xen-balloon.c6
-rw-r--r--drivers/xen/xen-pciback/conf_space_header.c16
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c35
-rw-r--r--drivers/xen/xen-pciback/pciback_ops.c9
-rw-r--r--drivers/xen/xen-pciback/vpci.c10
-rw-r--r--drivers/xen/xen-pciback/xenbus.c8
-rw-r--r--drivers/xen/xen-selfballoon.c11
-rw-r--r--drivers/xen/xenbus/xenbus_comms.c13
-rw-r--r--drivers/xen/xenbus/xenbus_dev_backend.c4
-rw-r--r--drivers/xen/xenbus/xenbus_dev_frontend.c4
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c32
-rw-r--r--drivers/xen/xenbus/xenbus_probe_backend.c8
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c35
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c22
-rw-r--r--drivers/xen/xencomm.c2
-rw-r--r--drivers/xen/xenfs/super.c4
-rw-r--r--drivers/zorro/proc.c22
-rw-r--r--fs/9p/Kconfig13
-rw-r--r--fs/9p/Makefile4
-rw-r--r--fs/9p/vfs_inode.c2
-rw-r--r--fs/9p/xattr.c4
-rw-r--r--fs/9p/xattr.h2
-rw-r--r--fs/9p/xattr_security.c80
-rw-r--r--fs/9p/xattr_trusted.c80
-rw-r--r--fs/adfs/dir.c6
-rw-r--r--fs/affs/namei.c26
-rw-r--r--fs/afs/flock.c7
-rw-r--r--fs/aio.c4
-rw-r--r--fs/autofs4/expire.c8
-rw-r--r--fs/autofs4/root.c2
-rw-r--r--fs/binfmt_aout.c2
-rw-r--r--fs/binfmt_elf.c2
-rw-r--r--fs/block_dev.c33
-rw-r--r--fs/btrfs/backref.c72
-rw-r--r--fs/btrfs/backref.h2
-rw-r--r--fs/btrfs/ctree.c120
-rw-r--r--fs/btrfs/ctree.h105
-rw-r--r--fs/btrfs/delayed-inode.c14
-rw-r--r--fs/btrfs/dev-replace.c6
-rw-r--r--fs/btrfs/disk-io.c483
-rw-r--r--fs/btrfs/disk-io.h32
-rw-r--r--fs/btrfs/export.c5
-rw-r--r--fs/btrfs/extent-tree.c315
-rw-r--r--fs/btrfs/extent_io.c41
-rw-r--r--fs/btrfs/extent_io.h1
-rw-r--r--fs/btrfs/file-item.c144
-rw-r--r--fs/btrfs/file.c165
-rw-r--r--fs/btrfs/free-space-cache.c103
-rw-r--r--fs/btrfs/free-space-cache.h2
-rw-r--r--fs/btrfs/inode.c501
-rw-r--r--fs/btrfs/ioctl.c82
-rw-r--r--fs/btrfs/lzo.c4
-rw-r--r--fs/btrfs/ordered-data.c128
-rw-r--r--fs/btrfs/ordered-data.h27
-rw-r--r--fs/btrfs/qgroup.c283
-rw-r--r--fs/btrfs/relocation.c102
-rw-r--r--fs/btrfs/root-tree.c201
-rw-r--r--fs/btrfs/scrub.c90
-rw-r--r--fs/btrfs/send.c235
-rw-r--r--fs/btrfs/super.c25
-rw-r--r--fs/btrfs/transaction.c322
-rw-r--r--fs/btrfs/transaction.h50
-rw-r--r--fs/btrfs/tree-log.c41
-rw-r--r--fs/btrfs/ulist.c15
-rw-r--r--fs/btrfs/version.h4
-rw-r--r--fs/btrfs/volumes.c351
-rw-r--r--fs/btrfs/volumes.h7
-rw-r--r--fs/buffer.c34
-rw-r--r--fs/cachefiles/rdwr.c30
-rw-r--r--fs/ceph/addr.c88
-rw-r--r--fs/ceph/caps.c102
-rw-r--r--fs/ceph/file.c15
-rw-r--r--fs/ceph/inode.c18
-rw-r--r--fs/ceph/locks.c4
-rw-r--r--fs/ceph/mds_client.c16
-rw-r--r--fs/ceph/mdsmap.c42
-rw-r--r--fs/ceph/super.c2
-rw-r--r--fs/ceph/super.h4
-rw-r--r--fs/ceph/xattr.c9
-rw-r--r--fs/cifs/Kconfig1
-rw-r--r--fs/cifs/cifs_debug.c52
-rw-r--r--fs/cifs/cifs_unicode.h8
-rw-r--r--fs/cifs/cifsencrypt.c40
-rw-r--r--fs/cifs/cifsfs.c13
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h48
-rw-r--r--fs/cifs/cifspdu.h17
-rw-r--r--fs/cifs/cifsproto.h4
-rw-r--r--fs/cifs/cifssmb.c425
-rw-r--r--fs/cifs/connect.c159
-rw-r--r--fs/cifs/dir.c9
-rw-r--r--fs/cifs/file.c15
-rw-r--r--fs/cifs/misc.c3
-rw-r--r--fs/cifs/readdir.c29
-rw-r--r--fs/cifs/sess.c95
-rw-r--r--fs/cifs/smb1ops.c23
-rw-r--r--fs/cifs/smb2glob.h2
-rw-r--r--fs/cifs/smb2misc.c4
-rw-r--r--fs/cifs/smb2ops.c48
-rw-r--r--fs/cifs/smb2pdu.c282
-rw-r--r--fs/cifs/smb2pdu.h100
-rw-r--r--fs/cifs/smb2proto.h4
-rw-r--r--fs/cifs/smb2transport.c151
-rw-r--r--fs/cifs/smbfsctl.h27
-rw-r--r--fs/cifs/transport.c6
-rw-r--r--fs/coda/dir.c10
-rw-r--r--fs/configfs/dir.c2
-rw-r--r--fs/configfs/file.c2
-rw-r--r--fs/coredump.c121
-rw-r--r--fs/dcache.c66
-rw-r--r--fs/ecryptfs/crypto.c342
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h2
-rw-r--r--fs/ecryptfs/file.c16
-rw-r--r--fs/ecryptfs/inode.c4
-rw-r--r--fs/ecryptfs/main.c7
-rw-r--r--fs/ecryptfs/messaging.c3
-rw-r--r--fs/efivarfs/super.c9
-rw-r--r--fs/eventpoll.c16
-rw-r--r--fs/exec.c17
-rw-r--r--fs/ext2/namei.c24
-rw-r--r--fs/ext3/fsync.c8
-rw-r--r--fs/ext3/inode.c1
-rw-r--r--fs/ext3/namei.c47
-rw-r--r--fs/ext3/super.c13
-rw-r--r--fs/ext4/file.c24
-rw-r--r--fs/ext4/namei.c47
-rw-r--r--fs/f2fs/dir.c20
-rw-r--r--fs/fat/fat.h1
-rw-r--r--fs/fat/file.c8
-rw-r--r--fs/fat/inode.c12
-rw-r--r--fs/fat/misc.c5
-rw-r--r--fs/fat/namei_msdos.c6
-rw-r--r--fs/fat/namei_vfat.c12
-rw-r--r--fs/file_table.c2
-rw-r--r--fs/fs-writeback.c10
-rw-r--r--fs/fuse/file.c3
-rw-r--r--fs/fuse/inode.c2
-rw-r--r--fs/gfs2/dentry.c3
-rw-r--r--fs/gfs2/file.c2
-rw-r--r--fs/hfs/hfs_fs.h7
-rw-r--r--fs/hfs/string.c6
-rw-r--r--fs/hfsplus/hfsplus_fs.h7
-rw-r--r--fs/hfsplus/unicode.c7
-rw-r--r--fs/hpfs/buffer.c33
-rw-r--r--fs/hpfs/dentry.c7
-rw-r--r--fs/hpfs/file.c40
-rw-r--r--fs/hpfs/hpfs_fn.h7
-rw-r--r--fs/hpfs/map.c22
-rw-r--r--fs/hpfs/super.c17
-rw-r--r--fs/hppfs/hppfs.c11
-rw-r--r--fs/inode.c4
-rw-r--r--fs/internal.h6
-rw-r--r--fs/isofs/inode.c48
-rw-r--r--fs/isofs/namei.c3
-rw-r--r--fs/jfs/jfs_dmap.c70
-rw-r--r--fs/jfs/jfs_dtree.c37
-rw-r--r--fs/jfs/jfs_extent.c2
-rw-r--r--fs/jfs/jfs_imap.c69
-rw-r--r--fs/jfs/jfs_metapage.c5
-rw-r--r--fs/jfs/jfs_superblock.h1
-rw-r--r--fs/jfs/jfs_txnmgr.c2
-rw-r--r--fs/jfs/jfs_xtree.c62
-rw-r--r--fs/jfs/namei.c9
-rw-r--r--fs/jfs/resize.c2
-rw-r--r--fs/jfs/super.c22
-rw-r--r--fs/jfs/xattr.c8
-rw-r--r--fs/lockd/svc.c2
-rw-r--r--fs/lockd/svclock.c14
-rw-r--r--fs/lockd/svcsubs.c12
-rw-r--r--fs/locks.c328
-rw-r--r--fs/minix/dir.c2
-rw-r--r--fs/minix/namei.c13
-rw-r--r--fs/namei.c113
-rw-r--r--fs/ncpfs/dir.c45
-rw-r--r--fs/ncpfs/inode.c16
-rw-r--r--fs/ncpfs/mmap.c2
-rw-r--r--fs/nfs/Kconfig14
-rw-r--r--fs/nfs/Makefile6
-rw-r--r--fs/nfs/blocklayout/blocklayout.c3
-rw-r--r--fs/nfs/callback.c6
-rw-r--r--fs/nfs/callback.h3
-rw-r--r--fs/nfs/callback_proc.c3
-rw-r--r--fs/nfs/callback_xdr.c52
-rw-r--r--fs/nfs/client.c4
-rw-r--r--fs/nfs/delegation.c10
-rw-r--r--fs/nfs/dir.c94
-rw-r--r--fs/nfs/dns_resolve.c32
-rw-r--r--fs/nfs/file.c30
-rw-r--r--fs/nfs/getroot.c2
-rw-r--r--fs/nfs/idmap.c56
-rw-r--r--fs/nfs/inode.c140
-rw-r--r--fs/nfs/internal.h3
-rw-r--r--fs/nfs/mount_clnt.c14
-rw-r--r--fs/nfs/namespace.c2
-rw-r--r--fs/nfs/nfs3proc.c9
-rw-r--r--fs/nfs/nfs4_fs.h8
-rw-r--r--fs/nfs/nfs4client.c15
-rw-r--r--fs/nfs/nfs4file.c1
-rw-r--r--fs/nfs/nfs4filelayout.c3
-rw-r--r--fs/nfs/nfs4filelayout.h3
-rw-r--r--fs/nfs/nfs4filelayoutdev.c8
-rw-r--r--fs/nfs/nfs4proc.c691
-rw-r--r--fs/nfs/nfs4session.c40
-rw-r--r--fs/nfs/nfs4session.h7
-rw-r--r--fs/nfs/nfs4state.c46
-rw-r--r--fs/nfs/nfs4super.c14
-rw-r--r--fs/nfs/nfs4xdr.c182
-rw-r--r--fs/nfs/objlayout/objlayout.c4
-rw-r--r--fs/nfs/pnfs.c42
-rw-r--r--fs/nfs/pnfs.h6
-rw-r--r--fs/nfs/proc.c13
-rw-r--r--fs/nfs/super.c199
-rw-r--r--fs/nfs/unlink.c2
-rw-r--r--fs/nfs/write.c31
-rw-r--r--fs/nfsd/Kconfig16
-rw-r--r--fs/nfsd/nfs4proc.c44
-rw-r--r--fs/nfsd/nfs4state.c233
-rw-r--r--fs/nfsd/nfs4xdr.c169
-rw-r--r--fs/nfsd/nfsd.h26
-rw-r--r--fs/nfsd/nfssvc.c2
-rw-r--r--fs/nfsd/state.h1
-rw-r--r--fs/nfsd/vfs.c28
-rw-r--r--fs/nfsd/vfs.h7
-rw-r--r--fs/nfsd/xdr4.h4
-rw-r--r--fs/nilfs2/alloc.c63
-rw-r--r--fs/nilfs2/alloc.h2
-rw-r--r--fs/nilfs2/ifile.c22
-rw-r--r--fs/nilfs2/ifile.h2
-rw-r--r--fs/nilfs2/inode.c8
-rw-r--r--fs/nilfs2/segment.c4
-rw-r--r--fs/nilfs2/super.c33
-rw-r--r--fs/nilfs2/the_nilfs.c4
-rw-r--r--fs/nilfs2/the_nilfs.h4
-rw-r--r--fs/notify/dnotify/dnotify.c25
-rw-r--r--fs/notify/fanotify/fanotify_user.c92
-rw-r--r--fs/notify/inotify/inotify_user.c13
-rw-r--r--fs/notify/mark.c50
-rw-r--r--fs/ocfs2/alloc.c8
-rw-r--r--fs/ocfs2/cluster/heartbeat.c19
-rw-r--r--fs/ocfs2/cluster/quorum.c2
-rw-r--r--fs/ocfs2/cluster/tcp.c29
-rw-r--r--fs/ocfs2/dlm/dlmlock.c1
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c7
-rw-r--r--fs/ocfs2/file.c12
-rw-r--r--fs/ocfs2/journal.h3
-rw-r--r--fs/ocfs2/namei.c70
-rw-r--r--fs/ocfs2/ocfs2.h1
-rw-r--r--fs/ocfs2/suballoc.c37
-rw-r--r--fs/ocfs2/super.c6
-rw-r--r--fs/ocfs2/xattr.c18
-rw-r--r--fs/open.c63
-rw-r--r--fs/proc/base.c105
-rw-r--r--fs/proc/fd.c18
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/kcore.c2
-rw-r--r--fs/proc/namespaces.c13
-rw-r--r--fs/proc/proc_sysctl.c7
-rw-r--r--fs/proc/task_mmu.c145
-rw-r--r--fs/proc/uptime.c3
-rw-r--r--fs/proc/vmcore.c694
-rw-r--r--fs/pstore/ftrace.c2
-rw-r--r--fs/pstore/inode.c11
-rw-r--r--fs/pstore/platform.c21
-rw-r--r--fs/pstore/ram.c5
-rw-r--r--fs/pstore/ram_core.c54
-rw-r--r--fs/quota/dquot.c6
-rw-r--r--fs/read_write.c65
-rw-r--r--fs/select.c66
-rw-r--r--fs/seq_file.c54
-rw-r--r--fs/splice.c38
-rw-r--r--fs/sysv/namei.c3
-rw-r--r--fs/timerfd.c131
-rw-r--r--fs/ubifs/super.c2
-rw-r--r--fs/udf/namei.c24
-rw-r--r--fs/xfs/Makefile1
-rw-r--r--fs/xfs/xfs_alloc.c24
-rw-r--r--fs/xfs/xfs_bmap_btree.h2
-rw-r--r--fs/xfs/xfs_buf_item.c87
-rw-r--r--fs/xfs/xfs_buf_item.h4
-rw-r--r--fs/xfs/xfs_dfrag.c8
-rw-r--r--fs/xfs/xfs_dir2_leaf.c3
-rw-r--r--fs/xfs/xfs_dquot.c16
-rw-r--r--fs/xfs/xfs_dquot.h4
-rw-r--r--fs/xfs/xfs_file.c6
-rw-r--r--fs/xfs/xfs_fsops.c2
-rw-r--r--fs/xfs/xfs_ialloc.c74
-rw-r--r--fs/xfs/xfs_ialloc.h8
-rw-r--r--fs/xfs/xfs_icache.c3
-rw-r--r--fs/xfs/xfs_icache.h1
-rw-r--r--fs/xfs/xfs_icreate_item.c195
-rw-r--r--fs/xfs/xfs_icreate_item.h52
-rw-r--r--fs/xfs/xfs_inode.c68
-rw-r--r--fs/xfs/xfs_iomap.c13
-rw-r--r--fs/xfs/xfs_iops.c3
-rw-r--r--fs/xfs/xfs_itable.c5
-rw-r--r--fs/xfs/xfs_log.c22
-rw-r--r--fs/xfs/xfs_log.h5
-rw-r--r--fs/xfs/xfs_log_cil.c75
-rw-r--r--fs/xfs/xfs_log_recover.c114
-rw-r--r--fs/xfs/xfs_mount.c92
-rw-r--r--fs/xfs/xfs_mount.h4
-rw-r--r--fs/xfs/xfs_qm.c175
-rw-r--r--fs/xfs/xfs_qm.h83
-rw-r--r--fs/xfs/xfs_qm_syscalls.c51
-rw-r--r--fs/xfs/xfs_quota.h47
-rw-r--r--fs/xfs/xfs_quotaops.c6
-rw-r--r--fs/xfs/xfs_sb.h6
-rw-r--r--fs/xfs/xfs_super.c39
-rw-r--r--fs/xfs/xfs_symlink.c51
-rw-r--r--fs/xfs/xfs_symlink.h2
-rw-r--r--fs/xfs/xfs_sysctl.c26
-rw-r--r--fs/xfs/xfs_trace.h5
-rw-r--r--fs/xfs/xfs_trans.c118
-rw-r--r--fs/xfs/xfs_trans.h16
-rw-r--r--fs/xfs/xfs_trans_buf.c34
-rw-r--r--fs/xfs/xfs_trans_dquot.c87
-rw-r--r--fs/xfs/xfs_trans_inode.c11
-rw-r--r--fs/xfs/xfs_vnodeops.c15
-rw-r--r--include/acpi/acconfig.h4
-rw-r--r--include/acpi/acoutput.h8
-rw-r--r--include/acpi/acpi_bus.h30
-rw-r--r--include/acpi/acpixf.h3
-rw-r--r--include/acpi/processor.h5
-rw-r--r--include/asm-generic/pgtable.h27
-rw-r--r--include/asm-generic/sections.h21
-rw-r--r--include/asm-generic/vmlinux.lds.h19
-rw-r--r--include/clocksource/arm_arch_timer.h2
-rw-r--r--include/drm/drmP.h40
-rw-r--r--include/drm/drm_crtc.h37
-rw-r--r--include/drm/drm_fixed.h94
-rw-r--r--include/drm/drm_gem_cma_helper.h12
-rw-r--r--include/drm/drm_mm.h38
-rw-r--r--include/drm/drm_os_linux.h16
-rw-r--r--include/drm/drm_pciids.h24
-rw-r--r--include/drm/drm_rect.h167
-rw-r--r--include/drm/i915_powerwell.h36
-rw-r--r--include/drm/ttm/ttm_bo_api.h37
-rw-r--r--include/drm/ttm/ttm_bo_driver.h169
-rw-r--r--include/drm/ttm/ttm_execbuf_util.h12
-rw-r--r--include/dt-bindings/pinctrl/rockchip.h32
-rw-r--r--include/kvm/arm_arch_timer.h (renamed from arch/arm/include/asm/kvm_arch_timer.h)4
-rw-r--r--include/kvm/arm_vgic.h (renamed from arch/arm/include/asm/kvm_vgic.h)0
-rw-r--r--include/linux/acpi.h3
-rw-r--r--include/linux/aer.h22
-rw-r--r--include/linux/alarmtimer.h4
-rw-r--r--include/linux/amba/pl08x.h8
-rw-r--r--include/linux/async_tx.h4
-rw-r--r--include/linux/audit.h26
-rw-r--r--include/linux/backlight.h6
-rw-r--r--include/linux/bcma/bcma.h1
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h55
-rw-r--r--include/linux/bio.h4
-rw-r--r--include/linux/bootmem.h2
-rw-r--r--include/linux/buffer_head.h3
-rw-r--r--include/linux/can/platform/flexcan.h20
-rw-r--r--include/linux/ceph/decode.h5
-rw-r--r--include/linux/ceph/osd_client.h1
-rw-r--r--include/linux/cgroup.h229
-rw-r--r--include/linux/clk-provider.h62
-rw-r--r--include/linux/clk/tegra.h6
-rw-r--r--include/linux/clockchips.h5
-rw-r--r--include/linux/clocksource.h8
-rw-r--r--include/linux/cpu.h3
-rw-r--r--include/linux/cpu_cooling.h4
-rw-r--r--include/linux/cpufreq.h54
-rw-r--r--include/linux/cpuidle.h6
-rw-r--r--include/linux/crc-t10dif.h4
-rw-r--r--include/linux/dcache.h16
-rw-r--r--include/linux/debug_locks.h4
-rw-r--r--include/linux/decompress/unlz4.h10
-rw-r--r--include/linux/devfreq.h2
-rw-r--r--include/linux/device-mapper.h6
-rw-r--r--include/linux/device.h22
-rw-r--r--include/linux/dmaengine.h5
-rw-r--r--include/linux/dw_apb_timer.h1
-rw-r--r--include/linux/efi.h4
-rw-r--r--include/linux/elevator.h6
-rw-r--r--include/linux/err.h10
-rw-r--r--include/linux/fb.h2
-rw-r--r--include/linux/filter.h4
-rw-r--r--include/linux/firewire.h2
-rw-r--r--include/linux/freezer.h171
-rw-r--r--include/linux/fs.h55
-rw-r--r--include/linux/fsnotify.h8
-rw-r--r--include/linux/ftrace.h9
-rw-r--r--include/linux/gfp.h2
-rw-r--r--include/linux/huge_mm.h8
-rw-r--r--include/linux/hugetlb.h6
-rw-r--r--include/linux/i2c/twl.h31
-rw-r--r--include/linux/ieee80211.h10
-rw-r--r--include/linux/if_link.h1
-rw-r--r--include/linux/if_macvlan.h12
-rw-r--r--include/linux/if_team.h11
-rw-r--r--include/linux/if_vlan.h2
-rw-r--r--include/linux/igmp.h1
-rw-r--r--include/linux/inetdevice.h5
-rw-r--r--include/linux/init.h19
-rw-r--r--include/linux/input/ti_am335x_tsc.h23
-rw-r--r--include/linux/input/tps6507x-ts.h1
-rw-r--r--include/linux/io.h25
-rw-r--r--include/linux/irqdomain.h142
-rw-r--r--include/linux/jiffies.h4
-rw-r--r--include/linux/kernel.h5
-rw-r--r--include/linux/ktime.h23
-rw-r--r--include/linux/kvm_host.h4
-rw-r--r--include/linux/lcd.h5
-rw-r--r--include/linux/libata.h5
-rw-r--r--include/linux/lz4.h87
-rw-r--r--include/linux/marvell_phy.h2
-rw-r--r--include/linux/memcontrol.h9
-rw-r--r--include/linux/memory_hotplug.h14
-rw-r--r--include/linux/mfd/88pm80x.h17
-rw-r--r--include/linux/mfd/abx500/ab8500-sysctrl.h4
-rw-r--r--include/linux/mfd/abx500/ab8500.h2
-rw-r--r--include/linux/mfd/arizona/core.h4
-rw-r--r--include/linux/mfd/arizona/pdata.h2
-rw-r--r--include/linux/mfd/arizona/registers.h47
-rw-r--r--include/linux/mfd/davinci_voicecodec.h4
-rw-r--r--include/linux/mfd/dbx500-prcmu.h12
-rw-r--r--include/linux/mfd/kempld.h125
-rw-r--r--include/linux/mfd/max77693-private.h13
-rw-r--r--include/linux/mfd/max77693.h18
-rw-r--r--include/linux/mfd/max8998-private.h7
-rw-r--r--include/linux/mfd/max8998.h20
-rw-r--r--include/linux/mfd/mc13xxx.h100
-rw-r--r--include/linux/mfd/palmas.h14
-rw-r--r--include/linux/mfd/rtsx_pci.h1
-rw-r--r--include/linux/mfd/samsung/core.h6
-rw-r--r--include/linux/mfd/samsung/s2mps11.h1
-rw-r--r--include/linux/mfd/ti_am335x_tscadc.h35
-rw-r--r--include/linux/mfd/tmio.h5
-rw-r--r--include/linux/mfd/tps6507x.h1
-rw-r--r--include/linux/mfd/twl6040.h7
-rw-r--r--include/linux/mfd/wm8994/core.h2
-rw-r--r--include/linux/mfd/wm8994/pdata.h10
-rw-r--r--include/linux/mfd/wm8994/registers.h8
-rw-r--r--include/linux/mlx4/cmd.h3
-rw-r--r--include/linux/mlx4/device.h3
-rw-r--r--include/linux/mlx4/qp.h36
-rw-r--r--include/linux/mm.h49
-rw-r--r--include/linux/mm_types.h3
-rw-r--r--include/linux/mman.h8
-rw-r--r--include/linux/mmc/card.h11
-rw-r--r--include/linux/mmc/core.h5
-rw-r--r--include/linux/mmc/host.h12
-rw-r--r--include/linux/mmc/sdhci.h6
-rw-r--r--include/linux/mmzone.h68
-rw-r--r--include/linux/mod_devicetable.h25
-rw-r--r--include/linux/moduleparam.h2
-rw-r--r--include/linux/msi.h1
-rw-r--r--include/linux/mv643xx_eth.h2
-rw-r--r--include/linux/nbd.h1
-rw-r--r--include/linux/net.h6
-rw-r--r--include/linux/netdev_features.h4
-rw-r--r--include/linux/netdevice.h85
-rw-r--r--include/linux/netfilter.h2
-rw-r--r--include/linux/netlink.h27
-rw-r--r--include/linux/netpoll.h4
-rw-r--r--include/linux/nfs4.h22
-rw-r--r--include/linux/nfs_fs.h28
-rw-r--r--include/linux/nfs_fs_sb.h8
-rw-r--r--include/linux/nfs_xdr.h20
-rw-r--r--include/linux/of_device.h6
-rw-r--r--include/linux/of_dma.h1
-rw-r--r--include/linux/of_platform.h35
-rw-r--r--include/linux/pageblock-flags.h6
-rw-r--r--include/linux/pagevec.h34
-rw-r--r--include/linux/pci.h6
-rw-r--r--include/linux/pci_ids.h7
-rw-r--r--include/linux/percpu-refcount.h174
-rw-r--r--include/linux/phy.h27
-rw-r--r--include/linux/pid.h6
-rw-r--r--include/linux/pinctrl/consumer.h77
-rw-r--r--include/linux/pinctrl/devinfo.h4
-rw-r--r--include/linux/pinctrl/pinconf-generic.h25
-rw-r--r--include/linux/pinctrl/pinconf.h2
-rw-r--r--include/linux/pinctrl/pinctrl.h4
-rw-r--r--include/linux/platform_data/brcmfmac-sdio.h5
-rw-r--r--include/linux/platform_data/clk-ux500.h6
-rw-r--r--include/linux/platform_data/cyttsp4.h76
-rw-r--r--include/linux/platform_data/dma-atmel.h4
-rw-r--r--include/linux/platform_data/dma-imx.h6
-rw-r--r--include/linux/platform_data/g762.h37
-rw-r--r--include/linux/platform_data/keypad-pxa27x.h3
-rw-r--r--include/linux/platform_data/mmc-esdhc-imx.h1
-rw-r--r--include/linux/platform_data/net-cw1200.h81
-rw-r--r--include/linux/platform_data/pwm-renesas-tpu.h16
-rw-r--r--include/linux/platform_data/rcar-du.h54
-rw-r--r--include/linux/platform_data/remoteproc-omap.h2
-rw-r--r--include/linux/platform_data/si5351.h18
-rw-r--r--include/linux/platform_data/ssm2518.h22
-rw-r--r--include/linux/platform_data/ti_am335x_adc.h14
-rw-r--r--include/linux/platform_device.h3
-rw-r--r--include/linux/pm_runtime.h2
-rw-r--r--include/linux/posix-timers.h16
-rw-r--r--include/linux/power/smartreflex.h10
-rw-r--r--include/linux/power_supply.h4
-rw-r--r--include/linux/pstore.h12
-rw-r--r--include/linux/ptrace.h10
-rw-r--r--include/linux/pvclock_gtod.h7
-rw-r--r--include/linux/pwm.h29
-rw-r--r--include/linux/reboot.h27
-rw-r--r--include/linux/regmap.h43
-rw-r--r--include/linux/regulator/ab8500.h4
-rw-r--r--include/linux/regulator/consumer.h1
-rw-r--r--include/linux/reservation.h62
-rw-r--r--include/linux/rio.h82
-rw-r--r--include/linux/rio_ids.h2
-rw-r--r--include/linux/scatterlist.h5
-rw-r--r--include/linux/sched.h16
-rw-r--r--include/linux/sched_clock.h21
-rw-r--r--include/linux/security.h60
-rw-r--r--include/linux/sem.h6
-rw-r--r--include/linux/seq_file.h6
-rw-r--r--include/linux/sh_dma.h2
-rw-r--r--include/linux/shdma-base.h3
-rw-r--r--include/linux/skbuff.h137
-rw-r--r--include/linux/smp.h20
-rw-r--r--include/linux/spi/spi.h3
-rw-r--r--include/linux/spi/xilinx_spi.h1
-rw-r--r--include/linux/spinlock_api_smp.h2
-rw-r--r--include/linux/ssb/ssb_driver_mips.h15
-rw-r--r--include/linux/ssb/ssb_regs.h1
-rw-r--r--include/linux/stmmac.h4
-rw-r--r--include/linux/sunrpc/cache.h49
-rw-r--r--include/linux/sunrpc/gss_api.h2
-rw-r--r--include/linux/sunrpc/sched.h20
-rw-r--r--include/linux/sunrpc/svcauth.h11
-rw-r--r--include/linux/suspend.h1
-rw-r--r--include/linux/swap.h24
-rw-r--r--include/linux/tcp.h1
-rw-r--r--include/linux/tpm.h2
-rw-r--r--include/linux/vexpress.h1
-rw-r--r--include/linux/virtio.h11
-rw-r--r--include/linux/virtio_ring.h1
-rw-r--r--include/linux/vmalloc.h16
-rw-r--r--include/linux/workqueue.h42
-rw-r--r--include/linux/writeback.h8
-rw-r--r--include/linux/zbud.h22
-rw-r--r--include/net/9p/transport.h6
-rw-r--r--include/net/act_api.h2
-rw-r--r--include/net/addrconf.h4
-rw-r--r--include/net/bluetooth/hci.h1
-rw-r--r--include/net/bluetooth/hci_core.h29
-rw-r--r--include/net/bluetooth/l2cap.h2
-rw-r--r--include/net/cfg80211.h236
-rw-r--r--include/net/gen_stats.h10
-rw-r--r--include/net/gre.h31
-rw-r--r--include/net/ieee80211_radiotap.h7
-rw-r--r--include/net/if_inet6.h13
-rw-r--r--include/net/inet_ecn.h6
-rw-r--r--include/net/inet_sock.h1
-rw-r--r--include/net/ip_fib.h5
-rw-r--r--include/net/ip_tunnels.h36
-rw-r--r--include/net/ip_vs.h92
-rw-r--r--include/net/ipv6.h10
-rw-r--r--include/net/ll_poll.h183
-rw-r--r--include/net/mac80211.h27
-rw-r--r--include/net/ndisc.h2
-rw-r--r--include/net/net_namespace.h13
-rw-r--r--include/net/netfilter/xt_rateest.h2
-rw-r--r--include/net/netns/x_tables.h6
-rw-r--r--include/net/nfc/hci.h7
-rw-r--r--include/net/nfc/nci_core.h58
-rw-r--r--include/net/nfc/nfc.h35
-rw-r--r--include/net/ping.h65
-rw-r--r--include/net/sch_generic.h17
-rw-r--r--include/net/sctp/checksum.h5
-rw-r--r--include/net/sctp/sctp.h111
-rw-r--r--include/net/sctp/structs.h6
-rw-r--r--include/net/sock.h21
-rw-r--r--include/net/tcp.h29
-rw-r--r--include/net/transp_v6.h79
-rw-r--r--include/net/udp.h8
-rw-r--r--include/scsi/iscsi_if.h5
-rw-r--r--include/scsi/libiscsi.h4
-rw-r--r--include/scsi/libsas.h2
-rw-r--r--include/scsi/scsi.h5
-rw-r--r--include/scsi/scsi_device.h1
-rw-r--r--include/scsi/scsi_devinfo.h1
-rw-r--r--include/sound/control.h3
-rw-r--r--include/sound/core.h2
-rw-r--r--include/sound/pcm.h5
-rw-r--r--include/sound/rt5640.h22
-rw-r--r--include/sound/soc-dapm.h3
-rw-r--r--include/sound/soc.h4
-rw-r--r--include/target/iscsi/iscsi_transport.h21
-rw-r--r--include/target/target_core_base.h23
-rw-r--r--include/target/target_core_configfs.h1
-rw-r--r--include/target/target_core_fabric.h2
-rw-r--r--include/target/target_core_fabric_configfs.h11
-rw-r--r--include/trace/events/9p.h28
-rw-r--r--include/trace/events/btrfs.h35
-rw-r--r--include/trace/events/pagemap.h89
-rw-r--r--include/trace/events/power.h173
-rw-r--r--include/trace/events/regmap.h23
-rw-r--r--include/trace/events/target.h214
-rw-r--r--include/trace/syscall.h1
-rw-r--r--include/uapi/asm-generic/fcntl.h4
-rw-r--r--include/uapi/asm-generic/poll.h2
-rw-r--r--include/uapi/asm-generic/socket.h2
-rw-r--r--include/uapi/drm/drm.h1
-rw-r--r--include/uapi/drm/drm_mode.h13
-rw-r--r--include/uapi/drm/i915_drm.h3
-rw-r--r--include/uapi/drm/tegra_drm.h2
-rw-r--r--include/uapi/linux/btrfs.h42
-rw-r--r--include/uapi/linux/dm-ioctl.h4
-rw-r--r--include/uapi/linux/ethtool.h4
-rw-r--r--include/uapi/linux/gen_stats.h11
-rw-r--r--include/uapi/linux/if_arp.h1
-rw-r--r--include/uapi/linux/if_link.h15
-rw-r--r--include/uapi/linux/if_pppox.h4
-rw-r--r--include/uapi/linux/if_tun.h2
-rw-r--r--include/uapi/linux/input.h17
-rw-r--r--include/uapi/linux/ip_vs.h6
-rw-r--r--include/uapi/linux/kvm.h2
-rw-r--r--include/uapi/linux/msdos_fs.h10
-rw-r--r--include/uapi/linux/netfilter/nfnetlink_queue.h2
-rw-r--r--include/uapi/linux/netfilter/xt_socket.h7
-rw-r--r--include/uapi/linux/nfc.h18
-rw-r--r--include/uapi/linux/nl80211.h37
-rw-r--r--include/uapi/linux/openvswitch.h20
-rw-r--r--include/uapi/linux/pci_regs.h2
-rw-r--r--include/uapi/linux/ptrace.h3
-rw-r--r--include/uapi/linux/rtnetlink.h2
-rw-r--r--include/uapi/linux/snmp.h2
-rw-r--r--include/uapi/linux/tipc.h2
-rw-r--r--include/uapi/linux/tipc_config.h2
-rw-r--r--include/uapi/linux/vfio.h42
-rw-r--r--include/uapi/linux/virtio_config.h3
-rw-r--r--include/uapi/linux/virtio_console.h3
-rw-r--r--include/uapi/linux/virtio_pci.h4
-rw-r--r--include/uapi/mtd/ubi-user.h5
-rw-r--r--include/uapi/sound/asound.h2
-rw-r--r--include/video/display_timing.h1
-rw-r--r--include/video/of_display_timing.h3
-rw-r--r--include/video/omap-panel-data.h209
-rw-r--r--include/video/omapdss.h293
-rw-r--r--include/video/uvesafb.h1
-rw-r--r--include/xen/acpi.h16
-rw-r--r--include/xen/hvm.h4
-rw-r--r--include/xen/interface/io/netif.h12
-rw-r--r--include/xen/interface/io/protocols.h2
-rw-r--r--init/Kconfig22
-rw-r--r--init/do_mounts.c2
-rw-r--r--init/main.c5
-rw-r--r--ipc/mqueue.c2
-rw-r--r--ipc/msg.c226
-rw-r--r--ipc/sem.c442
-rw-r--r--ipc/shm.c34
-rw-r--r--ipc/util.c36
-rw-r--r--ipc/util.h22
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditfilter.c8
-rw-r--r--kernel/auditsc.c12
-rw-r--r--kernel/cgroup.c1536
-rw-r--r--kernel/cpuset.c478
-rw-r--r--kernel/events/core.c4
-rw-r--r--kernel/exit.c15
-rw-r--r--kernel/fork.c70
-rw-r--r--kernel/freezer.c12
-rw-r--r--kernel/hrtimer.c35
-rw-r--r--kernel/irq/generic-chip.c8
-rw-r--r--kernel/irq/irqdomain.c579
-rw-r--r--kernel/irq/proc.c2
-rw-r--r--kernel/kmod.c11
-rw-r--r--kernel/kprobes.c3
-rw-r--r--kernel/lockdep.c17
-rw-r--r--kernel/module.c77
-rw-r--r--kernel/panic.c8
-rw-r--r--kernel/params.c2
-rw-r--r--kernel/pid.c14
-rw-r--r--kernel/posix-cpu-timers.c395
-rw-r--r--kernel/power/Kconfig20
-rw-r--r--kernel/power/main.c6
-rw-r--r--kernel/power/process.c26
-rw-r--r--kernel/power/qos.c14
-rw-r--r--kernel/power/snapshot.c9
-rw-r--r--kernel/power/suspend.c2
-rw-r--r--kernel/printk.c2
-rw-r--r--kernel/ptrace.c61
-rw-r--r--kernel/rcutree.c2
-rw-r--r--kernel/reboot.c419
-rw-r--r--kernel/resource.c1
-rw-r--r--kernel/sched/stats.h39
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/sys.c352
-rw-r--r--kernel/sysctl.c7
-rw-r--r--kernel/sysctl_binary.c1
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/alarmtimer.c47
-rw-r--r--kernel/time/clockevents.c271
-rw-r--r--kernel/time/clocksource.c266
-rw-r--r--kernel/time/sched_clock.c (renamed from arch/arm/kernel/sched_clock.c)17
-rw-r--r--kernel/time/tick-broadcast.c126
-rw-r--r--kernel/time/tick-common.c197
-rw-r--r--kernel/time/tick-internal.h17
-rw-r--r--kernel/time/timekeeping.c65
-rw-r--r--kernel/time/timekeeping_debug.c72
-rw-r--r--kernel/time/timekeeping_internal.h14
-rw-r--r--kernel/timer.c8
-rw-r--r--kernel/trace/ftrace.c38
-rw-r--r--kernel/trace/trace.c338
-rw-r--r--kernel/trace/trace.h17
-rw-r--r--kernel/trace/trace_events.c166
-rw-r--r--kernel/trace/trace_events_filter.c6
-rw-r--r--kernel/trace/trace_functions.c103
-rw-r--r--kernel/trace/trace_irqsoff.c4
-rw-r--r--kernel/trace/trace_kprobe.c190
-rw-r--r--kernel/trace/trace_selftest.c18
-rw-r--r--kernel/trace/trace_syscalls.c21
-rw-r--r--kernel/trace/trace_uprobe.c4
-rw-r--r--kernel/workqueue.c26
-rw-r--r--lib/Kconfig17
-rw-r--r--lib/Kconfig.debug1076
-rw-r--r--lib/Kconfig.kgdb4
-rw-r--r--lib/Makefile10
-rw-r--r--lib/clz_ctz.c58
-rw-r--r--lib/crc-t10dif.c73
-rw-r--r--lib/decompress.c5
-rw-r--r--lib/decompress_unlz4.c187
-rw-r--r--lib/dump_stack.c47
-rw-r--r--lib/fonts/Kconfig117
-rw-r--r--lib/fonts/Makefile18
-rw-r--r--lib/fonts/font_10x18.c (renamed from drivers/video/console/font_10x18.c)0
-rw-r--r--lib/fonts/font_6x11.c (renamed from drivers/video/console/font_6x11.c)0
-rw-r--r--lib/fonts/font_7x14.c (renamed from drivers/video/console/font_7x14.c)0
-rw-r--r--lib/fonts/font_8x16.c (renamed from drivers/video/console/font_8x16.c)0
-rw-r--r--lib/fonts/font_8x8.c (renamed from drivers/video/console/font_8x8.c)0
-rw-r--r--lib/fonts/font_acorn_8x8.c (renamed from drivers/video/console/font_acorn_8x8.c)0
-rw-r--r--lib/fonts/font_mini_4x6.c (renamed from drivers/video/console/font_mini_4x6.c)0
-rw-r--r--lib/fonts/font_pearl_8x8.c (renamed from drivers/video/console/font_pearl_8x8.c)0
-rw-r--r--lib/fonts/font_sun12x22.c (renamed from drivers/video/console/font_sun12x22.c)0
-rw-r--r--lib/fonts/font_sun8x16.c (renamed from drivers/video/console/font_sun8x16.c)0
-rw-r--r--lib/fonts/fonts.c (renamed from drivers/video/console/fonts.c)2
-rw-r--r--lib/idr.c7
-rw-r--r--lib/lz4/Makefile3
-rw-r--r--lib/lz4/lz4_compress.c443
-rw-r--r--lib/lz4/lz4_decompress.c326
-rw-r--r--lib/lz4/lz4defs.h156
-rw-r--r--lib/lz4/lz4hc_compress.c539
-rw-r--r--lib/percpu-refcount.c158
-rw-r--r--lib/percpu_counter.c2
-rw-r--r--lib/scatterlist.c133
-rw-r--r--lib/vsprintf.c126
-rw-r--r--mm/Kconfig42
-rw-r--r--mm/Makefile2
-rw-r--r--mm/backing-dev.c5
-rw-r--r--mm/bootmem.c39
-rw-r--r--mm/filemap.c6
-rw-r--r--mm/huge_memory.c30
-rw-r--r--mm/hugetlb.c223
-rw-r--r--mm/internal.h5
-rw-r--r--mm/memblock.c2
-rw-r--r--mm/memcontrol.c363
-rw-r--r--mm/memory-failure.c22
-rw-r--r--mm/memory.c15
-rw-r--r--mm/memory_hotplug.c139
-rw-r--r--mm/mm_init.c47
-rw-r--r--mm/mmap.c40
-rw-r--r--mm/mmu_notifier.c2
-rw-r--r--mm/mremap.c20
-rw-r--r--mm/nobootmem.c35
-rw-r--r--mm/nommu.c10
-rw-r--r--mm/page_alloc.c384
-rw-r--r--mm/page_io.c50
-rw-r--r--mm/pgtable-generic.c5
-rw-r--r--mm/rmap.c9
-rw-r--r--mm/shmem.c45
-rw-r--r--mm/sparse.c8
-rw-r--r--mm/swap.c106
-rw-r--r--mm/swapfile.c55
-rw-r--r--mm/util.c1
-rw-r--r--mm/vmalloc.c164
-rw-r--r--mm/vmscan.c605
-rw-r--r--mm/zbud.c527
-rw-r--r--mm/zswap.c943
-rw-r--r--net/8021q/vlan.c2
-rw-r--r--net/9p/client.c75
-rw-r--r--net/9p/trans_fd.c40
-rw-r--r--net/9p/trans_rdma.c133
-rw-r--r--net/Kconfig17
-rw-r--r--net/Makefile1
-rw-r--r--net/appletalk/aarp.c2
-rw-r--r--net/appletalk/ddp.c2
-rw-r--r--net/atm/clip.c8
-rw-r--r--net/atm/mpc.c6
-rw-r--r--net/ax25/af_ax25.c6
-rw-r--r--net/ax25/sysctl_net_ax25.c2
-rw-r--r--net/batman-adv/Makefile1
-rw-r--r--net/batman-adv/bat_iv_ogm.c123
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c94
-rw-r--r--net/batman-adv/bridge_loop_avoidance.h12
-rw-r--r--net/batman-adv/distributed-arp-table.c82
-rw-r--r--net/batman-adv/hard-interface.c98
-rw-r--r--net/batman-adv/icmp_socket.c4
-rw-r--r--net/batman-adv/main.c1
-rw-r--r--net/batman-adv/main.h18
-rw-r--r--net/batman-adv/network-coding.c22
-rw-r--r--net/batman-adv/network-coding.h6
-rw-r--r--net/batman-adv/originator.c6
-rw-r--r--net/batman-adv/originator.h2
-rw-r--r--net/batman-adv/ring_buffer.c51
-rw-r--r--net/batman-adv/ring_buffer.h27
-rw-r--r--net/batman-adv/routing.c64
-rw-r--r--net/batman-adv/routing.h1
-rw-r--r--net/batman-adv/send.c36
-rw-r--r--net/batman-adv/send.h6
-rw-r--r--net/batman-adv/soft-interface.c6
-rw-r--r--net/batman-adv/translation-table.c74
-rw-r--r--net/batman-adv/translation-table.h2
-rw-r--r--net/batman-adv/types.h6
-rw-r--r--net/batman-adv/unicast.c2
-rw-r--r--net/batman-adv/vis.c19
-rw-r--r--net/bluetooth/hci_core.c201
-rw-r--r--net/bluetooth/hci_event.c71
-rw-r--r--net/bluetooth/hidp/core.c70
-rw-r--r--net/bluetooth/hidp/hidp.h2
-rw-r--r--net/bluetooth/l2cap_core.c121
-rw-r--r--net/bluetooth/l2cap_sock.c4
-rw-r--r--net/bluetooth/mgmt.c229
-rw-r--r--net/bridge/br_device.c21
-rw-r--r--net/bridge/br_fdb.c5
-rw-r--r--net/bridge/br_forward.c14
-rw-r--r--net/bridge/br_if.c2
-rw-r--r--net/bridge/br_input.c15
-rw-r--r--net/bridge/br_mdb.c2
-rw-r--r--net/bridge/br_multicast.c74
-rw-r--r--net/bridge/br_netfilter.c4
-rw-r--r--net/bridge/br_netlink.c10
-rw-r--r--net/bridge/br_notify.c2
-rw-r--r--net/bridge/br_private.h9
-rw-r--r--net/bridge/br_sysfs_br.c26
-rw-r--r--net/bridge/br_sysfs_if.c4
-rw-r--r--net/bridge/netfilter/ebt_ulog.c6
-rw-r--r--net/bridge/netfilter/ebtables.c6
-rw-r--r--net/caif/caif_dev.c4
-rw-r--r--net/caif/caif_usb.c4
-rw-r--r--net/can/af_can.c4
-rw-r--r--net/can/bcm.c4
-rw-r--r--net/can/gw.c4
-rw-r--r--net/can/raw.c4
-rw-r--r--net/ceph/auth_none.c6
-rw-r--r--net/ceph/osd_client.c63
-rw-r--r--net/core/datagram.c5
-rw-r--r--net/core/dev.c238
-rw-r--r--net/core/drop_monitor.c4
-rw-r--r--net/core/dst.c2
-rw-r--r--net/core/ethtool.c24
-rw-r--r--net/core/fib_rules.c4
-rw-r--r--net/core/gen_estimator.c12
-rw-r--r--net/core/gen_stats.c22
-rw-r--r--net/core/link_watch.c3
-rw-r--r--net/core/neighbour.c34
-rw-r--r--net/core/net-procfs.c16
-rw-r--r--net/core/netpoll.c16
-rw-r--r--net/core/netprio_cgroup.c2
-rw-r--r--net/core/pktgen.c81
-rw-r--r--net/core/rtnetlink.c32
-rw-r--r--net/core/skbuff.c69
-rw-r--r--net/core/sock.c26
-rw-r--r--net/core/sysctl_net_core.c139
-rw-r--r--net/decnet/af_decnet.c4
-rw-r--r--net/decnet/dn_dev.c6
-rw-r--r--net/decnet/sysctl_net_decnet.c6
-rw-r--r--net/ieee802154/6lowpan.c5
-rw-r--r--net/ipv4/Kconfig11
-rw-r--r--net/ipv4/Makefile7
-rw-r--r--net/ipv4/af_inet.c26
-rw-r--r--net/ipv4/ah4.c7
-rw-r--r--net/ipv4/arp.c8
-rw-r--r--net/ipv4/devinet.c9
-rw-r--r--net/ipv4/esp4.c7
-rw-r--r--net/ipv4/fib_frontend.c4
-rw-r--r--net/ipv4/fib_semantics.c3
-rw-r--r--net/ipv4/gre.c253
-rw-r--r--net/ipv4/gre_demux.c414
-rw-r--r--net/ipv4/gre_offload.c127
-rw-r--r--net/ipv4/icmp.c51
-rw-r--r--net/ipv4/igmp.c79
-rw-r--r--net/ipv4/inet_fragment.c4
-rw-r--r--net/ipv4/ip_gre.c258
-rw-r--r--net/ipv4/ip_tunnel.c177
-rw-r--r--net/ipv4/ip_tunnel_core.c122
-rw-r--r--net/ipv4/ip_vti.c7
-rw-r--r--net/ipv4/ipcomp.c7
-rw-r--r--net/ipv4/ipip.c20
-rw-r--r--net/ipv4/ipmr.c4
-rw-r--r--net/ipv4/netfilter/Kconfig2
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c7
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c6
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c2
-rw-r--r--net/ipv4/ping.c641
-rw-r--r--net/ipv4/proc.c1
-rw-r--r--net/ipv4/route.c144
-rw-r--r--net/ipv4/sysctl_net_ipv4.c31
-rw-r--r--net/ipv4/tcp.c344
-rw-r--r--net/ipv4/tcp_input.c517
-rw-r--r--net/ipv4/tcp_ipv4.c78
-rw-r--r--net/ipv4/tcp_minisocks.c6
-rw-r--r--net/ipv4/tcp_offload.c332
-rw-r--r--net/ipv4/tcp_output.c39
-rw-r--r--net/ipv4/udp.c90
-rw-r--r--net/ipv4/udp_offload.c100
-rw-r--r--net/ipv4/xfrm4_tunnel.c2
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/addrconf.c304
-rw-r--r--net/ipv6/addrconf_core.c1
-rw-r--r--net/ipv6/af_inet6.c12
-rw-r--r--net/ipv6/datagram.c27
-rw-r--r--net/ipv6/exthdrs_core.c2
-rw-r--r--net/ipv6/icmp.c23
-rw-r--r--net/ipv6/ip6_offload.c1
-rw-r--r--net/ipv6/ip6_output.c16
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/mcast.c75
-rw-r--r--net/ipv6/mip6.c6
-rw-r--r--net/ipv6/ndisc.c11
-rw-r--r--net/ipv6/netfilter/ip6t_MASQUERADE.c6
-rw-r--r--net/ipv6/output_core.c3
-rw-r--r--net/ipv6/ping.c277
-rw-r--r--net/ipv6/raw.c48
-rw-r--r--net/ipv6/route.c24
-rw-r--r--net/ipv6/sit.c211
-rw-r--r--net/ipv6/sysctl_net_ipv6.c4
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/ipv6/udp.c62
-rw-r--r--net/ipv6/udp_offload.c3
-rw-r--r--net/ipx/af_ipx.c2
-rw-r--r--net/irda/irsysctl.c6
-rw-r--r--net/iucv/af_iucv.c2
-rw-r--r--net/l2tp/l2tp_core.c114
-rw-r--r--net/l2tp/l2tp_core.h5
-rw-r--r--net/l2tp/l2tp_ppp.c3
-rw-r--r--net/mac80211/aes_ccm.c6
-rw-r--r--net/mac80211/cfg.c67
-rw-r--r--net/mac80211/debugfs_netdev.c15
-rw-r--r--net/mac80211/driver-ops.h3
-rw-r--r--net/mac80211/ht.c8
-rw-r--r--net/mac80211/ibss.c114
-rw-r--r--net/mac80211/ieee80211_i.h37
-rw-r--r--net/mac80211/iface.c34
-rw-r--r--net/mac80211/key.c24
-rw-r--r--net/mac80211/key.h15
-rw-r--r--net/mac80211/main.c9
-rw-r--r--net/mac80211/mesh.c107
-rw-r--r--net/mac80211/mesh.h7
-rw-r--r--net/mac80211/mesh_plink.c8
-rw-r--r--net/mac80211/mlme.c436
-rw-r--r--net/mac80211/rate.c8
-rw-r--r--net/mac80211/rx.c56
-rw-r--r--net/mac80211/scan.c9
-rw-r--r--net/mac80211/sta_info.c8
-rw-r--r--net/mac80211/sta_info.h9
-rw-r--r--net/mac80211/tx.c11
-rw-r--r--net/mac80211/util.c41
-rw-r--r--net/mac80211/vht.c2
-rw-r--r--net/mac80211/wep.c48
-rw-r--r--net/mac80211/wpa.c68
-rw-r--r--net/mpls/Kconfig9
-rw-r--r--net/mpls/Makefile4
-rw-r--r--net/mpls/mpls_gso.c108
-rw-r--r--net/netfilter/core.c21
-rw-r--r--net/netfilter/ipvs/ip_vs_conn.c35
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c4
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c35
-rw-r--r--net/netfilter/ipvs/ip_vs_dh.c10
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_lc.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_nq.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c860
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_tcp.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_rr.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_sed.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c108
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c19
-rw-r--r--net/netfilter/ipvs/ip_vs_wlc.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_wrr.c3
-rw-r--r--net/netfilter/nf_conntrack_ftp.c73
-rw-r--r--net/netfilter/nf_conntrack_netlink.c30
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c6
-rw-r--r--net/netfilter/nf_conntrack_standalone.c4
-rw-r--r--net/netfilter/nf_log.c6
-rw-r--r--net/netfilter/nf_nat_helper.c2
-rw-r--r--net/netfilter/nfnetlink_cthelper.c16
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c6
-rw-r--r--net/netfilter/nfnetlink_queue_core.c47
-rw-r--r--net/netfilter/xt_CT.c10
-rw-r--r--net/netfilter/xt_TEE.c2
-rw-r--r--net/netfilter/xt_rateest.c2
-rw-r--r--net/netfilter/xt_socket.c96
-rw-r--r--net/netlabel/netlabel_unlabeled.c7
-rw-r--r--net/netlink/af_netlink.c178
-rw-r--r--net/netlink/af_netlink.h1
-rw-r--r--net/netrom/af_netrom.c2
-rw-r--r--net/netrom/sysctl_net_netrom.c2
-rw-r--r--net/nfc/core.c224
-rw-r--r--net/nfc/hci/core.c75
-rw-r--r--net/nfc/llcp.h3
-rw-r--r--net/nfc/llcp_commands.c22
-rw-r--r--net/nfc/llcp_core.c16
-rw-r--r--net/nfc/llcp_sock.c19
-rw-r--r--net/nfc/nci/Kconfig10
-rw-r--r--net/nfc/nci/Makefile4
-rw-r--r--net/nfc/nci/core.c37
-rw-r--r--net/nfc/nci/data.c2
-rw-r--r--net/nfc/nci/spi.c378
-rw-r--r--net/nfc/netlink.c183
-rw-r--r--net/nfc/nfc.h11
-rw-r--r--net/openvswitch/Kconfig14
-rw-r--r--net/openvswitch/Makefile3
-rw-r--r--net/openvswitch/actions.c8
-rw-r--r--net/openvswitch/datapath.c371
-rw-r--r--net/openvswitch/datapath.h4
-rw-r--r--net/openvswitch/dp_notify.c2
-rw-r--r--net/openvswitch/flow.c211
-rw-r--r--net/openvswitch/flow.h47
-rw-r--r--net/openvswitch/vport-gre.c275
-rw-r--r--net/openvswitch/vport-internal_dev.c3
-rw-r--r--net/openvswitch/vport-netdev.c9
-rw-r--r--net/openvswitch/vport-netdev.h1
-rw-r--r--net/openvswitch/vport.c34
-rw-r--r--net/openvswitch/vport.h23
-rw-r--r--net/packet/af_packet.c5
-rw-r--r--net/phonet/pn_dev.c4
-rw-r--r--net/phonet/sysctl.c4
-rw-r--r--net/rds/ib_sysctl.c2
-rw-r--r--net/rds/iw_sysctl.c2
-rw-r--r--net/rds/sysctl.c2
-rw-r--r--net/rose/af_rose.c6
-rw-r--r--net/rose/sysctl_net_rose.c2
-rw-r--r--net/sched/act_mirred.c2
-rw-r--r--net/sched/sch_cbq.c2
-rw-r--r--net/sched/sch_drr.c2
-rw-r--r--net/sched/sch_generic.c44
-rw-r--r--net/sched/sch_hfsc.c2
-rw-r--r--net/sched/sch_htb.c261
-rw-r--r--net/sched/sch_netem.c111
-rw-r--r--net/sched/sch_qfq.c2
-rw-r--r--net/sched/sch_tbf.c47
-rw-r--r--net/sctp/Kconfig11
-rw-r--r--net/sctp/associola.c84
-rw-r--r--net/sctp/bind_addr.c2
-rw-r--r--net/sctp/chunk.c7
-rw-r--r--net/sctp/debug.c4
-rw-r--r--net/sctp/endpointola.c25
-rw-r--r--net/sctp/input.c12
-rw-r--r--net/sctp/inqueue.c9
-rw-r--r--net/sctp/ipv6.c29
-rw-r--r--net/sctp/output.c40
-rw-r--r--net/sctp/outqueue.c214
-rw-r--r--net/sctp/proc.c12
-rw-r--r--net/sctp/protocol.c56
-rw-r--r--net/sctp/sm_make_chunk.c54
-rw-r--r--net/sctp/sm_sideeffect.c107
-rw-r--r--net/sctp/sm_statefuns.c85
-rw-r--r--net/sctp/socket.c289
-rw-r--r--net/sctp/sysctl.c10
-rw-r--r--net/sctp/transport.c51
-rw-r--r--net/sctp/tsnmap.c10
-rw-r--r--net/sctp/ulpevent.c10
-rw-r--r--net/socket.c23
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c5
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c14
-rw-r--r--net/sunrpc/cache.c83
-rw-r--r--net/sunrpc/clnt.c73
-rw-r--r--net/sunrpc/rpc_pipe.c29
-rw-r--r--net/sunrpc/sched.c21
-rw-r--r--net/sunrpc/svc.c2
-rw-r--r--net/sunrpc/svcauth_unix.c6
-rw-r--r--net/sunrpc/svcsock.c9
-rw-r--r--net/sunrpc/sysctl.c10
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma.c8
-rw-r--r--net/sunrpc/xprtrdma/transport.c4
-rw-r--r--net/sunrpc/xprtsock.c5
-rw-r--r--net/tipc/Makefile3
-rw-r--r--net/tipc/bcast.c3
-rw-r--r--net/tipc/bcast.h3
-rw-r--r--net/tipc/config.c119
-rw-r--r--net/tipc/core.c22
-rw-r--r--net/tipc/core.h17
-rw-r--r--net/tipc/discover.c7
-rw-r--r--net/tipc/eth_media.c19
-rw-r--r--net/tipc/ib_media.c17
-rw-r--r--net/tipc/link.c88
-rw-r--r--net/tipc/msg.c19
-rw-r--r--net/tipc/msg.h8
-rw-r--r--net/tipc/name_table.c10
-rw-r--r--net/tipc/name_table.h11
-rw-r--r--net/tipc/node_subscr.c2
-rw-r--r--net/tipc/port.c320
-rw-r--r--net/tipc/port.h85
-rw-r--r--net/tipc/server.c596
-rw-r--r--net/tipc/server.h94
-rw-r--r--net/tipc/socket.c146
-rw-r--r--net/tipc/subscr.c348
-rw-r--r--net/tipc/subscr.h21
-rw-r--r--net/tipc/sysctl.c64
-rw-r--r--net/unix/af_unix.c3
-rw-r--r--net/unix/sysctl_net_unix.c2
-rw-r--r--net/vmw_vsock/af_vsock.c55
-rw-r--r--net/vmw_vsock/vmci_transport.c18
-rw-r--r--net/wireless/chan.c57
-rw-r--r--net/wireless/core.c270
-rw-r--r--net/wireless/core.h123
-rw-r--r--net/wireless/debugfs.c4
-rw-r--r--net/wireless/ibss.c16
-rw-r--r--net/wireless/mesh.c15
-rw-r--r--net/wireless/mlme.c433
-rw-r--r--net/wireless/nl80211.c814
-rw-r--r--net/wireless/reg.c138
-rw-r--r--net/wireless/scan.c51
-rw-r--r--net/wireless/sme.c652
-rw-r--r--net/wireless/sysfs.c8
-rw-r--r--net/wireless/trace.h46
-rw-r--r--net/wireless/util.c39
-rw-r--r--net/wireless/wext-compat.c22
-rw-r--r--net/wireless/wext-sme.c49
-rw-r--r--net/x25/af_x25.c17
-rw-r--r--net/xfrm/xfrm_input.c5
-rw-r--r--net/xfrm/xfrm_output.c9
-rw-r--r--net/xfrm/xfrm_policy.c2
-rw-r--r--net/xfrm/xfrm_proc.c1
-rw-r--r--scripts/Makefile.headersinst20
-rw-r--r--scripts/Makefile.lib9
-rwxr-xr-xscripts/checkpatch.pl652
-rwxr-xr-xscripts/coccicheck76
-rw-r--r--scripts/coccinelle/api/alloc/drop_kmalloc_cast.cocci2
-rw-r--r--scripts/coccinelle/api/alloc/kzalloc-simple.cocci2
-rw-r--r--scripts/coccinelle/api/d_find_alias.cocci2
-rw-r--r--scripts/coccinelle/api/devm_request_and_ioremap.cocci2
-rw-r--r--scripts/coccinelle/api/kstrdup.cocci2
-rw-r--r--scripts/coccinelle/api/memdup.cocci2
-rw-r--r--scripts/coccinelle/api/memdup_user.cocci2
-rw-r--r--scripts/coccinelle/api/ptr_ret.cocci2
-rw-r--r--scripts/coccinelle/api/simple_open.cocci2
-rw-r--r--scripts/coccinelle/free/devm_free.cocci2
-rw-r--r--scripts/coccinelle/free/kfree.cocci2
-rw-r--r--scripts/coccinelle/free/kfreeaddr.cocci32
-rw-r--r--scripts/coccinelle/free/pci_free_consistent.cocci52
-rw-r--r--scripts/coccinelle/iterators/fen.cocci2
-rw-r--r--scripts/coccinelle/iterators/itnull.cocci2
-rw-r--r--scripts/coccinelle/iterators/list_entry_update.cocci2
-rw-r--r--scripts/coccinelle/iterators/use_after_iter.cocci2
-rw-r--r--scripts/coccinelle/locks/call_kern.cocci2
-rw-r--r--scripts/coccinelle/locks/double_lock.cocci2
-rw-r--r--scripts/coccinelle/locks/flags.cocci2
-rw-r--r--scripts/coccinelle/locks/mini_lock.cocci2
-rw-r--r--scripts/coccinelle/misc/boolinit.cocci2
-rw-r--r--scripts/coccinelle/misc/cstptr.cocci2
-rw-r--r--scripts/coccinelle/misc/doubleinit.cocci2
-rw-r--r--scripts/coccinelle/misc/ifaddr.cocci2
-rw-r--r--scripts/coccinelle/misc/ifcol.cocci2
-rw-r--r--scripts/coccinelle/misc/noderef.cocci2
-rw-r--r--scripts/coccinelle/misc/orplus.cocci2
-rw-r--r--scripts/coccinelle/misc/warn.cocci2
-rw-r--r--scripts/coccinelle/null/eno.cocci2
-rw-r--r--scripts/coccinelle/null/kmerr.cocci2
-rw-r--r--scripts/coccinelle/tests/doublebitand.cocci2
-rw-r--r--scripts/coccinelle/tests/doubletest.cocci2
-rw-r--r--scripts/coccinelle/tests/odd_ptr_err.cocci2
-rwxr-xr-xscripts/config12
-rw-r--r--scripts/headers_install.sh7
-rw-r--r--scripts/kconfig/conf.c6
-rw-r--r--scripts/kconfig/confdata.c33
-rw-r--r--scripts/kconfig/expr.h3
-rw-r--r--scripts/kconfig/lkc.h3
-rw-r--r--scripts/kconfig/lkc_proto.h1
-rw-r--r--scripts/kconfig/lxdialog/checklist.c8
-rw-r--r--scripts/kconfig/lxdialog/dialog.h14
-rw-r--r--scripts/kconfig/lxdialog/inputbox.c8
-rw-r--r--scripts/kconfig/lxdialog/menubox.c6
-rw-r--r--scripts/kconfig/lxdialog/textbox.c6
-rw-r--r--scripts/kconfig/lxdialog/util.c46
-rw-r--r--scripts/kconfig/lxdialog/yesno.c8
-rw-r--r--scripts/kconfig/mconf.c21
-rw-r--r--scripts/kconfig/menu.c16
-rw-r--r--scripts/kconfig/nconf.c39
-rw-r--r--scripts/kconfig/nconf.gui.c20
-rw-r--r--scripts/kconfig/symbol.c99
-rw-r--r--scripts/mod/Makefile15
-rw-r--r--scripts/mod/devicetable-offsets.c6
-rw-r--r--scripts/mod/file2alias.c30
-rw-r--r--scripts/mod/modpost.c54
-rwxr-xr-xscripts/package/mkspec1
-rwxr-xr-xscripts/setlocalversion3
-rw-r--r--scripts/sortextable.c5
-rw-r--r--security/apparmor/audit.c2
-rw-r--r--security/apparmor/context.c44
-rw-r--r--security/apparmor/domain.c26
-rw-r--r--security/apparmor/include/apparmor.h12
-rw-r--r--security/apparmor/include/context.h61
-rw-r--r--security/apparmor/include/file.h14
-rw-r--r--security/apparmor/include/match.h21
-rw-r--r--security/apparmor/include/policy.h16
-rw-r--r--security/apparmor/include/procattr.h1
-rw-r--r--security/apparmor/include/sid.h4
-rw-r--r--security/apparmor/ipc.c13
-rw-r--r--security/apparmor/lib.c44
-rw-r--r--security/apparmor/lsm.c69
-rw-r--r--security/apparmor/match.c23
-rw-r--r--security/apparmor/path.c2
-rw-r--r--security/apparmor/policy.c181
-rw-r--r--security/apparmor/policy_unpack.c4
-rw-r--r--security/apparmor/procattr.c6
-rw-r--r--security/apparmor/resource.c15
-rw-r--r--security/capability.c21
-rw-r--r--security/device_cgroup.c56
-rw-r--r--security/integrity/Kconfig15
-rw-r--r--security/integrity/Makefile1
-rw-r--r--security/integrity/evm/evm_main.c15
-rw-r--r--security/integrity/ima/Kconfig12
-rw-r--r--security/integrity/ima/Makefile1
-rw-r--r--security/integrity/ima/ima.h14
-rw-r--r--security/integrity/ima/ima_main.c2
-rw-r--r--security/integrity/integrity.h14
-rw-r--r--security/integrity/integrity_audit.c (renamed from security/integrity/ima/ima_audit.c)12
-rw-r--r--security/security.c24
-rw-r--r--security/selinux/hooks.c116
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/netif.c2
-rw-r--r--security/selinux/ss/policydb.c5
-rw-r--r--security/smack/smack.h110
-rw-r--r--security/smack/smack_access.c43
-rw-r--r--security/smack/smack_lsm.c695
-rw-r--r--security/smack/smackfs.c53
-rw-r--r--sound/arm/aaci.c2
-rw-r--r--sound/arm/pxa2xx-ac97.c1
-rw-r--r--sound/core/Kconfig9
-rw-r--r--sound/core/init.c55
-rw-r--r--sound/core/pcm_lib.c3
-rw-r--r--sound/core/pcm_native.c40
-rw-r--r--sound/core/vmaster.c65
-rw-r--r--sound/drivers/aloop.c1
-rw-r--r--sound/drivers/dummy.c1
-rw-r--r--sound/drivers/ml403-ac97cr.c1
-rw-r--r--sound/drivers/mpu401/mpu401.c1
-rw-r--r--sound/drivers/mtpav.c1
-rw-r--r--sound/drivers/pcsp/pcsp.c1
-rw-r--r--sound/drivers/serial-u16550.c1
-rw-r--r--sound/drivers/virmidi.c1
-rw-r--r--sound/drivers/vx/vx_core.c2
-rw-r--r--sound/firewire/amdtp.h1
-rw-r--r--sound/firewire/isight.c44
-rw-r--r--sound/firewire/scs1x.c43
-rw-r--r--sound/firewire/speakers.c106
-rw-r--r--sound/i2c/other/ak4xxx-adda.c2
-rw-r--r--sound/isa/ad1848/ad1848.c1
-rw-r--r--sound/isa/adlib.c1
-rw-r--r--sound/isa/cmi8328.c1
-rw-r--r--sound/isa/cmi8330.c1
-rw-r--r--sound/isa/cs423x/cs4231.c1
-rw-r--r--sound/isa/cs423x/cs4236.c2
-rw-r--r--sound/isa/es1688/es1688.c1
-rw-r--r--sound/isa/es18xx.c2
-rw-r--r--sound/isa/galaxy/galaxy.c1
-rw-r--r--sound/isa/gus/gusclassic.c1
-rw-r--r--sound/isa/gus/gusextreme.c1
-rw-r--r--sound/isa/gus/gusmax.c1
-rw-r--r--sound/isa/gus/interwave.c1
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c1
-rw-r--r--sound/isa/opl3sa2.c2
-rw-r--r--sound/isa/opti9xx/miro.c1
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c1
-rw-r--r--sound/isa/sb/jazz16.c1
-rw-r--r--sound/isa/sb/sb16.c1
-rw-r--r--sound/isa/sb/sb8.c1
-rw-r--r--sound/isa/sc6000.c1
-rw-r--r--sound/isa/sscape.c1
-rw-r--r--sound/isa/wavefront/wavefront.c1
-rw-r--r--sound/oss/kahlua.c2
-rw-r--r--sound/parisc/harmony.c3
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ad1889.c1
-rw-r--r--sound/pci/ali5451/ali5451.c1
-rw-r--r--sound/pci/als300.c1
-rw-r--r--sound/pci/als4000.c1
-rw-r--r--sound/pci/asihpi/asihpi.c2
-rw-r--r--sound/pci/asihpi/hpioctl.c1
-rw-r--r--sound/pci/atiixp.c1
-rw-r--r--sound/pci/atiixp_modem.c1
-rw-r--r--sound/pci/au88x0/au88x0.c1
-rw-r--r--sound/pci/aw2/aw2-alsa.c1
-rw-r--r--sound/pci/azt3328.c1
-rw-r--r--sound/pci/bt87x.c1
-rw-r--r--sound/pci/ca0106/ca0106_main.c1
-rw-r--r--sound/pci/cmipci.c1
-rw-r--r--sound/pci/cs4281.c3
-rw-r--r--sound/pci/cs46xx/cs46xx.c1
-rw-r--r--sound/pci/cs5530.c1
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c1
-rw-r--r--sound/pci/ctxfi/xfi.c1
-rw-r--r--sound/pci/echoaudio/echoaudio.c1
-rw-r--r--sound/pci/emu10k1/emu10k1.c1
-rw-r--r--sound/pci/emu10k1/emu10k1x.c1
-rw-r--r--sound/pci/ens1370.c3
-rw-r--r--sound/pci/es1938.c1
-rw-r--r--sound/pci/es1968.c74
-rw-r--r--sound/pci/fm801.c1
-rw-r--r--sound/pci/hda/Kconfig11
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_codec.c69
-rw-r--r--sound/pci/hda/hda_codec.h11
-rw-r--r--sound/pci/hda/hda_generic.c59
-rw-r--r--sound/pci/hda/hda_generic.h4
-rw-r--r--sound/pci/hda/hda_i915.c75
-rw-r--r--sound/pci/hda/hda_i915.h35
-rw-r--r--sound/pci/hda/hda_intel.c140
-rw-r--r--sound/pci/hda/hda_jack.c2
-rw-r--r--sound/pci/hda/hda_local.h10
-rw-r--r--sound/pci/hda/hda_proc.c15
-rw-r--r--sound/pci/hda/patch_analog.c12
-rw-r--r--sound/pci/hda/patch_ca0132.c8
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_hdmi.c128
-rw-r--r--sound/pci/hda/patch_realtek.c132
-rw-r--r--sound/pci/hda/patch_sigmatel.c14
-rw-r--r--sound/pci/hda/patch_via.c15
-rw-r--r--sound/pci/ice1712/ice1712.c1
-rw-r--r--sound/pci/ice1712/ice1724.c1
-rw-r--r--sound/pci/intel8x0.c1
-rw-r--r--sound/pci/intel8x0m.c1
-rw-r--r--sound/pci/korg1212/korg1212.c1
-rw-r--r--sound/pci/lola/lola.c1
-rw-r--r--sound/pci/lx6464es/lx6464es.c1
-rw-r--r--sound/pci/maestro3.c1
-rw-r--r--sound/pci/mixart/mixart.c1
-rw-r--r--sound/pci/nm256/nm256.c1
-rw-r--r--sound/pci/oxygen/oxygen_lib.c1
-rw-r--r--sound/pci/pcxhr/pcxhr.c1
-rw-r--r--sound/pci/riptide/riptide.c2
-rw-r--r--sound/pci/rme32.c1
-rw-r--r--sound/pci/rme96.c1
-rw-r--r--sound/pci/rme9652/hdsp.c1
-rw-r--r--sound/pci/rme9652/hdspm.c59
-rw-r--r--sound/pci/rme9652/rme9652.c1
-rw-r--r--sound/pci/sis7019.c1
-rw-r--r--sound/pci/sonicvibes.c1
-rw-r--r--sound/pci/trident/trident.c1
-rw-r--r--sound/pci/via82xx.c1
-rw-r--r--sound/pci/via82xx_modem.c1
-rw-r--r--sound/pci/vx222/vx222.c1
-rw-r--r--sound/pci/ymfpci/ymfpci.c1
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c2
-rw-r--r--sound/ppc/powermac.c1
-rw-r--r--sound/sh/aica.c1
-rw-r--r--sound/sh/sh_dac_audio.c2
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile1
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c9
-rw-r--r--sound/soc/au1x/ac97c.c21
-rw-r--r--sound/soc/au1x/psc-ac97.c33
-rw-r--r--sound/soc/blackfin/Kconfig47
-rw-r--r--sound/soc/blackfin/Makefile4
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c1
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.h26
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c37
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c19
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c40
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c1
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c1
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c183
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.h21
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c129
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c10
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h2
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c1
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c345
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.h18
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c328
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h23
-rw-r--r--sound/soc/cirrus/Kconfig2
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c28
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c16
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c138
-rw-r--r--sound/soc/codecs/88pm860x-codec.c15
-rw-r--r--sound/soc/codecs/Kconfig18
-rw-r--r--sound/soc/codecs/Makefile14
-rw-r--r--sound/soc/codecs/ab8500-codec.c85
-rw-r--r--sound/soc/codecs/ab8500-codec.h42
-rw-r--r--sound/soc/codecs/ac97.c7
-rw-r--r--sound/soc/codecs/ad1980.c12
-rw-r--r--sound/soc/codecs/adau1701.c321
-rw-r--r--sound/soc/codecs/arizona.c7
-rw-r--r--sound/soc/codecs/arizona.h3
-rw-r--r--sound/soc/codecs/bt-sco.c (renamed from sound/soc/codecs/dfbmcs320.c)37
-rw-r--r--sound/soc/codecs/hdmi.c (renamed from sound/soc/codecs/omap-hdmi.c)26
-rw-r--r--sound/soc/codecs/jz4740.c2
-rw-r--r--sound/soc/codecs/max98090.c24
-rw-r--r--sound/soc/codecs/rt5640.c2128
-rw-r--r--sound/soc/codecs/rt5640.h2092
-rw-r--r--sound/soc/codecs/sgtl5000.c267
-rw-r--r--sound/soc/codecs/sgtl5000.h2
-rw-r--r--sound/soc/codecs/si476x.c6
-rw-r--r--sound/soc/codecs/sn95031.c2
-rw-r--r--sound/soc/codecs/spdif_receiver.c10
-rw-r--r--sound/soc/codecs/spdif_transmitter.c (renamed from sound/soc/codecs/spdif_transciever.c)10
-rw-r--r--sound/soc/codecs/ssm2518.c856
-rw-r--r--sound/soc/codecs/ssm2518.h20
-rw-r--r--sound/soc/codecs/stac9766.c26
-rw-r--r--sound/soc/codecs/tas5086.c330
-rw-r--r--sound/soc/codecs/tlv320aic3x.c6
-rw-r--r--sound/soc/codecs/twl6040.c109
-rw-r--r--sound/soc/codecs/wm0010.c10
-rw-r--r--sound/soc/codecs/wm5102.c205
-rw-r--r--sound/soc/codecs/wm5110.c192
-rw-r--r--sound/soc/codecs/wm8400.c9
-rw-r--r--sound/soc/codecs/wm8903.c6
-rw-r--r--sound/soc/codecs/wm8904.c9
-rw-r--r--sound/soc/codecs/wm8962.c145
-rw-r--r--sound/soc/codecs/wm8990.c11
-rw-r--r--sound/soc/codecs/wm8991.h9
-rw-r--r--sound/soc/codecs/wm8994.c200
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/codecs/wm8995.h7
-rw-r--r--sound/soc/codecs/wm9705.c16
-rw-r--r--sound/soc/codecs/wm9712.c18
-rw-r--r--sound/soc/codecs/wm9713.c18
-rw-r--r--sound/soc/codecs/wm_adsp.c461
-rw-r--r--sound/soc/codecs/wm_adsp.h13
-rw-r--r--sound/soc/codecs/wm_hubs.c6
-rw-r--r--sound/soc/davinci/Kconfig10
-rw-r--r--sound/soc/davinci/Makefile2
-rw-r--r--sound/soc/davinci/davinci-mcasp.c4
-rw-r--r--sound/soc/davinci/davinci-sffsdr.c181
-rw-r--r--sound/soc/dwc/designware_i2s.c6
-rw-r--r--sound/soc/fsl/Kconfig17
-rw-r--r--sound/soc/fsl/Makefile13
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c2
-rw-r--r--sound/soc/fsl/fsl_ssi.c13
-rw-r--r--sound/soc/fsl/imx-audmux.c8
-rw-r--r--sound/soc/fsl/imx-mc13783.c2
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c2
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c92
-rw-r--r--sound/soc/fsl/imx-pcm.c145
-rw-r--r--sound/soc/fsl/imx-pcm.h10
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c43
-rw-r--r--sound/soc/fsl/imx-ssi.c55
-rw-r--r--sound/soc/fsl/imx-ssi.h3
-rw-r--r--sound/soc/fsl/imx-wm8962.c323
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c10
-rw-r--r--sound/soc/fsl/mx27vis-aic32x4.c2
-rw-r--r--sound/soc/fsl/phycore-ac97.c2
-rw-r--r--sound/soc/fsl/wm1133-ev1.c2
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c17
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c2
-rw-r--r--sound/soc/mid-x86/mfld_machine.c32
-rw-r--r--sound/soc/mxs/mxs-pcm.c18
-rw-r--r--sound/soc/mxs/mxs-pcm.h7
-rw-r--r--sound/soc/mxs/mxs-saif.c72
-rw-r--r--sound/soc/mxs/mxs-saif.h1
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c10
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c60
-rw-r--r--sound/soc/omap/Kconfig2
-rw-r--r--sound/soc/omap/Makefile1
-rw-r--r--sound/soc/omap/omap-hdmi-card.c2
-rw-r--r--sound/soc/omap/omap-mcbsp.c2
-rw-r--r--sound/soc/pxa/Kconfig20
-rw-r--r--sound/soc/pxa/Makefile4
-rw-r--r--sound/soc/pxa/mmp-pcm.c6
-rw-r--r--sound/soc/pxa/mmp-sspa.c2
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c10
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.h3
-rw-r--r--sound/soc/pxa/saarb.c190
-rw-r--r--sound/soc/pxa/tavorevb3.c189
-rw-r--r--sound/soc/pxa/zylonite.c1
-rw-r--r--sound/soc/samsung/Kconfig2
-rw-r--r--sound/soc/samsung/ac97.c42
-rw-r--r--sound/soc/samsung/bells.c14
-rw-r--r--sound/soc/samsung/i2s.c66
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c2
-rw-r--r--sound/soc/samsung/s3c-i2s-v2.c4
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c1
-rw-r--r--sound/soc/samsung/smdk_wm8994pcm.c1
-rw-r--r--sound/soc/sh/fsi.c10
-rw-r--r--sound/soc/sh/hac.c8
-rw-r--r--sound/soc/soc-core.c123
-rw-r--r--sound/soc/soc-dapm.c110
-rw-r--r--sound/soc/soc-pcm.c91
-rw-r--r--sound/soc/soc-utils.c13
-rw-r--r--sound/soc/spear/Kconfig9
-rw-r--r--sound/soc/spear/Makefile8
-rw-r--r--sound/soc/spear/spdif_in.c31
-rw-r--r--sound/soc/spear/spdif_out.c43
-rw-r--r--sound/soc/spear/spear_pcm.c152
-rw-r--r--sound/soc/tegra/Kconfig10
-rw-r--r--sound/soc/tegra/Makefile2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c67
-rw-r--r--sound/soc/tegra/tegra30_ahub.c25
-rw-r--r--sound/soc/tegra/tegra30_i2s.c26
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c23
-rw-r--r--sound/soc/tegra/tegra_rt5640.c257
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c17
-rw-r--r--sound/soc/ux500/mop500.c2
-rw-r--r--sound/soc/ux500/mop500_ab8500.c62
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c11
-rw-r--r--sound/soc/ux500/ux500_msp_dai.h4
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c88
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h74
-rw-r--r--sound/soc/ux500/ux500_pcm.c30
-rw-r--r--sound/sound_core.c2
-rw-r--r--sound/sparc/dbri.c2
-rw-r--r--sound/spi/at73c213.c1
-rw-r--r--sound/usb/6fire/chip.c2
-rw-r--r--sound/usb/6fire/pcm.c12
-rw-r--r--sound/usb/Kconfig31
-rw-r--r--sound/usb/Makefile2
-rw-r--r--sound/usb/caiaq/audio.c14
-rw-r--r--sound/usb/caiaq/device.c31
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/clock.c4
-rw-r--r--sound/usb/format.c34
-rw-r--r--sound/usb/format.h2
-rw-r--r--sound/usb/hiface/Makefile2
-rw-r--r--sound/usb/hiface/chip.c297
-rw-r--r--sound/usb/hiface/chip.h30
-rw-r--r--sound/usb/hiface/pcm.c621
-rw-r--r--sound/usb/hiface/pcm.h24
-rw-r--r--sound/usb/midi.c74
-rw-r--r--sound/usb/misc/ua101.c2
-rw-r--r--sound/usb/mixer_quirks.c212
-rw-r--r--sound/usb/pcm.c45
-rw-r--r--sound/usb/quirks-table.h509
-rw-r--r--sound/usb/quirks.c213
-rw-r--r--sound/usb/stream.c18
-rw-r--r--sound/usb/usbaudio.h2
-rw-r--r--sound/usb/usx2y/usbusx2y.c2
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c3
-rw-r--r--tools/include/tools/be_byteshift.h34
-rw-r--r--tools/include/tools/le_byteshift.h34
-rw-r--r--tools/lguest/Makefile1
-rw-r--r--tools/lguest/lguest.c32
-rw-r--r--tools/power/cpupower/Makefile4
-rw-r--r--tools/power/cpupower/man/cpupower-monitor.110
-rw-r--r--tools/power/cpupower/utils/builtin.h1
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpuidle-set.c118
-rw-r--r--tools/power/cpupower/utils/cpupower.c13
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c118
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h10
-rw-r--r--tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c196
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c4
-rwxr-xr-xtools/testing/ktest/ktest.pl2
-rw-r--r--tools/testing/selftests/Makefile1
-rw-r--r--tools/testing/selftests/cpu-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/kcmp/.gitignore2
-rw-r--r--tools/testing/selftests/kcmp/Makefile3
-rw-r--r--tools/testing/selftests/memory-hotplug/Makefile2
-rw-r--r--tools/testing/selftests/net/psock_tpacket.c59
-rw-r--r--tools/testing/selftests/timers/Makefile8
-rw-r--r--tools/testing/selftests/timers/posix_timers.c221
-rw-r--r--tools/testing/selftests/vm/.gitignore4
-rw-r--r--tools/testing/selftests/vm/Makefile7
-rw-r--r--tools/testing/selftests/vm/hugetlbfstest.c84
-rw-r--r--tools/testing/selftests/vm/run_vmtests16
-rw-r--r--tools/virtio/linux/module.h5
-rw-r--r--tools/virtio/linux/virtio.h3
-rw-r--r--usr/Kconfig9
-rw-r--r--virt/kvm/arm/arch_timer.c (renamed from arch/arm/kvm/arch_timer.c)34
-rw-r--r--virt/kvm/arm/vgic.c (renamed from arch/arm/kvm/vgic.c)0
-rw-r--r--virt/kvm/eventfd.c2
-rw-r--r--virt/kvm/kvm_main.c4
5380 files changed, 297515 insertions, 96246 deletions
diff --git a/Documentation/ABI/stable/sysfs-module b/Documentation/ABI/stable/sysfs-module
index a0dd21c6db59..6272ae5fb366 100644
--- a/Documentation/ABI/stable/sysfs-module
+++ b/Documentation/ABI/stable/sysfs-module
@@ -4,9 +4,13 @@ Description:
/sys/module/MODULENAME
The name of the module that is in the kernel. This
- module name will show up either if the module is built
- directly into the kernel, or if it is loaded as a
- dynamic module.
+ module name will always show up if the module is loaded as a
+ dynamic module. If it is built directly into the kernel, it
+ will only show up if it has a version or at least one
+ parameter.
+
+ Note: The conditions of creation in the built-in case are not
+ by design and may be removed in the future.
/sys/module/MODULENAME/parameters
This directory contains individual files that are each
diff --git a/Documentation/ABI/testing/sysfs-bus-acpi b/Documentation/ABI/testing/sysfs-bus-acpi
new file mode 100644
index 000000000000..7fa9cbc75344
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-acpi
@@ -0,0 +1,58 @@
+What: /sys/bus/acpi/devices/.../path
+Date: December 2006
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ This attribute indicates the full path of ACPI namespace
+ object associated with the device object. For example,
+ \_SB_.PCI0.
+ This file is not present for device objects representing
+ fixed ACPI hardware features (like power and sleep
+ buttons).
+
+What: /sys/bus/acpi/devices/.../modalias
+Date: July 2007
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ This attribute indicates the PNP IDs of the device object.
+ That is acpi:HHHHHHHH:[CCCCCCC:]. Where each HHHHHHHH or
+ CCCCCCCC contains device object's PNPID (_HID or _CID).
+
+What: /sys/bus/acpi/devices/.../hid
+Date: April 2005
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ This attribute indicates the hardware ID (_HID) of the
+ device object. For example, PNP0103.
+ This file is present for device objects having the _HID
+ control method.
+
+What: /sys/bus/acpi/devices/.../description
+Date: October 2012
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ This attribute contains the output of the device object's
+ _STR control method, if present.
+
+What: /sys/bus/acpi/devices/.../adr
+Date: October 2012
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ This attribute contains the output of the device object's
+ _ADR control method, which is present for ACPI device
+ objects representing devices having standard enumeration
+ algorithms, such as PCI.
+
+What: /sys/bus/acpi/devices/.../uid
+Date: October 2012
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ This attribute contains the output of the device object's
+ _UID control method, if present.
+
+What: /sys/bus/acpi/devices/.../eject
+Date: December 2006
+Contact: Rafael J. Wysocki <rjw@rjwysocki.net>
+Description:
+ Writing 1 to this attribute will trigger hot removal of
+ this device object. This file exists for every device
+ object that has _EJ0 method.
diff --git a/Documentation/ABI/testing/sysfs-class-devfreq b/Documentation/ABI/testing/sysfs-class-devfreq
index 0ba6ea2f89d9..ee39acacf6f8 100644
--- a/Documentation/ABI/testing/sysfs-class-devfreq
+++ b/Documentation/ABI/testing/sysfs-class-devfreq
@@ -78,3 +78,23 @@ Contact: Nishanth Menon <nm@ti.com>
Description:
The /sys/class/devfreq/.../available_governors shows
currently available governors in the system.
+
+What: /sys/class/devfreq/.../min_freq
+Date: January 2013
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../min_freq shows and stores
+ the minimum frequency requested by users. It is 0 if
+ the user does not care. min_freq overrides the
+ frequency requested by governors.
+
+What: /sys/class/devfreq/.../max_freq
+Date: January 2013
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/devfreq/.../max_freq shows and stores
+ the maximum frequency requested by users. It is 0 if
+ the user does not care. max_freq overrides the
+ frequency requested by governors and min_freq.
+ The max_freq overrides min_freq because max_freq may be
+ used to throttle devices to avoid overheating.
diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm
new file mode 100644
index 000000000000..c479d77b67c5
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-pwm
@@ -0,0 +1,79 @@
+What: /sys/class/pwm/
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ The pwm/ class sub-directory belongs to the Generic PWM
+ Framework and provides a sysfs interface for using PWM
+ channels.
+
+What: /sys/class/pwm/pwmchipN/
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ A /sys/class/pwm/pwmchipN directory is created for each
+ probed PWM controller/chip where N is the base of the
+ PWM chip.
+
+What: /sys/class/pwm/pwmchipN/npwm
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ The number of PWM channels supported by the PWM chip.
+
+What: /sys/class/pwm/pwmchipN/export
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ Exports a PWM channel from the PWM chip for sysfs control.
+ Value is between 0 and /sys/class/pwm/pwmchipN/npwm - 1.
+
+What: /sys/class/pwm/pwmchipN/unexport
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ Unexports a PWM channel.
+
+What: /sys/class/pwm/pwmchipN/pwmX
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ A /sys/class/pwm/pwmchipN/pwmX directory is created for
+ each exported PWM channel where X is the exported PWM
+ channel number.
+
+What: /sys/class/pwm/pwmchipN/pwmX/period
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ Sets the PWM signal period in nanoseconds.
+
+What: /sys/class/pwm/pwmchipN/pwmX/duty_cycle
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ Sets the PWM signal duty cycle in nanoseconds.
+
+What: /sys/class/pwm/pwmchipN/pwmX/polarity
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ Sets the output polarity of the PWM signal to "normal" or
+ "inversed".
+
+What: /sys/class/pwm/pwmchipN/pwmX/enable
+Date: May 2013
+KernelVersion: 3.11
+Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
+Description:
+ Enable/disable the PWM signal.
+ 0 is disabled
+ 1 is enabled
diff --git a/Documentation/ABI/testing/sysfs-devices-online b/Documentation/ABI/testing/sysfs-devices-online
new file mode 100644
index 000000000000..f990026c0740
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-online
@@ -0,0 +1,20 @@
+What: /sys/devices/.../online
+Date: April 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The /sys/devices/.../online attribute is only present for
+ devices whose bus types provide .online() and .offline()
+ callbacks. The number read from it (0 or 1) reflects the value
+ of the device's 'offline' field. If that number is 1 and '0'
+ (or 'n', or 'N') is written to this file, the device bus type's
+ .offline() callback is executed for the device and (if
+ successful) its 'offline' field is updated accordingly. In
+ turn, if that number is 0 and '1' (or 'y', or 'Y') is written to
+ this file, the device bus type's .online() callback is executed
+ for the device and (if successful) its 'offline' field is
+ updated as appropriate.
+
+ After a successful execution of the bus type's .offline()
+ callback the device cannot be used for any purpose until either
+ it is removed (i.e. device_del() is called for it), or its bus
+ type's .online() is exeucted successfully.
diff --git a/Documentation/ABI/testing/sysfs-devices-sun b/Documentation/ABI/testing/sysfs-devices-sun
index 86be9848a77e..625ce4b63758 100644
--- a/Documentation/ABI/testing/sysfs-devices-sun
+++ b/Documentation/ABI/testing/sysfs-devices-sun
@@ -1,4 +1,4 @@
-Whatt: /sys/devices/.../sun
+What: /sys/devices/.../sun
Date: October 2012
Contact: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Description:
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 2447698aed41..468e4d48f884 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -144,6 +144,21 @@ Description: Discover and change clock speed of CPUs
to learn how to control the knobs.
+What: /sys/devices/system/cpu/cpu#/cpufreq/freqdomain_cpus
+Date: June 2013
+Contact: cpufreq@vger.kernel.org
+Description: Discover CPUs in the same CPU frequency coordination domain
+
+ freqdomain_cpus is the list of CPUs (online+offline) that share
+ the same clock/freq domain (possibly at the hardware level).
+ That information may be hidden from the cpufreq core and the
+ value of related_cpus may be different from freqdomain_cpus. This
+ attribute is useful for user space DVFS controllers to get better
+ power/performance results for platforms using acpi-cpufreq.
+
+ This file is only present if the acpi-cpufreq driver is in use.
+
+
What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
Date: August 2008
KernelVersion: 2.6.27
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
index 3d98009f447a..ed5dd567d397 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-wiimote
+++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote
@@ -12,7 +12,7 @@ Description: Make it possible to set/get current led state. Reading from it
What: /sys/bus/hid/drivers/wiimote/<dev>/extension
Date: August 2011
KernelVersion: 3.2
-Contact: David Herrmann <dh.herrmann@googlemail.com>
+Contact: David Herrmann <dh.herrmann@gmail.com>
Description: This file contains the currently connected and initialized
extensions. It can be one of: none, motionp, nunchuck, classic,
motionp+nunchuck, motionp+classic
@@ -20,3 +20,40 @@ Description: This file contains the currently connected and initialized
the official Nintendo Nunchuck extension and classic is the
Nintendo Classic Controller extension. The motionp extension can
be combined with the other two.
+ Starting with kernel-version 3.11 Motion Plus hotplugging is
+ supported and if detected, it's no longer reported as static
+ extension. You will get uevent notifications for the motion-plus
+ device then.
+
+What: /sys/bus/hid/drivers/wiimote/<dev>/devtype
+Date: May 2013
+KernelVersion: 3.11
+Contact: David Herrmann <dh.herrmann@gmail.com>
+Description: While a device is initialized by the wiimote driver, we perform
+ a device detection and signal a "change" uevent after it is
+ done. This file shows the detected device type. "pending" means
+ that the detection is still ongoing, "unknown" means, that the
+ device couldn't be detected or loaded. "generic" means, that the
+ device couldn't be detected but supports basic Wii Remote
+ features and can be used.
+ Other strings for each device-type are available and may be
+ added if new device-specific detections are added.
+ Currently supported are:
+ gen10: First Wii Remote generation
+ gen20: Second Wii Remote Plus generation (builtin MP)
+ balanceboard: Wii Balance Board
+
+What: /sys/bus/hid/drivers/wiimote/<dev>/bboard_calib
+Date: May 2013
+KernelVersion: 3.11
+Contact: David Herrmann <dh.herrmann@gmail.com>
+Description: This attribute is only provided if the device was detected as a
+ balance board. It provides a single line with 3 calibration
+ values for all 4 sensors. The values are separated by colons and
+ are each 2 bytes long (encoded as 4 digit hexadecimal value).
+ First, 0kg values for all 4 sensors are written, followed by the
+ 17kg values for all 4 sensors and last the 34kg values for all 4
+ sensors.
+ Calibration data is already applied by the kernel to all input
+ values but may be used by user-space to perform other
+ transformations.
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
index ce9bee98b43b..b4436cca97a8 100644
--- a/Documentation/ABI/testing/sysfs-firmware-acpi
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -44,6 +44,16 @@ Description:
or 0 (unset). Attempts to write any other values to it will
cause -EINVAL to be returned.
+What: /sys/firmware/acpi/hotplug/force_remove
+Date: May 2013
+Contact: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Description:
+ The number in this file (0 or 1) determines whether (1) or not
+ (0) the ACPI subsystem will allow devices to be hot-removed even
+ if they cannot be put offline gracefully (from the kernel's
+ viewpoint). That number can be changed by writing a boolean
+ value to this file.
+
What: /sys/firmware/acpi/interrupts/
Date: February 2008
Contact: Len Brown <lenb@kernel.org>
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index e00b8f0dde52..7fe0546c504a 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -389,7 +389,8 @@ Albeit deprecated by some people, the equivalent of the goto statement is
used frequently by compilers in form of the unconditional jump instruction.
The goto statement comes in handy when a function exits from multiple
-locations and some common work such as cleanup has to be done.
+locations and some common work such as cleanup has to be done. If there is no
+cleanup needed then just return directly.
The rationale is:
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl
index 0f6a3edcd44b..49267ea97568 100644
--- a/Documentation/DocBook/80211.tmpl
+++ b/Documentation/DocBook/80211.tmpl
@@ -127,14 +127,11 @@
!Finclude/net/cfg80211.h cfg80211_ibss_params
!Finclude/net/cfg80211.h cfg80211_connect_params
!Finclude/net/cfg80211.h cfg80211_pmksa
-!Finclude/net/cfg80211.h cfg80211_send_rx_auth
-!Finclude/net/cfg80211.h cfg80211_send_auth_timeout
-!Finclude/net/cfg80211.h cfg80211_send_rx_assoc
-!Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
-!Finclude/net/cfg80211.h cfg80211_send_deauth
-!Finclude/net/cfg80211.h __cfg80211_send_deauth
-!Finclude/net/cfg80211.h cfg80211_send_disassoc
-!Finclude/net/cfg80211.h __cfg80211_send_disassoc
+!Finclude/net/cfg80211.h cfg80211_rx_mlme_mgmt
+!Finclude/net/cfg80211.h cfg80211_auth_timeout
+!Finclude/net/cfg80211.h cfg80211_rx_assoc_resp
+!Finclude/net/cfg80211.h cfg80211_assoc_timeout
+!Finclude/net/cfg80211.h cfg80211_tx_mlme_mgmt
!Finclude/net/cfg80211.h cfg80211_ibss_joined
!Finclude/net/cfg80211.h cfg80211_connect_result
!Finclude/net/cfg80211.h cfg80211_roamed
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index c36892c072da..cbfdf5486639 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -126,6 +126,8 @@ X!Edrivers/base/interface.c
</sect1>
<sect1><title>Device Drivers DMA Management</title>
!Edrivers/base/dma-buf.c
+!Edrivers/base/reservation.c
+!Iinclude/linux/reservation.h
!Edrivers/base/dma-coherent.c
!Edrivers/base/dma-mapping.c
</sect1>
@@ -297,10 +299,10 @@ KAO -->
</sect1>
<sect1><title>Frame Buffer Fonts</title>
<para>
- Refer to the file drivers/video/console/fonts.c for more information.
+ Refer to the file lib/fonts/fonts.c for more information.
</para>
<!-- FIXME: Removed for now since no structured comments in source
-X!Idrivers/video/console/fonts.c
+X!Ilib/fonts/fonts.c
-->
</sect1>
</chapter>
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index f9df3b872c16..7d1278e7a434 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -186,11 +186,12 @@
<varlistentry>
<term>DRIVER_HAVE_IRQ</term><term>DRIVER_IRQ_SHARED</term>
<listitem><para>
- DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler. The
- DRM core will automatically register an interrupt handler when the
- flag is set. DRIVER_IRQ_SHARED indicates whether the device &amp;
- handler support shared IRQs (note that this is required of PCI
- drivers).
+ DRIVER_HAVE_IRQ indicates whether the driver has an IRQ handler
+ managed by the DRM Core. The core will support simple IRQ handler
+ installation when the flag is set. The installation process is
+ described in <xref linkend="drm-irq-registration"/>.</para>
+ <para>DRIVER_IRQ_SHARED indicates whether the device &amp; handler
+ support shared IRQs (note that this is required of PCI drivers).
</para></listitem>
</varlistentry>
<varlistentry>
@@ -344,50 +345,71 @@ char *date;</synopsis>
The DRM core tries to facilitate IRQ handler registration and
unregistration by providing <function>drm_irq_install</function> and
<function>drm_irq_uninstall</function> functions. Those functions only
- support a single interrupt per device.
- </para>
- <!--!Fdrivers/char/drm/drm_irq.c drm_irq_install-->
- <para>
- Both functions get the device IRQ by calling
- <function>drm_dev_to_irq</function>. This inline function will call a
- bus-specific operation to retrieve the IRQ number. For platform devices,
- <function>platform_get_irq</function>(..., 0) is used to retrieve the
- IRQ number.
- </para>
- <para>
- <function>drm_irq_install</function> starts by calling the
- <methodname>irq_preinstall</methodname> driver operation. The operation
- is optional and must make sure that the interrupt will not get fired by
- clearing all pending interrupt flags or disabling the interrupt.
- </para>
- <para>
- The IRQ will then be requested by a call to
- <function>request_irq</function>. If the DRIVER_IRQ_SHARED driver
- feature flag is set, a shared (IRQF_SHARED) IRQ handler will be
- requested.
- </para>
- <para>
- The IRQ handler function must be provided as the mandatory irq_handler
- driver operation. It will get passed directly to
- <function>request_irq</function> and thus has the same prototype as all
- IRQ handlers. It will get called with a pointer to the DRM device as the
- second argument.
- </para>
- <para>
- Finally the function calls the optional
- <methodname>irq_postinstall</methodname> driver operation. The operation
- usually enables interrupts (excluding the vblank interrupt, which is
- enabled separately), but drivers may choose to enable/disable interrupts
- at a different time.
- </para>
- <para>
- <function>drm_irq_uninstall</function> is similarly used to uninstall an
- IRQ handler. It starts by waking up all processes waiting on a vblank
- interrupt to make sure they don't hang, and then calls the optional
- <methodname>irq_uninstall</methodname> driver operation. The operation
- must disable all hardware interrupts. Finally the function frees the IRQ
- by calling <function>free_irq</function>.
+ support a single interrupt per device, devices that use more than one
+ IRQs need to be handled manually.
</para>
+ <sect4>
+ <title>Managed IRQ Registration</title>
+ <para>
+ Both the <function>drm_irq_install</function> and
+ <function>drm_irq_uninstall</function> functions get the device IRQ by
+ calling <function>drm_dev_to_irq</function>. This inline function will
+ call a bus-specific operation to retrieve the IRQ number. For platform
+ devices, <function>platform_get_irq</function>(..., 0) is used to
+ retrieve the IRQ number.
+ </para>
+ <para>
+ <function>drm_irq_install</function> starts by calling the
+ <methodname>irq_preinstall</methodname> driver operation. The operation
+ is optional and must make sure that the interrupt will not get fired by
+ clearing all pending interrupt flags or disabling the interrupt.
+ </para>
+ <para>
+ The IRQ will then be requested by a call to
+ <function>request_irq</function>. If the DRIVER_IRQ_SHARED driver
+ feature flag is set, a shared (IRQF_SHARED) IRQ handler will be
+ requested.
+ </para>
+ <para>
+ The IRQ handler function must be provided as the mandatory irq_handler
+ driver operation. It will get passed directly to
+ <function>request_irq</function> and thus has the same prototype as all
+ IRQ handlers. It will get called with a pointer to the DRM device as the
+ second argument.
+ </para>
+ <para>
+ Finally the function calls the optional
+ <methodname>irq_postinstall</methodname> driver operation. The operation
+ usually enables interrupts (excluding the vblank interrupt, which is
+ enabled separately), but drivers may choose to enable/disable interrupts
+ at a different time.
+ </para>
+ <para>
+ <function>drm_irq_uninstall</function> is similarly used to uninstall an
+ IRQ handler. It starts by waking up all processes waiting on a vblank
+ interrupt to make sure they don't hang, and then calls the optional
+ <methodname>irq_uninstall</methodname> driver operation. The operation
+ must disable all hardware interrupts. Finally the function frees the IRQ
+ by calling <function>free_irq</function>.
+ </para>
+ </sect4>
+ <sect4>
+ <title>Manual IRQ Registration</title>
+ <para>
+ Drivers that require multiple interrupt handlers can't use the managed
+ IRQ registration functions. In that case IRQs must be registered and
+ unregistered manually (usually with the <function>request_irq</function>
+ and <function>free_irq</function> functions, or their devm_* equivalent).
+ </para>
+ <para>
+ When manually registering IRQs, drivers must not set the DRIVER_HAVE_IRQ
+ driver feature flag, and must not provide the
+ <methodname>irq_handler</methodname> driver operation. They must set the
+ <structname>drm_device</structname> <structfield>irq_enabled</structfield>
+ field to 1 upon registration of the IRQs, and clear it to 0 after
+ unregistering the IRQs.
+ </para>
+ </sect4>
</sect3>
<sect3>
<title>Memory Manager Initialization</title>
@@ -434,7 +456,7 @@ char *date;</synopsis>
The DRM core includes two memory managers, namely Translation Table Maps
(TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory
manager to be developed and tried to be a one-size-fits-them all
- solution. It provides a single userspace API to accomodate the need of
+ solution. It provides a single userspace API to accommodate the need of
all hardware, supporting both Unified Memory Architecture (UMA) devices
and devices with dedicated video RAM (i.e. most discrete video cards).
This resulted in a large, complex piece of code that turned out to be
@@ -701,7 +723,7 @@ char *date;</synopsis>
<para>
Similar to global names, GEM file descriptors are also used to share GEM
objects across processes. They offer additional security: as file
- descriptors must be explictly sent over UNIX domain sockets to be shared
+ descriptors must be explicitly sent over UNIX domain sockets to be shared
between applications, they can't be guessed like the globally unique GEM
names.
</para>
@@ -1154,7 +1176,7 @@ int max_width, max_height;</synopsis>
</para>
<para>
The <methodname>page_flip</methodname> operation schedules a page flip.
- Once any pending rendering targetting the new frame buffer has
+ Once any pending rendering targeting the new frame buffer has
completed, the CRTC will be reprogrammed to display that frame buffer
after the next vertical refresh. The operation must return immediately
without waiting for rendering or page flip to complete and must block
@@ -1214,6 +1236,15 @@ int max_width, max_height;</synopsis>
<title>Miscellaneous</title>
<itemizedlist>
<listitem>
+ <synopsis>void (*set_property)(struct drm_crtc *crtc,
+ struct drm_property *property, uint64_t value);</synopsis>
+ <para>
+ Set the value of the given CRTC property to
+ <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
+ for more information about properties.
+ </para>
+ </listitem>
+ <listitem>
<synopsis>void (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
uint32_t start, uint32_t size);</synopsis>
<para>
@@ -1363,6 +1394,15 @@ int max_width, max_height;</synopsis>
<xref linkend="drm-kms-init"/>.
</para>
</listitem>
+ <listitem>
+ <synopsis>void (*set_property)(struct drm_plane *plane,
+ struct drm_property *property, uint64_t value);</synopsis>
+ <para>
+ Set the value of the given plane property to
+ <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
+ for more information about properties.
+ </para>
+ </listitem>
</itemizedlist>
</sect3>
</sect2>
@@ -1572,6 +1612,15 @@ int max_width, max_height;</synopsis>
<title>Miscellaneous</title>
<itemizedlist>
<listitem>
+ <synopsis>void (*set_property)(struct drm_connector *connector,
+ struct drm_property *property, uint64_t value);</synopsis>
+ <para>
+ Set the value of the given connector property to
+ <parameter>value</parameter>. See <xref linkend="drm-kms-properties"/>
+ for more information about properties.
+ </para>
+ </listitem>
+ <listitem>
<synopsis>void (*destroy)(struct drm_connector *connector);</synopsis>
<para>
Destroy the connector when not needed anymore. See
@@ -1846,10 +1895,6 @@ void intel_crt_init(struct drm_device *dev)
<synopsis>bool (*mode_fixup)(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);</synopsis>
- <note><para>
- FIXME: The mode argument be const, but the i915 driver modifies
- mode-&gt;clock in <function>intel_dp_mode_fixup</function>.
- </para></note>
<para>
Let encoders adjust the requested mode or reject it completely. This
operation returns true if the mode is accepted (possibly after being
@@ -2161,6 +2206,128 @@ void intel_crt_init(struct drm_device *dev)
<title>EDID Helper Functions Reference</title>
!Edrivers/gpu/drm/drm_edid.c
</sect2>
+ <sect2>
+ <title>Rectangle Utilities Reference</title>
+!Pinclude/drm/drm_rect.h rect utils
+!Iinclude/drm/drm_rect.h
+!Edrivers/gpu/drm/drm_rect.c
+ </sect2>
+ </sect1>
+
+ <!-- Internals: kms properties -->
+
+ <sect1 id="drm-kms-properties">
+ <title>KMS Properties</title>
+ <para>
+ Drivers may need to expose additional parameters to applications than
+ those described in the previous sections. KMS supports attaching
+ properties to CRTCs, connectors and planes and offers a userspace API to
+ list, get and set the property values.
+ </para>
+ <para>
+ Properties are identified by a name that uniquely defines the property
+ purpose, and store an associated value. For all property types except blob
+ properties the value is a 64-bit unsigned integer.
+ </para>
+ <para>
+ KMS differentiates between properties and property instances. Drivers
+ first create properties and then create and associate individual instances
+ of those properties to objects. A property can be instantiated multiple
+ times and associated with different objects. Values are stored in property
+ instances, and all other property information are stored in the propery
+ and shared between all instances of the property.
+ </para>
+ <para>
+ Every property is created with a type that influences how the KMS core
+ handles the property. Supported property types are
+ <variablelist>
+ <varlistentry>
+ <term>DRM_MODE_PROP_RANGE</term>
+ <listitem><para>Range properties report their minimum and maximum
+ admissible values. The KMS core verifies that values set by
+ application fit in that range.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>DRM_MODE_PROP_ENUM</term>
+ <listitem><para>Enumerated properties take a numerical value that
+ ranges from 0 to the number of enumerated values defined by the
+ property minus one, and associate a free-formed string name to each
+ value. Applications can retrieve the list of defined value-name pairs
+ and use the numerical value to get and set property instance values.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>DRM_MODE_PROP_BITMASK</term>
+ <listitem><para>Bitmask properties are enumeration properties that
+ additionally restrict all enumerated values to the 0..63 range.
+ Bitmask property instance values combine one or more of the
+ enumerated bits defined by the property.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>DRM_MODE_PROP_BLOB</term>
+ <listitem><para>Blob properties store a binary blob without any format
+ restriction. The binary blobs are created as KMS standalone objects,
+ and blob property instance values store the ID of their associated
+ blob object.</para>
+ <para>Blob properties are only used for the connector EDID property
+ and cannot be created by drivers.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ <para>
+ To create a property drivers call one of the following functions depending
+ on the property type. All property creation functions take property flags
+ and name, as well as type-specific arguments.
+ <itemizedlist>
+ <listitem>
+ <synopsis>struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
+ const char *name,
+ uint64_t min, uint64_t max);</synopsis>
+ <para>Create a range property with the given minimum and maximum
+ values.</para>
+ </listitem>
+ <listitem>
+ <synopsis>struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
+ const char *name,
+ const struct drm_prop_enum_list *props,
+ int num_values);</synopsis>
+ <para>Create an enumerated property. The <parameter>props</parameter>
+ argument points to an array of <parameter>num_values</parameter>
+ value-name pairs.</para>
+ </listitem>
+ <listitem>
+ <synopsis>struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
+ int flags, const char *name,
+ const struct drm_prop_enum_list *props,
+ int num_values);</synopsis>
+ <para>Create a bitmask property. The <parameter>props</parameter>
+ argument points to an array of <parameter>num_values</parameter>
+ value-name pairs.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ Properties can additionally be created as immutable, in which case they
+ will be read-only for applications but can be modified by the driver. To
+ create an immutable property drivers must set the DRM_MODE_PROP_IMMUTABLE
+ flag at property creation time.
+ </para>
+ <para>
+ When no array of value-name pairs is readily available at property
+ creation time for enumerated or range properties, drivers can create
+ the property using the <function>drm_property_create</function> function
+ and manually add enumeration value-name pairs by calling the
+ <function>drm_property_add_enum</function> function. Care must be taken to
+ properly specify the property type through the <parameter>flags</parameter>
+ argument.
+ </para>
+ <para>
+ After creating properties drivers can attach property instances to CRTC,
+ connector and plane objects by calling the
+ <function>drm_object_attach_property</function>. The function takes a
+ pointer to the target object, a pointer to the previously created property
+ and an initial instance value.
+ </para>
</sect1>
<!-- Internals: vertical blanking -->
diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
index 67e7ab41c0a6..09e884e5b9f5 100644
--- a/Documentation/DocBook/kernel-locking.tmpl
+++ b/Documentation/DocBook/kernel-locking.tmpl
@@ -1955,12 +1955,17 @@ machines due to caching.
</sect1>
</chapter>
- <chapter id="apiref">
+ <chapter id="apiref-mutex">
<title>Mutex API reference</title>
!Iinclude/linux/mutex.h
!Ekernel/mutex.c
</chapter>
+ <chapter id="apiref-futex">
+ <title>Futex API reference</title>
+!Ikernel/futex.c
+ </chapter>
+
<chapter id="references">
<title>Further reading</title>
diff --git a/Documentation/DocBook/media/dvb/frontend.xml b/Documentation/DocBook/media/dvb/frontend.xml
index df39ba395df0..0d6e81bd9ed2 100644
--- a/Documentation/DocBook/media/dvb/frontend.xml
+++ b/Documentation/DocBook/media/dvb/frontend.xml
@@ -233,7 +233,7 @@ typedef enum fe_status {
<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">Syncronization bytes was found</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>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 8d7a77928d49..c2fc9ec1417e 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -3147,7 +3147,7 @@ giving priority to the center of the metered area.</entry>
<entry>A multi-zone metering. The light intensity is measured
in several points of the frame and the the results are combined. The
algorithm of the zones selection and their significance in calculating the
-final value is device dependant.</entry>
+final value is device dependent.</entry>
</row>
</tbody>
</entrytbl>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml
index 2f82b1da8dfe..8a70a1707b7a 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-nv12mt.xml
@@ -24,7 +24,7 @@ into 64x32 macroblocks. The CbCr plane has the same width, in bytes, as the Y
plane (and the image), but is half as tall in pixels. The chroma plane is also
grouped into 64x32 macroblocks.</para>
<para>Width of the buffer has to be aligned to the multiple of 128, and
-height alignment is 32. Every four adjactent buffers - two horizontally and two
+height alignment is 32. Every four adjacent buffers - two horizontally and two
vertically are grouped together and are located in memory in Z or flipped Z
order. </para>
<para>Layout of macroblocks in memory is presented in the following
diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl
index bd97a13fa5ae..3210dcf741c9 100644
--- a/Documentation/DocBook/writing_usb_driver.tmpl
+++ b/Documentation/DocBook/writing_usb_driver.tmpl
@@ -83,7 +83,7 @@
</para>
<para>
Because each different protocol causes a new driver to be created, I have
- written a generic USB driver skeleton, modeled after the pci-skeleton.c
+ written a generic USB driver skeleton, modelled after the pci-skeleton.c
file in the kernel source tree upon which many PCI network drivers have
been based. This USB skeleton can be found at drivers/usb/usb-skeleton.c
in the kernel source tree. In this article I will walk through the basics
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index f8ebcde43b17..c6a06b71594d 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -272,7 +272,7 @@ int main(int argc, char *argv[])
char *logfile = NULL;
int loop = 0;
int containerset = 0;
- char containerpath[1024];
+ char *containerpath = NULL;
int cfd = 0;
int forking = 0;
sigset_t sigset;
@@ -299,7 +299,7 @@ int main(int argc, char *argv[])
break;
case 'C':
containerset = 1;
- strncpy(containerpath, optarg, strlen(optarg) + 1);
+ containerpath = optarg;
break;
case 'w':
logfile = strdup(optarg);
diff --git a/Documentation/acpi/namespace.txt b/Documentation/acpi/namespace.txt
new file mode 100644
index 000000000000..260f6a3661fa
--- /dev/null
+++ b/Documentation/acpi/namespace.txt
@@ -0,0 +1,395 @@
+ACPI Device Tree - Representation of ACPI Namespace
+
+Copyright (C) 2013, Intel Corporation
+Author: Lv Zheng <lv.zheng@intel.com>
+
+
+Abstract:
+
+The Linux ACPI subsystem converts ACPI namespace objects into a Linux
+device tree under the /sys/devices/LNXSYSTEM:00 and updates it upon
+receiving ACPI hotplug notification events. For each device object in this
+hierarchy there is a corresponding symbolic link in the
+/sys/bus/acpi/devices.
+This document illustrates the structure of the ACPI device tree.
+
+
+Credit:
+
+Thanks for the help from Zhang Rui <rui.zhang@intel.com> and Rafael J.
+Wysocki <rafael.j.wysocki@intel.com>.
+
+
+1. ACPI Definition Blocks
+
+ The ACPI firmware sets up RSDP (Root System Description Pointer) in the
+ system memory address space pointing to the XSDT (Extended System
+ Description Table). The XSDT always points to the FADT (Fixed ACPI
+ Description Table) using its first entry, the data within the FADT
+ includes various fixed-length entries that describe fixed ACPI features
+ of the hardware. The FADT contains a pointer to the DSDT
+ (Differentiated System Descripition Table). The XSDT also contains
+ entries pointing to possibly multiple SSDTs (Secondary System
+ Description Table).
+
+ The DSDT and SSDT data is organized in data structures called definition
+ blocks that contain definitions of various objects, including ACPI
+ control methods, encoded in AML (ACPI Machine Language). The data block
+ of the DSDT along with the contents of SSDTs represents a hierarchical
+ data structure called the ACPI namespace whose topology reflects the
+ structure of the underlying hardware platform.
+
+ The relationships between ACPI System Definition Tables described above
+ are illustrated in the following diagram.
+
+ +---------+ +-------+ +--------+ +------------------------+
+ | RSDP | +->| XSDT | +->| FADT | | +-------------------+ |
+ +---------+ | +-------+ | +--------+ +-|->| DSDT | |
+ | Pointer | | | Entry |-+ | ...... | | | +-------------------+ |
+ +---------+ | +-------+ | X_DSDT |--+ | | Definition Blocks | |
+ | Pointer |-+ | ..... | | ...... | | +-------------------+ |
+ +---------+ +-------+ +--------+ | +-------------------+ |
+ | Entry |------------------|->| SSDT | |
+ +- - - -+ | +-------------------| |
+ | Entry | - - - - - - - -+ | | Definition Blocks | |
+ +- - - -+ | | +-------------------+ |
+ | | +- - - - - - - - - -+ |
+ +-|->| SSDT | |
+ | +-------------------+ |
+ | | Definition Blocks | |
+ | +- - - - - - - - - -+ |
+ +------------------------+
+ |
+ OSPM Loading |
+ \|/
+ +----------------+
+ | ACPI Namespace |
+ +----------------+
+
+ Figure 1. ACPI Definition Blocks
+
+ NOTE: RSDP can also contain a pointer to the RSDT (Root System
+ Description Table). Platforms provide RSDT to enable
+ compatibility with ACPI 1.0 operating systems. The OS is expected
+ to use XSDT, if present.
+
+
+2. Example ACPI Namespace
+
+ All definition blocks are loaded into a single namespace. The namespace
+ is a hierarchy of objects identified by names and paths.
+ The following naming conventions apply to object names in the ACPI
+ namespace:
+ 1. All names are 32 bits long.
+ 2. The first byte of a name must be one of 'A' - 'Z', '_'.
+ 3. Each of the remaining bytes of a name must be one of 'A' - 'Z', '0'
+ - '9', '_'.
+ 4. Names starting with '_' are reserved by the ACPI specification.
+ 5. The '\' symbol represents the root of the namespace (i.e. names
+ prepended with '\' are relative to the namespace root).
+ 6. The '^' symbol represents the parent of the current namespace node
+ (i.e. names prepended with '^' are relative to the parent of the
+ current namespace node).
+
+ The figure below shows an example ACPI namespace.
+
+ +------+
+ | \ | Root
+ +------+
+ |
+ | +------+
+ +-| _PR | Scope(_PR): the processor namespace
+ | +------+
+ | |
+ | | +------+
+ | +-| CPU0 | Processor(CPU0): the first processor
+ | +------+
+ |
+ | +------+
+ +-| _SB | Scope(_SB): the system bus namespace
+ | +------+
+ | |
+ | | +------+
+ | +-| LID0 | Device(LID0); the lid device
+ | | +------+
+ | | |
+ | | | +------+
+ | | +-| _HID | Name(_HID, "PNP0C0D"): the hardware ID
+ | | | +------+
+ | | |
+ | | | +------+
+ | | +-| _STA | Method(_STA): the status control method
+ | | +------+
+ | |
+ | | +------+
+ | +-| PCI0 | Device(PCI0); the PCI root bridge
+ | +------+
+ | |
+ | | +------+
+ | +-| _HID | Name(_HID, "PNP0A08"): the hardware ID
+ | | +------+
+ | |
+ | | +------+
+ | +-| _CID | Name(_CID, "PNP0A03"): the compatible ID
+ | | +------+
+ | |
+ | | +------+
+ | +-| RP03 | Scope(RP03): the PCI0 power scope
+ | | +------+
+ | | |
+ | | | +------+
+ | | +-| PXP3 | PowerResource(PXP3): the PCI0 power resource
+ | | +------+
+ | |
+ | | +------+
+ | +-| GFX0 | Device(GFX0): the graphics adapter
+ | +------+
+ | |
+ | | +------+
+ | +-| _ADR | Name(_ADR, 0x00020000): the PCI bus address
+ | | +------+
+ | |
+ | | +------+
+ | +-| DD01 | Device(DD01): the LCD output device
+ | +------+
+ | |
+ | | +------+
+ | +-| _BCL | Method(_BCL): the backlight control method
+ | +------+
+ |
+ | +------+
+ +-| _TZ | Scope(_TZ): the thermal zone namespace
+ | +------+
+ | |
+ | | +------+
+ | +-| FN00 | PowerResource(FN00): the FAN0 power resource
+ | | +------+
+ | |
+ | | +------+
+ | +-| FAN0 | Device(FAN0): the FAN0 cooling device
+ | | +------+
+ | | |
+ | | | +------+
+ | | +-| _HID | Name(_HID, "PNP0A0B"): the hardware ID
+ | | +------+
+ | |
+ | | +------+
+ | +-| TZ00 | ThermalZone(TZ00); the FAN thermal zone
+ | +------+
+ |
+ | +------+
+ +-| _GPE | Scope(_GPE): the GPE namespace
+ +------+
+
+ Figure 2. Example ACPI Namespace
+
+
+3. Linux ACPI Device Objects
+
+ The Linux kernel's core ACPI subsystem creates struct acpi_device
+ objects for ACPI namespace objects representing devices, power resources
+ processors, thermal zones. Those objects are exported to user space via
+ sysfs as directories in the subtree under /sys/devices/LNXSYSTM:00. The
+ format of their names is <bus_id:instance>, where 'bus_id' refers to the
+ ACPI namespace representation of the given object and 'instance' is used
+ for distinguishing different object of the same 'bus_id' (it is
+ two-digit decimal representation of an unsigned integer).
+
+ The value of 'bus_id' depends on the type of the object whose name it is
+ part of as listed in the table below.
+
+ +---+-----------------+-------+----------+
+ | | Object/Feature | Table | bus_id |
+ +---+-----------------+-------+----------+
+ | N | Root | xSDT | LNXSYSTM |
+ +---+-----------------+-------+----------+
+ | N | Device | xSDT | _HID |
+ +---+-----------------+-------+----------+
+ | N | Processor | xSDT | LNXCPU |
+ +---+-----------------+-------+----------+
+ | N | ThermalZone | xSDT | LNXTHERM |
+ +---+-----------------+-------+----------+
+ | N | PowerResource | xSDT | LNXPOWER |
+ +---+-----------------+-------+----------+
+ | N | Other Devices | xSDT | device |
+ +---+-----------------+-------+----------+
+ | F | PWR_BUTTON | FADT | LNXPWRBN |
+ +---+-----------------+-------+----------+
+ | F | SLP_BUTTON | FADT | LNXSLPBN |
+ +---+-----------------+-------+----------+
+ | M | Video Extension | xSDT | LNXVIDEO |
+ +---+-----------------+-------+----------+
+ | M | ATA Controller | xSDT | LNXIOBAY |
+ +---+-----------------+-------+----------+
+ | M | Docking Station | xSDT | LNXDOCK |
+ +---+-----------------+-------+----------+
+
+ Table 1. ACPI Namespace Objects Mapping
+
+ The following rules apply when creating struct acpi_device objects on
+ the basis of the contents of ACPI System Description Tables (as
+ indicated by the letter in the first column and the notation in the
+ second column of the table above):
+ N:
+ The object's source is an ACPI namespace node (as indicated by the
+ named object's type in the second column). In that case the object's
+ directory in sysfs will contain the 'path' attribute whose value is
+ the full path to the node from the namespace root.
+ struct acpi_device objects are created for the ACPI namespace nodes
+ whose _STA control methods return PRESENT or FUNCTIONING. The power
+ resource nodes or nodes without _STA are assumed to be both PRESENT
+ and FUNCTIONING.
+ F:
+ The struct acpi_device object is created for a fixed hardware
+ feature (as indicated by the fixed feature flag's name in the second
+ column), so its sysfs directory will not contain the 'path'
+ attribute.
+ M:
+ The struct acpi_device object is created for an ACPI namespace node
+ with specific control methods (as indicated by the ACPI defined
+ device's type in the second column). The 'path' attribute containing
+ its namespace path will be present in its sysfs directory. For
+ example, if the _BCL method is present for an ACPI namespace node, a
+ struct acpi_device object with LNXVIDEO 'bus_id' will be created for
+ it.
+
+ The third column of the above table indicates which ACPI System
+ Description Tables contain information used for the creation of the
+ struct acpi_device objects represented by the given row (xSDT means DSDT
+ or SSDT).
+
+ The forth column of the above table indicates the 'bus_id' generation
+ rule of the struct acpi_device object:
+ _HID:
+ _HID in the last column of the table means that the object's bus_id
+ is derived from the _HID/_CID identification objects present under
+ the corresponding ACPI namespace node. The object's sysfs directory
+ will then contain the 'hid' and 'modalias' attributes that can be
+ used to retrieve the _HID and _CIDs of that object.
+ LNXxxxxx:
+ The 'modalias' attribute is also present for struct acpi_device
+ objects having bus_id of the "LNXxxxxx" form (pseudo devices), in
+ which cases it contains the bus_id string itself.
+ device:
+ 'device' in the last column of the table indicates that the object's
+ bus_id cannot be determined from _HID/_CID of the corresponding
+ ACPI namespace node, although that object represents a device (for
+ example, it may be a PCI device with _ADR defined and without _HID
+ or _CID). In that case the string 'device' will be used as the
+ object's bus_id.
+
+
+4. Linux ACPI Physical Device Glue
+
+ ACPI device (i.e. struct acpi_device) objects may be linked to other
+ objects in the Linux' device hierarchy that represent "physical" devices
+ (for example, devices on the PCI bus). If that happens, it means that
+ the ACPI device object is a "companion" of a device otherwise
+ represented in a different way and is used (1) to provide configuration
+ information on that device which cannot be obtained by other means and
+ (2) to do specific things to the device with the help of its ACPI
+ control methods. One ACPI device object may be linked this way to
+ multiple "physical" devices.
+
+ If an ACPI device object is linked to a "physical" device, its sysfs
+ directory contains the "physical_node" symbolic link to the sysfs
+ directory of the target device object. In turn, the target device's
+ sysfs directory will then contain the "firmware_node" symbolic link to
+ the sysfs directory of the companion ACPI device object.
+ The linking mechanism relies on device identification provided by the
+ ACPI namespace. For example, if there's an ACPI namespace object
+ representing a PCI device (i.e. a device object under an ACPI namespace
+ object representing a PCI bridge) whose _ADR returns 0x00020000 and the
+ bus number of the parent PCI bridge is 0, the sysfs directory
+ representing the struct acpi_device object created for that ACPI
+ namespace object will contain the 'physical_node' symbolic link to the
+ /sys/devices/pci0000:00/0000:00:02:0/ sysfs directory of the
+ corresponding PCI device.
+
+ The linking mechanism is generally bus-specific. The core of its
+ implementation is located in the drivers/acpi/glue.c file, but there are
+ complementary parts depending on the bus types in question located
+ elsewhere. For example, the PCI-specific part of it is located in
+ drivers/pci/pci-acpi.c.
+
+
+5. Example Linux ACPI Device Tree
+
+ The sysfs hierarchy of struct acpi_device objects corresponding to the
+ example ACPI namespace illustrated in Figure 2 with the addition of
+ fixed PWR_BUTTON/SLP_BUTTON devices is shown below.
+
+ +--------------+---+-----------------+
+ | LNXSYSTEM:00 | \ | acpi:LNXSYSTEM: |
+ +--------------+---+-----------------+
+ |
+ | +-------------+-----+----------------+
+ +-| LNXPWRBN:00 | N/A | acpi:LNXPWRBN: |
+ | +-------------+-----+----------------+
+ |
+ | +-------------+-----+----------------+
+ +-| LNXSLPBN:00 | N/A | acpi:LNXSLPBN: |
+ | +-------------+-----+----------------+
+ |
+ | +-----------+------------+--------------+
+ +-| LNXCPU:00 | \_PR_.CPU0 | acpi:LNXCPU: |
+ | +-----------+------------+--------------+
+ |
+ | +-------------+-------+----------------+
+ +-| LNXSYBUS:00 | \_SB_ | acpi:LNXSYBUS: |
+ | +-------------+-------+----------------+
+ | |
+ | | +- - - - - - - +- - - - - - +- - - - - - - -+
+ | +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: |
+ | | +- - - - - - - +- - - - - - +- - - - - - - -+
+ | |
+ | | +------------+------------+-----------------------+
+ | +-| PNP0A08:00 | \_SB_.PCI0 | acpi:PNP0A08:PNP0A03: |
+ | +------------+------------+-----------------------+
+ | |
+ | | +-----------+-----------------+-----+
+ | +-| device:00 | \_SB_.PCI0.RP03 | N/A |
+ | | +-----------+-----------------+-----+
+ | | |
+ | | | +-------------+----------------------+----------------+
+ | | +-| LNXPOWER:00 | \_SB_.PCI0.RP03.PXP3 | acpi:LNXPOWER: |
+ | | +-------------+----------------------+----------------+
+ | |
+ | | +-------------+-----------------+----------------+
+ | +-| LNXVIDEO:00 | \_SB_.PCI0.GFX0 | acpi:LNXVIDEO: |
+ | +-------------+-----------------+----------------+
+ | |
+ | | +-----------+-----------------+-----+
+ | +-| device:01 | \_SB_.PCI0.DD01 | N/A |
+ | +-----------+-----------------+-----+
+ |
+ | +-------------+-------+----------------+
+ +-| LNXSYBUS:01 | \_TZ_ | acpi:LNXSYBUS: |
+ +-------------+-------+----------------+
+ |
+ | +-------------+------------+----------------+
+ +-| LNXPOWER:0a | \_TZ_.FN00 | acpi:LNXPOWER: |
+ | +-------------+------------+----------------+
+ |
+ | +------------+------------+---------------+
+ +-| PNP0C0B:00 | \_TZ_.FAN0 | acpi:PNP0C0B: |
+ | +------------+------------+---------------+
+ |
+ | +-------------+------------+----------------+
+ +-| LNXTHERM:00 | \_TZ_.TZ00 | acpi:LNXTHERM: |
+ +-------------+------------+----------------+
+
+ Figure 3. Example Linux ACPI Device Tree
+
+ NOTE: Each node is represented as "object/path/modalias", where:
+ 1. 'object' is the name of the object's directory in sysfs.
+ 2. 'path' is the ACPI namespace path of the corresponding
+ ACPI namespace object, as returned by the object's 'path'
+ sysfs attribute.
+ 3. 'modalias' is the value of the object's 'modalias' sysfs
+ attribute (as described earlier in this document).
+ NOTE: N/A indicates the device object does not have the 'path' or the
+ 'modalias' attribute.
+ NOTE: The PNP0C0D device listed above is highlighted (marked by "*")
+ to indicate it will be created only when its _STA methods return
+ PRESENT or FUNCTIONING.
diff --git a/Documentation/acpi/video_extension.txt b/Documentation/acpi/video_extension.txt
new file mode 100644
index 000000000000..78b32ac02466
--- /dev/null
+++ b/Documentation/acpi/video_extension.txt
@@ -0,0 +1,106 @@
+ACPI video extensions
+~~~~~~~~~~~~~~~~~~~~~
+
+This driver implement the ACPI Extensions For Display Adapters for
+integrated graphics devices on motherboard, as specified in ACPI 2.0
+Specification, Appendix B, allowing to perform some basic control like
+defining the video POST device, retrieving EDID information or to
+setup a video output, etc. Note that this is an ref. implementation
+only. It may or may not work for your integrated video device.
+
+The ACPI video driver does 3 things regarding backlight control:
+
+1 Export a sysfs interface for user space to control backlight level
+
+If the ACPI table has a video device, and acpi_backlight=vendor kernel
+command line is not present, the driver will register a backlight device
+and set the required backlight operation structure for it for the sysfs
+interface control. For every registered class device, there will be a
+directory named acpi_videoX under /sys/class/backlight.
+
+The backlight sysfs interface has a standard definition here:
+Documentation/ABI/stable/sysfs-class-backlight.
+
+And what ACPI video driver does is:
+actual_brightness: on read, control method _BQC will be evaluated to
+get the brightness level the firmware thinks it is at;
+bl_power: not implemented, will set the current brightness instead;
+brightness: on write, control method _BCM will run to set the requested
+brightness level;
+max_brightness: Derived from the _BCL package(see below);
+type: firmware
+
+Note that ACPI video backlight driver will always use index for
+brightness, actual_brightness and max_brightness. So if we have
+the following _BCL package:
+
+Method (_BCL, 0, NotSerialized)
+{
+ Return (Package (0x0C)
+ {
+ 0x64,
+ 0x32,
+ 0x0A,
+ 0x14,
+ 0x1E,
+ 0x28,
+ 0x32,
+ 0x3C,
+ 0x46,
+ 0x50,
+ 0x5A,
+ 0x64
+ })
+}
+
+The first two levels are for when laptop are on AC or on battery and are
+not used by Linux currently. The remaining 10 levels are supported levels
+that we can choose from. The applicable index values are from 0 (that
+corresponds to the 0x0A brightness value) to 9 (that corresponds to the
+0x64 brightness value) inclusive. Each of those index values is regarded
+as a "brightness level" indicator. Thus from the user space perspective
+the range of available brightness levels is from 0 to 9 (max_brightness)
+inclusive.
+
+2 Notify user space about hotkey event
+
+There are generally two cases for hotkey event reporting:
+i) For some laptops, when user presses the hotkey, a scancode will be
+ generated and sent to user space through the input device created by
+ the keyboard driver as a key type input event, with proper remap, the
+ following key code will appear to user space:
+
+ EV_KEY, KEY_BRIGHTNESSUP
+ EV_KEY, KEY_BRIGHTNESSDOWN
+ etc.
+
+For this case, ACPI video driver does not need to do anything(actually,
+it doesn't even know this happened).
+
+ii) For some laptops, the press of the hotkey will not generate the
+ scancode, instead, firmware will notify the video device ACPI node
+ about the event. The event value is defined in the ACPI spec. ACPI
+ video driver will generate an key type input event according to the
+ notify value it received and send the event to user space through the
+ input device it created:
+
+ event keycode
+ 0x86 KEY_BRIGHTNESSUP
+ 0x87 KEY_BRIGHTNESSDOWN
+ etc.
+
+so this would lead to the same effect as case i) now.
+
+Once user space tool receives this event, it can modify the backlight
+level through the sysfs interface.
+
+3 Change backlight level in the kernel
+
+This works for machines covered by case ii) in Section 2. Once the driver
+received a notification, it will set the backlight level accordingly. This does
+not affect the sending of event to user space, they are always sent to user
+space regardless of whether or not the video module controls the backlight level
+directly. This behaviour can be controlled through the brightness_switch_enabled
+module parameter as documented in kernel-parameters.txt. It is recommended to
+disable this behaviour once a GUI environment starts up and wants to have full
+control of the backlight level.
diff --git a/Documentation/arm/IXP4xx b/Documentation/arm/IXP4xx
index 7b9351f2f555..e48b74de6ac0 100644
--- a/Documentation/arm/IXP4xx
+++ b/Documentation/arm/IXP4xx
@@ -36,7 +36,7 @@ Linux currently supports the following features on the IXP4xx chips:
- Timers (watchdog, OS)
The following components of the chips are not supported by Linux and
-require the use of Intel's proprietary CSR softare:
+require the use of Intel's proprietary CSR software:
- USB device interface
- Network interfaces (HSS, Utopia, NPEs, etc)
diff --git a/Documentation/arm64/memory.txt b/Documentation/arm64/memory.txt
index 5f583af0a6e1..78a377124ef0 100644
--- a/Documentation/arm64/memory.txt
+++ b/Documentation/arm64/memory.txt
@@ -73,3 +73,10 @@ Translation table lookup with 64KB pages:
| | +--------------------------> [41:29] L2 index (only 38:29 used)
| +-------------------------------> [47:42] L1 index (not used)
+-------------------------------------------------> [63] TTBR0/1
+
+When using KVM, the hypervisor maps kernel pages in EL2, at a fixed
+offset from the kernel VA (top 24bits of the kernel VA set to zero):
+
+Start End Size Use
+-----------------------------------------------------------------------
+0000004000000000 0000007fffffffff 256GB kernel objects mapped in HYP
diff --git a/Documentation/bcache.txt b/Documentation/bcache.txt
index b3a7e7d384f6..c3365f26b2d9 100644
--- a/Documentation/bcache.txt
+++ b/Documentation/bcache.txt
@@ -181,7 +181,7 @@ want for getting the best possible numbers when benchmarking.
In practice this isn't an issue because as soon as a write comes along it'll
cause the btree node to be split, and you need almost no write traffic for
- this to not show up enough to be noticable (especially since bcache's btree
+ this to not show up enough to be noticeable (especially since bcache's btree
nodes are huge and index large regions of the device). But when you're
benchmarking, if you're trying to warm the cache by reading a bunch of data
and there's no other traffic - that can be a problem.
@@ -222,7 +222,7 @@ running
it's in passthrough mode or caching).
sequential_cutoff
- A sequential IO will bypass the cache once it passes this threshhold; the
+ A sequential IO will bypass the cache once it passes this threshold; the
most recent 128 IOs are tracked so sequential IO can be detected even when
it isn't all done at once.
@@ -296,7 +296,7 @@ cache_miss_collisions
since the synchronization for cache misses was rewritten)
cache_readaheads
- Count of times readahead occured.
+ Count of times readahead occurred.
SYSFS - CACHE SET:
@@ -362,7 +362,7 @@ unregister
SYSFS - CACHE SET INTERNAL:
This directory also exposes timings for a number of internal operations, with
-separate files for average duration, average frequency, last occurence and max
+separate files for average duration, average frequency, last occurrence and max
duration: garbage collection, btree read, btree node sorts and btree splits.
active_journal_entries
@@ -417,7 +417,7 @@ freelist_percent
space.
io_errors
- Number of errors that have occured, decayed by io_error_halflife.
+ Number of errors that have occurred, decayed by io_error_halflife.
metadata_written
Sum of all non data writes (btree writes and all other metadata).
diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt
index e54ac1d53403..7d2d046c265f 100644
--- a/Documentation/block/queue-sysfs.txt
+++ b/Documentation/block/queue-sysfs.txt
@@ -93,7 +93,7 @@ To avoid priority inversion through request starvation, a request
queue maintains a separate request pool per each cgroup when
CONFIG_BLK_CGROUP is enabled, and this parameter applies to each such
per-block-cgroup request pool. IOW, if there are N block cgroups,
-each request queue may have upto N request pools, each independently
+each request queue may have up to N request pools, each independently
regulated by nr_requests.
optimal_io_size (RO)
diff --git a/Documentation/cgroups/blkio-controller.txt b/Documentation/cgroups/blkio-controller.txt
index da272c8f44e7..cd556b914786 100644
--- a/Documentation/cgroups/blkio-controller.txt
+++ b/Documentation/cgroups/blkio-controller.txt
@@ -94,11 +94,13 @@ Throttling/Upper Limit policy
Hierarchical Cgroups
====================
-- Currently only CFQ supports hierarchical groups. For throttling,
- cgroup interface does allow creation of hierarchical cgroups and
- internally it treats them as flat hierarchy.
- If somebody created a hierarchy like as follows.
+Both CFQ and throttling implement hierarchy support; however,
+throttling's hierarchy support is enabled iff "sane_behavior" is
+enabled from cgroup side, which currently is a development option and
+not publicly available.
+
+If somebody created a hierarchy like as follows.
root
/ \
@@ -106,21 +108,20 @@ Hierarchical Cgroups
|
test3
- CFQ will handle the hierarchy correctly but and throttling will
- practically treat all groups at same level. For details on CFQ
- hierarchy support, refer to Documentation/block/cfq-iosched.txt.
- Throttling will treat the hierarchy as if it looks like the
- following.
+CFQ by default and throttling with "sane_behavior" will handle the
+hierarchy correctly. For details on CFQ hierarchy support, refer to
+Documentation/block/cfq-iosched.txt. For throttling, all limits apply
+to the whole subtree while all statistics are local to the IOs
+directly generated by tasks in that cgroup.
+
+Throttling without "sane_behavior" enabled from cgroup side will
+practically treat all groups at same level as if it looks like the
+following.
pivot
/ / \ \
root test1 test2 test3
- Nesting cgroups, while allowed, isn't officially supported and blkio
- genereates warning when cgroups nest. Once throttling implements
- hierarchy support, hierarchy will be supported and the warning will
- be removed.
-
Various user visible config options
===================================
CONFIG_BLK_CGROUP
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index ddf4f93967a9..2a3330696372 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -304,7 +304,7 @@ kernel memory, we prevent new processes from being created when the kernel
memory usage is too high.
* slab pages: pages allocated by the SLAB or SLUB allocator are tracked. A copy
-of each kmem_cache is created everytime the cache is touched by the first time
+of each kmem_cache is created every time the cache is touched by the first time
from inside the memcg. The creation is done lazily, so some objects can still be
skipped while the cache is being created. All objects in a slab page should
belong to the same memcg. This only fails to hold when a task is migrated to a
@@ -490,10 +490,10 @@ 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
-inactive_anon - # of bytes of anonymous memory and swap cache memory on
+inactive_anon - # of bytes of anonymous and swap cache memory on inactive
LRU list.
active_anon - # of bytes of anonymous and swap cache memory on active
- inactive LRU list.
+ LRU list.
inactive_file - # of bytes of file-backed memory on inactive LRU list.
active_file - # of bytes of file-backed memory on active LRU list.
unevictable - # of bytes of memory that cannot be reclaimed (mlocked etc).
@@ -834,10 +834,9 @@ Test:
12. TODO
-1. Add support for accounting huge pages (as a separate controller)
-2. Make per-cgroup scanner reclaim not-shared pages first
-3. Teach controller to account for shared-pages
-4. Start reclamation in the background when the limit is
+1. Make per-cgroup scanner reclaim not-shared pages first
+2. Teach controller to account for shared-pages
+3. Start reclamation in the background when the limit is
not yet hit but the usage is getting closer
Summary
diff --git a/Documentation/clk.txt b/Documentation/clk.txt
index b9911c27f496..6f68ba0d1e01 100644
--- a/Documentation/clk.txt
+++ b/Documentation/clk.txt
@@ -32,7 +32,7 @@ hardware-specific bits for the hypothetical "foo" hardware.
Tying the two halves of this interface together is struct clk_hw, which
is defined in struct clk_foo and pointed to within struct clk. This
-allows easy for navigation between the two discrete halves of the common
+allows for easy navigation between the two discrete halves of the common
clock interface.
Part 2 - common data structures and api
diff --git a/Documentation/coccinelle.txt b/Documentation/coccinelle.txt
index 18de78599dd4..7f773d51fdd9 100644
--- a/Documentation/coccinelle.txt
+++ b/Documentation/coccinelle.txt
@@ -6,15 +6,17 @@ Copyright 2010 Gilles Muller <Gilles.Muller@lip6.fr>
Getting Coccinelle
~~~~~~~~~~~~~~~~~~~~
-The semantic patches included in the kernel use the 'virtual rule'
-feature which was introduced in Coccinelle version 0.1.11.
+The semantic patches included in the kernel use features and options
+which are provided by Coccinelle version 1.0.0-rc11 and above.
+Using earlier versions will fail as the option names used by
+the Coccinelle files and coccicheck have been updated.
-Coccinelle (>=0.2.0) is available through the package manager
+Coccinelle is available through the package manager
of many distributions, e.g. :
- - Debian (>=squeeze)
- - Fedora (>=13)
- - Ubuntu (>=10.04 Lucid Lynx)
+ - Debian
+ - Fedora
+ - Ubuntu
- OpenSUSE
- Arch Linux
- NetBSD
@@ -36,11 +38,6 @@ as a regular user, and install it with
sudo make install
-The semantic patches in the kernel will work best with Coccinelle version
-0.2.4 or later. Using earlier versions may incur some parse errors in the
-semantic patch code, but any results that are obtained should still be
-correct.
-
Using Coccinelle on the Linux kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -48,7 +45,7 @@ A Coccinelle-specific target is defined in the top level
Makefile. This target is named 'coccicheck' and calls the 'coccicheck'
front-end in the 'scripts' directory.
-Four modes are defined: patch, report, context, and org. The mode to
+Four basic modes are defined: patch, report, context, and org. The mode to
use is specified by setting the MODE variable with 'MODE=<mode>'.
'patch' proposes a fix, when possible.
@@ -62,18 +59,24 @@ diff-like style.Lines of interest are indicated with '-'.
'org' generates a report in the Org mode format of Emacs.
Note that not all semantic patches implement all modes. For easy use
-of Coccinelle, the default mode is "chain" which tries the previous
-modes in the order above until one succeeds.
+of Coccinelle, the default mode is "report".
+
+Two other modes provide some common combinations of these modes.
-To make a report for every semantic patch, run the following command:
+'chain' tries the previous modes in the order above until one succeeds.
- make coccicheck MODE=report
+'rep+ctxt' runs successively the report mode and the context mode.
+ It should be used with the C option (described later)
+ which checks the code on a file basis.
-NB: The 'report' mode is the default one.
+Examples:
+ To make a report for every semantic patch, run the following command:
-To produce patches, run:
+ make coccicheck MODE=report
- make coccicheck MODE=patch
+ To produce patches, run:
+
+ make coccicheck MODE=patch
The coccicheck target applies every semantic patch available in the
@@ -91,6 +94,11 @@ To enable verbose messages set the V= variable, for example:
make coccicheck MODE=report V=1
+By default, coccicheck tries to run as parallel as possible. To change
+the parallelism, set the J= variable. For example, to run across 4 CPUs:
+
+ make coccicheck MODE=report J=4
+
Using Coccinelle with a single semantic patch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -124,26 +132,33 @@ To check only newly edited code, use the value 2 for the C flag, i.e.
make C=2 CHECK="scripts/coccicheck"
+In these modes, which works on a file basis, there is no information
+about semantic patches displayed, and no commit message proposed.
+
This runs every semantic patch in scripts/coccinelle by default. The
COCCI variable may additionally be used to only apply a single
semantic patch as shown in the previous section.
-The "chain" mode is the default. You can select another one with the
+The "report" mode is the default. You can select another one with the
MODE variable explained above.
-In this mode, there is no information about semantic patches
-displayed, and no commit message proposed.
-
Additional flags
~~~~~~~~~~~~~~~~~~
Additional flags can be passed to spatch through the SPFLAGS
variable.
- make SPFLAGS=--use_glimpse coccicheck
+ make SPFLAGS=--use-glimpse coccicheck
+ make SPFLAGS=--use-idutils coccicheck
See spatch --help to learn more about spatch options.
+Note that the '--use-glimpse' and '--use-idutils' options
+require external tools for indexing the code. None of them is
+thus active by default. However, by indexing the code with
+one of these tools, and according to the cocci file used,
+spatch could proceed the entire code base more quickly.
+
Proposing new semantic patches
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/cpu-freq/cpu-drivers.txt b/Documentation/cpu-freq/cpu-drivers.txt
index a3585eac83b6..19fa98e07bf7 100644
--- a/Documentation/cpu-freq/cpu-drivers.txt
+++ b/Documentation/cpu-freq/cpu-drivers.txt
@@ -186,7 +186,7 @@ As most cpufreq processors only allow for being set to a few specific
frequencies, a "frequency table" with some functions might assist in
some work of the processor driver. Such a "frequency table" consists
of an array of struct cpufreq_frequency_table entries, with any value in
-"index" you want to use, and the corresponding frequency in
+"driver_data" you want to use, and the corresponding frequency in
"frequency". At the end of the table, you need to add a
cpufreq_frequency_table entry with frequency set to CPUFREQ_TABLE_END. And
if you want to skip one entry in the table, set the frequency to
@@ -214,10 +214,4 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
is the corresponding frequency table helper for the ->target
stage. Just pass the values to this function, and the unsigned int
index returns the number of the frequency table entry which contains
-the frequency the CPU shall be set to. PLEASE NOTE: This is not the
-"index" which is in this cpufreq_table_entry.index, but instead
-cpufreq_table[index]. So, the new frequency is
-cpufreq_table[index].frequency, and the value you stored into the
-frequency table "index" field is
-cpufreq_table[index].index.
-
+the frequency the CPU shall be set to.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index 0efd1b905b9d..edd4b4df3932 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -370,8 +370,10 @@ A: There is no clear spec defined way from ACPI that can give us that
CPUs in MADT as hotpluggable CPUS. In the case there are no disabled CPUS
we assume 1/2 the number of CPUs currently present can be hotplugged.
- Caveat: Today's ACPI MADT can only provide 256 entries since the apicid field
- in MADT is only 8 bits.
+ Caveat: ACPI MADT can only provide 256 entries in systems with only ACPI 2.0c
+ or earlier ACPI version supported, because the apicid field in MADT is only
+ 8 bits. From ACPI 3.0, this limitation was removed since the apicid field
+ was extended to 32 bits with x2APIC introduced.
User Space Notification
diff --git a/Documentation/crypto/async-tx-api.txt b/Documentation/crypto/async-tx-api.txt
index ba046b8fa92f..7bf1be20d93a 100644
--- a/Documentation/crypto/async-tx-api.txt
+++ b/Documentation/crypto/async-tx-api.txt
@@ -222,5 +222,4 @@ drivers/dma/: location for offload engine drivers
include/linux/async_tx.h: core header file for the async_tx api
crypto/async_tx/async_tx.c: async_tx interface to dmaengine and common code
crypto/async_tx/async_memcpy.c: copy offload
-crypto/async_tx/async_memset.c: memory fill offload
crypto/async_tx/async_xor.c: xor and xor zero sum offload
diff --git a/Documentation/device-mapper/cache.txt b/Documentation/device-mapper/cache.txt
index f50470abe241..e8cdf7241b66 100644
--- a/Documentation/device-mapper/cache.txt
+++ b/Documentation/device-mapper/cache.txt
@@ -87,7 +87,7 @@ Migration throttling
Migrating data between the origin and cache device uses bandwidth.
The user can set a throttle to prevent more than a certain amount of
-migration occuring at any one time. Currently we're not taking any
+migration occurring at any one time. Currently we're not taking any
account of normal io traffic going to the devices. More work needs
doing here to avoid migrating during those peak io moments.
diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt
index e9192283e5a5..ef8ba9fa58c4 100644
--- a/Documentation/device-mapper/dm-raid.txt
+++ b/Documentation/device-mapper/dm-raid.txt
@@ -222,3 +222,5 @@ Version History
1.4.2 Add RAID10 "far" and "offset" algorithm support.
1.5.0 Add message interface to allow manipulation of the sync_action.
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".
diff --git a/Documentation/device-mapper/switch.txt b/Documentation/device-mapper/switch.txt
new file mode 100644
index 000000000000..2fa749387be8
--- /dev/null
+++ b/Documentation/device-mapper/switch.txt
@@ -0,0 +1,126 @@
+dm-switch
+=========
+
+The device-mapper switch target creates a device that supports an
+arbitrary mapping of fixed-size regions of I/O across a fixed set of
+paths. The path used for any specific region can be switched
+dynamically by sending the target a message.
+
+It maps I/O to underlying block devices efficiently when there is a large
+number of fixed-sized address regions but there is no simple pattern
+that would allow for a compact representation of the mapping such as
+dm-stripe.
+
+Background
+----------
+
+Dell EqualLogic and some other iSCSI storage arrays use a distributed
+frameless architecture. In this architecture, the storage group
+consists of a number of distinct storage arrays ("members") each having
+independent controllers, disk storage and network adapters. When a LUN
+is created it is spread across multiple members. The details of the
+spreading are hidden from initiators connected to this storage system.
+The storage group exposes a single target discovery portal, no matter
+how many members are being used. When iSCSI sessions are created, each
+session is connected to an eth port on a single member. Data to a LUN
+can be sent on any iSCSI session, and if the blocks being accessed are
+stored on another member the I/O will be forwarded as required. This
+forwarding is invisible to the initiator. The storage layout is also
+dynamic, and the blocks stored on disk may be moved from member to
+member as needed to balance the load.
+
+This architecture simplifies the management and configuration of both
+the storage group and initiators. In a multipathing configuration, it
+is possible to set up multiple iSCSI sessions to use multiple network
+interfaces on both the host and target to take advantage of the
+increased network bandwidth. An initiator could use a simple round
+robin algorithm to send I/O across all paths and let the storage array
+members forward it as necessary, but there is a performance advantage to
+sending data directly to the correct member.
+
+A device-mapper table already lets you map different regions of a
+device onto different targets. However in this architecture the LUN is
+spread with an address region size on the order of 10s of MBs, which
+means the resulting table could have more than a million entries and
+consume far too much memory.
+
+Using this device-mapper switch target we can now build a two-layer
+device hierarchy:
+
+ Upper Tier – Determine which array member the I/O should be sent to.
+ Lower Tier – Load balance amongst paths to a particular member.
+
+The lower tier consists of a single dm multipath device for each member.
+Each of these multipath devices contains the set of paths directly to
+the array member in one priority group, and leverages existing path
+selectors to load balance amongst these paths. We also build a
+non-preferred priority group containing paths to other array members for
+failover reasons.
+
+The upper tier consists of a single dm-switch device. This device uses
+a bitmap to look up the location of the I/O and choose the appropriate
+lower tier device to route the I/O. By using a bitmap we are able to
+use 4 bits for each address range in a 16 member group (which is very
+large for us). This is a much denser representation than the dm table
+b-tree can achieve.
+
+Construction Parameters
+=======================
+
+ <num_paths> <region_size> <num_optional_args> [<optional_args>...]
+ [<dev_path> <offset>]+
+
+<num_paths>
+ The number of paths across which to distribute the I/O.
+
+<region_size>
+ The number of 512-byte sectors in a region. Each region can be redirected
+ to any of the available paths.
+
+<num_optional_args>
+ The number of optional arguments. Currently, no optional arguments
+ are supported and so this must be zero.
+
+<dev_path>
+ The block device that represents a specific path to the device.
+
+<offset>
+ The offset of the start of data on the specific <dev_path> (in units
+ of 512-byte sectors). This number is added to the sector number when
+ forwarding the request to the specific path. Typically it is zero.
+
+Messages
+========
+
+set_region_mappings <index>:<path_nr> [<index>]:<path_nr> [<index>]:<path_nr>...
+
+Modify the region table by specifying which regions are redirected to
+which paths.
+
+<index>
+ The region number (region size was specified in constructor parameters).
+ If index is omitted, the next region (previous index + 1) is used.
+ Expressed in hexadecimal (WITHOUT any prefix like 0x).
+
+<path_nr>
+ The path number in the range 0 ... (<num_paths> - 1).
+ Expressed in hexadecimal (WITHOUT any prefix like 0x).
+
+Status
+======
+
+No status line is reported.
+
+Example
+=======
+
+Assume that you have volumes vg1/switch0 vg1/switch1 vg1/switch2 with
+the same size.
+
+Create a switch device with 64kB region size:
+ dmsetup create switch --table "0 `blockdev --getsize /dev/vg1/switch0`
+ switch 3 128 0 /dev/vg1/switch0 0 /dev/vg1/switch1 0 /dev/vg1/switch2 0"
+
+Set mappings for the first 7 entries to point to devices switch0, switch1,
+switch2, switch0, switch1, switch2, switch1:
+ dmsetup message switch 0 set_region_mappings 0:0 :1 :2 :0 :1 :2 :1
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index b9015912bca6..23721d3be3e6 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -100,8 +100,7 @@ Your cooperation is appreciated.
10 = /dev/aio Asynchronous I/O notification interface
11 = /dev/kmsg Writes to this come out as printk's, reads
export the buffered printk records.
- 12 = /dev/oldmem Used by crashdump kernels to access
- the memory of the kernel that crashed.
+ 12 = /dev/oldmem OBSOLETE - replaced by /proc/vmcore
1 block RAM disk
0 = /dev/ram0 First RAM disk
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt
index cbef09b5c8a7..69ddf9fad2dc 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2cc.txt
@@ -16,6 +16,9 @@ Required properties:
performs the same operation).
"marvell,"aurora-outer-cache: Marvell Controller designed to be
compatible with the ARM one with outer cache mode.
+ "bcm,bcm11351-a2-pl310-cache": For Broadcom bcm11351 chipset where an
+ offset needs to be added to the address before passing down to the L2
+ cache controller
- cache-unified : Specifies the cache is a unified cache.
- cache-level : Should be set to 2 for a level 2 cache.
- reg : Physical base address and size of cache controller's memory mapped
diff --git a/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
index f2f2171e530e..9e5f73412cd7 100644
--- a/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
+++ b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
@@ -5,7 +5,7 @@ can combine interrupt sources as a group and provide a single interrupt request
for the group. The interrupt request from each group are connected to a parent
interrupt controller, such as GIC in case of Exynos4210.
-The interrupt combiner controller consists of multiple combiners. Upto eight
+The interrupt combiner controller consists of multiple combiners. Up to eight
interrupt sources can be connected to a combiner. The combiner outputs one
combined interrupt for its eight interrupt sources. The combined interrupt
is usually connected to a parent interrupt controller.
@@ -14,8 +14,8 @@ A single node in the device tree is used to describe the interrupt combiner
controller module (which includes multiple combiners). A combiner in the
interrupt controller module shares config/control registers with other
combiners. For example, a 32-bit interrupt enable/disable config register
-can accommodate upto 4 interrupt combiners (with each combiner supporting
-upto 8 interrupt sources).
+can accommodate up to 4 interrupt combiners (with each combiner supporting
+up to 8 interrupt sources).
Required properties:
- compatible: should be "samsung,exynos4210-combiner".
diff --git a/Documentation/devicetree/bindings/arm/spear/shirq.txt b/Documentation/devicetree/bindings/arm/spear/shirq.txt
index 13fbb8866bd6..715a013ed4bd 100644
--- a/Documentation/devicetree/bindings/arm/spear/shirq.txt
+++ b/Documentation/devicetree/bindings/arm/spear/shirq.txt
@@ -14,7 +14,7 @@ A single node in the device tree is used to describe the shared
interrupt multiplexor (one node for all groups). A group in the
interrupt controller shares config/control registers with other groups.
For example, a 32-bit interrupt enable/disable config register can
-accommodate upto 4 interrupt groups.
+accommodate up to 4 interrupt groups.
Required properties:
- compatible: should be, either of
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index b519f9b699c3..3ec0c5c4f0e9 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -12,6 +12,11 @@ Optional properties:
- calxeda,port-phys: phandle-combophy and lane assignment, which maps each
SATA port to a combophy and a lane within that
combophy
+- calxeda,sgpio-gpio: phandle-gpio bank, bit offset, and default on or off,
+ which indicates that the driver supports SGPIO
+ indicator lights using the indicated GPIOs
+- calxeda,led-order : a u32 array that map port numbers to offsets within the
+ SGPIO bitstream.
- dma-coherent : Present if dma operations are coherent
Example:
diff --git a/Documentation/devicetree/bindings/clock/nspire-clock.txt b/Documentation/devicetree/bindings/clock/nspire-clock.txt
new file mode 100644
index 000000000000..7c3bc8bb5b9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/nspire-clock.txt
@@ -0,0 +1,24 @@
+TI-NSPIRE Clocks
+
+Required properties:
+- compatible: Valid compatible properties include:
+ "lsi,nspire-cx-ahb-divider" for the AHB divider in the CX model
+ "lsi,nspire-classic-ahb-divider" for the AHB divider in the older model
+ "lsi,nspire-cx-clock" for the base clock in the CX model
+ "lsi,nspire-classic-clock" for the base clock in the older model
+
+- reg: Physical base address of the controller and length of memory mapped
+ region.
+
+Optional:
+- clocks: For the "nspire-*-ahb-divider" compatible clocks, this is the parent
+ clock where it divides the rate from.
+
+Example:
+
+ahb_clk {
+ #clock-cells = <0>;
+ compatible = "lsi,nspire-cx-clock";
+ reg = <0x900B0000 0x4>;
+ clocks = <&base_clk>;
+};
diff --git a/Documentation/devicetree/bindings/clock/rockchip.txt b/Documentation/devicetree/bindings/clock/rockchip.txt
new file mode 100644
index 000000000000..a891c823ed44
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip.txt
@@ -0,0 +1,74 @@
+Device Tree Clock bindings for arch-rockchip
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+== Gate clocks ==
+
+The gate registers form a continuos block which makes the dt node
+structure a matter of taste, as either all gates can be put into
+one gate clock spanning all registers or they can be divided into
+the 10 individual gates containing 16 clocks each.
+The code supports both approaches.
+
+Required properties:
+- compatible : "rockchip,rk2928-gate-clk"
+- reg : shall be the control register address(es) for the clock.
+- #clock-cells : from common clock binding; shall be set to 1
+- clock-output-names : the corresponding gate names that the clock controls
+- clocks : should contain the parent clock for each individual gate,
+ therefore the number of clocks elements should match the number of
+ clock-output-names
+
+Example using multiple gate clocks:
+
+ clk_gates0: gate-clk@200000d0 {
+ compatible = "rockchip,rk2928-gate-clk";
+ reg = <0x200000d0 0x4>;
+ clocks = <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>,
+ <&dummy>, <&dummy>;
+
+ clock-output-names =
+ "gate_core_periph", "gate_cpu_gpll",
+ "gate_ddrphy", "gate_aclk_cpu",
+ "gate_hclk_cpu", "gate_pclk_cpu",
+ "gate_atclk_cpu", "gate_i2s0",
+ "gate_i2s0_frac", "gate_i2s1",
+ "gate_i2s1_frac", "gate_i2s2",
+ "gate_i2s2_frac", "gate_spdif",
+ "gate_spdif_frac", "gate_testclk";
+
+ #clock-cells = <1>;
+ };
+
+ clk_gates1: gate-clk@200000d4 {
+ compatible = "rockchip,rk2928-gate-clk";
+ reg = <0x200000d4 0x4>;
+ clocks = <&xin24m>, <&xin24m>,
+ <&xin24m>, <&dummy>,
+ <&dummy>, <&xin24m>,
+ <&xin24m>, <&dummy>,
+ <&xin24m>, <&dummy>,
+ <&xin24m>, <&dummy>,
+ <&xin24m>, <&dummy>,
+ <&xin24m>, <&dummy>;
+
+ clock-output-names =
+ "gate_timer0", "gate_timer1",
+ "gate_timer2", "gate_jtag",
+ "gate_aclk_lcdc1_src", "gate_otgphy0",
+ "gate_otgphy1", "gate_ddr_gpll",
+ "gate_uart0", "gate_frac_uart0",
+ "gate_uart1", "gate_frac_uart1",
+ "gate_uart2", "gate_frac_uart2",
+ "gate_uart3", "gate_frac_uart3";
+
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/clock/silabs,si5351.txt b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
index cc374651662c..c40711e8e8f7 100644
--- a/Documentation/devicetree/bindings/clock/silabs,si5351.txt
+++ b/Documentation/devicetree/bindings/clock/silabs,si5351.txt
@@ -4,7 +4,7 @@ Reference
[1] Si5351A/B/C Data Sheet
http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
-The Si5351a/b/c are programmable i2c clock generators with upto 8 output
+The Si5351a/b/c are programmable i2c clock generators with up to 8 output
clocks. Si5351a also has a reduced pin-count package (MSOP10) where only
3 output clocks are accessible. The internal structure of the clock
generators can be found in [1].
@@ -44,6 +44,11 @@ Optional child node properties:
- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
divider.
- silabs,pll-master: boolean, multisynth can change pll frequency.
+- silabs,disable-state : clock output disable state, shall be
+ 0 = clock output is driven LOW when disabled
+ 1 = clock output is driven HIGH when disabled
+ 2 = clock output is FLOATING (HIGH-Z) when disabled
+ 3 = clock output is NEVER disabled
==Example==
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 729f52426fe1..d495521a79d2 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -12,22 +12,30 @@ Required properties:
"allwinner,sun4i-axi-clk" - for the AXI clock
"allwinner,sun4i-axi-gates-clk" - for the AXI gates
"allwinner,sun4i-ahb-clk" - for the AHB clock
- "allwinner,sun4i-ahb-gates-clk" - for the AHB gates
+ "allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
+ "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
"allwinner,sun4i-apb0-clk" - for the APB0 clock
- "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates
+ "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
+ "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun4i-apb1-clk" - for the APB1 clock
"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
- "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates
+ "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
+ "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
Required properties for all clocks:
- reg : shall be the control register address for the clock.
- clocks : shall be the input parent clock(s) phandle for the clock
- #clock-cells : from common clock binding; shall be set to 0 except for
- "allwinner,sun4i-*-gates-clk" where it shall be set to 1
+ "allwinner,*-gates-clk" where it shall be set to 1
-Additionally, "allwinner,sun4i-*-gates-clk" clocks require:
+Additionally, "allwinner,*-gates-clk" clocks require:
- clock-output-names : the corresponding gate names that the clock controls
+Clock consumers should specify the desired clocks they use with a
+"clocks" phandle cell. Consumers that are using a gated clock should
+provide an additional ID in their clock property. The values of this
+ID are documented in sunxi/<soc>-gates.txt.
+
For example:
osc24M: osc24M@01c20050 {
@@ -50,102 +58,3 @@ cpu: cpu@01c20054 {
reg = <0x01c20054 0x4>;
clocks = <&osc32k>, <&osc24M>, <&pll1>;
};
-
-
-
-Gate clock outputs
-
-The "allwinner,sun4i-*-gates-clk" clocks provide several gatable outputs;
-their corresponding offsets as present on sun4i are listed below. Note that
-some of these gates are not present on sun5i.
-
- * AXI gates ("allwinner,sun4i-axi-gates-clk")
-
- DRAM 0
-
- * AHB gates ("allwinner,sun4i-ahb-gates-clk")
-
- USB0 0
- EHCI0 1
- OHCI0 2*
- EHCI1 3
- OHCI1 4*
- SS 5
- DMA 6
- BIST 7
- MMC0 8
- MMC1 9
- MMC2 10
- MMC3 11
- MS 12**
- NAND 13
- SDRAM 14
-
- ACE 16
- EMAC 17
- TS 18
-
- SPI0 20
- SPI1 21
- SPI2 22
- SPI3 23
- PATA 24
- SATA 25**
- GPS 26*
-
- VE 32
- TVD 33
- TVE0 34
- TVE1 35
- LCD0 36
- LCD1 37
-
- CSI0 40
- CSI1 41
-
- HDMI 43
- DE_BE0 44
- DE_BE1 45
- DE_FE0 46
- DE_FE1 47
-
- MP 50
-
- MALI400 52
-
- * APB0 gates ("allwinner,sun4i-apb0-gates-clk")
-
- CODEC 0
- SPDIF 1*
- AC97 2
- IIS 3
-
- PIO 5
- IR0 6
- IR1 7
-
- KEYPAD 10
-
- * APB1 gates ("allwinner,sun4i-apb1-gates-clk")
-
- I2C0 0
- I2C1 1
- I2C2 2
-
- CAN 4
- SCR 5
- PS20 6
- PS21 7
-
- UART0 16
- UART1 17
- UART2 18
- UART3 19
- UART4 20
- UART5 21
- UART6 22
- UART7 23
-
-Notation:
- [*]: The datasheet didn't mention these, but they are present on AW code
- [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt
new file mode 100644
index 000000000000..6a03475bbfe2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunxi/sun4i-a10-gates.txt
@@ -0,0 +1,93 @@
+Gate clock outputs
+------------------
+
+ * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+ DRAM 0
+
+ * AHB gates ("allwinner,sun4i-ahb-gates-clk")
+
+ USB0 0
+ EHCI0 1
+ OHCI0 2*
+ EHCI1 3
+ OHCI1 4*
+ SS 5
+ DMA 6
+ BIST 7
+ MMC0 8
+ MMC1 9
+ MMC2 10
+ MMC3 11
+ MS 12**
+ NAND 13
+ SDRAM 14
+
+ ACE 16
+ EMAC 17
+ TS 18
+
+ SPI0 20
+ SPI1 21
+ SPI2 22
+ SPI3 23
+ PATA 24
+ SATA 25**
+ GPS 26*
+
+ VE 32
+ TVD 33
+ TVE0 34
+ TVE1 35
+ LCD0 36
+ LCD1 37
+
+ CSI0 40
+ CSI1 41
+
+ HDMI 43
+ DE_BE0 44
+ DE_BE1 45
+ DE_FE1 46
+ DE_FE1 47
+
+ MP 50
+
+ MALI400 52
+
+ * APB0 gates ("allwinner,sun4i-apb0-gates-clk")
+
+ CODEC 0
+ SPDIF 1*
+ AC97 2
+ IIS 3
+
+ PIO 5
+ IR0 6
+ IR1 7
+
+ KEYPAD 10
+
+ * APB1 gates ("allwinner,sun4i-apb1-gates-clk")
+
+ I2C0 0
+ I2C1 1
+ I2C2 2
+
+ CAN 4
+ SCR 5
+ PS20 6
+ PS21 7
+
+ UART0 16
+ UART1 17
+ UART2 18
+ UART3 19
+ UART4 20
+ UART5 21
+ UART6 22
+ UART7 23
+
+Notation:
+ [*]: The datasheet didn't mention these, but they are present on AW code
+ [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt
new file mode 100644
index 000000000000..006b6dfc4703
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sunxi/sun5i-a13-gates.txt
@@ -0,0 +1,58 @@
+Gate clock outputs
+------------------
+
+ * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+ DRAM 0
+
+ * AHB gates ("allwinner,sun5i-a13-ahb-gates-clk")
+
+ USBOTG 0
+ EHCI 1
+ OHCI 2
+
+ SS 5
+ DMA 6
+ BIST 7
+ MMC0 8
+ MMC1 9
+ MMC2 10
+
+ NAND 13
+ SDRAM 14
+
+ SPI0 20
+ SPI1 21
+ SPI2 22
+
+ STIMER 28
+
+ VE 32
+
+ LCD 36
+
+ CSI 40
+
+ DE_BE 44
+
+ DE_FE 46
+
+ IEP 51
+ MALI400 52
+
+ * APB0 gates ("allwinner,sun5i-a13-apb0-gates-clk")
+
+ CODEC 0
+
+ PIO 5
+ IR 6
+
+ * APB1 gates ("allwinner,sun5i-a13-apb1-gates-clk")
+
+ I2C0 0
+ I2C1 1
+ I2C2 2
+
+ UART1 17
+
+ UART3 19
diff --git a/Documentation/devicetree/bindings/clock/vt8500.txt b/Documentation/devicetree/bindings/clock/vt8500.txt
index a880c70d0047..91d71cc0314a 100644
--- a/Documentation/devicetree/bindings/clock/vt8500.txt
+++ b/Documentation/devicetree/bindings/clock/vt8500.txt
@@ -8,6 +8,8 @@ Required properties:
- compatible : shall be one of the following:
"via,vt8500-pll-clock" - for a VT8500/WM8505 PLL clock
"wm,wm8650-pll-clock" - for a WM8650 PLL clock
+ "wm,wm8750-pll-clock" - for a WM8750 PLL clock
+ "wm,wm8850-pll-clock" - for a WM8850 PLL clock
"via,vt8500-device-clock" - for a VT/WM device clock
Required properties for PLL clocks:
diff --git a/Documentation/devicetree/bindings/dma/atmel-dma.txt b/Documentation/devicetree/bindings/dma/atmel-dma.txt
index c80e8a3402f0..c280a0e6f42d 100644
--- a/Documentation/devicetree/bindings/dma/atmel-dma.txt
+++ b/Documentation/devicetree/bindings/dma/atmel-dma.txt
@@ -24,8 +24,11 @@ The three cells in order are:
1. A phandle pointing to the DMA controller.
2. The memory interface (16 most significant bits), the peripheral interface
(16 less significant bits).
-3. The peripheral identifier for the hardware handshaking interface. The
-identifier can be different for tx and rx.
+3. Parameters for the at91 DMA configuration register which are device
+dependant:
+ - bit 7-0: peripheral identifier for the hardware handshaking interface. The
+ identifier can be different for tx and rx.
+ - bit 11-8: FIFO configuration. 0 for half FIFO, 1 for ALAP, 1 for ASAP.
Example:
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-dma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-dma.txt
new file mode 100644
index 000000000000..2717ecb47db9
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/fsl-imx-dma.txt
@@ -0,0 +1,48 @@
+* Freescale Direct Memory Access (DMA) Controller for i.MX
+
+This document will only describe differences to the generic DMA Controller and
+DMA request bindings as described in dma/dma.txt .
+
+* DMA controller
+
+Required properties:
+- compatible : Should be "fsl,<chip>-dma". chip can be imx1, imx21 or imx27
+- reg : Should contain DMA registers location and length
+- interrupts : First item should be DMA interrupt, second one is optional and
+ should contain DMA Error interrupt
+- #dma-cells : Has to be 1. imx-dma does not support anything else.
+
+Optional properties:
+- #dma-channels : Number of DMA channels supported. Should be 16.
+- #dma-requests : Number of DMA requests supported.
+
+Example:
+
+ dma: dma@10001000 {
+ compatible = "fsl,imx27-dma";
+ reg = <0x10001000 0x1000>;
+ interrupts = <32 33>;
+ #dma-cells = <1>;
+ #dma-channels = <16>;
+ };
+
+
+* DMA client
+
+Clients have to specify the DMA requests with phandles in a list.
+
+Required properties:
+- dmas: List of one or more DMA request specifiers. One DMA request specifier
+ consists of a phandle to the DMA controller followed by the integer
+ specifiying the request line.
+- dma-names: List of string identifiers for the DMA requests. For the correct
+ names, have a look at the specific client driver.
+
+Example:
+
+ sdhci1: sdhci@10013000 {
+ ...
+ dmas = <&dma 7>;
+ dma-names = "rx-tx";
+ ...
+ };
diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
index d1e3f443e205..68cee4f5539f 100644
--- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
+++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
@@ -4,14 +4,70 @@ Required properties:
- compatible : Should be "fsl,<chip>-sdma"
- reg : Should contain SDMA registers location and length
- interrupts : Should contain SDMA interrupt
+- #dma-cells : Must be <3>.
+ The first cell specifies the DMA request/event ID. See details below
+ about the second and third cell.
- fsl,sdma-ram-script-name : Should contain the full path of SDMA RAM
scripts firmware
+The second cell of dma phandle specifies the peripheral type of DMA transfer.
+The full ID of peripheral types can be found below.
+
+ ID transfer type
+ ---------------------
+ 0 MCU domain SSI
+ 1 Shared SSI
+ 2 MMC
+ 3 SDHC
+ 4 MCU domain UART
+ 5 Shared UART
+ 6 FIRI
+ 7 MCU domain CSPI
+ 8 Shared CSPI
+ 9 SIM
+ 10 ATA
+ 11 CCM
+ 12 External peripheral
+ 13 Memory Stick Host Controller
+ 14 Shared Memory Stick Host Controller
+ 15 DSP
+ 16 Memory
+ 17 FIFO type Memory
+ 18 SPDIF
+ 19 IPU Memory
+ 20 ASRC
+ 21 ESAI
+
+The third cell specifies the transfer priority as below.
+
+ ID transfer priority
+ -------------------------
+ 0 High
+ 1 Medium
+ 2 Low
+
Examples:
sdma@83fb0000 {
compatible = "fsl,imx51-sdma", "fsl,imx35-sdma";
reg = <0x83fb0000 0x4000>;
interrupts = <6>;
+ #dma-cells = <3>;
fsl,sdma-ram-script-name = "sdma-imx51.bin";
};
+
+DMA clients connected to the i.MX SDMA controller must use the format
+described in the dma.txt file.
+
+Examples:
+
+ssi2: ssi@70014000 {
+ compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
+ reg = <0x70014000 0x4000>;
+ interrupts = <30>;
+ clocks = <&clks 49>;
+ dmas = <&sdma 24 1 0>,
+ <&sdma 25 1 0>;
+ dma-names = "rx", "tx";
+ fsl,fifo-depth = <15>;
+};
diff --git a/Documentation/devicetree/bindings/dma/shdma.txt b/Documentation/devicetree/bindings/dma/shdma.txt
new file mode 100644
index 000000000000..c15994aa1939
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/shdma.txt
@@ -0,0 +1,75 @@
+* SHDMA Device Tree bindings
+
+Sh-/r-mobile and r-car systems often have multiple identical DMA controller
+instances, capable of serving any of a common set of DMA slave devices, using
+the same configuration. To describe this topology we require all compatible
+SHDMA DT nodes to be placed under a DMA multiplexer node. All such compatible
+DMAC instances have the same number of channels and use the same DMA
+descriptors. Therefore respective DMA DT bindings can also all be placed in the
+multiplexer node. Even if there is only one such DMAC instance on a system, it
+still has to be placed under such a multiplexer node.
+
+* DMA multiplexer
+
+Required properties:
+- compatible: should be "renesas,shdma-mux"
+- #dma-cells: should be <1>, see "dmas" property below
+
+Optional properties (currently unused):
+- dma-channels: number of DMA channels
+- dma-requests: number of DMA request signals
+
+* DMA controller
+
+Required properties:
+- compatible: should be "renesas,shdma"
+
+Example:
+ dmac: dma-mux0 {
+ compatible = "renesas,shdma-mux";
+ #dma-cells = <1>;
+ dma-channels = <6>;
+ dma-requests = <256>;
+ reg = <0 0>; /* Needed for AUXDATA */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ dma0: shdma@fe008020 {
+ compatible = "renesas,shdma";
+ reg = <0xfe008020 0x270>,
+ <0xfe009000 0xc>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 34 4
+ 0 28 4
+ 0 29 4
+ 0 30 4
+ 0 31 4
+ 0 32 4
+ 0 33 4>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5";
+ };
+
+ dma1: shdma@fe018020 {
+ ...
+ };
+
+ dma2: shdma@fe028020 {
+ ...
+ };
+ };
+
+* DMA client
+
+Required properties:
+- dmas: a list of <[DMA multiplexer phandle] [MID/RID value]> pairs,
+ where MID/RID values are fixed handles, specified in the SoC
+ manual
+- dma-names: a list of DMA channel names, one per "dmas" entry
+
+Example:
+ dmas = <&dmac 0xd1
+ &dmac 0xd2>;
+ dma-names = "tx", "rx";
diff --git a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
index e5f130159ae1..fff10da5e927 100644
--- a/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
+++ b/Documentation/devicetree/bindings/drm/tilcdc/tilcdc.txt
@@ -10,6 +10,14 @@ Recommended properties:
services interrupts for this device.
- ti,hwmods: Name of the hwmod associated to the LCDC
+Optional properties:
+ - max-bandwidth: The maximum pixels per second that the memory
+ interface / lcd controller combination can sustain
+ - max-width: The maximum horizontal pixel width supported by
+ the lcd controller.
+ - max-pixelclock: The maximum pixel clock that can be supported
+ by the lcd controller in KHz.
+
Example:
fb: fb@4830e000 {
diff --git a/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt b/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
new file mode 100644
index 000000000000..63bf4becd5f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
@@ -0,0 +1,48 @@
+Xilinx plb/axi GPIO controller
+
+Dual channel GPIO controller with configurable number of pins
+(from 1 to 32 per channel). Every pin can be configured as
+input/output/tristate. Both channels share the same global IRQ but
+local interrupts can be enabled on channel basis.
+
+Required properties:
+- compatible : Should be "xlnx,xps-gpio-1.00.a"
+- reg : Address and length of the register set for the device
+- #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.
+
+Optional properties:
+- interrupts : Interrupt mapping for GPIO IRQ.
+- interrupt-parent : Phandle for the interrupt controller that
+ services interrupts for this device.
+- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
+- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
+- xlnx,gpio-width : gpio width
+- xlnx,tri-default : if n-th bit is 1, GPIO-n is in tristate mode
+- xlnx,is-dual : if 1, controller also uses the second channel
+- xlnx,all-inputs-2 : as above but for the second channel
+- xlnx,dout-default-2 : as above but the second channel
+- xlnx,gpio2-width : as above but for the second channel
+- xlnx,tri-default-2 : as above but for the second channel
+
+
+Example:
+gpio: gpio@40000000 {
+ #gpio-cells = <2>;
+ compatible = "xlnx,xps-gpio-1.00.a";
+ gpio-controller ;
+ interrupt-parent = <&microblaze_0_intc>;
+ interrupts = < 6 2 >;
+ reg = < 0x40000000 0x10000 >;
+ xlnx,all-inputs = <0x0>;
+ xlnx,all-inputs-2 = <0x0>;
+ xlnx,dout-default = <0x0>;
+ xlnx,dout-default-2 = <0x0>;
+ xlnx,gpio-width = <0x2>;
+ xlnx,gpio2-width = <0x2>;
+ xlnx,interrupt-present = <0x1>;
+ xlnx,is-dual = <0x1>;
+ xlnx,tri-default = <0xffffffff>;
+ xlnx,tri-default-2 = <0xffffffff>;
+} ;
diff --git a/Documentation/devicetree/bindings/hwmon/g762.txt b/Documentation/devicetree/bindings/hwmon/g762.txt
new file mode 100644
index 000000000000..25cc6d8ee575
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/g762.txt
@@ -0,0 +1,47 @@
+GMT G762/G763 PWM Fan controller
+
+Required node properties:
+
+ - "compatible": must be either "gmt,g762" or "gmt,g763"
+ - "reg": I2C bus address of the device
+ - "clocks": a fixed clock providing input clock frequency
+ on CLK pin of the chip.
+
+Optional properties:
+
+ - "fan_startv": fan startup voltage. Accepted values are 0, 1, 2 and 3.
+ The higher the more.
+
+ - "pwm_polarity": pwm polarity. Accepted values are 0 (positive duty)
+ and 1 (negative duty).
+
+ - "fan_gear_mode": fan gear mode. Supported values are 0, 1 and 2.
+
+If an optional property is not set in .dts file, then current value is kept
+unmodified (e.g. u-boot installed value).
+
+Additional information on operational parameters for the device is available
+in Documentation/hwmon/g762. A detailed datasheet for the device is available
+at http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf.
+
+Example g762 node:
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ g762_clk: fixedclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <8192>;
+ }
+ }
+
+ g762: g762@3e {
+ compatible = "gmt,g762";
+ reg = <0x3e>;
+ clocks = <&g762_clk>
+ fan_gear_mode = <0>; /* chip default */
+ fan_startv = <1>; /* chip default */
+ pwm_polarity = <0>; /* chip default */
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
index e42a2ee233e6..7fd7fa25e9b0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt
@@ -10,6 +10,10 @@ Recommended properties :
- clock-frequency : desired I2C bus clock frequency in Hz.
+Optional properties :
+ - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
+ This option is only supported in hardware blocks version 1.11a or newer.
+
Example :
i2c@f0000 {
@@ -20,3 +24,14 @@ Example :
interrupts = <11>;
clock-frequency = <400000>;
};
+
+ i2c@1120000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0x1120000 0x1000>;
+ interrupt-parent = <&ictl>;
+ interrupts = <12 1>;
+ clock-frequency = <400000>;
+ i2c-sda-hold-time-ns = <300>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
index f46d928aa73d..a1ee681942cc 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
@@ -6,7 +6,11 @@ Required properties :
- reg : Offset and length of the register set for the device
- compatible : Should be "marvell,mv64xxx-i2c"
- interrupts : The interrupt number
- - clock-frequency : Desired I2C bus clock frequency in Hz.
+
+Optional properties :
+
+ - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the
+default frequency is 100kHz
Examples:
diff --git a/Documentation/devicetree/bindings/i2c/i2c-vt8500.txt b/Documentation/devicetree/bindings/i2c/i2c-vt8500.txt
new file mode 100644
index 000000000000..94a425eaa6c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-vt8500.txt
@@ -0,0 +1,24 @@
+* Wondermedia I2C Controller
+
+Required properties :
+
+ - compatible : should be "wm,wm8505-i2c"
+ - reg : Offset and length of the register set for the device
+ - interrupts : <IRQ> where IRQ is the interrupt number
+ - clocks : phandle to the I2C clock source
+
+Optional properties :
+
+ - clock-frequency : desired I2C bus clock frequency in Hz.
+ Valid values are 100000 and 400000.
+ Default to 100000 if not specified, or invalid value.
+
+Example :
+
+ i2c_0: i2c@d8280000 {
+ compatible = "wm,wm8505-i2c";
+ reg = <0xd8280000 0x1000>;
+ interrupts = <19>;
+ clocks = <&clki2c0>;
+ clock-frequency = <400000>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/ina2xx.txt b/Documentation/devicetree/bindings/i2c/ina2xx.txt
new file mode 100644
index 000000000000..a2ad85d7e747
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/ina2xx.txt
@@ -0,0 +1,22 @@
+ina2xx properties
+
+Required properties:
+- compatible: Must be one of the following:
+ - "ti,ina219" for ina219
+ - "ti,ina220" for ina220
+ - "ti,ina226" for ina226
+ - "ti,ina230" for ina230
+- reg: I2C address
+
+Optional properties:
+
+- shunt-resistor
+ Shunt resistor value in micro-Ohm
+
+Example:
+
+ina220@44 {
+ compatible = "ti,ina220";
+ reg = <0x44>;
+ shunt-resistor = <1000>;
+};
diff --git a/Documentation/devicetree/bindings/input/pxa27x-keypad.txt b/Documentation/devicetree/bindings/input/pxa27x-keypad.txt
new file mode 100644
index 000000000000..f8674f7e5ea5
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/pxa27x-keypad.txt
@@ -0,0 +1,60 @@
+* Marvell PXA Keypad controller
+
+Required Properties
+- compatible : should be "marvell,pxa27x-keypad"
+- reg : Address and length of the register set for the device
+- interrupts : The interrupt for the keypad controller
+- marvell,debounce-interval : How long time the key will be
+ recognized when it is pressed. It is a u32 value, and bit[31:16]
+ is debounce interval for direct key and bit[15:0] is debounce
+ interval for matrix key. The value is in binary number of 2ms
+
+Optional Properties For Matrix Keyes
+Please refer to matrix-keymap.txt
+
+Optional Properties for Direct Keyes
+- marvell,direct-key-count : How many direct keyes are used.
+- marvell,direct-key-mask : The mask indicates which keyes
+ are used. If bit[X] of the mask is set, the direct key X
+ is used.
+- marvell,direct-key-low-active : Direct key status register
+ tells the level of pins that connects to the direct keyes.
+ When this property is set, it means that when the pin level
+ is low, the key is pressed(active).
+- marvell,direct-key-map : It is a u16 array. Each item indicates
+ the linux key-code for the direct key.
+
+Optional Properties For Rotary
+- marvell,rotary0 : It is a u32 value. Bit[31:16] is the
+ linux key-code for rotary up. Bit[15:0] is the linux key-code
+ for rotary down. It is for rotary 0.
+- marvell,rotary1 : Same as marvell,rotary0. It is for rotary 1.
+- marvell,rotary-rel-key : When rotary is used for relative axes
+ in the device, the value indicates the key-code for relative
+ axes measurement in the device. It is a u32 value. Bit[31:16]
+ is for rotary 1, and Bit[15:0] is for rotary 0.
+
+Examples:
+ keypad: keypad@d4012000 {
+ keypad,num-rows = <3>;
+ keypad,num-columns = <5>;
+ linux,keymap = <0x0000000e /* KEY_BACKSPACE */
+ 0x0001006b /* KEY_END */
+ 0x00020061 /* KEY_RIGHTCTRL */
+ 0x0003000b /* KEY_0 */
+ 0x00040002 /* KEY_1 */
+ 0x0100008b /* KEY_MENU */
+ 0x01010066 /* KEY_HOME */
+ 0x010200e7 /* KEY_SEND */
+ 0x01030009 /* KEY_8 */
+ 0x0104000a /* KEY_9 */
+ 0x02000160 /* KEY_OK */
+ 0x02010003 /* KEY_2 */
+ 0x02020004 /* KEY_3 */
+ 0x02030005 /* KEY_4 */
+ 0x02040006>; /* KEY_5 */
+ marvell,rotary0 = <0x006c0067>; /* KEY_UP & KEY_DOWN */
+ marvell,direct-key-count = <1>;
+ marvell,direct-key-map = <0x001c>;
+ marvell,debounce-interval = <0x001e001e>;
+ };
diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt
index ce3e394c0e64..942d071baaa5 100644
--- a/Documentation/devicetree/bindings/input/samsung-keypad.txt
+++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt
@@ -25,14 +25,6 @@ Required Board Specific Properties:
- samsung,keypad-num-columns: Number of column lines connected to the
keypad controller.
-- row-gpios: List of gpios used as row lines. The gpio specifier for
- this property depends on the gpio controller to which these row lines
- are connected.
-
-- col-gpios: List of gpios used as column lines. The gpio specifier for
- this property depends on the gpio controller to which these column
- lines are connected.
-
- Keys represented as child nodes: Each key connected to the keypad
controller is represented as a child node to the keypad controller
device node and should include the following properties.
@@ -41,6 +33,9 @@ Required Board Specific Properties:
- linux,code: the key-code to be reported when the key is pressed
and released.
+- pinctrl-0: Should specify pin control groups used for this controller.
+- pinctrl-names: Should contain only one value - "default".
+
Optional Properties specific to linux:
- linux,keypad-no-autorepeat: do no enable autorepeat feature.
- linux,keypad-wakeup: use any event on keypad as wakeup event.
@@ -56,17 +51,8 @@ Example:
linux,input-no-autorepeat;
linux,input-wakeup;
- row-gpios = <&gpx2 0 3 3 0
- &gpx2 1 3 3 0>;
-
- col-gpios = <&gpx1 0 3 0 0
- &gpx1 1 3 0 0
- &gpx1 2 3 0 0
- &gpx1 3 3 0 0
- &gpx1 4 3 0 0
- &gpx1 5 3 0 0
- &gpx1 6 3 0 0
- &gpx1 7 3 0 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&keypad_rows &keypad_columns>;
key_1 {
keypad,row = <0>;
diff --git a/Documentation/devicetree/bindings/input/ti,nspire-keypad.txt b/Documentation/devicetree/bindings/input/ti,nspire-keypad.txt
new file mode 100644
index 000000000000..513d94d6e899
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/ti,nspire-keypad.txt
@@ -0,0 +1,60 @@
+TI-NSPIRE Keypad
+
+Required properties:
+- compatible: Compatible property value should be "ti,nspire-keypad".
+
+- reg: Physical base address of the peripheral and length of memory mapped
+ region.
+
+- interrupts: The interrupt number for the peripheral.
+
+- scan-interval: How often to scan in us. Based on a APB speed of 33MHz, the
+ maximum and minimum delay time is ~2000us and ~500us respectively
+
+- row-delay: How long to wait before scanning each row.
+
+- clocks: The clock this peripheral is attached to.
+
+- linux,keymap: The keymap to use
+ (see Documentation/devicetree/bindings/input/matrix-keymap.txt)
+
+Optional properties:
+- active-low: Specify that the keypad is active low (i.e. logical low signifies
+ a key press).
+
+Example:
+
+input {
+ compatible = "ti,nspire-keypad";
+ reg = <0x900E0000 0x1000>;
+ interrupts = <16>;
+
+ scan-interval = <1000>;
+ row-delay = <200>;
+
+ clocks = <&apb_pclk>;
+
+ linux,keymap = <
+ 0x0000001c 0x0001001c 0x00040039
+ 0x0005002c 0x00060015 0x0007000b
+ 0x0008000f 0x0100002d 0x01010011
+ 0x0102002f 0x01030004 0x01040016
+ 0x01050014 0x0106001f 0x01070002
+ 0x010a006a 0x02000013 0x02010010
+ 0x02020019 0x02030007 0x02040018
+ 0x02050031 0x02060032 0x02070005
+ 0x02080028 0x0209006c 0x03000026
+ 0x03010025 0x03020024 0x0303000a
+ 0x03040017 0x03050023 0x03060022
+ 0x03070008 0x03080035 0x03090069
+ 0x04000021 0x04010012 0x04020020
+ 0x0404002e 0x04050030 0x0406001e
+ 0x0407000d 0x04080037 0x04090067
+ 0x05010038 0x0502000c 0x0503001b
+ 0x05040034 0x0505001a 0x05060006
+ 0x05080027 0x0509000e 0x050a006f
+ 0x0600002b 0x0602004e 0x06030068
+ 0x06040003 0x0605006d 0x06060009
+ 0x06070001 0x0609000f 0x0708002a
+ 0x0709001d 0x070a0033 >;
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
new file mode 100644
index 000000000000..491c97b78384
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt
@@ -0,0 +1,44 @@
+* TI - TSC ADC (Touschscreen and analog digital converter)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Required properties:
+- child "tsc"
+ ti,wires: Wires refer to application modes i.e. 4/5/8 wire touchscreen
+ support on the platform.
+ ti,x-plate-resistance: X plate resistance
+ ti,coordiante-readouts: The sequencer supports a total of 16
+ programmable steps each step is used to
+ read a single coordinate. A single
+ readout is enough but multiple reads can
+ increase the quality.
+ A value of 5 means, 5 reads for X, 5 for
+ Y and 2 for Z (always). This utilises 12
+ of the 16 software steps available. The
+ remaining 4 can be used by the ADC.
+ ti,wire-config: Different boards could have a different order for
+ connecting wires on touchscreen. We need to provide an
+ 8 bit number where in the 1st four bits represent the
+ analog lines and the next 4 bits represent positive/
+ negative terminal on that input line. Notations to
+ represent the input lines and terminals resoectively
+ is as follows:
+ AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7.
+ XP = 0, XN = 1, YP = 2, YN = 3.
+- child "adc"
+ ti,adc-channels: List of analog inputs available for ADC.
+ AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7.
+
+Example:
+ tscadc: tscadc@44e0d000 {
+ compatible = "ti,am3359-tscadc";
+ tsc {
+ ti,wires = <4>;
+ ti,x-plate-resistance = <200>;
+ ti,coordiante-readouts = <5>;
+ ti,wire-config = <0x00 0x11 0x22 0x33>;
+ };
+
+ adc {
+ ti,adc-channels = <4 5 6 7>;
+ };
+ }
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
new file mode 100644
index 000000000000..e34c6cdd8ba8
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -0,0 +1,70 @@
+* ARM System MMU Architecture Implementation
+
+ARM SoCs may contain an implementation of the ARM System Memory
+Management Unit Architecture, which can be used to provide 1 or 2 stages
+of address translation to bus masters external to the CPU.
+
+The SMMU may also raise interrupts in response to various fault
+conditions.
+
+** System MMU required properties:
+
+- compatible : Should be one of:
+
+ "arm,smmu-v1"
+ "arm,smmu-v2"
+ "arm,mmu-400"
+ "arm,mmu-500"
+
+ depending on the particular implementation and/or the
+ version of the architecture implemented.
+
+- reg : Base address and size of the SMMU.
+
+- #global-interrupts : The number of global interrupts exposed by the
+ device.
+
+- interrupts : Interrupt list, with the first #global-irqs entries
+ corresponding to the global interrupts and any
+ following entries corresponding to context interrupts,
+ specified in order of their indexing by the SMMU.
+
+ For SMMUv2 implementations, there must be exactly one
+ interrupt per context bank. In the case of a single,
+ combined interrupt, it must be listed multiple times.
+
+- mmu-masters : A list of phandles to device nodes representing bus
+ masters for which the SMMU can provide a translation
+ and their corresponding StreamIDs (see example below).
+ Each device node linked from this list must have a
+ "#stream-id-cells" property, indicating the number of
+ StreamIDs associated with it.
+
+** System MMU optional properties:
+
+- smmu-parent : When multiple SMMUs are chained together, this
+ property can be used to provide a phandle to the
+ parent SMMU (that is the next SMMU on the path going
+ from the mmu-masters towards memory) node for this
+ SMMU.
+
+Example:
+
+ smmu {
+ compatible = "arm,smmu-v1";
+ reg = <0xba5e0000 0x10000>;
+ #global-interrupts = <2>;
+ interrupts = <0 32 4>,
+ <0 33 4>,
+ <0 34 4>, /* This is the first context interrupt */
+ <0 35 4>,
+ <0 36 4>,
+ <0 37 4>;
+
+ /*
+ * Two DMA controllers, the first with two StreamIDs (0xd01d
+ * and 0xd01e) and the second with only one (0xd11c).
+ */
+ mmu-masters = <&dma0 0xd01d 0xd01e>,
+ <&dma1 0xd11c>;
+ };
diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.txt b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt
new file mode 100644
index 000000000000..d5176882d8b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.txt
@@ -0,0 +1,147 @@
+Binding for TI/National Semiconductor LP55xx Led Drivers
+
+Required properties:
+- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562"
+- reg: I2C slave address
+- clock-mode: Input clock mode, (0: automode, 1: internal, 2: external)
+
+Each child has own specific current settings
+- led-cur: Current setting at each led channel (mA x10, 0 if led is not connected)
+- max-cur: Maximun current at each led channel.
+
+Optional properties:
+- label: Used for naming LEDs
+
+Alternatively, each child can have specific channel name
+- chan-name: Name of each channel name
+
+example 1) LP5521
+3 LED channels, external clock used. Channel names are 'lp5521_pri:channel0',
+'lp5521_pri:channel1' and 'lp5521_pri:channel2'
+
+lp5521@32 {
+ compatible = "national,lp5521";
+ reg = <0x32>;
+ label = "lp5521_pri";
+ clock-mode = /bits/ 8 <2>;
+
+ chan0 {
+ led-cur = /bits/ 8 <0x2f>;
+ max-cur = /bits/ 8 <0x5f>;
+ };
+
+ chan1 {
+ led-cur = /bits/ 8 <0x2f>;
+ max-cur = /bits/ 8 <0x5f>;
+ };
+
+ chan2 {
+ led-cur = /bits/ 8 <0x2f>;
+ max-cur = /bits/ 8 <0x5f>;
+ };
+};
+
+example 2) LP5523
+9 LED channels with specific name. Internal clock used.
+The I2C slave address is configurable with ASEL1 and ASEL0 pins.
+Available addresses are 32/33/34/35h.
+
+ASEL1 ASEL0 Address
+-------------------------
+ GND GND 32h
+ GND VEN 33h
+ VEN GND 34h
+ VEN VEN 35h
+
+lp5523@32 {
+ compatible = "national,lp5523";
+ reg = <0x32>;
+ clock-mode = /bits/ 8 <1>;
+
+ chan0 {
+ chan-name = "d1";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan1 {
+ chan-name = "d2";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan2 {
+ chan-name = "d3";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan3 {
+ chan-name = "d4";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan4 {
+ chan-name = "d5";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan5 {
+ chan-name = "d6";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan6 {
+ chan-name = "d7";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan7 {
+ chan-name = "d8";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+
+ chan8 {
+ chan-name = "d9";
+ led-cur = /bits/ 8 <0x14>;
+ max-cur = /bits/ 8 <0x20>;
+ };
+};
+
+example 3) LP5562
+4 channels are defined.
+
+lp5562@30 {
+ compatible = "ti,lp5562";
+ reg = <0x30>;
+ clock-mode = /bits/8 <2>;
+
+ chan0 {
+ chan-name = "R";
+ led-cur = /bits/ 8 <0x20>;
+ max-cur = /bits/ 8 <0x60>;
+ };
+
+ chan1 {
+ chan-name = "G";
+ led-cur = /bits/ 8 <0x20>;
+ max-cur = /bits/ 8 <0x60>;
+ };
+
+ chan2 {
+ chan-name = "B";
+ led-cur = /bits/ 8 <0x20>;
+ max-cur = /bits/ 8 <0x60>;
+ };
+
+ chan3 {
+ chan-name = "W";
+ led-cur = /bits/ 8 <0x20>;
+ max-cur = /bits/ 8 <0x60>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/metag/meta.txt b/Documentation/devicetree/bindings/metag/meta.txt
new file mode 100644
index 000000000000..f4457f57ab08
--- /dev/null
+++ b/Documentation/devicetree/bindings/metag/meta.txt
@@ -0,0 +1,30 @@
+* Meta Processor Binding
+
+This binding specifies what properties must be available in the device tree
+representation of a Meta Processor Core, which is the root node in the tree.
+
+Required properties:
+
+ - compatible: Specifies the compatibility list for the Meta processor.
+ The type shall be <string> and the value shall include "img,meta".
+
+Optional properties:
+
+ - clocks: Clock consumer specifiers as described in
+ Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+ - clock-names: Clock consumer names as described in
+ Documentation/devicetree/bindings/clock/clock-bindings.txt.
+
+Clocks are identified by name. Valid clocks are:
+
+ - "core": The Meta core clock from which the Meta timers are derived.
+
+* Examples
+
+/ {
+ compatible = "toumaz,tz1090", "img,meta";
+
+ clocks = <&meta_core_clk>;
+ clock-names = "core";
+};
diff --git a/Documentation/devicetree/bindings/mfd/arizona.txt b/Documentation/devicetree/bindings/mfd/arizona.txt
new file mode 100644
index 000000000000..0e295c9d8937
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/arizona.txt
@@ -0,0 +1,62 @@
+Wolfson Arizona class audio SoCs
+
+These devices are audio SoCs with extensive digital capabilites and a range
+of analogue I/O.
+
+Required properties:
+
+ - compatible : one of the following chip-specific strings:
+ "wlf,wm5102"
+ "wlf,wm5110"
+ - reg : I2C slave address when connected using I2C, chip select number when
+ using SPI.
+
+ - interrupts : The interrupt line the /IRQ signal for the device is
+ connected to.
+ - interrupt-controller : Arizona class devices contain interrupt controllers
+ and may provide interrupt services to other devices.
+ - interrupt-parent : The parent interrupt controller.
+ - #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
+ The first cell is the IRQ number.
+ The second cell is the flags, encoded as the trigger masks from
+ Documentation/devicetree/bindings/interrupts.txt
+
+ - gpio-controller : Indicates this device is a GPIO controller.
+ - #gpio-cells : Must be 2. The first cell is the pin number and the
+ second cell is used to specify optional parameters (currently unused).
+
+ - AVDD1-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
+ SPKVDDL-supply, SPKVDDR-supply : power supplies for the device, as covered
+ in Documentation/devicetree/bindings/regulator/regulator.txt
+
+Optional properties:
+
+ - wlf,reset : GPIO specifier for the GPIO controlling /RESET
+ - wlf,ldoena : GPIO specifier for the GPIO controlling LDOENA
+
+ - wlf,gpio-defaults : A list of GPIO configuration register values. If
+ absent, no configuration of these registers is performed. If any
+ entry has a value that is out of range for a 16 bit register then
+ the chip default will be used. If present exactly five values must
+ be specified.
+
+Example:
+
+codec: wm5102@1a {
+ compatible = "wlf,wm5102";
+ reg = <0x1a>;
+ interrupts = <347>;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&gic>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ wlf,gpio-defaults = <
+ 0x00000000, /* AIF1TXLRCLK */
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ >;
+};
diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
new file mode 100644
index 000000000000..11921cc417bf
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
@@ -0,0 +1,55 @@
+Maxim MAX77693 multi-function device
+
+MAX77693 is a Multifunction device with the following submodules:
+- PMIC,
+- CHARGER,
+- LED,
+- MUIC,
+- HAPTIC
+
+It is interfaced to host controller using i2c.
+This document describes the bindings for the mfd device.
+
+Required properties:
+- compatible : Must be "maxim,max77693".
+- reg : Specifies the i2c slave address of PMIC block.
+- interrupts : This i2c device has an IRQ line connected to the main SoC.
+- interrupt-parent : The parent interrupt controller.
+
+Optional properties:
+- regulators : The regulators of max77693 have to be instantiated under subnod
+ named "regulators" using the following format.
+
+ regulators {
+ regualtor-compatible = ESAFEOUT1/ESAFEOUT2/CHARGER
+ standard regulator constratints[*].
+ };
+
+ [*] refer Documentation/devicetree/bindings/regulator/regulator.txt
+
+Example:
+ max77693@66 {
+ compatible = "maxim,max77693";
+ reg = <0x66>;
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 2>;
+
+ regulators {
+ esafeout@1 {
+ regulator-compatible = "ESAFEOUT1";
+ regulator-name = "ESAFEOUT1";
+ regulator-boot-on;
+ };
+ esafeout@2 {
+ regulator-compatible = "ESAFEOUT2";
+ regulator-name = "ESAFEOUT2";
+ };
+ charger@0 {
+ regulator-compatible = "CHARGER";
+ regulator-name = "CHARGER";
+ regulator-min-microamp = <60000>;
+ regulator-max-microamp = <2580000>;
+ regulator-boot-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/max8998.txt b/Documentation/devicetree/bindings/mfd/max8998.txt
new file mode 100644
index 000000000000..23a3650ff2a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max8998.txt
@@ -0,0 +1,119 @@
+* Maxim MAX8998, National/TI LP3974 multi-function device
+
+The Maxim MAX8998 is a multi-function device which includes voltage/current
+regulators, real time clock, battery charging controller and several
+other sub-blocks. It is interfaced using an I2C interface. Each sub-block
+is addressed by the host system using different i2c slave address.
+
+PMIC sub-block
+--------------
+
+The PMIC sub-block contains a number of voltage and current regulators,
+with controllable parameters and dynamic voltage scaling capability.
+In addition, it includes a real time clock and battery charging controller
+as well. It is accessible at I2C address 0x66.
+
+Required properties:
+- compatible: Should be one of the following:
+ - "maxim,max8998" for Maxim MAX8998
+ - "national,lp3974" or "ti,lp3974" for National/TI LP3974.
+- reg: Specifies the i2c slave address of the pmic block. It should be 0x66.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+ the interrupts from MAX8998 are routed to.
+- interrupts: Interrupt specifiers for two interrupt sources.
+ - First interrupt specifier is for main interrupt.
+ - Second interrupt specifier is for power-on/-off interrupt.
+- max8998,pmic-buck1-dvs-gpios: GPIO specifiers for two host gpios used
+ for buck 1 dvs. The format of the gpio specifier depends on the gpio
+ controller.
+- max8998,pmic-buck2-dvs-gpio: GPIO specifier for host gpio used
+ for buck 2 dvs. The format of the gpio specifier depends on the gpio
+ controller.
+- max8998,pmic-buck1-default-dvs-idx: Default voltage setting selected from
+ the possible 4 options selectable by the dvs gpios. The value of this
+ property should be 0, 1, 2 or 3. If not specified or out of range,
+ a default value of 0 is taken.
+- max8998,pmic-buck2-default-dvs-idx: Default voltage setting selected from
+ the possible 2 options selectable by the dvs gpios. The value of this
+ property should be 0 or 1. If not specified or out of range, a default
+ value of 0 is taken.
+- max8998,pmic-buck-voltage-lock: If present, disallows changing of
+ preprogrammed buck dvfs voltages.
+
+Additional properties required if max8998,pmic-buck1-dvs-gpios is defined:
+- max8998,pmic-buck1-dvs-voltage: An array of 4 voltage values in microvolts
+ for buck1 regulator that can be selected using dvs gpio.
+
+Additional properties required if max8998,pmic-buck2-dvs-gpio is defined:
+- max8998,pmic-buck2-dvs-voltage: An array of 2 voltage values in microvolts
+ for buck2 regulator that can be selected using dvs gpio.
+
+Regulators: All the regulators of MAX8998 to be instantiated shall be
+listed in a child node named 'regulators'. Each regulator is represented
+by a child node of the 'regulators' node.
+
+ regulator-name {
+ /* standard regulator bindings here */
+ };
+
+Following regulators of the MAX8998 PMIC block are supported. Note that
+the 'n' in regulator name, as in LDOn or BUCKn, represents the LDO or BUCK
+number as described in MAX8998 datasheet.
+
+ - LDOn
+ - valid values for n are 2 to 17
+ - Example: LDO2, LDO10, LDO17
+ - BUCKn
+ - valid values for n are 1 to 4.
+ - Example: BUCK1, BUCK2, BUCK3, BUCK4
+
+ - ENVICHG: Battery Charging Current Monitor Output. This is a fixed
+ voltage type regulator
+
+ - ESAFEOUT1: (ldo19)
+ - ESAFEOUT2: (ld020)
+
+Standard regulator bindings are used inside regulator subnodes. Check
+ Documentation/devicetree/bindings/regulator/regulator.txt
+for more details.
+
+Example:
+
+ pmic@66 {
+ compatible = "maxim,max8998-pmic";
+ reg = <0x66>;
+ interrupt-parent = <&wakeup_eint>;
+ interrupts = <4 0>, <3 0>;
+
+ /* Buck 1 DVS settings */
+ max8998,pmic-buck1-default-dvs-idx = <0>;
+ max8998,pmic-buck1-dvs-gpios = <&gpx0 0 1 0 0>, /* SET1 */
+ <&gpx0 1 1 0 0>; /* SET2 */
+ max8998,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
+ <1000000>, <950000>;
+
+ /* Buck 2 DVS settings */
+ max8998,pmic-buck2-default-dvs-idx = <0>;
+ max8998,pmic-buck2-dvs-gpio = <&gpx0 0 3 0 0>; /* SET3 */
+ max8998,pmic-buck2-dvs-voltage = <1350000>, <1300000>;
+
+ /* Regulators to instantiate */
+ regulators {
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_ALIVE_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "VDD_ARM_1.2V";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/palmas.txt b/Documentation/devicetree/bindings/mfd/palmas.txt
new file mode 100644
index 000000000000..892537d1a48f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/palmas.txt
@@ -0,0 +1,49 @@
+* palmas device tree bindings
+
+The TI palmas family current members :-
+twl6035 (palmas)
+twl6037 (palmas)
+tps65913 (palmas)
+tps65914 (palmas)
+
+Required properties:
+- compatible : Should be from the list
+ ti,twl6035
+ ti,twl6036
+ ti,twl6037
+ ti,tps65913
+ ti,tps65914
+ ti,tps80036
+and also the generic series names
+ ti,palmas
+- interrupt-controller : palmas has its own internal IRQs
+- #interrupt-cells : should be set to 2 for IRQ number and flags
+ The first cell is the IRQ number.
+ The second cell is the flags, encoded as the trigger masks from
+ Documentation/devicetree/bindings/interrupts.txt
+- interrupt-parent : The parent interrupt controller.
+
+Optional properties:
+ ti,mux-padX : set the pad register X (1-2) to the correct muxing for the
+ hardware, if not set will use muxing in OTP.
+
+Example:
+
+palmas {
+ compatible = "ti,twl6035", "ti,palmas";
+ reg = <0x48>
+ interrupt-parent = <&intc>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ ti,mux-pad1 = <0>;
+ ti,mux-pad2 = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic {
+ compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
+ ....
+ };
+}
diff --git a/Documentation/devicetree/bindings/mfd/twl4030-power.txt b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
new file mode 100644
index 000000000000..8e15ec35ac99
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/twl4030-power.txt
@@ -0,0 +1,28 @@
+Texas Instruments TWL family (twl4030) reset and power management module
+
+The power management module inside the TWL family provides several facilities
+to control the power resources, including power scripts. For now, the
+binding only supports the complete shutdown of the system after poweroff.
+
+Required properties:
+- compatible : must be "ti,twl4030-power"
+
+Optional properties:
+- ti,use_poweroff: With this flag, the chip will initiates an ACTIVE-to-OFF or
+ SLEEP-to-OFF transition when the system poweroffs.
+
+Example:
+&i2c1 {
+ clock-frequency = <2600000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+ interrupt-parent = <&intc>;
+
+ twl_power: power {
+ compatible = "ti,twl4030-power";
+ ti,use_poweroff;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 85aada2263d5..458b57f199af 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -28,6 +28,7 @@ Optional properties:
- cap-mmc-highspeed: MMC high-speed timing is supported
- cap-power-off-card: powering off the card is safe
- cap-sdio-irq: enable SDIO IRQ signalling on this interface
+- full-pwr-cycle: full power cycle of the card is supported
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
new file mode 100644
index 000000000000..8a3d91d47b6a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
@@ -0,0 +1,23 @@
+* Rockchip specific extensions to the Synopsis Designware Mobile
+ Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsis dw mshc controller properties described
+by synopsis-dw-mshc.txt and the properties used by the Rockchip specific
+extensions to the Synopsis Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+ - "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following
+
+Example:
+
+ rkdwmmc0@12200000 {
+ compatible = "rockchip,rk2928-dw-mshc";
+ reg = <0x12200000 0x1000>;
+ interrupts = <0 75 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
index 726fd2122a13..cdcebea9c6f5 100644
--- a/Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
@@ -39,6 +39,19 @@ Required Properties:
Optional properties:
+* clocks: from common clock binding: handle to biu and ciu clocks for the
+ bus interface unit clock and the card interface unit clock.
+
+* clock-names: from common clock binding: Shall be "biu" and "ciu".
+ If the biu clock is missing we'll simply skip enabling it. If the
+ ciu clock is missing we'll just assume that the clock is running at
+ clock-frequency. It is an error to omit both the ciu clock and the
+ clock-frequency.
+
+* clock-frequency: should be the frequency (in Hz) of the ciu clock. If this
+ is specified and the ciu clock is specified then we'll try to set the ciu
+ clock to this at probe time.
+
* num-slots: specifies the number of slots supported by the controller.
The number of physical slots actually used could be equal or less than the
value specified by num-slots. If this property is not specified, the value
@@ -51,10 +64,13 @@ Optional properties:
* card-detect-delay: Delay in milli-seconds before detecting card after card
insert event. The default value is 0.
-* supports-highspeed: Enables support for high speed cards (upto 50MHz)
+* supports-highspeed: Enables support for high speed cards (up to 50MHz)
* broken-cd: as documented in mmc core bindings.
+* vmmc-supply: The phandle to the regulator to use for vmmc. If this is
+ specified we'll defer probe until we can find this regulator.
+
Aliases:
- All the MSHC controller nodes should be represented in the aliases node using
@@ -67,6 +83,8 @@ board specific portions as listed below.
dwmmc0@12200000 {
compatible = "snps,dw-mshc";
+ clocks = <&clock 351>, <&clock 132>;
+ clock-names = "biu", "ciu";
reg = <0x12200000 0x1000>;
interrupts = <0 75 0>;
#address-cells = <1>;
@@ -74,11 +92,13 @@ board specific portions as listed below.
};
dwmmc0@12200000 {
+ clock-frequency = <400000000>;
num-slots = <1>;
supports-highspeed;
broken-cd;
fifo-depth = <0x80>;
card-detect-delay = <200>;
+ vmmc-supply = <&buck8>;
slot@0 {
reg = <0>;
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
new file mode 100644
index 000000000000..b90bfcd138ff
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-emac.txt
@@ -0,0 +1,22 @@
+* Allwinner EMAC ethernet controller
+
+Required properties:
+- compatible: should be "allwinner,sun4i-emac".
+- reg: address and length of the register set for the device.
+- interrupts: interrupt for the device
+- phy: A phandle to a phy node defining the PHY address (as the reg
+ property, a single integer).
+- clocks: A phandle to the reference clock for this device
+
+Optional properties:
+- (local-)mac-address: mac address to be used by this driver
+
+Example:
+
+emac: ethernet@01c0b000 {
+ compatible = "allwinner,sun4i-emac";
+ reg = <0x01c0b000 0x1000>;
+ interrupts = <55>;
+ clocks = <&ahb_gates 17>;
+ phy = <&phy0>;
+};
diff --git a/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
new file mode 100644
index 000000000000..00b9f9a3ec1d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/allwinner,sun4i-mdio.txt
@@ -0,0 +1,26 @@
+* Allwinner A10 MDIO Ethernet Controller interface
+
+Required properties:
+- compatible: should be "allwinner,sun4i-mdio".
+- reg: address and length of the register set for the device.
+
+Optional properties:
+- phy-supply: phandle to a regulator if the PHY needs one
+
+Example at the SoC level:
+mdio@01c0b080 {
+ compatible = "allwinner,sun4i-mdio";
+ reg = <0x01c0b080 0x14>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+};
+
+And at the board level:
+
+mdio@01c0b080 {
+ phy-supply = <&reg_emac_3v3>;
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/net/arc_emac.txt b/Documentation/devicetree/bindings/net/arc_emac.txt
new file mode 100644
index 000000000000..bcbc3f009158
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/arc_emac.txt
@@ -0,0 +1,38 @@
+* Synopsys ARC EMAC 10/100 Ethernet driver (EMAC)
+
+Required properties:
+- compatible: Should be "snps,arc-emac"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the EMAC interrupts
+- clock-frequency: CPU frequency. It is needed to calculate and set polling
+period of EMAC.
+- max-speed: Maximum supported data-rate in Mbit/s. In some HW configurations
+bandwidth of external memory controller might be a limiting factor. That's why
+it's required to specify which data-rate is supported on current SoC or FPGA.
+For example if only 10 Mbit/s is supported (10BASE-T) set "10". If 100 Mbit/s is
+supported (100BASE-TX) set "100".
+- phy: PHY device attached to the EMAC via MDIO bus
+
+Child nodes of the driver are the individual PHY devices connected to the
+MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus.
+
+Optional properties:
+- mac-address: 6 bytes, mac address
+
+Examples:
+
+ ethernet@c0fc2000 {
+ compatible = "snps,arc-emac";
+ reg = <0xc0fc2000 0x3c>;
+ interrupts = <6>;
+ mac-address = [ 00 11 22 33 44 55 ];
+ clock-frequency = <80000000>;
+ max-speed = <100>;
+ phy = <&phy0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy0: ethernet-phy@0 {
+ reg = <1>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
index 8ff324eaa889..56d6cc336e1c 100644
--- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -16,6 +16,8 @@ Optional properties:
- clock-frequency : The oscillator frequency driving the flexcan device
+- xceiver-supply: Regulator that powers the CAN transceiver
+
Example:
can@1c000 {
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 4f2ca6b4a182..05d660e4ac64 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -28,6 +28,8 @@ Optional properties:
Slave Properties:
Required properties:
- phy_id : Specifies slave phy id
+- phy-mode : The interface between the SoC and the PHY (a string
+ that of_get_phy_mode() can understand)
- mac-address : Specifies slave MAC address
Optional properties:
@@ -58,11 +60,13 @@ Examples:
cpts_clock_shift = <29>;
cpsw_emac0: slave@0 {
phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii-txid";
/* Filled in by U-Boot */
mac-address = [ 00 00 00 00 00 00 ];
};
cpsw_emac1: slave@1 {
phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii-txid";
/* Filled in by U-Boot */
mac-address = [ 00 00 00 00 00 00 ];
};
@@ -84,11 +88,13 @@ Examples:
cpts_clock_shift = <29>;
cpsw_emac0: slave@0 {
phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii-txid";
/* Filled in by U-Boot */
mac-address = [ 00 00 00 00 00 00 ];
};
cpsw_emac1: slave@1 {
phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii-txid";
/* Filled in by U-Boot */
mac-address = [ 00 00 00 00 00 00 ];
};
diff --git a/Documentation/devicetree/bindings/net/davicom-dm9000.txt b/Documentation/devicetree/bindings/net/davicom-dm9000.txt
new file mode 100644
index 000000000000..2d39c990e641
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/davicom-dm9000.txt
@@ -0,0 +1,26 @@
+Davicom DM9000 Fast Ethernet controller
+
+Required properties:
+- compatible = "davicom,dm9000";
+- reg : physical addresses and sizes of registers, must contain 2 entries:
+ first entry : address register,
+ second entry : data register.
+- interrupt-parent : interrupt controller to which the device is connected
+- interrupts : interrupt specifier specific to interrupt controller
+
+Optional properties:
+- local-mac-address : A bytestring of 6 bytes specifying Ethernet MAC address
+ to use (from firmware or bootloader)
+- davicom,no-eeprom : Configuration EEPROM is not available
+- davicom,ext-phy : Use external PHY
+
+Example:
+
+ ethernet@18000000 {
+ compatible = "davicom,dm9000";
+ reg = <0x18000000 0x2 0x18000004 0x2>;
+ interrupt-parent = <&gpn>;
+ interrupts = <7 4>;
+ local-mac-address = [00 00 de ad be ef];
+ davicom,no-eeprom;
+ };
diff --git a/Documentation/devicetree/bindings/net/marvell-orion-net.txt b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
new file mode 100644
index 000000000000..a73b79f227e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
@@ -0,0 +1,85 @@
+Marvell Orion/Discovery ethernet controller
+=============================================
+
+The Marvell Discovery ethernet controller can be found on Marvell Orion SoCs
+(Kirkwood, Dove, Orion5x, and Discovery Innovation) and as part of Marvell
+Discovery system controller chips (mv64[345]60).
+
+The Discovery ethernet controller is described with two levels of nodes. The
+first level describes the ethernet controller itself and the second level
+describes up to 3 ethernet port nodes within that controller. The reason for
+the multiple levels is that the port registers are interleaved within a single
+set of controller registers. Each port node describes port-specific properties.
+
+Note: The above separation is only true for Discovery system controllers.
+For Orion SoCs we stick to the separation, although there each controller has
+only one port associated. Multiple ports are implemented as multiple single-port
+controllers. As Kirkwood has some issues with proper initialization after reset,
+an extra compatible string is added for it.
+
+* Ethernet controller node
+
+Required controller properties:
+ - #address-cells: shall be 1.
+ - #size-cells: shall be 0.
+ - compatible: shall be one of "marvell,orion-eth", "marvell,kirkwood-eth".
+ - reg: address and length of the controller registers.
+
+Optional controller properties:
+ - clocks: phandle reference to the controller clock.
+ - marvell,tx-checksum-limit: max tx packet size for hardware checksum.
+
+* Ethernet port node
+
+Required port properties:
+ - device_type: shall be "network".
+ - compatible: shall be one of "marvell,orion-eth-port",
+ "marvell,kirkwood-eth-port".
+ - reg: port number relative to ethernet controller, shall be 0, 1, or 2.
+ - interrupts: port interrupt.
+ - local-mac-address: 6 bytes MAC address.
+
+Optional port properties:
+ - marvell,tx-queue-size: size of the transmit ring buffer.
+ - marvell,tx-sram-addr: address of transmit descriptor buffer located in SRAM.
+ - marvell,tx-sram-size: size of transmit descriptor buffer located in SRAM.
+ - marvell,rx-queue-size: size of the receive ring buffer.
+ - marvell,rx-sram-addr: address of receive descriptor buffer located in SRAM.
+ - marvell,rx-sram-size: size of receive descriptor buffer located in SRAM.
+
+and
+
+ - phy-handle: phandle reference to ethernet PHY.
+
+or
+
+ - speed: port speed if no PHY connected.
+ - duplex: port mode if no PHY connected.
+
+* Node example:
+
+mdio-bus {
+ ...
+ ethphy: ethernet-phy@8 {
+ device_type = "ethernet-phy";
+ ...
+ };
+};
+
+eth: ethernet-controller@72000 {
+ compatible = "marvell,orion-eth";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x72000 0x2000>;
+ clocks = <&gate_clk 2>;
+ marvell,tx-checksum-limit = <1600>;
+
+ ethernet@0 {
+ device_type = "network";
+ compatible = "marvell,orion-eth-port";
+ reg = <0>;
+ interrupts = <29>;
+ phy-handle = <&ethphy>;
+ local-mac-address = [00 00 00 00 00 00];
+ };
+};
diff --git a/Documentation/devicetree/bindings/net/micrel-ks8851.txt b/Documentation/devicetree/bindings/net/micrel-ks8851.txt
new file mode 100644
index 000000000000..11ace3c3d805
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/micrel-ks8851.txt
@@ -0,0 +1,9 @@
+Micrel KS8851 Ethernet mac
+
+Required properties:
+- compatible = "micrel,ks8851-ml" of parallel interface
+- reg : 2 physical address and size of registers for data and command
+- interrupts : interrupt connection
+
+Optional properties:
+- local-mac-address : Ethernet mac address to use
diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt
index 060bbf098ef3..261c563b5f06 100644
--- a/Documentation/devicetree/bindings/net/stmmac.txt
+++ b/Documentation/devicetree/bindings/net/stmmac.txt
@@ -12,6 +12,16 @@ Required properties:
property
- phy-mode: String, operation mode of the PHY interface.
Supported values are: "mii", "rmii", "gmii", "rgmii".
+- snps,phy-addr phy address to connect to.
+- snps,reset-gpio gpio number for phy reset.
+- snps,reset-active-low boolean flag to indicate if phy reset is active low.
+- snps,reset-delays-us is triplet of delays
+ The 1st cell is reset pre-delay in micro seconds.
+ The 2nd cell is reset pulse in micro seconds.
+ The 3rd cell is reset post-delay in micro seconds.
+- snps,pbl Programmable Burst Length
+- snps,fixed-burst Program the DMA to use the fixed burst mode
+- snps,mixed-burst Program the DMA to use the mixed burst mode
Optional properties:
- mac-address: 6 bytes, mac address
diff --git a/Documentation/devicetree/bindings/net/via-velocity.txt b/Documentation/devicetree/bindings/net/via-velocity.txt
new file mode 100644
index 000000000000..b3db469b1ad7
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/via-velocity.txt
@@ -0,0 +1,20 @@
+* VIA Velocity 10/100/1000 Network Controller
+
+Required properties:
+- compatible : Should be "via,velocity-vt6110"
+- reg : Address and length of the io space
+- interrupts : Should contain the controller interrupt line
+
+Optional properties:
+- no-eeprom : PCI network cards use an external EEPROM to store data. Embedded
+ devices quite often set this data in uboot and do not provide an eeprom.
+ Specify this option if you have no external eeprom.
+
+Examples:
+
+eth0@d8004000 {
+ compatible = "via,velocity-vt6110";
+ reg = <0xd8004000 0x400>;
+ interrupts = <10>;
+ no-eeprom;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt
new file mode 100644
index 000000000000..ddcdeb697c29
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/fsl,vf610-pinctrl.txt
@@ -0,0 +1,41 @@
+Freescale Vybrid VF610 IOMUX Controller
+
+Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
+and usage.
+
+Required properties:
+- compatible: "fsl,vf610-iomuxc"
+- fsl,pins: two integers array, represents a group of pins mux and config
+ setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is
+ a pin working on a specific function, CONFIG is the pad setting value
+ such as pull-up, speed, ode for this pin. Please refer to Vybrid VF610
+ datasheet for the valid pad config settings.
+
+CONFIG bits definition:
+PAD_CTL_SPEED_LOW (1 << 12)
+PAD_CTL_SPEED_MED (2 << 12)
+PAD_CTL_SPEED_HIGH (3 << 12)
+PAD_CTL_SRE_FAST (1 << 11)
+PAD_CTL_SRE_SLOW (0 << 11)
+PAD_CTL_ODE (1 << 10)
+PAD_CTL_HYS (1 << 9)
+PAD_CTL_DSE_DISABLE (0 << 6)
+PAD_CTL_DSE_150ohm (1 << 6)
+PAD_CTL_DSE_75ohm (2 << 6)
+PAD_CTL_DSE_50ohm (3 << 6)
+PAD_CTL_DSE_37ohm (4 << 6)
+PAD_CTL_DSE_30ohm (5 << 6)
+PAD_CTL_DSE_25ohm (6 << 6)
+PAD_CTL_DSE_20ohm (7 << 6)
+PAD_CTL_PUS_100K_DOWN (0 << 4)
+PAD_CTL_PUS_47K_UP (1 << 4)
+PAD_CTL_PUS_100K_UP (2 << 4)
+PAD_CTL_PUS_22K_UP (3 << 4)
+PAD_CTL_PKE (1 << 3)
+PAD_CTL_PUE (1 << 2)
+PAD_CTL_OBE_ENABLE (1 << 1)
+PAD_CTL_IBE_ENABLE (1 << 0)
+PAD_CTL_OBE_IBE_ENABLE (3 << 0)
+
+Please refer to vf610-pinfunc.h in device tree source folder
+for all available PIN_FUNC_ID for Vybrid VF610.
diff --git a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt
new file mode 100644
index 000000000000..a186181c402b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pdc-pinctrl.txt
@@ -0,0 +1,127 @@
+ImgTec TZ1090 PDC pin controller
+
+Required properties:
+- compatible: "img,tz1090-pdc-pinctrl"
+- reg: Should contain the register physical address and length of the
+ SOC_GPIO_CONTROL registers in the PDC register region.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+TZ1090-PDC's pin configuration nodes act as a container for an abitrary number
+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. For this reason, even seemingly boolean
+values are actually tristates in this binding: unspecified, off, or on.
+Unspecified is represented as an absent property, and off/on are represented as
+integer values 0 and 1.
+
+Required subnode-properties:
+- tz1090,pins : An array of strings. Each string contains the name of a pin or
+ group. Valid values for these names are listed below.
+
+Optional subnode-properties:
+- tz1090,function: A string containing the name of the function to mux to the
+ pin or group. Valid values for function names are listed below, including
+ which pingroups can be muxed to them.
+- supported generic pinconfig properties (for further details see
+ Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt):
+ - bias-disable
+ - bias-high-impedance
+ - bias-bus-hold
+ - bias-pull-up
+ - bias-pull-down
+ - input-schmitt-enable
+ - input-schmitt-disable
+ - drive-strength: Integer, control drive strength of pins in mA.
+ 2: 2mA
+ 4: 4mA
+ 8: 8mA
+ 12: 12mA
+ - low-power-enable: Flag, power-on-start weak pull-down for invalid power.
+ - low-power-disable: Flag, power-on-start weak pull-down disabled.
+
+Note that many of these properties are only valid for certain specific pins
+or groups. See the TZ1090 TRM for complete details regarding which groups
+support which functionality. The Linux pinctrl driver may also be a useful
+reference.
+
+Valid values for pin and group names are:
+
+ pins:
+
+ These all support bias-high-impediance, bias-pull-up, bias-pull-down, and
+ bias-bus-hold (which can also be provided to any of the groups below to set
+ it for all gpio pins in that group).
+
+ gpio0, gpio1, sys_wake0, sys_wake1, sys_wake2, ir_data, ext_power.
+
+ mux groups:
+
+ These all support function.
+
+ gpio0
+ pins: gpio0.
+ function: ir_mod_stable_out.
+ gpio1
+ pins: gpio1.
+ function: ir_mod_power_out.
+
+ drive groups:
+
+ These support input-schmitt-enable, input-schmitt-disable,
+ drive-strength, low-power-enable, and low-power-disable.
+
+ pdc
+ pins: gpio0, gpio1, sys_wake0, sys_wake1, sys_wake2, ir_data,
+ ext_power.
+
+Example:
+
+ pinctrl_pdc: pinctrl@02006500 {
+ #gpio-range-cells = <3>;
+ compatible = "img,tz1090-pdc-pinctrl";
+ reg = <0x02006500 0x100>;
+ };
+
+Example board file extracts:
+
+ &pinctrl_pdc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&syswake_default>;
+
+ syswake_default: syswakes {
+ syswake_cfg {
+ tz1090,pins = "sys_wake0",
+ "sys_wake1",
+ "sys_wake2";
+ pull-up;
+ };
+ };
+ irmod_default: irmod {
+ gpio0_cfg {
+ tz1090,pins = "gpio0";
+ tz1090,function = "ir_mod_stable_out";
+ };
+ gpio1_cfg {
+ tz1090,pins = "gpio1";
+ tz1090,function = "ir_mod_power_out";
+ };
+ };
+ };
+
+ ir: ir@02006200 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&irmod_default>;
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
new file mode 100644
index 000000000000..4b27c99f7f9d
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
@@ -0,0 +1,227 @@
+ImgTec TZ1090 pin controller
+
+Required properties:
+- compatible: "img,tz1090-pinctrl"
+- reg: Should contain the register physical address and length of the pad
+ configuration registers (CR_PADS_* and CR_IF_CTL0).
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+TZ1090's pin configuration nodes act as a container for an abitrary number of
+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. For this reason, even seemingly boolean
+values are actually tristates in this binding: unspecified, off, or on.
+Unspecified is represented as an absent property, and off/on are represented as
+integer values 0 and 1.
+
+Required subnode-properties:
+- tz1090,pins : An array of strings. Each string contains the name of a pin or
+ group. Valid values for these names are listed below.
+
+Optional subnode-properties:
+- tz1090,function: A string containing the name of the function to mux to the
+ pin or group. Valid values for function names are listed below, including
+ which pingroups can be muxed to them.
+- supported generic pinconfig properties (for further details see
+ Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt):
+ - bias-disable
+ - bias-high-impedance
+ - bias-bus-hold
+ - bias-pull-up
+ - bias-pull-down
+ - input-schmitt-enable
+ - input-schmitt-disable
+ - drive-strength: Integer, control drive strength of pins in mA.
+ 2: 2mA
+ 4: 4mA
+ 8: 8mA
+ 12: 12mA
+
+
+Note that many of these properties are only valid for certain specific pins
+or groups. See the TZ1090 TRM for complete details regarding which groups
+support which functionality. The Linux pinctrl driver may also be a useful
+reference.
+
+Valid values for pin and group names are:
+
+ gpio pins:
+
+ These all support bias-high-impediance, bias-pull-up, bias-pull-down, and
+ bias-bus-hold (which can also be provided to any of the groups below to set
+ it for all pins in that group).
+
+ They also all support the some form of muxing. Any pins which are contained
+ in one of the mux groups (see below) can be muxed only to the functions
+ supported by the mux group. All other pins can be muxed to the "perip"
+ function which which enables them with their intended peripheral.
+
+ Different pins in the same mux group cannot be muxed to different functions,
+ however it is possible to mux only a subset of the pins in a mux group to a
+ particular function and leave the remaining pins unmuxed. This is useful if
+ the board connects certain pins in a group to other devices to be controlled
+ by GPIO, and you don't want the usual peripheral to have any control of the
+ pin.
+
+ ant_sel0, ant_sel1, gain0, gain1, gain2, gain3, gain4, gain5, gain6, gain7,
+ i2s_bclk_out, i2s_din, i2s_dout0, i2s_dout1, i2s_dout2, i2s_lrclk_out,
+ i2s_mclk, pa_on, pdm_a, pdm_b, pdm_c, pdm_d, pll_on, rx_hp, rx_on,
+ scb0_sclk, scb0_sdat, scb1_sclk, scb1_sdat, scb2_sclk, scb2_sdat, sdh_cd,
+ sdh_clk_in, sdh_wp, sdio_clk, sdio_cmd, sdio_d0, sdio_d1, sdio_d2, sdio_d3,
+ spi0_cs0, spi0_cs1, spi0_cs2, spi0_din, spi0_dout, spi0_mclk, spi1_cs0,
+ spi1_cs1, spi1_cs2, spi1_din, spi1_dout, spi1_mclk, tft_blank_ls, tft_blue0,
+ tft_blue1, tft_blue2, tft_blue3, tft_blue4, tft_blue5, tft_blue6, tft_blue7,
+ tft_green0, tft_green1, tft_green2, tft_green3, tft_green4, tft_green5,
+ tft_green6, tft_green7, tft_hsync_nr, tft_panelclk, tft_pwrsave, tft_red0,
+ tft_red1, tft_red2, tft_red3, tft_red4, tft_red5, tft_red6, tft_red7,
+ tft_vd12acb, tft_vdden_gd, tft_vsync_ns, tx_on, uart0_cts, uart0_rts,
+ uart0_rxd, uart0_txd, uart1_rxd, uart1_txd.
+
+ bias-high-impediance: supported.
+ bias-pull-up: supported.
+ bias-pull-down: supported.
+ bias-bus-hold: supported.
+ function: perip or those supported by pin's mux group.
+
+ other pins:
+
+ These other pins are part of various pin groups below, but can't be
+ controlled as GPIOs. They do however support bias-high-impediance,
+ bias-pull-up, bias-pull-down, and bias-bus-hold (which can also be provided
+ to any of the groups below to set it for all pins in that group).
+
+ clk_out0, clk_out1, tck, tdi, tdo, tms, trst.
+
+ bias-high-impediance: supported.
+ bias-pull-up: supported.
+ bias-pull-down: supported.
+ bias-bus-hold: supported.
+
+ mux groups:
+
+ These all support function, and some support drive configs.
+
+ afe
+ pins: tx_on, rx_on, pll_on, pa_on, rx_hp, ant_sel0,
+ ant_sel1, gain0, gain1, gain2, gain3, gain4,
+ gain5, gain6, gain7.
+ function: afe, ts_out_0.
+ input-schmitt-enable: supported.
+ input-schmitt-disable: supported.
+ drive-strength: supported.
+ pdm_d
+ pins: pdm_d.
+ function: pdm_dac, usb_vbus.
+ sdh
+ pins: sdh_cd, sdh_wp, sdh_clk_in.
+ function: sdh, sdio.
+ sdio
+ pins: sdio_clk, sdio_cmd, sdio_d0, sdio_d1, sdio_d2,
+ sdio_d3.
+ function: sdio, sdh.
+ spi1_cs2
+ pins: spi1_cs2.
+ function: spi1_cs2, usb_vbus.
+ tft
+ pins: tft_red0, tft_red1, tft_red2, tft_red3,
+ tft_red4, tft_red5, tft_red6, tft_red7,
+ tft_green0, tft_green1, tft_green2, tft_green3,
+ tft_green4, tft_green5, tft_green6, tft_green7,
+ tft_blue0, tft_blue1, tft_blue2, tft_blue3,
+ tft_blue4, tft_blue5, tft_blue6, tft_blue7,
+ tft_vdden_gd, tft_panelclk, tft_blank_ls,
+ tft_vsync_ns, tft_hsync_nr, tft_vd12acb,
+ tft_pwrsave.
+ function: tft, ext_dac, not_iqadc_stb, iqdac_stb, ts_out_1,
+ lcd_trace, phy_ringosc.
+ input-schmitt-enable: supported.
+ input-schmitt-disable: supported.
+ drive-strength: supported.
+
+ drive groups:
+
+ These all support input-schmitt-enable, input-schmitt-disable,
+ and drive-strength.
+
+ jtag
+ pins: tck, trst, tdi, tdo, tms.
+ scb1
+ pins: scb1_sdat, scb1_sclk.
+ scb2
+ pins: scb2_sdat, scb2_sclk.
+ spi0
+ pins: spi0_mclk, spi0_cs0, spi0_cs1, spi0_cs2, spi0_dout, spi0_din.
+ spi1
+ pins: spi1_mclk, spi1_cs0, spi1_cs1, spi1_cs2, spi1_dout, spi1_din.
+ uart
+ pins: uart0_txd, uart0_rxd, uart0_rts, uart0_cts,
+ uart1_txd, uart1_rxd.
+ drive_i2s
+ pins: clk_out1, i2s_din, i2s_dout0, i2s_dout1, i2s_dout2,
+ i2s_lrclk_out, i2s_bclk_out, i2s_mclk.
+ drive_pdm
+ pins: clk_out0, pdm_b, pdm_a.
+ drive_scb0
+ pins: scb0_sclk, scb0_sdat, pdm_d, pdm_c.
+ drive_sdio
+ pins: sdio_clk, sdio_cmd, sdio_d0, sdio_d1, sdio_d2, sdio_d3,
+ sdh_wp, sdh_cd, sdh_clk_in.
+
+ convenience groups:
+
+ These are just convenient groupings of pins and don't support any drive
+ configs.
+
+ uart0
+ pins: uart0_cts, uart0_rts, uart0_rxd, uart0_txd.
+ uart1
+ pins: uart1_rxd, uart1_txd.
+ scb0
+ pins: scb0_sclk, scb0_sdat.
+ i2s
+ pins: i2s_bclk_out, i2s_din, i2s_dout0, i2s_dout1, i2s_dout2,
+ i2s_lrclk_out, i2s_mclk.
+
+Example:
+
+ pinctrl: pinctrl@02005800 {
+ #gpio-range-cells = <3>;
+ compatible = "img,tz1090-pinctrl";
+ reg = <0x02005800 0xe4>;
+ };
+
+Example board file extract:
+
+ &pinctrl {
+ uart0_default: uart0 {
+ uart0_cfg {
+ tz1090,pins = "uart0_rxd",
+ "uart0_txd";
+ tz1090,function = "perip";
+ };
+ };
+ tft_default: tft {
+ tft_cfg {
+ tz1090,pins = "tft";
+ tz1090,function = "tft";
+ };
+ };
+ };
+
+ uart@02004b00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_default>;
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
index a648aaad6110..50ec3512a292 100644
--- a/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,dove-pinctrl.txt
@@ -10,29 +10,31 @@ Required properties:
Available mpp pins/groups and functions:
Note: brackets (x) are not part of the mpp name for marvell,function and given
only for more detailed description in this document.
+Note: pmu* also allows for Power Management functions listed below
name pins functions
================================================================================
-mpp0 0 gpio, pmu, uart2(rts), sdio0(cd), lcd0(pwm)
-mpp1 1 gpio, pmu, uart2(cts), sdio0(wp), lcd1(pwm)
+mpp0 0 gpio, pmu, uart2(rts), sdio0(cd), lcd0(pwm), pmu*
+mpp1 1 gpio, pmu, uart2(cts), sdio0(wp), lcd1(pwm), pmu*
mpp2 2 gpio, pmu, uart2(txd), sdio0(buspwr), sata(prsnt),
- uart1(rts)
+ uart1(rts), pmu*
mpp3 3 gpio, pmu, uart2(rxd), sdio0(ledctrl), sata(act),
- uart1(cts), lcd-spi(cs1)
-mpp4 4 gpio, pmu, uart3(rts), sdio1(cd), spi1(miso)
-mpp5 5 gpio, pmu, uart3(cts), sdio1(wp), spi1(cs)
-mpp6 6 gpio, pmu, uart3(txd), sdio1(buspwr), spi1(mosi)
-mpp7 7 gpio, pmu, uart3(rxd), sdio1(ledctrl), spi1(sck)
-mpp8 8 gpio, pmu, watchdog(rstout)
-mpp9 9 gpio, pmu, pex1(clkreq)
-mpp10 10 gpio, pmu, ssp(sclk)
+ uart1(cts), lcd-spi(cs1), pmu*
+mpp4 4 gpio, pmu, uart3(rts), sdio1(cd), spi1(miso), pmu*
+mpp5 5 gpio, pmu, uart3(cts), sdio1(wp), spi1(cs), pmu*
+mpp6 6 gpio, pmu, uart3(txd), sdio1(buspwr), spi1(mosi), pmu*
+mpp7 7 gpio, pmu, uart3(rxd), sdio1(ledctrl), spi1(sck), pmu*
+mpp8 8 gpio, pmu, watchdog(rstout), pmu*
+mpp9 9 gpio, pmu, pex1(clkreq), pmu*
+mpp10 10 gpio, pmu, ssp(sclk), pmu*
mpp11 11 gpio, pmu, sata(prsnt), sata-1(act), sdio0(ledctrl),
- sdio1(ledctrl), pex0(clkreq)
-mpp12 12 gpio, pmu, uart2(rts), audio0(extclk), sdio1(cd), sata(act)
+ sdio1(ledctrl), pex0(clkreq), pmu*
+mpp12 12 gpio, pmu, uart2(rts), audio0(extclk), sdio1(cd),
+ sata(act), pmu*
mpp13 13 gpio, pmu, uart2(cts), audio1(extclk), sdio1(wp),
- ssp(extclk)
-mpp14 14 gpio, pmu, uart2(txd), sdio1(buspwr), ssp(rxd)
-mpp15 15 gpio, pmu, uart2(rxd), sdio1(ledctrl), ssp(sfrm)
+ ssp(extclk), pmu*
+mpp14 14 gpio, pmu, uart2(txd), sdio1(buspwr), ssp(rxd), pmu*
+mpp15 15 gpio, pmu, uart2(rxd), sdio1(ledctrl), ssp(sfrm), pmu*
mpp16 16 gpio, uart3(rts), sdio0(cd), ac97(sdi1), lcd-spi(cs1)
mpp17 17 gpio, uart3(cts), sdio0(wp), ac97(sdi2), twsi(sda),
ac97-1(sysclko)
@@ -57,6 +59,21 @@ mpp_nand 64-71 gpo, nand
audio0 - i2s, ac97
twsi - none, opt1, opt2, opt3
+Power Management functions (pmu*):
+pmu-nc Pin not driven by any PM function
+pmu-low Pin driven low (0)
+pmu-high Pin driven high (1)
+pmic(sdi) Pin is used for PMIC SDI
+cpu-pwr-down Pin is used for CPU_PWRDWN
+standby-pwr-down Pin is used for STBY_PWRDWN
+core-pwr-good Pin is used for CORE_PWR_GOOD (Pins 0-7 only)
+cpu-pwr-good Pin is used for CPU_PWR_GOOD (Pins 8-15 only)
+bat-fault Pin is used for BATTERY_FAULT
+ext0-wakeup Pin is used for EXT0_WU
+ext1-wakeup Pin is used for EXT0_WU
+ext2-wakeup Pin is used for EXT0_WU
+pmu-blink Pin is used for blink function
+
Notes:
* group "mpp_audio1" allows the following functions and gpio pins:
- gpio : gpio on pins 52-57
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
index c95ea8278f87..aeb3c995cc04 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -126,3 +126,51 @@ device; they may be grandchildren, for example. Whether this is legal, and
whether there is any interaction between the child and intermediate parent
nodes, is again defined entirely by the binding for the individual pin
controller device.
+
+== Using generic pinconfig options ==
+
+Generic pinconfig parameters can be used by defining a separate node containing
+the applicable parameters (and optional values), like:
+
+pcfg_pull_up: pcfg_pull_up {
+ bias-pull-up;
+ drive-strength = <20>;
+};
+
+This node should then be referenced in the appropriate pinctrl node as a phandle
+and parsed in the driver using the pinconf_generic_parse_dt_config function.
+
+Supported configuration parameters are:
+
+bias-disable - disable any pin bias
+bias-high-impedance - high impedance mode ("third-state", "floating")
+bias-bus-hold - latch weakly
+bias-pull-up - pull up the pin
+bias-pull-down - pull down the pin
+bias-pull-pin-default - use pin-default pull state
+drive-push-pull - drive actively high and low
+drive-open-drain - drive with open drain
+drive-open-source - drive with open source
+drive-strength - sink or source at most X mA
+input-schmitt-enable - enable schmitt-trigger mode
+input-schmitt-disable - disable schmitt-trigger mode
+input-debounce - debounce mode with debound time X
+low-power-enable - enable low power mode
+low-power-disable - disable low power mode
+output-low - set the pin to output mode with low level
+output-high - set the pin to output mode with high level
+
+Arguments for parameters:
+
+- bias-pull-up, -down and -pin-default take as optional argument on hardware
+ supporting it the pull strength in Ohm. bias-disable will disable the pull.
+
+- drive-strength takes as argument the target strength in mA.
+
+- input-debounce takes the debounce time in usec as argument
+ or 0 to disable debouncing
+
+All parameters not listed here, do not take an argument.
+
+More in-depth documentation on these parameters can be found in
+<include/linux/pinctrl/pinconfig-generic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index 08f0c3d01575..5a02e30dd262 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -18,7 +18,8 @@ Optional properties:
pin functions is ignored
- pinctrl-single,bit-per-mux : boolean to indicate that one register controls
- more than one pin
+ more than one pin, for which "pinctrl-single,function-mask" property specifies
+ position mask of pin.
- pinctrl-single,drive-strength : array of value that are used to configure
drive strength in the pinmux register. They're value of drive strength
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
new file mode 100644
index 000000000000..05bf82a07dfd
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-st.txt
@@ -0,0 +1,110 @@
+*ST pin controller.
+
+Each multi-function pin is controlled, driven and routed through the
+PIO multiplexing block. Each pin supports GPIO functionality (ALT0)
+and multiple alternate functions(ALT1 - ALTx) that directly connect
+the pin to different hardware blocks.
+
+When a pin is in GPIO mode, Output Enable (OE), Open Drain(OD), and
+Pull Up (PU) are driven by the related PIO block.
+
+ST pinctrl driver controls PIO multiplexing block and also interacts with
+gpio driver to configure a pin.
+
+Required properties: (PIO multiplexing block)
+- compatible : should be "st,<SOC>-<pio-block>-pinctrl"
+ like st,stih415-sbc-pinctrl, st,stih415-front-pinctrl and so on.
+- gpio-controller : Indicates this device is a GPIO controller
+- #gpio-cells : Should be one. The first cell is the pin number.
+- st,retime-pin-mask : Should be mask to specify which pins can be retimed.
+ If the property is not present, it is assumed that all the pins in the
+ bank are capable of retiming. Retiming is mainly used to improve the
+ IO timing margins of external synchronous interfaces.
+- st,bank-name : Should be a name string for this bank as
+ specified in datasheet.
+- st,syscfg : Should be a phandle of the syscfg node.
+
+Example:
+ pin-controller-sbc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stih415-sbc-pinctrl";
+ st,syscfg = <&syscfg_sbc>;
+ ranges = <0 0xfe610000 0x5000>;
+ PIO0: gpio@fe610000 {
+ gpio-controller;
+ #gpio-cells = <1>;
+ reg = <0 0x100>;
+ st,bank-name = "PIO0";
+ };
+ ...
+ pin-functions nodes follow...
+ };
+
+
+Contents of function subnode node:
+----------------------
+Required properties for pin configuration node:
+- st,pins : Child node with list of pins with configuration.
+
+Below is the format of how each pin conf should look like.
+
+<bank offset mux mode rt_type rt_delay rt_clk>
+
+Every PIO is represented with 4-7 parameters depending on retime configuration.
+Each parameter is explained as below.
+
+-bank : Should be bank phandle to which this PIO belongs.
+-offset : Offset in the PIO bank.
+-mux : Should be alternate function number associated this pin.
+ Use same numbers from datasheet.
+-mode :pin configuration is selected from one of the below values.
+ IN
+ IN_PU
+ OUT
+ BIDIR
+ BIDIR_PU
+
+-rt_type Retiming Configuration for the pin.
+ Possible retime configuration are:
+
+ ------- -------------
+ value args
+ ------- -------------
+ NICLK <delay> <clk>
+ ICLK_IO <delay> <clk>
+ BYPASS <delay>
+ DE_IO <delay> <clk>
+ SE_ICLK_IO <delay> <clk>
+ SE_NICLK_IO <delay> <clk>
+
+- delay is retime delay in pico seconds as mentioned in data sheet.
+
+- rt_clk :clk to be use for retime.
+ Possible values are:
+ CLK_A
+ CLK_B
+ CLK_C
+ CLK_D
+
+Example of mmcclk pin which is a bi-direction pull pu with retime config
+as non inverted clock retimed with CLK_B and delay of 0 pico seconds:
+
+pin-controller {
+ ...
+ mmc0 {
+ pinctrl_mmc: mmc {
+ st,pins {
+ mmcclk = <&PIO13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>;
+ ...
+ };
+ };
+ ...
+ };
+};
+
+sdhci0:sdhci@fe810000{
+ ...
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
new file mode 100644
index 000000000000..d5dac7b843a9
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt
@@ -0,0 +1,153 @@
+* Renesas Pin Function Controller (GPIO and Pin Mux/Config)
+
+The Pin Function Controller (PFC) is a Pin Mux/Config controller. On SH7372,
+SH73A0, R8A73A4 and R8A7740 it also acts as a GPIO controller.
+
+
+Pin Control
+-----------
+
+Required Properties:
+
+ - compatible: should be one of the following.
+ - "renesas,pfc-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible pin-controller.
+ - "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller.
+ - "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-sh7372": for SH7372 (SH-Mobile AP4) 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
+ controller hardware module.
+
+Optional properties:
+
+ - #gpio-range-cells: Mandatory when the PFC doesn't handle GPIO, forbidden
+ otherwise. Should be 3.
+
+The PFC node also acts as a container for pin configuration nodes. Please refer
+to pinctrl-bindings.txt in this directory for the definition of the term "pin
+configuration node" and for the common pinctrl bindings used by client devices.
+
+Each pin configuration node represents a desired configuration for a pin, a
+pin group, or a list of pins or pin groups. The configuration can include the
+function to select on those pin(s) and pin configuration parameters (such as
+pull-up and pull-down).
+
+Pin configuration nodes contain pin configuration properties, either directly
+or grouped in child subnodes. Both pin muxing and configuration parameters can
+be grouped in that way and referenced as a single pin configuration node by
+client devices.
+
+A configuration node or subnode must reference at least one pin (through the
+pins or pin groups properties) and contain at least a function or one
+configuration parameter. When the function is present only pin groups can be
+used to reference pins.
+
+All pin configuration nodes and subnodes names are ignored. All of those nodes
+are parsed through phandles and processed purely based on their content.
+
+Pin Configuration Node Properties:
+
+- renesas,pins : An array of strings, each string containing the name of a pin.
+- renesas,groups : An array of strings, each string containing the name of a pin
+ group.
+
+- renesas,function: A string containing the name of the function to mux to the
+ pin group(s) specified by the renesas,groups property
+
+ Valid values for pin, group and function names can be found in the group and
+ function arrays of the PFC data file corresponding to the SoC
+ (drivers/pinctrl/sh-pfc/pfc-*.c)
+
+The pin configuration parameters use the generic pinconf bindings defined in
+pinctrl-bindings.txt in this directory. The supported parameters are
+bias-disable, bias-pull-up and bias-pull-down.
+
+
+GPIO
+----
+
+On SH7372, SH73A0, R8A73A4 and R8A7740 the PFC node is also a GPIO controller
+node.
+
+Required Properties:
+
+ - gpio-controller: Marks the device node as a gpio controller.
+
+ - #gpio-cells: Should be 2. The first cell is the GPIO number and the second
+ cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
+ GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
+
+The syntax of the gpio specifier used by client nodes should be the following
+with values derived from the SoC user manual.
+
+ <[phandle of the gpio controller node]
+ [pin number within the gpio controller]
+ [flags]>
+
+On other mach-shmobile platforms GPIO is handled by the gpio-rcar driver.
+Please refer to Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
+for documentation of the GPIO device tree bindings on those platforms.
+
+
+Examples
+--------
+
+Example 1: SH73A0 (SH-Mobile AG5) pin controller node
+
+ pfc: pfc@e6050000 {
+ compatible = "renesas,pfc-sh73a0";
+ reg = <0xe6050000 0x8000>,
+ <0xe605801c 0x1c>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+Example 2: A GPIO LED node that references a GPIO
+
+ #include <dt-bindings/gpio/gpio.h>
+
+ leds {
+ compatible = "gpio-leds";
+ led1 {
+ gpios = <&pfc 20 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps
+ for the MMCIF and SCIFA4 devices
+
+ &pfc {
+ pinctrl-0 = <&scifa4_pins>;
+ pinctrl-names = "default";
+
+ mmcif_pins: mmcif {
+ mux {
+ renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0";
+ renesas,function = "mmc0";
+ };
+ cfg {
+ renesas,groups = "mmc0_data8_0";
+ renesas,pins = "PORT279";
+ bias-pull-up;
+ };
+ };
+
+ scifa4_pins: scifa4 {
+ renesas,groups = "scifa4_data", "scifa4_ctrl";
+ renesas,function = "scifa4";
+ };
+ };
+
+Example 4: KZM-A9-GT (SH-Mobile AG5) default pin state for the MMCIF device
+
+ &mmcif {
+ pinctrl-0 = <&mmcif_pins>;
+ pinctrl-names = "default";
+
+ bus-width = <8>;
+ vmmc-supply = <&reg_1p8v>;
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
new file mode 100644
index 000000000000..b0fb1018d7ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
@@ -0,0 +1,97 @@
+* Rockchip Pinmux Controller
+
+The Rockchip Pinmux Controller, enables the IC
+to share one PAD to several functional blocks. The sharing is done by
+multiplexing the PAD input/output signals. For each PAD there are up to
+4 muxing options with option 0 being the use as a GPIO.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The Rockchip pin configuration node is a node of a group of pins which can be
+used for a specific device or function. This node represents both mux and
+config of the pins in that group. The 'pins' selects the function mode(also
+named pin mode) this pin can work on and the 'config' configures various pad
+settings such as pull-up, etc.
+
+The pins are grouped into up to 5 individual pin banks which need to be
+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"
+
+Required properties for gpio sub nodes:
+ - compatible: "rockchip,gpio-bank"
+ - reg: register of the gpio bank (different than the iomux registerset)
+ - interrupts: base interrupt of the gpio bank in the interrupt controller
+ - clocks: clock that drives this bank
+ - gpio-controller: identifies the node as a gpio controller and pin bank.
+ - #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
+ binding is used, the amount of cells must be specified as 2. See generic
+ GPIO binding documentation for description of particular cells.
+ - interrupt-controller: identifies the controller node as interrupt-parent.
+ - #interrupt-cells: the value of this property should be 2 and the interrupt
+ cells should use the standard two-cell scheme described in
+ bindings/interrupt-controller/interrupts.txt
+
+Required properties for pin configuration node:
+ - rockchip,pins: 3 integers array, represents a group of pins mux and config
+ setting. The format is rockchip,pins = <PIN_BANK PIN_BANK_IDX MUX &phandle>.
+ The MUX 0 means gpio and MUX 1 to 3 mean the specific device function.
+ The phandle of a node containing the generic pinconfig options
+ to use, as described in pinctrl-bindings.txt in this directory.
+
+Examples:
+
+#include <dt-bindings/pinctrl/rockchip.h>
+
+...
+
+pinctrl@20008000 {
+ compatible = "rockchip,rk3066a-pinctrl";
+ reg = <0x20008000 0x150>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio0: gpio0@20034000 {
+ compatible = "rockchip,gpio-bank";
+ reg = <0x20034000 0x100>;
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk_gates8 9>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ ...
+
+ pcfg_pull_default: pcfg_pull_default {
+ bias-pull-pin-default
+ };
+
+ uart2 {
+ uart2_xfer: uart2-xfer {
+ rockchip,pins = <RK_GPIO1 8 1 &pcfg_pull_default>,
+ <RK_GPIO1 9 1 &pcfg_pull_default>;
+ };
+ };
+};
+
+uart2: serial@20064000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x20064000 0x400>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <1>;
+ clocks = <&mux_uart2>;
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_xfer>;
+};
diff --git a/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt
new file mode 100644
index 000000000000..e3865e136067
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt
@@ -0,0 +1,352 @@
+ST Ericsson abx500 pinmux controller
+
+Required properties:
+- compatible: "stericsson,ab8500-gpio", "stericsson,ab8540-gpio",
+ "stericsson,ab8505-gpio", "stericsson,ab9540-gpio",
+
+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".
+
+ST Ericsson'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 input, output, pull up, pull down...
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Required subnode-properties:
+- ste,pins : An array of strings. Each string contains the name of a pin or
+ group.
+
+Optional subnode-properties:
+- ste,function: A string containing the name of the function to mux to the
+ pin or group.
+
+- generic pin configuration option to use. Example :
+
+ default_cfg {
+ ste,pins = "GPIO1";
+ bias-disable;
+ };
+
+- ste,config: Handle of pin configuration node containing the generic
+ pinconfig options to use, as described in pinctrl-bindings.txt in
+ this directory. Example :
+
+ pcfg_bias_disable: pcfg_bias_disable {
+ bias-disable;
+ };
+
+ default_cfg {
+ ste,pins = "GPIO1";
+ ste.config = <&pcfg_bias_disable>;
+ };
+
+Example board file extract:
+
+&pinctrl_abx500 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sysclkreq2_default_mode>, <&sysclkreq3_default_mode>, <&gpio3_default_mode>, <&sysclkreq6_default_mode>, <&pwmout1_default_mode>, <&pwmout2_default_mode>, <&pwmout3_default_mode>, <&adi1_default_mode>, <&dmic12_default_mode>, <&dmic34_default_mode>, <&dmic56_default_mode>, <&sysclkreq5_default_mode>, <&batremn_default_mode>, <&service_default_mode>, <&pwrctrl0_default_mode>, <&pwrctrl1_default_mode>, <&pwmextvibra1_default_mode>, <&pwmextvibra2_default_mode>, <&gpio51_default_mode>, <&gpio52_default_mode>, <&gpio53_default_mode>, <&gpio54_default_mode>, <&pdmclkdat_default_mode>;
+
+ sysclkreq2 {
+ sysclkreq2_default_mode: sysclkreq2_default {
+ default_mux {
+ ste,function = "sysclkreq";
+ ste,pins = "sysclkreq2_d_1";
+ };
+ default_cfg {
+ ste,pins = "GPIO1";
+ bias-disable;
+ };
+ };
+ };
+ sysclkreq3 {
+ sysclkreq3_default_mode: sysclkreq3_default {
+ default_mux {
+ ste,function = "sysclkreq";
+ ste,pins = "sysclkreq3_d_1";
+ };
+ default_cfg {
+ ste,pins = "GPIO2";
+ output-low;
+ };
+ };
+ };
+ gpio3 {
+ gpio3_default_mode: gpio3_default {
+ default_mux {
+ ste,function = "gpio";
+ ste,pins = "gpio3_a_1";
+ };
+ default_cfg {
+ ste,pins = "GPIO3";
+ output-low;
+ };
+ };
+ };
+ sysclkreq6 {
+ sysclkreq6_default_mode: sysclkreq6_default {
+ default_mux {
+ ste,function = "sysclkreq";
+ ste,pins = "sysclkreq6_d_1";
+ };
+ default_cfg {
+ ste,pins = "GPIO4";
+ bias-disable;
+ };
+ };
+ };
+ pwmout1 {
+ pwmout1_default_mode: pwmout1_default {
+ default_mux {
+ ste,function = "pwmout";
+ ste,pins = "pwmout1_d_1";
+ };
+ default_cfg {
+ ste,pins = "GPIO14";
+ output-low;
+ };
+ };
+ };
+ pwmout2 {
+ pwmout2_default_mode: pwmout2_default {
+ pwmout2_default_mux {
+ ste,function = "pwmout";
+ ste,pins = "pwmout2_d_1";
+ };
+ pwmout2_default_cfg {
+ ste,pins = "GPIO15";
+ output-low;
+ };
+ };
+ };
+ pwmout3 {
+ pwmout3_default_mode: pwmout3_default {
+ pwmout3_default_mux {
+ ste,function = "pwmout";
+ ste,pins = "pwmout3_d_1";
+ };
+ pwmout3_default_cfg {
+ ste,pins = "GPIO16";
+ output-low;
+ };
+ };
+ };
+ adi1 {
+
+ adi1_default_mode: adi1_default {
+ adi1_default_mux {
+ ste,function = "adi1";
+ ste,pins = "adi1_d_1";
+ };
+ adi1_default_cfg1 {
+ ste,pins = "GPIO17","GPIO19","GPIO20";
+ bias-disable;
+ };
+ adi1_default_cfg2 {
+ ste,pins = "GPIO18";
+ output-low;
+ };
+ };
+ };
+ dmic12 {
+ dmic12_default_mode: dmic12_default {
+ dmic12_default_mux {
+ ste,function = "dmic";
+ ste,pins = "dmic12_d_1";
+ };
+ dmic12_default_cfg1 {
+ ste,pins = "GPIO27";
+ output-low;
+ };
+ dmic12_default_cfg2 {
+ ste,pins = "GPIO28";
+ bias-disable;
+ };
+ };
+ };
+ dmic34 {
+ dmic34_default_mode: dmic34_default {
+ dmic34_default_mux {
+ ste,function = "dmic";
+ ste,pins = "dmic34_d_1";
+ };
+ dmic34_default_cfg1 {
+ ste,pins = "GPIO29";
+ output-low;
+ };
+ dmic34_default_cfg2 {
+ ste,pins = "GPIO30";
+ bias-disable;{
+
+ };
+ };
+ };
+ dmic56 {
+ dmic56_default_mode: dmic56_default {
+ dmic56_default_mux {
+ ste,function = "dmic";
+ ste,pins = "dmic56_d_1";
+ };
+ dmic56_default_cfg1 {
+ ste,pins = "GPIO31";
+ output-low;
+ };
+ dmic56_default_cfg2 {
+ ste,pins = "GPIO32";
+ bias-disable;
+ };
+ };
+ };
+ sysclkreq5 {
+ sysclkreq5_default_mode: sysclkreq5_default {
+ sysclkreq5_default_mux {
+ ste,function = "sysclkreq";
+ ste,pins = "sysclkreq5_d_1";
+ };
+ sysclkreq5_default_cfg {
+ ste,pins = "GPIO42";
+ output-low;
+ };
+ };
+ };
+ batremn {
+ batremn_default_mode: batremn_default {
+ batremn_default_mux {
+ ste,function = "batremn";
+ ste,pins = "batremn_d_1";
+ };
+ batremn_default_cfg {
+ ste,pins = "GPIO43";
+ bias-disable;
+ };
+ };
+ };
+ service {
+ service_default_mode: service_default {
+ service_default_mux {
+ ste,function = "service";
+ ste,pins = "service_d_1";
+ };
+ service_default_cfg {
+ ste,pins = "GPIO44";
+ bias-disable;
+ };
+ };
+ };
+ pwrctrl0 {
+ pwrctrl0_default_mux: pwrctrl0_mux {
+ pwrctrl0_default_mux {
+ ste,function = "pwrctrl";
+ ste,pins = "pwrctrl0_d_1";
+ };
+ };
+ pwrctrl0_default_mode: pwrctrl0_default {
+ pwrctrl0_default_cfg {
+ ste,pins = "GPIO45";
+ bias-disable;
+ };
+ };
+ };
+ pwrctrl1 {
+ pwrctrl1_default_mux: pwrctrl1_mux {
+ pwrctrl1_default_mux {
+ ste,function = "pwrctrl";
+ ste,pins = "pwrctrl1_d_1";
+ };
+ };
+ pwrctrl1_default_mode: pwrctrl1_default {
+ pwrctrl1_default_cfg {
+ ste,pins = "GPIO46";
+ bias-disable;
+ };
+ };
+ };
+ pwmextvibra1 {
+ pwmextvibra1_default_mode: pwmextvibra1_default {
+ pwmextvibra1_default_mux {
+ ste,function = "pwmextvibra";
+ ste,pins = "pwmextvibra1_d_1";
+ };
+ pwmextvibra1_default_cfg {
+ ste,pins = "GPIO47";
+ bias-disable;
+ };
+ };
+ };
+ pwmextvibra2 {
+ pwmextvibra2_default_mode: pwmextvibra2_default {
+ pwmextvibra2_default_mux {
+ ste,function = "pwmextvibra";
+ ste,pins = "pwmextvibra2_d_1";
+ };
+ pwmextvibra1_default_cfg {
+ ste,pins = "GPIO48";
+ bias-disable;
+ };
+ };
+ };
+ gpio51 {
+ gpio51_default_mode: gpio51_default {
+ gpio51_default_mux {
+ ste,function = "gpio";
+ ste,pins = "gpio51_a_1";
+ };
+ gpio51_default_cfg {
+ ste,pins = "GPIO51";
+ output-low;
+ };
+ };
+ };
+ gpio52 {
+ gpio52_default_mode: gpio52_default {
+ gpio52_default_mux {
+ ste,function = "gpio";
+ ste,pins = "gpio52_a_1";
+ };
+ gpio52_default_cfg {
+ ste,pins = "GPIO52";
+ bias-pull-down;
+ };
+ };
+ };
+ gpio53 {
+ gpio53_default_mode: gpio53_default {
+ gpio53_default_mux {
+ ste,function = "gpio";
+ ste,pins = "gpio53_a_1";
+ };
+ gpio53_default_cfg {
+ ste,pins = "GPIO53";
+ bias-pull-down;
+ };
+ };
+ };
+ gpio54 {
+ gpio54_default_mode: gpio54_default {
+ gpio54_default_mux {
+ ste,function = "gpio";
+ ste,pins = "gpio54_a_1";
+ };
+ gpio54_default_cfg {
+ ste,pins = "GPIO54";
+ output-low;
+ };
+ };
+ };
+ pdmclkdat {
+ pdmclkdat_default_mode: pdmclkdat_default {
+ pdmclkdat_default_mux {
+ ste,function = "pdm";
+ ste,pins = "pdmclkdat_d_1";
+ };
+ pdmclkdat_default_cfg {
+ ste,pins = "GPIO55", "GPIO56";
+ bias-disable;
+ };
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt b/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt
new file mode 100644
index 000000000000..2246bc5c874b
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/lp8727_charger.txt
@@ -0,0 +1,44 @@
+Binding for TI/National Semiconductor LP8727 Charger
+
+Required properties:
+- compatible: "ti,lp8727"
+- reg: I2C slave address 27h
+
+Optional properties:
+- interrupt-parent: interrupt controller node (see interrupt binding[0])
+- interrupts: interrupt specifier (see interrupt binding[0])
+- debounce-ms: interrupt debounce time. (u32)
+
+AC and USB charging parameters
+- charger-type: "ac" or "usb" (string)
+- eoc-level: value of 'enum lp8727_eoc_level' (u8)
+- charging-current: value of 'enum lp8727_ichg' (u8)
+
+[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+Example)
+
+lp8727@27 {
+ compatible = "ti,lp8727";
+ reg = <0x27>;
+
+ /* GPIO 134 is used for LP8728 interrupt pin */
+ interrupt-parent = <&gpio5>; /* base = 128 */
+ interrupts = <6 0x2>; /* offset = 6, falling edge type */
+
+ debounce-ms = <300>;
+
+ /* AC charger: 5% EOC and 500mA charging current */
+ ac {
+ charger-type = "ac";
+ eoc-level = /bits/ 8 <0>;
+ charging-current = /bits/ 8 <4>;
+ };
+
+ /* USB charger: 10% EOC and 400mA charging current */
+ usb {
+ charger-type = "usb";
+ eoc-level = /bits/ 8 <1>;
+ charging-current = /bits/ 8 <2>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/powerpc/4xx/emac.txt b/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
index 2161334a7ca5..712baf6c3e24 100644
--- a/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
+++ b/Documentation/devicetree/bindings/powerpc/4xx/emac.txt
@@ -1,7 +1,7 @@
4xx/Axon EMAC ethernet nodes
The EMAC ethernet controller in IBM and AMCC 4xx chips, and also
- the Axon bridge. To operate this needs to interact with a ths
+ the Axon bridge. To operate this needs to interact with a this
special McMAL DMA controller, and sometimes an RGMII or ZMII
interface. In addition to the nodes and properties described
below, the node for the OPB bus on which the EMAC sits must have a
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt b/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt
new file mode 100644
index 000000000000..641bc13983e1
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/interlaken-lac.txt
@@ -0,0 +1,309 @@
+===============================================================================
+Freescale Interlaken Look-Aside Controller Device Bindings
+Copyright 2012 Freescale Semiconductor Inc.
+
+CONTENTS
+ - Interlaken Look-Aside Controller (LAC) Node
+ - Example LAC Node
+ - Interlaken Look-Aside Controller (LAC) Software Portal Node
+ - Interlaken Look-Aside Controller (LAC) Software Portal Child Nodes
+ - Example LAC SWP Node with Child Nodes
+
+==============================================================================
+Interlaken Look-Aside Controller (LAC) Node
+
+DESCRIPTION
+
+The Interlaken is a narrow, high speed channelized chip-to-chip interface. To
+facilitate interoperability between a data path device and a look-aside
+co-processor, the Interlaken Look-Aside protocol is defined for short
+transaction-related transfers. Although based on the Interlaken protocol,
+Interlaken Look-Aside is not directly compatible with Interlaken and can be
+considered a different operation mode.
+
+The Interlaken LA controller connects internal platform to Interlaken serial
+interface. It accepts LA command through software portals, which are system
+memory mapped 4KB spaces. The LA commands are then translated into the
+Interlaken control words and data words, which are sent on TX side to TCAM
+through SerDes lanes.
+
+There are two 4KiB spaces defined within the LAC global register memory map.
+There is a full register set at 0x0000-0x0FFF (also known as the "hypervisor"
+version), and a subset at 0x1000-0x1FFF. The former is a superset of the
+latter, and includes certain registers that should not be accessible to
+partitioned software. Separate nodes are used for each region, with a phandle
+linking the hypervisor node to the normal operating node.
+
+PROPERTIES
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,interlaken-lac". This represents only
+ those LAC CCSR registers not protected in partitioned
+ software. The version of the device is determined by the LAC
+ IP Block Revision Register (IPBRR0) at offset 0x0BF8.
+
+ Table of correspondences between IPBRR0 values and example
+ chips:
+ Value Device
+ ----------- -------
+ 0x02000100 T4240
+
+ The Hypervisor node has a different compatible. It must include
+ "fsl,interlaken-lac-hv". This node represents the protected
+ LAC register space and is required except inside a partition
+ where access to the hypervisor node is to be denied.
+
+ - fsl,non-hv-node
+ Usage: required in "fsl,interlaken-lac-hv"
+ Value type: <phandle>
+ Definition: Points to the non-protected LAC CCSR mapped register space
+ node.
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. The first resource represents the
+ Interlaken LAC configuration registers.
+
+ - interrupts:
+ Usage: required in non-hv node only
+ Value type: <prop-encoded-array>
+ Definition: Interrupt mapping for Interlaken LAC error IRQ.
+
+EXAMPLE
+ lac: lac@229000 {
+ compatible = "fsl,interlaken-lac"
+ reg = <0x229000 0x1000>;
+ interrupts = <16 2 1 18>;
+ };
+
+ lac-hv@228000 {
+ compatible = "fsl,interlaken-lac-hv"
+ reg = <0x228000 0x1000>;
+ fsl,non-hv-node = <&lac>;
+ };
+
+===============================================================================
+Interlaken Look-Aside Controller (LAC) Software Portal Container Node
+
+DESCRIPTION
+The Interlaken Look-Aside Controller (LAC) utilizes Software Portals to accept
+Interlaken Look-Aside (ILA) commands. The Interlaken LAC software portal
+memory map occupies 128KB of memory space. The software portal memory space is
+intended to be cache-enabled. WIMG for each software space is required to be
+0010 if stashing is enabled; otherwise, WIMG can be 0000 or 0010.
+
+PROPERTIES
+
+ - #address-cells
+ Usage: required
+ Value type: <u32>
+ Definition: A standard property. Must have a value of 1.
+
+ - #size-cells
+ Usage: required
+ Value type: <u32>
+ Definition: A standard property. Must have a value of 1.
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,interlaken-lac-portals"
+
+ - ranges
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies the address and length
+ of the LAC portal memory space.
+
+===============================================================================
+Interlaken Look-Aside Controller (LAC) Software Portals Child Nodes
+
+DESCRIPTION
+There are up to 24 available software portals with each software portal
+requiring 4KB of consecutive memory within the software portal memory mapped
+space.
+
+PROPERTIES
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,interlaken-lac-portal-vX.Y" where X is
+ the Major version (IP_MJ) found in the LAC IP Block Revision
+ Register (IPBRR0), at offset 0x0BF8, and Y is the Minor version
+ (IP_MN).
+
+ Table of correspondences between version values and example chips:
+ Value Device
+ ------ -------
+ 1.0 T4240
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. The first resource represents the
+ Interlaken LAC software portal registers.
+
+ - fsl,liodn
+ Value type: <u32>
+ Definition: The logical I/O device number (LIODN) for this device. The
+ LIODN is a number expressed by this device and used to perform
+ look-ups in the IOMMU (PAMU) address table when performing
+ DMAs. This property is automatically added by u-boot.
+
+===============================================================================
+EXAMPLE
+
+lac-portals {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ compatible = "fsl,interlaken-lac-portals";
+ ranges = <0x0 0xf 0xf4400000 0x20000>;
+
+ lportal0: lac-portal@0 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x204>;
+ reg = <0x0 0x1000>;
+ };
+
+ lportal1: lac-portal@1000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x205>;
+ reg = <0x1000 0x1000>;
+ };
+
+ lportal2: lac-portal@2000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x206>;
+ reg = <0x2000 0x1000>;
+ };
+
+ lportal3: lac-portal@3000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x207>;
+ reg = <0x3000 0x1000>;
+ };
+
+ lportal4: lac-portal@4000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x208>;
+ reg = <0x4000 0x1000>;
+ };
+
+ lportal5: lac-portal@5000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x209>;
+ reg = <0x5000 0x1000>;
+ };
+
+ lportal6: lac-portal@6000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x20A>;
+ reg = <0x6000 0x1000>;
+ };
+
+ lportal7: lac-portal@7000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x20B>;
+ reg = <0x7000 0x1000>;
+ };
+
+ lportal8: lac-portal@8000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x20C>;
+ reg = <0x8000 0x1000>;
+ };
+
+ lportal9: lac-portal@9000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x20D>;
+ reg = <0x9000 0x1000>;
+ };
+
+ lportal10: lac-portal@A000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x20E>;
+ reg = <0xA000 0x1000>;
+ };
+
+ lportal11: lac-portal@B000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x20F>;
+ reg = <0xB000 0x1000>;
+ };
+
+ lportal12: lac-portal@C000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x210>;
+ reg = <0xC000 0x1000>;
+ };
+
+ lportal13: lac-portal@D000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x211>;
+ reg = <0xD000 0x1000>;
+ };
+
+ lportal14: lac-portal@E000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x212>;
+ reg = <0xE000 0x1000>;
+ };
+
+ lportal15: lac-portal@F000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x213>;
+ reg = <0xF000 0x1000>;
+ };
+
+ lportal16: lac-portal@10000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x214>;
+ reg = <0x10000 0x1000>;
+ };
+
+ lportal17: lac-portal@11000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x215>;
+ reg = <0x11000 0x1000>;
+ };
+
+ lportal8: lac-portal@1200 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x216>;
+ reg = <0x12000 0x1000>;
+ };
+
+ lportal19: lac-portal@13000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x217>;
+ reg = <0x13000 0x1000>;
+ };
+
+ lportal20: lac-portal@14000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x218>;
+ reg = <0x14000 0x1000>;
+ };
+
+ lportal21: lac-portal@15000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x219>;
+ reg = <0x15000 0x1000>;
+ };
+
+ lportal22: lac-portal@16000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x21A>;
+ reg = <0x16000 0x1000>;
+ };
+
+ lportal23: lac-portal@17000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ fsl,liodn = <0x21B>;
+ reg = <0x17000 0x1000>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/pps/pps-gpio.txt b/Documentation/devicetree/bindings/pps/pps-gpio.txt
new file mode 100644
index 000000000000..40bf9c3564a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/pps/pps-gpio.txt
@@ -0,0 +1,20 @@
+Device-Tree Bindings for a PPS Signal on GPIO
+
+These properties describe a PPS (pulse-per-second) signal connected to
+a GPIO pin.
+
+Required properties:
+- compatible: should be "pps-gpio"
+- gpios: one PPS GPIO in the format described by ../gpio/gpio.txt
+
+Optional properties:
+- assert-falling-edge: when present, assert is indicated by a falling edge
+ (instead of by a rising edge)
+
+Example:
+ pps {
+ compatible = "pps-gpio";
+ gpios = <&gpio2 6 0>;
+
+ assert-falling-edge;
+ };
diff --git a/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
new file mode 100644
index 000000000000..1e3dfe7a4894
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/nxp,pca9685-pwm.txt
@@ -0,0 +1,27 @@
+NXP PCA9685 16-channel 12-bit PWM LED controller
+================================================
+
+Required properties:
+ - compatible: "nxp,pca9685-pwm"
+ - #pwm-cells: should be 2. The first cell specifies the per-chip index
+ of the PWM to use and the second cell is the period in nanoseconds.
+ The index 16 is the ALLCALL channel, that sets all PWM channels at the same
+ time.
+
+Optional properties:
+ - invert (bool): boolean to enable inverted logic
+ - open-drain (bool): boolean to configure outputs with open-drain structure;
+ if omitted use totem-pole structure
+
+Example:
+
+For LEDs that are directly connected to the PCA, the following setting is
+applicable:
+
+pca: pca@41 {
+ compatible = "nxp,pca9685-pwm";
+ #pwm-cells = <2>;
+ reg = <0x41>;
+ invert;
+ open-drain;
+};
diff --git a/Documentation/devicetree/bindings/regulator/lp872x.txt b/Documentation/devicetree/bindings/regulator/lp872x.txt
new file mode 100644
index 000000000000..78183182dad9
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/lp872x.txt
@@ -0,0 +1,160 @@
+Binding for TI/National Semiconductor LP872x Driver
+
+Required properties:
+ - compatible: "ti,lp8720" or "ti,lp8725"
+ - reg: I2C slave address. 0x7d = LP8720, 0x7a = LP8725
+
+Optional properties:
+ - ti,general-config: the value of LP872X_GENERAL_CFG register (u8)
+ (LP8720)
+ bit[2]: BUCK output voltage control by external DVS pin or register
+ 1 = external pin, 0 = bit7 of register 08h
+ bit[1]: sleep control by external DVS pin or register
+ 1 = external pin, 0 = bit6 of register 08h
+ bit[0]: time step unit(usec). 1 = 25, 0 = 50
+
+ (LP8725)
+ bit[7:6]: time step unit(usec). 00 = 32, 01 = 64, 10 = 128, 11 = 256
+ bit[4]: BUCK2 enable control. 1 = enable, 0 = disable
+ bit[3]: BUCK2 output voltage register address. 1 = 0Ah, 0 = 0Bh
+ bit[2]: BUCK1 output voltage control by external DVS pin or register
+ 1 = register 08h, 0 = DVS
+ bit[1]: LDO sleep control. 1 = sleep mode, 0 = normal
+ bit[0]: BUCK1 enable control, 1 = enable, 0 = disable
+
+ For more details, please see the datasheet.
+
+ - ti,update-config: define it when LP872X_GENERAL_CFG register should be set
+ - ti,dvs-gpio: GPIO specifier for external DVS pin control of LP872x devices.
+ - ti,dvs-vsel: DVS selector. 0 = SEL_V1, 1 = SEL_V2.
+ - ti,dvs-state: initial DVS pin state. 0 = DVS_LOW, 1 = DVS_HIGH.
+
+ Sub nodes for regulator_init_data
+ LP8720 has maximum 6 nodes. (child name: ldo1 ~ 5 and buck)
+ LP8725 has maximum 9 nodes. (child name: ldo1 ~ 5, lilo1,2 and buck1,2)
+ For more details, please see the following binding document.
+ (Documentation/devicetree/bindings/regulator/regulator.txt)
+
+Datasheet
+ - LP8720: http://www.ti.com/lit/ds/symlink/lp8720.pdf
+ - LP8725: http://www.ti.com/lit/ds/symlink/lp8725.pdf
+
+Example 1) LP8720
+
+lp8720@7d {
+ compatible = "ti,lp8720";
+ reg = <0x7d>;
+
+ /* external DVS pin used, timestep is 25usec */
+ ti,general-config = /bits/ 8 <0x03>;
+ ti,update-config;
+
+ /*
+ * The dvs-gpio depends on the processor environment.
+ * For example, following GPIO specifier means GPIO134 in OMAP4.
+ */
+ ti,dvs-gpio = <&gpio5 6 0>;
+ ti,dvs-vsel = /bits/ 8 <1>; /* SEL_V2 */
+ ti,dvs-state = /bits/ 8 <1>; /* DVS_HIGH */
+
+ vaf: ldo1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vmmc: ldo2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcam_io: ldo3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ vcam_core: ldo4 {
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-boot-on;
+ };
+
+ vcam: ldo5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcc: buck {
+ regulator-name = "VBUCK";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <2300000>;
+ };
+};
+
+Example 2) LP8725
+
+lp8725@7a {
+ compatible = "ti,lp8725";
+ reg = <0x7a>;
+
+ /* Enable BUCK1,2, no DVS, normal LDO mode, timestep is 256usec */
+ ti,general-config = /bits/ 8 <0xdd>;
+ ti,update-config;
+
+ vcam_io: ldo1 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcam_core: ldo2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcam: ldo3 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcmmb_io: ldo4 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ vcmmb_core: ldo5 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ vaux1: lilo1 {
+ regulator-name = "VAUX1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vaux2: lilo2 {
+ regulator-name = "VAUX2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vcc1: buck1 {
+ regulator-name = "VBUCK1";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-min-microamp = <460000>;
+ regulator-max-microamp = <1370000>;
+ regulator-boot-on;
+ };
+
+ vcc2: buck2 {
+ regulator-name = "VBUCK2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-min-microamp = <460000>;
+ regulator-max-microamp = <1370000>;
+ regulator-boot-on;
+ };
+};
diff --git a/Documentation/devicetree/bindings/regulator/max8973-regulator.txt b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt
new file mode 100644
index 000000000000..4f15d8a1bfd0
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/max8973-regulator.txt
@@ -0,0 +1,21 @@
+* Maxim MAX8973 Voltage Regulator
+
+Required properties:
+
+- compatible: must be "maxim,max8973"
+- 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.
+
+Example:
+
+ max8973@1b {
+ compatible = "maxim,max8973";
+ reg = <0x1b>;
+
+ regulator-min-microvolt = <935000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/max8997-regulator.txt b/Documentation/devicetree/bindings/regulator/max8997-regulator.txt
index 9e5e51d78868..5c186a7a77ba 100644
--- a/Documentation/devicetree/bindings/regulator/max8997-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/max8997-regulator.txt
@@ -1,6 +1,6 @@
* Maxim MAX8997 Voltage and Current Regulator
-The Maxim MAX8997 is a multi-function device which includes volatage and
+The Maxim MAX8997 is a multi-function device which includes voltage and
current regulators, rtc, charger controller and other sub-blocks. It is
interfaced to the host controller using a i2c interface. Each sub-block is
addressed by the host system using different i2c slave address. This document
diff --git a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt
new file mode 100644
index 000000000000..d5a308629c57
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt
@@ -0,0 +1,72 @@
+* palmas regulator IP block devicetree bindings
+
+Required properties:
+- compatible : Should be from the list
+ ti,twl6035-pmic
+ ti,twl6036-pmic
+ ti,twl6037-pmic
+ ti,tps65913-pmic
+ ti,tps65914-pmic
+and also the generic series names
+ ti,palmas-pmic
+- interrupt-parent : The parent interrupt controller which is palmas.
+- interrupts : The interrupt number and the type which can be looked up here:
+ arch/arm/boot/dts/include/dt-bindings/interrupt-controller/irq.h
+- interrupts-name: The names of the individual interrupts.
+
+Optional properties:
+- ti,ldo6-vibrator : ldo6 is in vibrator mode
+
+Optional nodes:
+- regulators : Must contain a sub-node per regulator from the list below.
+ Each sub-node should contain the constraints and initialization
+ information for that regulator. See regulator.txt for a
+ description of standard properties for these sub-nodes.
+ Additional custom properties are listed below.
+
+ For ti,palmas-pmic - smps12, smps123, smps3 depending on OTP,
+ smps45, smps457, smps7 depending on variant, smps6, smps[8-10],
+ ldo[1-9], ldoln, ldousb.
+
+ Optional sub-node properties:
+ ti,warm-reset - maintain voltage during warm reset(boolean)
+ ti,roof-floor - control voltage selection by pin(boolean)
+ ti,sleep-mode - mode to adopt in pmic sleep 0 - off, 1 - auto,
+ 2 - eco, 3 - forced pwm
+ ti,tstep - slope control 0 - Jump, 1 10mV/us, 2 5mV/us, 3 2.5mV/us
+ ti,smps-range - OTP has the wrong range set for the hardware so override
+ 0 - low range, 1 - high range.
+
+Example:
+
+#include <dt-bindings/interrupt-controller/irq.h>
+
+pmic {
+ compatible = "ti,twl6035-pmic", "ti,palmas-pmic";
+ interrupt-parent = <&palmas>;
+ interrupts = <14 IRQ_TYPE_NONE>;
+ interrupts-name = "short-irq";
+
+ ti,ldo6-vibrator;
+
+ regulators {
+ smps12_reg : smps12 {
+ regulator-name = "smps12";
+ regulator-min-microvolt = < 600000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ ti,warm-reset;
+ ti,roof-floor;
+ ti,mode-sleep = <0>;
+ ti,tstep = <0>;
+ ti,smps-range = <1>;
+ };
+
+ ldo1_reg: ldo1 {
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index ecfc6ccd67ef..48a3b8e5d6bd 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -9,6 +9,7 @@ Optional properties:
- regulator-max-microamp: largest current consumers may set
- 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)
diff --git a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
index a35ff99003a5..d1660a90fc06 100644
--- a/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/s5m8767-regulator.txt
@@ -1,6 +1,6 @@
* Samsung S5M8767 Voltage and Current Regulator
-The Samsung S5M8767 is a multi-function device which includes volatage and
+The Samsung S5M8767 is a multi-function device which includes voltage and
current regulators, rtc, charger controller and other sub-blocks. It is
interfaced to the host controller using a i2c interface. Each sub-block is
addressed by the host system using different i2c slave address. This document
@@ -103,13 +103,13 @@ Example:
s5m8767,pmic-buck-default-dvs-idx = <0>;
- s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 1 0 0>, /* DVS1 */
- <&gpx0 1 1 0 0>, /* DVS2 */
- <&gpx0 2 1 0 0>; /* DVS3 */
+ s5m8767,pmic-buck-dvs-gpios = <&gpx0 0 0>, /* DVS1 */
+ <&gpx0 1 0>, /* DVS2 */
+ <&gpx0 2 0>; /* DVS3 */
- s5m8767,pmic-buck-ds-gpios = <&gpx2 3 1 0 0>, /* SET1 */
- <&gpx2 4 1 0 0>, /* SET2 */
- <&gpx2 5 1 0 0>; /* SET3 */
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 0>, /* SET1 */
+ <&gpx2 4 0>, /* SET2 */
+ <&gpx2 5 0>; /* SET3 */
s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
<1250000>, <1200000>,
diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
new file mode 100644
index 000000000000..2e57a33e9029
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt
@@ -0,0 +1,128 @@
+Adaptive Body Bias(ABB) SoC internal LDO regulator for Texas Instruments SoCs
+
+Required Properties:
+- compatible: Should be one of:
+ - "ti,abb-v1" for older SoCs like OMAP3
+ - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5
+- reg: Address and length of the register set for the device. It contains
+ the information of registers in the same order as described by reg-names
+- reg-names: Should contain the reg names
+ - "base-address" - contains base address of ABB module
+ - "int-address" - contains address of interrupt register for ABB module
+ (also see Optional properties)
+- #address-cell: should be 0
+- #size-cell: should be 0
+- clocks: should point to the clock node used by ABB module
+- ti,settling-time: Settling time in uSecs from SoC documentation for ABB module
+ to settle down(target time for SR2_WTCNT_VALUE).
+- ti,clock-cycles: SoC specific data about count of system ti,clock-cycles used for
+ computing settling time from SoC Documentation for ABB module(clock
+ cycles for SR2_WTCNT_VALUE).
+- ti,tranxdone-status-mask: Mask to the int-register to write-to-clear mask
+ indicating LDO tranxdone (operation complete).
+- ti,abb_info: An array of 6-tuples u32 items providing information about ABB
+ configuration needed per operational voltage of the device.
+ Each item consists of the following in the same order:
+ volt: voltage in uV - Only used to index ABB information.
+ ABB mode: one of the following:
+ 0-bypass
+ 1-Forward Body Bias(FBB)
+ 3-Reverse Body Bias(RBB)
+ efuse: (see Optional properties)
+ RBB enable efuse Mask: (See Optional properties)
+ FBB enable efuse Mask: (See Optional properties)
+ Vset value efuse Mask: (See Optional properties)
+
+ NOTE: If more than 1 entry is present, then regulator is setup to change
+ voltage, allowing for various modes to be selected indexed off
+ the regulator. Further, ABB LDOs are considered always-on by
+ default.
+
+Optional Properties:
+- reg-names: In addition to the required properties, the following are optional
+ - "efuse-address" - Contains efuse base address used to pick up ABB info.
+ - "ldo-address" - Contains address of ABB LDO overide register address.
+ "efuse-address" is required for this.
+- ti,ldovbb-vset-mask - Required if ldo-address is set, mask for LDO override
+ register to provide override vset value.
+- ti,ldovbb-override-mask - Required if ldo-address is set, mask for LDO
+ override register to enable override vset value.
+- ti,abb_opp_sel: Addendum to the description in required properties
+ efuse: Mandatory if 'efuse-address' register is defined. Provides offset
+ from efuse-address to pick up ABB characteristics. Set to 0 if
+ 'efuse-address' is not defined.
+ RBB enable efuse Mask: Optional if 'efuse-address' register is defined.
+ 'ABB mode' is force set to RBB mode if value at "efuse-address"
+ + efuse maps to RBB mask. Set to 0 to ignore this.
+ FBB enable efuse Mask: Optional if 'efuse-address' register is defined.
+ 'ABB mode' is force set to FBB mode if value at "efuse-address"
+ + efuse maps to FBB mask (valid only if RBB mask does not match)
+ Set to 0 to ignore this.
+ Vset value efuse Mask: Mandatory if ldo-address is set. Picks up from
+ efuse the value to set in 'ti,ldovbb-vset-mask' at ldo-address.
+
+Example #1: Simplest configuration (no efuse data, hard coded ABB table):
+abb_x: regulator-abb-x {
+ compatible = "ti,abb-v1";
+ regulator-name = "abb_x";
+ #address-cell = <0>;
+ #size-cells = <0>;
+ reg = <0x483072f0 0x8>, <0x48306818 0x4>;
+ reg-names = "base-address", "int-address";
+ ti,tranxdone-status-mask = <0x4000000>;
+ clocks = <&sysclk>;
+ ti,settling-time = <30>;
+ ti,clock-cycles = <8>;
+ ti,abb_info = <
+ /* uV ABB efuse rbb_m fbb_m vset_m */
+ 1012500 0 0 0 0 0 /* Bypass */
+ 1200000 3 0 0 0 0 /* RBB mandatory */
+ 1320000 1 0 0 0 0 /* FBB mandatory */
+ >;
+};
+
+Example #2: Efuse bits contain ABB mode setting (no LDO override capability)
+abb_y: regulator-abb-y {
+ compatible = "ti,abb-v2";
+ regulator-name = "abb_y";
+ #address-cell = <0>;
+ #size-cells = <0>;
+ reg = <0x4a307bd0 0x8>, <0x4a306014 0x4>, <0x4A002268 0x8>;
+ reg-names = "base-address", "int-address", "efuse-address";
+ ti,tranxdone-status-mask = <0x4000000>;
+ clocks = <&sysclk>;
+ ti,settling-time = <50>;
+ ti,clock-cycles = <16>;
+ ti,abb_info = <
+ /* uV ABB efuse rbb_m fbb_m vset_m */
+ 975000 0 0 0 0 0 /* Bypass */
+ 1012500 0 0 0x40000 0 0 /* RBB optional */
+ 1200000 0 0x4 0 0x40000 0 /* FBB optional */
+ 1320000 1 0 0 0 0 /* FBB mandatory */
+ >;
+};
+
+Example #3: Efuse bits contain ABB mode setting and LDO override capability
+abb_z: regulator-abb-z {
+ compatible = "ti,abb-v2";
+ regulator-name = "abb_z";
+ #address-cell = <0>;
+ #size-cells = <0>;
+ reg = <0x4ae07ce4 0x8>, <0x4ae06010 0x4>,
+ <0x4a002194 0x8>, <0x4ae0C314 0x4>;
+ reg-names = "base-address", "int-address",
+ "efuse-address", "ldo-address";
+ ti,tranxdone-status-mask = <0x8000000>;
+ /* LDOVBBMM_MUX_CTRL */
+ ti,ldovbb-override-mask = <0x400>;
+ /* LDOVBBMM_VSET_OUT */
+ ti,ldovbb-vset-mask = <0x1F>;
+ clocks = <&sysclk>;
+ ti,settling-time = <50>;
+ ti,clock-cycles = <16>;
+ ti,abb_info = <
+ /* uV ABB efuse rbb_m fbb_m vset_m */
+ 975000 0 0 0 0 0 /* Bypass */
+ 1200000 0 0x4 0 0x40000 0x1f00 /* FBB optional, vset */
+ >;
+};
diff --git a/Documentation/devicetree/bindings/regulator/twl-regulator.txt b/Documentation/devicetree/bindings/regulator/twl-regulator.txt
index 658749b90b97..75b0c1669504 100644
--- a/Documentation/devicetree/bindings/regulator/twl-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/twl-regulator.txt
@@ -18,20 +18,20 @@ For twl6030 regulators/LDOs
- "ti,twl6030-vdd1" for VDD1 SMPS
- "ti,twl6030-vdd2" for VDD2 SMPS
- "ti,twl6030-vdd3" for VDD3 SMPS
-For twl6025 regulators/LDOs
+For twl6032 regulators/LDOs
- compatible:
- - "ti,twl6025-ldo1" for LDO1 LDO
- - "ti,twl6025-ldo2" for LDO2 LDO
- - "ti,twl6025-ldo3" for LDO3 LDO
- - "ti,twl6025-ldo4" for LDO4 LDO
- - "ti,twl6025-ldo5" for LDO5 LDO
- - "ti,twl6025-ldo6" for LDO6 LDO
- - "ti,twl6025-ldo7" for LDO7 LDO
- - "ti,twl6025-ldoln" for LDOLN LDO
- - "ti,twl6025-ldousb" for LDOUSB LDO
- - "ti,twl6025-smps3" for SMPS3 SMPS
- - "ti,twl6025-smps4" for SMPS4 SMPS
- - "ti,twl6025-vio" for VIO SMPS
+ - "ti,twl6032-ldo1" for LDO1 LDO
+ - "ti,twl6032-ldo2" for LDO2 LDO
+ - "ti,twl6032-ldo3" for LDO3 LDO
+ - "ti,twl6032-ldo4" for LDO4 LDO
+ - "ti,twl6032-ldo5" for LDO5 LDO
+ - "ti,twl6032-ldo6" for LDO6 LDO
+ - "ti,twl6032-ldo7" for LDO7 LDO
+ - "ti,twl6032-ldoln" for LDOLN LDO
+ - "ti,twl6032-ldousb" for LDOUSB LDO
+ - "ti,twl6032-smps3" for SMPS3 SMPS
+ - "ti,twl6032-smps4" for SMPS4 SMPS
+ - "ti,twl6032-vio" for VIO SMPS
For twl4030 regulators/LDOs
- compatible:
- "ti,twl4030-vaux1" for VAUX1 LDO
diff --git a/Documentation/devicetree/bindings/serio/olpc,ap-sp.txt b/Documentation/devicetree/bindings/serio/olpc,ap-sp.txt
new file mode 100644
index 000000000000..0e72183f52bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/serio/olpc,ap-sp.txt
@@ -0,0 +1,13 @@
+OLPC AP-SP serio interface
+
+Required properties:
+- compatible : "olpc,ap-sp"
+- reg : base address and length of SoC's WTM registers
+- interrupts : SP-AP interrupt
+
+Example:
+ ap-sp@d4290000 {
+ compatible = "olpc,ap-sp";
+ reg = <0xd4290000 0x1000>;
+ interrupts = <40>;
+ }
diff --git a/Documentation/devicetree/bindings/sound/adi,adau1701.txt b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
new file mode 100644
index 000000000000..547a49b56a62
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/adi,adau1701.txt
@@ -0,0 +1,35 @@
+Analog Devices ADAU1701
+
+Required properties:
+
+ - compatible: Should contain "adi,adau1701"
+ - reg: The i2c address. Value depends on the state of ADDR0
+ and ADDR1, as wired in hardware.
+
+Optional properties:
+
+ - reset-gpio: A GPIO spec to define which pin is connected to the
+ chip's !RESET pin. If specified, the driver will
+ assert a hardware reset at probe time.
+ - adi,pll-mode-gpios: An array of two GPIO specs to describe the GPIOs
+ the ADAU's PLL config pins are connected to.
+ The state of the pins are set according to the
+ configured clock divider on ASoC side before the
+ firmware is loaded.
+ - adi,pin-config: An array of 12 numerical values selecting one of the
+ pin configurations as described in the datasheet,
+ table 53. Note that the value of this property has
+ to be prefixed with '/bits/ 8'.
+
+Examples:
+
+ i2c_bus {
+ adau1701@34 {
+ compatible = "adi,adau1701";
+ reg = <0x34>;
+ reset-gpio = <&gpio 23 0>;
+ 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/imx-audio-wm8962.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
new file mode 100644
index 000000000000..f49450a87890
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
@@ -0,0 +1,46 @@
+Freescale i.MX audio complex with WM8962 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-wm8962"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the WM8962 audio codec
+- audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source. Valid names could be power
+ supplies, WM8962 pins, and the jacks on the board:
+
+ Power supplies:
+ * Mic Bias
+
+ Board connectors:
+ * Mic Jack
+ * Headphone Jack
+ * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+ compatible = "fsl,imx6q-sabresd-wm8962",
+ "fsl,imx-audio-wm8962";
+ model = "wm8962-audio";
+ ssi-controller = <&ssi2>;
+ audio-codec = <&codec>;
+ audio-routing =
+ "Headphone Jack", "HPOUTL",
+ "Headphone Jack", "HPOUTR",
+ "Ext Spk", "SPKOUTL",
+ "Ext Spk", "SPKOUTR",
+ "MICBIAS", "AMIC",
+ "IN3R", "MICBIAS",
+ "DMIC", "MICBIAS",
+ "DMICDAT", "DMIC";
+ mux-int-port = <2>;
+ mux-ext-port = <3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-saif.txt b/Documentation/devicetree/bindings/sound/mxs-saif.txt
index c37ba6143d9b..7ba07a118e37 100644
--- a/Documentation/devicetree/bindings/sound/mxs-saif.txt
+++ b/Documentation/devicetree/bindings/sound/mxs-saif.txt
@@ -3,8 +3,11 @@
Required properties:
- compatible: Should be "fsl,<chip>-saif"
- reg: Should contain registers location and length
-- interrupts: Should contain ERROR and DMA interrupts
-- fsl,saif-dma-channel: APBX DMA channel for the SAIF
+- interrupts: Should contain ERROR interrupt number
+- dmas: DMA specifier, consisting of a phandle to DMA controller node
+ and SAIF DMA channel ID.
+ Refer to dma.txt and fsl-mxs-dma.txt for details.
+- dma-names: Must be "rx-tx".
Optional properties:
- fsl,saif-master: phandle to the master SAIF. It's only required for
@@ -23,14 +26,16 @@ aliases {
saif0: saif@80042000 {
compatible = "fsl,imx28-saif";
reg = <0x80042000 2000>;
- interrupts = <59 80>;
- fsl,saif-dma-channel = <4>;
+ interrupts = <59>;
+ dmas = <&dma_apbx 4>;
+ dma-names = "rx-tx";
};
saif1: saif@80046000 {
compatible = "fsl,imx28-saif";
reg = <0x80046000 2000>;
- interrupts = <58 81>;
- fsl,saif-dma-channel = <5>;
+ interrupts = <58>;
+ dmas = <&dma_apbx 5>;
+ dma-names = "rx-tx";
fsl,saif-master = <&saif0>;
};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
new file mode 100644
index 000000000000..d130818700b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
@@ -0,0 +1,71 @@
+NVIDIA Tegra audio complex, with RT5640 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-rt5640"
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must include the following entries:
+ "pll_a" (The Tegra clock of that name),
+ "pll_a_out0" (The Tegra clock of that name),
+ "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source. Valid names for sources and
+ sinks are the RT5640's pins, and the jacks on the board:
+
+ RT5640 pins:
+
+ * DMIC1
+ * DMIC2
+ * MICBIAS1
+ * IN1P
+ * IN1R
+ * IN2P
+ * IN2R
+ * HPOL
+ * HPOR
+ * LOUTL
+ * LOUTR
+ * MONOP
+ * MONON
+ * SPOLP
+ * SPOLN
+ * SPORP
+ * SPORN
+
+ Board connectors:
+
+ * Headphones
+ * Speakers
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+ connected to the CODEC.
+- nvidia,audio-codec : The phandle of the RT5640 audio codec. This binding
+ assumes that AIF1 on the CODEC is connected to Tegra.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
+
+Example:
+
+sound {
+ compatible = "nvidia,tegra-audio-rt5640-dalmore",
+ "nvidia,tegra-audio-rt5640";
+ nvidia,model = "NVIDIA Tegra Dalmore";
+
+ nvidia,audio-routing =
+ "Headphones", "HPOR",
+ "Headphones", "HPOL",
+ "Speakers", "SPORP",
+ "Speakers", "SPORN",
+ "Speakers", "SPOLP",
+ "Speakers", "SPOLN";
+
+ nvidia,i2s-controller = <&tegra_i2s1>;
+ nvidia,audio-codec = <&rt5640>;
+
+ nvidia,hp-det-gpios = <&gpio 143 0>; /* GPIO PR7 */
+
+ clocks = <&tegra_car 216>, <&tegra_car 217>, <&tegra_car 120>;
+ clock-names = "pll_a", "pll_a_out0", "mclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5640.txt b/Documentation/devicetree/bindings/sound/rt5640.txt
new file mode 100644
index 000000000000..005bcb24d72d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5640.txt
@@ -0,0 +1,30 @@
+RT5640 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+- compatible : "realtek,rt5640".
+
+- reg : The I2C address of the device.
+
+- interrupts : The CODEC's interrupt output.
+
+Optional properties:
+
+- realtek,in1-differential
+- realtek,in2-differential
+ Boolean. Indicate MIC1/2 input are differential, rather than single-ended.
+
+- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
+
+Example:
+
+rt5640 {
+ compatible = "realtek,rt5640";
+ reg = <0x1c>;
+ interrupt-parent = <&gpio>;
+ interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>;
+ realtek,ldo1-en-gpios =
+ <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
+};
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt
index 9cc44449508d..955df60a118c 100644
--- a/Documentation/devicetree/bindings/sound/sgtl5000.txt
+++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt
@@ -5,9 +5,12 @@ Required properties:
- reg : the I2C address of the device
+- clocks : the clock provider of SYS_MCLK
+
Example:
codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
+ clocks = <&clks 150>;
};
diff --git a/Documentation/devicetree/bindings/sound/spdif-receiver.txt b/Documentation/devicetree/bindings/sound/spdif-receiver.txt
new file mode 100644
index 000000000000..80f807bf8a1d
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/spdif-receiver.txt
@@ -0,0 +1,10 @@
+Device-Tree bindings for dummy spdif receiver
+
+Required properties:
+ - compatible: should be "linux,spdif-dir".
+
+Example node:
+
+ codec: spdif-receiver {
+ compatible = "linux,spdif-dir";
+ };
diff --git a/Documentation/devicetree/bindings/sound/spdif-transmitter.txt b/Documentation/devicetree/bindings/sound/spdif-transmitter.txt
new file mode 100644
index 000000000000..55a85841dd85
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/spdif-transmitter.txt
@@ -0,0 +1,10 @@
+Device-Tree bindings for dummy spdif transmitter
+
+Required properties:
+ - compatible: should be "linux,spdif-dit".
+
+Example node:
+
+ codec: spdif-transmitter {
+ compatible = "linux,spdif-dit";
+ };
diff --git a/Documentation/devicetree/bindings/sound/ssm2518.txt b/Documentation/devicetree/bindings/sound/ssm2518.txt
new file mode 100644
index 000000000000..59381a778c79
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ssm2518.txt
@@ -0,0 +1,20 @@
+SSM2518 audio amplifier
+
+This device supports I2C only.
+
+Required properties:
+ - compatible : Must be "adi,ssm2518"
+ - reg : the I2C address of the device. This will either be 0x34 (ADDR pin low)
+ or 0x35 (ADDR pin high)
+
+Optional properties:
+ - gpios : GPIO connected to the nSD pin. If the property is not present it is
+ assumed that the nSD pin is hardwired to always on.
+
+Example:
+
+ ssm2518: ssm2518@34 {
+ compatible = "adi,ssm2518";
+ reg = <0x34>;
+ gpios = <&gpio 5 0>;
+ };
diff --git a/Documentation/devicetree/bindings/sound/ti,tas5086.txt b/Documentation/devicetree/bindings/sound/ti,tas5086.txt
index 8ea4f5b4818d..d2866a0d6a26 100644
--- a/Documentation/devicetree/bindings/sound/ti,tas5086.txt
+++ b/Documentation/devicetree/bindings/sound/ti,tas5086.txt
@@ -20,6 +20,17 @@ Optional properties:
When not specified, the hardware default of 1300ms
is retained.
+ - ti,mid-z-channel-X: Boolean properties, X being a number from 1 to 6.
+ If given, channel X will start with the Mid-Z start
+ sequence, otherwise the default Low-Z scheme is used.
+
+ The correct configuration depends on how the power
+ stages connected to the PWM output pins work. Not all
+ power stages are compatible to Mid-Z - please refer
+ to the datasheets for more details.
+
+ Most systems should not set any of these properties.
+
Examples:
i2c_bus {
diff --git a/Documentation/devicetree/bindings/sound/wm8962.txt b/Documentation/devicetree/bindings/sound/wm8962.txt
index dceb3b1c2bb7..7f82b59ec8f9 100644
--- a/Documentation/devicetree/bindings/sound/wm8962.txt
+++ b/Documentation/devicetree/bindings/sound/wm8962.txt
@@ -8,9 +8,32 @@ Required properties:
- reg : the I2C address of the device.
+Optional properties:
+ - spk-mono: This is a boolean property. If present, the SPK_MONO bit
+ of R51 (Class D Control 2) gets set, indicating that the speaker is
+ in mono mode.
+
+ - mic-cfg : Default register value for R48 (Additional Control 4).
+ If absent, the default should be the register default.
+
+ - gpio-cfg : A list of GPIO configuration register values. The list must
+ be 6 entries long. If absent, no configuration of these registers is
+ performed. And note that only the value within [0x0, 0xffff] is valid.
+ Any other value is regarded as setting the GPIO register by its reset
+ value 0x0.
+
Example:
codec: wm8962@1a {
compatible = "wlf,wm8962";
reg = <0x1a>;
+
+ gpio-cfg = <
+ 0x0000 /* 0:Default */
+ 0x0000 /* 1:Default */
+ 0x0013 /* 2:FN_DMICCLK */
+ 0x0000 /* 3:Default */
+ 0x8014 /* 4:FN_DMICCDAT */
+ 0x0000 /* 5:Default */
+ >;
};
diff --git a/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt
index 8bf89c643640..f11f295c8450 100644
--- a/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt
+++ b/Documentation/devicetree/bindings/spi/brcm,bcm2835-spi.txt
@@ -2,7 +2,7 @@ Broadcom BCM2835 SPI0 controller
The BCM2835 contains two forms of SPI master controller, one known simply as
SPI0, and the other known as the "Universal SPI Master"; part of the
-auxilliary block. This binding applies to the SPI0 controller.
+auxiliary block. This binding applies to the SPI0 controller.
Required properties:
- compatible: Should be "brcm,bcm2835-spi".
diff --git a/Documentation/devicetree/bindings/spi/omap-spi.txt b/Documentation/devicetree/bindings/spi/omap-spi.txt
index 938809c6829b..4c85c4c69584 100644
--- a/Documentation/devicetree/bindings/spi/omap-spi.txt
+++ b/Documentation/devicetree/bindings/spi/omap-spi.txt
@@ -10,7 +10,18 @@ Required properties:
input. The default is D0 as input and
D1 as output.
-Example:
+Optional properties:
+- dmas: List of DMA specifiers with the controller specific format
+ as described in the generic DMA client binding. A tx and rx
+ specifier is required for each chip select.
+- dma-names: List of DMA request names. These strings correspond
+ 1:1 with the DMA specifiers listed in dmas. The string naming
+ is to be "rxN" and "txN" for RX and TX requests,
+ respectively, where N equals the chip select number.
+
+Examples:
+
+[hwmod populated DMA resources]
mcspi1: mcspi@1 {
#address-cells = <1>;
@@ -20,3 +31,17 @@ mcspi1: mcspi@1 {
ti,spi-num-cs = <4>;
};
+[generic DMA request binding]
+
+mcspi1: mcspi@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,omap4-mcspi";
+ ti,hwmods = "mcspi1";
+ ti,spi-num-cs = <2>;
+ dmas = <&edma 42
+ &edma 43
+ &edma 44
+ &edma 45>;
+ dma-names = "tx0", "rx0", "tx1", "rx1";
+};
diff --git a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
index 1629652372b6..0c9222d27fae 100644
--- a/drivers/staging/ti-soc-thermal/ti_soc_thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
@@ -17,8 +17,9 @@ Required properties:
- interrupts : this entry should indicate which interrupt line
the talert signal is routed to;
Specific:
-- ti,tshut-gpio : this entry should be used to inform which GPIO
-line the tshut signal is routed to;
+- gpios : this entry should be used to inform which GPIO
+line the tshut signal is routed to. The informed GPIO will
+be treated as an IRQ;
- regs : this entry must also be specified and it is specific
to each bandgap version, because the mapping may change from
soc to soc, apart of depending on available features.
@@ -37,7 +38,7 @@ bandgap {
0x4a002378 0x18>;
compatible = "ti,omap4460-bandgap";
interrupts = <0 126 4>; /* talert */
- ti,tshut-gpio = <86>;
+ gpios = <&gpio3 22 0>; /* tshut */
};
OMAP4470:
@@ -47,7 +48,7 @@ bandgap {
0x4a002378 0x18>;
compatible = "ti,omap4470-bandgap";
interrupts = <0 126 4>; /* talert */
- ti,tshut-gpio = <86>;
+ gpios = <&gpio3 22 0>; /* tshut */
};
OMAP5430:
@@ -59,3 +60,15 @@ bandgap {
compatible = "ti,omap5430-bandgap";
interrupts = <0 126 4>; /* talert */
};
+
+DRA752:
+bandgap {
+ reg = <0x4a0021e0 0xc
+ 0x4a00232c 0xc
+ 0x4a002380 0x2c
+ 0x4a0023C0 0x3c
+ 0x4a002564 0x8
+ 0x4a002574 0x50>;
+ compatible = "ti,dra752-bandgap";
+ interrupts = <0 126 4>; /* talert */
+};
diff --git a/Documentation/devicetree/bindings/timer/lsi,zevio-timer.txt b/Documentation/devicetree/bindings/timer/lsi,zevio-timer.txt
new file mode 100644
index 000000000000..b2d07ad90e9a
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/lsi,zevio-timer.txt
@@ -0,0 +1,33 @@
+TI-NSPIRE timer
+
+Required properties:
+
+- compatible : should be "lsi,zevio-timer".
+- reg : The physical base address and size of the timer (always first).
+- clocks: phandle to the source clock.
+
+Optional properties:
+
+- interrupts : The interrupt number of the first timer.
+- reg : The interrupt acknowledgement registers
+ (always after timer base address)
+
+If any of the optional properties are not given, the timer is added as a
+clock-source only.
+
+Example:
+
+timer {
+ compatible = "lsi,zevio-timer";
+ reg = <0x900D0000 0x1000>, <0x900A0020 0x8>;
+ interrupts = <19>;
+ clocks = <&timer_clk>;
+};
+
+Example (no clock-events):
+
+timer {
+ compatible = "lsi,zevio-timer";
+ reg = <0x900D0000 0x1000>;
+ clocks = <&timer_clk>;
+};
diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
index cb47bfbcaeea..b5a86d20ee36 100644
--- a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
+++ b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
@@ -44,7 +44,7 @@ Example 1: In this example, the system uses only the first global timer
};
Example 2: In this example, the MCT global and local timer interrupts are
- connected to two seperate interrupt controllers. Hence, an
+ connected to two separate interrupt controllers. Hence, an
interrupt-map is created to map the interrupts to the respective
interrupt controllers.
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
new file mode 100644
index 000000000000..20468b2a7516
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -0,0 +1,16 @@
+* Universal Flash Storage (UFS) Host Controller
+
+UFSHC nodes are defined to describe on-chip UFS host controllers.
+Each UFS controller instance should have its own node.
+
+Required properties:
+- compatible : compatible list, contains "jedec,ufs-1.1"
+- interrupts : <interrupt mapping for UFS host controller IRQ>
+- reg : <registers mapping>
+
+Example:
+ ufshc@0xfc598000 {
+ compatible = "jedec,ufs-1.1";
+ reg = <0xfc598000 0x800>;
+ interrupts = <0 28 0>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/am33xx-usb.txt b/Documentation/devicetree/bindings/usb/am33xx-usb.txt
index ea840f7f9258..dc9dc8c87f15 100644
--- a/Documentation/devicetree/bindings/usb/am33xx-usb.txt
+++ b/Documentation/devicetree/bindings/usb/am33xx-usb.txt
@@ -12,7 +12,7 @@ AM33XX MUSB GLUE
represents PERIPHERAL.
- port1-mode : Should be "1" to represent HOST. "3" signifies OTG and "2"
represents PERIPHERAL.
- - power : Should be "250". This signifies the controller can supply upto
+ - power : Should be "250". This signifies the controller can supply up to
500mA when operating in host mode.
Example:
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index d4769f343d6c..57e71f6817d0 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -16,7 +16,7 @@ OMAP MUSB GLUE
specifying ULPI and UTMI respectively.
- mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
represents PERIPHERAL.
- - power : Should be "50". This signifies the controller can supply upto
+ - power : Should be "50". This signifies the controller can supply up to
100mA when operating in host mode.
- usb-phy : the phandle for the PHY device
diff --git a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
index 36b9aede3f40..0aee0ad3f035 100644
--- a/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
+++ b/Documentation/devicetree/bindings/usb/twlxxxx-usb.txt
@@ -8,7 +8,7 @@ TWL6030 USB COMPARATOR
usb interrupt number that raises VBUS interrupts when the controller has to
act as device
- usb-supply : phandle to the regulator device tree node. It should be vusb
- if it is twl6030 or ldousb if it is twl6025 subclass.
+ if it is twl6030 or ldousb if it is twl6032 subclass.
twl6030-usb {
compatible = "ti,twl6030-usb";
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index db0457d61682..d5a79caec147 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -18,6 +18,7 @@ chrp Common Hardware Reference Platform
cirrus Cirrus Logic, Inc.
cortina Cortina Systems, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
+davicom DAVICOM Semiconductor, Inc.
denx Denx Software Engineering
emmicro EM Microelectronic
epson Seiko Epson Corp.
@@ -58,6 +59,7 @@ snps Synopsys, Inc.
st STMicroelectronics
ste ST-Ericsson
stericsson ST-Ericsson
+toumaz Toumaz
ti Texas Instruments
toshiba Toshiba Corporation
v3 V3 Semiconductor
diff --git a/Documentation/devicetree/bindings/video/display-timing.txt b/Documentation/devicetree/bindings/video/display-timing.txt
index 150038552bc3..e1d4a0b59612 100644
--- a/Documentation/devicetree/bindings/video/display-timing.txt
+++ b/Documentation/devicetree/bindings/video/display-timing.txt
@@ -34,6 +34,7 @@ optional properties:
- ignored = ignored
- interlaced (bool): boolean to enable interlaced mode
- doublescan (bool): boolean to enable doublescan mode
+ - doubleclk (bool): boolean to enable doubleclock mode
All the optional properties that are not bool follow the following logic:
<1>: high active
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
index 589edee37394..323983be3c30 100644
--- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt
+++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt
@@ -1,22 +1,23 @@
Device-Tree bindings for drm hdmi driver
Required properties:
-- compatible: value should be "samsung,exynos5-hdmi".
+- compatible: value should be one among the following:
+ 1) "samsung,exynos5-hdmi" <DEPRECATED>
+ 2) "samsung,exynos4210-hdmi"
+ 3) "samsung,exynos4212-hdmi"
- reg: physical base address of the hdmi and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
- hpd-gpio: following information about the hotplug gpio pin.
a) phandle of the gpio controller node.
b) pin number within the gpio controller.
- c) pin function mode.
- d) optional flags and pull up/down.
- e) drive strength.
+ c) optional flags and pull up/down.
Example:
hdmi {
- compatible = "samsung,exynos5-hdmi";
+ compatible = "samsung,exynos4212-hdmi";
reg = <0x14530000 0x100000>;
interrupts = <0 95 0>;
- hpd-gpio = <&gpx3 7 0xf 1 3>;
+ hpd-gpio = <&gpx3 7 1>;
};
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmiddc.txt b/Documentation/devicetree/bindings/video/exynos_hdmiddc.txt
index fa166d945809..41eee971562b 100644
--- a/Documentation/devicetree/bindings/video/exynos_hdmiddc.txt
+++ b/Documentation/devicetree/bindings/video/exynos_hdmiddc.txt
@@ -1,12 +1,15 @@
Device-Tree bindings for hdmiddc driver
Required properties:
-- compatible: value should be "samsung,exynos5-hdmiddc".
+- compatible: value should be one of the following
+ 1) "samsung,exynos5-hdmiddc" <DEPRECATED>
+ 2) "samsung,exynos4210-hdmiddc"
+
- reg: I2C address of the hdmiddc device.
Example:
hdmiddc {
- compatible = "samsung,exynos5-hdmiddc";
+ compatible = "samsung,exynos4210-hdmiddc";
reg = <0x50>;
};
diff --git a/Documentation/devicetree/bindings/video/exynos_hdmiphy.txt b/Documentation/devicetree/bindings/video/exynos_hdmiphy.txt
index 858f4f9b902f..162f641f7639 100644
--- a/Documentation/devicetree/bindings/video/exynos_hdmiphy.txt
+++ b/Documentation/devicetree/bindings/video/exynos_hdmiphy.txt
@@ -1,12 +1,15 @@
Device-Tree bindings for hdmiphy driver
Required properties:
-- compatible: value should be "samsung,exynos5-hdmiphy".
+- compatible: value should be one of the following:
+ 1) "samsung,exynos5-hdmiphy" <DEPRECATED>
+ 2) "samsung,exynos4210-hdmiphy".
+ 3) "samsung,exynos4212-hdmiphy".
- reg: I2C address of the hdmiphy device.
Example:
hdmiphy {
- compatible = "samsung,exynos5-hdmiphy";
+ compatible = "samsung,exynos4210-hdmiphy";
reg = <0x38>;
};
diff --git a/Documentation/devicetree/bindings/video/exynos_mixer.txt b/Documentation/devicetree/bindings/video/exynos_mixer.txt
index 9b2ea0343566..3334b0a8e343 100644
--- a/Documentation/devicetree/bindings/video/exynos_mixer.txt
+++ b/Documentation/devicetree/bindings/video/exynos_mixer.txt
@@ -1,7 +1,12 @@
Device-Tree bindings for mixer driver
Required properties:
-- compatible: value should be "samsung,exynos5-mixer".
+- compatible: value should be one of the following:
+ 1) "samsung,exynos5-mixer" <DEPRECATED>
+ 2) "samsung,exynos4210-mixer"
+ 3) "samsung,exynos5250-mixer"
+ 4) "samsung,exynos5420-mixer"
+
- reg: physical base address of the mixer and length of memory mapped
region.
- interrupts: interrupt number to the cpu.
@@ -9,7 +14,7 @@ Required properties:
Example:
mixer {
- compatible = "samsung,exynos5-mixer";
+ compatible = "samsung,exynos5250-mixer";
reg = <0x14450000 0x10000>;
interrupts = <0 94 0>;
};
diff --git a/Documentation/devicetree/bindings/video/fsl,imx-fb.txt b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
new file mode 100644
index 000000000000..46da08db186a
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/fsl,imx-fb.txt
@@ -0,0 +1,51 @@
+Freescale imx21 Framebuffer
+
+This framebuffer driver supports devices imx1, imx21, imx25, and imx27.
+
+Required properties:
+- compatible : "fsl,<chip>-fb", chip should be imx1 or imx21
+- reg : Should contain 1 register ranges(address and length)
+- interrupts : One interrupt of the fb dev
+
+Required nodes:
+- display: Phandle to a display node as described in
+ Documentation/devicetree/bindings/video/display-timing.txt
+ Additional, the display node has to define properties:
+ - bits-per-pixel: Bits per pixel
+ - fsl,pcr: LCDC PCR value
+
+Optional properties:
+- fsl,dmacr: DMA Control Register value. This is optional. By default, the
+ register is not modified as recommended by the datasheet.
+- fsl,lscr1: LCDC Sharp Configuration Register value.
+
+Example:
+
+ imxfb: fb@10021000 {
+ compatible = "fsl,imx21-fb";
+ interrupts = <61>;
+ reg = <0x10021000 0x1000>;
+ display = <&display0>;
+ };
+
+ ...
+
+ display0: display0 {
+ model = "Primeview-PD050VL1";
+ native-mode = <&timing_disp0>;
+ bits-per-pixel = <16>;
+ fsl,pcr = <0xf0c88080>; /* non-standard but required */
+ display-timings {
+ timing_disp0: 640x480 {
+ hactive = <640>;
+ vactive = <480>;
+ hback-porch = <112>;
+ hfront-porch = <36>;
+ hsync-len = <32>;
+ vback-porch = <33>;
+ vfront-porch = <33>;
+ vsync-len = <2>;
+ clock-frequency = <25000000>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/video/ssd1307fb.txt b/Documentation/devicetree/bindings/video/ssd1307fb.txt
index 3d0060cff062..7a125427ff4b 100644
--- a/Documentation/devicetree/bindings/video/ssd1307fb.txt
+++ b/Documentation/devicetree/bindings/video/ssd1307fb.txt
@@ -1,13 +1,17 @@
* Solomon SSD1307 Framebuffer Driver
Required properties:
- - compatible: Should be "solomon,ssd1307fb-<bus>". The only supported bus for
- now is i2c.
+ - compatible: Should be "solomon,<chip>fb-<bus>". The only supported bus for
+ now is i2c, and the supported chips are 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
- specification [0]
+ specification [0]. Only required for the ssd1307.
- reset-gpios: Should contain the GPIO used to reset the OLED display
+ - solomon,height: Height in pixel of the screen driven by the controller
+ - solomon,width: Width in pixel of the screen driven by the controller
+ - solomon,page-offset: Offset of pages (band of 8 pixels) that the screen is
+ mapped to.
Optional properties:
- reset-active-low: Is the reset gpio is active on physical low?
diff --git a/Documentation/devicetree/usage-model.txt b/Documentation/devicetree/usage-model.txt
index 0efedaad5165..2b6b3d3f0388 100644
--- a/Documentation/devicetree/usage-model.txt
+++ b/Documentation/devicetree/usage-model.txt
@@ -106,17 +106,18 @@ In the majority of cases, the machine identity is irrelevant, and the
kernel will instead select setup code based on the machine's core
CPU or SoC. On ARM for example, setup_arch() in
arch/arm/kernel/setup.c will call setup_machine_fdt() in
-arch/arm/kernel/devicetree.c which searches through the machine_desc
+arch/arm/kernel/devtree.c which searches through the machine_desc
table and selects the machine_desc which best matches the device tree
data. It determines the best match by looking at the 'compatible'
property in the root device tree node, and comparing it with the
-dt_compat list in struct machine_desc.
+dt_compat list in struct machine_desc (which is defined in
+arch/arm/include/asm/mach/arch.h if you're curious).
The 'compatible' property contains a sorted list of strings starting
with the exact name of the machine, followed by an optional list of
boards it is compatible with sorted from most compatible to least. For
example, the root compatible properties for the TI BeagleBoard and its
-successor, the BeagleBoard xM board might look like:
+successor, the BeagleBoard xM board might look like, respectively:
compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3";
compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
@@ -161,7 +162,7 @@ cases.
Instead, the compatible list allows a generic machine_desc to provide
support for a wide common set of boards by specifying "less
-compatible" value in the dt_compat list. In the example above,
+compatible" values in the dt_compat list. In the example above,
generic board support can claim compatibility with "ti,omap3" or
"ti,omap3450". If a bug was discovered on the original beagleboard
that required special workaround code during early boot, then a new
@@ -377,7 +378,7 @@ platform_devices as more platform_devices is a common pattern, and the
device tree support code reflects that and makes the above example
simpler. The second argument to of_platform_populate() is an
of_device_id table, and any node that matches an entry in that table
-will also get its child nodes registered. In the tegra case, the code
+will also get its child nodes registered. In the Tegra case, the code
can look something like this:
static void __init harmony_init_machine(void)
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index 72322c6d7352..1bbdcfcf1f13 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -279,7 +279,7 @@ The dyndbg option is a "fake" module parameter, which means:
- modules do not need to define it explicitly
- every module gets it tacitly, whether they use pr_debug or not
-- it doesnt appear in /sys/module/$module/parameters/
+- it doesn't appear in /sys/module/$module/parameters/
To see it, grep the control file, or inspect /proc/cmdline.
For CONFIG_DYNAMIC_DEBUG kernels, any settings given at boot-time (or
diff --git a/Documentation/early-userspace/README b/Documentation/early-userspace/README
index e35d83052192..661a73fad399 100644
--- a/Documentation/early-userspace/README
+++ b/Documentation/early-userspace/README
@@ -71,7 +71,7 @@ can really be interpreted as any legal argument to
gen_initramfs_list.sh. If a directory is specified as an argument then
the contents are scanned, uid/gid translation is performed, and
usr/gen_init_cpio file directives are output. If a directory is
-specified as an arugemnt to scripts/gen_initramfs_list.sh then the
+specified as an argument to scripts/gen_initramfs_list.sh then the
contents of the file are simply copied to the output. All of the output
directives from directory scanning and file contents copying are
processed by usr/gen_init_cpio.
diff --git a/Documentation/fb/cirrusfb.txt b/Documentation/fb/cirrusfb.txt
index f9436843e998..f75950d330a4 100644
--- a/Documentation/fb/cirrusfb.txt
+++ b/Documentation/fb/cirrusfb.txt
@@ -55,7 +55,7 @@ Version 1.9.4.4
* Overhaul color register routines.
* Associated with the above, console colors are now obtained from a LUT
called 'palette' instead of from the VGA registers. This code was
- modeled after that in atyfb and matroxfb.
+ modelled after that in atyfb and matroxfb.
* Code cleanup, add comments.
* Overhaul SR07 handling.
* Bug fixes.
diff --git a/Documentation/fb/uvesafb.txt b/Documentation/fb/uvesafb.txt
index eefdd91d298a..f6362d88763b 100644
--- a/Documentation/fb/uvesafb.txt
+++ b/Documentation/fb/uvesafb.txt
@@ -81,17 +81,11 @@ pmipal Use the protected mode interface for palette changes.
mtrr:n Setup memory type range registers for the framebuffer
where n:
- 0 - disabled (equivalent to nomtrr) (default)
- 1 - uncachable
- 2 - write-back
- 3 - write-combining
- 4 - write-through
-
- If you see the following in dmesg, choose the type that matches
- the old one. In this example, use "mtrr:2".
-...
-mtrr: type mismatch for e0000000,8000000 old: write-back new: write-combining
-...
+ 0 - disabled (equivalent to nomtrr)
+ 3 - write-combining (default)
+
+ Values other than 0 and 3 will result in a warning and will be
+ treated just like 3.
nomtrr Do not use memory type range registers.
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 9858f337529c..fe7afe225381 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -11,10 +11,8 @@ be able to use diff(1).
prototypes:
int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
- int (*d_hash)(const struct dentry *, const struct inode *,
- struct qstr *);
- int (*d_compare)(const struct dentry *, const struct inode *,
- const struct dentry *, const struct inode *,
+ int (*d_hash)(const struct dentry *, struct qstr *);
+ int (*d_compare)(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
@@ -66,6 +64,7 @@ prototypes:
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
+ int (*tmpfile) (struct inode *, struct dentry *, umode_t);
locking rules:
all may block
@@ -93,6 +92,7 @@ removexattr: yes
fiemap: no
update_time: no
atomic_open: yes
+tmpfile: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
@@ -344,25 +344,38 @@ prototypes:
locking rules:
- file_lock_lock may block
+ inode->i_lock may block
fl_copy_lock: yes no
fl_release_private: maybe no
----------------------- lock_manager_operations ---------------------------
prototypes:
int (*lm_compare_owner)(struct file_lock *, struct file_lock *);
+ unsigned long (*lm_owner_key)(struct file_lock *);
void (*lm_notify)(struct file_lock *); /* unblock callback */
int (*lm_grant)(struct file_lock *, struct file_lock *, int);
void (*lm_break)(struct file_lock *); /* break_lease callback */
int (*lm_change)(struct file_lock **, int);
locking rules:
- file_lock_lock may block
-lm_compare_owner: yes no
-lm_notify: yes no
-lm_grant: no no
-lm_break: yes no
-lm_change yes no
+
+ inode->i_lock blocked_lock_lock may block
+lm_compare_owner: yes[1] maybe no
+lm_owner_key yes[1] yes no
+lm_notify: yes yes no
+lm_grant: no no no
+lm_break: yes no no
+lm_change yes no no
+
+[1]: ->lm_compare_owner and ->lm_owner_key are generally called with
+*an* inode->i_lock held. It may not be the i_lock of the inode
+associated with either file_lock argument! This is the case with deadlock
+detection, since the code has to chase down the owners of locks that may
+be entirely unrelated to the one on which the lock is being acquired.
+For deadlock detection however, the blocked_lock_lock is also held. The
+fact that these locks are held ensures that the file_locks do not
+disappear out from under you while doing the comparison or generating an
+owner key.
--------------------------- buffer_head -----------------------------------
prototypes:
diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
index f7433355394a..41fd757997b3 100644
--- a/Documentation/filesystems/jfs.txt
+++ b/Documentation/filesystems/jfs.txt
@@ -42,7 +42,7 @@ nodiscard(*) block device when blocks are freed. This is useful for SSD
devices and sparse/thinly-provisioned LUNs. The FITRIM ioctl
command is also available together with the nodiscard option.
The value of minlen specifies the minimum blockcount, when
- a TRIM command to the block device is considered usefull.
+ a TRIM command to the block device is considered useful.
When no value is given to the discard option, it defaults to
64 blocks, which means 256KiB in JFS.
The minlen value of discard overrides the minlen value given
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index fd8d0d594fc7..fcc22c982a25 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -473,7 +473,8 @@ This file is only present if the CONFIG_MMU kernel configuration option is
enabled.
The /proc/PID/clear_refs is used to reset the PG_Referenced and ACCESSED/YOUNG
-bits on both physical and virtual pages associated with a process.
+bits on both physical and virtual pages associated with a process, and the
+soft-dirty bit on pte (see Documentation/vm/soft-dirty.txt for details).
To clear the bits for all the pages associated with the process
> echo 1 > /proc/PID/clear_refs
@@ -482,6 +483,10 @@ To clear the bits for the anonymous pages associated with the process
To clear the bits for the file mapped pages associated with the process
> echo 3 > /proc/PID/clear_refs
+
+To clear the soft-dirty bit
+ > echo 4 > /proc/PID/clear_refs
+
Any other value written to /proc/PID/clear_refs will have no effect.
The /proc/pid/pagemap gives the PFN, which can be used to find the pageflags
diff --git a/Documentation/filesystems/qnx6.txt b/Documentation/filesystems/qnx6.txt
index e59f2f09f56e..99e90184a72f 100644
--- a/Documentation/filesystems/qnx6.txt
+++ b/Documentation/filesystems/qnx6.txt
@@ -148,7 +148,7 @@ smaller than addressing space in the bitmap.
Bitmap system area
------------------
-The bitmap itself is devided into three parts.
+The bitmap itself is divided into three parts.
First the system area, that is split into two halfs.
Then userspace.
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index 4a93e98b290a..aa1f459fa6cf 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -307,7 +307,7 @@ the following:
<proceeding files...>
<slot #3, id = 0x43, characters = "h is long">
- <slot #2, id = 0x02, characters = "xtension whic">
+ <slot #2, id = 0x02, characters = "xtension which">
<slot #1, id = 0x01, characters = "My Big File.E">
<directory entry, name = "MYBIGFIL.EXT">
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index e6bd1ffd821e..f93a88250a44 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -360,6 +360,8 @@ struct inode_operations {
int (*removexattr) (struct dentry *, const char *);
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *,
+ int (*tmpfile) (struct inode *, struct dentry *, umode_t);
+} ____cacheline_aligned;
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
};
@@ -472,6 +474,9 @@ otherwise noted.
component is negative or needs lookup. Cached positive dentries are
still handled by f_op->open().
+ tmpfile: called in the end of O_TMPFILE open(). Optional, equivalent to
+ atomically creating, opening and unlinking a file in given directory.
+
The Address Space Object
========================
@@ -554,7 +559,6 @@ your filesystem. The following members are defined:
struct address_space_operations {
int (*writepage)(struct page *page, struct writeback_control *wbc);
int (*readpage)(struct file *, struct page *);
- int (*sync_page)(struct page *);
int (*writepages)(struct address_space *, struct writeback_control *);
int (*set_page_dirty)(struct page *page);
int (*readpages)(struct file *filp, struct address_space *mapping,
@@ -576,6 +580,9 @@ struct address_space_operations {
/* migrate the contents of a page to the specified target */
int (*migratepage) (struct page *, struct page *);
int (*launder_page) (struct page *);
+ int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
+ unsigned long);
+ void (*is_dirty_writeback) (struct page *, bool *, bool *);
int (*error_remove_page) (struct mapping *mapping, struct page *page);
int (*swap_activate)(struct file *);
int (*swap_deactivate)(struct file *);
@@ -607,13 +614,6 @@ struct address_space_operations {
In this case, the page will be relocated, relocked and if
that all succeeds, ->readpage will be called again.
- sync_page: called by the VM to notify the backing store to perform all
- queued I/O operations for a page. I/O operations for other pages
- associated with this address_space object may also be performed.
-
- This function is optional and is called only for pages with
- PG_Writeback set while waiting for the writeback to complete.
-
writepages: called by the VM to write out pages associated with the
address_space object. If wbc->sync_mode is WBC_SYNC_ALL, then
the writeback_control will specify a range of pages that must be
@@ -742,6 +742,20 @@ struct address_space_operations {
prevent redirtying the page, it is kept locked during the whole
operation.
+ is_partially_uptodate: Called by the VM when reading a file through the
+ pagecache when the underlying blocksize != pagesize. If the required
+ block is up to date then the read can complete without needing the IO
+ to bring the whole page up to date.
+
+ is_dirty_writeback: Called by the VM when attempting to reclaim a page.
+ The VM uses dirty and writeback information to determine if it needs
+ to stall to allow flushers a chance to complete some IO. Ordinarily
+ it can use PageDirty and PageWriteback but some filesystems have
+ more complex state (unstable pages in NFS prevent reclaim) or
+ do not set those flags due to locking problems (jbd). This callback
+ allows a filesystem to indicate to the VM if a page should be
+ treated as dirty or writeback for the purposes of stalling.
+
error_remove_page: normally set to generic_error_remove_page if truncation
is ok for this address space. Used for memory failure handling.
Setting this implies you deal with pages going away under you,
@@ -901,10 +915,8 @@ defined:
struct dentry_operations {
int (*d_revalidate)(struct dentry *, unsigned int);
int (*d_weak_revalidate)(struct dentry *, unsigned int);
- int (*d_hash)(const struct dentry *, const struct inode *,
- struct qstr *);
- int (*d_compare)(const struct dentry *, const struct inode *,
- const struct dentry *, const struct inode *,
+ int (*d_hash)(const struct dentry *, struct qstr *);
+ int (*d_compare)(const struct dentry *, const struct dentry *,
unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *);
void (*d_release)(struct dentry *);
@@ -949,25 +961,24 @@ struct dentry_operations {
d_hash: called when the VFS adds a dentry to the hash table. The first
dentry passed to d_hash is the parent directory that the name is
- to be hashed into. The inode is the dentry's inode.
+ to be hashed into.
Same locking and synchronisation rules as d_compare regarding
what is safe to dereference etc.
d_compare: called to compare a dentry name with a given name. The first
dentry is the parent of the dentry to be compared, the second is
- the parent's inode, then the dentry and inode (may be NULL) of the
- child dentry. len and name string are properties of the dentry to be
- compared. qstr is the name to compare it with.
+ the child dentry. len and name string are properties of the dentry
+ to be compared. qstr is the name to compare it with.
Must be constant and idempotent, and should not take locks if
- possible, and should not or store into the dentry or inodes.
- Should not dereference pointers outside the dentry or inodes without
+ possible, and should not or store into the dentry.
+ Should not dereference pointers outside the dentry without
lots of care (eg. d_parent, d_inode, d_name should not be used).
However, our vfsmount is pinned, and RCU held, so the dentries and
inodes won't disappear, neither will our sb or filesystem module.
- ->i_sb and ->d_sb may be used.
+ ->d_sb may be used.
It is a tricky calling convention because it needs to be called under
"rcu-walk", ie. without any locks or references on things.
diff --git a/Documentation/hwmon/ds1621 b/Documentation/hwmon/ds1621
index 5e97f333c4df..896cdc972ca8 100644
--- a/Documentation/hwmon/ds1621
+++ b/Documentation/hwmon/ds1621
@@ -2,16 +2,30 @@ Kernel driver ds1621
====================
Supported chips:
- * Dallas Semiconductor DS1621
+ * Dallas Semiconductor / Maxim Integrated DS1621
Prefix: 'ds1621'
- Addresses scanned: I2C 0x48 - 0x4f
- Datasheet: Publicly available at the Dallas Semiconductor website
- http://www.dalsemi.com/
+ Addresses scanned: none
+ Datasheet: Publicly available from www.maximintegrated.com
+
* Dallas Semiconductor DS1625
- Prefix: 'ds1621'
- Addresses scanned: I2C 0x48 - 0x4f
- Datasheet: Publicly available at the Dallas Semiconductor website
- http://www.dalsemi.com/
+ Prefix: 'ds1625'
+ Addresses scanned: none
+ Datasheet: Publicly available from www.datasheetarchive.com
+
+ * Maxim Integrated DS1631
+ Prefix: 'ds1631'
+ Addresses scanned: none
+ Datasheet: Publicly available from www.maximintegrated.com
+
+ * Maxim Integrated DS1721
+ Prefix: 'ds1721'
+ Addresses scanned: none
+ Datasheet: Publicly available from www.maximintegrated.com
+
+ * Maxim Integrated DS1731
+ Prefix: 'ds1731'
+ Addresses scanned: none
+ Datasheet: Publicly available from www.maximintegrated.com
Authors:
Christian W. Zuckschwerdt <zany@triq.net>
@@ -59,5 +73,115 @@ any of the limits have ever been met or exceeded since last power-up or
reset. Be aware: When testing, it showed that the status of Tout can change
with neither of the alarms set.
-Temperature conversion of the DS1621 takes up to 1000ms; internal access to
-non-volatile registers may last for 10ms or below.
+Since there is no version or vendor identification register, there is
+no unique identification for these devices. Therefore, explicit device
+instantiation is required for correct device identification and functionality
+(one device per address in this address range: 0x48..0x4f).
+
+The DS1625 is pin compatible and functionally equivalent with the DS1621,
+but the DS1621 is meant to replace it. The DS1631, DS1721, and DS1731 are
+also pin compatible with the DS1621 and provide multi-resolution support.
+
+Additionally, the DS1721 data sheet says the temperature flags (THF and TLF)
+are used internally, however, these flags do get set and cleared as the actual
+temperature crosses the min or max settings (which by default are set to 75
+and 80 degrees respectively).
+
+Temperature Conversion:
+-----------------------
+DS1621 - 750ms (older devices may take up to 1000ms)
+DS1625 - 500ms
+DS1631 - 93ms..750ms for 9..12 bits resolution, respectively.
+DS1721 - 93ms..750ms for 9..12 bits resolution, respectively.
+DS1731 - 93ms..750ms for 9..12 bits resolution, respectively.
+
+Note:
+On the DS1621, internal access to non-volatile registers may last for 10ms
+or less (unverified on the other devices).
+
+Temperature Accuracy:
+---------------------
+DS1621: +/- 0.5 degree Celsius (from 0 to +70 degrees)
+DS1625: +/- 0.5 degree Celsius (from 0 to +70 degrees)
+DS1631: +/- 0.5 degree Celsius (from 0 to +70 degrees)
+DS1721: +/- 1.0 degree Celsius (from -10 to +85 degrees)
+DS1731: +/- 1.0 degree Celsius (from -10 to +85 degrees)
+
+Note:
+Please refer to the device datasheets for accuracy at other temperatures.
+
+Temperature Resolution:
+-----------------------
+As mentioned above, the DS1631, DS1721, and DS1731 provide multi-resolution
+support, which is achieved via the R0 and R1 config register bits, where:
+
+R0..R1
+------
+ 0 0 => 9 bits, 0.5 degrees Celcius
+ 1 0 => 10 bits, 0.25 degrees Celcius
+ 0 1 => 11 bits, 0.125 degrees Celcius
+ 1 1 => 12 bits, 0.0625 degrees Celcius
+
+Note:
+At initial device power-on, the default resolution is set to 12-bits.
+
+The resolution mode for the DS1631, DS1721, or DS1731 can be changed from
+userspace, via the device 'update_interval' sysfs attribute. This attribute
+will normalize the range of input values to the device maximum resolution
+values defined in the datasheet as follows:
+
+Resolution Conversion Time Input Range
+ (C/LSB) (msec) (msec)
+------------------------------------------------
+0.5 93.75 0....94
+0.25 187.5 95...187
+0.125 375 188..375
+0.0625 750 376..infinity
+------------------------------------------------
+
+The following examples show how the 'update_interval' attribute can be
+used to change the conversion time:
+
+$ cat update_interval
+750
+$ cat temp1_input
+22062
+$
+$ echo 300 > update_interval
+$ cat update_interval
+375
+$ cat temp1_input
+22125
+$
+$ echo 150 > update_interval
+$ cat update_interval
+188
+$ cat temp1_input
+22250
+$
+$ echo 1 > update_interval
+$ cat update_interval
+94
+$ cat temp1_input
+22000
+$
+$ echo 1000 > update_interval
+$ cat update_interval
+750
+$ cat temp1_input
+22062
+$
+
+As shown, the ds1621 driver automatically adjusts the 'update_interval'
+user input, via a step function. Reading back the 'update_interval' value
+after a write operation provides the conversion time used by the device.
+
+Mathematically, the resolution can be derived from the conversion time
+via the following function:
+
+ g(x) = 0.5 * [minimum_conversion_time/x]
+
+where:
+ -> 'x' = the output from 'update_interval'
+ -> 'g(x)' = the resolution in degrees C per LSB.
+ -> 93.75ms = minimum conversion time
diff --git a/Documentation/hwmon/g762 b/Documentation/hwmon/g762
new file mode 100644
index 000000000000..923db9c5b5bc
--- /dev/null
+++ b/Documentation/hwmon/g762
@@ -0,0 +1,65 @@
+Kernel driver g762
+==================
+
+The GMT G762 Fan Speed PWM Controller is connected directly to a fan
+and performs closed-loop or open-loop control of the fan speed. Two
+modes - PWM or DC - are supported by the device.
+
+For additional information, a detailed datasheet is available at
+http://natisbad.org/NAS/ref/GMT_EDS-762_763-080710-0.2.pdf. sysfs
+bindings are described in Documentation/hwmon/sysfs-interface.
+
+The following entries are available to the user in a subdirectory of
+/sys/bus/i2c/drivers/g762/ to control the operation of the device.
+This can be done manually using the following entries but is usually
+done via a userland daemon like fancontrol.
+
+Note that those entries do not provide ways to setup the specific
+hardware characteristics of the system (reference clock, pulses per
+fan revolution, ...); Those can be modified via devicetree bindings
+documented in Documentation/devicetree/bindings/hwmon/g762.txt or
+using a specific platform_data structure in board initialization
+file (see include/linux/platform_data/g762.h).
+
+ fan1_target: set desired fan speed. This only makes sense in closed-loop
+ fan speed control (i.e. when pwm1_enable is set to 2).
+
+ fan1_input: provide current fan rotation value in RPM as reported by
+ the fan to the device.
+
+ fan1_div: fan clock divisor. Supported value are 1, 2, 4 and 8.
+
+ fan1_pulses: number of pulses per fan revolution. Supported values
+ are 2 and 4.
+
+ fan1_fault: reports fan failure, i.e. no transition on fan gear pin for
+ about 0.7s (if the fan is not voluntarily set off).
+
+ fan1_alarm: in closed-loop control mode, if fan RPM value is 25% out
+ of the programmed value for over 6 seconds 'fan1_alarm' is
+ set to 1.
+
+ pwm1_enable: set current fan speed control mode i.e. 1 for manual fan
+ speed control (open-loop) via pwm1 described below, 2 for
+ automatic fan speed control (closed-loop) via fan1_target
+ above.
+
+ pwm1_mode: set or get fan driving mode: 1 for PWM mode, 0 for DC mode.
+
+ pwm1: get or set PWM fan control value in open-loop mode. This is an
+ integer value between 0 and 255. 0 stops the fan, 255 makes
+ it run at full speed.
+
+Both in PWM mode ('pwm1_mode' set to 1) and DC mode ('pwm1_mode' set to 0),
+when current fan speed control mode is open-loop ('pwm1_enable' set to 1),
+the fan speed is programmed by setting a value between 0 and 255 via 'pwm1'
+entry (0 stops the fan, 255 makes it run at full speed). In closed-loop mode
+('pwm1_enable' set to 2), the expected rotation speed in RPM can be passed to
+the chip via 'fan1_target'. In closed-loop mode, the target speed is compared
+with current speed (available via 'fan1_input') by the device and a feedback
+is performed to match that target value. The fan speed value is computed
+based on the parameters associated with the physical characteristics of the
+system: a reference clock source frequency, a number of pulses per fan
+revolution, etc.
+
+Note that the driver will update its values at most once per second.
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
index 03444f9d833f..4223c2d3b508 100644
--- a/Documentation/hwmon/ina2xx
+++ b/Documentation/hwmon/ina2xx
@@ -44,4 +44,6 @@ The INA226 monitors both a shunt voltage drop and bus supply voltage.
The INA230 is a high or low side current shunt and power monitor with an I2C
interface. The INA230 monitors both a shunt voltage drop and bus supply voltage.
-The shunt value in micro-ohms can be set via platform data.
+The shunt value in micro-ohms can be set via platform data or device tree.
+Please refer to the Documentation/devicetree/bindings/i2c/ina2xx.txt for bindings
+if the device tree is used.
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index d55b8ab2d10f..d29dea0f3232 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -24,6 +24,7 @@ Supported adapters:
* Intel Lynx Point-LP (PCH)
* Intel Avoton (SOC)
* Intel Wellsburg (PCH)
+ * Intel Coleto Creek (PCH)
Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
index 1e6634f54c50..a370b2047cf3 100644
--- a/Documentation/i2c/busses/i2c-piix4
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -13,7 +13,7 @@ Supported adapters:
* AMD SP5100 (SB700 derivative found on some server mainboards)
Datasheet: Publicly available at the AMD website
http://support.amd.com/us/Embedded_TechDocs/44413.pdf
- * AMD Hudson-2
+ * AMD Hudson-2, CZ
Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
Datasheet: Publicly available at the SMSC website http://www.smsc.com
diff --git a/Documentation/input/multi-touch-protocol.txt b/Documentation/input/multi-touch-protocol.txt
index 2c179613f81b..de139b18184a 100644
--- a/Documentation/input/multi-touch-protocol.txt
+++ b/Documentation/input/multi-touch-protocol.txt
@@ -80,6 +80,8 @@ Userspace can detect that a driver can report more total contacts than slots
by noting that the largest supported BTN_TOOL_*TAP event is larger than the
total number of type B slots reported in the absinfo for the ABS_MT_SLOT axis.
+The minimum value of the ABS_MT_SLOT axis must be 0.
+
Protocol Example A
------------------
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 237acab169dd..2a5f0e14efa3 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -72,6 +72,7 @@ Code Seq#(hex) Include File Comments
0x06 all linux/lp.h
0x09 all linux/raid/md_u.h
0x10 00-0F drivers/char/s390/vmcp.h
+0x10 10-1F arch/s390/include/uapi/sclp_ctl.h
0x12 all linux/fs.h
linux/blkpg.h
0x1b all InfiniBand Subsystem <http://infiniband.sourceforge.net/>
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index 213859e69e88..e349f293cc98 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -174,6 +174,19 @@ Searching in menuconfig:
/^hotplug
+ When searching, symbols are sorted thus:
+ - exact match first: an exact match is when the search matches
+ the complete symbol name;
+ - alphabetical order: when two symbols do not match exactly,
+ they are sorted in alphabetical order (in the user's current
+ locale).
+ For example: ^ATH.K matches:
+ ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
+ [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
+ of which only ATH5K and ATH9K match exactly and so are sorted
+ first (and in alphabetical order), then come all other symbols,
+ sorted in alphabetical order.
+
______________________________________________________________________
User interface options for 'menuconfig'
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 9c7fd988e299..88d5a863712a 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -47,19 +47,12 @@ parameter. Optionally the size of the ELF header can also be passed
when using the elfcorehdr=[size[KMG]@]offset[KMG] syntax.
-With the dump-capture kernel, you can access the memory image, or "old
-memory," in two ways:
-
-- Through a /dev/oldmem device interface. A capture utility can read the
- device file and write out the memory in raw format. This is a raw dump
- of memory. Analysis and capture tools must be intelligent enough to
- determine where to look for the right information.
-
-- Through /proc/vmcore. This exports the dump as an ELF-format file that
- you can write out using file copy commands such as cp or scp. Further,
- you can use analysis tools such as the GNU Debugger (GDB) and the Crash
- tool to debug the dump file. This method ensures that the dump pages are
- correctly ordered.
+With the dump-capture kernel, you can access the memory image through
+/proc/vmcore. This exports the dump as an ELF-format file that you can
+write out using file copy commands such as cp or scp. Further, you can
+use analysis tools such as the GNU Debugger (GDB) and the Crash tool to
+debug the dump file. This method ensures that the dump pages are correctly
+ordered.
Setup and Installation
@@ -423,18 +416,6 @@ the following command:
cp /proc/vmcore <dump-file>
-You can also access dumped memory as a /dev/oldmem device for a linear
-and raw view. To create the device, use the following command:
-
- mknod /dev/oldmem c 1 12
-
-Use the dd command with suitable options for count, bs, and skip to
-access specific portions of the dump.
-
-To see the entire memory, use the following command:
-
- dd if=/dev/oldmem of=oldmem.001
-
Analysis
========
@@ -461,14 +442,6 @@ format. Crash is available on Dave Anderson's site at the following URL:
http://people.redhat.com/~anderson/
-To Do
-=====
-
-1) Provide relocatable kernels for all architectures to help in maintaining
- multiple kernels for crash_dump, and the same kernel as the system kernel
- can be used to capture the dump.
-
-
Contact
=======
diff --git a/Documentation/kernel-doc-nano-HOWTO.txt b/Documentation/kernel-doc-nano-HOWTO.txt
index 99b57abddf8a..acbc1a3d0d91 100644
--- a/Documentation/kernel-doc-nano-HOWTO.txt
+++ b/Documentation/kernel-doc-nano-HOWTO.txt
@@ -142,9 +142,10 @@ are:
- Makefile
- The targets 'sgmldocs', 'psdocs', 'pdfdocs', and 'htmldocs' are used
- to build DocBook files, PostScript files, PDF files, and html files
- in Documentation/DocBook.
+ The targets 'xmldocs', 'psdocs', 'pdfdocs', and 'htmldocs' are used
+ to build XML DocBook files, PostScript files, PDF files, and html files
+ in Documentation/DocBook. The older target 'sgmldocs' is equivalent
+ to 'xmldocs'.
- Documentation/DocBook/Makefile
@@ -158,8 +159,8 @@ If you just want to read the ready-made books on the various
subsystems (see Documentation/DocBook/*.tmpl), just type 'make
psdocs', or 'make pdfdocs', or 'make htmldocs', depending on your
preference. If you would rather read a different format, you can type
-'make sgmldocs' and then use DocBook tools to convert
-Documentation/DocBook/*.sgml to a format of your choice (for example,
+'make xmldocs' and then use DocBook tools to convert
+Documentation/DocBook/*.xml to a format of your choice (for example,
'db2html ...' if 'make htmldocs' was not defined).
If you want to see man pages instead, you can do this:
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 2fe6e767b3d6..15356aca938c 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1129,11 +1129,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
The builtin appraise policy appraises all files
owned by uid=0.
- ima_audit= [IMA]
- Format: { "0" | "1" }
- 0 -- integrity auditing messages. (Default)
- 1 -- enable informational integrity auditing messages.
-
ima_hash= [IMA]
Format: { "sha1" | "md5" }
default: "sha1"
@@ -1158,6 +1153,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
inport.irq= [HW] Inport (ATI XL and Microsoft) busmouse driver
Format: <irq>
+ int_pln_enable [x86] Enable power limit notification interrupt
+
+ integrity_audit=[IMA]
+ Format: { "0" | "1" }
+ 0 -- basic integrity auditing messages. (Default)
+ 1 -- additional integrity auditing messages.
+
intel_iommu= [DMAR] Intel IOMMU driver (DMAR) option
on
Enable intel iommu driver.
@@ -1456,6 +1458,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
* dump_id: dump IDENTIFY data.
+ * atapi_dmadir: Enable ATAPI DMADIR bridge support
+
If there are multiple matching configurations changing
the same attribute, the last one is used.
@@ -2677,9 +2681,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Run specified binary instead of /init from the ramdisk,
used for early userspace startup. See initrd.
- reboot= [BUGS=X86-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
- Format: <reboot_mode>[,<reboot_mode2>[,...]]
- See arch/*/kernel/reboot.c or arch/*/kernel/process.c
+ reboot= [KNL]
+ Format (x86 or x86_64):
+ [w[arm] | c[old] | h[ard] | s[oft] | g[pio]] \
+ [[,]s[mp]#### \
+ [[,]b[ios] | a[cpi] | k[bd] | t[riple] | e[fi] | p[ci]] \
+ [[,]f[orce]
+ Where reboot_mode is one of warm (soft) or cold (hard) or gpio,
+ reboot_type is one of bios, acpi, kbd, triple, efi, or pci,
+ reboot_force is either force or not specified,
+ reboot_cpu is s[mp]#### with #### being the processor
+ to be used for rebooting.
relax_domain_level=
[KNL, SMP] Set scheduler's default relax_domain_level.
@@ -3069,6 +3081,19 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
See also Documentation/trace/ftrace.txt "trace options"
section.
+ traceoff_on_warning
+ [FTRACE] enable this option to disable tracing when a
+ warning is hit. This turns off "tracing_on". Tracing can
+ be enabled again by echoing '1' into the "tracing_on"
+ file located in /sys/kernel/debug/tracing/
+
+ This option is useful, as it disables the trace before
+ the WARNING dump is called, which prevents the trace to
+ be filled with content caused by the warning output.
+
+ This option can also be set at run time via the sysctl
+ option: kernel/traceoff_on_warning
+
transparent_hugepage=
[KNL]
Format: [always|madvise|never]
@@ -3229,6 +3254,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
video= [FB] Frame buffer configuration
See Documentation/fb/modedb.txt.
+ video.brightness_switch_enabled= [0,1]
+ If set to 1, on receiving an ACPI notify event
+ generated by hotkey, video driver will adjust brightness
+ level and then send out the event to user space through
+ the allocated input device; If set to 0, video driver
+ will only send out the event without touching backlight
+ brightness level.
+ default: 1
+
virtio_mmio.device=
[VMMIO] Memory mapped virtio (platform) device.
@@ -3341,6 +3375,21 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
that this also can be controlled per-workqueue for
workqueues visible under /sys/bus/workqueue/.
+ workqueue.power_efficient
+ Per-cpu workqueues are generally preferred because
+ they show better performance thanks to cache
+ locality; unfortunately, per-cpu workqueues tend to
+ be more power hungry than unbound workqueues.
+
+ Enabling this makes the per-cpu workqueues which
+ were observed to contribute significantly to power
+ consumption unbound, leading to measurably lower
+ power usage at the cost of small performance
+ overhead.
+
+ The default value of this parameter is determined by
+ the config option CONFIG_WQ_POWER_EFFICIENT_DEFAULT.
+
x2apic_phys [X86-64,APIC] Use x2apic physical mode instead of
default x2apic cluster mode on platforms
supporting x2apic.
diff --git a/Documentation/kernel-per-CPU-kthreads.txt b/Documentation/kernel-per-CPU-kthreads.txt
index 5f39ef55c6f6..32351bfabf20 100644
--- a/Documentation/kernel-per-CPU-kthreads.txt
+++ b/Documentation/kernel-per-CPU-kthreads.txt
@@ -232,7 +232,7 @@ Purpose: Offload RCU callbacks from the corresponding CPU.
To reduce its OS jitter, do at least one of the following:
1. Use affinity, cgroups, or other mechanism to force these kthreads
to execute on some other CPU.
-2. Build with CONFIG_RCU_NOCB_CPUS=n, which will prevent these
+2. Build with CONFIG_RCU_NOCB_CPU=n, which will prevent these
kthreads from being created in the first place. However, please
note that this will not eliminate OS jitter, but will instead
shift it to RCU_SOFTIRQ.
diff --git a/Documentation/laptops/dslm.c b/Documentation/laptops/dslm.c
index 72ff290c5fc6..d5dd2d4b04d8 100644
--- a/Documentation/laptops/dslm.c
+++ b/Documentation/laptops/dslm.c
@@ -2,7 +2,7 @@
* dslm.c
* Simple Disk Sleep Monitor
* by Bartek Kania
- * Licenced under the GPL
+ * Licensed under the GPL
*/
#include <unistd.h>
#include <stdlib.h>
diff --git a/Documentation/md.txt b/Documentation/md.txt
index e0ddd327632d..fbb2fcbf16b6 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -566,13 +566,6 @@ also have
when it reaches the current sync_max (below) and possibly at
other times.
- sync_max
- This is a number of sectors at which point a resync/recovery
- process will pause. When a resync is active, the value can
- only ever be increased, never decreased. The value of 'max'
- effectively disables the limit.
-
-
sync_speed
This shows the current actual speed, in K/sec, of the current
sync_action. It is averaged over the last 30 seconds.
@@ -593,6 +586,12 @@ also have
that number to reach sync_max. Then you can either increase
"sync_max", or can write 'idle' to "sync_action".
+ The value of 'max' for "sync_max" effectively disables the limit.
+ When a resync is active, the value can only ever be increased,
+ never decreased.
+ The value of '0' is the minimum for "sync_min".
+
+
Each active md device may also have attributes specific to the
personality module that manages it.
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 77bd0a42f19d..eeced24e56af 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -18,7 +18,7 @@ Abstract media device model
Discovering a device internal topology, and configuring it at runtime, is one
of the goals of the media framework. To achieve this, hardware devices are
-modeled as an oriented graph of building blocks called entities connected
+modelled as an oriented graph of building blocks called entities connected
through pads.
An entity is a basic media hardware building block. It can correspond to
diff --git a/Documentation/metag/kernel-ABI.txt b/Documentation/metag/kernel-ABI.txt
index 7b8dee83b9c1..628216603198 100644
--- a/Documentation/metag/kernel-ABI.txt
+++ b/Documentation/metag/kernel-ABI.txt
@@ -189,7 +189,7 @@ call:
64-bit arguments are placed in matching pairs of registers (i.e. the same
register number in both D0 and D1 units), with the least significant half in D0
-and the most significant half in D1, leaving a gap where necessary. Futher
+and the most significant half in D1, leaving a gap where necessary. Further
arguments are stored on the stack in reverse order (earlier arguments at higher
addresses):
diff --git a/Documentation/misc-devices/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt
index 6ec702950719..15bba1aeba9a 100644
--- a/Documentation/misc-devices/mei/mei.txt
+++ b/Documentation/misc-devices/mei/mei.txt
@@ -120,7 +120,7 @@ The Intel MEI Driver supports the following IOCTL command:
Notes:
max_msg_length (MTU) in client properties describes the maximum
data that can be sent or received. (e.g. if MTU=2K, can send
- requests up to bytes 2k and received responses upto 2k bytes).
+ requests up to bytes 2k and received responses up to 2k bytes).
Intel ME Applications:
==============
diff --git a/Documentation/networking/.gitignore b/Documentation/networking/.gitignore
index 286a5680f490..e69de29bb2d1 100644
--- a/Documentation/networking/.gitignore
+++ b/Documentation/networking/.gitignore
@@ -1 +0,0 @@
-ifenslave
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index 258d9b92c36f..32dfbd924121 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -88,8 +88,6 @@ gianfar.txt
- Gianfar Ethernet Driver.
ieee802154.txt
- Linux IEEE 802.15.4 implementation, API and drivers
-ifenslave.c
- - Configure network interfaces for parallel routing (bonding).
igb.txt
- README for the Intel Gigabit Ethernet Driver (igb).
igbvf.txt
diff --git a/Documentation/networking/Makefile b/Documentation/networking/Makefile
index 24c308dd3fd1..0aa1ac98fc2b 100644
--- a/Documentation/networking/Makefile
+++ b/Documentation/networking/Makefile
@@ -1,11 +1,6 @@
# kbuild trick to avoid linker error. Can be omitted if a module is built.
obj- := dummy.o
-# List of programs to build
-hostprogs-y := ifenslave
-
-HOSTCFLAGS_ifenslave.o += -I$(objtree)/usr/include
-
# Tell kbuild to always build the programs
always := $(hostprogs-y)
diff --git a/Documentation/networking/arcnet.txt b/Documentation/networking/arcnet.txt
index 9ff579502151..aff97f47c05c 100644
--- a/Documentation/networking/arcnet.txt
+++ b/Documentation/networking/arcnet.txt
@@ -70,9 +70,10 @@ list, mail to linux-arcnet@tichy.ch.uj.edu.pl.
There are archives of the mailing list at:
http://epistolary.org/mailman/listinfo.cgi/arcnet
-The people on linux-net@vger.kernel.org have also been known to be very
-helpful, especially when we're talking about ALPHA Linux kernels that may or
-may not work right in the first place.
+The people on linux-net@vger.kernel.org (now defunct, replaced by
+netdev@vger.kernel.org) have also been known to be very helpful, especially
+when we're talking about ALPHA Linux kernels that may or may not work right
+in the first place.
Other Drivers and Info
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 10a015c384b8..87bbcfee2e06 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -104,8 +104,7 @@ Table of Contents
==============================
Most popular distro kernels ship with the bonding driver
-already available as a module and the ifenslave user level control
-program installed and ready for use. If your distro does not, or you
+already available as a module. If your distro does not, or you
have need to compile bonding from source (e.g., configuring and
installing a mainline kernel from kernel.org), you'll need to perform
the following steps:
@@ -124,46 +123,13 @@ device support" section. It is recommended that you configure the
driver as module since it is currently the only way to pass parameters
to the driver or configure more than one bonding device.
- Build and install the new kernel and modules, then continue
-below to install ifenslave.
+ Build and install the new kernel and modules.
-1.2 Install ifenslave Control Utility
+1.2 Bonding Control Utility
-------------------------------------
- The ifenslave user level control program is included in the
-kernel source tree, in the file Documentation/networking/ifenslave.c.
-It is generally recommended that you use the ifenslave that
-corresponds to the kernel that you are using (either from the same
-source tree or supplied with the distro), however, ifenslave
-executables from older kernels should function (but features newer
-than the ifenslave release are not supported). Running an ifenslave
-that is newer than the kernel is not supported, and may or may not
-work.
-
- To install ifenslave, do the following:
-
-# gcc -Wall -O -I/usr/src/linux/include ifenslave.c -o ifenslave
-# cp ifenslave /sbin/ifenslave
-
- If your kernel source is not in "/usr/src/linux," then replace
-"/usr/src/linux/include" in the above with the location of your kernel
-source include directory.
-
- You may wish to back up any existing /sbin/ifenslave, or, for
-testing or informal use, tag the ifenslave to the kernel version
-(e.g., name the ifenslave executable /sbin/ifenslave-2.6.10).
-
-IMPORTANT NOTE:
-
- If you omit the "-I" or specify an incorrect directory, you
-may end up with an ifenslave that is incompatible with the kernel
-you're trying to build it for. Some distros (e.g., Red Hat from 7.1
-onwards) do not have /usr/include/linux symbolically linked to the
-default kernel source include directory.
-
-SECOND IMPORTANT NOTE:
- If you plan to configure bonding using sysfs or using the
-/etc/network/interfaces file, you do not need to use ifenslave.
+ It is recommended to configure bonding via iproute2 (netlink)
+or sysfs, the old ifenslave control utility is obsolete.
2. Bonding Driver Options
=========================
@@ -337,6 +303,12 @@ arp_validate
such a situation, validation of backup slaves must be
disabled.
+ The validation of ARP requests on backup slaves is mainly
+ helping bonding to decide which slaves are more likely to
+ work in case of the active slave failure, it doesn't really
+ guarantee that the backup slave will work if it's selected
+ as the next active slave.
+
This option is useful in network configurations in which
multiple bonding hosts are concurrently issuing ARPs to one or
more targets beyond a common switch. Should the link between
@@ -349,6 +321,25 @@ arp_validate
This option was added in bonding version 3.1.0.
+arp_all_targets
+
+ Specifies the quantity of arp_ip_targets that must be reachable
+ in order for the ARP monitor to consider a slave as being up.
+ This option affects only active-backup mode for slaves with
+ arp_validation enabled.
+
+ Possible values are:
+
+ any or 0
+
+ consider the slave up only when any of the arp_ip_targets
+ is reachable
+
+ all or 1
+
+ consider the slave up only when all of the arp_ip_targets
+ are reachable
+
downdelay
Specifies the time, in milliseconds, to wait before disabling
@@ -851,7 +842,7 @@ resend_igmp
==============================
You can configure bonding using either your distro's network
-initialization scripts, or manually using either ifenslave or the
+initialization scripts, or manually using either iproute2 or the
sysfs interface. Distros generally use one of three packages for the
network initialization scripts: initscripts, sysconfig or interfaces.
Recent versions of these packages have support for bonding, while older
@@ -1160,7 +1151,7 @@ not support this method for specifying multiple bonding interfaces; for
those instances, see the "Configuring Multiple Bonds Manually" section,
below.
-3.3 Configuring Bonding Manually with Ifenslave
+3.3 Configuring Bonding Manually with iproute2
-----------------------------------------------
This section applies to distros whose network initialization
@@ -1171,7 +1162,7 @@ version 8.
The general method for these systems is to place the bonding
module parameters into a config file in /etc/modprobe.d/ (as
appropriate for the installed distro), then add modprobe and/or
-ifenslave commands to the system's global init script. The name of
+`ip link` commands to the system's global init script. The name of
the global init script differs; for sysconfig, it is
/etc/init.d/boot.local and for initscripts it is /etc/rc.d/rc.local.
@@ -1183,8 +1174,8 @@ reboots, edit the appropriate file (/etc/init.d/boot.local or
modprobe bonding mode=balance-alb miimon=100
modprobe e100
ifconfig bond0 192.168.1.1 netmask 255.255.255.0 up
-ifenslave bond0 eth0
-ifenslave bond0 eth1
+ip link set eth0 master bond0
+ip link set eth1 master bond0
Replace the example bonding module parameters and bond0
network configuration (IP address, netmask, etc) with the appropriate
diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt
index 67a9cb259d40..09eb57329f11 100644
--- a/Documentation/networking/ieee802154.txt
+++ b/Documentation/networking/ieee802154.txt
@@ -5,7 +5,7 @@
Introduction
============
The IEEE 802.15.4 working group focuses on standartization of bottom
-two layers: Medium Accsess Control (MAC) and Physical (PHY). And there
+two layers: Medium Access Control (MAC) and Physical (PHY). And there
are mainly two options available for upper layers:
- ZigBee - proprietary protocol from ZigBee Alliance
- 6LowPAN - IPv6 networking over low rate personal area networks
diff --git a/Documentation/networking/ifenslave.c b/Documentation/networking/ifenslave.c
deleted file mode 100644
index ac5debb2f16c..000000000000
--- a/Documentation/networking/ifenslave.c
+++ /dev/null
@@ -1,1105 +0,0 @@
-/* Mode: C;
- * ifenslave.c: Configure network interfaces for parallel routing.
- *
- * This program controls the Linux implementation of running multiple
- * network interfaces in parallel.
- *
- * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov>
- * Copyright 1994-1996 Donald Becker
- *
- * 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.
- *
- * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
- * Center of Excellence in Space Data and Information Sciences
- * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
- *
- * Changes :
- * - 2000/10/02 Willy Tarreau <willy at meta-x.org> :
- * - few fixes. Master's MAC address is now correctly taken from
- * the first device when not previously set ;
- * - detach support : call BOND_RELEASE to detach an enslaved interface.
- * - give a mini-howto from command-line help : # ifenslave -h
- *
- * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> :
- * - Master is now brought down before setting the MAC address. In
- * the 2.4 kernel you can't change the MAC address while the device is
- * up because you get EBUSY.
- *
- * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com>
- * - Added the ability to change the active interface on a mode 1 bond
- * at runtime.
- *
- * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> :
- * - No longer set the MAC address of the master. The bond device will
- * take care of this itself
- * - Try the SIOC*** versions of the bonding ioctls before using the
- * old versions
- * - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
- * - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
- * SIOCGIFFLAGS now called before hwaddr_notset test
- *
- * - 2002/10/31 Tony Cureington <tony.cureington * hp_com> :
- * - If the master does not have a hardware address when the first slave
- * is enslaved, the master is assigned the hardware address of that
- * slave - there is a comment in bonding.c stating "ifenslave takes
- * care of this now." This corrects the problem of slaves having
- * different hardware addresses in active-backup mode when
- * multiple interfaces are specified on a single ifenslave command
- * (ifenslave bond0 eth0 eth1).
- *
- * - 2003/03/18 - Tsippy Mendelson <tsippy.mendelson at intel dot com> and
- * Shmulik Hen <shmulik.hen at intel dot com>
- * - Moved setting the slave's mac address and openning it, from
- * the application to the driver. This enables support of modes
- * that need to use the unique mac address of each slave.
- * The driver also takes care of closing the slave and restoring its
- * original mac address upon release.
- * In addition, block possibility of enslaving before the master is up.
- * This prevents putting the system in an undefined state.
- *
- * - 2003/05/01 - Amir Noam <amir.noam at intel dot com>
- * - Added ABI version control to restore compatibility between
- * new/old ifenslave and new/old bonding.
- * - Prevent adding an adapter that is already a slave.
- * Fixes the problem of stalling the transmission and leaving
- * the slave in a down state.
- *
- * - 2003/05/01 - Shmulik Hen <shmulik.hen at intel dot com>
- * - Prevent enslaving if the bond device is down.
- * Fixes the problem of leaving the system in unstable state and
- * halting when trying to remove the module.
- * - Close socket on all abnormal exists.
- * - Add versioning scheme that follows that of the bonding driver.
- * current version is 1.0.0 as a base line.
- *
- * - 2003/05/22 - Jay Vosburgh <fubar at us dot ibm dot com>
- * - ifenslave -c was broken; it's now fixed
- * - Fixed problem with routes vanishing from master during enslave
- * processing.
- *
- * - 2003/05/27 - Amir Noam <amir.noam at intel dot com>
- * - Fix backward compatibility issues:
- * For drivers not using ABI versions, slave was set down while
- * it should be left up before enslaving.
- * Also, master was not set down and the default set_mac_address()
- * would fail and generate an error message in the system log.
- * - For opt_c: slave should not be set to the master's setting
- * while it is running. It was already set during enslave. To
- * simplify things, it is now handled separately.
- *
- * - 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
- * - Code cleanup and style changes
- * set version to 1.1.0
- */
-
-#define APP_VERSION "1.1.0"
-#define APP_RELDATE "December 1, 2003"
-#define APP_NAME "ifenslave"
-
-static char *version =
-APP_NAME ".c:v" APP_VERSION " (" APP_RELDATE ")\n"
-"o Donald Becker (becker@cesdis.gsfc.nasa.gov).\n"
-"o Detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n"
-"o 2.4 kernel support added on 2001/02/16 by Chad N. Tindel\n"
-" (ctindel at ieee dot org).\n";
-
-static const char *usage_msg =
-"Usage: ifenslave [-f] <master-if> <slave-if> [<slave-if>...]\n"
-" ifenslave -d <master-if> <slave-if> [<slave-if>...]\n"
-" ifenslave -c <master-if> <slave-if>\n"
-" ifenslave --help\n";
-
-static const char *help_msg =
-"\n"
-" To create a bond device, simply follow these three steps :\n"
-" - ensure that the required drivers are properly loaded :\n"
-" # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n"
-" - assign an IP address to the bond device :\n"
-" # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n"
-" - attach all the interfaces you need to the bond device :\n"
-" # ifenslave [{-f|--force}] bond0 eth0 [eth1 [eth2]...]\n"
-" If bond0 didn't have a MAC address, it will take eth0's. Then, all\n"
-" interfaces attached AFTER this assignment will get the same MAC addr.\n"
-" (except for ALB/TLB modes)\n"
-"\n"
-" To set the bond device down and automatically release all the slaves :\n"
-" # ifconfig bond0 down\n"
-"\n"
-" To detach a dead interface without setting the bond device down :\n"
-" # ifenslave {-d|--detach} bond0 eth0 [eth1 [eth2]...]\n"
-"\n"
-" To change active slave :\n"
-" # ifenslave {-c|--change-active} bond0 eth0\n"
-"\n"
-" To show master interface info\n"
-" # ifenslave bond0\n"
-"\n"
-" To show all interfaces info\n"
-" # ifenslave {-a|--all-interfaces}\n"
-"\n"
-" To be more verbose\n"
-" # ifenslave {-v|--verbose} ...\n"
-"\n"
-" # ifenslave {-u|--usage} Show usage\n"
-" # ifenslave {-V|--version} Show version\n"
-" # ifenslave {-h|--help} This message\n"
-"\n";
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <linux/if.h>
-#include <net/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/if_bonding.h>
-#include <linux/sockios.h>
-
-typedef unsigned long long u64; /* hack, so we may include kernel's ethtool.h */
-typedef __uint32_t u32; /* ditto */
-typedef __uint16_t u16; /* ditto */
-typedef __uint8_t u8; /* ditto */
-#include <linux/ethtool.h>
-
-struct option longopts[] = {
- /* { name has_arg *flag val } */
- {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */
- {"change-active", 0, 0, 'c'}, /* Change the active slave. */
- {"detach", 0, 0, 'd'}, /* Detach a slave interface. */
- {"force", 0, 0, 'f'}, /* Force the operation. */
- {"help", 0, 0, 'h'}, /* Give help */
- {"usage", 0, 0, 'u'}, /* Give usage */
- {"verbose", 0, 0, 'v'}, /* Report each action taken. */
- {"version", 0, 0, 'V'}, /* Emit version information. */
- { 0, 0, 0, 0}
-};
-
-/* Command-line flags. */
-unsigned int
-opt_a = 0, /* Show-all-interfaces flag. */
-opt_c = 0, /* Change-active-slave flag. */
-opt_d = 0, /* Detach a slave interface. */
-opt_f = 0, /* Force the operation. */
-opt_h = 0, /* Help */
-opt_u = 0, /* Usage */
-opt_v = 0, /* Verbose flag. */
-opt_V = 0; /* Version */
-
-int skfd = -1; /* AF_INET socket for ioctl() calls.*/
-int abi_ver = 0; /* userland - kernel ABI version */
-int hwaddr_set = 0; /* Master's hwaddr is set */
-int saved_errno;
-
-struct ifreq master_mtu, master_flags, master_hwaddr;
-struct ifreq slave_mtu, slave_flags, slave_hwaddr;
-
-struct dev_ifr {
- struct ifreq *req_ifr;
- char *req_name;
- int req_type;
-};
-
-struct dev_ifr master_ifra[] = {
- {&master_mtu, "SIOCGIFMTU", SIOCGIFMTU},
- {&master_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS},
- {&master_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR},
- {NULL, "", 0}
-};
-
-struct dev_ifr slave_ifra[] = {
- {&slave_mtu, "SIOCGIFMTU", SIOCGIFMTU},
- {&slave_flags, "SIOCGIFFLAGS", SIOCGIFFLAGS},
- {&slave_hwaddr, "SIOCGIFHWADDR", SIOCGIFHWADDR},
- {NULL, "", 0}
-};
-
-static void if_print(char *ifname);
-static int get_drv_info(char *master_ifname);
-static int get_if_settings(char *ifname, struct dev_ifr ifra[]);
-static int get_slave_flags(char *slave_ifname);
-static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr);
-static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr);
-static int set_slave_mtu(char *slave_ifname, int mtu);
-static int set_if_flags(char *ifname, short flags);
-static int set_if_up(char *ifname, short flags);
-static int set_if_down(char *ifname, short flags);
-static int clear_if_addr(char *ifname);
-static int set_if_addr(char *master_ifname, char *slave_ifname);
-static int change_active(char *master_ifname, char *slave_ifname);
-static int enslave(char *master_ifname, char *slave_ifname);
-static int release(char *master_ifname, char *slave_ifname);
-#define v_print(fmt, args...) \
- if (opt_v) \
- fprintf(stderr, fmt, ## args )
-
-int main(int argc, char *argv[])
-{
- char **spp, *master_ifname, *slave_ifname;
- int c, i, rv;
- int res = 0;
- int exclusive = 0;
-
- while ((c = getopt_long(argc, argv, "acdfhuvV", longopts, 0)) != EOF) {
- switch (c) {
- case 'a': opt_a++; exclusive++; break;
- case 'c': opt_c++; exclusive++; break;
- case 'd': opt_d++; exclusive++; break;
- case 'f': opt_f++; exclusive++; break;
- case 'h': opt_h++; exclusive++; break;
- case 'u': opt_u++; exclusive++; break;
- case 'v': opt_v++; break;
- case 'V': opt_V++; exclusive++; break;
-
- case '?':
- fprintf(stderr, "%s", usage_msg);
- res = 2;
- goto out;
- }
- }
-
- /* options check */
- if (exclusive > 1) {
- fprintf(stderr, "%s", usage_msg);
- res = 2;
- goto out;
- }
-
- if (opt_v || opt_V) {
- printf("%s", version);
- if (opt_V) {
- res = 0;
- goto out;
- }
- }
-
- if (opt_u) {
- printf("%s", usage_msg);
- res = 0;
- goto out;
- }
-
- if (opt_h) {
- printf("%s", usage_msg);
- printf("%s", help_msg);
- res = 0;
- goto out;
- }
-
- /* Open a basic socket */
- if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- perror("socket");
- res = 1;
- goto out;
- }
-
- if (opt_a) {
- if (optind == argc) {
- /* No remaining args */
- /* show all interfaces */
- if_print((char *)NULL);
- goto out;
- } else {
- /* Just show usage */
- fprintf(stderr, "%s", usage_msg);
- res = 2;
- goto out;
- }
- }
-
- /* Copy the interface name */
- spp = argv + optind;
- master_ifname = *spp++;
-
- if (master_ifname == NULL) {
- fprintf(stderr, "%s", usage_msg);
- res = 2;
- goto out;
- }
-
- /* exchange abi version with bonding module */
- res = get_drv_info(master_ifname);
- if (res) {
- fprintf(stderr,
- "Master '%s': Error: handshake with driver failed. "
- "Aborting\n",
- master_ifname);
- goto out;
- }
-
- slave_ifname = *spp++;
-
- if (slave_ifname == NULL) {
- if (opt_d || opt_c) {
- fprintf(stderr, "%s", usage_msg);
- res = 2;
- goto out;
- }
-
- /* A single arg means show the
- * configuration for this interface
- */
- if_print(master_ifname);
- goto out;
- }
-
- res = get_if_settings(master_ifname, master_ifra);
- if (res) {
- /* Probably a good reason not to go on */
- fprintf(stderr,
- "Master '%s': Error: get settings failed: %s. "
- "Aborting\n",
- master_ifname, strerror(res));
- goto out;
- }
-
- /* check if master is indeed a master;
- * if not then fail any operation
- */
- if (!(master_flags.ifr_flags & IFF_MASTER)) {
- fprintf(stderr,
- "Illegal operation; the specified interface '%s' "
- "is not a master. Aborting\n",
- master_ifname);
- res = 1;
- goto out;
- }
-
- /* check if master is up; if not then fail any operation */
- if (!(master_flags.ifr_flags & IFF_UP)) {
- fprintf(stderr,
- "Illegal operation; the specified master interface "
- "'%s' is not up.\n",
- master_ifname);
- res = 1;
- goto out;
- }
-
- /* Only for enslaving */
- if (!opt_c && !opt_d) {
- sa_family_t master_family = master_hwaddr.ifr_hwaddr.sa_family;
- unsigned char *hwaddr =
- (unsigned char *)master_hwaddr.ifr_hwaddr.sa_data;
-
- /* The family '1' is ARPHRD_ETHER for ethernet. */
- if (master_family != 1 && !opt_f) {
- fprintf(stderr,
- "Illegal operation: The specified master "
- "interface '%s' is not ethernet-like.\n "
- "This program is designed to work with "
- "ethernet-like network interfaces.\n "
- "Use the '-f' option to force the "
- "operation.\n",
- master_ifname);
- res = 1;
- goto out;
- }
-
- /* Check master's hw addr */
- for (i = 0; i < 6; i++) {
- if (hwaddr[i] != 0) {
- hwaddr_set = 1;
- break;
- }
- }
-
- if (hwaddr_set) {
- v_print("current hardware address of master '%s' "
- "is %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
- "type %d\n",
- master_ifname,
- hwaddr[0], hwaddr[1],
- hwaddr[2], hwaddr[3],
- hwaddr[4], hwaddr[5],
- master_family);
- }
- }
-
- /* Accepts only one slave */
- if (opt_c) {
- /* change active slave */
- res = get_slave_flags(slave_ifname);
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: get flags failed. "
- "Aborting\n",
- slave_ifname);
- goto out;
- }
- res = change_active(master_ifname, slave_ifname);
- if (res) {
- fprintf(stderr,
- "Master '%s', Slave '%s': Error: "
- "Change active failed\n",
- master_ifname, slave_ifname);
- }
- } else {
- /* Accept multiple slaves */
- do {
- if (opt_d) {
- /* detach a slave interface from the master */
- rv = get_slave_flags(slave_ifname);
- if (rv) {
- /* Can't work with this slave. */
- /* remember the error and skip it*/
- fprintf(stderr,
- "Slave '%s': Error: get flags "
- "failed. Skipping\n",
- slave_ifname);
- res = rv;
- continue;
- }
- rv = release(master_ifname, slave_ifname);
- if (rv) {
- fprintf(stderr,
- "Master '%s', Slave '%s': Error: "
- "Release failed\n",
- master_ifname, slave_ifname);
- res = rv;
- }
- } else {
- /* attach a slave interface to the master */
- rv = get_if_settings(slave_ifname, slave_ifra);
- if (rv) {
- /* Can't work with this slave. */
- /* remember the error and skip it*/
- fprintf(stderr,
- "Slave '%s': Error: get "
- "settings failed: %s. "
- "Skipping\n",
- slave_ifname, strerror(rv));
- res = rv;
- continue;
- }
- rv = enslave(master_ifname, slave_ifname);
- if (rv) {
- fprintf(stderr,
- "Master '%s', Slave '%s': Error: "
- "Enslave failed\n",
- master_ifname, slave_ifname);
- res = rv;
- }
- }
- } while ((slave_ifname = *spp++) != NULL);
- }
-
-out:
- if (skfd >= 0) {
- close(skfd);
- }
-
- return res;
-}
-
-static short mif_flags;
-
-/* Get the inteface configuration from the kernel. */
-static int if_getconfig(char *ifname)
-{
- struct ifreq ifr;
- int metric, mtu; /* Parameters of the master interface. */
- struct sockaddr dstaddr, broadaddr, netmask;
- unsigned char *hwaddr;
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
- return -1;
- mif_flags = ifr.ifr_flags;
- printf("The result of SIOCGIFFLAGS on %s is %x.\n",
- ifname, ifr.ifr_flags);
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0)
- return -1;
- printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n",
- ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1],
- ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]);
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0)
- return -1;
-
- /* Gotta convert from 'char' to unsigned for printf(). */
- hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data;
- printf("The result of SIOCGIFHWADDR is type %d "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
- ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
- hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) {
- metric = 0;
- } else
- metric = ifr.ifr_metric;
- printf("The result of SIOCGIFMETRIC is %d\n", metric);
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0)
- mtu = 0;
- else
- mtu = ifr.ifr_mtu;
- printf("The result of SIOCGIFMTU is %d\n", mtu);
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) {
- memset(&dstaddr, 0, sizeof(struct sockaddr));
- } else
- dstaddr = ifr.ifr_dstaddr;
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) {
- memset(&broadaddr, 0, sizeof(struct sockaddr));
- } else
- broadaddr = ifr.ifr_broadaddr;
-
- strcpy(ifr.ifr_name, ifname);
- if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) {
- memset(&netmask, 0, sizeof(struct sockaddr));
- } else
- netmask = ifr.ifr_netmask;
-
- return 0;
-}
-
-static void if_print(char *ifname)
-{
- char buff[1024];
- struct ifconf ifc;
- struct ifreq *ifr;
- int i;
-
- if (ifname == (char *)NULL) {
- ifc.ifc_len = sizeof(buff);
- ifc.ifc_buf = buff;
- if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) {
- perror("SIOCGIFCONF failed");
- return;
- }
-
- ifr = ifc.ifc_req;
- for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) {
- if (if_getconfig(ifr->ifr_name) < 0) {
- fprintf(stderr,
- "%s: unknown interface.\n",
- ifr->ifr_name);
- continue;
- }
-
- if (((mif_flags & IFF_UP) == 0) && !opt_a) continue;
- /*ife_print(&ife);*/
- }
- } else {
- if (if_getconfig(ifname) < 0) {
- fprintf(stderr,
- "%s: unknown interface.\n", ifname);
- }
- }
-}
-
-static int get_drv_info(char *master_ifname)
-{
- struct ifreq ifr;
- struct ethtool_drvinfo info;
- char *endptr;
-
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
- ifr.ifr_data = (caddr_t)&info;
-
- info.cmd = ETHTOOL_GDRVINFO;
- strncpy(info.driver, "ifenslave", 32);
- snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION);
-
- if (ioctl(skfd, SIOCETHTOOL, &ifr) < 0) {
- if (errno == EOPNOTSUPP) {
- goto out;
- }
-
- saved_errno = errno;
- v_print("Master '%s': Error: get bonding info failed %s\n",
- master_ifname, strerror(saved_errno));
- return 1;
- }
-
- abi_ver = strtoul(info.fw_version, &endptr, 0);
- if (*endptr) {
- v_print("Master '%s': Error: got invalid string as an ABI "
- "version from the bonding module\n",
- master_ifname);
- return 1;
- }
-
-out:
- v_print("ABI ver is %d\n", abi_ver);
-
- return 0;
-}
-
-static int change_active(char *master_ifname, char *slave_ifname)
-{
- struct ifreq ifr;
- int res = 0;
-
- if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
- fprintf(stderr,
- "Illegal operation: The specified slave interface "
- "'%s' is not a slave\n",
- slave_ifname);
- return 1;
- }
-
- strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
- strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
- if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &ifr) < 0) &&
- (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &ifr) < 0)) {
- saved_errno = errno;
- v_print("Master '%s': Error: SIOCBONDCHANGEACTIVE failed: "
- "%s\n",
- master_ifname, strerror(saved_errno));
- res = 1;
- }
-
- return res;
-}
-
-static int enslave(char *master_ifname, char *slave_ifname)
-{
- struct ifreq ifr;
- int res = 0;
-
- if (slave_flags.ifr_flags & IFF_SLAVE) {
- fprintf(stderr,
- "Illegal operation: The specified slave interface "
- "'%s' is already a slave\n",
- slave_ifname);
- return 1;
- }
-
- res = set_if_down(slave_ifname, slave_flags.ifr_flags);
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: bring interface down failed\n",
- slave_ifname);
- return res;
- }
-
- if (abi_ver < 2) {
- /* Older bonding versions would panic if the slave has no IP
- * address, so get the IP setting from the master.
- */
- set_if_addr(master_ifname, slave_ifname);
- } else {
- res = clear_if_addr(slave_ifname);
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: clear address failed\n",
- slave_ifname);
- return res;
- }
- }
-
- if (master_mtu.ifr_mtu != slave_mtu.ifr_mtu) {
- res = set_slave_mtu(slave_ifname, master_mtu.ifr_mtu);
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: set MTU failed\n",
- slave_ifname);
- return res;
- }
- }
-
- if (hwaddr_set) {
- /* Master already has an hwaddr
- * so set it's hwaddr to the slave
- */
- if (abi_ver < 1) {
- /* The driver is using an old ABI, so
- * the application sets the slave's
- * hwaddr
- */
- res = set_slave_hwaddr(slave_ifname,
- &(master_hwaddr.ifr_hwaddr));
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: set hw address "
- "failed\n",
- slave_ifname);
- goto undo_mtu;
- }
-
- /* For old ABI the application needs to bring the
- * slave back up
- */
- res = set_if_up(slave_ifname, slave_flags.ifr_flags);
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: bring interface "
- "down failed\n",
- slave_ifname);
- goto undo_slave_mac;
- }
- }
- /* The driver is using a new ABI,
- * so the driver takes care of setting
- * the slave's hwaddr and bringing
- * it up again
- */
- } else {
- /* No hwaddr for master yet, so
- * set the slave's hwaddr to it
- */
- if (abi_ver < 1) {
- /* For old ABI, the master needs to be
- * down before setting its hwaddr
- */
- res = set_if_down(master_ifname, master_flags.ifr_flags);
- if (res) {
- fprintf(stderr,
- "Master '%s': Error: bring interface "
- "down failed\n",
- master_ifname);
- goto undo_mtu;
- }
- }
-
- res = set_master_hwaddr(master_ifname,
- &(slave_hwaddr.ifr_hwaddr));
- if (res) {
- fprintf(stderr,
- "Master '%s': Error: set hw address "
- "failed\n",
- master_ifname);
- goto undo_mtu;
- }
-
- if (abi_ver < 1) {
- /* For old ABI, bring the master
- * back up
- */
- res = set_if_up(master_ifname, master_flags.ifr_flags);
- if (res) {
- fprintf(stderr,
- "Master '%s': Error: bring interface "
- "up failed\n",
- master_ifname);
- goto undo_master_mac;
- }
- }
-
- hwaddr_set = 1;
- }
-
- /* Do the real thing */
- strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
- strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
- if ((ioctl(skfd, SIOCBONDENSLAVE, &ifr) < 0) &&
- (ioctl(skfd, BOND_ENSLAVE_OLD, &ifr) < 0)) {
- saved_errno = errno;
- v_print("Master '%s': Error: SIOCBONDENSLAVE failed: %s\n",
- master_ifname, strerror(saved_errno));
- res = 1;
- }
-
- if (res) {
- goto undo_master_mac;
- }
-
- return 0;
-
-/* rollback (best effort) */
-undo_master_mac:
- set_master_hwaddr(master_ifname, &(master_hwaddr.ifr_hwaddr));
- hwaddr_set = 0;
- goto undo_mtu;
-undo_slave_mac:
- set_slave_hwaddr(slave_ifname, &(slave_hwaddr.ifr_hwaddr));
-undo_mtu:
- set_slave_mtu(slave_ifname, slave_mtu.ifr_mtu);
- return res;
-}
-
-static int release(char *master_ifname, char *slave_ifname)
-{
- struct ifreq ifr;
- int res = 0;
-
- if (!(slave_flags.ifr_flags & IFF_SLAVE)) {
- fprintf(stderr,
- "Illegal operation: The specified slave interface "
- "'%s' is not a slave\n",
- slave_ifname);
- return 1;
- }
-
- strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
- strncpy(ifr.ifr_slave, slave_ifname, IFNAMSIZ);
- if ((ioctl(skfd, SIOCBONDRELEASE, &ifr) < 0) &&
- (ioctl(skfd, BOND_RELEASE_OLD, &ifr) < 0)) {
- saved_errno = errno;
- v_print("Master '%s': Error: SIOCBONDRELEASE failed: %s\n",
- master_ifname, strerror(saved_errno));
- return 1;
- } else if (abi_ver < 1) {
- /* The driver is using an old ABI, so we'll set the interface
- * down to avoid any conflicts due to same MAC/IP
- */
- res = set_if_down(slave_ifname, slave_flags.ifr_flags);
- if (res) {
- fprintf(stderr,
- "Slave '%s': Error: bring interface "
- "down failed\n",
- slave_ifname);
- }
- }
-
- /* set to default mtu */
- set_slave_mtu(slave_ifname, 1500);
-
- return res;
-}
-
-static int get_if_settings(char *ifname, struct dev_ifr ifra[])
-{
- int i;
- int res = 0;
-
- for (i = 0; ifra[i].req_ifr; i++) {
- strncpy(ifra[i].req_ifr->ifr_name, ifname, IFNAMSIZ);
- res = ioctl(skfd, ifra[i].req_type, ifra[i].req_ifr);
- if (res < 0) {
- saved_errno = errno;
- v_print("Interface '%s': Error: %s failed: %s\n",
- ifname, ifra[i].req_name,
- strerror(saved_errno));
-
- return saved_errno;
- }
- }
-
- return 0;
-}
-
-static int get_slave_flags(char *slave_ifname)
-{
- int res = 0;
-
- strncpy(slave_flags.ifr_name, slave_ifname, IFNAMSIZ);
- res = ioctl(skfd, SIOCGIFFLAGS, &slave_flags);
- if (res < 0) {
- saved_errno = errno;
- v_print("Slave '%s': Error: SIOCGIFFLAGS failed: %s\n",
- slave_ifname, strerror(saved_errno));
- } else {
- v_print("Slave %s: flags %04X.\n",
- slave_ifname, slave_flags.ifr_flags);
- }
-
- return res;
-}
-
-static int set_master_hwaddr(char *master_ifname, struct sockaddr *hwaddr)
-{
- unsigned char *addr = (unsigned char *)hwaddr->sa_data;
- struct ifreq ifr;
- int res = 0;
-
- strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
- memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
- res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
- if (res < 0) {
- saved_errno = errno;
- v_print("Master '%s': Error: SIOCSIFHWADDR failed: %s\n",
- master_ifname, strerror(saved_errno));
- return res;
- } else {
- v_print("Master '%s': hardware address set to "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
- master_ifname, addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
- }
-
- return res;
-}
-
-static int set_slave_hwaddr(char *slave_ifname, struct sockaddr *hwaddr)
-{
- unsigned char *addr = (unsigned char *)hwaddr->sa_data;
- struct ifreq ifr;
- int res = 0;
-
- strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
- memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(struct sockaddr));
- res = ioctl(skfd, SIOCSIFHWADDR, &ifr);
- if (res < 0) {
- saved_errno = errno;
-
- v_print("Slave '%s': Error: SIOCSIFHWADDR failed: %s\n",
- slave_ifname, strerror(saved_errno));
-
- if (saved_errno == EBUSY) {
- v_print(" The device is busy: it must be idle "
- "before running this command.\n");
- } else if (saved_errno == EOPNOTSUPP) {
- v_print(" The device does not support setting "
- "the MAC address.\n"
- " Your kernel likely does not support slave "
- "devices.\n");
- } else if (saved_errno == EINVAL) {
- v_print(" The device's address type does not match "
- "the master's address type.\n");
- }
- return res;
- } else {
- v_print("Slave '%s': hardware address set to "
- "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
- slave_ifname, addr[0], addr[1], addr[2],
- addr[3], addr[4], addr[5]);
- }
-
- return res;
-}
-
-static int set_slave_mtu(char *slave_ifname, int mtu)
-{
- struct ifreq ifr;
- int res = 0;
-
- ifr.ifr_mtu = mtu;
- strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
-
- res = ioctl(skfd, SIOCSIFMTU, &ifr);
- if (res < 0) {
- saved_errno = errno;
- v_print("Slave '%s': Error: SIOCSIFMTU failed: %s\n",
- slave_ifname, strerror(saved_errno));
- } else {
- v_print("Slave '%s': MTU set to %d.\n", slave_ifname, mtu);
- }
-
- return res;
-}
-
-static int set_if_flags(char *ifname, short flags)
-{
- struct ifreq ifr;
- int res = 0;
-
- ifr.ifr_flags = flags;
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
- res = ioctl(skfd, SIOCSIFFLAGS, &ifr);
- if (res < 0) {
- saved_errno = errno;
- v_print("Interface '%s': Error: SIOCSIFFLAGS failed: %s\n",
- ifname, strerror(saved_errno));
- } else {
- v_print("Interface '%s': flags set to %04X.\n", ifname, flags);
- }
-
- return res;
-}
-
-static int set_if_up(char *ifname, short flags)
-{
- return set_if_flags(ifname, flags | IFF_UP);
-}
-
-static int set_if_down(char *ifname, short flags)
-{
- return set_if_flags(ifname, flags & ~IFF_UP);
-}
-
-static int clear_if_addr(char *ifname)
-{
- struct ifreq ifr;
- int res = 0;
-
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
- ifr.ifr_addr.sa_family = AF_INET;
- memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data));
-
- res = ioctl(skfd, SIOCSIFADDR, &ifr);
- if (res < 0) {
- saved_errno = errno;
- v_print("Interface '%s': Error: SIOCSIFADDR failed: %s\n",
- ifname, strerror(saved_errno));
- } else {
- v_print("Interface '%s': address cleared\n", ifname);
- }
-
- return res;
-}
-
-static int set_if_addr(char *master_ifname, char *slave_ifname)
-{
- struct ifreq ifr;
- int res;
- unsigned char *ipaddr;
- int i;
- struct {
- char *req_name;
- char *desc;
- int g_ioctl;
- int s_ioctl;
- } ifra[] = {
- {"IFADDR", "addr", SIOCGIFADDR, SIOCSIFADDR},
- {"DSTADDR", "destination addr", SIOCGIFDSTADDR, SIOCSIFDSTADDR},
- {"BRDADDR", "broadcast addr", SIOCGIFBRDADDR, SIOCSIFBRDADDR},
- {"NETMASK", "netmask", SIOCGIFNETMASK, SIOCSIFNETMASK},
- {NULL, NULL, 0, 0},
- };
-
- for (i = 0; ifra[i].req_name; i++) {
- strncpy(ifr.ifr_name, master_ifname, IFNAMSIZ);
- res = ioctl(skfd, ifra[i].g_ioctl, &ifr);
- if (res < 0) {
- int saved_errno = errno;
-
- v_print("Interface '%s': Error: SIOCG%s failed: %s\n",
- master_ifname, ifra[i].req_name,
- strerror(saved_errno));
-
- ifr.ifr_addr.sa_family = AF_INET;
- memset(ifr.ifr_addr.sa_data, 0,
- sizeof(ifr.ifr_addr.sa_data));
- }
-
- strncpy(ifr.ifr_name, slave_ifname, IFNAMSIZ);
- res = ioctl(skfd, ifra[i].s_ioctl, &ifr);
- if (res < 0) {
- int saved_errno = errno;
-
- v_print("Interface '%s': Error: SIOCS%s failed: %s\n",
- slave_ifname, ifra[i].req_name,
- strerror(saved_errno));
-
- }
-
- ipaddr = (unsigned char *)ifr.ifr_addr.sa_data;
- v_print("Interface '%s': set IP %s to %d.%d.%d.%d\n",
- slave_ifname, ifra[i].desc,
- ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
- }
-
- return 0;
-}
-
-/*
- * Local variables:
- * version-control: t
- * kept-new-versions: 5
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave"
- * End:
- */
-
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 3458d6343e01..10742902146f 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -183,7 +183,7 @@ tcp_early_retrans - INTEGER
for triggering fast retransmit when the amount of outstanding data is
small and when no previously unsent data can be transmitted (such
that limited transmit could be used). Also controls the use of
- Tail loss probe (TLP) that converts RTOs occuring due to tail
+ Tail loss probe (TLP) that converts RTOs occurring due to tail
losses into fast recovery (draft-dukkipati-tcpm-tcp-loss-probe-01).
Possible values:
0 disables ER
@@ -685,6 +685,15 @@ ip_dynaddr - BOOLEAN
occurs.
Default: 0
+ip_early_demux - BOOLEAN
+ Optimize input packet processing down to one demux for
+ certain kinds of local sockets. Currently we only do this
+ for established TCP sockets.
+
+ It may add an additional cost for pure routing workloads that
+ reduces overall throughput, in such case you should disable it.
+ Default: 1
+
icmp_echo_ignore_all - BOOLEAN
If set non-zero, then the kernel will ignore all ICMP ECHO
requests sent to it.
@@ -729,7 +738,7 @@ icmp_ignore_bogus_error_responses - BOOLEAN
frames. Such violations are normally logged via a kernel warning.
If this is set to TRUE, the kernel will not give such warnings, which
will avoid log file clutter.
- Default: FALSE
+ Default: 1
icmp_errors_use_inbound_ifaddr - BOOLEAN
diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt
index 9573d0c48c6e..7a3c04729591 100644
--- a/Documentation/networking/ipvs-sysctl.txt
+++ b/Documentation/networking/ipvs-sysctl.txt
@@ -181,6 +181,19 @@ snat_reroute - BOOLEAN
always be the same as the original route so it is an optimisation
to disable snat_reroute and avoid the recalculation.
+sync_persist_mode - INTEGER
+ default 0
+
+ Controls the synchronisation of connections when using persistence
+
+ 0: All types of connections are synchronised
+ 1: Attempt to reduce the synchronisation traffic depending on
+ the connection type. For persistent services avoid synchronisation
+ for normal connections, do it only for persistence templates.
+ In such case, for TCP and SCTP it may need enabling sloppy_tcp and
+ sloppy_sctp flags on backup servers. For non-persistent services
+ such optimization is not applied, mode 0 is assumed.
+
sync_version - INTEGER
default 1
diff --git a/Documentation/networking/netlink_mmap.txt b/Documentation/networking/netlink_mmap.txt
index 1c2dab409625..533378839546 100644
--- a/Documentation/networking/netlink_mmap.txt
+++ b/Documentation/networking/netlink_mmap.txt
@@ -54,7 +54,7 @@ it will use an allocated socket buffer as usual and the contents will be
copied to the ring on transmission, nullifying most of the performance gains.
Dumps of kernel databases automatically support memory mapped I/O.
-Conversion of the transmit path involves changing message contruction to
+Conversion of the transmit path involves changing message construction to
use memory from the TX ring instead of (usually) a buffer declared on the
stack and setting up the frame header approriately. Optionally poll() can
be used to wait for free frames in the TX ring.
@@ -65,8 +65,8 @@ Structured and definitions for using memory mapped I/O are contained in
RX and TX rings
----------------
-Each ring contains a number of continous memory blocks, containing frames of
-fixed size dependant on the parameters used for ring setup.
+Each ring contains a number of continuous memory blocks, containing frames of
+fixed size dependent on the parameters used for ring setup.
Ring: [ block 0 ]
[ frame 0 ]
@@ -80,7 +80,7 @@ Ring: [ block 0 ]
[ frame 2 * n + 1 ]
The blocks are only visible to the kernel, from the point of view of user-space
-the ring just contains the frames in a continous memory zone.
+the ring just contains the frames in a continuous memory zone.
The ring parameters used for setting up the ring are defined as follows:
@@ -91,7 +91,7 @@ struct nl_mmap_req {
unsigned int nm_frame_nr;
};
-Frames are grouped into blocks, where each block is a continous region of memory
+Frames are grouped into blocks, where each block is a continuous region of memory
and holds nm_block_size / nm_frame_size frames. The total number of frames in
the ring is nm_frame_nr. The following invariants hold:
@@ -113,8 +113,8 @@ Some parameters are constrained, specifically:
- nm_frame_nr must equal the actual number of frames as specified above.
-When the kernel can't allocate phsyically continous memory for a ring block,
-it will fall back to use physically discontinous memory. This might affect
+When the kernel can't allocate physically continuous memory for a ring block,
+it will fall back to use physically discontinuous memory. This might affect
performance negatively, in order to avoid this the nm_frame_size parameter
should be chosen to be as small as possible for the required frame size and
the number of blocks should be increased instead.
@@ -274,9 +274,9 @@ This example assumes some ring parameters of the ring setup are available.
/* Get next frame header */
hdr = rx_ring + frame_offset;
- if (hdr->nm_status == NL_MMAP_STATUS_VALID)
+ if (hdr->nm_status == NL_MMAP_STATUS_VALID) {
/* Regular memory mapped frame */
- nlh = (void *hdr) + NL_MMAP_HDRLEN;
+ nlh = (void *)hdr + NL_MMAP_HDRLEN;
len = hdr->nm_len;
/* Release empty message immediately. May happen
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 23dd80e82b8e..8572796b1eb6 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -704,6 +704,12 @@ So it seems to be a good candidate to be used with packet fanout.
Minimal example code by Daniel Borkmann based on Chetan Loke's lolpcap (compile
it with gcc -Wall -O2 blob.c, and try things like "./a.out eth0", etc.):
+/* Written from scratch, but kernel-to-user space API usage
+ * dissected from lolpcap:
+ * Copyright 2011, Chetan Loke <loke.chetan@gmail.com>
+ * License: GPL, version 2.0
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -722,27 +728,6 @@ it with gcc -Wall -O2 blob.c, and try things like "./a.out eth0", etc.):
#include <linux/if_ether.h>
#include <linux/ip.h>
-#define BLOCK_SIZE (1 << 22)
-#define FRAME_SIZE 2048
-
-#define NUM_BLOCKS 64
-#define NUM_FRAMES ((BLOCK_SIZE * NUM_BLOCKS) / FRAME_SIZE)
-
-#define BLOCK_RETIRE_TOV_IN_MS 64
-#define BLOCK_PRIV_AREA_SZ 13
-
-#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1))
-
-#define BLOCK_STATUS(x) ((x)->h1.block_status)
-#define BLOCK_NUM_PKTS(x) ((x)->h1.num_pkts)
-#define BLOCK_O2FP(x) ((x)->h1.offset_to_first_pkt)
-#define BLOCK_LEN(x) ((x)->h1.blk_len)
-#define BLOCK_SNUM(x) ((x)->h1.seq_num)
-#define BLOCK_O2PRIV(x) ((x)->offset_to_priv)
-#define BLOCK_PRIV(x) ((void *) ((uint8_t *) (x) + BLOCK_O2PRIV(x)))
-#define BLOCK_HDR_LEN (ALIGN_8(sizeof(struct block_desc)))
-#define BLOCK_PLUS_PRIV(sz_pri) (BLOCK_HDR_LEN + ALIGN_8((sz_pri)))
-
#ifndef likely
# define likely(x) __builtin_expect(!!(x), 1)
#endif
@@ -765,7 +750,7 @@ struct ring {
static unsigned long packets_total = 0, bytes_total = 0;
static sig_atomic_t sigint = 0;
-void sighandler(int num)
+static void sighandler(int num)
{
sigint = 1;
}
@@ -774,6 +759,8 @@ static int setup_socket(struct ring *ring, char *netdev)
{
int err, i, fd, v = TPACKET_V3;
struct sockaddr_ll ll;
+ unsigned int blocksiz = 1 << 22, framesiz = 1 << 11;
+ unsigned int blocknum = 64;
fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (fd < 0) {
@@ -788,13 +775,12 @@ static int setup_socket(struct ring *ring, char *netdev)
}
memset(&ring->req, 0, sizeof(ring->req));
- ring->req.tp_block_size = BLOCK_SIZE;
- ring->req.tp_frame_size = FRAME_SIZE;
- ring->req.tp_block_nr = NUM_BLOCKS;
- ring->req.tp_frame_nr = NUM_FRAMES;
- ring->req.tp_retire_blk_tov = BLOCK_RETIRE_TOV_IN_MS;
- ring->req.tp_sizeof_priv = BLOCK_PRIV_AREA_SZ;
- ring->req.tp_feature_req_word |= TP_FT_REQ_FILL_RXHASH;
+ ring->req.tp_block_size = blocksiz;
+ ring->req.tp_frame_size = framesiz;
+ ring->req.tp_block_nr = blocknum;
+ ring->req.tp_frame_nr = (blocksiz * blocknum) / framesiz;
+ ring->req.tp_retire_blk_tov = 60;
+ ring->req.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH;
err = setsockopt(fd, SOL_PACKET, PACKET_RX_RING, &ring->req,
sizeof(ring->req));
@@ -804,8 +790,7 @@ static int setup_socket(struct ring *ring, char *netdev)
}
ring->map = mmap(NULL, ring->req.tp_block_size * ring->req.tp_block_nr,
- PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED,
- fd, 0);
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, fd, 0);
if (ring->map == MAP_FAILED) {
perror("mmap");
exit(1);
@@ -835,58 +820,6 @@ static int setup_socket(struct ring *ring, char *netdev)
return fd;
}
-#ifdef __checked
-static uint64_t prev_block_seq_num = 0;
-
-void assert_block_seq_num(struct block_desc *pbd)
-{
- if (unlikely(prev_block_seq_num + 1 != BLOCK_SNUM(pbd))) {
- printf("prev_block_seq_num:%"PRIu64", expected seq:%"PRIu64" != "
- "actual seq:%"PRIu64"\n", prev_block_seq_num,
- prev_block_seq_num + 1, (uint64_t) BLOCK_SNUM(pbd));
- exit(1);
- }
-
- prev_block_seq_num = BLOCK_SNUM(pbd);
-}
-
-static void assert_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
-{
- if (BLOCK_NUM_PKTS(pbd)) {
- if (unlikely(bytes != BLOCK_LEN(pbd))) {
- printf("block:%u with %upackets, expected len:%u != actual len:%u\n",
- block_num, BLOCK_NUM_PKTS(pbd), bytes, BLOCK_LEN(pbd));
- exit(1);
- }
- } else {
- if (unlikely(BLOCK_LEN(pbd) != BLOCK_PLUS_PRIV(BLOCK_PRIV_AREA_SZ))) {
- printf("block:%u, expected len:%lu != actual len:%u\n",
- block_num, BLOCK_HDR_LEN, BLOCK_LEN(pbd));
- exit(1);
- }
- }
-}
-
-static void assert_block_header(struct block_desc *pbd, const int block_num)
-{
- uint32_t block_status = BLOCK_STATUS(pbd);
-
- if (unlikely((block_status & TP_STATUS_USER) == 0)) {
- printf("block:%u, not in TP_STATUS_USER\n", block_num);
- exit(1);
- }
-
- assert_block_seq_num(pbd);
-}
-#else
-static inline void assert_block_header(struct block_desc *pbd, const int block_num)
-{
-}
-static void assert_block_len(struct block_desc *pbd, uint32_t bytes, int block_num)
-{
-}
-#endif
-
static void display(struct tpacket3_hdr *ppd)
{
struct ethhdr *eth = (struct ethhdr *) ((uint8_t *) ppd + ppd->tp_mac);
@@ -916,37 +849,27 @@ static void display(struct tpacket3_hdr *ppd)
static void walk_block(struct block_desc *pbd, const int block_num)
{
- int num_pkts = BLOCK_NUM_PKTS(pbd), i;
+ int num_pkts = pbd->h1.num_pkts, i;
unsigned long bytes = 0;
- unsigned long bytes_with_padding = BLOCK_PLUS_PRIV(BLOCK_PRIV_AREA_SZ);
struct tpacket3_hdr *ppd;
- assert_block_header(pbd, block_num);
-
- ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + BLOCK_O2FP(pbd));
+ ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd +
+ pbd->h1.offset_to_first_pkt);
for (i = 0; i < num_pkts; ++i) {
bytes += ppd->tp_snaplen;
- if (ppd->tp_next_offset)
- bytes_with_padding += ppd->tp_next_offset;
- else
- bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac);
-
display(ppd);
- ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd + ppd->tp_next_offset);
- __sync_synchronize();
+ ppd = (struct tpacket3_hdr *) ((uint8_t *) ppd +
+ ppd->tp_next_offset);
}
- assert_block_len(pbd, bytes_with_padding, block_num);
-
packets_total += num_pkts;
bytes_total += bytes;
}
-void flush_block(struct block_desc *pbd)
+static void flush_block(struct block_desc *pbd)
{
- BLOCK_STATUS(pbd) = TP_STATUS_KERNEL;
- __sync_synchronize();
+ pbd->h1.block_status = TP_STATUS_KERNEL;
}
static void teardown_socket(struct ring *ring, int fd)
@@ -962,7 +885,7 @@ int main(int argc, char **argp)
socklen_t len;
struct ring ring;
struct pollfd pfd;
- unsigned int block_num = 0;
+ unsigned int block_num = 0, blocks = 64;
struct block_desc *pbd;
struct tpacket_stats_v3 stats;
@@ -984,15 +907,15 @@ int main(int argc, char **argp)
while (likely(!sigint)) {
pbd = (struct block_desc *) ring.rd[block_num].iov_base;
-retry_block:
- if ((BLOCK_STATUS(pbd) & TP_STATUS_USER) == 0) {
+
+ if ((pbd->h1.block_status & TP_STATUS_USER) == 0) {
poll(&pfd, 1, -1);
- goto retry_block;
+ continue;
}
walk_block(pbd, block_num);
flush_block(pbd);
- block_num = (block_num + 1) % NUM_BLOCKS;
+ block_num = (block_num + 1) % blocks;
}
len = sizeof(stats);
diff --git a/Documentation/networking/scaling.txt b/Documentation/networking/scaling.txt
index 579994afbe06..ca6977f5b2ed 100644
--- a/Documentation/networking/scaling.txt
+++ b/Documentation/networking/scaling.txt
@@ -163,6 +163,64 @@ and unnecessary. If there are fewer hardware queues than CPUs, then
RPS might be beneficial if the rps_cpus for each queue are the ones that
share the same memory domain as the interrupting CPU for that queue.
+==== RPS Flow Limit
+
+RPS scales kernel receive processing across CPUs without introducing
+reordering. The trade-off to sending all packets from the same flow
+to the same CPU is CPU load imbalance if flows vary in packet rate.
+In the extreme case a single flow dominates traffic. Especially on
+common server workloads with many concurrent connections, such
+behavior indicates a problem such as a misconfiguration or spoofed
+source Denial of Service attack.
+
+Flow Limit is an optional RPS feature that prioritizes small flows
+during CPU contention by dropping packets from large flows slightly
+ahead of those from small flows. It is active only when an RPS or RFS
+destination CPU approaches saturation. Once a CPU's input packet
+queue exceeds half the maximum queue length (as set by sysctl
+net.core.netdev_max_backlog), the kernel starts a per-flow packet
+count over the last 256 packets. If a flow exceeds a set ratio (by
+default, half) of these packets when a new packet arrives, then the
+new packet is dropped. Packets from other flows are still only
+dropped once the input packet queue reaches netdev_max_backlog.
+No packets are dropped when the input packet queue length is below
+the threshold, so flow limit does not sever connections outright:
+even large flows maintain connectivity.
+
+== Interface
+
+Flow limit is compiled in by default (CONFIG_NET_FLOW_LIMIT), but not
+turned on. It is implemented for each CPU independently (to avoid lock
+and cache contention) and toggled per CPU by setting the relevant bit
+in sysctl net.core.flow_limit_cpu_bitmap. It exposes the same CPU
+bitmap interface as rps_cpus (see above) when called from procfs:
+
+ /proc/sys/net/core/flow_limit_cpu_bitmap
+
+Per-flow rate is calculated by hashing each packet into a hashtable
+bucket and incrementing a per-bucket counter. The hash function is
+the same that selects a CPU in RPS, but as the number of buckets can
+be much larger than the number of CPUs, flow limit has finer-grained
+identification of large flows and fewer false positives. The default
+table has 4096 buckets. This value can be modified through sysctl
+
+ net.core.flow_limit_table_len
+
+The value is only consulted when a new table is allocated. Modifying
+it does not update active tables.
+
+== Suggested Configuration
+
+Flow limit is useful on systems with many concurrent connections,
+where a single connection taking up 50% of a CPU indicates a problem.
+In such environments, enable the feature on all CPUs that handle
+network rx interrupts (as set in /proc/irq/N/smp_affinity).
+
+The feature depends on the input packet queue length to exceed
+the flow limit threshold (50%) + the flow history length (256).
+Setting net.core.netdev_max_backlog to either 1000 or 10000
+performed well in experiments.
+
RFS: Receive Flow Steering
==========================
diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
index b4038ffb3bc5..9a8041dcbb53 100644
--- a/Documentation/networking/vortex.txt
+++ b/Documentation/networking/vortex.txt
@@ -359,7 +359,7 @@ steps you should take:
- OK, it's a driver problem.
You need to generate a report. Typically this is an email to the
- maintainer and/or linux-net@vger.kernel.org. The maintainer's
+ maintainer and/or netdev@vger.kernel.org. The maintainer's
email address will be in the driver source or in the MAINTAINERS file.
- The contents of your report will vary a lot depending upon the
diff --git a/Documentation/parisc/registers b/Documentation/parisc/registers
index dd3caddd1ad9..10c7d1730f5d 100644
--- a/Documentation/parisc/registers
+++ b/Documentation/parisc/registers
@@ -78,6 +78,14 @@ Shadow Registers used by interruption handler code
TOC enable bit 1
=========================================================================
+
+The PA-RISC architecture defines 7 registers as "shadow registers".
+Those are used in RETURN FROM INTERRUPTION AND RESTORE instruction to reduce
+the state save and restore time by eliminating the need for general register
+(GR) saves and restores in interruption handlers.
+Shadow registers are the GRs 1, 8, 9, 16, 17, 24, and 25.
+
+=========================================================================
Register usage notes, originally from John Marvin, with some additional
notes from Randolph Chung.
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index 447fd4cd54ec..052e13af2d38 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -203,15 +203,8 @@ using a certain resistor value - pull up and pull down - so that the pin has a
stable value when nothing is driving the rail it is connected to, or when it's
unconnected.
-Pin configuration can be programmed either using the explicit APIs described
-immediately below, or by adding configuration entries into the mapping table;
-see section "Board/machine configuration" below.
-
-For example, a platform may do the following to pull up a pin to VDD:
-
-#include <linux/pinctrl/consumer.h>
-
-ret = pin_config_set("foo-dev", "FOO_GPIO_PIN", PLATFORM_X_PULL_UP);
+Pin configuration can be programmed by adding configuration entries into the
+mapping table; see section "Board/machine configuration" below.
The format and meaning of the configuration parameter, PLATFORM_X_PULL_UP
above, is entirely defined by the pin controller driver.
@@ -298,7 +291,7 @@ Since the pin controller subsystem have its pinspace local to the pin
controller we need a mapping so that the pin control subsystem can figure out
which pin controller handles control of a certain GPIO pin. Since a single
pin controller may be muxing several GPIO ranges (typically SoCs that have
-one set of pins but internally several GPIO silicon blocks, each modeled as
+one set of pins but internally several GPIO silicon blocks, each modelled as
a struct gpio_chip) any number of GPIO ranges can be added to a pin controller
instance like this:
@@ -350,6 +343,23 @@ chip b:
- GPIO range : [48 .. 55]
- pin range : [64 .. 71]
+The above examples assume the mapping between the GPIOs and pins is
+linear. If the mapping is sparse or haphazard, an array of arbitrary pin
+numbers can be encoded in the range like this:
+
+static const unsigned range_pins[] = { 14, 1, 22, 17, 10, 8, 6, 2 };
+
+static struct pinctrl_gpio_range gpio_range = {
+ .name = "chip",
+ .id = 0,
+ .base = 32,
+ .pins = &range_pins,
+ .npins = ARRAY_SIZE(range_pins),
+ .gc = &chip;
+};
+
+In this case the pin_base property will be ignored.
+
When GPIO-specific functions in the pin control subsystem are called, these
ranges will be used to look up the appropriate pin controller by inspecting
and matching the pin to the pin ranges across all controllers. When a
@@ -357,9 +367,9 @@ pin controller handling the matching range is found, GPIO-specific functions
will be called on that specific pin controller.
For all functionalities dealing with pin biasing, pin muxing etc, the pin
-controller subsystem will subtract the range's .base offset from the passed
-in gpio number, and add the ranges's .pin_base offset to retrive a pin number.
-After that, the subsystem passes it on to the pin control driver, so the driver
+controller subsystem will look up the corresponding pin number from the passed
+in gpio number, and use the range's internals to retrive a pin number. After
+that, the subsystem passes it on to the pin control driver, so the driver
will get an pin number into its handled number range. Further it is also passed
the range ID value, so that the pin controller knows which range it should
deal with.
@@ -368,6 +378,7 @@ Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see
section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind
pinctrl and gpio drivers.
+
PINMUX interfaces
=================
@@ -1226,8 +1237,8 @@ setting up the config and muxing for the pins right before the device is
probing, nevertheless orthogonal to the GPIO subsystem.
But there are also situations where it makes sense for the GPIO subsystem
-to communicate directly with with the pinctrl subsystem, using the latter
-as a back-end. This is when the GPIO driver may call out to the functions
+to communicate directly with the pinctrl subsystem, using the latter as a
+back-end. This is when the GPIO driver may call out to the functions
described in the section "Pin control interaction with the GPIO subsystem"
above. This only involves per-pin multiplexing, and will be completely
hidden behind the gpio_*() function namespace. In this case, the driver
diff --git a/Documentation/power/pm_qos_interface.txt b/Documentation/power/pm_qos_interface.txt
index 79a2a58425ee..483632087788 100644
--- a/Documentation/power/pm_qos_interface.txt
+++ b/Documentation/power/pm_qos_interface.txt
@@ -7,7 +7,7 @@ one of the parameters.
Two different PM QoS frameworks are available:
1. PM QoS classes for cpu_dma_latency, network_latency, network_throughput.
2. the per-device PM QoS framework provides the API to manage the per-device latency
-constraints.
+constraints and PM QoS flags.
Each parameters have defined units:
* latency: usec
@@ -86,13 +86,17 @@ To remove the user mode request for a target value simply close the device
node.
-2. PM QoS per-device latency framework
+2. PM QoS per-device latency and flags framework
+
+For each device, there are two lists of PM QoS requests. One is maintained
+along with the aggregated target of latency value and the other is for PM QoS
+flags. Values are updated in response to changes of the request list.
+
+Target latency value is simply the minimum of the request values held in the
+parameter list elements. The PM QoS flags aggregate value is a gather (bitwise
+OR) of all list elements' values. Two device PM QoS flags are defined currently:
+PM_QOS_FLAG_NO_POWER_OFF and PM_QOS_FLAG_REMOTE_WAKEUP.
-For each device a list of performance requests is maintained along with
-an aggregated target value. The aggregated target value is updated with
-changes to the request list or elements of the list. Typically the
-aggregated target value is simply the max or min of the request values held
-in the parameter list elements.
Note: the aggregated target value is implemented as an atomic variable so that
reading the aggregated value does not require any locking mechanism.
@@ -119,6 +123,38 @@ the request.
s32 dev_pm_qos_read_value(device):
Returns the aggregated value for a given device's constraints list.
+enum pm_qos_flags_status dev_pm_qos_flags(device, mask)
+Check PM QoS flags of the given device against the given mask of flags.
+The meaning of the return values is as follows:
+ PM_QOS_FLAGS_ALL: All flags from the mask are set
+ PM_QOS_FLAGS_SOME: Some flags from the mask are set
+ PM_QOS_FLAGS_NONE: No flags from the mask are set
+ PM_QOS_FLAGS_UNDEFINED: The device's PM QoS structure has not been
+ initialized or the list of requests is empty.
+
+int dev_pm_qos_add_ancestor_request(dev, handle, value)
+Add a PM QoS request for the first direct ancestor of the given device whose
+power.ignore_children flag is unset.
+
+int dev_pm_qos_expose_latency_limit(device, value)
+Add a request to the device's PM QoS list of latency constraints and create
+a sysfs attribute pm_qos_resume_latency_us under the device's power directory
+allowing user space to manipulate that request.
+
+void dev_pm_qos_hide_latency_limit(device)
+Drop the request added by dev_pm_qos_expose_latency_limit() from the device's
+PM QoS list of latency constraints and remove sysfs attribute pm_qos_resume_latency_us
+from the device's power directory.
+
+int dev_pm_qos_expose_flags(device, value)
+Add a request to the device's PM QoS list of flags and create sysfs attributes
+pm_qos_no_power_off and pm_qos_remote_wakeup under the device's power directory
+allowing user space to change these flags' value.
+
+void dev_pm_qos_hide_flags(device)
+Drop the request added by dev_pm_qos_expose_flags() from the device's PM QoS list
+of flags and remove sysfs attributes pm_qos_no_power_off and pm_qos_remote_wakeup
+under the device's power directory.
Notification mechanisms:
The per-device PM QoS framework has 2 different and distinct notification trees:
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 6c9f5d9aa115..71d8fe4e75d3 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -144,8 +144,12 @@ The action performed by the idle callback is totally dependent on the subsystem
(or driver) in question, but the expected and recommended action is to check
if the device can be suspended (i.e. if all of the conditions necessary for
suspending the device are satisfied) and to queue up a suspend request for the
-device in that case. The value returned by this callback is ignored by the PM
-core.
+device in that case. If there is no idle callback, or if the callback returns
+0, then the PM core will attempt to carry out a runtime suspend of the device;
+in essence, it will call pm_runtime_suspend() directly. To prevent this (for
+example, if the callback routine has started a delayed suspend), the routine
+should return a non-zero value. Negative error return codes are ignored by the
+PM core.
The helper functions provided by the PM core, described in Section 4, guarantee
that the following constraints are met with respect to runtime PM callbacks for
@@ -301,9 +305,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
removing the device from device hierarchy
int pm_runtime_idle(struct device *dev);
- - execute the subsystem-level idle callback for the device; returns 0 on
- success or error code on failure, where -EINPROGRESS means that
- ->runtime_idle() is already being executed
+ - execute the subsystem-level idle callback for the device; returns an
+ error code on failure, where -EINPROGRESS means that ->runtime_idle() is
+ already being executed; if there is no callback or the callback returns 0
+ then run pm_runtime_suspend(dev) and return its result
int pm_runtime_suspend(struct device *dev);
- execute the subsystem-level suspend callback for the device; returns 0 on
@@ -660,11 +665,6 @@ Subsystems may wish to conserve code space by using the set of generic power
management callbacks provided by the PM core, defined in
driver/base/power/generic_ops.c:
- int pm_generic_runtime_idle(struct device *dev);
- - invoke the ->runtime_idle() callback provided by the driver of this
- device, if defined, and call pm_runtime_suspend() for this device if the
- return value is 0 or the callback is not defined
-
int pm_generic_runtime_suspend(struct device *dev);
- invoke the ->runtime_suspend() callback provided by the driver of this
device and return its result, or return -EINVAL if not defined
diff --git a/Documentation/power/video_extension.txt b/Documentation/power/video_extension.txt
deleted file mode 100644
index b2f9b1598ac2..000000000000
--- a/Documentation/power/video_extension.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-ACPI video extensions
-~~~~~~~~~~~~~~~~~~~~~
-
-This driver implement the ACPI Extensions For Display Adapters for
-integrated graphics devices on motherboard, as specified in ACPI 2.0
-Specification, Appendix B, allowing to perform some basic control like
-defining the video POST device, retrieving EDID information or to
-setup a video output, etc. Note that this is an ref. implementation
-only. It may or may not work for your integrated video device.
-
-Interfaces exposed to userland through /proc/acpi/video:
-
-VGA/info : display the supported video bus device capability like Video ROM, CRT/LCD/TV.
-VGA/ROM : Used to get a copy of the display devices' ROM data (up to 4k).
-VGA/POST_info : Used to determine what options are implemented.
-VGA/POST : Used to get/set POST device.
-VGA/DOS : Used to get/set ownership of output switching:
- Please refer ACPI spec B.4.1 _DOS
-VGA/CRT : CRT output
-VGA/LCD : LCD output
-VGA/TVO : TV output
-VGA/*/brightness : Used to get/set brightness of output device
-
-Notify event through /proc/acpi/event:
-
-#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
-#define ACPI_VIDEO_NOTIFY_PROBE 0x81
-#define ACPI_VIDEO_NOTIFY_CYCLE 0x82
-#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83
-#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84
-
-#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x82
-#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x83
-#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x84
-#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x85
-#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x86
-
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index dd9e92802ec0..05026ce1875e 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -14,6 +14,8 @@ hvcs.txt
- IBM "Hypervisor Virtual Console Server" Installation Guide
mpc52xx.txt
- Linux 2.6.x on MPC52xx family
+pmu-ebb.txt
+ - Description of the API for using the PMU with Event Based Branches.
qe_firmware.txt
- describes the layout of firmware binaries for the Freescale QUICC
Engine and the code that parses and uploads the microcode therein.
diff --git a/Documentation/powerpc/pmu-ebb.txt b/Documentation/powerpc/pmu-ebb.txt
new file mode 100644
index 000000000000..73cd163dbfb8
--- /dev/null
+++ b/Documentation/powerpc/pmu-ebb.txt
@@ -0,0 +1,137 @@
+PMU Event Based Branches
+========================
+
+Event Based Branches (EBBs) are a feature which allows the hardware to
+branch directly to a specified user space address when certain events occur.
+
+The full specification is available in Power ISA v2.07:
+
+ https://www.power.org/documentation/power-isa-version-2-07/
+
+One type of event for which EBBs can be configured is PMU exceptions. This
+document describes the API for configuring the Power PMU to generate EBBs,
+using the Linux perf_events API.
+
+
+Terminology
+-----------
+
+Throughout this document we will refer to an "EBB event" or "EBB events". This
+just refers to a struct perf_event which has set the "EBB" flag in its
+attr.config. All events which can be configured on the hardware PMU are
+possible "EBB events".
+
+
+Background
+----------
+
+When a PMU EBB occurs it is delivered to the currently running process. As such
+EBBs can only sensibly be used by programs for self-monitoring.
+
+It is a feature of the perf_events API that events can be created on other
+processes, subject to standard permission checks. This is also true of EBB
+events, however unless the target process enables EBBs (via mtspr(BESCR)) no
+EBBs will ever be delivered.
+
+This makes it possible for a process to enable EBBs for itself, but not
+actually configure any events. At a later time another process can come along
+and attach an EBB event to the process, which will then cause EBBs to be
+delivered to the first process. It's not clear if this is actually useful.
+
+
+When the PMU is configured for EBBs, all PMU interrupts are delivered to the
+user process. This means once an EBB event is scheduled on the PMU, no non-EBB
+events can be configured. This means that EBB events can not be run
+concurrently with regular 'perf' commands, or any other perf events.
+
+It is however safe to run 'perf' commands on a process which is using EBBs. The
+kernel will in general schedule the EBB event, and perf will be notified that
+its events could not run.
+
+The exclusion between EBB events and regular events is implemented using the
+existing "pinned" and "exclusive" attributes of perf_events. This means EBB
+events will be given priority over other events, unless they are also pinned.
+If an EBB event and a regular event are both pinned, then whichever is enabled
+first will be scheduled and the other will be put in error state. See the
+section below titled "Enabling an EBB event" for more information.
+
+
+Creating an EBB event
+---------------------
+
+To request that an event is counted using EBB, the event code should have bit
+63 set.
+
+EBB events must be created with a particular, and restrictive, set of
+attributes - this is so that they interoperate correctly with the rest of the
+perf_events subsystem.
+
+An EBB event must be created with the "pinned" and "exclusive" attributes set.
+Note that if you are creating a group of EBB events, only the leader can have
+these attributes set.
+
+An EBB event must NOT set any of the "inherit", "sample_period", "freq" or
+"enable_on_exec" attributes.
+
+An EBB event must be attached to a task. This is specified to perf_event_open()
+by passing a pid value, typically 0 indicating the current task.
+
+All events in a group must agree on whether they want EBB. That is all events
+must request EBB, or none may request EBB.
+
+EBB events must specify the PMC they are to be counted on. This ensures
+userspace is able to reliably determine which PMC the event is scheduled on.
+
+
+Enabling an EBB event
+---------------------
+
+Once an EBB event has been successfully opened, it must be enabled with the
+perf_events API. This can be achieved either via the ioctl() interface, or the
+prctl() interface.
+
+However, due to the design of the perf_events API, enabling an event does not
+guarantee that it has been scheduled on the PMU. To ensure that the EBB event
+has been scheduled on the PMU, you must perform a read() on the event. If the
+read() returns EOF, then the event has not been scheduled and EBBs are not
+enabled.
+
+This behaviour occurs because the EBB event is pinned and exclusive. When the
+EBB event is enabled it will force all other non-pinned events off the PMU. In
+this case the enable will be successful. However if there is already an event
+pinned on the PMU then the enable will not be successful.
+
+
+Reading an EBB event
+--------------------
+
+It is possible to read() from an EBB event. However the results are
+meaningless. Because interrupts are being delivered to the user process the
+kernel is not able to count the event, and so will return a junk value.
+
+
+Closing an EBB event
+--------------------
+
+When an EBB event is finished with, you can close it using close() as for any
+regular event. If this is the last EBB event the PMU will be deconfigured and
+no further PMU EBBs will be delivered.
+
+
+EBB Handler
+-----------
+
+The EBB handler is just regular userspace code, however it must be written in
+the style of an interrupt handler. When the handler is entered all registers
+are live (possibly) and so must be saved somehow before the handler can invoke
+other code.
+
+It's up to the program how to handle this. For C programs a relatively simple
+option is to create an interrupt frame on the stack and save registers there.
+
+Fork
+----
+
+EBB events are not inherited across fork. If the child process wishes to use
+EBBs it should open a new event for itself. Similarly the EBB state in
+BESCR/EBBHR/EBBRR is cleared across fork().
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index 3af5ae6c9c11..3e8cb73ac43c 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -121,6 +121,38 @@ IPv6 addresses:
print a compressed IPv6 address as described by
http://tools.ietf.org/html/rfc5952
+IPv4/IPv6 addresses (generic, with port, flowinfo, scope):
+
+ %pIS 1.2.3.4 or 0001:0002:0003:0004:0005:0006:0007:0008
+ %piS 001.002.003.004 or 00010002000300040005000600070008
+ %pISc 1.2.3.4 or 1:2:3:4:5:6:7:8
+ %pISpc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345
+ %p[Ii]S[pfschnbl]
+
+ For printing an IP address without the need to distinguish whether it's
+ of type AF_INET or AF_INET6, a pointer to a valid 'struct sockaddr',
+ specified through 'IS' or 'iS', can be passed to this format specifier.
+
+ The additional 'p', 'f', and 's' specifiers are used to specify port
+ (IPv4, IPv6), flowinfo (IPv6) and scope (IPv6). Ports have a ':' prefix,
+ flowinfo a '/' and scope a '%', each followed by the actual value.
+
+ In case of an IPv6 address the compressed IPv6 address as described by
+ http://tools.ietf.org/html/rfc5952 is being used if the additional
+ specifier 'c' is given. The IPv6 address is surrounded by '[', ']' in
+ case of additional specifiers 'p', 'f' or 's' as suggested by
+ https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07
+
+ In case of IPv4 addresses, the additional 'h', 'n', 'b', and 'l'
+ specifiers can be used as well and are ignored in case of an IPv6
+ address.
+
+ Further examples:
+
+ %pISfc 1.2.3.4 or [1:2:3:4:5:6:7:8]/123456789
+ %pISsc 1.2.3.4 or [1:2:3:4:5:6:7:8]%1234567890
+ %pISpfc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345/123456789
+
UUID/GUID addresses:
%pUb 00010203-0405-0607-0809-0a0b0c0d0e0f
diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
index 7d2b4c9b544b..1039b68fe9c6 100644
--- a/Documentation/pwm.txt
+++ b/Documentation/pwm.txt
@@ -45,6 +45,43 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
+Using PWMs with the sysfs interface
+-----------------------------------
+
+If CONFIG_SYSFS is enabled in your kernel configuration a simple sysfs
+interface is provided to use the PWMs from userspace. It is exposed at
+/sys/class/pwm/. Each probed PWM controller/chip will be exported as
+pwmchipN, where N is the base of the PWM chip. Inside the directory you
+will find:
+
+npwm - The number of PWM channels this chip supports (read-only).
+
+export - Exports a PWM channel for use with sysfs (write-only).
+
+unexport - Unexports a PWM channel from sysfs (write-only).
+
+The PWM channels are numbered using a per-chip index from 0 to npwm-1.
+
+When a PWM channel is exported a pwmX directory will be created in the
+pwmchipN directory it is associated with, where X is the number of the
+channel that was exported. The following properties will then be available:
+
+period - The total period of the PWM signal (read/write).
+ Value is in nanoseconds and is the sum of the active and inactive
+ time of the PWM.
+
+duty_cycle - The active time of the PWM signal (read/write).
+ Value is in nanoseconds and must be less than the period.
+
+polarity - Changes the polarity of the PWM signal (read/write).
+ Writes to this property only work if the PWM chip supports changing
+ the polarity. The polarity can only be changed if the PWM is not
+ enabled. Value is the string "normal" or "inversed".
+
+enable - Enable/disable the PWM signal (read/write).
+ 0 - disabled
+ 1 - enabled
+
Implementing a PWM driver
-------------------------
diff --git a/Documentation/rapidio/rapidio.txt b/Documentation/rapidio/rapidio.txt
index a9c16c979da2..717f5aa388b1 100644
--- a/Documentation/rapidio/rapidio.txt
+++ b/Documentation/rapidio/rapidio.txt
@@ -73,28 +73,44 @@ data structure. This structure includes lists of all devices and local master
ports that form the same network. It also contains a pointer to the default
master port that is used to communicate with devices within the network.
+2.5 Device Drivers
+
+RapidIO device-specific drivers follow Linux Kernel Driver Model and are
+intended to support specific RapidIO devices attached to the RapidIO network.
+
+2.6 Subsystem Interfaces
+
+RapidIO interconnect specification defines features that may be used to provide
+one or more common service layers for all participating RapidIO devices. These
+common services may act separately from device-specific drivers or be used by
+device-specific drivers. Example of such service provider is the RIONET driver
+which implements Ethernet-over-RapidIO interface. Because only one driver can be
+registered for a device, all common RapidIO services have to be registered as
+subsystem interfaces. This allows to have multiple common services attached to
+the same device without blocking attachment of a device-specific driver.
+
3. Subsystem Initialization
---------------------------
In order to initialize the RapidIO subsystem, a platform must initialize and
register at least one master port within the RapidIO network. To register mport
-within the subsystem controller driver initialization code calls function
+within the subsystem controller driver's initialization code calls function
rio_register_mport() for each available master port.
-RapidIO subsystem uses subsys_initcall() or device_initcall() to perform
-controller initialization (depending on controller device type).
-
After all active master ports are registered with a RapidIO subsystem,
an enumeration and/or discovery routine may be called automatically or
by user-space command.
+RapidIO subsystem can be configured to be built as a statically linked or
+modular component of the kernel (see details below).
+
4. Enumeration and Discovery
----------------------------
4.1 Overview
------------
-RapidIO subsystem configuration options allow users to specify enumeration and
+RapidIO subsystem configuration options allow users to build enumeration and
discovery methods as statically linked components or loadable modules.
An enumeration/discovery method implementation and available input parameters
define how any given method can be attached to available RapidIO mports:
@@ -115,8 +131,8 @@ several methods to initiate an enumeration and/or discovery process:
endpoint waits for enumeration to be completed. If the specified timeout
expires the discovery process is terminated without obtaining RapidIO network
information. NOTE: a timed out discovery process may be restarted later using
- a user-space command as it is described later if the given endpoint was
- enumerated successfully.
+ a user-space command as it is described below (if the given endpoint was
+ enumerated successfully).
(b) Statically linked enumeration and discovery process can be started by
a command from user space. This initiation method provides more flexibility
@@ -138,15 +154,42 @@ When a network scan process is started it calls an enumeration or discovery
routine depending on the configured role of a master port: host or agent.
Enumeration is performed by a master port if it is configured as a host port by
-assigning a host device ID greater than or equal to zero. A host device ID is
-assigned to a master port through the kernel command line parameter "riohdid=",
-or can be configured in a platform-specific manner. If the host device ID for
-a specific master port is set to -1, the discovery process will be performed
-for it.
+assigning a host destination ID greater than or equal to zero. The host
+destination ID can be assigned to a master port using various methods depending
+on RapidIO subsystem build configuration:
+
+ (a) For a statically linked RapidIO subsystem core use command line parameter
+ "rapidio.hdid=" with a list of destination ID assignments in order of mport
+ device registration. For example, in a system with two RapidIO controllers
+ the command line parameter "rapidio.hdid=-1,7" will result in assignment of
+ the host destination ID=7 to the second RapidIO controller, while the first
+ one will be assigned destination ID=-1.
+
+ (b) If the RapidIO subsystem core is built as a loadable module, in addition
+ to the method shown above, the host destination ID(s) can be specified using
+ traditional methods of passing module parameter "hdid=" during its loading:
+ - from command line: "modprobe rapidio hdid=-1,7", or
+ - from modprobe configuration file using configuration command "options",
+ like in this example: "options rapidio hdid=-1,7". An example of modprobe
+ configuration file is provided in the section below.
+
+ NOTES:
+ (i) if "hdid=" parameter is omitted all available mport will be assigned
+ destination ID = -1;
+ (ii) the "hdid=" parameter in systems with multiple mports can have
+ destination ID assignments omitted from the end of list (default = -1).
+
+If the host device ID for a specific master port is set to -1, the discovery
+process will be performed for it.
The enumeration and discovery routines use RapidIO maintenance transactions
to access the configuration space of devices.
+NOTE: If RapidIO switch-specific device drivers are built as loadable modules
+they must be loaded before enumeration/discovery process starts.
+This requirement is cased by the fact that enumeration/discovery methods invoke
+vendor-specific callbacks on early stages.
+
4.2 Automatic Start of Enumeration and Discovery
------------------------------------------------
@@ -266,7 +309,36 @@ method's module initialization routine calls rio_register_scan() to attach
an enumerator to a specified mport device (or devices). The basic enumerator
implementation demonstrates this process.
-5. References
+4.6 Using Loadable RapidIO Switch Drivers
+-----------------------------------------
+
+In the case when RapidIO switch drivers are built as loadable modules a user
+must ensure that they are loaded before the enumeration/discovery starts.
+This process can be automated by specifying pre- or post- dependencies in the
+RapidIO-specific modprobe configuration file as shown in the example below.
+
+ File /etc/modprobe.d/rapidio.conf:
+ ----------------------------------
+
+ # Configure RapidIO subsystem modules
+
+ # Set enumerator host destination ID (overrides kernel command line option)
+ options rapidio hdid=-1,2
+
+ # Load RapidIO switch drivers immediately after rapidio core module was loaded
+ softdep rapidio post: idt_gen2 idtcps tsi57x
+
+ # OR :
+
+ # Load RapidIO switch drivers just before rio-scan enumerator module is loaded
+ softdep rio-scan pre: idt_gen2 idtcps tsi57x
+
+ --------------------------
+
+NOTE: In the example above, one of "softdep" commands must be removed or
+commented out to keep required module loading sequence.
+
+A. References
-------------
[1] RapidIO Trade Association. RapidIO Interconnect Specifications.
diff --git a/Documentation/rapidio/sysfs.txt b/Documentation/rapidio/sysfs.txt
index 19878179da4c..271438c0617f 100644
--- a/Documentation/rapidio/sysfs.txt
+++ b/Documentation/rapidio/sysfs.txt
@@ -40,6 +40,7 @@ device_rev - returns the device revision level
(see 4.1 for switch specific details)
lprev - returns name of previous device (switch) on the path to the device
that that owns this attribute
+ modalias - returns the device modalias
In addition to the files listed above, each device has a binary attribute file
that allows read/write access to the device configuration registers using
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 32aa4002de4a..596b60c08b74 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -153,9 +153,10 @@ since_epoch: The number of seconds since the epoch according to the RTC
time: RTC-provided time
wakealarm: The time at which the clock will generate a system wakeup
event. This is a one shot wakeup event, so must be reset
- after wake if a daily wakeup is required. Format is either
- seconds since the epoch or, if there's a leading +, seconds
- in the future.
+ after wake if a daily wakeup is required. Format is seconds since
+ the epoch by default, or if there's a leading +, seconds in the
+ future, or if there is a leading +=, seconds ahead of the current
+ alarm.
IOCTL INTERFACE
---------------
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 09673c7fc8ee..cc92ca8c8963 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,25 @@
+Release Date : Wed. May 15, 2013 17:00:00 PST 2013 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Adam Radford
+ Kashyap Desai
+ Sumit Saxena
+Current Version : 06.600.18.00-rc1
+Old Version : 06.506.00.00-rc1
+ 1. Return DID_ERROR for scsi io, when controller is in critical h/w error.
+ 2. Fix the interrupt mask for Gen2 controller.
+ 3. Update balance count in driver to be in sync of firmware.
+ 4. Free event detail memory without device ID check.
+ 5. Set IO request timeout value provided by OS timeout for Tape devices.
+ 6. Add support for MegaRAID Fury (device ID-0x005f) 12Gb/s controllers.
+ 7. Add support to display Customer branding details in syslog.
+ 8. Set IoFlags to enable Fast Path for JBODs for Invader/Fury(12 Gb/s)
+ controllers.
+ 9. Add support for Extended MSI-x vectors for Invader and Fury(12Gb/s
+ HBA).
+ 10.Add support for Uneven Span PRL11.
+ 11.Add support to differentiate between iMR and MR Firmware.
+ 12.Version and Changelog update.
+-------------------------------------------------------------------------------
Release Date : Sat. Feb 9, 2013 17:00:00 PST 2013 -
(emaild-id:megaraidlinux@lsi.com)
Adam Radford
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 77d68e23b247..809d72b8eff1 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -21,41 +21,41 @@ ALC267/268
==========
inv-dmic Inverted internal mic workaround
-ALC269/270/275/276/280/282
+ALC269/270/275/276/28x/29x
======
- laptop-amic Laptops with analog-mic input
- laptop-dmic Laptops with digital-mic input
- alc269-dmic Enable ALC269(VA) digital mic workaround
- alc271-dmic Enable ALC271X digital mic workaround
- inv-dmic Inverted internal mic workaround
- lenovo-dock Enables docking station I/O for some Lenovos
+ laptop-amic Laptops with analog-mic input
+ laptop-dmic Laptops with digital-mic input
+ alc269-dmic Enable ALC269(VA) digital mic workaround
+ alc271-dmic Enable ALC271X digital mic workaround
+ inv-dmic Inverted internal mic workaround
+ lenovo-dock Enables docking station I/O for some Lenovos
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
-ALC662/663/272
+ALC66x/67x/892
==============
- mario Chromebook mario model fixup
- asus-mode1 ASUS
- asus-mode2 ASUS
- asus-mode3 ASUS
- asus-mode4 ASUS
- asus-mode5 ASUS
- asus-mode6 ASUS
- asus-mode7 ASUS
- asus-mode8 ASUS
- inv-dmic Inverted internal mic workaround
+ mario Chromebook mario model fixup
+ asus-mode1 ASUS
+ asus-mode2 ASUS
+ asus-mode3 ASUS
+ asus-mode4 ASUS
+ asus-mode5 ASUS
+ asus-mode6 ASUS
+ asus-mode7 ASUS
+ asus-mode8 ASUS
+ inv-dmic Inverted internal mic workaround
dell-headset-multi Headset jack, which can also be used as mic-in
ALC680
======
N/A
-ALC882/883/885/888/889
+ALC88x/898/1150
======================
acer-aspire-4930g Acer Aspire 4930G/5930G/6530G/6930G/7730G
acer-aspire-8930g Acer Aspire 8330G/6935G
acer-aspire Acer Aspire others
- inv-dmic Inverted internal mic workaround
+ inv-dmic Inverted internal mic workaround
no-primary-hp VAIO Z/VGC-LN51JGB workaround (for fixed speaker DAC)
ALC861/660
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
index 98335b7a5337..d69e14c9002c 100644
--- a/Documentation/sysctl/net.txt
+++ b/Documentation/sysctl/net.txt
@@ -1,4 +1,4 @@
-Documentation for /proc/sys/net/* kernel version 2.4.0-test11-pre4
+Documentation for /proc/sys/net/*
(c) 1999 Terrehon Bowden <terrehon@pacbell.net>
Bodo Bauer <bb@ricochet.net>
(c) 2000 Jorge Nerin <comandante@zaralinux.com>
@@ -9,10 +9,10 @@ For general info and legal blurb, please look in README.
==============================================================
This file contains the documentation for the sysctl files in
-/proc/sys/net and is valid for Linux kernel version 2.4.0-test11-pre4.
+/proc/sys/net
The interface to the networking parts of the kernel is located in
-/proc/sys/net. The following table shows all possible subdirectories.You may
+/proc/sys/net. The following table shows all possible subdirectories. You may
see only some of them, depending on your kernel's configuration.
@@ -26,7 +26,7 @@ Table : Subdirectories in /proc/sys/net
ipv4 IP version 4 x25 X.25 protocol
ipx IPX token-ring IBM token ring
bridge Bridging decnet DEC net
- ipv6 IP version 6
+ ipv6 IP version 6 tipc TIPC
..............................................................................
1. /proc/sys/net/core - Network core options
@@ -50,6 +50,29 @@ The maximum number of packets that kernel can handle on a NAPI interrupt,
it's a Per-CPU variable.
Default: 64
+low_latency_read
+----------------
+Low latency busy poll timeout for socket reads. (needs CONFIG_NET_LL_RX_POLL)
+Approximate time in us to busy loop waiting for packets on the device queue.
+This sets the default value of the SO_LL socket option.
+Can be set or overridden per socket by setting socket option SO_LL, which is
+the preferred method of enabling.
+If you need to enable the feature globally via sysctl, a value of 50 is recommended.
+Will increase power usage.
+Default: 0 (off)
+
+low_latency_poll
+----------------
+Low latency busy poll timeout for poll and select. (needs CONFIG_NET_LL_RX_POLL)
+Approximate time in us to busy loop waiting for events.
+Recommended value depends on the number of sockets you poll on.
+For several sockets 50, for several hundreds 100.
+For more than that you probably want to use epoll.
+Note that only sockets with SO_LL set will be busy polled, so you want to either
+selectively set SO_LL on those sockets or set sysctl.net.low_latency_read globally.
+Will increase power usage.
+Default: 0 (off)
+
rmem_default
------------
@@ -93,8 +116,7 @@ netdev_budget
Maximum number of packets taken from all interfaces in one polling cycle (NAPI
poll). In one polling cycle interfaces which are registered to polling are
-probed in a round-robin manner. The limit of packets in one such probe can be
-set per-device via sysfs class/net/<device>/weight .
+probed in a round-robin manner.
netdev_max_backlog
------------------
@@ -201,3 +223,18 @@ IPX.
The /proc/net/ipx_route table holds a list of IPX routes. For each route it
gives the destination network, the router node (or Directly) and the network
address of the router (or Connected) for internal networks.
+
+6. TIPC
+-------------------------------------------------------
+
+The TIPC protocol now has a tunable for the receive memory, similar to the
+tcp_rmem - i.e. a vector of 3 INTEGERs: (min, default, max)
+
+ # cat /proc/sys/net/tipc/tipc_rmem
+ 4252725 34021800 68043600
+ #
+
+The max value is set to CONN_OVERLOAD_LIMIT, and the default and min values
+are scaled (shifted) versions of that same value. Note that the min value
+is not at this point in time used in any meaningful way, but the triplet is
+preserved in order to be consistent with things like tcp_rmem.
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index dcc75a9ed919..36ecc26c7433 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -510,7 +510,7 @@ Specify "[Dd]efault" to request automatic configuration. Autoconfiguration
will select "node" order in following case.
(1) if the DMA zone does not exist or
(2) if the DMA zone comprises greater than 50% of the available memory or
-(3) if any node's DMA zone comprises greater than 60% of its local memory and
+(3) if any node's DMA zone comprises greater than 70% of its local memory and
the amount of local memory is big enough.
Otherwise, "zone" order will be selected. Default order is recommended unless
diff --git a/Documentation/thermal/exynos_thermal_emulation b/Documentation/thermal/exynos_thermal_emulation
index 36a3e79c1203..b15efec6ca28 100644
--- a/Documentation/thermal/exynos_thermal_emulation
+++ b/Documentation/thermal/exynos_thermal_emulation
@@ -20,7 +20,7 @@ When it's enabled, sysfs node will be created as
The sysfs node, 'emul_node', will contain value 0 for the initial state. When you input any
temperature you want to update to sysfs node, it automatically enable emulation mode and
current temperature will be changed into it.
-(Exynos also supports user changable delay time which would be used to delay of
+(Exynos also supports user changeable delay time which would be used to delay of
changing temperature. However, this node only uses same delay of real sensing time, 938us.)
Exynos emulation mode requires synchronous of value changing and enabling. It means when you
diff --git a/Documentation/thermal/x86_pkg_temperature_thermal b/Documentation/thermal/x86_pkg_temperature_thermal
new file mode 100644
index 000000000000..17a3a4c0a0ca
--- /dev/null
+++ b/Documentation/thermal/x86_pkg_temperature_thermal
@@ -0,0 +1,47 @@
+Kernel driver: x86_pkg_temp_thermal
+===================
+
+Supported chips:
+* x86: with package level thermal management
+(Verify using: CPUID.06H:EAX[bit 6] =1)
+
+Authors: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+
+Reference
+---
+Intel® 64 and IA-32 Architectures Software Developer’s Manual (Jan, 2013):
+Chapter 14.6: PACKAGE LEVEL THERMAL MANAGEMENT
+
+Description
+---------
+
+This driver register CPU digital temperature package level sensor as a thermal
+zone with maximum two user mode configurable trip points. Number of trip points
+depends on the capability of the package. Once the trip point is violated,
+user mode can receive notification via thermal notification mechanism and can
+take any action to control temperature.
+
+
+Threshold management
+--------------------
+Each package will register as a thermal zone under /sys/class/thermal.
+Example:
+/sys/class/thermal/thermal_zone1
+
+This contains two trip points:
+- trip_point_0_temp
+- trip_point_1_temp
+
+User can set any temperature between 0 to TJ-Max temperature. Temperature units
+are in milli-degree Celsius. Refer to "Documentation/thermal/sysfs-api.txt" for
+thermal sys-fs details.
+
+Any value other than 0 in these trip points, can trigger thermal notifications.
+Setting 0, stops sending thermal notifications.
+
+Thermal notifications: To get kobject-uevent notifications, set the thermal zone
+policy to "user_space". For example: echo -n "user_space" > policy
+
+
+
+
diff --git a/Documentation/trace/events-power.txt b/Documentation/trace/events-power.txt
index e1498ff8cf94..3bd33b8dc7c4 100644
--- a/Documentation/trace/events-power.txt
+++ b/Documentation/trace/events-power.txt
@@ -63,3 +63,34 @@ power_domain_target "%s state=%lu cpu_id=%lu"
The first parameter gives the power domain name (e.g. "mpu_pwrdm").
The second parameter is the power domain target state.
+4. PM QoS events
+================
+The PM QoS events are used for QoS add/update/remove request and for
+target/flags update.
+
+pm_qos_add_request "pm_qos_class=%s value=%d"
+pm_qos_update_request "pm_qos_class=%s value=%d"
+pm_qos_remove_request "pm_qos_class=%s value=%d"
+pm_qos_update_request_timeout "pm_qos_class=%s value=%d, timeout_us=%ld"
+
+The first parameter gives the QoS class name (e.g. "CPU_DMA_LATENCY").
+The second parameter is value to be added/updated/removed.
+The third parameter is timeout value in usec.
+
+pm_qos_update_target "action=%s prev_value=%d curr_value=%d"
+pm_qos_update_flags "action=%s prev_value=0x%x curr_value=0x%x"
+
+The first parameter gives the QoS action name (e.g. "ADD_REQ").
+The second parameter is the previous QoS value.
+The third parameter is the current QoS value to update.
+
+And, there are also events used for device PM QoS add/update/remove request.
+
+dev_pm_qos_add_request "device=%s type=%s new_value=%d"
+dev_pm_qos_update_request "device=%s type=%s new_value=%d"
+dev_pm_qos_remove_request "device=%s type=%s new_value=%d"
+
+The first parameter gives the device name which tries to add/update/remove
+QoS requests.
+The second parameter gives the request type (e.g. "DEV_PM_QOS_LATENCY").
+The third parameter is value to be added/updated/removed.
diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt
index bb24c2a0e870..37732a220d33 100644
--- a/Documentation/trace/events.txt
+++ b/Documentation/trace/events.txt
@@ -183,13 +183,22 @@ The relational-operators depend on the type of the field being tested:
The operators available for numeric fields are:
-==, !=, <, <=, >, >=
+==, !=, <, <=, >, >=, &
And for string fields they are:
-==, !=
+==, !=, ~
-Currently, only exact string matches are supported.
+The glob (~) only accepts a wild card character (*) at the start and or
+end of the string. For example:
+
+ prev_comm ~ "*sh"
+ prev_comm ~ "sh*"
+ prev_comm ~ "*sh*"
+
+But does not allow for it to be within the string:
+
+ prev_comm ~ "ba*sh" <-- is invalid
5.2 Setting filters
-------------------
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index bfe8c29b1f1d..b937c6e2163c 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -2430,6 +2430,19 @@ The following commands are supported:
echo '!schedule:disable_event:sched:sched_switch' > \
set_ftrace_filter
+- dump
+ When the function is hit, it will dump the contents of the ftrace
+ ring buffer to the console. This is useful if you need to debug
+ something, and want to dump the trace when a certain function
+ is hit. Perhaps its a function that is called before a tripple
+ fault happens and does not allow you to get a regular dump.
+
+- cpudump
+ When the function is hit, it will dump the contents of the ftrace
+ ring buffer for the current CPU to the console. Unlike the "dump"
+ command, it only prints out the contents of the ring buffer for the
+ CPU that executed the function that triggered the dump.
+
trace_pipe
----------
diff --git a/Documentation/vfio.txt b/Documentation/vfio.txt
index 8eda3635a17d..d7993dcf8537 100644
--- a/Documentation/vfio.txt
+++ b/Documentation/vfio.txt
@@ -172,12 +172,12 @@ group and can access them as follows:
struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
/* Create a new container */
- container = open("/dev/vfio/vfio, O_RDWR);
+ container = open("/dev/vfio/vfio", O_RDWR);
if (ioctl(container, VFIO_GET_API_VERSION) != VFIO_API_VERSION)
/* Unknown API version */
- if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_X86_IOMMU))
+ if (!ioctl(container, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU))
/* Doesn't support the IOMMU driver we want. */
/* Open the group */
@@ -193,7 +193,7 @@ group and can access them as follows:
ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
/* Enable the IOMMU model we want */
- ioctl(container, VFIO_SET_IOMMU, VFIO_X86_IOMMU)
+ ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU)
/* Get addition IOMMU info */
ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);
@@ -283,6 +283,69 @@ a direct pass through for VFIO_DEVICE_* ioctls. The read/write/mmap
interfaces implement the device region access defined by the device's
own VFIO_DEVICE_GET_REGION_INFO ioctl.
+
+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)
+(PE is often a PCI domain but not always).
+
+2) The hardware supports so called DMA windows - the PCI address range
+within which DMA transfer is allowed, any attempt to access address space
+out of the window leads to the whole PE isolation.
+
+3) PPC64 guests are paravirtualized but not fully emulated. There is an API
+to map/unmap pages for DMA, and it normally maps 1..32 pages per call and
+currently there is no way to reduce the number of calls. In order to make things
+faster, the map/unmap handling has been implemented in real mode which provides
+an excellent performance which has limitations such as inability to do
+locked pages accounting in real time.
+
+So 3 additional ioctls have been added:
+
+ VFIO_IOMMU_SPAPR_TCE_GET_INFO - returns the size and the start
+ of the DMA window on the PCI bus.
+
+ VFIO_IOMMU_ENABLE - enables the container. The locked pages accounting
+ is done at this point. This lets user first to know what
+ the DMA window is and adjust rlimit before doing any real job.
+
+ VFIO_IOMMU_DISABLE - disables the container.
+
+
+The code flow from the example above should be slightly changed:
+
+ .....
+ /* Add the group to the container */
+ ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
+
+ /* Enable the IOMMU model we want */
+ ioctl(container, VFIO_SET_IOMMU, VFIO_SPAPR_TCE_IOMMU)
+
+ /* Get addition sPAPR IOMMU info */
+ vfio_iommu_spapr_tce_info spapr_iommu_info;
+ ioctl(container, VFIO_IOMMU_SPAPR_TCE_GET_INFO, &spapr_iommu_info);
+
+ if (ioctl(container, VFIO_IOMMU_ENABLE))
+ /* Cannot enable container, may be low rlimit */
+
+ /* Allocate some space and setup a DMA mapping */
+ dma_map.vaddr = mmap(0, 1024 * 1024, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+
+ dma_map.size = 1024 * 1024;
+ dma_map.iova = 0; /* 1MB starting at 0x0 from device view */
+ dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;
+
+ /* Check here is .iova/.size are within DMA window from spapr_iommu_info */
+
+ ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map);
+ .....
+
-------------------------------------------------------------------------------
[1] VFIO was originally an acronym for "Virtual Function I/O" in its
diff --git a/Documentation/video4linux/si476x.txt b/Documentation/video4linux/si476x.txt
index d1a08db2cbd9..2f9b4875ab8a 100644
--- a/Documentation/video4linux/si476x.txt
+++ b/Documentation/video4linux/si476x.txt
@@ -166,7 +166,7 @@ The drivers exposes following files:
--------------------------------------------------------------------
0x21 | dev | Frequency deviation
--------------------------------------------------------------------
- 0x24 | assi | Adjascent channel SSI
+ 0x24 | assi | Adjacent channel SSI
--------------------------------------------------------------------
0x25 | usn | Ultrasonic noise indicator
--------------------------------------------------------------------
diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt
index f62fcdbc8b9f..daa9e2ac162c 100644
--- a/Documentation/video4linux/soc-camera.txt
+++ b/Documentation/video4linux/soc-camera.txt
@@ -116,7 +116,7 @@ VIDIOC_S_FMT: sets user window. Should preserve previously set sensor window as
much as possible by modifying scaling factors. If the sensor window cannot be
preserved precisely, it may be changed too.
-In soc-camera there are two locations, where scaling and cropping can taks
+In soc-camera there are two locations, where scaling and cropping can take
place: in the camera driver and in the host driver. User ioctls are first passed
to the host driver, which then generally passes them down to the camera driver.
It is more efficient to perform scaling and cropping in the camera driver to
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 5f91eda91647..ef925eaa1460 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -280,7 +280,7 @@ kvm_run' (see below).
4.11 KVM_GET_REGS
Capability: basic
-Architectures: all except ARM
+Architectures: all except ARM, arm64
Type: vcpu ioctl
Parameters: struct kvm_regs (out)
Returns: 0 on success, -1 on error
@@ -301,7 +301,7 @@ struct kvm_regs {
4.12 KVM_SET_REGS
Capability: basic
-Architectures: all except ARM
+Architectures: all except ARM, arm64
Type: vcpu ioctl
Parameters: struct kvm_regs (in)
Returns: 0 on success, -1 on error
@@ -587,7 +587,7 @@ struct kvm_fpu {
4.24 KVM_CREATE_IRQCHIP
Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64, ARM
+Architectures: x86, ia64, ARM, arm64
Type: vm ioctl
Parameters: none
Returns: 0 on success, -1 on error
@@ -595,14 +595,14 @@ Returns: 0 on success, -1 on error
Creates an interrupt controller model in the kernel. On x86, creates a virtual
ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a
local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23
-only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM, a GIC is
+only go to the IOAPIC. On ia64, a IOSAPIC is created. On ARM/arm64, a GIC is
created.
4.25 KVM_IRQ_LINE
Capability: KVM_CAP_IRQCHIP
-Architectures: x86, ia64, arm
+Architectures: x86, ia64, arm, arm64
Type: vm ioctl
Parameters: struct kvm_irq_level
Returns: 0 on success, -1 on error
@@ -612,9 +612,10 @@ On some architectures it is required that an interrupt controller model has
been previously created with KVM_CREATE_IRQCHIP. Note that edge-triggered
interrupts require the level to be set to 1 and then back to 0.
-ARM can signal an interrupt either at the CPU level, or at the in-kernel irqchip
-(GIC), and for in-kernel irqchip can tell the GIC to use PPIs designated for
-specific cpus. The irq field is interpreted like this:
+ARM/arm64 can signal an interrupt either at the CPU level, or at the
+in-kernel irqchip (GIC), and for in-kernel irqchip can tell the GIC to
+use PPIs designated for specific cpus. The irq field is interpreted
+like this:
 bits: | 31 ... 24 | 23 ... 16 | 15 ... 0 |
field: | irq_type | vcpu_index | irq_id |
@@ -1683,7 +1684,7 @@ The parameter is defined like this:
This ioctl maps the memory at "user_addr" with the length "length" to
the vcpu's address space starting at "vcpu_addr". All parameters need to
-be alligned by 1 megabyte.
+be aligned by 1 megabyte.
4.66 KVM_S390_UCAS_UNMAP
@@ -1703,7 +1704,7 @@ The parameter is defined like this:
This ioctl unmaps the memory in the vcpu's address space starting at
"vcpu_addr" with the length "length". The field "user_addr" is ignored.
-All parameters need to be alligned by 1 megabyte.
+All parameters need to be aligned by 1 megabyte.
4.67 KVM_S390_VCPU_FAULT
@@ -1831,6 +1832,22 @@ ARM 32-bit VFP control registers have the following id bit patterns:
ARM 64-bit FP registers have the following id bit patterns:
0x4030 0000 0012 0 <regno:12>
+
+arm64 registers are mapped using the lower 32 bits. The upper 16 of
+that is the register group type, or coprocessor number:
+
+arm64 core/FP-SIMD registers have the following id bit patterns. Note
+that the size of the access is variable, as the kvm_regs structure
+contains elements ranging from 32 to 128 bits. The index is a 32bit
+value in the kvm_regs structure seen as a 32bit array.
+ 0x60x0 0000 0010 <index into the kvm_regs struct:16>
+
+arm64 CCSIDR registers are demultiplexed by CSSELR value:
+ 0x6020 0000 0011 00 <csselr:8>
+
+arm64 system registers have the following id bit patterns:
+ 0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
+
4.69 KVM_GET_ONE_REG
Capability: KVM_CAP_ONE_REG
@@ -1972,7 +1989,7 @@ Returns: 0 on success, -1 on error
This populates and returns a structure describing the features of
the "Server" class MMU emulation supported by KVM.
-This can in turn be used by userspace to generate the appropariate
+This can in turn be used by userspace to generate the appropriate
device-tree properties for the guest operating system.
The structure contains some global informations, followed by an
@@ -2019,7 +2036,7 @@ be OR'ed into the "vsid" argument of the slbmte instruction.
The "enc" array is a list which for each of those segment base page
size provides the list of supported actual page sizes (which can be
only larger or equal to the base page size), along with the
-corresponding encoding in the hash PTE. Similarily, the array is
+corresponding encoding in the hash PTE. Similarly, the array is
8 entries sorted by increasing sizes and an entry with a "0" shift
is an empty entry and a terminator:
@@ -2261,10 +2278,10 @@ return indicates the attribute is implemented. It does not necessarily
indicate that the attribute can be read or written in the device's
current state. "addr" is ignored.
-4.77 KVM_ARM_VCPU_INIT
+4.82 KVM_ARM_VCPU_INIT
Capability: basic
-Architectures: arm
+Architectures: arm, arm64
Type: vcpu ioctl
Parameters: struct struct kvm_vcpu_init (in)
Returns: 0 on success; -1 on error
@@ -2283,12 +2300,14 @@ should be created before this ioctl is invoked.
Possible features:
- KVM_ARM_VCPU_POWER_OFF: Starts the CPU in a power-off state.
Depends on KVM_CAP_ARM_PSCI.
+ - KVM_ARM_VCPU_EL1_32BIT: Starts the CPU in a 32bit mode.
+ Depends on KVM_CAP_ARM_EL1_32BIT (arm64 only).
-4.78 KVM_GET_REG_LIST
+4.83 KVM_GET_REG_LIST
Capability: basic
-Architectures: arm
+Architectures: arm, arm64
Type: vcpu ioctl
Parameters: struct kvm_reg_list (in/out)
Returns: 0 on success; -1 on error
@@ -2305,10 +2324,10 @@ This ioctl returns the guest registers that are supported for the
KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
-4.80 KVM_ARM_SET_DEVICE_ADDR
+4.84 KVM_ARM_SET_DEVICE_ADDR
Capability: KVM_CAP_ARM_SET_DEVICE_ADDR
-Architectures: arm
+Architectures: arm, arm64
Type: vm ioctl
Parameters: struct kvm_arm_device_address (in)
Returns: 0 on success, -1 on error
@@ -2329,20 +2348,21 @@ can access emulated or directly exposed devices, which the host kernel needs
to know about. The id field is an architecture specific identifier for a
specific device.
-ARM divides the id field into two parts, a device id and an address type id
-specific to the individual device.
+ARM/arm64 divides the id field into two parts, a device id and an
+address type id specific to the individual device.
 bits: | 63 ... 32 | 31 ... 16 | 15 ... 0 |
field: | 0x00000000 | device id | addr type id |
-ARM currently only require this when using the in-kernel GIC support for the
-hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2 as the device id. When
-setting the base address for the guest's mapping of the VGIC virtual CPU
-and distributor interface, the ioctl must be called after calling
-KVM_CREATE_IRQCHIP, but before calling KVM_RUN on any of the VCPUs. Calling
-this ioctl twice for any of the base addresses will return -EEXIST.
+ARM/arm64 currently only require this when using the in-kernel GIC
+support for the hardware VGIC features, using KVM_ARM_DEVICE_VGIC_V2
+as the device id. When setting the base address for the guest's
+mapping of the VGIC virtual CPU and distributor interface, the ioctl
+must be called after calling KVM_CREATE_IRQCHIP, but before calling
+KVM_RUN on any of the VCPUs. Calling this ioctl twice for any of the
+base addresses will return -EEXIST.
-4.82 KVM_PPC_RTAS_DEFINE_TOKEN
+4.85 KVM_PPC_RTAS_DEFINE_TOKEN
Capability: KVM_CAP_PPC_RTAS
Architectures: ppc
diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt
index 43fcb761ed16..290894176142 100644
--- a/Documentation/virtual/kvm/mmu.txt
+++ b/Documentation/virtual/kvm/mmu.txt
@@ -191,12 +191,12 @@ Shadow pages contain the following information:
A counter keeping track of how many hardware registers (guest cr3 or
pdptrs) are now pointing at the page. While this counter is nonzero, the
page cannot be destroyed. See role.invalid.
- multimapped:
- Whether there exist multiple sptes pointing at this page.
- parent_pte/parent_ptes:
- If multimapped is zero, parent_pte points at the single spte that points at
- this page's spt. Otherwise, parent_ptes points at a data structure
- with a list of parent_ptes.
+ parent_ptes:
+ The reverse mapping for the pte/ptes pointing at this page's spt. If
+ parent_ptes bit 0 is zero, only one spte points at this pages and
+ parent_ptes points at this single spte, otherwise, there exists multiple
+ sptes pointing at this page and (parent_ptes & ~0x1) points at a data
+ structure with a list of parent_ptes.
unsync:
If true, then the translations in this page may not match the guest's
translation. This is equivalent to the state of the tlb when a pte is
@@ -210,6 +210,24 @@ Shadow pages contain the following information:
A bitmap indicating which sptes in spt point (directly or indirectly) at
pages that may be unsynchronized. Used to quickly locate all unsychronized
pages reachable from a given page.
+ mmu_valid_gen:
+ Generation number of the page. It is compared with kvm->arch.mmu_valid_gen
+ during hash table lookup, and used to skip invalidated shadow pages (see
+ "Zapping all pages" below.)
+ clear_spte_count:
+ Only present on 32-bit hosts, where a 64-bit spte cannot be written
+ atomically. The reader uses this while running out of the MMU lock
+ to detect in-progress updates and retry them until the writer has
+ finished the write.
+ write_flooding_count:
+ A guest may write to a page table many times, causing a lot of
+ emulations if the page needs to be write-protected (see "Synchronized
+ and unsynchronized pages" below). Leaf pages can be unsynchronized
+ so that they do not trigger frequent emulation, but this is not
+ possible for non-leafs. This field counts the number of emulations
+ since the last time the page table was actually used; if emulation
+ is triggered too frequently on this page, KVM will unmap the page
+ to avoid emulation in the future.
Reverse map
===========
@@ -258,14 +276,26 @@ This is the most complicated event. The cause of a page fault can be:
Handling a page fault is performed as follows:
+ - if the RSV bit of the error code is set, the page fault is caused by guest
+ accessing MMIO and cached MMIO information is available.
+ - walk shadow page table
+ - check for valid generation number in the spte (see "Fast invalidation of
+ MMIO sptes" below)
+ - cache the information to vcpu->arch.mmio_gva, vcpu->arch.access and
+ vcpu->arch.mmio_gfn, and call the emulator
+ - If both P bit and R/W bit of error code are set, this could possibly
+ be handled as a "fast page fault" (fixed without taking the MMU lock). See
+ the description in Documentation/virtual/kvm/locking.txt.
- if needed, walk the guest page tables to determine the guest translation
(gva->gpa or ngpa->gpa)
- if permissions are insufficient, reflect the fault back to the guest
- determine the host page
- - if this is an mmio request, there is no host page; call the emulator
- to emulate the instruction instead
+ - if this is an mmio request, there is no host page; cache the info to
+ vcpu->arch.mmio_gva, vcpu->arch.access and vcpu->arch.mmio_gfn
- walk the shadow page table to find the spte for the translation,
instantiating missing intermediate page tables as necessary
+ - If this is an mmio request, cache the mmio info to the spte and set some
+ reserved bit on the spte (see callers of kvm_mmu_set_mmio_spte_mask)
- try to unsynchronize the page
- if successful, we can let the guest continue and modify the gpte
- emulate the instruction
@@ -351,6 +381,51 @@ causes its write_count to be incremented, thus preventing instantiation of
a large spte. The frames at the end of an unaligned memory slot have
artificially inflated ->write_counts so they can never be instantiated.
+Zapping all pages (page generation count)
+=========================================
+
+For the large memory guests, walking and zapping all pages is really slow
+(because there are a lot of pages), and also blocks memory accesses of
+all VCPUs because it needs to hold the MMU lock.
+
+To make it be more scalable, kvm maintains a global generation number
+which is stored in kvm->arch.mmu_valid_gen. Every shadow page stores
+the current global generation-number into sp->mmu_valid_gen when it
+is created. Pages with a mismatching generation number are "obsolete".
+
+When KVM need zap all shadow pages sptes, it just simply increases the global
+generation-number then reload root shadow pages on all vcpus. As the VCPUs
+create new shadow page tables, the old pages are not used because of the
+mismatching generation number.
+
+KVM then walks through all pages and zaps obsolete pages. While the zap
+operation needs to take the MMU lock, the lock can be released periodically
+so that the VCPUs can make progress.
+
+Fast invalidation of MMIO sptes
+===============================
+
+As mentioned in "Reaction to events" above, kvm will cache MMIO
+information in leaf sptes. When a new memslot is added or an existing
+memslot is changed, this information may become stale and needs to be
+invalidated. This also needs to hold the MMU lock while walking all
+shadow pages, and is made more scalable with a similar technique.
+
+MMIO sptes have a few spare bits, which are used to store a
+generation number. The global generation number is stored in
+kvm_memslots(kvm)->generation, and increased whenever guest memory info
+changes. This generation number is distinct from the one described in
+the previous section.
+
+When KVM finds an MMIO spte, it checks the generation number of the spte.
+If the generation number of the spte does not equal the global generation
+number, it will ignore the cached MMIO information and handle the page
+fault through the slow path.
+
+Since only 19 bits are used to store generation-number on mmio spte, all
+pages are zapped when there is an overflow.
+
+
Further reading
===============
diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt
index 7587493c67f1..5948e455c4d2 100644
--- a/Documentation/vm/pagemap.txt
+++ b/Documentation/vm/pagemap.txt
@@ -15,7 +15,8 @@ There are three components to pagemap:
* Bits 0-54 page frame number (PFN) if present
* Bits 0-4 swap type if swapped
* Bits 5-54 swap offset if swapped
- * Bits 55-60 page shift (page size = 1<<page shift)
+ * Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt)
+ * Bits 56-60 zero
* Bit 61 page is file-page or shared-anon
* Bit 62 page swapped
* Bit 63 page present
@@ -147,5 +148,5 @@ once.
Other notes:
Reading from any of the files will return -EINVAL if you are not starting
-the read on an 8-byte boundary (e.g., if you seeked an odd number of bytes
+the read on an 8-byte boundary (e.g., if you sought an odd number of bytes
into the file), or if the size of the read is not a multiple of 8 bytes.
diff --git a/Documentation/vm/soft-dirty.txt b/Documentation/vm/soft-dirty.txt
new file mode 100644
index 000000000000..9a12a5956bc0
--- /dev/null
+++ b/Documentation/vm/soft-dirty.txt
@@ -0,0 +1,36 @@
+ SOFT-DIRTY PTEs
+
+ The soft-dirty is a bit on a PTE which helps to track which pages a task
+writes to. In order to do this tracking one should
+
+ 1. Clear soft-dirty bits from the task's PTEs.
+
+ This is done by writing "4" into the /proc/PID/clear_refs file of the
+ task in question.
+
+ 2. Wait some time.
+
+ 3. Read soft-dirty bits from the PTEs.
+
+ This is done by reading from the /proc/PID/pagemap. The bit 55 of the
+ 64-bit qword is the soft-dirty one. If set, the respective PTE was
+ written to since step 1.
+
+
+ Internally, to do this tracking, the writable bit is cleared from PTEs
+when the soft-dirty bit is cleared. So, after this, when the task tries to
+modify a page at some virtual address the #PF occurs and the kernel sets
+the soft-dirty bit on the respective PTE.
+
+ Note, that although all the task's address space is marked as r/o after the
+soft-dirty bits clear, the #PF-s that occur after that are processed fast.
+This is so, since the pages are still mapped to physical memory, and thus all
+the kernel does is finds this fact out and puts both writable and soft-dirty
+bits on the PTE.
+
+
+ This feature is actively used by the checkpoint-restore project. You
+can find more details about it on http://criu.org
+
+
+-- Pavel Emelyanov, Apr 9, 2013
diff --git a/Documentation/vm/transhuge.txt b/Documentation/vm/transhuge.txt
index 8785fb87d9c7..4a63953a41f1 100644
--- a/Documentation/vm/transhuge.txt
+++ b/Documentation/vm/transhuge.txt
@@ -120,8 +120,8 @@ By default kernel tries to use huge zero page on read page fault.
It's possible to disable huge zero page by writing 0 or enable it
back by writing 1:
-echo 0 >/sys/kernel/mm/transparent_hugepage/khugepaged/use_zero_page
-echo 1 >/sys/kernel/mm/transparent_hugepage/khugepaged/use_zero_page
+echo 0 >/sys/kernel/mm/transparent_hugepage/use_zero_page
+echo 1 >/sys/kernel/mm/transparent_hugepage/use_zero_page
khugepaged will be automatically started when
transparent_hugepage/enabled is set to "always" or "madvise, and it'll
diff --git a/Documentation/vm/zswap.txt b/Documentation/vm/zswap.txt
new file mode 100644
index 000000000000..7e492d8aaeaf
--- /dev/null
+++ b/Documentation/vm/zswap.txt
@@ -0,0 +1,68 @@
+Overview:
+
+Zswap is a lightweight compressed cache for swap pages. It takes pages that are
+in the process of being swapped out and attempts to compress them into a
+dynamically allocated RAM-based memory pool. zswap basically trades CPU cycles
+for potentially reduced swap I/O.  This trade-off can also result in a
+significant performance improvement if reads from the compressed cache are
+faster than reads from a swap device.
+
+NOTE: Zswap is a new feature as of v3.11 and interacts heavily with memory
+reclaim. This interaction has not be fully explored on the large set of
+potential configurations and workloads that exist. For this reason, zswap
+is a work in progress and should be considered experimental.
+
+Some potential benefits:
+* Desktop/laptop users with limited RAM capacities can mitigate the
+    performance impact of swapping.
+* Overcommitted guests that share a common I/O resource can
+    dramatically reduce their swap I/O pressure, avoiding heavy handed I/O
+ throttling by the hypervisor. This allows more work to get done with less
+ impact to the guest workload and guests sharing the I/O subsystem
+* Users with SSDs as swap devices can extend the life of the device by
+    drastically reducing life-shortening writes.
+
+Zswap evicts pages from compressed cache on an LRU basis to the backing swap
+device when the compressed pool reaches it 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
+
+Design:
+
+Zswap receives pages for compression through the Frontswap API and is able to
+evict pages from its own compressed pool on an LRU basis and write them back to
+the backing swap device in the case that the compressed pool is full.
+
+Zswap makes use of zbud for the managing the compressed memory pool. Each
+allocation in zbud is not directly accessible by address. Rather, a handle is
+return by the allocation routine and that handle must be mapped before being
+accessed. The compressed memory pool grows on demand and shrinks as compressed
+pages are freed. The pool is not preallocated.
+
+When a swap page is passed from frontswap to zswap, zswap maintains a mapping
+of the swap entry, a combination of the swap type and swap offset, to the zbud
+handle that references that compressed swap page. This mapping is achieved
+with a red-black tree per swap type. The swap offset is the search key for the
+tree nodes.
+
+During a page fault on a PTE that is a swap entry, frontswap calls the zswap
+load function to decompress the page into the page allocated by the page fault
+handler.
+
+Once there are no PTEs referencing a swap page stored in zswap (i.e. the count
+in the swap_map goes to 0) the swap code calls the zswap invalidate function,
+via frontswap, to free the compressed entry.
+
+Zswap seeks to be simple in its policies. Sysfs attributes allow for one user
+controlled policies:
+* max_pool_percent - The maximum percentage of memory that the compressed
+ pool can occupy.
+
+Zswap allows the compressor to be selected at kernel boot time by setting the
+“compressor” attribute. The default compressor is lzo. e.g.
+zswap.compressor=deflate
+
+A debugfs interface is provided for various statistic about pool size, number
+of pages stored, and various counters for the reasons pages are rejected.
diff --git a/Documentation/w1/slaves/w1_ds28e04 b/Documentation/w1/slaves/w1_ds28e04
index 85bc9a7e02fe..7819b65cfa48 100644
--- a/Documentation/w1/slaves/w1_ds28e04
+++ b/Documentation/w1/slaves/w1_ds28e04
@@ -24,7 +24,7 @@ Memory Access
A write operation on the "eeprom" file writes the given byte sequence
to the EEPROM of the DS28E04. If CRC checking mode is enabled only
- fully alligned blocks of 32 bytes with valid CRC16 values (in bytes 30
+ fully aligned blocks of 32 bytes with valid CRC16 values (in bytes 30
and 31) are allowed to be written.
PIO Access
diff --git a/Documentation/x86/boot.txt b/Documentation/x86/boot.txt
index 3840b6f28afb..fc66d42422ee 100644
--- a/Documentation/x86/boot.txt
+++ b/Documentation/x86/boot.txt
@@ -657,9 +657,10 @@ Protocol: 2.08+
uncompressed data should be determined using the standard magic
numbers. The currently supported compression formats are gzip
(magic numbers 1F 8B or 1F 9E), bzip2 (magic number 42 5A), LZMA
- (magic number 5D 00), and XZ (magic number FD 37). The uncompressed
- payload is currently always ELF (magic number 7F 45 4C 46).
-
+ (magic number 5D 00), XZ (magic number FD 37), and LZ4 (magic number
+ 02 21). The uncompressed payload is currently always ELF (magic
+ number 7F 45 4C 46).
+
Field name: payload_length
Type: read
Offset/size: 0x24c/4
diff --git a/MAINTAINERS b/MAINTAINERS
index e626794c3860..9d771d9825cf 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -180,6 +180,11 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs.git
S: Maintained
F: Documentation/filesystems/9p.txt
F: fs/9p/
+F: net/9p/
+F: include/net/9p/
+F: include/uapi/linux/virtio_9p.h
+F: include/trace/events/9p.h
+
A8293 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
@@ -242,6 +247,11 @@ F: drivers/acpi/
F: drivers/pnp/pnpacpi/
F: include/linux/acpi.h
F: include/acpi/
+F: Documentation/acpi
+F: Documentation/ABI/testing/sysfs-bus-acpi
+F: drivers/pci/*acpi*
+F: drivers/pci/*/*acpi*
+F: drivers/pci/*/*/*acpi*
ACPI FAN DRIVER
M: Zhang Rui <rui.zhang@intel.com>
@@ -742,7 +752,7 @@ S: Maintained
F: arch/arm/mach-highbank/
ARM/CAVIUM NETWORKS CNS3XXX MACHINE SUPPORT
-M: Anton Vorontsov <avorontsov@mvista.com>
+M: Anton Vorontsov <anton@enomsg.org>
S: Maintained
F: arch/arm/mach-cns3xxx/
T: git git://git.infradead.org/users/cbou/linux-cns3xxx.git
@@ -1296,6 +1306,7 @@ S: Maintained
F: arch/arm/mach-vt8500/
F: drivers/clocksource/vt8500_timer.c
F: drivers/gpio/gpio-vt8500.c
+F: drivers/i2c/busses/i2c-wmt.c
F: drivers/mmc/host/wmt-sdmmc.c
F: drivers/pwm/pwm-vt8500.c
F: drivers/rtc/rtc-vt8500.c
@@ -1320,6 +1331,13 @@ W: http://wiki.xilinx.com
T: git git://git.xilinx.com/linux-xlnx.git
S: Supported
F: arch/arm/mach-zynq/
+F: drivers/cpuidle/cpuidle-zynq.c
+
+ARM SMMU DRIVER
+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
ARM64 PORT (AARCH64 ARCHITECTURE)
M: Catalin Marinas <catalin.marinas@arm.com>
@@ -1611,6 +1629,7 @@ F: drivers/net/wireless/b43legacy/
BACKLIGHT CLASS/SUBSYSTEM
M: Richard Purdie <rpurdie@rpsys.net>
+M: Jingoo Han <jg1.han@samsung.com>
S: Maintained
F: drivers/video/backlight/
F: include/linux/backlight.h
@@ -1869,6 +1888,13 @@ S: Odd fixes
F: Documentation/video4linux/bttv/
F: drivers/media/pci/bt8xx/bttv*
+BUSLOGIC SCSI DRIVER
+M: Khalid Aziz <khalid@gonehiking.org>
+L: linux-scsi@vger.kernel.org
+S: Maintained
+F: drivers/scsi/BusLogic.*
+F: drivers/scsi/FlashPoint.*
+
C-MEDIA CMI8788 DRIVER
M: Clemens Ladisch <clemens@ladisch.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -2109,9 +2135,12 @@ COCCINELLE/Semantic Patches (SmPL)
M: Julia Lawall <Julia.Lawall@lip6.fr>
M: Gilles Muller <Gilles.Muller@lip6.fr>
M: Nicolas Palix <nicolas.palix@imag.fr>
+M: Michal Marek <mmarek@suse.cz>
L: cocci@systeme.lip6.fr (moderated for non-subscribers)
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild.git misc
W: http://coccinelle.lip6.fr/
S: Supported
+F: Documentation/coccinelle.txt
F: scripts/coccinelle/
F: scripts/coccicheck
@@ -2131,9 +2160,10 @@ M: Mike Turquette <mturquette@linaro.org>
L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
T: git git://git.linaro.org/people/mturquette/linux.git
S: Maintained
-F: drivers/clk/clk.c
-F: drivers/clk/clk-*
+F: drivers/clk/
+X: drivers/clk/clkdev.c
F: include/linux/clk-pr*
+F: include/linux/clk/
COMMON INTERNET FILE SYSTEM (CIFS)
M: Steve French <sfrench@samba.org>
@@ -2226,7 +2256,8 @@ M: Viresh Kumar <viresh.kumar@linaro.org>
L: cpufreq@vger.kernel.org
L: linux-pm@vger.kernel.org
S: Maintained
-T: git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+T: git git://git.linaro.org/people/vireshk/linux.git (For ARM Updates)
F: drivers/cpufreq/
F: include/linux/cpufreq.h
@@ -2310,6 +2341,11 @@ M: Jaya Kumar <jayakumar.alsa@gmail.com>
S: Maintained
F: sound/pci/cs5535audio/
+CW1200 WLAN driver
+M: Solomon Peachy <pizza@shaftnet.org>
+S: Maintained
+F: drivers/net/wireless/cw1200/
+
CX18 VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
@@ -2527,7 +2563,7 @@ F: drivers/usb/dwc3/
DEVICE FREQUENCY (DEVFREQ)
M: MyungJoo Ham <myungjoo.ham@samsung.com>
M: Kyungmin Park <kyungmin.park@samsung.com>
-L: linux-kernel@vger.kernel.org
+L: linux-pm@vger.kernel.org
S: Maintained
F: drivers/devfreq/
@@ -2538,6 +2574,7 @@ S: Maintained
DEVICE-MAPPER (LVM)
M: Alasdair Kergon <agk@redhat.com>
+M: Mike Snitzer <snitzer@redhat.com>
M: dm-devel@redhat.com
L: dm-devel@redhat.com
W: http://sources.redhat.com/dm
@@ -2549,6 +2586,7 @@ F: drivers/md/dm*
F: drivers/md/persistent-data/
F: include/linux/device-mapper.h
F: include/linux/dm-*.h
+F: include/uapi/linux/dm-*.h
DIOLAN U2C-12 I2C DRIVER
M: Guenter Roeck <linux@roeck-us.net>
@@ -2708,12 +2746,14 @@ F: include/drm/exynos*
F: include/uapi/drm/exynos*
DRM DRIVERS FOR NVIDIA TEGRA
-M: Thierry Reding <thierry.reding@avionic-design.de>
+M: Thierry Reding <thierry.reding@gmail.com>
+M: Terje Bergström <tbergstrom@nvidia.com>
L: dri-devel@lists.freedesktop.org
L: linux-tegra@vger.kernel.org
-T: git git://gitorious.org/thierryreding/linux.git
+T: git git://anongit.freedesktop.org/tegra/linux.git
S: Maintained
-F: drivers/gpu/drm/tegra/
+F: drivers/gpu/host1x/
+F: include/uapi/drm/tegra_drm.h
F: Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
DSBR100 USB FM RADIO DRIVER
@@ -3114,6 +3154,13 @@ M: Maxim Levitsky <maximlevitsky@gmail.com>
S: Maintained
F: drivers/media/rc/ene_ir.*
+ENHANCED ERROR HANDLING (EEH)
+M: Gavin Shan <shangw@linux.vnet.ibm.com>
+L: linuxppc-dev@lists.ozlabs.org
+S: Supported
+F: Documentation/powerpc/eeh-pci-error-recovery.txt
+F: arch/powerpc/kernel/eeh*.c
+
EPSON S1D13XXX FRAMEBUFFER DRIVER
M: Kristoffer Ericson <kristoffer.ericson@gmail.com>
S: Maintained
@@ -3587,6 +3634,7 @@ GPIO SUBSYSTEM
M: Grant Likely <grant.likely@linaro.org>
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
+L: linux-gpio@vger.kernel.org
T: git git://git.secretlab.ca/git/linux-2.6.git
F: Documentation/gpio.txt
F: drivers/gpio/
@@ -3999,7 +4047,8 @@ S: Maintained
F: arch/ia64/
IBM Power in-Nest Crypto Acceleration
-M: Kent Yoder <key@linux.vnet.ibm.com>
+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/
@@ -4128,6 +4177,7 @@ F: drivers/ipack/
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
M: Mimi Zohar <zohar@us.ibm.com>
+M: Dmitry Kasatkin <d.kasatkin@samsung.com>
S: Supported
F: security/integrity/ima/
@@ -4731,14 +4781,23 @@ F: arch/s390/kvm/
F: drivers/s390/kvm/
KERNEL VIRTUAL MACHINE (KVM) FOR ARM
-M: Christoffer Dall <cdall@cs.columbia.edu>
+M: Christoffer Dall <christoffer.dall@linaro.org>
L: kvmarm@lists.cs.columbia.edu
W: http://systems.cs.columbia.edu/projects/kvm-arm
-S: Maintained
+S: Supported
F: arch/arm/include/uapi/asm/kvm*
F: arch/arm/include/asm/kvm*
F: arch/arm/kvm/
+KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
+M: Marc Zyngier <marc.zyngier@arm.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: kvmarm@lists.cs.columbia.edu
+S: Maintained
+F: arch/arm64/include/uapi/asm/kvm*
+F: arch/arm64/include/asm/kvm*
+F: arch/arm64/kvm/
+
KEXEC
M: Eric Biederman <ebiederm@xmission.com>
W: http://kernel.org/pub/linux/utils/kernel/kexec/
@@ -5452,9 +5511,12 @@ F: include/media/mt9v032.h
MULTIFUNCTION DEVICES (MFD)
M: Samuel Ortiz <sameo@linux.intel.com>
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git
+M: Lee Jones <lee.jones@linaro.org>
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-fixes.git
S: Supported
F: drivers/mfd/
+F: include/linux/mfd/
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
M: Chris Ball <cjb@laptop.org>
@@ -5954,8 +6016,10 @@ M: Willem Riede <osst@riede.org>
L: osst-users@lists.sourceforge.net
L: linux-scsi@vger.kernel.org
S: Maintained
-F: drivers/scsi/osst*
-F: drivers/scsi/st*
+F: Documentation/scsi/osst.txt
+F: drivers/scsi/osst.*
+F: drivers/scsi/osst_*.h
+F: drivers/scsi/st.h
OPENCORES I2C BUS DRIVER
M: Peter Korsgaard <jacmet@sunsite.dk>
@@ -6169,7 +6233,6 @@ M: Linas Vepstas <linasvepstas@gmail.com>
L: linux-pci@vger.kernel.org
S: Supported
F: Documentation/PCI/pci-error-recovery.txt
-F: Documentation/powerpc/eeh-pci-error-recovery.txt
PCI SUBSYSTEM
M: Bjorn Helgaas <bhelgaas@google.com>
@@ -6285,6 +6348,16 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/pinctrl/pinctrl-at91.c
+PIN CONTROLLER - SAMSUNG
+M: Tomasz Figa <t.figa@samsung.com>
+M: Thomas Abraham <thomas.abraham@linaro.org>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+S: Maintained
+F: drivers/pinctrl/pinctrl-exynos.*
+F: drivers/pinctrl/pinctrl-s3c*
+F: drivers/pinctrl/pinctrl-samsung.*
+
PIN CONTROLLER - ST SPEAR
M: Viresh Kumar <viresh.linux@gmail.com>
L: spear-devel@list.st.com
@@ -6344,7 +6417,7 @@ F: include/linux/timer*
F: kernel/*timer*
POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
-M: Anton Vorontsov <cbou@mail.ru>
+M: Anton Vorontsov <anton@enomsg.org>
M: David Woodhouse <dwmw2@infradead.org>
T: git git://git.infradead.org/battery-2.6.git
S: Maintained
@@ -6454,7 +6527,7 @@ S: Maintained
F: drivers/block/ps3vram.c
PSTORE FILESYSTEM
-M: Anton Vorontsov <cbouatmailru@gmail.com>
+M: Anton Vorontsov <anton@enomsg.org>
M: Colin Cross <ccross@android.com>
M: Kees Cook <keescook@chromium.org>
M: Tony Luck <tony.luck@intel.com>
@@ -6506,8 +6579,8 @@ S: Maintained
F: drivers/media/usb/pwc/*
PWM SUBSYSTEM
-M: Thierry Reding <thierry.reding@avionic-design.de>
-L: linux-kernel@vger.kernel.org
+M: Thierry Reding <thierry.reding@gmail.com>
+L: linux-pwm@vger.kernel.org
S: Maintained
W: http://gitorious.org/linux-pwm
T: git git://gitorious.org/linux-pwm/linux-pwm.git
@@ -7010,8 +7083,7 @@ SYNOPSYS DESIGNWARE DMAC DRIVER
M: Viresh Kumar <viresh.linux@gmail.com>
S: Maintained
F: include/linux/dw_dmac.h
-F: drivers/dma/dw_dmac_regs.h
-F: drivers/dma/dw_dmac.c
+F: drivers/dma/dw/
SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
M: Seungwon Jeon <tgih.jun@samsung.com>
@@ -7103,7 +7175,8 @@ M: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
L: linux-scsi@vger.kernel.org
S: Maintained
F: Documentation/scsi/st.txt
-F: drivers/scsi/st*
+F: drivers/scsi/st.*
+F: drivers/scsi/st_*.h
SCTP PROTOCOL
M: Vlad Yasevich <vyasevich@gmail.com>
@@ -7152,7 +7225,7 @@ F: drivers/mmc/host/sdhci.*
F: drivers/mmc/host/sdhci-pltfm.[ch]
SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
-M: Anton Vorontsov <avorontsov@ru.mvista.com>
+M: Anton Vorontsov <anton@enomsg.org>
L: linuxppc-dev@lists.ozlabs.org
L: linux-mmc@vger.kernel.org
S: Maintained
@@ -8088,6 +8161,7 @@ M: Zhang Rui <rui.zhang@intel.com>
M: Eduardo Valentin <eduardo.valentin@ti.com>
L: linux-pm@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal.git
Q: https://patchwork.kernel.org/project/linux-pm/list/
S: Supported
F: drivers/thermal/
@@ -8112,8 +8186,8 @@ F: drivers/platform/x86/thinkpad_acpi.c
TI BANDGAP AND THERMAL DRIVER
M: Eduardo Valentin <eduardo.valentin@ti.com>
L: linux-pm@vger.kernel.org
-S: Maintained
-F: drivers/staging/omap-thermal/
+S: Supported
+F: drivers/thermal/ti-soc-thermal/
TI FLASH MEDIA INTERFACE DRIVER
M: Alex Dubov <oakad@yahoo.com>
@@ -8261,7 +8335,8 @@ S: Odd fixes
F: drivers/media/usb/tm6000/
TPM DEVICE DRIVER
-M: Kent Yoder <key@linux.vnet.ibm.com>
+M: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com>
+M: Ashley Lai <ashley@ashleylai.com>
M: Rajiv Andrade <mail@srajiv.net>
W: http://tpmdd.sourceforge.net
M: Marcel Selhorst <tpmdd@selhorst.net>
@@ -8821,6 +8896,7 @@ M: "Michael S. Tsirkin" <mst@redhat.com>
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/virtio/
+F: tools/virtio/
F: drivers/net/virtio_net.c
F: drivers/block/virtio_blk.c
F: include/linux/virtio_*.h
@@ -8916,7 +8992,7 @@ M: Liam Girdwood <lgirdwood@gmail.com>
M: Mark Brown <broonie@kernel.org>
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?p=48
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/regulator.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git
S: Supported
F: drivers/regulator/
F: include/linux/regulator/
@@ -9135,6 +9211,13 @@ S: Supported
F: arch/arm/xen/
F: arch/arm/include/asm/xen/
+XEN HYPERVISOR ARM64
+M: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+L: xen-devel@lists.xensource.com (moderated for non-subscribers)
+S: Supported
+F: arch/arm64/xen/
+F: arch/arm64/include/asm/xen/
+
XEN NETWORK BACKEND DRIVER
M: Ian Campbell <ian.campbell@citrix.com>
L: xen-devel@lists.xensource.com (moderated for non-subscribers)
@@ -9208,6 +9291,13 @@ F: Documentation/networking/z8530drv.txt
F: drivers/net/hamradio/*scc.c
F: drivers/net/hamradio/z8530.h
+ZBUD COMPRESSED PAGE ALLOCATOR
+M: Seth Jennings <sjenning@linux.vnet.ibm.com>
+L: linux-mm@kvack.org
+S: Maintained
+F: mm/zbud.c
+F: include/linux/zbud.h
+
ZD1211RW WIRELESS DRIVER
M: Daniel Drake <dsd@gentoo.org>
M: Ulrich Kunitz <kune@deine-taler.de>
@@ -9230,6 +9320,12 @@ M: "Maciej W. Rozycki" <macro@linux-mips.org>
S: Maintained
F: drivers/tty/serial/zs.*
+ZSWAP COMPRESSED SWAP CACHING
+M: Seth Jennings <sjenning@linux.vnet.ibm.com>
+L: linux-mm@kvack.org
+S: Maintained
+F: mm/zswap.c
+
THE REST
M: Linus Torvalds <torvalds@linux-foundation.org>
L: linux-kernel@vger.kernel.org
diff --git a/Makefile b/Makefile
index e5e3ba085191..4e3575c7ec35 100644
--- a/Makefile
+++ b/Makefile
@@ -794,7 +794,7 @@ PHONY += $(vmlinux-dirs)
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
-# Store (new) KERNELRELASE string in include/config/kernel.release
+# Store (new) KERNELRELEASE string in include/config/kernel.release
include/config/kernel.release: include/config/auto.conf FORCE
$(Q)rm -f $@
$(Q)echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" > $@
@@ -1116,6 +1116,7 @@ help:
@echo ' gtags - Generate GNU GLOBAL index'
@echo ' kernelrelease - Output the release version string'
@echo ' kernelversion - Output the version stored in Makefile'
+ @echo ' image_name - Output the image name'
@echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \
echo ' (default: $(INSTALL_HDR_PATH))'; \
echo ''
@@ -1310,7 +1311,7 @@ export_report:
endif #ifeq ($(config-targets),1)
endif #ifeq ($(mixed-targets),1)
-PHONY += checkstack kernelrelease kernelversion
+PHONY += checkstack kernelrelease kernelversion image_name
# UML needs a little special treatment here. It wants to use the host
# toolchain, so needs $(SUBARCH) passed to checkstack.pl. Everyone
@@ -1331,6 +1332,9 @@ kernelrelease:
kernelversion:
@echo $(KERNELVERSION)
+image_name:
+ @echo $(KBUILD_IMAGE)
+
# Clear a bunch of variables before executing the submake
tools/: FORCE
$(Q)mkdir -p $(objtree)/tools
diff --git a/arch/Kconfig b/arch/Kconfig
index a4429bcd609e..8d2ae24b9f4a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -365,6 +365,9 @@ config HAVE_IRQ_TIME_ACCOUNTING
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
bool
+config HAVE_ARCH_SOFT_DIRTY
+ bool
+
config HAVE_MOD_ARCH_SPECIFIC
bool
help
diff --git a/arch/alpha/include/asm/mmzone.h b/arch/alpha/include/asm/mmzone.h
index c5b5d6bac9ed..14ce27bccd24 100644
--- a/arch/alpha/include/asm/mmzone.h
+++ b/arch/alpha/include/asm/mmzone.h
@@ -71,8 +71,6 @@ PLAT_NODE_DATA_LOCALNR(unsigned long p, int n)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr)
-
#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> 32))
#define pgd_page(pgd) (pfn_to_page(pgd_val(pgd) >> 32))
#define pte_pfn(pte) (pte_val(pte) >> 32)
diff --git a/arch/alpha/include/uapi/asm/fcntl.h b/arch/alpha/include/uapi/asm/fcntl.h
index 6d9e805f18a7..dfdadb0b4bef 100644
--- a/arch/alpha/include/uapi/asm/fcntl.h
+++ b/arch/alpha/include/uapi/asm/fcntl.h
@@ -32,6 +32,7 @@
#define O_SYNC (__O_SYNC|O_DSYNC)
#define O_PATH 040000000
+#define O_TMPFILE 0100000000
#define F_GETLK 7
#define F_SETLK 8
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index eee6ea76bdaf..4885825e498d 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -81,4 +81,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 1d4aabfcf9a1..837c0fa58317 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -238,8 +238,8 @@ nautilus_init_pci(void)
if (pci_mem < memtop)
memtop = pci_mem;
if (memtop > alpha_mv.min_mem_address) {
- free_reserved_area((unsigned long)__va(alpha_mv.min_mem_address),
- (unsigned long)__va(memtop), 0, NULL);
+ free_reserved_area(__va(alpha_mv.min_mem_address),
+ __va(memtop), -1, NULL);
printk("nautilus_init_pci: %ldk freed\n",
(memtop - alpha_mv.min_mem_address) >> 10);
}
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 0ba85ee4a466..a1bea91df56a 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -276,56 +276,25 @@ srm_paging_stop (void)
}
#endif
-#ifndef CONFIG_DISCONTIGMEM
-static void __init
-printk_memory_info(void)
-{
- unsigned long codesize, reservedpages, datasize, initsize, tmp;
- extern int page_is_ram(unsigned long) __init;
-
- /* printk all informations */
- reservedpages = 0;
- for (tmp = 0; tmp < max_low_pfn; tmp++)
- /*
- * Only count reserved RAM pages
- */
- if (page_is_ram(tmp) && PageReserved(mem_map+tmp))
- reservedpages++;
-
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_data;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, %luk data, %luk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10);
-}
-
void __init
mem_init(void)
{
- max_mapnr = num_physpages = max_low_pfn;
- totalram_pages += free_all_bootmem();
+ set_max_mapnr(max_low_pfn);
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-
- printk_memory_info();
+ free_all_bootmem();
+ mem_init_print_info(NULL);
}
-#endif /* CONFIG_DISCONTIGMEM */
void
free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
void
free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index 33885048fa36..d543d71c28b4 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -129,8 +129,6 @@ setup_memory_node(int nid, void *kernel_end)
if (node_max_pfn > max_low_pfn)
max_pfn = max_low_pfn = node_max_pfn;
- num_physpages += node_max_pfn - node_min_pfn;
-
#if 0 /* we'll try this one again in a little while */
/* Cute trick to make sure our local node data is on local memory */
node_data[nid] = (pg_data_t *)(__va(node_min_pfn << PAGE_SHIFT));
@@ -321,41 +319,3 @@ void __init paging_init(void)
/* Initialize the kernel's ZERO_PGE. */
memset((void *)ZERO_PGE, 0, PAGE_SIZE);
}
-
-void __init mem_init(void)
-{
- unsigned long codesize, reservedpages, datasize, initsize, pfn;
- extern int page_is_ram(unsigned long) __init;
- unsigned long nid, i;
- high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
-
- reservedpages = 0;
- for_each_online_node(nid) {
- /*
- * This will free up the bootmem, ie, slot 0 memory
- */
- totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
-
- pfn = NODE_DATA(nid)->node_start_pfn;
- for (i = 0; i < node_spanned_pages(nid); i++, pfn++)
- if (page_is_ram(pfn) &&
- PageReserved(nid_page_nr(nid, i)))
- reservedpages++;
- }
-
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_data;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk("Memory: %luk/%luk available (%luk kernel code, %luk reserved, "
- "%luk data, %luk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10);
-#if 0
- mem_stress();
-#endif
-}
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 5917099470ea..68fcbb2d59e2 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -34,6 +34,7 @@ config ARC
select OF
select OF_EARLY_FLATTREE
select PERF_USE_VMALLOC
+ select HAVE_DEBUG_STACKOVERFLOW
config SCHED_OMIT_FRAME_POINTER
def_bool y
@@ -184,6 +185,7 @@ config ARC_CACHE_PAGES
config ARC_CACHE_VIPT_ALIASING
bool "Support VIPT Aliasing D$"
+ depends on ARC_HAS_DCACHE
default n
endif #ARC_CACHE
@@ -361,13 +363,6 @@ config ARC_MISALIGN_ACCESS
Use ONLY-IF-ABS-NECESSARY as it will be very slow and also can hide
potential bugs in code
-config ARC_STACK_NONEXEC
- bool "Make stack non-executable"
- default n
- help
- To disable the execute permissions of stack/heap of processes
- which are enabled by default.
-
config HZ
int "Timer Frequency"
default 100
diff --git a/arch/arc/Kconfig.debug b/arch/arc/Kconfig.debug
index 962c6099659e..a7fc0da25650 100644
--- a/arch/arc/Kconfig.debug
+++ b/arch/arc/Kconfig.debug
@@ -15,13 +15,6 @@ config EARLY_PRINTK
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash.
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config 16KSTACKS
bool "Use 16Kb for kernel stacks instead of 8Kb"
help
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index 183397fd289e..8c0b1aa56f7e 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -9,25 +9,27 @@
UTS_MACHINE := arc
ifeq ($(CROSS_COMPILE),)
-CROSS_COMPILE := arc-elf32-
+CROSS_COMPILE := arc-linux-uclibc-
endif
KBUILD_DEFCONFIG := fpga_defconfig
cflags-y += -mA7 -fno-common -pipe -fno-builtin -D__linux__
-LINUXINCLUDE += -include ${src}/arch/arc/include/asm/defines.h
-
ifdef CONFIG_ARC_CURR_IN_REG
# For a global register defintion, make sure it gets passed to every file
# We had a customer reported bug where some code built in kernel was NOT using
# any kernel headers, and missing the r25 global register
-# Can't do unconditionally (like above) because of recursive include issues
+# Can't do unconditionally because of recursive include issues
# due to <linux/thread_info.h>
LINUXINCLUDE += -include ${src}/arch/arc/include/asm/current.h
endif
-atleast_gcc44 := $(call cc-ifversion, -gt, 0402, y)
+upto_gcc42 := $(call cc-ifversion, -le, 0402, y)
+upto_gcc44 := $(call cc-ifversion, -le, 0404, y)
+atleast_gcc44 := $(call cc-ifversion, -ge, 0404, y)
+atleast_gcc48 := $(call cc-ifversion, -ge, 0408, y)
+
cflags-$(atleast_gcc44) += -fsection-anchors
cflags-$(CONFIG_ARC_HAS_LLSC) += -mlock
@@ -35,6 +37,11 @@ cflags-$(CONFIG_ARC_HAS_SWAPE) += -mswape
cflags-$(CONFIG_ARC_HAS_RTSC) += -mrtsc
cflags-$(CONFIG_ARC_DW2_UNWIND) += -fasynchronous-unwind-tables
+# By default gcc 4.8 generates dwarf4 which kernel unwinder can't grok
+ifeq ($(atleast_gcc48),y)
+cflags-$(CONFIG_ARC_DW2_UNWIND) += -gdwarf-2
+endif
+
ifndef CONFIG_CC_OPTIMIZE_FOR_SIZE
# Generic build system uses -O2, we want -O3
cflags-y += -O3
@@ -48,11 +55,10 @@ cflags-$(disable_small_data) += -mno-sdata -fcall-used-gp
cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mbig-endian
ldflags-$(CONFIG_CPU_BIG_ENDIAN) += -EB
-# STAR 9000518362:
+# STAR 9000518362: (fixed with binutils shipping with gcc 4.8)
# arc-linux-uclibc-ld (buildroot) or arceb-elf32-ld (EZChip) don't accept
-# --build-id w/o "-marclinux".
-# Default arc-elf32-ld is OK
-ldflags-y += -marclinux
+# --build-id w/o "-marclinux". Default arc-elf32-ld is OK
+ldflags-$(upto_gcc44) += -marclinux
ARC_LIBGCC := -mA7
cflags-$(CONFIG_ARC_HAS_HW_MPY) += -multcost=16
@@ -66,8 +72,8 @@ ifndef CONFIG_ARC_HAS_HW_MPY
# With gcc 4.4.7, -mno-mpy is enough to make any other related adjustments,
# e.g. increased cost of MPY. With gcc 4.2.1 this had to be explicitly hinted
- ARC_LIBGCC := -marc600
- ifneq ($(atleast_gcc44),y)
+ ifeq ($(upto_gcc42),y)
+ ARC_LIBGCC := -marc600
cflags-y += -multcost=30
endif
endif
diff --git a/arch/arc/boot/dts/abilis_tb100.dtsi b/arch/arc/boot/dts/abilis_tb100.dtsi
index 941ad118a7e7..d9f8249aa66e 100644
--- a/arch/arc/boot/dts/abilis_tb100.dtsi
+++ b/arch/arc/boot/dts/abilis_tb100.dtsi
@@ -21,10 +21,6 @@
/include/ "abilis_tb10x.dtsi"
-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */
/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -173,7 +169,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -185,7 +181,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -197,7 +193,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -209,7 +205,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -221,7 +217,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -233,7 +229,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -245,7 +241,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -257,7 +253,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -269,7 +265,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -281,7 +277,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -293,7 +289,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -305,7 +301,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -317,7 +313,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -329,7 +325,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb100_dvk.dts b/arch/arc/boot/dts/abilis_tb100_dvk.dts
index 0fa0d4abe795..ebc313a9f5b2 100644
--- a/arch/arc/boot/dts/abilis_tb100_dvk.dts
+++ b/arch/arc/boot/dts/abilis_tb100_dvk.dts
@@ -45,19 +45,19 @@
};
i2c0: i2c@FF120000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c1: i2c@FF121000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c2: i2c@FF122000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c3: i2c@FF123000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c4: i2c@FF124000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
leds {
diff --git a/arch/arc/boot/dts/abilis_tb101.dtsi b/arch/arc/boot/dts/abilis_tb101.dtsi
index fd25c212049f..da8ca7941e67 100644
--- a/arch/arc/boot/dts/abilis_tb101.dtsi
+++ b/arch/arc/boot/dts/abilis_tb101.dtsi
@@ -21,10 +21,6 @@
/include/ "abilis_tb10x.dtsi"
-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */
/ {
clock-frequency = <500000000>; /* 500 MHZ */
@@ -182,7 +178,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF140000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -194,7 +190,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF141000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -206,7 +202,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF142000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -218,7 +214,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF143000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -230,7 +226,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF144000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -242,7 +238,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF145000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -254,7 +250,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF146000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -266,7 +262,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF147000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -278,7 +274,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF148000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -290,7 +286,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF149000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -302,7 +298,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14A000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -314,7 +310,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14B000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -326,7 +322,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14C000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
@@ -338,7 +334,7 @@
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <27 1>;
+ interrupts = <27 2>;
reg = <0xFF14D000 0x1000>;
gpio-controller;
#gpio-cells = <1>;
diff --git a/arch/arc/boot/dts/abilis_tb101_dvk.dts b/arch/arc/boot/dts/abilis_tb101_dvk.dts
index a4d80ce283ae..b204657993aa 100644
--- a/arch/arc/boot/dts/abilis_tb101_dvk.dts
+++ b/arch/arc/boot/dts/abilis_tb101_dvk.dts
@@ -45,19 +45,19 @@
};
i2c0: i2c@FF120000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c1: i2c@FF121000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c2: i2c@FF122000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c3: i2c@FF123000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
i2c4: i2c@FF124000 {
- sda-hold-time = <432>;
+ i2c-sda-hold-time-ns = <432>;
};
leds {
diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi
index b97e3051ba4b..edf56f4749e1 100644
--- a/arch/arc/boot/dts/abilis_tb10x.dtsi
+++ b/arch/arc/boot/dts/abilis_tb10x.dtsi
@@ -19,10 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* interrupt specifiers
- * --------------------
- * 0: rising, 1: low, 2: high, 3: falling,
- */
/ {
compatible = "abilis,arc-tb10x";
@@ -78,7 +74,7 @@
#interrupt-cells = <1>;
};
tb10x_ictl: pic@fe002000 {
- compatible = "abilis,tb10x_ictl";
+ compatible = "abilis,tb10x-ictl";
reg = <0xFE002000 0x20>;
interrupt-controller;
#interrupt-cells = <2>;
@@ -91,7 +87,7 @@
compatible = "snps,dw-apb-uart";
reg = <0xFF100000 0x100>;
clock-frequency = <166666666>;
- interrupts = <25 1>;
+ interrupts = <25 8>;
reg-shift = <2>;
reg-io-width = <4>;
interrupt-parent = <&tb10x_ictl>;
@@ -100,7 +96,7 @@
compatible = "snps,dwmac-3.70a","snps,dwmac";
reg = <0xFE100000 0x1058>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <6 1>;
+ interrupts = <6 8>;
interrupt-names = "macirq";
clocks = <&ahb_clk>;
clock-names = "stmmaceth";
@@ -109,7 +105,7 @@
compatible = "snps,dma-spear1340";
reg = <0xFE000000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <14 1>;
+ interrupts = <14 8>;
dma-channels = <6>;
dma-requests = <0>;
dma-masters = <1>;
@@ -128,7 +124,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF120000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c1: i2c@FF121000 {
@@ -137,7 +133,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF121000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c2: i2c@FF122000 {
@@ -146,7 +142,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF122000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c3: i2c@FF123000 {
@@ -155,7 +151,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF123000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
i2c4: i2c@FF124000 {
@@ -164,7 +160,7 @@
compatible = "snps,designware-i2c";
reg = <0xFF124000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <12 1>;
+ interrupts = <12 8>;
clocks = <&ahb_clk>;
};
@@ -176,7 +172,7 @@
num-cs = <1>;
reg = <0xFE010000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <26 1>;
+ interrupts = <26 8>;
clocks = <&ahb_clk>;
};
spi1: spi@0xFE011000 {
@@ -187,7 +183,7 @@
num-cs = <2>;
reg = <0xFE011000 0x20>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <10 1>;
+ interrupts = <10 8>;
clocks = <&ahb_clk>;
};
@@ -195,7 +191,7 @@
compatible = "abilis,tb100-tsm";
reg = <0xff316000 0x400>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <17 1>;
+ interrupts = <17 8>;
output-clkdiv = <4>;
global-packet-delay = <0x21>;
port-packet-delay = <0>;
@@ -213,7 +209,7 @@
"cpuctrl",
"a6it_int_force";
interrupt-parent = <&tb10x_ictl>;
- interrupts = <20 1>, <19 1>;
+ interrupts = <20 2>, <19 2>;
interrupt-names = "cmd_irq", "event_irq";
};
tb10x_mdsc0: tb10x-mdscr@FF300000 {
@@ -239,7 +235,7 @@
compatible = "abilis,tb100-wfb";
reg = <0xff319000 0x1000>;
interrupt-parent = <&tb10x_ictl>;
- interrupts = <16 1>;
+ interrupts = <16 8>;
};
};
};
diff --git a/arch/arc/boot/dts/angel4.dts b/arch/arc/boot/dts/angel4.dts
index bae4f936cb03..4fb2d6f655bd 100644
--- a/arch/arc/boot/dts/angel4.dts
+++ b/arch/arc/boot/dts/angel4.dts
@@ -51,5 +51,21 @@
current-speed = <115200>;
status = "okay";
};
+
+ ethernet@c0fc2000 {
+ compatible = "snps,arc-emac";
+ reg = <0xc0fc2000 0x3c>;
+ interrupts = <6>;
+ mac-address = [ 00 11 22 33 44 55 ];
+ clock-frequency = <80000000>;
+ max-speed = <100>;
+ phy = <&phy0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy0: ethernet-phy@0 {
+ reg = <1>;
+ };
+ };
};
};
diff --git a/arch/arc/configs/fpga_defconfig b/arch/arc/configs/fpga_defconfig
index 95350be6ef6f..4ca50f1f8d05 100644
--- a/arch/arc/configs/fpga_defconfig
+++ b/arch/arc/configs/fpga_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
@@ -38,6 +38,9 @@ CONFIG_INET=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FIRMWARE_IN_KERNEL is not set
# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+CONFIG_ARC_EMAC=y
+CONFIG_LXT_PHY=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
diff --git a/arch/arc/configs/nsimosci_defconfig b/arch/arc/configs/nsimosci_defconfig
index 446c96c24eff..451af30914f6 100644
--- a/arch/arc/configs/nsimosci_defconfig
+++ b/arch/arc/configs/nsimosci_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
diff --git a/arch/arc/configs/tb10x_defconfig b/arch/arc/configs/tb10x_defconfig
index 4fa5cd9f2202..6be6492442d6 100644
--- a/arch/arc/configs/tb10x_defconfig
+++ b/arch/arc/configs/tb10x_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-elf32-"
+CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="tb10x"
CONFIG_SYSVIPC=y
diff --git a/arch/arc/include/asm/arcregs.h b/arch/arc/include/asm/arcregs.h
index 1b907c465666..355cb470c2a4 100644
--- a/arch/arc/include/asm/arcregs.h
+++ b/arch/arc/include/asm/arcregs.h
@@ -20,7 +20,6 @@
#define ARC_REG_PERIBASE_BCR 0x69
#define ARC_REG_FP_BCR 0x6B /* Single-Precision FPU */
#define ARC_REG_DPFP_BCR 0x6C /* Dbl Precision FPU */
-#define ARC_REG_MMU_BCR 0x6f
#define ARC_REG_DCCM_BCR 0x74 /* DCCM Present + SZ */
#define ARC_REG_TIMERS_BCR 0x75
#define ARC_REG_ICCM_BCR 0x78
@@ -34,22 +33,12 @@
#define ARC_REG_D_UNCACH_BCR 0x6A
/* status32 Bits Positions */
-#define STATUS_H_BIT 0 /* CPU Halted */
-#define STATUS_E1_BIT 1 /* Int 1 enable */
-#define STATUS_E2_BIT 2 /* Int 2 enable */
-#define STATUS_A1_BIT 3 /* Int 1 active */
-#define STATUS_A2_BIT 4 /* Int 2 active */
#define STATUS_AE_BIT 5 /* Exception active */
#define STATUS_DE_BIT 6 /* PC is in delay slot */
#define STATUS_U_BIT 7 /* User/Kernel mode */
#define STATUS_L_BIT 12 /* Loop inhibit */
/* These masks correspond to the status word(STATUS_32) bits */
-#define STATUS_H_MASK (1<<STATUS_H_BIT)
-#define STATUS_E1_MASK (1<<STATUS_E1_BIT)
-#define STATUS_E2_MASK (1<<STATUS_E2_BIT)
-#define STATUS_A1_MASK (1<<STATUS_A1_BIT)
-#define STATUS_A2_MASK (1<<STATUS_A2_BIT)
#define STATUS_AE_MASK (1<<STATUS_AE_BIT)
#define STATUS_DE_MASK (1<<STATUS_DE_BIT)
#define STATUS_U_MASK (1<<STATUS_U_BIT)
@@ -71,6 +60,7 @@
#define ECR_V_ITLB_MISS 0x21
#define ECR_V_DTLB_MISS 0x22
#define ECR_V_PROTV 0x23
+#define ECR_V_TRAP 0x25
/* Protection Violation Exception Cause Code Values */
#define ECR_C_PROTV_INST_FETCH 0x00
@@ -79,94 +69,23 @@
#define ECR_C_PROTV_XCHG 0x03
#define ECR_C_PROTV_MISALIG_DATA 0x04
+#define ECR_C_BIT_PROTV_MISALIG_DATA 10
+
+/* Machine Check Cause Code Values */
+#define ECR_C_MCHK_DUP_TLB 0x01
+
/* DTLB Miss Exception Cause Code Values */
#define ECR_C_BIT_DTLB_LD_MISS 8
#define ECR_C_BIT_DTLB_ST_MISS 9
+/* Dummy ECR values for Interrupts */
+#define event_IRQ1 0x0031abcd
+#define event_IRQ2 0x0032abcd
/* Auxiliary registers */
#define AUX_IDENTITY 4
#define AUX_INTR_VEC_BASE 0x25
-#define AUX_IRQ_LEV 0x200 /* IRQ Priority: L1 or L2 */
-#define AUX_IRQ_HINT 0x201 /* For generating Soft Interrupts */
-#define AUX_IRQ_LV12 0x43 /* interrupt level register */
-
-#define AUX_IENABLE 0x40c
-#define AUX_ITRIGGER 0x40d
-#define AUX_IPULSE 0x415
-
-/* Timer related Aux registers */
-#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */
-#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */
-#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */
-#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */
-#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */
-#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */
-
-#define TIMER_CTRL_IE (1 << 0) /* Interupt when Count reachs limit */
-#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */
-
-/* MMU Management regs */
-#define ARC_REG_TLBPD0 0x405
-#define ARC_REG_TLBPD1 0x406
-#define ARC_REG_TLBINDEX 0x407
-#define ARC_REG_TLBCOMMAND 0x408
-#define ARC_REG_PID 0x409
-#define ARC_REG_SCRATCH_DATA0 0x418
-
-/* Bits in MMU PID register */
-#define MMU_ENABLE (1 << 31) /* Enable MMU for process */
-
-/* Error code if probe fails */
-#define TLB_LKUP_ERR 0x80000000
-
-/* TLB Commands */
-#define TLBWrite 0x1
-#define TLBRead 0x2
-#define TLBGetIndex 0x3
-#define TLBProbe 0x4
-
-#if (CONFIG_ARC_MMU_VER >= 2)
-#define TLBWriteNI 0x5 /* write JTLB without inv uTLBs */
-#define TLBIVUTLB 0x6 /* explicitly inv uTLBs */
-#else
-#undef TLBWriteNI /* These cmds don't exist on older MMU */
-#undef TLBIVUTLB
-#endif
-/* Instruction cache related Auxiliary registers */
-#define ARC_REG_IC_BCR 0x77 /* Build Config reg */
-#define ARC_REG_IC_IVIC 0x10
-#define ARC_REG_IC_CTRL 0x11
-#define ARC_REG_IC_IVIL 0x19
-#if (CONFIG_ARC_MMU_VER > 2)
-#define ARC_REG_IC_PTAG 0x1E
-#endif
-
-/* Bit val in IC_CTRL */
-#define IC_CTRL_CACHE_DISABLE 0x1
-
-/* Data cache related Auxiliary registers */
-#define ARC_REG_DC_BCR 0x72
-#define ARC_REG_DC_IVDC 0x47
-#define ARC_REG_DC_CTRL 0x48
-#define ARC_REG_DC_IVDL 0x4A
-#define ARC_REG_DC_FLSH 0x4B
-#define ARC_REG_DC_FLDL 0x4C
-#if (CONFIG_ARC_MMU_VER > 2)
-#define ARC_REG_DC_PTAG 0x5C
-#endif
-
-/* Bit val in DC_CTRL */
-#define DC_CTRL_INV_MODE_FLUSH 0x40
-#define DC_CTRL_FLUSH_STATUS 0x100
-
-/* MMU Management regs */
-#define ARC_REG_PID 0x409
-#define ARC_REG_SCRATCH_DATA0 0x418
-
-/* Bits in MMU PID register */
-#define MMU_ENABLE (1 << 31) /* Enable MMU for process */
/*
* Floating Pt Registers
@@ -293,24 +212,6 @@ struct bcr_identity {
#endif
};
-struct bcr_mmu_1_2 {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int ver:8, ways:4, sets:4, u_itlb:8, u_dtlb:8;
-#else
- unsigned int u_dtlb:8, u_itlb:8, sets:4, ways:4, ver:8;
-#endif
-};
-
-struct bcr_mmu_3 {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4,
- u_itlb:4, u_dtlb:4;
-#else
- unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4,
- ways:4, ver:8;
-#endif
-};
-
#define EXTN_SWAP_VALID 0x1
#define EXTN_NORM_VALID 0x2
#define EXTN_MINMAX_VALID 0x2
@@ -343,14 +244,6 @@ struct bcr_extn_xymem {
#endif
};
-struct bcr_cache {
-#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
-#else
- unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
-#endif
-};
-
struct bcr_perip {
#ifdef CONFIG_CPU_BIG_ENDIAN
unsigned int start:8, pad2:8, sz:8, pad:8;
@@ -403,7 +296,7 @@ struct cpuinfo_arc_mmu {
};
struct cpuinfo_arc_cache {
- unsigned int has_aliasing, sz, line_len, assoc, ver;
+ unsigned int sz, line_len, assoc, ver;
};
struct cpuinfo_arc_ccm {
diff --git a/arch/arc/include/asm/bug.h b/arch/arc/include/asm/bug.h
index 2ad8f9b1c54b..5b18e94c6678 100644
--- a/arch/arc/include/asm/bug.h
+++ b/arch/arc/include/asm/bug.h
@@ -18,9 +18,8 @@ struct task_struct;
void show_regs(struct pt_regs *regs);
void show_stacktrace(struct task_struct *tsk, struct pt_regs *regs);
void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
- unsigned long address, unsigned long cause_reg);
-void die(const char *str, struct pt_regs *regs, unsigned long address,
- unsigned long cause_reg);
+ unsigned long address);
+void die(const char *str, struct pt_regs *regs, unsigned long address);
#define BUG() do { \
dump_stack(); \
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index d5555fe4742a..5802849a6cae 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -18,21 +18,19 @@
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
-#define ARC_ICACHE_WAYS 2
-#define ARC_DCACHE_WAYS 4
-
-/* Helpers */
+/* For a rare case where customers have differently config I/D */
#define ARC_ICACHE_LINE_LEN L1_CACHE_BYTES
#define ARC_DCACHE_LINE_LEN L1_CACHE_BYTES
#define ICACHE_LINE_MASK (~(ARC_ICACHE_LINE_LEN - 1))
#define DCACHE_LINE_MASK (~(ARC_DCACHE_LINE_LEN - 1))
-#if ARC_ICACHE_LINE_LEN != ARC_DCACHE_LINE_LEN
-#error "Need to fix some code as I/D cache lines not same"
-#else
-#define is_not_cache_aligned(p) ((unsigned long)p & (~DCACHE_LINE_MASK))
-#endif
+/*
+ * ARC700 doesn't cache any access in top 256M.
+ * Ideal for wiring memory mapped peripherals as we don't need to do
+ * explicit uncached accesses (LD.di/ST.di) hence more portable drivers
+ */
+#define ARC_UNCACHED_ADDR_SPACE 0xc0000000
#ifndef __ASSEMBLY__
@@ -57,16 +55,10 @@
#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
-/*
- * ARC700 doesn't cache any access in top 256M.
- * Ideal for wiring memory mapped peripherals as we don't need to do
- * explicit uncached accesses (LD.di/ST.di) hence more portable drivers
- */
-#define ARC_UNCACHED_ADDR_SPACE 0xc0000000
-
extern void arc_cache_init(void);
extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
extern void __init read_decode_cache_bcr(void);
-#endif
+
+#endif /* !__ASSEMBLY__ */
#endif /* _ASM_CACHE_H */
diff --git a/arch/arc/include/asm/cacheflush.h b/arch/arc/include/asm/cacheflush.h
index ef62682e8d95..6abc4972bc93 100644
--- a/arch/arc/include/asm/cacheflush.h
+++ b/arch/arc/include/asm/cacheflush.h
@@ -81,16 +81,19 @@ void flush_anon_page(struct vm_area_struct *vma,
#endif /* CONFIG_ARC_CACHE_VIPT_ALIASING */
/*
+ * A new pagecache page has PG_arch_1 clear - thus dcache dirty by default
+ * This works around some PIO based drivers which don't call flush_dcache_page
+ * to record that they dirtied the dcache
+ */
+#define PG_dc_clean PG_arch_1
+
+/*
* Simple wrapper over config option
* Bootup code ensures that hardware matches kernel configuration
*/
static inline int cache_is_vipt_aliasing(void)
{
-#ifdef CONFIG_ARC_CACHE_VIPT_ALIASING
- return 1;
-#else
- return 0;
-#endif
+ return IS_ENABLED(CONFIG_ARC_CACHE_VIPT_ALIASING);
}
#define CACHE_COLOR(addr) (((unsigned long)(addr) >> (PAGE_SHIFT)) & 1)
diff --git a/arch/arc/include/asm/defines.h b/arch/arc/include/asm/defines.h
deleted file mode 100644
index 6097bb439cc5..000000000000
--- a/arch/arc/include/asm/defines.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.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 __ARC_ASM_DEFINES_H__
-#define __ARC_ASM_DEFINES_H__
-
-#if defined(CONFIG_ARC_MMU_V1)
-#define CONFIG_ARC_MMU_VER 1
-#elif defined(CONFIG_ARC_MMU_V2)
-#define CONFIG_ARC_MMU_VER 2
-#elif defined(CONFIG_ARC_MMU_V3)
-#define CONFIG_ARC_MMU_VER 3
-#endif
-
-#ifdef CONFIG_ARC_HAS_LLSC
-#define __CONFIG_ARC_HAS_LLSC_VAL 1
-#else
-#define __CONFIG_ARC_HAS_LLSC_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_SWAPE
-#define __CONFIG_ARC_HAS_SWAPE_VAL 1
-#else
-#define __CONFIG_ARC_HAS_SWAPE_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_RTSC
-#define __CONFIG_ARC_HAS_RTSC_VAL 1
-#else
-#define __CONFIG_ARC_HAS_RTSC_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_MMU_SASID
-#define __CONFIG_ARC_MMU_SASID_VAL 1
-#else
-#define __CONFIG_ARC_MMU_SASID_VAL 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_ICACHE
-#define __CONFIG_ARC_HAS_ICACHE 1
-#else
-#define __CONFIG_ARC_HAS_ICACHE 0
-#endif
-
-#ifdef CONFIG_ARC_HAS_DCACHE
-#define __CONFIG_ARC_HAS_DCACHE 1
-#else
-#define __CONFIG_ARC_HAS_DCACHE 0
-#endif
-
-#endif /* __ARC_ASM_DEFINES_H__ */
diff --git a/arch/arc/include/asm/entry.h b/arch/arc/include/asm/entry.h
index eb2ae53187d9..8943c028d4bb 100644
--- a/arch/arc/include/asm/entry.h
+++ b/arch/arc/include/asm/entry.h
@@ -50,194 +50,177 @@
* Eff Addr for load = [reg2]
*/
+.macro PUSH reg
+ st.a \reg, [sp, -4]
+.endm
+
+.macro PUSHAX aux
+ lr r9, [\aux]
+ PUSH r9
+.endm
+
+.macro POP reg
+ ld.ab \reg, [sp, 4]
+.endm
+
+.macro POPAX aux
+ POP r9
+ sr r9, [\aux]
+.endm
+
/*--------------------------------------------------------------
- * Save caller saved registers (scratch registers) ( r0 - r12 )
- * Registers are pushed / popped in the order defined in struct ptregs
- * in asm/ptrace.h
+ * Helpers to save/restore Scratch Regs:
+ * used by Interrupt/Exception Prologue/Epilogue
*-------------------------------------------------------------*/
-.macro SAVE_CALLER_SAVED
- st.a r0, [sp, -4]
- st.a r1, [sp, -4]
- st.a r2, [sp, -4]
- st.a r3, [sp, -4]
- st.a r4, [sp, -4]
- st.a r5, [sp, -4]
- st.a r6, [sp, -4]
- st.a r7, [sp, -4]
- st.a r8, [sp, -4]
- st.a r9, [sp, -4]
- st.a r10, [sp, -4]
- st.a r11, [sp, -4]
- st.a r12, [sp, -4]
+.macro SAVE_R0_TO_R12
+ PUSH r0
+ PUSH r1
+ PUSH r2
+ PUSH r3
+ PUSH r4
+ PUSH r5
+ PUSH r6
+ PUSH r7
+ PUSH r8
+ PUSH r9
+ PUSH r10
+ PUSH r11
+ PUSH r12
+.endm
+
+.macro RESTORE_R12_TO_R0
+ POP r12
+ POP r11
+ POP r10
+ POP r9
+ POP r8
+ POP r7
+ POP r6
+ POP r5
+ POP r4
+ POP r3
+ POP r2
+ POP r1
+ POP r0
+
+#ifdef CONFIG_ARC_CURR_IN_REG
+ ld r25, [sp, 12]
+#endif
.endm
/*--------------------------------------------------------------
- * Restore caller saved registers (scratch registers)
+ * Helpers to save/restore callee-saved regs:
+ * used by several macros below
*-------------------------------------------------------------*/
-.macro RESTORE_CALLER_SAVED
- ld.ab r12, [sp, 4]
- ld.ab r11, [sp, 4]
- ld.ab r10, [sp, 4]
- ld.ab r9, [sp, 4]
- ld.ab r8, [sp, 4]
- ld.ab r7, [sp, 4]
- ld.ab r6, [sp, 4]
- ld.ab r5, [sp, 4]
- ld.ab r4, [sp, 4]
- ld.ab r3, [sp, 4]
- ld.ab r2, [sp, 4]
- ld.ab r1, [sp, 4]
- ld.ab r0, [sp, 4]
+.macro SAVE_R13_TO_R24
+ PUSH r13
+ PUSH r14
+ PUSH r15
+ PUSH r16
+ PUSH r17
+ PUSH r18
+ PUSH r19
+ PUSH r20
+ PUSH r21
+ PUSH r22
+ PUSH r23
+ PUSH r24
+.endm
+
+.macro RESTORE_R24_TO_R13
+ POP r24
+ POP r23
+ POP r22
+ POP r21
+ POP r20
+ POP r19
+ POP r18
+ POP r17
+ POP r16
+ POP r15
+ POP r14
+ POP r13
.endm
+#define OFF_USER_R25_FROM_R24 (SZ_CALLEE_REGS + SZ_PT_REGS - 8)/4
/*--------------------------------------------------------------
- * Save callee saved registers (non scratch registers) ( r13 - r25 )
- * on kernel stack.
- * User mode callee regs need to be saved in case of
- * -fork and friends for replicating from parent to child
- * -before going into do_signal( ) for ptrace/core-dump
- * Special case handling is required for r25 in case it is used by kernel
- * for caching task ptr. Low level exception/ISR save user mode r25
- * into task->thread.user_r25. So it needs to be retrieved from there and
- * saved into kernel stack with rest of callee reg-file
+ * Collect User Mode callee regs as struct callee_regs - needed by
+ * fork/do_signal/unaligned-access-emulation.
+ * (By default only scratch regs are saved on entry to kernel)
+ *
+ * Special handling for r25 if used for caching Task Pointer.
+ * It would have been saved in task->thread.user_r25 already, but to keep
+ * the interface same it is copied into regular r25 placeholder in
+ * struct callee_regs.
*-------------------------------------------------------------*/
.macro SAVE_CALLEE_SAVED_USER
- st.a r13, [sp, -4]
- st.a r14, [sp, -4]
- st.a r15, [sp, -4]
- st.a r16, [sp, -4]
- st.a r17, [sp, -4]
- st.a r18, [sp, -4]
- st.a r19, [sp, -4]
- st.a r20, [sp, -4]
- st.a r21, [sp, -4]
- st.a r22, [sp, -4]
- st.a r23, [sp, -4]
- st.a r24, [sp, -4]
+
+ SAVE_R13_TO_R24
#ifdef CONFIG_ARC_CURR_IN_REG
; Retrieve orig r25 and save it on stack
- ld r12, [r25, TASK_THREAD + THREAD_USER_R25]
+ ld.as r12, [sp, OFF_USER_R25_FROM_R24]
st.a r12, [sp, -4]
#else
- st.a r25, [sp, -4]
+ PUSH r25
#endif
- /* move up by 1 word to "create" callee_regs->"stack_place_holder" */
- sub sp, sp, 4
.endm
/*--------------------------------------------------------------
- * Save callee saved registers (non scratch registers) ( r13 - r25 )
- * kernel mode callee regs needed to be saved in case of context switch
- * If r25 is used for caching task pointer then that need not be saved
- * as it can be re-created from current task global
+ * Save kernel Mode callee regs at the time of Contect Switch.
+ *
+ * Special handling for r25 if used for caching Task Pointer.
+ * Kernel simply skips saving it since it will be loaded with
+ * incoming task pointer anyways
*-------------------------------------------------------------*/
.macro SAVE_CALLEE_SAVED_KERNEL
- st.a r13, [sp, -4]
- st.a r14, [sp, -4]
- st.a r15, [sp, -4]
- st.a r16, [sp, -4]
- st.a r17, [sp, -4]
- st.a r18, [sp, -4]
- st.a r19, [sp, -4]
- st.a r20, [sp, -4]
- st.a r21, [sp, -4]
- st.a r22, [sp, -4]
- st.a r23, [sp, -4]
- st.a r24, [sp, -4]
+
+ SAVE_R13_TO_R24
+
#ifdef CONFIG_ARC_CURR_IN_REG
- sub sp, sp, 8
-#else
- st.a r25, [sp, -4]
sub sp, sp, 4
+#else
+ PUSH r25
#endif
.endm
/*--------------------------------------------------------------
- * RESTORE_CALLEE_SAVED_KERNEL:
- * Loads callee (non scratch) Reg File by popping from Kernel mode stack.
- * This is reverse of SAVE_CALLEE_SAVED,
- *
- * NOTE:
- * Ideally this shd only be called in switch_to for loading
- * switched-IN task's CALLEE Reg File.
- * For all other cases RESTORE_CALLEE_SAVED_FAST must be used
- * which simply pops the stack w/o touching regs.
+ * Opposite of SAVE_CALLEE_SAVED_KERNEL
*-------------------------------------------------------------*/
.macro RESTORE_CALLEE_SAVED_KERNEL
-
#ifdef CONFIG_ARC_CURR_IN_REG
- add sp, sp, 8 /* skip callee_reg gutter and user r25 placeholder */
+ add sp, sp, 4 /* skip usual r25 placeholder */
#else
- add sp, sp, 4 /* skip "callee_regs->stack_place_holder" */
- ld.ab r25, [sp, 4]
+ POP r25
#endif
-
- ld.ab r24, [sp, 4]
- ld.ab r23, [sp, 4]
- ld.ab r22, [sp, 4]
- ld.ab r21, [sp, 4]
- ld.ab r20, [sp, 4]
- ld.ab r19, [sp, 4]
- ld.ab r18, [sp, 4]
- ld.ab r17, [sp, 4]
- ld.ab r16, [sp, 4]
- ld.ab r15, [sp, 4]
- ld.ab r14, [sp, 4]
- ld.ab r13, [sp, 4]
-
+ RESTORE_R24_TO_R13
.endm
/*--------------------------------------------------------------
- * RESTORE_CALLEE_SAVED_USER:
- * This is called after do_signal where tracer might have changed callee regs
- * thus we need to restore the reg file.
- * Special case handling is required for r25 in case it is used by kernel
- * for caching task ptr. Ptrace would have modified on-kernel-stack value of
- * r25, which needs to be shoved back into task->thread.user_r25 where from
- * Low level exception/ISR return code will retrieve to populate with rest of
- * callee reg-file.
+ * Opposite of SAVE_CALLEE_SAVED_USER
+ *
+ * ptrace tracer or unaligned-access fixup might have changed a user mode
+ * callee reg which is saved back to usual r25 storage location
*-------------------------------------------------------------*/
.macro RESTORE_CALLEE_SAVED_USER
- add sp, sp, 4 /* skip "callee_regs->stack_place_holder" */
-
#ifdef CONFIG_ARC_CURR_IN_REG
ld.ab r12, [sp, 4]
- st r12, [r25, TASK_THREAD + THREAD_USER_R25]
+ st.as r12, [sp, OFF_USER_R25_FROM_R24]
#else
- ld.ab r25, [sp, 4]
+ POP r25
#endif
-
- ld.ab r24, [sp, 4]
- ld.ab r23, [sp, 4]
- ld.ab r22, [sp, 4]
- ld.ab r21, [sp, 4]
- ld.ab r20, [sp, 4]
- ld.ab r19, [sp, 4]
- ld.ab r18, [sp, 4]
- ld.ab r17, [sp, 4]
- ld.ab r16, [sp, 4]
- ld.ab r15, [sp, 4]
- ld.ab r14, [sp, 4]
- ld.ab r13, [sp, 4]
+ RESTORE_R24_TO_R13
.endm
/*--------------------------------------------------------------
* Super FAST Restore callee saved regs by simply re-adjusting SP
*-------------------------------------------------------------*/
.macro DISCARD_CALLEE_SAVED_USER
- add sp, sp, 14 * 4
-.endm
-
-/*--------------------------------------------------------------
- * Restore User mode r25 saved in task_struct->thread.user_r25
- *-------------------------------------------------------------*/
-.macro RESTORE_USER_R25
- ld r25, [r25, TASK_THREAD + THREAD_USER_R25]
+ add sp, sp, SZ_CALLEE_REGS
.endm
/*-------------------------------------------------------------
@@ -252,7 +235,7 @@
ld \out, [\tsk, TASK_THREAD_INFO]
/* Go to end of page where stack begins (grows upwards) */
- add2 \out, \out, (THREAD_SIZE - 4)/4 /* one word GUTTER */
+ add2 \out, \out, (THREAD_SIZE)/4
.endm
@@ -305,33 +288,28 @@
* safe-keeping not really needed, but it keeps the epilogue code
* (SP restore) simpler/uniform.
*/
- b.d 77f
-
- st.a sp, [sp, -12] ; Make room for orig_r0 and orig_r8
+ b.d 66f
+ mov r9, sp
88: /*------Intr/Ecxp happened in user mode, "switch" stack ------ */
GET_CURR_TASK_ON_CPU r9
-#ifdef CONFIG_ARC_CURR_IN_REG
-
- /* If current task pointer cached in r25, time to
- * -safekeep USER r25 in task->thread_struct->user_r25
- * -load r25 with current task ptr
- */
- st.as r25, [r9, (TASK_THREAD + THREAD_USER_R25)/4]
- mov r25, r9
-#endif
-
/* With current tsk in r9, get it's kernel mode stack base */
GET_TSK_STACK_BASE r9, r9
-#ifdef PT_REGS_CANARY
- st 0xabcdabcd, [r9, 0]
+66:
+#ifdef CONFIG_ARC_CURR_IN_REG
+ /*
+ * Treat r25 as scratch reg, save it on stack first
+ * Load it with current task pointer
+ */
+ st r25, [r9, -4]
+ GET_CURR_TASK_ON_CPU r25
#endif
/* Save Pre Intr/Exception User SP on kernel stack */
- st.a sp, [r9, -12] ; Make room for orig_r0 and orig_r8
+ st.a sp, [r9, -16] ; Make room for orig_r0, ECR, user_r25
/* CAUTION:
* SP should be set at the very end when we are done with everything
@@ -342,7 +320,7 @@
/* set SP to point to kernel mode stack */
mov sp, r9
-77: /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
+ /* ----- Stack Switched to kernel Mode, Now save REG FILE ----- */
.endm
@@ -369,7 +347,7 @@
* @reg [OUT] &thread_info of "current"
*/
.macro GET_CURR_THR_INFO_FROM_SP reg
- and \reg, sp, ~(THREAD_SIZE - 1)
+ bic \reg, sp, (THREAD_SIZE - 1)
.endm
/*
@@ -413,62 +391,25 @@
* Note that syscalls are implemented via TRAP which is also a exception
* from CPU's point of view
*-------------------------------------------------------------*/
-.macro SAVE_ALL_EXCEPTION marker
+.macro SAVE_ALL_SYS
- st \marker, [sp, 8] /* orig_r8 */
+ lr r9, [ecr]
+ st r9, [sp, 8] /* ECR */
st r0, [sp, 4] /* orig_r0, needed only for sys calls */
/* Restore r9 used to code the early prologue */
EXCPN_PROLOG_RESTORE_REG r9
- SAVE_CALLER_SAVED
- st.a r26, [sp, -4] /* gp */
- st.a fp, [sp, -4]
- st.a blink, [sp, -4]
- lr r9, [eret]
- st.a r9, [sp, -4]
- lr r9, [erstatus]
- st.a r9, [sp, -4]
- st.a lp_count, [sp, -4]
- lr r9, [lp_end]
- st.a r9, [sp, -4]
- lr r9, [lp_start]
- st.a r9, [sp, -4]
- lr r9, [erbta]
- st.a r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
- mov r9, 0xdeadbeef
- st r9, [sp, -4]
-#endif
-
- /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
- sub sp, sp, 4
-.endm
-
-/*--------------------------------------------------------------
- * Save scratch regs for exceptions
- *-------------------------------------------------------------*/
-.macro SAVE_ALL_SYS
- SAVE_ALL_EXCEPTION orig_r8_IS_EXCPN
-.endm
-
-/*--------------------------------------------------------------
- * Save scratch regs for sys calls
- *-------------------------------------------------------------*/
-.macro SAVE_ALL_TRAP
- /*
- * Setup pt_regs->orig_r8.
- * Encode syscall number (r8) in upper short word of event type (r9)
- * N.B. #1: This is already endian safe (see ptrace.h)
- * #2: Only r9 can be used as scratch as it is already clobbered
- * and it's contents are no longer needed by the latter part
- * of exception prologue
- */
- lsl r9, r8, 16
- or r9, r9, orig_r8_IS_SCALL
-
- SAVE_ALL_EXCEPTION r9
+ SAVE_R0_TO_R12
+ PUSH gp
+ PUSH fp
+ PUSH blink
+ PUSHAX eret
+ PUSHAX erstatus
+ PUSH lp_count
+ PUSHAX lp_end
+ PUSHAX lp_start
+ PUSHAX erbta
.endm
/*--------------------------------------------------------------
@@ -483,28 +424,22 @@
* by hardware and that is not good.
*-------------------------------------------------------------*/
.macro RESTORE_ALL_SYS
+ POPAX erbta
+ POPAX lp_start
+ POPAX lp_end
+
+ POP r9
+ mov lp_count, r9 ;LD to lp_count is not allowed
- add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */
-
- ld.ab r9, [sp, 4]
- sr r9, [erbta]
- ld.ab r9, [sp, 4]
- sr r9, [lp_start]
- ld.ab r9, [sp, 4]
- sr r9, [lp_end]
- ld.ab r9, [sp, 4]
- mov lp_count, r9
- ld.ab r9, [sp, 4]
- sr r9, [erstatus]
- ld.ab r9, [sp, 4]
- sr r9, [eret]
- ld.ab blink, [sp, 4]
- ld.ab fp, [sp, 4]
- ld.ab r26, [sp, 4] /* gp */
- RESTORE_CALLER_SAVED
+ POPAX erstatus
+ POPAX eret
+ POP blink
+ POP fp
+ POP gp
+ RESTORE_R12_TO_R0
ld sp, [sp] /* restore original sp */
- /* orig_r0 and orig_r8 skipped automatically */
+ /* orig_r0, ECR, user_r25 skipped automatically */
.endm
@@ -513,9 +448,7 @@
*-------------------------------------------------------------*/
.macro SAVE_ALL_INT1
- /* restore original r9 , saved in int1_saved_reg
- * It will be saved on stack in macro: SAVE_CALLER_SAVED
- */
+ /* restore original r9 to be saved as part of reg-file */
#ifdef CONFIG_SMP
lr r9, [ARC_REG_SCRATCH_DATA0]
#else
@@ -523,29 +456,19 @@
#endif
/* now we are ready to save the remaining context :) */
- st orig_r8_IS_IRQ1, [sp, 8] /* Event Type */
+ st event_IRQ1, [sp, 8] /* Dummy ECR */
st 0, [sp, 4] /* orig_r0 , N/A for IRQ */
- SAVE_CALLER_SAVED
- st.a r26, [sp, -4] /* gp */
- st.a fp, [sp, -4]
- st.a blink, [sp, -4]
- st.a ilink1, [sp, -4]
- lr r9, [status32_l1]
- st.a r9, [sp, -4]
- st.a lp_count, [sp, -4]
- lr r9, [lp_end]
- st.a r9, [sp, -4]
- lr r9, [lp_start]
- st.a r9, [sp, -4]
- lr r9, [bta_l1]
- st.a r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
- mov r9, 0xdeadbee1
- st r9, [sp, -4]
-#endif
- /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
- sub sp, sp, 4
+
+ SAVE_R0_TO_R12
+ PUSH gp
+ PUSH fp
+ PUSH blink
+ PUSH ilink1
+ PUSHAX status32_l1
+ PUSH lp_count
+ PUSHAX lp_end
+ PUSHAX lp_start
+ PUSHAX bta_l1
.endm
.macro SAVE_ALL_INT2
@@ -558,30 +481,19 @@
ld r9, [@int2_saved_reg]
/* now we are ready to save the remaining context :) */
- st orig_r8_IS_IRQ2, [sp, 8] /* Event Type */
+ st event_IRQ2, [sp, 8] /* Dummy ECR */
st 0, [sp, 4] /* orig_r0 , N/A for IRQ */
- SAVE_CALLER_SAVED
- st.a r26, [sp, -4] /* gp */
- st.a fp, [sp, -4]
- st.a blink, [sp, -4]
- st.a ilink2, [sp, -4]
- lr r9, [status32_l2]
- st.a r9, [sp, -4]
- st.a lp_count, [sp, -4]
- lr r9, [lp_end]
- st.a r9, [sp, -4]
- lr r9, [lp_start]
- st.a r9, [sp, -4]
- lr r9, [bta_l2]
- st.a r9, [sp, -4]
-
-#ifdef PT_REGS_CANARY
- mov r9, 0xdeadbee2
- st r9, [sp, -4]
-#endif
- /* move up by 1 word to "create" pt_regs->"stack_place_holder" */
- sub sp, sp, 4
+ SAVE_R0_TO_R12
+ PUSH gp
+ PUSH fp
+ PUSH blink
+ PUSH ilink2
+ PUSHAX status32_l2
+ PUSH lp_count
+ PUSHAX lp_end
+ PUSHAX lp_start
+ PUSHAX bta_l2
.endm
/*--------------------------------------------------------------
@@ -595,52 +507,41 @@
*-------------------------------------------------------------*/
.macro RESTORE_ALL_INT1
- add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */
-
- ld.ab r9, [sp, 4] /* Actual reg file */
- sr r9, [bta_l1]
- ld.ab r9, [sp, 4]
- sr r9, [lp_start]
- ld.ab r9, [sp, 4]
- sr r9, [lp_end]
- ld.ab r9, [sp, 4]
- mov lp_count, r9
- ld.ab r9, [sp, 4]
- sr r9, [status32_l1]
- ld.ab r9, [sp, 4]
- mov ilink1, r9
- ld.ab blink, [sp, 4]
- ld.ab fp, [sp, 4]
- ld.ab r26, [sp, 4] /* gp */
- RESTORE_CALLER_SAVED
+ POPAX bta_l1
+ POPAX lp_start
+ POPAX lp_end
+
+ POP r9
+ mov lp_count, r9 ;LD to lp_count is not allowed
+
+ POPAX status32_l1
+ POP ilink1
+ POP blink
+ POP fp
+ POP gp
+ RESTORE_R12_TO_R0
ld sp, [sp] /* restore original sp */
- /* orig_r0 and orig_r8 skipped automatically */
+ /* orig_r0, ECR, user_r25 skipped automatically */
.endm
.macro RESTORE_ALL_INT2
- add sp, sp, 4 /* hop over unused "pt_regs->stack_place_holder" */
-
- ld.ab r9, [sp, 4]
- sr r9, [bta_l2]
- ld.ab r9, [sp, 4]
- sr r9, [lp_start]
- ld.ab r9, [sp, 4]
- sr r9, [lp_end]
- ld.ab r9, [sp, 4]
- mov lp_count, r9
- ld.ab r9, [sp, 4]
- sr r9, [status32_l2]
- ld.ab r9, [sp, 4]
- mov ilink2, r9
- ld.ab blink, [sp, 4]
- ld.ab fp, [sp, 4]
- ld.ab r26, [sp, 4] /* gp */
- RESTORE_CALLER_SAVED
+ POPAX bta_l2
+ POPAX lp_start
+ POPAX lp_end
- ld sp, [sp] /* restore original sp */
- /* orig_r0 and orig_r8 skipped automatically */
+ POP r9
+ mov lp_count, r9 ;LD to lp_count is not allowed
+ POPAX status32_l2
+ POP ilink2
+ POP blink
+ POP fp
+ POP gp
+ RESTORE_R12_TO_R0
+
+ ld sp, [sp] /* restore original sp */
+ /* orig_r0, ECR, user_r25 skipped automatically */
.endm
diff --git a/arch/arc/include/asm/irq.h b/arch/arc/include/asm/irq.h
index 57898a17eb82..c0a72105ee0b 100644
--- a/arch/arc/include/asm/irq.h
+++ b/arch/arc/include/asm/irq.h
@@ -21,6 +21,6 @@
extern void __init arc_init_IRQ(void);
extern int __init get_hw_config_num_irq(void);
-void __cpuinit arc_local_timer_setup(unsigned int cpu);
+void arc_local_timer_setup(unsigned int cpu);
#endif
diff --git a/arch/arc/include/asm/irqflags.h b/arch/arc/include/asm/irqflags.h
index eac071668201..d99f79bcf865 100644
--- a/arch/arc/include/asm/irqflags.h
+++ b/arch/arc/include/asm/irqflags.h
@@ -19,6 +19,26 @@
#include <asm/arcregs.h>
+/* status32 Reg bits related to Interrupt Handling */
+#define STATUS_E1_BIT 1 /* Int 1 enable */
+#define STATUS_E2_BIT 2 /* Int 2 enable */
+#define STATUS_A1_BIT 3 /* Int 1 active */
+#define STATUS_A2_BIT 4 /* Int 2 active */
+
+#define STATUS_E1_MASK (1<<STATUS_E1_BIT)
+#define STATUS_E2_MASK (1<<STATUS_E2_BIT)
+#define STATUS_A1_MASK (1<<STATUS_A1_BIT)
+#define STATUS_A2_MASK (1<<STATUS_A2_BIT)
+
+/* Other Interrupt Handling related Aux regs */
+#define AUX_IRQ_LEV 0x200 /* IRQ Priority: L1 or L2 */
+#define AUX_IRQ_HINT 0x201 /* For generating Soft Interrupts */
+#define AUX_IRQ_LV12 0x43 /* interrupt level register */
+
+#define AUX_IENABLE 0x40c
+#define AUX_ITRIGGER 0x40d
+#define AUX_IPULSE 0x415
+
#ifndef __ASSEMBLY__
/******************************************************************
diff --git a/arch/arc/include/asm/kgdb.h b/arch/arc/include/asm/kgdb.h
index 4930957ca3d3..b65fca7ffeb5 100644
--- a/arch/arc/include/asm/kgdb.h
+++ b/arch/arc/include/asm/kgdb.h
@@ -31,7 +31,7 @@ static inline void arch_kgdb_breakpoint(void)
__asm__ __volatile__ ("trap_s 0x4\n");
}
-extern void kgdb_trap(struct pt_regs *regs, int param);
+extern void kgdb_trap(struct pt_regs *regs);
enum arc700_linux_regnums {
_R0 = 0,
@@ -53,7 +53,7 @@ enum arc700_linux_regnums {
};
#else
-#define kgdb_trap(regs, param)
+#define kgdb_trap(regs)
#endif
#endif /* __ARC_KGDB_H__ */
diff --git a/arch/arc/include/asm/kprobes.h b/arch/arc/include/asm/kprobes.h
index 4d9c211fce70..944dbedb38b5 100644
--- a/arch/arc/include/asm/kprobes.h
+++ b/arch/arc/include/asm/kprobes.h
@@ -50,11 +50,9 @@ struct kprobe_ctlblk {
int kprobe_fault_handler(struct pt_regs *regs, unsigned long cause);
void kretprobe_trampoline(void);
-void trap_is_kprobe(unsigned long cause, unsigned long address,
- struct pt_regs *regs);
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs);
#else
-static void trap_is_kprobe(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+static void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
{
}
#endif
diff --git a/arch/arc/include/asm/mmu.h b/arch/arc/include/asm/mmu.h
index 56b02320f1a9..7c03fe61759c 100644
--- a/arch/arc/include/asm/mmu.h
+++ b/arch/arc/include/asm/mmu.h
@@ -9,6 +9,40 @@
#ifndef _ASM_ARC_MMU_H
#define _ASM_ARC_MMU_H
+#if defined(CONFIG_ARC_MMU_V1)
+#define CONFIG_ARC_MMU_VER 1
+#elif defined(CONFIG_ARC_MMU_V2)
+#define CONFIG_ARC_MMU_VER 2
+#elif defined(CONFIG_ARC_MMU_V3)
+#define CONFIG_ARC_MMU_VER 3
+#endif
+
+/* MMU Management regs */
+#define ARC_REG_MMU_BCR 0x06f
+#define ARC_REG_TLBPD0 0x405
+#define ARC_REG_TLBPD1 0x406
+#define ARC_REG_TLBINDEX 0x407
+#define ARC_REG_TLBCOMMAND 0x408
+#define ARC_REG_PID 0x409
+#define ARC_REG_SCRATCH_DATA0 0x418
+
+/* Bits in MMU PID register */
+#define MMU_ENABLE (1 << 31) /* Enable MMU for process */
+
+/* Error code if probe fails */
+#define TLB_LKUP_ERR 0x80000000
+
+/* TLB Commands */
+#define TLBWrite 0x1
+#define TLBRead 0x2
+#define TLBGetIndex 0x3
+#define TLBProbe 0x4
+
+#if (CONFIG_ARC_MMU_VER >= 2)
+#define TLBWriteNI 0x5 /* write JTLB without inv uTLBs */
+#define TLBIVUTLB 0x6 /* explicitly inv uTLBs */
+#endif
+
#ifndef __ASSEMBLY__
typedef struct {
@@ -18,6 +52,16 @@ typedef struct {
#endif
} mm_context_t;
+#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
+void tlb_paranoid_check(unsigned int pid_sw, unsigned long address);
+#else
+#define tlb_paranoid_check(a, b)
#endif
+void arc_mmu_init(void);
+extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
+void __init read_decode_mmu_bcr(void);
+
+#endif /* !__ASSEMBLY__ */
+
#endif
diff --git a/arch/arc/include/asm/page.h b/arch/arc/include/asm/page.h
index ab84bf131fe1..9c8aa41e45c2 100644
--- a/arch/arc/include/asm/page.h
+++ b/arch/arc/include/asm/page.h
@@ -96,13 +96,8 @@ typedef unsigned long pgtable_t;
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-/* Default Permissions for page, used in mmap.c */
-#ifdef CONFIG_ARC_STACK_NONEXEC
+/* Default Permissions for stack/heaps pages (Non Executable) */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE)
-#else
-#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#endif
#define WANT_PAGE_VIRTUAL 1
diff --git a/arch/arc/include/asm/pgtable.h b/arch/arc/include/asm/pgtable.h
index c110ac87d22b..4749a0eee1cf 100644
--- a/arch/arc/include/asm/pgtable.h
+++ b/arch/arc/include/asm/pgtable.h
@@ -135,6 +135,12 @@
/* ioremap */
#define PAGE_KERNEL_NO_CACHE __pgprot(_K_PAGE_PERMS)
+/* Masks for actual TLB "PD"s */
+#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT)
+#define PTE_BITS_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE | \
+ _PAGE_U_EXECUTE | _PAGE_U_WRITE | _PAGE_U_READ | \
+ _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
+
/**************************************************************************
* Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
*
diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h
index 5f26b2c1cba0..15334ab66b56 100644
--- a/arch/arc/include/asm/processor.h
+++ b/arch/arc/include/asm/processor.h
@@ -19,6 +19,7 @@
#ifndef __ASSEMBLY__
#include <asm/arcregs.h> /* for STATUS_E1_MASK et all */
+#include <asm/ptrace.h>
/* Arch specific stuff which needs to be saved per task.
* However these items are not so important so as to earn a place in
@@ -28,10 +29,6 @@ struct thread_struct {
unsigned long ksp; /* kernel mode stack pointer */
unsigned long callee_reg; /* pointer to callee regs */
unsigned long fault_address; /* dbls as brkpt holder as well */
- unsigned long cause_code; /* Exception Cause Code (ECR) */
-#ifdef CONFIG_ARC_CURR_IN_REG
- unsigned long user_r25;
-#endif
#ifdef CONFIG_ARC_FPU_SAVE_RESTORE
struct arc_fpu fpu;
#endif
@@ -50,7 +47,7 @@ struct task_struct;
unsigned long thread_saved_pc(struct task_struct *t);
#define task_pt_regs(p) \
- ((struct pt_regs *)(THREAD_SIZE - 4 + (void *)task_stack_page(p)) - 1)
+ ((struct pt_regs *)(THREAD_SIZE + (void *)task_stack_page(p)) - 1)
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while (0)
@@ -75,11 +72,15 @@ unsigned long thread_saved_pc(struct task_struct *t);
/*
* Where abouts of Task's sp, fp, blink when it was last seen in kernel mode.
- * These can't be derived from pt_regs as that would give correp user-mode val
+ * Look in process.c for details of kernel stack layout
*/
#define KSTK_ESP(tsk) (tsk->thread.ksp)
-#define KSTK_BLINK(tsk) (*((unsigned int *)((KSTK_ESP(tsk)) + (13+1+1)*4)))
-#define KSTK_FP(tsk) (*((unsigned int *)((KSTK_ESP(tsk)) + (13+1)*4)))
+
+#define KSTK_REG(tsk, off) (*((unsigned int *)(KSTK_ESP(tsk) + \
+ sizeof(struct callee_regs) + off)))
+
+#define KSTK_BLINK(tsk) KSTK_REG(tsk, 4)
+#define KSTK_FP(tsk) KSTK_REG(tsk, 0)
/*
* Do necessary setup to start up a newly executed thread.
diff --git a/arch/arc/include/asm/ptrace.h b/arch/arc/include/asm/ptrace.h
index 6179de7e07c2..c9938e7a7dbd 100644
--- a/arch/arc/include/asm/ptrace.h
+++ b/arch/arc/include/asm/ptrace.h
@@ -17,12 +17,6 @@
/* THE pt_regs: Defines how regs are saved during entry into kernel */
struct pt_regs {
- /*
- * 1 word gutter after reg-file has been saved
- * Technically not needed, Since SP always points to a "full" location
- * (vs. "empty"). But pt_regs is shared with tools....
- */
- long res;
/* Real registers */
long bta; /* bta_l1, bta_l2, erbta */
@@ -50,22 +44,32 @@ struct pt_regs {
long sp; /* user/kernel sp depending on where we came from */
long orig_r0;
- /*to distinguish bet excp, syscall, irq */
+ /*
+ * To distinguish bet excp, syscall, irq
+ * For traps and exceptions, Exception Cause Register.
+ * ECR: <00> <VV> <CC> <PP>
+ * Last word used by Linux for extra state mgmt (syscall-restart)
+ * For interrupts, use artificial ECR values to note current prio-level
+ */
union {
+ struct {
#ifdef CONFIG_CPU_BIG_ENDIAN
- /* so that assembly code is same for LE/BE */
- unsigned long orig_r8:16, event:16;
+ unsigned long state:8, ecr_vec:8,
+ ecr_cause:8, ecr_param:8;
#else
- unsigned long event:16, orig_r8:16;
+ unsigned long ecr_param:8, ecr_cause:8,
+ ecr_vec:8, state:8;
#endif
- long orig_r8_word;
+ };
+ unsigned long event;
};
+
+ long user_r25;
};
/* Callee saved registers - need to be saved only when you are scheduled out */
struct callee_regs {
- long res; /* Again this is not needed */
long r25;
long r24;
long r23;
@@ -99,18 +103,20 @@ struct callee_regs {
/* return 1 if PC in delay slot */
#define delay_mode(regs) ((regs->status32 & STATUS_DE_MASK) == STATUS_DE_MASK)
-#define in_syscall(regs) (regs->event & orig_r8_IS_SCALL)
-#define in_brkpt_trap(regs) (regs->event & orig_r8_IS_BRKPT)
+#define in_syscall(regs) ((regs->ecr_vec == ECR_V_TRAP) && !regs->ecr_param)
+#define in_brkpt_trap(regs) ((regs->ecr_vec == ECR_V_TRAP) && regs->ecr_param)
+
+#define STATE_SCALL_RESTARTED 0x01
-#define syscall_wont_restart(regs) (regs->event |= orig_r8_IS_SCALL_RESTARTED)
-#define syscall_restartable(regs) !(regs->event & orig_r8_IS_SCALL_RESTARTED)
+#define syscall_wont_restart(reg) (reg->state |= STATE_SCALL_RESTARTED)
+#define syscall_restartable(reg) !(reg->state & STATE_SCALL_RESTARTED)
#define current_pt_regs() \
({ \
/* open-coded current_thread_info() */ \
register unsigned long sp asm ("sp"); \
unsigned long pg_start = (sp & ~(THREAD_SIZE - 1)); \
- (struct pt_regs *)(pg_start + THREAD_SIZE - 4) - 1; \
+ (struct pt_regs *)(pg_start + THREAD_SIZE) - 1; \
})
static inline long regs_return_value(struct pt_regs *regs)
@@ -120,11 +126,4 @@ static inline long regs_return_value(struct pt_regs *regs)
#endif /* !__ASSEMBLY__ */
-#define orig_r8_IS_SCALL 0x0001
-#define orig_r8_IS_SCALL_RESTARTED 0x0002
-#define orig_r8_IS_BRKPT 0x0004
-#define orig_r8_IS_EXCPN 0x0008
-#define orig_r8_IS_IRQ1 0x0010
-#define orig_r8_IS_IRQ2 0x0020
-
#endif /* __ASM_PTRACE_H */
diff --git a/arch/arc/include/asm/syscall.h b/arch/arc/include/asm/syscall.h
index 33ab3048e9b2..29de09804306 100644
--- a/arch/arc/include/asm/syscall.h
+++ b/arch/arc/include/asm/syscall.h
@@ -18,7 +18,7 @@ static inline long
syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
if (user_mode(regs) && in_syscall(regs))
- return regs->orig_r8;
+ return regs->r8;
else
return -1;
}
@@ -26,8 +26,7 @@ syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
static inline void
syscall_rollback(struct task_struct *task, struct pt_regs *regs)
{
- /* XXX: I can't fathom how pt_regs->r8 will be clobbered ? */
- regs->r8 = regs->orig_r8;
+ regs->r0 = regs->orig_r0;
}
static inline long
diff --git a/arch/arc/include/asm/tlb-mmu1.h b/arch/arc/include/asm/tlb-mmu1.h
index a5ff961b1efc..8a1ec96012ae 100644
--- a/arch/arc/include/asm/tlb-mmu1.h
+++ b/arch/arc/include/asm/tlb-mmu1.h
@@ -9,9 +9,9 @@
#ifndef __ASM_TLB_MMU_V1_H__
#define __ASM_TLB_MMU_V1_H__
-#if defined(__ASSEMBLY__) && defined(CONFIG_ARC_MMU_VER == 1)
+#include <asm/mmu.h>
-#include <asm/tlb.h>
+#if defined(__ASSEMBLY__) && (CONFIG_ARC_MMU_VER == 1)
.macro TLB_WRITE_HEURISTICS
diff --git a/arch/arc/include/asm/tlb.h b/arch/arc/include/asm/tlb.h
index cb0c708ca665..a9db5f62aaf3 100644
--- a/arch/arc/include/asm/tlb.h
+++ b/arch/arc/include/asm/tlb.h
@@ -9,18 +9,6 @@
#ifndef _ASM_ARC_TLB_H
#define _ASM_ARC_TLB_H
-#ifdef __KERNEL__
-
-#include <asm/pgtable.h>
-
-/* Masks for actual TLB "PD"s */
-#define PTE_BITS_IN_PD0 (_PAGE_GLOBAL | _PAGE_PRESENT)
-#define PTE_BITS_IN_PD1 (PAGE_MASK | _PAGE_CACHEABLE | \
- _PAGE_U_EXECUTE | _PAGE_U_WRITE | _PAGE_U_READ | \
- _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
-
-#ifndef __ASSEMBLY__
-
#define tlb_flush(tlb) \
do { \
if (tlb->fullmm) \
@@ -56,18 +44,4 @@ do { \
#include <linux/pagemap.h>
#include <asm-generic/tlb.h>
-#ifdef CONFIG_ARC_DBG_TLB_PARANOIA
-void tlb_paranoid_check(unsigned int pid_sw, unsigned long address);
-#else
-#define tlb_paranoid_check(a, b)
-#endif
-
-void arc_mmu_init(void);
-extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
-void __init read_decode_mmu_bcr(void);
-
-#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL__ */
-
#endif /* _ASM_ARC_TLB_H */
diff --git a/arch/arc/include/asm/unaligned.h b/arch/arc/include/asm/unaligned.h
index 5dbe63f17b66..60702f3751d2 100644
--- a/arch/arc/include/asm/unaligned.h
+++ b/arch/arc/include/asm/unaligned.h
@@ -16,11 +16,11 @@
#ifdef CONFIG_ARC_MISALIGN_ACCESS
int misaligned_fixup(unsigned long address, struct pt_regs *regs,
- unsigned long cause, struct callee_regs *cregs);
+ struct callee_regs *cregs);
#else
static inline int
misaligned_fixup(unsigned long address, struct pt_regs *regs,
- unsigned long cause, struct callee_regs *cregs)
+ struct callee_regs *cregs)
{
return 0;
}
diff --git a/arch/arc/include/uapi/asm/ptrace.h b/arch/arc/include/uapi/asm/ptrace.h
index 30333cec0fef..2618cc13ba75 100644
--- a/arch/arc/include/uapi/asm/ptrace.h
+++ b/arch/arc/include/uapi/asm/ptrace.h
@@ -20,28 +20,31 @@
*
* This is to decouple pt_regs from user-space ABI, to be able to change it
* w/o affecting the ABI.
- * Although the layout (initial padding) is similar to pt_regs to have some
- * optimizations when copying pt_regs to/from user_regs_struct.
+ *
+ * The intermediate pad,pad2 are relics of initial layout based on pt_regs
+ * for optimizations when copying pt_regs to/from user_regs_struct.
+ * We no longer need them, but can't be changed as they are part of ABI now.
*
* Also, sigcontext only care about the scratch regs as that is what we really
- * save/restore for signal handling.
+ * save/restore for signal handling. However gdb also uses the same struct
+ * hence callee regs need to be in there too.
*/
struct user_regs_struct {
+ long pad;
struct {
- long pad;
long bta, lp_start, lp_end, lp_count;
long status32, ret, blink, fp, gp;
long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
long sp;
} scratch;
+ long pad2;
struct {
- long pad;
long r25, r24, r23, r22, r21, r20;
long r19, r18, r17, r16, r15, r14, r13;
} callee;
long efa; /* break pt addr, for break points in delay slots */
- long stop_pc; /* give dbg stop_pc directly after checking orig_r8 */
+ long stop_pc; /* give dbg stop_pc after ensuring brkpt trap */
};
#endif /* !__ASSEMBLY__ */
diff --git a/arch/arc/kernel/asm-offsets.c b/arch/arc/kernel/asm-offsets.c
index 7dcda7025241..6c3aa0edb9b5 100644
--- a/arch/arc/kernel/asm-offsets.c
+++ b/arch/arc/kernel/asm-offsets.c
@@ -24,9 +24,6 @@ int main(void)
DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
DEFINE(THREAD_CALLEE_REG, offsetof(struct thread_struct, callee_reg));
-#ifdef CONFIG_ARC_CURR_IN_REG
- DEFINE(THREAD_USER_R25, offsetof(struct thread_struct, user_r25));
-#endif
DEFINE(THREAD_FAULT_ADDR,
offsetof(struct thread_struct, fault_address));
@@ -49,7 +46,7 @@ int main(void)
BLANK();
DEFINE(PT_status32, offsetof(struct pt_regs, status32));
- DEFINE(PT_orig_r8, offsetof(struct pt_regs, orig_r8_word));
+ DEFINE(PT_event, offsetof(struct pt_regs, event));
DEFINE(PT_sp, offsetof(struct pt_regs, sp));
DEFINE(PT_r0, offsetof(struct pt_regs, r0));
DEFINE(PT_r1, offsetof(struct pt_regs, r1));
@@ -60,5 +57,7 @@ int main(void)
DEFINE(PT_r6, offsetof(struct pt_regs, r6));
DEFINE(PT_r7, offsetof(struct pt_regs, r7));
+ DEFINE(SZ_CALLEE_REGS, sizeof(struct callee_regs));
+ DEFINE(SZ_PT_REGS, sizeof(struct pt_regs));
return 0;
}
diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c
index 60844dac6132..34410eb1a308 100644
--- a/arch/arc/kernel/ctx_sw.c
+++ b/arch/arc/kernel/ctx_sw.c
@@ -23,10 +23,6 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
unsigned int tmp;
unsigned int prev = (unsigned int)prev_task;
unsigned int next = (unsigned int)next_task;
- int num_words_to_skip = 1;
-#ifdef CONFIG_ARC_CURR_IN_REG
- num_words_to_skip++;
-#endif
__asm__ __volatile__(
/* FP/BLINK save generated by gcc (standard function prologue */
@@ -44,8 +40,9 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
"st.a r24, [sp, -4] \n\t"
#ifndef CONFIG_ARC_CURR_IN_REG
"st.a r25, [sp, -4] \n\t"
+#else
+ "sub sp, sp, 4 \n\t" /* usual r25 placeholder */
#endif
- "sub sp, sp, %4 \n\t" /* create gutter at top */
/* set ksp of outgoing task in tsk->thread.ksp */
"st.as sp, [%3, %1] \n\t"
@@ -76,10 +73,10 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
/* start loading it's CALLEE reg file */
- "add sp, sp, %4 \n\t" /* skip gutter at top */
-
#ifndef CONFIG_ARC_CURR_IN_REG
"ld.ab r25, [sp, 4] \n\t"
+#else
+ "add sp, sp, 4 \n\t"
#endif
"ld.ab r24, [sp, 4] \n\t"
"ld.ab r23, [sp, 4] \n\t"
@@ -100,8 +97,7 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
/* FP/BLINK restore generated by gcc (standard func epilogue */
: "=r"(tmp)
- : "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev),
- "n"(num_words_to_skip * 4)
+ : "n"((TASK_THREAD + THREAD_KSP) / 4), "r"(next), "r"(prev)
: "blink"
);
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 0c6d664d4a83..1d7165156e17 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -142,7 +142,7 @@ VECTOR reserved ; Reserved Exceptions
.endr
#include <linux/linkage.h> /* ARC_{EXTRY,EXIT} */
-#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,TRAP...} */
+#include <asm/entry.h> /* SAVE_ALL_{INT1,INT2,SYS...} */
#include <asm/errno.h>
#include <asm/arcregs.h>
#include <asm/irqflags.h>
@@ -274,10 +274,8 @@ ARC_ENTRY instr_service
SWITCH_TO_KERNEL_STK
SAVE_ALL_SYS
- lr r0, [ecr]
- lr r1, [efa]
-
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
FAKE_RET_FROM_EXCPN r9
@@ -298,9 +296,8 @@ ARC_ENTRY mem_service
SWITCH_TO_KERNEL_STK
SAVE_ALL_SYS
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
bl do_memory_error
b ret_from_exception
ARC_EXIT mem_service
@@ -317,11 +314,14 @@ ARC_ENTRY EV_MachineCheck
SWITCH_TO_KERNEL_STK
SAVE_ALL_SYS
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lr r2, [ecr]
+ lr r0, [efa]
+ mov r1, sp
+
+ lsr r3, r2, 8
+ bmsk r3, r3, 7
+ brne r3, ECR_C_MCHK_DUP_TLB, 1f
- brne r0, 0x200100, 1f
bl do_tlb_overlap_fault
b ret_from_exception
@@ -355,8 +355,8 @@ ARC_ENTRY EV_TLBProtV
; ecr and efa were not saved in case an Intr sneaks in
; after fake rtie
;
- lr r3, [ecr]
- lr r4, [efa]
+ lr r2, [ecr]
+ lr r1, [efa] ; Faulting Data address
; --------(4) Return from CPU Exception Mode ---------
; Fake a rtie, but rtie to next label
@@ -368,31 +368,25 @@ ARC_ENTRY EV_TLBProtV
;------ (5) Type of Protection Violation? ----------
;
; ProtV Hardware Exception is triggered for Access Faults of 2 types
- ; -Access Violaton (WRITE to READ ONLY Page) - for linux COW
- ; -Unaligned Access (READ/WRITE on odd boundary)
+ ; -Access Violaton : 00_23_(00|01|02|03)_00
+ ; x r w r+w
+ ; -Unaligned Access : 00_23_04_00
;
- cmp r3, 0x230400 ; Misaligned data access ?
- beq 4f
+ bbit1 r2, ECR_C_BIT_PROTV_MISALIG_DATA, 4f
;========= (6a) Access Violation Processing ========
- cmp r3, 0x230100
- mov r1, 0x0 ; if LD exception ? write = 0
- mov.ne r1, 0x1 ; else write = 1
-
- mov r2, r4 ; faulting address
mov r0, sp ; pt_regs
bl do_page_fault
b ret_from_exception
;========== (6b) Non aligned access ============
4:
- mov r0, r3 ; cause code
- mov r1, r4 ; faulting address
- mov r2, sp ; pt_regs
+ mov r0, r1
+ mov r1, sp ; pt_regs
#ifdef CONFIG_ARC_MISALIGN_ACCESS
SAVE_CALLEE_SAVED_USER
- mov r3, sp ; callee_regs
+ mov r2, sp ; callee_regs
bl do_misaligned_access
@@ -419,9 +413,8 @@ ARC_ENTRY EV_PrivilegeV
SWITCH_TO_KERNEL_STK
SAVE_ALL_SYS
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
FAKE_RET_FROM_EXCPN r9
@@ -440,9 +433,8 @@ ARC_ENTRY EV_Extension
SWITCH_TO_KERNEL_STK
SAVE_ALL_SYS
- lr r0, [ecr]
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
bl do_extension_fault
b ret_from_exception
ARC_EXIT EV_Extension
@@ -498,11 +490,8 @@ tracesys_exit:
trap_with_param:
; stop_pc info by gdb needs this info
- stw orig_r8_IS_BRKPT, [sp, PT_orig_r8]
-
- mov r0, r12
- lr r1, [efa]
- mov r2, sp
+ lr r0, [efa]
+ mov r1, sp
; Now that we have read EFA, its safe to do "fake" rtie
; and get out of CPU exception mode
@@ -544,11 +533,11 @@ ARC_ENTRY EV_Trap
lr r9, [erstatus]
SWITCH_TO_KERNEL_STK
- SAVE_ALL_TRAP
+ SAVE_ALL_SYS
;------- (4) What caused the Trap --------------
lr r12, [ecr]
- and.f 0, r12, ECR_PARAM_MASK
+ bmsk.f 0, r12, 7
bnz trap_with_param
; ======= (5a) Trap is due to System Call ========
@@ -589,11 +578,7 @@ ARC_ENTRY ret_from_exception
; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
ld r8, [sp, PT_status32] ; returning to User/Kernel Mode
-#ifdef CONFIG_PREEMPT
bbit0 r8, STATUS_U_BIT, resume_kernel_mode
-#else
- bbit0 r8, STATUS_U_BIT, restore_regs
-#endif
; Before returning to User mode check-for-and-complete any pending work
; such as rescheduling/signal-delivery etc.
@@ -653,10 +638,10 @@ resume_user_mode_begin:
b resume_user_mode_begin ; unconditionally back to U mode ret chks
; for single exit point from this block
-#ifdef CONFIG_PREEMPT
-
resume_kernel_mode:
+#ifdef CONFIG_PREEMPT
+
; Can't preempt if preemption disabled
GET_CURR_THR_INFO_FROM_SP r10
ld r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -687,17 +672,6 @@ restore_regs :
; XXX can this be optimised out
IRQ_DISABLE_SAVE r9, r10 ;@r10 has prisitine (pre-disable) copy
-#ifdef CONFIG_ARC_CURR_IN_REG
- ; Restore User R25
- ; Earlier this used to be only for returning to user mode
- ; However with 2 levels of IRQ this can also happen even if
- ; in kernel mode
- ld r9, [sp, PT_sp]
- brhs r9, VMALLOC_START, 8f
- RESTORE_USER_R25
-8:
-#endif
-
; Restore REG File. In case multiple Events outstanding,
; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
; Note that we use realtime STATUS32 (not pt_regs->status32) to
@@ -714,28 +688,33 @@ not_exception:
#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
+ ; Level 2 interrupt return Path - from hardware standpoint
bbit0 r10, STATUS_A2_BIT, not_level2_interrupt
;------------------------------------------------------------------
+ ; However the context returning might not have taken L2 intr itself
+ ; e.g. Task'A' user-code -> L2 intr -> schedule -> 'B' user-code ret
+ ; Special considerations needed for the context which took L2 intr
+
+ ld r9, [sp, PT_event] ; Ensure this is L2 intr context
+ brne r9, event_IRQ2, 149f
+
+ ;------------------------------------------------------------------
; if L2 IRQ interrupted a L1 ISR, we'd disbaled preemption earlier
; so that sched doesnt move to new task, causing L1 to be delayed
; undeterministically. Now that we've achieved that, lets reset
; things to what they were, before returning from L2 context
;----------------------------------------------------------------
- ldw r9, [sp, PT_orig_r8] ; get orig_r8 to make sure it is
- brne r9, orig_r8_IS_IRQ2, 149f ; infact a L2 ISR ret path
-
ld r9, [sp, PT_status32] ; get statu32_l2 (saved in pt_regs)
bbit0 r9, STATUS_A1_BIT, 149f ; L1 not active when L2 IRQ, so normal
- ; A1 is set in status32_l2
; decrement thread_info->preempt_count (re-enable preemption)
GET_CURR_THR_INFO_FROM_SP r10
ld r9, [r10, THREAD_INFO_PREEMPT_COUNT]
; paranoid check, given A1 was active when A2 happened, preempt count
- ; must not be 0 beccause we would have incremented it.
+ ; must not be 0 because we would have incremented it.
; If this does happen we simply HALT as it means a BUG !!!
cmp r9, 0
bnz 2f
diff --git a/arch/arc/kernel/head.S b/arch/arc/kernel/head.S
index 006dec3fc353..2a913f85a747 100644
--- a/arch/arc/kernel/head.S
+++ b/arch/arc/kernel/head.S
@@ -27,6 +27,8 @@ stext:
; Don't clobber r0-r4 yet. It might have bootloader provided info
;-------------------------------------------------------------------
+ sr @_int_vec_base_lds, [AUX_INTR_VEC_BASE]
+
#ifdef CONFIG_SMP
; Only Boot (Master) proceeds. Others wait in platform dependent way
; IDENTITY Reg [ 3 2 1 0 ]
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c
index 8115fa531575..305b3f866aa7 100644
--- a/arch/arc/kernel/irq.c
+++ b/arch/arc/kernel/irq.c
@@ -28,25 +28,17 @@
* -Disable all IRQs (on CPU side)
* -Optionally, setup the High priority Interrupts as Level 2 IRQs
*/
-void __cpuinit arc_init_IRQ(void)
+void arc_init_IRQ(void)
{
int level_mask = 0;
- write_aux_reg(AUX_INTR_VEC_BASE, _int_vec_base_lds);
-
/* Disable all IRQs: enable them as devices request */
write_aux_reg(AUX_IENABLE, 0);
/* setup any high priority Interrupts (Level2 in ARCompact jargon) */
-#ifdef CONFIG_ARC_IRQ3_LV2
- level_mask |= (1 << 3);
-#endif
-#ifdef CONFIG_ARC_IRQ5_LV2
- level_mask |= (1 << 5);
-#endif
-#ifdef CONFIG_ARC_IRQ6_LV2
- level_mask |= (1 << 6);
-#endif
+ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ3_LV2) << 3;
+ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ5_LV2) << 5;
+ level_mask |= IS_ENABLED(CONFIG_ARC_IRQ6_LV2) << 6;
if (level_mask) {
pr_info("Level-2 interrupts bitset %x\n", level_mask);
diff --git a/arch/arc/kernel/kgdb.c b/arch/arc/kernel/kgdb.c
index 52bdc83c1495..a7698fb14818 100644
--- a/arch/arc/kernel/kgdb.c
+++ b/arch/arc/kernel/kgdb.c
@@ -169,7 +169,7 @@ int kgdb_arch_init(void)
return 0;
}
-void kgdb_trap(struct pt_regs *regs, int param)
+void kgdb_trap(struct pt_regs *regs)
{
/* trap_s 3 is used for breakpoints that overwrite existing
* instructions, while trap_s 4 is used for compiled breakpoints.
@@ -181,7 +181,7 @@ void kgdb_trap(struct pt_regs *regs, int param)
* with trap_s 4 (compiled) breakpoints, continuation needs to
* start after the breakpoint.
*/
- if (param == 3)
+ if (regs->ecr_param == 3)
instruction_pointer(regs) -= BREAK_INSTR_SIZE;
kgdb_handle_exception(1, SIGTRAP, 0, regs);
diff --git a/arch/arc/kernel/kprobes.c b/arch/arc/kernel/kprobes.c
index 5a7b80e2d883..72f97822784a 100644
--- a/arch/arc/kernel/kprobes.c
+++ b/arch/arc/kernel/kprobes.c
@@ -517,8 +517,7 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p)
return 0;
}
-void trap_is_kprobe(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+void trap_is_kprobe(unsigned long address, struct pt_regs *regs)
{
- notify_die(DIE_TRAP, "kprobe_trap", regs, address, cause, SIGTRAP);
+ notify_die(DIE_TRAP, "kprobe_trap", regs, address, 0, SIGTRAP);
}
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index cad66851e0c4..07a3a968fe49 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -55,10 +55,8 @@ asmlinkage void ret_from_fork(void);
* | ... |
* | unused |
* | |
- * ------------------ <==== top of Stack (thread.ksp)
- * | UNUSED 1 word|
* ------------------
- * | r25 |
+ * | r25 | <==== top of Stack (thread.ksp)
* ~ ~
* | --to-- | (CALLEE Regs of user mode)
* | r13 |
@@ -76,7 +74,10 @@ asmlinkage void ret_from_fork(void);
* | --to-- | (scratch Regs of user mode)
* | r0 |
* ------------------
- * | UNUSED 1 word|
+ * | SP |
+ * | orig_r0 |
+ * | event/ECR |
+ * | user_r25 |
* ------------------ <===== END of PAGE
*/
int copy_thread(unsigned long clone_flags,
diff --git a/arch/arc/kernel/ptrace.c b/arch/arc/kernel/ptrace.c
index c6a81c58d0f3..333238564b67 100644
--- a/arch/arc/kernel/ptrace.c
+++ b/arch/arc/kernel/ptrace.c
@@ -40,7 +40,15 @@ static int genregs_get(struct task_struct *target,
offsetof(struct user_regs_struct, LOC), \
offsetof(struct user_regs_struct, LOC) + 4);
+#define REG_O_ZERO(LOC) \
+ if (!ret) \
+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
+ offsetof(struct user_regs_struct, LOC), \
+ offsetof(struct user_regs_struct, LOC) + 4);
+
+ REG_O_ZERO(pad);
REG_O_CHUNK(scratch, callee, ptregs);
+ REG_O_ZERO(pad2);
REG_O_CHUNK(callee, efa, cregs);
REG_O_CHUNK(efa, stop_pc, &target->thread.fault_address);
@@ -88,8 +96,10 @@ static int genregs_set(struct task_struct *target,
offsetof(struct user_regs_struct, LOC), \
offsetof(struct user_regs_struct, LOC) + 4);
- /* TBD: disallow updates to STATUS32, orig_r8 etc*/
- REG_IN_CHUNK(scratch, callee, ptregs); /* pt_regs[bta..orig_r8] */
+ REG_IGNORE_ONE(pad);
+ /* TBD: disallow updates to STATUS32 etc*/
+ REG_IN_CHUNK(scratch, pad2, ptregs); /* pt_regs[bta..sp] */
+ REG_IGNORE_ONE(pad2);
REG_IN_CHUNK(callee, efa, cregs); /* callee_regs[r25..r13] */
REG_IGNORE_ONE(efa); /* efa update invalid */
REG_IN_ONE(stop_pc, &ptregs->ret); /* stop_pc: PC update */
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index b2b3731dd1e9..6b083454d039 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -31,14 +31,14 @@
int running_on_hw = 1; /* vs. on ISS */
char __initdata command_line[COMMAND_LINE_SIZE];
-struct machine_desc *machine_desc __cpuinitdata;
+struct machine_desc *machine_desc;
struct task_struct *_current_task[NR_CPUS]; /* For stack switching */
struct cpuinfo_arc cpuinfo_arc700[NR_CPUS];
-void __cpuinit read_arc_build_cfg_regs(void)
+void read_arc_build_cfg_regs(void)
{
struct bcr_perip uncached_space;
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -182,7 +182,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
FIX_PTR(cpu);
#define IS_AVAIL1(var, str) ((var) ? str : "")
#define IS_AVAIL2(var, str) ((var == 0x2) ? str : "")
-#define IS_USED(var) ((var) ? "(in-use)" : "(not used)")
+#define IS_USED(cfg) (IS_ENABLED(cfg) ? "(in-use)" : "(not used)")
n += scnprintf(buf + n, len - n,
"Extn [700-Base]\t: %s %s %s %s %s %s\n",
@@ -202,9 +202,9 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
if (cpu->core.family == 0x34) {
n += scnprintf(buf + n, len - n,
"Extn [700-4.10]\t: LLOCK/SCOND %s, SWAPE %s, RTSC %s\n",
- IS_USED(__CONFIG_ARC_HAS_LLSC_VAL),
- IS_USED(__CONFIG_ARC_HAS_SWAPE_VAL),
- IS_USED(__CONFIG_ARC_HAS_RTSC_VAL));
+ IS_USED(CONFIG_ARC_HAS_LLSC),
+ IS_USED(CONFIG_ARC_HAS_SWAPE),
+ IS_USED(CONFIG_ARC_HAS_RTSC));
}
n += scnprintf(buf + n, len - n, "Extn [CCM]\t: %s",
@@ -237,7 +237,7 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
return buf;
}
-void __cpuinit arc_chk_ccms(void)
+void arc_chk_ccms(void)
{
#if defined(CONFIG_ARC_HAS_DCCM) || defined(CONFIG_ARC_HAS_ICCM)
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -272,7 +272,7 @@ void __cpuinit arc_chk_ccms(void)
* hardware has dedicated regs which need to be saved/restored on ctx-sw
* (Single Precision uses core regs), thus kernel is kind of oblivious to it
*/
-void __cpuinit arc_chk_fpu(void)
+void arc_chk_fpu(void)
{
struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
@@ -293,7 +293,7 @@ void __cpuinit arc_chk_fpu(void)
* such as only for boot CPU etc
*/
-void __cpuinit setup_processor(void)
+void setup_processor(void)
{
char str[512];
int cpu_id = smp_processor_id();
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 5c7fd603d216..bca3052c956d 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -117,7 +117,7 @@ const char *arc_platform_smp_cpuinfo(void)
* Called from asm stub in head.S
* "current"/R25 already setup by low level boot code
*/
-void __cpuinit start_kernel_secondary(void)
+void start_kernel_secondary(void)
{
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
@@ -154,7 +154,7 @@ void __cpuinit start_kernel_secondary(void)
*
* Essential requirements being where to run from (PC) and stack (SP)
*/
-int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
+int __cpu_up(unsigned int cpu, struct task_struct *idle)
{
unsigned long wait_till;
diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c
index ca0207b9d5b6..f8b7d880304d 100644
--- a/arch/arc/kernel/stacktrace.c
+++ b/arch/arc/kernel/stacktrace.c
@@ -79,7 +79,7 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
* assembly code
*/
frame_info->regs.r27 = 0;
- frame_info->regs.r28 += 64;
+ frame_info->regs.r28 += 60;
frame_info->call_frame = 0;
} else {
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index 09f4309aa2c0..0e51e69cf30d 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -44,13 +44,24 @@
#include <asm/clk.h>
#include <asm/mach_desc.h>
+/* Timer related Aux registers */
+#define ARC_REG_TIMER0_LIMIT 0x23 /* timer 0 limit */
+#define ARC_REG_TIMER0_CTRL 0x22 /* timer 0 control */
+#define ARC_REG_TIMER0_CNT 0x21 /* timer 0 count */
+#define ARC_REG_TIMER1_LIMIT 0x102 /* timer 1 limit */
+#define ARC_REG_TIMER1_CTRL 0x101 /* timer 1 control */
+#define ARC_REG_TIMER1_CNT 0x100 /* timer 1 count */
+
+#define TIMER_CTRL_IE (1 << 0) /* Interupt when Count reachs limit */
+#define TIMER_CTRL_NH (1 << 1) /* Count only when CPU NOT halted */
+
#define ARC_TIMER_MAX 0xFFFFFFFF
/********** Clock Source Device *********/
#ifdef CONFIG_ARC_HAS_RTSC
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
{
/* RTSC insn taps into cpu clk, needs no setup */
@@ -105,7 +116,7 @@ static bool is_usable_as_clocksource(void)
/*
* set 32bit TIMER1 to keep counting monotonically and wraparound
*/
-int __cpuinit arc_counter_setup(void)
+int arc_counter_setup(void)
{
write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMER_MAX);
write_aux_reg(ARC_REG_TIMER1_CNT, 0);
@@ -212,7 +223,7 @@ static struct irqaction arc_timer_irq = {
* Setup the local event timer for @cpu
* N.B. weak so that some exotic ARC SoCs can completely override it
*/
-void __attribute__((weak)) __cpuinit arc_local_timer_setup(unsigned int cpu)
+void __attribute__((weak)) arc_local_timer_setup(unsigned int cpu)
{
struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
diff --git a/arch/arc/kernel/traps.c b/arch/arc/kernel/traps.c
index 0471d9c9dd54..e21692d2fdab 100644
--- a/arch/arc/kernel/traps.c
+++ b/arch/arc/kernel/traps.c
@@ -28,10 +28,9 @@ void __init trap_init(void)
return;
}
-void die(const char *str, struct pt_regs *regs, unsigned long address,
- unsigned long cause_reg)
+void die(const char *str, struct pt_regs *regs, unsigned long address)
{
- show_kernel_fault_diag(str, regs, address, cause_reg);
+ show_kernel_fault_diag(str, regs, address);
/* DEAD END */
__asm__("flag 1");
@@ -42,14 +41,13 @@ void die(const char *str, struct pt_regs *regs, unsigned long address,
* -for user faults enqueues requested signal
* -for kernel, chk if due to copy_(to|from)_user, otherwise die()
*/
-static noinline int handle_exception(unsigned long cause, char *str,
- struct pt_regs *regs, siginfo_t *info)
+static noinline int
+handle_exception(const char *str, struct pt_regs *regs, siginfo_t *info)
{
if (user_mode(regs)) {
struct task_struct *tsk = current;
tsk->thread.fault_address = (__force unsigned int)info->si_addr;
- tsk->thread.cause_code = cause;
force_sig_info(info->si_signo, info, tsk);
@@ -58,14 +56,14 @@ static noinline int handle_exception(unsigned long cause, char *str,
if (fixup_exception(regs))
return 0;
- die(str, regs, (unsigned long)info->si_addr, cause);
+ die(str, regs, (unsigned long)info->si_addr);
}
return 1;
}
#define DO_ERROR_INFO(signr, str, name, sicode) \
-int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
+int name(unsigned long address, struct pt_regs *regs) \
{ \
siginfo_t info = { \
.si_signo = signr, \
@@ -73,7 +71,7 @@ int name(unsigned long cause, unsigned long address, struct pt_regs *regs) \
.si_code = sicode, \
.si_addr = (void __user *)address, \
}; \
- return handle_exception(cause, str, regs, &info);\
+ return handle_exception(str, regs, &info);\
}
/*
@@ -90,11 +88,11 @@ DO_ERROR_INFO(SIGBUS, "Misaligned Access", do_misaligned_error, BUS_ADRALN)
/*
* Entry Point for Misaligned Data access Exception, for emulating in software
*/
-int do_misaligned_access(unsigned long cause, unsigned long address,
- struct pt_regs *regs, struct callee_regs *cregs)
+int do_misaligned_access(unsigned long address, struct pt_regs *regs,
+ struct callee_regs *cregs)
{
- if (misaligned_fixup(address, regs, cause, cregs) != 0)
- return do_misaligned_error(cause, address, regs);
+ if (misaligned_fixup(address, regs, cregs) != 0)
+ return do_misaligned_error(address, regs);
return 0;
}
@@ -104,10 +102,9 @@ int do_misaligned_access(unsigned long cause, unsigned long address,
* Entry point for miscll errors such as Nested Exceptions
* -Duplicate TLB entry is handled seperately though
*/
-void do_machine_check_fault(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+void do_machine_check_fault(unsigned long address, struct pt_regs *regs)
{
- die("Machine Check Exception", regs, address, cause);
+ die("Machine Check Exception", regs, address);
}
@@ -120,23 +117,22 @@ void do_machine_check_fault(unsigned long cause, unsigned long address,
* -1 used for software breakpointing (gdb)
* -2 used by kprobes
*/
-void do_non_swi_trap(unsigned long cause, unsigned long address,
- struct pt_regs *regs)
+void do_non_swi_trap(unsigned long address, struct pt_regs *regs)
{
- unsigned int param = cause & 0xff;
+ unsigned int param = regs->ecr_param;
switch (param) {
case 1:
- trap_is_brkpt(cause, address, regs);
+ trap_is_brkpt(address, regs);
break;
case 2:
- trap_is_kprobe(param, address, regs);
+ trap_is_kprobe(address, regs);
break;
case 3:
case 4:
- kgdb_trap(regs, param);
+ kgdb_trap(regs);
break;
default:
@@ -149,14 +145,14 @@ void do_non_swi_trap(unsigned long cause, unsigned long address,
* -For a corner case, ARC kprobes implementation resorts to using
* this exception, hence the check
*/
-void do_insterror_or_kprobe(unsigned long cause,
- unsigned long address,
- struct pt_regs *regs)
+void do_insterror_or_kprobe(unsigned long address, struct pt_regs *regs)
{
+ int rc;
+
/* Check if this exception is caused by kprobes */
- if (notify_die(DIE_IERR, "kprobe_ierr", regs, address,
- cause, SIGILL) == NOTIFY_STOP)
+ rc = notify_die(DIE_IERR, "kprobe_ierr", regs, address, 0, SIGILL);
+ if (rc == NOTIFY_STOP)
return;
- insterror_is_error(cause, address, regs);
+ insterror_is_error(address, regs);
}
diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index 11c301b81c92..73a7450ee622 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -101,7 +101,7 @@ static void show_faulting_vma(unsigned long address, char *buf)
if (file) {
struct path *path = &file->f_path;
nm = d_path(path, buf, PAGE_SIZE - 1);
- inode = vma->vm_file->f_path.dentry->d_inode;
+ inode = file_inode(vma->vm_file);
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
}
@@ -117,23 +117,22 @@ static void show_faulting_vma(unsigned long address, char *buf)
static void show_ecr_verbose(struct pt_regs *regs)
{
- unsigned int vec, cause_code, cause_reg;
+ unsigned int vec, cause_code;
unsigned long address;
- cause_reg = current->thread.cause_code;
- pr_info("\n[ECR ]: 0x%08x => ", cause_reg);
+ pr_info("\n[ECR ]: 0x%08lx => ", regs->event);
/* For Data fault, this is data address not instruction addr */
address = current->thread.fault_address;
- vec = cause_reg >> 16;
- cause_code = (cause_reg >> 8) & 0xFF;
+ vec = regs->ecr_vec;
+ cause_code = regs->ecr_cause;
/* For DTLB Miss or ProtV, display the memory involved too */
if (vec == ECR_V_DTLB_MISS) {
- pr_cont("Invalid %s 0x%08lx by insn @ 0x%08lx\n",
- (cause_code == 0x01) ? "Read From" :
- ((cause_code == 0x02) ? "Write to" : "EX"),
+ pr_cont("Invalid %s @ 0x%08lx by insn @ 0x%08lx\n",
+ (cause_code == 0x01) ? "Read" :
+ ((cause_code == 0x02) ? "Write" : "EX"),
address, regs->ret);
} else if (vec == ECR_V_ITLB_MISS) {
pr_cont("Insn could not be fetched\n");
@@ -144,14 +143,12 @@ static void show_ecr_verbose(struct pt_regs *regs)
} else if (vec == ECR_V_PROTV) {
if (cause_code == ECR_C_PROTV_INST_FETCH)
pr_cont("Execute from Non-exec Page\n");
- else if (cause_code == ECR_C_PROTV_LOAD)
- pr_cont("Read from Non-readable Page\n");
- else if (cause_code == ECR_C_PROTV_STORE)
- pr_cont("Write to Non-writable Page\n");
- else if (cause_code == ECR_C_PROTV_XCHG)
- pr_cont("Data exchange protection violation\n");
else if (cause_code == ECR_C_PROTV_MISALIG_DATA)
pr_cont("Misaligned r/w from 0x%08lx\n", address);
+ else
+ pr_cont("%s access not allowed on page\n",
+ (cause_code == 0x01) ? "Read" :
+ ((cause_code == 0x02) ? "Write" : "EX"));
} else if (vec == ECR_V_INSN_ERR) {
pr_cont("Illegal Insn\n");
} else {
@@ -176,8 +173,7 @@ void show_regs(struct pt_regs *regs)
print_task_path_n_nm(tsk, buf);
show_regs_print_info(KERN_INFO);
- if (current->thread.cause_code)
- show_ecr_verbose(regs);
+ show_ecr_verbose(regs);
pr_info("[EFA ]: 0x%08lx\n[BLINK ]: %pS\n[ERET ]: %pS\n",
current->thread.fault_address,
@@ -213,10 +209,9 @@ void show_regs(struct pt_regs *regs)
}
void show_kernel_fault_diag(const char *str, struct pt_regs *regs,
- unsigned long address, unsigned long cause_reg)
+ unsigned long address)
{
current->thread.fault_address = address;
- current->thread.cause_code = cause_reg;
/* Caller and Callee regs */
show_regs(regs);
diff --git a/arch/arc/kernel/unaligned.c b/arch/arc/kernel/unaligned.c
index 4cd81633febd..c0f832f595d3 100644
--- a/arch/arc/kernel/unaligned.c
+++ b/arch/arc/kernel/unaligned.c
@@ -187,7 +187,7 @@ fault: state->fault = 1;
* Returns 0 if successfully handled, 1 if some error happened
*/
int misaligned_fixup(unsigned long address, struct pt_regs *regs,
- unsigned long cause, struct callee_regs *cregs)
+ struct callee_regs *cregs)
{
struct disasm_state state;
char buf[TASK_COMM_LEN];
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index a8d02223da44..e550b117ec4f 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -289,6 +289,8 @@ static void __init setup_unwind_table(struct unwind_table *table,
* instead of the initial loc addr
* return;
*/
+ WARN(1, "unwinder: FDE->initial_location NULL %p\n",
+ (const u8 *)(fde + 1) + *fde);
}
++n;
}
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index d3c92f52d444..2555f5886af6 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -125,6 +125,11 @@ SECTIONS
*(.debug_frame)
__end_unwind = .;
}
+ /*
+ * gcc 4.8 generates this for -fasynchonous-unwind-tables,
+ * while we still use the .debug_frame based unwinder
+ */
+ /DISCARD/ : { *(.eh_frame) }
#else
/DISCARD/ : { *(.debug_frame) }
#endif
@@ -142,15 +147,18 @@ SECTIONS
*(.arcextmap.*)
}
+#ifndef CONFIG_DEBUG_INFO
/* open-coded because we need .debug_frame seperately for unwinding */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
+ /DISCARD/ : { *(.debug_aranges) }
+ /DISCARD/ : { *(.debug_pubnames) }
+ /DISCARD/ : { *(.debug_info) }
+ /DISCARD/ : { *(.debug_abbrev) }
+ /DISCARD/ : { *(.debug_line) }
+ /DISCARD/ : { *(.debug_str) }
+ /DISCARD/ : { *(.debug_loc) }
+ /DISCARD/ : { *(.debug_macinfo) }
+ /DISCARD/ : { *(.debug_ranges) }
+#endif
#ifdef CONFIG_ARC_HAS_DCCM
. = CONFIG_ARC_DCCM_BASE;
diff --git a/arch/arc/mm/cache_arc700.c b/arch/arc/mm/cache_arc700.c
index aedce1905441..f415d851b765 100644
--- a/arch/arc/mm/cache_arc700.c
+++ b/arch/arc/mm/cache_arc700.c
@@ -73,6 +73,33 @@
#include <asm/cachectl.h>
#include <asm/setup.h>
+/* Instruction cache related Auxiliary registers */
+#define ARC_REG_IC_BCR 0x77 /* Build Config reg */
+#define ARC_REG_IC_IVIC 0x10
+#define ARC_REG_IC_CTRL 0x11
+#define ARC_REG_IC_IVIL 0x19
+#if (CONFIG_ARC_MMU_VER > 2)
+#define ARC_REG_IC_PTAG 0x1E
+#endif
+
+/* Bit val in IC_CTRL */
+#define IC_CTRL_CACHE_DISABLE 0x1
+
+/* Data cache related Auxiliary registers */
+#define ARC_REG_DC_BCR 0x72 /* Build Config reg */
+#define ARC_REG_DC_IVDC 0x47
+#define ARC_REG_DC_CTRL 0x48
+#define ARC_REG_DC_IVDL 0x4A
+#define ARC_REG_DC_FLSH 0x4B
+#define ARC_REG_DC_FLDL 0x4C
+#if (CONFIG_ARC_MMU_VER > 2)
+#define ARC_REG_DC_PTAG 0x5C
+#endif
+
+/* Bit val in DC_CTRL */
+#define DC_CTRL_INV_MODE_FLUSH 0x40
+#define DC_CTRL_FLUSH_STATUS 0x100
+
char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
{
int n = 0;
@@ -89,8 +116,10 @@ char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
enb ? "" : "DISABLED (kernel-build)"); \
}
- PR_CACHE(&cpuinfo_arc700[c].icache, __CONFIG_ARC_HAS_ICACHE, "I-Cache");
- PR_CACHE(&cpuinfo_arc700[c].dcache, __CONFIG_ARC_HAS_DCACHE, "D-Cache");
+ PR_CACHE(&cpuinfo_arc700[c].icache, IS_ENABLED(CONFIG_ARC_HAS_ICACHE),
+ "I-Cache");
+ PR_CACHE(&cpuinfo_arc700[c].dcache, IS_ENABLED(CONFIG_ARC_HAS_DCACHE),
+ "D-Cache");
return buf;
}
@@ -100,17 +129,23 @@ char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
* the cpuinfo structure for later use.
* No Validation done here, simply read/convert the BCRs
*/
-void __cpuinit read_decode_cache_bcr(void)
+void read_decode_cache_bcr(void)
{
- struct bcr_cache ibcr, dbcr;
struct cpuinfo_arc_cache *p_ic, *p_dc;
unsigned int cpu = smp_processor_id();
+ struct bcr_cache {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int pad:12, line_len:4, sz:4, config:4, ver:8;
+#else
+ unsigned int ver:8, config:4, sz:4, line_len:4, pad:12;
+#endif
+ } ibcr, dbcr;
p_ic = &cpuinfo_arc700[cpu].icache;
READ_BCR(ARC_REG_IC_BCR, ibcr);
- if (ibcr.config == 0x3)
- p_ic->assoc = 2;
+ BUG_ON(ibcr.config != 3);
+ p_ic->assoc = 2; /* Fixed to 2w set assoc */
p_ic->line_len = 8 << ibcr.line_len;
p_ic->sz = 0x200 << ibcr.sz;
p_ic->ver = ibcr.ver;
@@ -118,8 +153,8 @@ void __cpuinit read_decode_cache_bcr(void)
p_dc = &cpuinfo_arc700[cpu].dcache;
READ_BCR(ARC_REG_DC_BCR, dbcr);
- if (dbcr.config == 0x2)
- p_dc->assoc = 4;
+ BUG_ON(dbcr.config != 2);
+ p_dc->assoc = 4; /* Fixed to 4w set assoc */
p_dc->line_len = 16 << dbcr.line_len;
p_dc->sz = 0x200 << dbcr.sz;
p_dc->ver = dbcr.ver;
@@ -132,14 +167,12 @@ void __cpuinit read_decode_cache_bcr(void)
* 3. Enable the Caches, setup default flush mode for D-Cache
* 3. Calculate the SHMLBA used by user space
*/
-void __cpuinit arc_cache_init(void)
+void arc_cache_init(void)
{
- unsigned int temp;
unsigned int cpu = smp_processor_id();
struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
struct cpuinfo_arc_cache *dc = &cpuinfo_arc700[cpu].dcache;
- int way_pg_ratio = way_pg_ratio;
- int dcache_does_alias;
+ unsigned int dcache_does_alias, temp;
char str[256];
printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
@@ -149,20 +182,11 @@ void __cpuinit arc_cache_init(void)
#ifdef CONFIG_ARC_HAS_ICACHE
/* 1. Confirm some of I-cache params which Linux assumes */
- if ((ic->assoc != ARC_ICACHE_WAYS) ||
- (ic->line_len != ARC_ICACHE_LINE_LEN)) {
+ if (ic->line_len != ARC_ICACHE_LINE_LEN)
panic("Cache H/W doesn't match kernel Config");
- }
-#if (CONFIG_ARC_MMU_VER > 2)
- if (ic->ver != 3) {
- if (running_on_hw)
- panic("Cache ver doesn't match MMU ver\n");
-
- /* For ISS - suggest the toggles to use */
- pr_err("Use -prop=icache_version=3,-prop=dcache_version=3\n");
- }
-#endif
+ if (ic->ver != CONFIG_ARC_MMU_VER)
+ panic("Cache ver doesn't match MMU ver\n");
#endif
/* Enable/disable I-Cache */
@@ -181,14 +205,12 @@ chk_dc:
return;
#ifdef CONFIG_ARC_HAS_DCACHE
- if ((dc->assoc != ARC_DCACHE_WAYS) ||
- (dc->line_len != ARC_DCACHE_LINE_LEN)) {
+ if (dc->line_len != ARC_DCACHE_LINE_LEN)
panic("Cache H/W doesn't match kernel Config");
- }
-
- dcache_does_alias = (dc->sz / ARC_DCACHE_WAYS) > PAGE_SIZE;
/* check for D-Cache aliasing */
+ dcache_does_alias = (dc->sz / dc->assoc) > PAGE_SIZE;
+
if (dcache_does_alias && !cache_is_vipt_aliasing())
panic("Enable CONFIG_ARC_CACHE_VIPT_ALIASING\n");
else if (!dcache_does_alias && cache_is_vipt_aliasing())
@@ -239,11 +261,9 @@ static inline void wait_for_flush(void)
*/
static inline void __dc_entire_op(const int cacheop)
{
- unsigned long flags, tmp = tmp;
+ unsigned int tmp = tmp;
int aux;
- local_irq_save(flags);
-
if (cacheop == OP_FLUSH_N_INV) {
/* Dcache provides 2 cmd: FLUSH or INV
* INV inturn has sub-modes: DISCARD or FLUSH-BEFORE
@@ -267,8 +287,6 @@ static inline void __dc_entire_op(const int cacheop)
/* Switch back the DISCARD ONLY Invalidate mode */
if (cacheop == OP_FLUSH_N_INV)
write_aux_reg(ARC_REG_DC_CTRL, tmp & ~DC_CTRL_INV_MODE_FLUSH);
-
- local_irq_restore(flags);
}
/*
@@ -459,8 +477,15 @@ static void __ic_line_inv_vaddr(unsigned long paddr, unsigned long vaddr,
local_irq_restore(flags);
}
+static inline void __ic_entire_inv(void)
+{
+ write_aux_reg(ARC_REG_IC_IVIC, 1);
+ read_aux_reg(ARC_REG_IC_CTRL); /* blocks */
+}
+
#else
+#define __ic_entire_inv()
#define __ic_line_inv_vaddr(pstart, vstart, sz)
#endif /* CONFIG_ARC_HAS_ICACHE */
@@ -487,7 +512,7 @@ void flush_dcache_page(struct page *page)
struct address_space *mapping;
if (!cache_is_vipt_aliasing()) {
- set_bit(PG_arch_1, &page->flags);
+ clear_bit(PG_dc_clean, &page->flags);
return;
}
@@ -501,7 +526,7 @@ void flush_dcache_page(struct page *page)
* Make a note that K-mapping is dirty
*/
if (!mapping_mapped(mapping)) {
- set_bit(PG_arch_1, &page->flags);
+ clear_bit(PG_dc_clean, &page->flags);
} else if (page_mapped(page)) {
/* kernel reading from page with U-mapping */
@@ -629,26 +654,13 @@ void ___flush_dcache_page(unsigned long paddr, unsigned long vaddr)
__dc_line_op(paddr, vaddr & PAGE_MASK, PAGE_SIZE, OP_FLUSH_N_INV);
}
-void flush_icache_all(void)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- write_aux_reg(ARC_REG_IC_IVIC, 1);
-
- /* lr will not complete till the icache inv operation is not over */
- read_aux_reg(ARC_REG_IC_CTRL);
- local_irq_restore(flags);
-}
-
noinline void flush_cache_all(void)
{
unsigned long flags;
local_irq_save(flags);
- flush_icache_all();
+ __ic_entire_inv();
__dc_entire_op(OP_FLUSH_N_INV);
local_irq_restore(flags);
@@ -667,7 +679,12 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long u_vaddr,
{
unsigned int paddr = pfn << PAGE_SHIFT;
- __sync_icache_dcache(paddr, u_vaddr, PAGE_SIZE);
+ u_vaddr &= PAGE_MASK;
+
+ ___flush_dcache_page(paddr, u_vaddr);
+
+ if (vma->vm_flags & VM_EXEC)
+ __inv_icache_page(paddr, u_vaddr);
}
void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
@@ -717,7 +734,7 @@ void copy_user_highpage(struct page *to, struct page *from,
* non copied user pages (e.g. read faults which wire in pagecache page
* directly).
*/
- set_bit(PG_arch_1, &to->flags);
+ clear_bit(PG_dc_clean, &to->flags);
/*
* if SRC was already usermapped and non-congruent to kernel mapping
@@ -725,15 +742,16 @@ void copy_user_highpage(struct page *to, struct page *from,
*/
if (clean_src_k_mappings) {
__flush_dcache_page(kfrom, kfrom);
+ set_bit(PG_dc_clean, &from->flags);
} else {
- set_bit(PG_arch_1, &from->flags);
+ clear_bit(PG_dc_clean, &from->flags);
}
}
void clear_user_page(void *to, unsigned long u_vaddr, struct page *page)
{
clear_page(to);
- set_bit(PG_arch_1, &page->flags);
+ clear_bit(PG_dc_clean, &page->flags);
}
diff --git a/arch/arc/mm/fault.c b/arch/arc/mm/fault.c
index 689ffd86d5e9..0fd1f0d515ff 100644
--- a/arch/arc/mm/fault.c
+++ b/arch/arc/mm/fault.c
@@ -15,6 +15,7 @@
#include <linux/uaccess.h>
#include <linux/kdebug.h>
#include <asm/pgalloc.h>
+#include <asm/mmu.h>
static int handle_vmalloc_fault(struct mm_struct *mm, unsigned long address)
{
@@ -51,14 +52,14 @@ bad_area:
return 1;
}
-void do_page_fault(struct pt_regs *regs, int write, unsigned long address,
- unsigned long cause_code)
+void do_page_fault(struct pt_regs *regs, unsigned long address)
{
struct vm_area_struct *vma = NULL;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
siginfo_t info;
int fault, ret;
+ int write = regs->ecr_cause & ECR_C_PROTV_STORE; /* ST/EX */
unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
(write ? FAULT_FLAG_WRITE : 0);
@@ -109,7 +110,8 @@ good_area:
/* Handle protection violation, execute on heap or stack */
- if (cause_code == ((ECR_V_PROTV << 16) | ECR_C_PROTV_INST_FETCH))
+ if ((regs->ecr_vec == ECR_V_PROTV) &&
+ (regs->ecr_cause == ECR_C_PROTV_INST_FETCH))
goto bad_area;
if (write) {
@@ -176,7 +178,6 @@ bad_area_nosemaphore:
/* User mode accesses just cause a SIGSEGV */
if (user_mode(regs)) {
tsk->thread.fault_address = address;
- tsk->thread.cause_code = cause_code;
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* info.si_code has been set above */
@@ -197,7 +198,7 @@ no_context:
if (fixup_exception(regs))
return;
- die("Oops", regs, address, cause_code);
+ die("Oops", regs, address);
out_of_memory:
if (is_global_init(tsk)) {
@@ -206,8 +207,10 @@ out_of_memory:
}
up_read(&mm->mmap_sem);
- if (user_mode(regs))
- do_group_exit(SIGKILL); /* This will never return */
+ if (user_mode(regs)) {
+ pagefault_out_of_memory();
+ return;
+ }
goto no_context;
@@ -218,7 +221,6 @@ do_sigbus:
goto no_context;
tsk->thread.fault_address = address;
- tsk->thread.cause_code = cause_code;
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c
index 4a177365b2c4..a08ce7185423 100644
--- a/arch/arc/mm/init.c
+++ b/arch/arc/mm/init.c
@@ -74,7 +74,7 @@ void __init setup_arch_memory(void)
/* Last usable page of low mem (no HIGHMEM yet for ARC port) */
max_low_pfn = max_pfn = PFN_DOWN(end_mem);
- max_mapnr = num_physpages = max_low_pfn - min_low_pfn;
+ max_mapnr = max_low_pfn - min_low_pfn;
/*------------- reserve kernel image -----------------------*/
memblock_reserve(CONFIG_LINUX_LINK_BASE,
@@ -84,7 +84,7 @@ void __init setup_arch_memory(void)
/*-------------- node setup --------------------------------*/
memset(zones_size, 0, sizeof(zones_size));
- zones_size[ZONE_NORMAL] = num_physpages;
+ zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
/*
* We can't use the helper free_area_init(zones[]) because it uses
@@ -106,39 +106,9 @@ void __init setup_arch_memory(void)
*/
void __init mem_init(void)
{
- int codesize, datasize, initsize, reserved_pages, free_pages;
- int tmp;
-
high_memory = (void *)(CONFIG_LINUX_LINK_BASE + arc_mem_sz);
-
- totalram_pages = free_all_bootmem();
-
- /* count all reserved pages [kernel code/data/mem_map..] */
- reserved_pages = 0;
- for (tmp = 0; tmp < max_mapnr; tmp++)
- if (PageReserved(mem_map + tmp))
- reserved_pages++;
-
- /* XXX: nr_free_pages() is equivalent */
- free_pages = max_mapnr - reserved_pages;
-
- /*
- * For the purpose of display below, split the "reserve mem"
- * kernel code/data is already shown explicitly,
- * Show any other reservations (mem_map[ ] et al)
- */
- reserved_pages -= (((unsigned int)_end - CONFIG_LINUX_LINK_BASE) >>
- PAGE_SHIFT);
-
- codesize = _etext - _text;
- datasize = _end - _etext;
- initsize = __init_end - __init_begin;
-
- pr_info("Memory Available: %dM / %ldM (%dK code, %dK data, %dK init, %dK reserv)\n",
- PAGES_TO_MB(free_pages),
- TO_MB(arc_mem_sz),
- TO_KB(codesize), TO_KB(datasize), TO_KB(initsize),
- PAGES_TO_KB(reserved_pages));
+ free_all_bootmem();
+ mem_init_print_info(NULL);
}
/*
@@ -146,13 +116,13 @@ void __init mem_init(void)
*/
void __init_refok free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
index fe1c5a073afe..7957dc4e4d4a 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -55,7 +55,7 @@
#include <asm/arcregs.h>
#include <asm/setup.h>
#include <asm/mmu_context.h>
-#include <asm/tlb.h>
+#include <asm/mmu.h>
/* Need for ARC MMU v2
*
@@ -97,6 +97,7 @@
* J-TLB entry got evicted/replaced.
*/
+
/* A copy of the ASID from the PID reg is kept in asid_cache */
int asid_cache = FIRST_ASID;
@@ -432,9 +433,14 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
{
unsigned long vaddr = vaddr_unaligned & PAGE_MASK;
unsigned long paddr = pte_val(*ptep) & PAGE_MASK;
+ struct page *page = pfn_to_page(pte_pfn(*ptep));
create_tlb(vma, vaddr, ptep);
+ if (page == ZERO_PAGE(0)) {
+ return;
+ }
+
/*
* Exec page : Independent of aliasing/page-color considerations,
* since icache doesn't snoop dcache on ARC, any dirty
@@ -446,9 +452,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
*/
if ((vma->vm_flags & VM_EXEC) ||
addr_not_cache_congruent(paddr, vaddr)) {
- struct page *page = pfn_to_page(pte_pfn(*ptep));
- int dirty = test_and_clear_bit(PG_arch_1, &page->flags);
+ int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
if (dirty) {
/* wback + inv dcache lines */
__flush_dcache_page(paddr, paddr);
@@ -464,12 +469,27 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
* the cpuinfo structure for later use.
* No Validation is done here, simply read/convert the BCRs
*/
-void __cpuinit read_decode_mmu_bcr(void)
+void read_decode_mmu_bcr(void)
{
- unsigned int tmp;
- struct bcr_mmu_1_2 *mmu2; /* encoded MMU2 attr */
- struct bcr_mmu_3 *mmu3; /* encoded MMU3 attr */
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
+ unsigned int tmp;
+ struct bcr_mmu_1_2 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int ver:8, ways:4, sets:4, u_itlb:8, u_dtlb:8;
+#else
+ unsigned int u_dtlb:8, u_itlb:8, sets:4, ways:4, ver:8;
+#endif
+ } *mmu2;
+
+ struct bcr_mmu_3 {
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ unsigned int ver:8, ways:4, sets:4, osm:1, reserv:3, pg_sz:4,
+ u_itlb:4, u_dtlb:4;
+#else
+ unsigned int u_dtlb:4, u_itlb:4, pg_sz:4, reserv:3, osm:1, sets:4,
+ ways:4, ver:8;
+#endif
+ } *mmu3;
tmp = read_aux_reg(ARC_REG_MMU_BCR);
mmu->ver = (tmp >> 24);
@@ -505,12 +525,12 @@ char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len)
"J-TLB %d (%dx%d), uDTLB %d, uITLB %d, %s\n",
p_mmu->num_tlb, p_mmu->sets, p_mmu->ways,
p_mmu->u_dtlb, p_mmu->u_itlb,
- __CONFIG_ARC_MMU_SASID_VAL ? "SASID" : "");
+ IS_ENABLED(CONFIG_ARC_MMU_SASID) ? "SASID" : "");
return buf;
}
-void __cpuinit arc_mmu_init(void)
+void arc_mmu_init(void)
{
char str[256];
struct cpuinfo_arc_mmu *mmu = &cpuinfo_arc700[smp_processor_id()].mmu;
diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S
index 3357d26ffe54..5c5bb23001b0 100644
--- a/arch/arc/mm/tlbex.S
+++ b/arch/arc/mm/tlbex.S
@@ -39,7 +39,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
-#include <asm/tlb.h>
+#include <asm/mmu.h>
#include <asm/pgtable.h>
#include <asm/arcregs.h>
#include <asm/cache.h>
@@ -147,9 +147,9 @@ ex_saved_reg1:
#ifdef CONFIG_ARC_DBG_TLB_MISS_COUNT
and.f 0, r0, _PAGE_PRESENT
bz 1f
- ld r2, [num_pte_not_present]
- add r2, r2, 1
- st r2, [num_pte_not_present]
+ ld r3, [num_pte_not_present]
+ add r3, r3, 1
+ st r3, [num_pte_not_present]
1:
#endif
@@ -271,22 +271,22 @@ ARC_ENTRY EV_TLBMissI
#endif
;----------------------------------------------------------------
- ; Get the PTE corresponding to V-addr accessed
+ ; Get the PTE corresponding to V-addr accessed, r2 is setup with EFA
LOAD_FAULT_PTE
;----------------------------------------------------------------
; VERIFY_PTE: Check if PTE permissions approp for executing code
cmp_s r2, VMALLOC_START
- mov.lo r2, (_PAGE_PRESENT | _PAGE_U_READ | _PAGE_U_EXECUTE)
- mov.hs r2, (_PAGE_PRESENT | _PAGE_K_READ | _PAGE_K_EXECUTE)
+ mov.lo r2, (_PAGE_PRESENT | _PAGE_U_EXECUTE)
+ mov.hs r2, (_PAGE_PRESENT | _PAGE_K_EXECUTE)
and r3, r0, r2 ; Mask out NON Flag bits from PTE
xor.f r3, r3, r2 ; check ( ( pte & flags_test ) == flags_test )
bnz do_slow_path_pf
; Let Linux VM know that the page was accessed
- or r0, r0, (_PAGE_PRESENT | _PAGE_ACCESSED) ; set Accessed Bit
- st_s r0, [r1] ; Write back PTE
+ or r0, r0, _PAGE_ACCESSED ; set Accessed Bit
+ st_s r0, [r1] ; Write back PTE
CONV_PTE_TO_TLB
COMMIT_ENTRY_TO_MMU
@@ -311,7 +311,7 @@ ARC_ENTRY EV_TLBMissD
;----------------------------------------------------------------
; Get the PTE corresponding to V-addr accessed
- ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE
+ ; If PTE exists, it will setup, r0 = PTE, r1 = Ptr to PTE, r2 = EFA
LOAD_FAULT_PTE
;----------------------------------------------------------------
@@ -345,7 +345,7 @@ ARC_ENTRY EV_TLBMissD
;----------------------------------------------------------------
; UPDATE_PTE: Let Linux VM know that page was accessed/dirty
lr r3, [ecr]
- or r0, r0, (_PAGE_PRESENT | _PAGE_ACCESSED) ; Accessed bit always
+ or r0, r0, _PAGE_ACCESSED ; Accessed bit always
btst_s r3, ECR_C_BIT_DTLB_ST_MISS ; See if it was a Write Access ?
or.nz r0, r0, _PAGE_MODIFIED ; if Write, set Dirty bit as well
st_s r0, [r1] ; Write back PTE
@@ -381,18 +381,7 @@ do_slow_path_pf:
; ------- setup args for Linux Page fault Hanlder ---------
mov_s r0, sp
- lr r2, [efa]
- lr r3, [ecr]
-
- ; Both st and ex imply WRITE access of some sort, hence do_page_fault( )
- ; invoked with write=1 for DTLB-st/ex Miss and write=0 for ITLB miss or
- ; DTLB-ld Miss
- ; DTLB Miss Cause code is ld = 0x01 , st = 0x02, ex = 0x03
- ; Following code uses that fact that st/ex have one bit in common
-
- btst_s r3, ECR_C_BIT_DTLB_ST_MISS
- mov.z r1, 0
- mov.nz r1, 1
+ lr r1, [efa]
; We don't want exceptions to be disabled while the fault is handled.
; Now that we have saved the context we return from exception hence
diff --git a/arch/arc/plat-arcfpga/include/plat/irq.h b/arch/arc/plat-arcfpga/include/plat/irq.h
index 41e335670f60..6adbc53c3a5b 100644
--- a/arch/arc/plat-arcfpga/include/plat/irq.h
+++ b/arch/arc/plat-arcfpga/include/plat/irq.h
@@ -16,8 +16,6 @@
#define UART1_IRQ 10
#define UART2_IRQ 11
-#define VMAC_IRQ 6
-
#define IDE_IRQ 13
#define PCI_IRQ 14
#define PS2_IRQ 15
diff --git a/arch/arc/plat-arcfpga/include/plat/memmap.h b/arch/arc/plat-arcfpga/include/plat/memmap.h
index 1663f3388085..5c78e6135a1f 100644
--- a/arch/arc/plat-arcfpga/include/plat/memmap.h
+++ b/arch/arc/plat-arcfpga/include/plat/memmap.h
@@ -15,8 +15,6 @@
#define UART0_BASE 0xC0FC1000
#define UART1_BASE 0xC0FC1100
-#define VMAC_REG_BASEADDR 0xC0FC2000
-
#define IDE_CONTROLLER_BASE 0xC0FC9000
#define AHB_PCI_HOST_BRG_BASE 0xC0FD0000
diff --git a/arch/arc/plat-arcfpga/platform.c b/arch/arc/plat-arcfpga/platform.c
index b3700c064c06..d71f3c3bcf24 100644
--- a/arch/arc/plat-arcfpga/platform.c
+++ b/arch/arc/plat-arcfpga/platform.c
@@ -77,6 +77,7 @@ static void __init setup_bvci_lat_unit(void)
/*----------------------- Platform Devices -----------------------------*/
+#if IS_ENABLED(CONFIG_SERIAL_ARC)
static unsigned long arc_uart_info[] = {
0, /* uart->is_emulated (runtime @running_on_hw) */
0, /* uart->port.uartclk */
@@ -115,7 +116,7 @@ static struct platform_device arc_uart0_dev = {
static struct platform_device *fpga_early_devs[] __initdata = {
&arc_uart0_dev,
};
-#endif
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
static void arc_fpga_serial_init(void)
{
@@ -152,8 +153,13 @@ static void arc_fpga_serial_init(void)
* otherwise the early console never gets a chance to run.
*/
add_preferred_console("ttyARC", 0, "115200");
-#endif
+#endif /* CONFIG_SERIAL_ARC_CONSOLE */
+}
+#else /* !IS_ENABLED(CONFIG_SERIAL_ARC) */
+static void arc_fpga_serial_init(void)
+{
}
+#endif
static void __init plat_fpga_early_init(void)
{
@@ -169,7 +175,7 @@ static void __init plat_fpga_early_init(void)
}
static struct of_dev_auxdata plat_auxdata_lookup[] __initdata = {
-#if defined(CONFIG_SERIAL_ARC) || defined(CONFIG_SERIAL_ARC_MODULE)
+#if IS_ENABLED(CONFIG_SERIAL_ARC)
OF_DEV_AUXDATA("snps,arc-uart", UART0_BASE, "arc-uart", arc_uart_info),
#endif
{}
diff --git a/arch/arc/plat-tb10x/Kconfig b/arch/arc/plat-tb10x/Kconfig
index 1d3452100f1f..1ab386bb5da8 100644
--- a/arch/arc/plat-tb10x/Kconfig
+++ b/arch/arc/plat-tb10x/Kconfig
@@ -22,6 +22,7 @@ menuconfig ARC_PLAT_TB10X
select PINCTRL
select PINMUX
select ARCH_REQUIRE_GPIOLIB
+ select TB10X_IRQC
help
Support for platforms based on the TB10x home media gateway SOC by
Abilis Systems. TB10x is based on the ARC700 CPU architecture.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index de7049bdea85..0ac9be677ebb 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -14,6 +14,7 @@ config ARM
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
+ select GENERIC_SCHED_CLOCK
select GENERIC_SMP_IDLE_THREAD
select GENERIC_IDLE_POLL_SETUP
select GENERIC_STRNCPY_FROM_USER
@@ -40,6 +41,7 @@ config ARM
select HAVE_IDE if PCI || ISA || PCMCIA
select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZ4
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_LZO
select HAVE_KERNEL_XZ
@@ -175,6 +177,9 @@ config ARCH_HAS_CPUFREQ
and that the relevant menu configurations are displayed for
it.
+config ARCH_HAS_BANDGAP
+ bool
+
config GENERIC_HWEIGHT
bool
default y
@@ -1450,7 +1455,7 @@ config SMP
depends on CPU_V6K || CPU_V7
depends on GENERIC_CLOCKEVENTS
depends on HAVE_SMP
- depends on MMU
+ depends on MMU || ARM_MPU
select USE_GENERIC_SMP_HELPERS
help
This enables support for systems with more than one CPU. If you have
@@ -1471,7 +1476,7 @@ config SMP
config SMP_ON_UP
bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
- depends on SMP && !XIP_KERNEL
+ depends on SMP && !XIP_KERNEL && MMU
default y
help
SMP kernels contain instructions which fail on non-SMP processors.
@@ -1744,6 +1749,14 @@ config HW_PERF_EVENTS
Enable hardware performance counter support for perf events. If
disabled, perf events will use software events only.
+config SYS_SUPPORTS_HUGETLBFS
+ def_bool y
+ depends on ARM_LPAE
+
+config HAVE_ARCH_TRANSPARENT_HUGEPAGE
+ def_bool y
+ depends on ARM_LPAE
+
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index c859495da480..aed66d5df7f1 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -50,3 +50,15 @@ config REMAP_VECTORS_TO_RAM
Otherwise, say 'y' here. In this case, the kernel will require
external support to redirect the hardware exception vectors to
the writable versions located at DRAM_BASE.
+
+config ARM_MPU
+ bool 'Use the ARM v7 PMSA Compliant MPU'
+ depends on CPU_V7
+ default y
+ help
+ Some ARM systems without an MMU have instead a Memory Protection
+ Unit (MPU) that defines the type and permissions for regions of
+ memory.
+
+ If your CPU has an MPU then you should choose 'y' here unless you
+ know that you do not want to use the MPU.
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 77c1411c9a91..5b7be8d975b5 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -550,6 +550,13 @@ choice
of the tiles using the RS1 memory map, including all new A-class
core tiles, FPGA-based SMMs and software models.
+ config DEBUG_VEXPRESS_UART0_CRX
+ bool "Use PL011 UART0 at 0xb0090000 (Cortex-R compliant tiles)"
+ depends on ARCH_VEXPRESS && !MMU
+ help
+ This option selects UART0 at 0xb0090000. This is appropriate for
+ Cortex-R series tiles and SMMs, such as Cortex-R5 and Cortex-R7
+
config DEBUG_VT8500_UART0
bool "Use UART0 on VIA/Wondermedia SoCs"
depends on ARCH_VT8500
@@ -789,7 +796,8 @@ config DEBUG_LL_INCLUDE
default "debug/u300.S" if DEBUG_U300_UART
default "debug/ux500.S" if DEBUG_UX500_UART
default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT || \
- DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1
+ DEBUG_VEXPRESS_UART0_CA9 || DEBUG_VEXPRESS_UART0_RS1 || \
+ DEBUG_VEXPRESS_UART0_CRX
default "debug/vt8500.S" if DEBUG_VT8500_UART0
default "debug/zynq.S" if DEBUG_ZYNQ_UART0 || DEBUG_ZYNQ_UART1
default "mach/debug-macro.S"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 72caf82a8280..c0ac0f5e5e5c 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -59,38 +59,44 @@ comma = ,
# Note that GCC does not numerically define an architecture version
# macro, but instead defines a whole series of macros which makes
# testing for a specific architecture or later rather impossible.
-arch-$(CONFIG_CPU_32v7M) :=-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
-arch-$(CONFIG_CPU_32v7) :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
-arch-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+arch-$(CONFIG_CPU_32v7M) =-D__LINUX_ARM_ARCH__=7 -march=armv7-m -Wa,-march=armv7-m
+arch-$(CONFIG_CPU_32v7) =-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7-a,-march=armv5t -Wa$(comma)-march=armv7-a)
+arch-$(CONFIG_CPU_32v6) =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
# Only override the compiler option if ARMv6. The ARMv6K extensions are
# always available in ARMv7
ifeq ($(CONFIG_CPU_32v6),y)
-arch-$(CONFIG_CPU_32v6K) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+arch-$(CONFIG_CPU_32v6K) =-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
endif
-arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
-arch-$(CONFIG_CPU_32v4T) :=-D__LINUX_ARM_ARCH__=4 -march=armv4t
-arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4
-arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3
+arch-$(CONFIG_CPU_32v5) =-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
+arch-$(CONFIG_CPU_32v4T) =-D__LINUX_ARM_ARCH__=4 -march=armv4t
+arch-$(CONFIG_CPU_32v4) =-D__LINUX_ARM_ARCH__=4 -march=armv4
+arch-$(CONFIG_CPU_32v3) =-D__LINUX_ARM_ARCH__=3 -march=armv3
+
+# Evaluate arch cc-option calls now
+arch-y := $(arch-y)
# This selects how we optimise for the processor.
-tune-$(CONFIG_CPU_ARM7TDMI) :=-mtune=arm7tdmi
-tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi
-tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi
-tune-$(CONFIG_CPU_ARM9TDMI) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM946E) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
-tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_FA526) :=-mtune=arm9tdmi
-tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110
-tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100
-tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_XSC3) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
-tune-$(CONFIG_CPU_FEROCEON) :=$(call cc-option,-mtune=marvell-f,-mtune=xscale)
-tune-$(CONFIG_CPU_V6) :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
-tune-$(CONFIG_CPU_V6K) :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_ARM7TDMI) =-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM720T) =-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM740T) =-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM9TDMI) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM940T) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM946E) =$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
+tune-$(CONFIG_CPU_ARM920T) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM922T) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM925T) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM926T) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_FA526) =-mtune=arm9tdmi
+tune-$(CONFIG_CPU_SA110) =-mtune=strongarm110
+tune-$(CONFIG_CPU_SA1100) =-mtune=strongarm1100
+tune-$(CONFIG_CPU_XSCALE) =$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+tune-$(CONFIG_CPU_XSC3) =$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale
+tune-$(CONFIG_CPU_FEROCEON) =$(call cc-option,-mtune=marvell-f,-mtune=xscale)
+tune-$(CONFIG_CPU_V6) =$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+tune-$(CONFIG_CPU_V6K) =$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
+
+# Evaluate tune cc-option calls now
+tune-y := $(tune-y)
ifeq ($(CONFIG_AEABI),y)
CFLAGS_ABI :=-mabi=aapcs-linux -mno-thumb-interwork
@@ -295,9 +301,10 @@ zImage Image xipImage bootpImage uImage: vmlinux
zinstall uinstall install: vmlinux
$(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) $@
-%.dtb: scripts
+%.dtb: | scripts
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
+PHONY += dtbs
dtbs: scripts
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) dtbs
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index f79a08efe000..47279aa96a6a 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -6,6 +6,7 @@ piggy.gzip
piggy.lzo
piggy.lzma
piggy.xzkern
+piggy.lz4
vmlinux
vmlinux.lds
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 120b83bfde20..7ac1610252ba 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -27,7 +27,7 @@ OBJS += misc.o decompress.o
ifeq ($(CONFIG_DEBUG_UNCOMPRESS),y)
OBJS += debug.o
endif
-FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c
+FONTC = $(srctree)/lib/fonts/font_acorn_8x8.c
# string library code (-Os is enforced to keep it much smaller)
OBJS += string.o
@@ -91,6 +91,7 @@ suffix_$(CONFIG_KERNEL_GZIP) = gzip
suffix_$(CONFIG_KERNEL_LZO) = lzo
suffix_$(CONFIG_KERNEL_LZMA) = lzma
suffix_$(CONFIG_KERNEL_XZ) = xzkern
+suffix_$(CONFIG_KERNEL_LZ4) = lz4
# Borrowed libfdt files for the ATAG compatibility mode
@@ -115,7 +116,7 @@ targets := vmlinux vmlinux.lds \
font.o font.c head.o misc.o $(OBJS)
# Make sure files are removed during clean
-extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern \
+extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern piggy.lz4 \
lib1funcs.S ashldi3.S $(libfdt) $(libfdt_hdrs) \
hyp-stub.S
diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c
index aabc02a68482..d1153c8a765a 100644
--- a/arch/arm/boot/compressed/atags_to_fdt.c
+++ b/arch/arm/boot/compressed/atags_to_fdt.c
@@ -53,6 +53,17 @@ static const void *getprop(const void *fdt, const char *node_path,
return fdt_getprop(fdt, offset, property, len);
}
+static uint32_t get_cell_size(const void *fdt)
+{
+ int len;
+ uint32_t cell_size = 1;
+ const uint32_t *size_len = getprop(fdt, "/", "#size-cells", &len);
+
+ if (size_len)
+ cell_size = fdt32_to_cpu(*size_len);
+ return cell_size;
+}
+
static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
{
char cmdline[COMMAND_LINE_SIZE];
@@ -95,9 +106,11 @@ static void merge_fdt_bootargs(void *fdt, const char *fdt_cmdline)
int atags_to_fdt(void *atag_list, void *fdt, int total_space)
{
struct tag *atag = atag_list;
- uint32_t mem_reg_property[2 * NR_BANKS];
+ /* In the case of 64 bits memory size, need to reserve 2 cells for
+ * address and size for each bank */
+ uint32_t mem_reg_property[2 * 2 * NR_BANKS];
int memcount = 0;
- int ret;
+ int ret, memsize;
/* make sure we've got an aligned pointer */
if ((u32)atag_list & 0x3)
@@ -137,8 +150,25 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
continue;
if (!atag->u.mem.size)
continue;
- mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
- mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
+ memsize = get_cell_size(fdt);
+
+ if (memsize == 2) {
+ /* if memsize is 2, that means that
+ * each data needs 2 cells of 32 bits,
+ * so the data are 64 bits */
+ uint64_t *mem_reg_prop64 =
+ (uint64_t *)mem_reg_property;
+ mem_reg_prop64[memcount++] =
+ cpu_to_fdt64(atag->u.mem.start);
+ mem_reg_prop64[memcount++] =
+ cpu_to_fdt64(atag->u.mem.size);
+ } else {
+ mem_reg_property[memcount++] =
+ cpu_to_fdt32(atag->u.mem.start);
+ mem_reg_property[memcount++] =
+ cpu_to_fdt32(atag->u.mem.size);
+ }
+
} else if (atag->hdr.tag == ATAG_INITRD2) {
uint32_t initrd_start, initrd_size;
initrd_start = atag->u.initrd.start;
@@ -150,8 +180,10 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)
}
}
- if (memcount)
- setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
+ if (memcount) {
+ setprop(fdt, "/memory", "reg", mem_reg_property,
+ 4 * memcount * memsize);
+ }
return fdt_pack(fdt);
}
diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
index 24b0475cb8bf..bd245d34952d 100644
--- a/arch/arm/boot/compressed/decompress.c
+++ b/arch/arm/boot/compressed/decompress.c
@@ -51,6 +51,10 @@ extern char * strstr(const char * s1, const char *s2);
#include "../../../../lib/decompress_unxz.c"
#endif
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
{
return decompress(input, len, NULL, NULL, output, NULL, error);
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 032a8d987148..75189f13cf54 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -142,7 +142,6 @@ start:
mov r7, r1 @ save architecture ID
mov r8, r2 @ save atags pointer
-#ifndef __ARM_ARCH_2__
/*
* Booting from Angel - need to enter SVC mode and disable
* FIQs/IRQs (numeric definitions from angel arm.h source).
@@ -158,10 +157,6 @@ not_angel:
safe_svcmode_maskall r0
msr spsr_cxsf, r9 @ Save the CPU boot mode in
@ SPSR
-#else
- teqp pc, #0x0c000003 @ turn off interrupts
-#endif
-
/*
* Note that some cache flushing and other stuff may
* be needed here - is there an Angel SWI call for this?
@@ -183,7 +178,19 @@ not_angel:
ldr r4, =zreladdr
#endif
- bl cache_on
+ /*
+ * Set up a page table only if it won't overwrite ourself.
+ * That means r4 < pc && r4 - 16k page directory > &_end.
+ * Given that r4 > &_end is most unfrequent, we add a rough
+ * additional 1MB of room for a possible appended DTB.
+ */
+ mov r0, pc
+ cmp r0, r4
+ ldrcc r0, LC0+32
+ addcc r0, r0, pc
+ cmpcc r4, r0
+ orrcc r4, r4, #1 @ remember we skipped cache_on
+ blcs cache_on
restart: adr r0, LC0
ldmia r0, {r1, r2, r3, r6, r10, r11, r12}
@@ -229,7 +236,7 @@ restart: adr r0, LC0
* r0 = delta
* r2 = BSS start
* r3 = BSS end
- * r4 = final kernel address
+ * r4 = final kernel address (possibly with LSB set)
* r5 = appended dtb size (still unknown)
* r6 = _edata
* r7 = architecture ID
@@ -277,6 +284,7 @@ restart: adr r0, LC0
*/
cmp r0, #1
sub r0, r4, #TEXT_OFFSET
+ bic r0, r0, #1
add r0, r0, #0x100
mov r1, r6
sub r2, sp, r6
@@ -323,12 +331,13 @@ dtb_check_done:
/*
* Check to see if we will overwrite ourselves.
- * r4 = final kernel address
+ * r4 = final kernel address (possibly with LSB set)
* r9 = size of decompressed image
* r10 = end of this image, including bss/stack/malloc space if non XIP
* We basically want:
* r4 - 16k page directory >= r10 -> OK
* r4 + image length <= address of wont_overwrite -> OK
+ * Note: the possible LSB in r4 is harmless here.
*/
add r10, r10, #16384
cmp r4, r10
@@ -390,7 +399,8 @@ dtb_check_done:
add sp, sp, r6
#endif
- bl cache_clean_flush
+ tst r4, #1
+ bleq cache_clean_flush
adr r0, BSYM(restart)
add r0, r0, r6
@@ -402,7 +412,7 @@ wont_overwrite:
* r0 = delta
* r2 = BSS start
* r3 = BSS end
- * r4 = kernel execution address
+ * r4 = kernel execution address (possibly with LSB set)
* r5 = appended dtb size (0 if not present)
* r7 = architecture ID
* r8 = atags pointer
@@ -465,6 +475,15 @@ not_relocated: mov r0, #0
cmp r2, r3
blo 1b
+ /*
+ * Did we skip the cache setup earlier?
+ * That is indicated by the LSB in r4.
+ * Do it now if so.
+ */
+ tst r4, #1
+ bic r4, r4, #1
+ blne cache_on
+
/*
* The C runtime environment should now be setup sufficiently.
* Set up some pointers, and start decompressing.
@@ -513,6 +532,7 @@ LC0: .word LC0 @ r1
.word _got_start @ r11
.word _got_end @ ip
.word .L_user_stack_end @ sp
+ .word _end - restart + 16384 + 1024*1024
.size LC0, . - LC0
#ifdef CONFIG_ARCH_RPC
diff --git a/arch/arm/boot/compressed/piggy.lz4.S b/arch/arm/boot/compressed/piggy.lz4.S
new file mode 100644
index 000000000000..3d9a575618a3
--- /dev/null
+++ b/arch/arm/boot/compressed/piggy.lz4.S
@@ -0,0 +1,6 @@
+ .section .piggydata,#alloc
+ .globl input_data
+input_data:
+ .incbin "arch/arm/boot/compressed/piggy.lz4"
+ .globl input_data_end
+input_data_end:
diff --git a/arch/arm/boot/dts/am335x-bone.dts b/arch/arm/boot/dts/am335x-bone.dts
index 04feaf8f1420..444b4ede0d60 100644
--- a/arch/arm/boot/dts/am335x-bone.dts
+++ b/arch/arm/boot/dts/am335x-bone.dts
@@ -214,10 +214,12 @@
&cpsw_emac0 {
phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "mii";
};
&cpsw_emac1 {
phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "mii";
};
&mac {
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index a16bb9691cc6..3aee1a43782d 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -467,8 +467,24 @@
&cpsw_emac0 {
phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii-txid";
};
&cpsw_emac1 {
phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii-txid";
+};
+
+&tscadc {
+ status = "okay";
+ tsc {
+ ti,wires = <4>;
+ ti,x-plate-resistance = <200>;
+ ti,coordiante-readouts = <5>;
+ ti,wire-config = <0x00 0x11 0x22 0x33>;
+ };
+
+ adc {
+ ti,adc-channels = <4 5 6 7>;
+ };
};
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 9e00eef9b74b..0c8ad173d2b0 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -392,3 +392,13 @@
pinctrl-0 = <&davinci_mdio_default>;
pinctrl-1 = <&davinci_mdio_sleep>;
};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <0>;
+ phy-mode = "rgmii-txid";
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <1>;
+ phy-mode = "rgmii-txid";
+};
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 0d4df90477f7..38b446ba1ce1 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -502,6 +502,23 @@
status = "disabled";
};
+ tscadc: tscadc@44e0d000 {
+ compatible = "ti,am3359-tscadc";
+ reg = <0x44e0d000 0x1000>;
+ interrupt-parent = <&intc>;
+ interrupts = <16>;
+ ti,hwmods = "adc_tsc";
+ status = "disabled";
+
+ tsc {
+ compatible = "ti,am3359-tsc";
+ };
+ am335x_adc: adc {
+ #io-channel-cells = <1>;
+ compatible = "ti,am3359-adc";
+ };
+ };
+
gpmc: gpmc@50000000 {
compatible = "ti,am3352-gpmc";
ti,hwmods = "gpmc";
diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
index 7d1a27949c13..9866cd736dee 100644
--- a/arch/arm/boot/dts/atlas6.dtsi
+++ b/arch/arm/boot/dts/atlas6.dtsi
@@ -613,7 +613,7 @@
};
rtc-iobg {
- compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus";
+ compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x80030000 0x10000>;
diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi
index 17979d5f23b4..c0cdf66f8964 100644
--- a/arch/arm/boot/dts/bcm11351.dtsi
+++ b/arch/arm/boot/dts/bcm11351.dtsi
@@ -50,10 +50,10 @@
};
L2: l2-cache {
- compatible = "arm,pl310-cache";
- reg = <0x3ff20000 0x1000>;
- cache-unified;
- cache-level = <2>;
+ compatible = "bcm,bcm11351-a2-pl310-cache";
+ reg = <0x3ff20000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
};
timer@35006000 {
diff --git a/arch/arm/boot/dts/cros5250-common.dtsi b/arch/arm/boot/dts/cros5250-common.dtsi
index 3f0239ec1bc5..dc259e8b8a73 100644
--- a/arch/arm/boot/dts/cros5250-common.dtsi
+++ b/arch/arm/boot/dts/cros5250-common.dtsi
@@ -190,7 +190,7 @@
samsung,i2c-max-bus-freq = <66000>;
hdmiddc@50 {
- compatible = "samsung,exynos5-hdmiddc";
+ compatible = "samsung,exynos4210-hdmiddc";
reg = <0x50>;
};
};
@@ -224,7 +224,7 @@
samsung,i2c-max-bus-freq = <378000>;
hdmiphy@38 {
- compatible = "samsung,exynos5-hdmiphy";
+ compatible = "samsung,exynos4212-hdmiphy";
reg = <0x38>;
};
};
diff --git a/arch/arm/boot/dts/ecx-common.dtsi b/arch/arm/boot/dts/ecx-common.dtsi
index d61b535f682a..e8559b753c9d 100644
--- a/arch/arm/boot/dts/ecx-common.dtsi
+++ b/arch/arm/boot/dts/ecx-common.dtsi
@@ -33,6 +33,8 @@
calxeda,port-phys = <&combophy5 0 &combophy0 0
&combophy0 1 &combophy0 2
&combophy0 3>;
+ calxeda,sgpio-gpio =<&gpioh 5 1 &gpioh 6 1 &gpioh 7 1>;
+ calxeda,led-order = <4 0 1 2 3>;
};
sdhci@ffe0e000 {
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 35a66dee4011..49f18c24a576 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -105,7 +105,7 @@
samsung,i2c-max-bus-freq = <66000>;
hdmiddc@50 {
- compatible = "samsung,exynos5-hdmiddc";
+ compatible = "samsung,exynos4210-hdmiddc";
reg = <0x50>;
};
};
@@ -135,7 +135,7 @@
samsung,i2c-max-bus-freq = <66000>;
hdmiphy@38 {
- compatible = "samsung,exynos5-hdmiphy";
+ compatible = "samsung,exynos4212-hdmiphy";
reg = <0x38>;
};
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 41cd625b6020..ef57277fc38f 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -599,7 +599,7 @@
};
hdmi {
- compatible = "samsung,exynos5-hdmi";
+ compatible = "samsung,exynos4212-hdmi";
reg = <0x14530000 0x70000>;
interrupts = <0 95 0>;
clocks = <&clock 333>, <&clock 136>, <&clock 137>,
@@ -609,7 +609,7 @@
};
mixer {
- compatible = "samsung,exynos5-mixer";
+ compatible = "samsung,exynos5250-mixer";
reg = <0x14450000 0x10000>;
interrupts = <0 94 0>;
};
diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts
index 3637bf3b1d59..1f0d38d7b16f 100644
--- a/arch/arm/boot/dts/imx28-evk.dts
+++ b/arch/arm/boot/dts/imx28-evk.dts
@@ -155,12 +155,14 @@
can0: can@80032000 {
pinctrl-names = "default";
pinctrl-0 = <&can0_pins_a>;
+ xceiver-supply = <&reg_can_3v3>;
status = "okay";
};
can1: can@80034000 {
pinctrl-names = "default";
pinctrl-0 = <&can1_pins_a>;
+ xceiver-supply = <&reg_can_3v3>;
status = "okay";
};
};
@@ -319,6 +321,16 @@
gpio = <&gpio3 30 0>;
enable-active-high;
};
+
+ reg_can_3v3: can-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "can-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 13 0>;
+ enable-active-high;
+ };
+
};
sound {
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 195451bf7706..6a8acb01b1d3 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -736,7 +736,7 @@
dcp@80028000 {
reg = <0x80028000 0x2000>;
interrupts = <52 53 54>;
- status = "disabled";
+ compatible = "fsl-dcp";
};
pxp@8002a000 {
diff --git a/arch/arm/boot/dts/omap3-devkit8000.dts b/arch/arm/boot/dts/omap3-devkit8000.dts
index af32eff9f4b7..7ef282795dd4 100644
--- a/arch/arm/boot/dts/omap3-devkit8000.dts
+++ b/arch/arm/boot/dts/omap3-devkit8000.dts
@@ -124,20 +124,21 @@
reg = <0 0 0>; /* CS0, offset 0 */
nand-bus-width = <16>;
- gpmc,sync-clk = <0>;
- gpmc,cs-on = <0>;
- gpmc,cs-rd-off = <44>;
- gpmc,cs-wr-off = <44>;
- gpmc,adv-on = <6>;
- gpmc,adv-rd-off = <34>;
- gpmc,adv-wr-off = <44>;
- gpmc,we-off = <40>;
- gpmc,oe-off = <54>;
- gpmc,access = <64>;
- gpmc,rd-cycle = <82>;
- gpmc,wr-cycle = <82>;
- gpmc,wr-access = <40>;
- gpmc,wr-data-mux-bus = <0>;
+ gpmc,device-nand;
+ gpmc,sync-clki-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>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 02edd8965f8a..05e9489cf95c 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -610,7 +610,7 @@
};
rtc-iobg {
- compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus";
+ compatible = "sirf,prima2-rtciobg", "sirf-prima2-rtciobg-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x80030000 0x10000>;
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 0e22a285dfe0..757c4cd900ee 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -27,6 +27,21 @@
};
soc@01c20000 {
+ 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>;
+ };
+ };
+
pinctrl@01c20800 {
led_pins_cubieboard: led_pins@0 {
allwinner,pins = "PH20", "PH21";
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index b9efac100c85..3514b37d66bc 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -23,10 +23,51 @@
};
soc@01c20000 {
+ 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>;
+ };
+ };
+
+ pio: pinctrl@01c20800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hackberry_hogs>;
+
+ hackberry_hogs: hogs@0 {
+ allwinner,pins = "PH19";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
uart0: serial@01c28000 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
};
+
+ regulators {
+ compatible = "simple-bus";
+
+ reg_emac_3v3: emac-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "emac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 7 19 0>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 82e03d22f913..b2bd6e124250 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -167,6 +167,22 @@
reg = <0x01c20000 0x300000>;
ranges;
+ emac: ethernet@01c0b000 {
+ compatible = "allwinner,sun4i-emac";
+ reg = <0x01c0b000 0x1000>;
+ interrupts = <55>;
+ clocks = <&ahb_gates 17>;
+ status = "disabled";
+ };
+
+ mdio@01c0b080 {
+ compatible = "allwinner,sun4i-mdio";
+ reg = <0x01c0b080 0x14>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
intc: interrupt-controller@01c20400 {
compatible = "allwinner,sun4i-ic";
reg = <0x01c20400 0x400>;
@@ -226,6 +242,17 @@
allwinner,drive = <0>;
allwinner,pull = <0>;
};
+
+ 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 = <0>;
+ allwinner,pull = <0>;
+ };
};
timer@01c20c00 {
diff --git a/arch/arm/common/mcpm_head.S b/arch/arm/common/mcpm_head.S
index 8178705c4b24..80f033614a1f 100644
--- a/arch/arm/common/mcpm_head.S
+++ b/arch/arm/common/mcpm_head.S
@@ -32,11 +32,11 @@
1901: adr r0, 1902b
bl printascii
mov r0, r9
- bl printhex8
+ bl printhex2
adr r0, 1903b
bl printascii
mov r0, r10
- bl printhex8
+ bl printhex2
adr r0, 1904b
bl printascii
#endif
diff --git a/arch/arm/common/mcpm_platsmp.c b/arch/arm/common/mcpm_platsmp.c
index 3caed0db6986..510e5b13aa2e 100644
--- a/arch/arm/common/mcpm_platsmp.c
+++ b/arch/arm/common/mcpm_platsmp.c
@@ -19,10 +19,6 @@
#include <asm/smp.h>
#include <asm/smp_plat.h>
-static void __init simple_smp_init_cpus(void)
-{
-}
-
static int __cpuinit mcpm_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
unsigned int mpidr, pcpu, pcluster, ret;
@@ -74,7 +70,6 @@ static void mcpm_cpu_die(unsigned int cpu)
#endif
static struct smp_operations __initdata mcpm_smp_ops = {
- .smp_init_cpus = simple_smp_init_cpus,
.smp_boot_secondary = mcpm_boot_secondary,
.smp_secondary_init = mcpm_secondary_init,
#ifdef CONFIG_HOTPLUG_CPU
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index ddc740769601..023ee63827a2 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -28,8 +28,8 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/timer-sp.h>
diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig
index e3bf2d65618e..65edf6d47215 100644
--- a/arch/arm/configs/bcm_defconfig
+++ b/arch/arm/configs/bcm_defconfig
@@ -78,6 +78,13 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_BCM_KONA=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 2ac0ffb12f03..a24c02443920 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -286,3 +286,4 @@ CONFIG_SOC_OMAP5=y
CONFIG_TI_DAVINCI_MDIO=y
CONFIG_TI_DAVINCI_CPDMA=y
CONFIG_TI_CPSW=y
+CONFIG_AT803X_PHY=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 7c1bfc0aea0c..accefe099182 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -80,15 +80,6 @@ static inline u32 arch_timer_get_cntfrq(void)
return val;
}
-static inline u64 arch_counter_get_cntpct(void)
-{
- u64 cval;
-
- isb();
- asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (cval));
- return cval;
-}
-
static inline u64 arch_counter_get_cntvct(void)
{
u64 cval;
diff --git a/arch/arm/include/asm/cp15.h b/arch/arm/include/asm/cp15.h
index cedd3721318b..6493802f880a 100644
--- a/arch/arm/include/asm/cp15.h
+++ b/arch/arm/include/asm/cp15.h
@@ -23,6 +23,11 @@
#define CR_RR (1 << 14) /* Round Robin cache replacement */
#define CR_L4 (1 << 15) /* LDR pc can set T bit */
#define CR_DT (1 << 16)
+#ifdef CONFIG_MMU
+#define CR_HA (1 << 17) /* Hardware management of Access Flag */
+#else
+#define CR_BR (1 << 17) /* MPU Background region enable (PMSA) */
+#endif
#define CR_IT (1 << 18)
#define CR_ST (1 << 19)
#define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index d7deb62554c9..8c25dc4e9851 100644
--- a/arch/arm/include/asm/cputype.h
+++ b/arch/arm/include/asm/cputype.h
@@ -8,6 +8,7 @@
#define CPUID_CACHETYPE 1
#define CPUID_TCM 2
#define CPUID_TLBTYPE 3
+#define CPUID_MPUIR 4
#define CPUID_MPIDR 5
#ifdef CONFIG_CPU_V7M
diff --git a/arch/arm/include/asm/div64.h b/arch/arm/include/asm/div64.h
index fe92ccf1d0b0..191ada6e4d2d 100644
--- a/arch/arm/include/asm/div64.h
+++ b/arch/arm/include/asm/div64.h
@@ -46,7 +46,7 @@
__rem; \
})
-#if __GNUC__ < 4
+#if __GNUC__ < 4 || !defined(CONFIG_AEABI)
/*
* gcc versions earlier than 4.0 are simply too problematic for the
diff --git a/arch/arm/include/asm/glue-proc.h b/arch/arm/include/asm/glue-proc.h
index e6168c0c18e9..74a8b84f3cb1 100644
--- a/arch/arm/include/asm/glue-proc.h
+++ b/arch/arm/include/asm/glue-proc.h
@@ -230,21 +230,21 @@
# endif
#endif
-#ifdef CONFIG_CPU_PJ4B
+#ifdef CONFIG_CPU_V7M
# ifdef CPU_NAME
# undef MULTI_CPU
# define MULTI_CPU
# else
-# define CPU_NAME cpu_pj4b
+# define CPU_NAME cpu_v7m
# endif
#endif
-#ifdef CONFIG_CPU_V7M
+#ifdef CONFIG_CPU_PJ4B
# ifdef CPU_NAME
# undef MULTI_CPU
# define MULTI_CPU
# else
-# define CPU_NAME cpu_v7m
+# define CPU_NAME cpu_pj4b
# endif
#endif
diff --git a/arch/arm/include/asm/hardware/iop3xx.h b/arch/arm/include/asm/hardware/iop3xx.h
index ed94b1a366ae..423744bf18eb 100644
--- a/arch/arm/include/asm/hardware/iop3xx.h
+++ b/arch/arm/include/asm/hardware/iop3xx.h
@@ -223,11 +223,12 @@ extern int iop3xx_get_init_atu(void);
#ifndef __ASSEMBLY__
#include <linux/types.h>
+#include <linux/reboot.h>
void iop3xx_map_io(void);
void iop_init_cp6_handler(void);
void iop_init_time(unsigned long tickrate);
-void iop3xx_restart(char, const char *);
+void iop3xx_restart(enum reboot_mode, const char *);
static inline u32 read_tmr0(void)
{
diff --git a/arch/arm/include/asm/hugetlb-3level.h b/arch/arm/include/asm/hugetlb-3level.h
new file mode 100644
index 000000000000..d4014fbe5ea3
--- /dev/null
+++ b/arch/arm/include/asm/hugetlb-3level.h
@@ -0,0 +1,71 @@
+/*
+ * arch/arm/include/asm/hugetlb-3level.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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_ARM_HUGETLB_3LEVEL_H
+#define _ASM_ARM_HUGETLB_3LEVEL_H
+
+
+/*
+ * If our huge pte is non-zero then mark the valid bit.
+ * This allows pte_present(huge_ptep_get(ptep)) to return true for non-zero
+ * ptes.
+ * (The valid bit is automatically cleared by set_pte_at for PROT_NONE ptes).
+ */
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ pte_t retval = *ptep;
+ if (pte_val(retval))
+ pte_val(retval) |= L_PTE_VALID;
+ return retval;
+}
+
+static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ set_pte_at(mm, addr, ptep, pte);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_clear_flush(vma, addr, ptep);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+#endif /* _ASM_ARM_HUGETLB_3LEVEL_H */
diff --git a/arch/arm/include/asm/hugetlb.h b/arch/arm/include/asm/hugetlb.h
new file mode 100644
index 000000000000..1f1b1cd112f3
--- /dev/null
+++ b/arch/arm/include/asm/hugetlb.h
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/include/asm/hugetlb.h
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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_ARM_HUGETLB_H
+#define _ASM_ARM_HUGETLB_H
+
+#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
+
+#include <asm/hugetlb-3level.h>
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr, unsigned long len)
+{
+ return 0;
+}
+
+static inline int prepare_hugepage_range(struct file *file,
+ unsigned long addr, unsigned long len)
+{
+ struct hstate *h = hstate_file(file);
+ if (len & ~huge_page_mask(h))
+ return -EINVAL;
+ if (addr & ~huge_page_mask(h))
+ return -EINVAL;
+ 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);
+}
+
+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);
+}
+
+#endif /* _ASM_ARM_HUGETLB_H */
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 652b56086de7..d070741b2b37 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -130,16 +130,16 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
*/
extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
size_t, unsigned int, void *);
-extern void __iomem *__arm_ioremap_caller(unsigned long, size_t, unsigned int,
+extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
void *);
extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int);
-extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached);
+extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
+extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
extern void __iounmap(volatile void __iomem *addr);
extern void __arm_iounmap(volatile void __iomem *addr);
-extern void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
unsigned int, void *);
extern void (*arch_iounmap)(volatile void __iomem *);
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index 124623e5ef14..64e96960de29 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -135,7 +135,6 @@
#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
-#define S2_PGD_SIZE (1 << S2_PGD_ORDER)
/* Virtualization Translation Control Register (VTCR) bits */
#define VTCR_SH0 (3 << 12)
diff --git a/arch/arm/include/asm/kvm_asm.h b/arch/arm/include/asm/kvm_asm.h
index 18d50322a9e2..a2f43ddcc300 100644
--- a/arch/arm/include/asm/kvm_asm.h
+++ b/arch/arm/include/asm/kvm_asm.h
@@ -37,16 +37,18 @@
#define c5_AIFSR 15 /* Auxilary Instrunction Fault Status R */
#define c6_DFAR 16 /* Data Fault Address Register */
#define c6_IFAR 17 /* Instruction Fault Address Register */
-#define c9_L2CTLR 18 /* Cortex A15 L2 Control Register */
-#define c10_PRRR 19 /* Primary Region Remap Register */
-#define c10_NMRR 20 /* Normal Memory Remap Register */
-#define c12_VBAR 21 /* Vector Base Address Register */
-#define c13_CID 22 /* Context ID Register */
-#define c13_TID_URW 23 /* Thread ID, User R/W */
-#define c13_TID_URO 24 /* Thread ID, User R/O */
-#define c13_TID_PRIV 25 /* Thread ID, Privileged */
-#define c14_CNTKCTL 26 /* Timer Control Register (PL1) */
-#define NR_CP15_REGS 27 /* Number of regs (incl. invalid) */
+#define c7_PAR 18 /* Physical Address Register */
+#define c7_PAR_high 19 /* PAR top 32 bits */
+#define c9_L2CTLR 20 /* Cortex A15 L2 Control Register */
+#define c10_PRRR 21 /* Primary Region Remap Register */
+#define c10_NMRR 22 /* Normal Memory Remap Register */
+#define c12_VBAR 23 /* Vector Base Address Register */
+#define c13_CID 24 /* Context ID Register */
+#define c13_TID_URW 25 /* Thread ID, User R/W */
+#define c13_TID_URO 26 /* Thread ID, User R/O */
+#define c13_TID_PRIV 27 /* Thread ID, Privileged */
+#define c14_CNTKCTL 28 /* Timer Control Register (PL1) */
+#define NR_CP15_REGS 29 /* Number of regs (incl. invalid) */
#define ARM_EXCEPTION_RESET 0
#define ARM_EXCEPTION_UNDEFINED 1
@@ -72,8 +74,6 @@ extern char __kvm_hyp_vector[];
extern char __kvm_hyp_code_start[];
extern char __kvm_hyp_code_end[];
-extern void __kvm_tlb_flush_vmid(struct kvm *kvm);
-
extern void __kvm_flush_vm_context(void);
extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index 82b4babead2c..a464e8d7b6c5 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -65,11 +65,6 @@ static inline bool vcpu_mode_priv(struct kvm_vcpu *vcpu)
return cpsr_mode > USR_MODE;;
}
-static inline bool kvm_vcpu_reg_is_pc(struct kvm_vcpu *vcpu, int reg)
-{
- return reg == 15;
-}
-
static inline u32 kvm_vcpu_get_hsr(struct kvm_vcpu *vcpu)
{
return vcpu->arch.fault.hsr;
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 57cb786a6203..7d22517d8071 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -23,9 +23,14 @@
#include <asm/kvm_asm.h>
#include <asm/kvm_mmio.h>
#include <asm/fpstate.h>
-#include <asm/kvm_arch_timer.h>
+#include <kvm/arm_arch_timer.h>
+#if defined(CONFIG_KVM_ARM_MAX_VCPUS)
#define KVM_MAX_VCPUS CONFIG_KVM_ARM_MAX_VCPUS
+#else
+#define KVM_MAX_VCPUS 0
+#endif
+
#define KVM_USER_MEM_SLOTS 32
#define KVM_PRIVATE_MEM_SLOTS 4
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
@@ -38,7 +43,7 @@
#define KVM_NR_PAGE_SIZES 1
#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
-#include <asm/kvm_vgic.h>
+#include <kvm/arm_vgic.h>
struct kvm_vcpu;
u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode);
@@ -190,8 +195,8 @@ int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
int exception_index);
-static inline void __cpu_init_hyp_mode(unsigned long long boot_pgd_ptr,
- unsigned long long pgd_ptr,
+static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
+ phys_addr_t pgd_ptr,
unsigned long hyp_stack_ptr,
unsigned long vector_ptr)
{
diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 75bf07910b81..441efc491b50 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -11,6 +11,7 @@
#include <linux/types.h>
#ifndef __ASSEMBLY__
+#include <linux/reboot.h>
struct tag;
struct meminfo;
@@ -43,7 +44,7 @@ struct machine_desc {
unsigned char reserve_lp0 :1; /* never has lp0 */
unsigned char reserve_lp1 :1; /* never has lp1 */
unsigned char reserve_lp2 :1; /* never has lp2 */
- char restart_mode; /* default restart mode */
+ enum reboot_mode reboot_mode; /* default restart mode */
struct smp_operations *smp; /* SMP operations */
bool (*smp_init)(void);
void (*fixup)(struct tag *, char **,
@@ -58,7 +59,7 @@ struct machine_desc {
#ifdef CONFIG_MULTI_IRQ_HANDLER
void (*handle_irq)(struct pt_regs *);
#endif
- void (*restart)(char, const char *);
+ void (*restart)(enum reboot_mode, const char *);
};
/*
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 57870ab313c5..e750a938fd3c 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -18,6 +18,8 @@
#include <linux/types.h>
#include <linux/sizes.h>
+#include <asm/cache.h>
+
#ifdef CONFIG_NEED_MACH_MEMORY_H
#include <mach/memory.h>
#endif
@@ -141,6 +143,20 @@
#define page_to_phys(page) (__pfn_to_phys(page_to_pfn(page)))
#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)
+
#ifndef __ASSEMBLY__
/*
@@ -207,7 +223,7 @@ static inline unsigned long __phys_to_virt(unsigned long x)
* direct-mapped view. We assume this is the first page
* of RAM in the mem_map as well.
*/
-#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT)
+#define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHIFT))
/*
* These are *only* valid on the kernel direct mapped RAM memory.
@@ -260,12 +276,6 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
/*
* Conversion between a struct page and a physical address.
*
- * Note: when converting an unknown physical address to a
- * struct page, the resulting pointer must be validated
- * using VALID_PAGE(). It must return an invalid struct page
- * for any physical address not corresponding to a system
- * RAM address.
- *
* page_to_pfn(page) convert a struct page * to a PFN number
* pfn_to_page(pfn) convert a _valid_ PFN number to struct page *
*
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index a7b85e0d0cc1..b5792b7fd8d3 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -18,6 +18,7 @@
#include <asm/cacheflush.h>
#include <asm/cachetype.h>
#include <asm/proc-fns.h>
+#include <asm/smp_plat.h>
#include <asm-generic/mm_hooks.h>
void __check_vmalloc_seq(struct mm_struct *mm);
@@ -27,7 +28,15 @@ void __check_vmalloc_seq(struct mm_struct *mm);
void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
#define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; })
-DECLARE_PER_CPU(atomic64_t, active_asids);
+#ifdef CONFIG_ARM_ERRATA_798181
+void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
+ cpumask_t *mask);
+#else /* !CONFIG_ARM_ERRATA_798181 */
+static inline void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
+ cpumask_t *mask)
+{
+}
+#endif /* CONFIG_ARM_ERRATA_798181 */
#else /* !CONFIG_CPU_HAS_ASID */
@@ -98,12 +107,16 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
#ifdef CONFIG_MMU
unsigned int cpu = smp_processor_id();
-#ifdef CONFIG_SMP
- /* check for possible thread migration */
- if (!cpumask_empty(mm_cpumask(next)) &&
+ /*
+ * __sync_icache_dcache doesn't broadcast the I-cache invalidation,
+ * so check for possible thread migration and invalidate the I-cache
+ * if we're new to this CPU.
+ */
+ if (cache_ops_need_broadcast() &&
+ !cpumask_empty(mm_cpumask(next)) &&
!cpumask_test_cpu(cpu, mm_cpumask(next)))
__flush_icache_all();
-#endif
+
if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next) {
check_and_switch_context(next, tsk);
if (cache_is_vivt())
diff --git a/arch/arm/include/asm/mpu.h b/arch/arm/include/asm/mpu.h
new file mode 100644
index 000000000000..c3247cc2fe08
--- /dev/null
+++ b/arch/arm/include/asm/mpu.h
@@ -0,0 +1,76 @@
+#ifndef __ARM_MPU_H
+#define __ARM_MPU_H
+
+#ifdef CONFIG_ARM_MPU
+
+/* MPUIR layout */
+#define MPUIR_nU 1
+#define MPUIR_DREGION 8
+#define MPUIR_IREGION 16
+#define MPUIR_DREGION_SZMASK (0xFF << MPUIR_DREGION)
+#define MPUIR_IREGION_SZMASK (0xFF << MPUIR_IREGION)
+
+/* ID_MMFR0 data relevant to MPU */
+#define MMFR0_PMSA (0xF << 4)
+#define MMFR0_PMSAv7 (3 << 4)
+
+/* MPU D/I Size Register fields */
+#define MPU_RSR_SZ 1
+#define MPU_RSR_EN 0
+
+/* The D/I RSR value for an enabled region spanning the whole of memory */
+#define MPU_RSR_ALL_MEM 63
+
+/* Individual bits in the DR/IR ACR */
+#define MPU_ACR_XN (1 << 12)
+#define MPU_ACR_SHARED (1 << 2)
+
+/* C, B and TEX[2:0] bits only have semantic meanings when grouped */
+#define MPU_RGN_CACHEABLE 0xB
+#define MPU_RGN_SHARED_CACHEABLE (MPU_RGN_CACHEABLE | MPU_ACR_SHARED)
+#define MPU_RGN_STRONGLY_ORDERED 0
+
+/* Main region should only be shared for SMP */
+#ifdef CONFIG_SMP
+#define MPU_RGN_NORMAL (MPU_RGN_CACHEABLE | MPU_ACR_SHARED)
+#else
+#define MPU_RGN_NORMAL MPU_RGN_CACHEABLE
+#endif
+
+/* Access permission bits of ACR (only define those that we use)*/
+#define MPU_AP_PL1RW_PL0RW (0x3 << 8)
+#define MPU_AP_PL1RW_PL0R0 (0x2 << 8)
+#define MPU_AP_PL1RW_PL0NA (0x1 << 8)
+
+/* For minimal static MPU region configurations */
+#define MPU_PROBE_REGION 0
+#define MPU_BG_REGION 1
+#define MPU_RAM_REGION 2
+#define MPU_VECTORS_REGION 3
+
+/* Maximum number of regions Linux is interested in */
+#define MPU_MAX_REGIONS 16
+
+#define MPU_DATA_SIDE 0
+#define MPU_INSTR_SIDE 1
+
+#ifndef __ASSEMBLY__
+
+struct mpu_rgn {
+ /* Assume same attributes for d/i-side */
+ u32 drbar;
+ u32 drsr;
+ u32 dracr;
+};
+
+struct mpu_rgn_info {
+ u32 mpuir;
+ struct mpu_rgn rgns[MPU_MAX_REGIONS];
+};
+extern struct mpu_rgn_info mpu_rgn_info;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARM_MPU */
+
+#endif
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index 812a4944e783..6363f3d1d505 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -13,7 +13,7 @@
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
+#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
#ifndef __ASSEMBLY__
diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
index 18f5cef82ad5..626989fec4d3 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -30,6 +30,7 @@
#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0)
#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
+#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1)
#define PMD_BIT4 (_AT(pmdval_t, 0))
#define PMD_DOMAIN(x) (_AT(pmdval_t, 0))
#define PMD_APTABLE_SHIFT (61)
@@ -41,6 +42,8 @@
*/
#define PMD_SECT_BUFFERABLE (_AT(pmdval_t, 1) << 2)
#define PMD_SECT_CACHEABLE (_AT(pmdval_t, 1) << 3)
+#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */
+#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */
#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
#define PMD_SECT_nG (_AT(pmdval_t, 1) << 11)
@@ -66,6 +69,7 @@
#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0)
#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0)
+#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1)
#define PTE_BUFFERABLE (_AT(pteval_t, 1) << 2) /* AttrIndx[0] */
#define PTE_CACHEABLE (_AT(pteval_t, 1) << 3) /* AttrIndx[1] */
#define PTE_EXT_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
@@ -79,4 +83,24 @@
#define PHYS_MASK_SHIFT (40)
#define PHYS_MASK ((1ULL << PHYS_MASK_SHIFT) - 1)
+/*
+ * TTBR0/TTBR1 split (PAGE_OFFSET):
+ * 0x40000000: T0SZ = 2, T1SZ = 0 (not used)
+ * 0x80000000: T0SZ = 0, T1SZ = 1
+ * 0xc0000000: T0SZ = 0, T1SZ = 2
+ *
+ * Only use this feature if PHYS_OFFSET <= PAGE_OFFSET, otherwise
+ * booting secondary CPUs would end up using TTBR1 for the identity
+ * mapping set up in TTBR0.
+ */
+#if defined CONFIG_VMSPLIT_2G
+#define TTBR1_OFFSET 16 /* skip two L1 entries */
+#elif defined CONFIG_VMSPLIT_3G
+#define TTBR1_OFFSET (4096 * (1 + 3)) /* only L2, skip pgd + 3*pmd */
+#else
+#define TTBR1_OFFSET 0
+#endif
+
+#define TTBR1_SIZE (((PAGE_OFFSET >> 30) - 1) << 16)
+
#endif
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 86b8fe398b95..5689c18c85f5 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -33,7 +33,7 @@
#define PTRS_PER_PMD 512
#define PTRS_PER_PGD 4
-#define PTE_HWTABLE_PTRS (PTRS_PER_PTE)
+#define PTE_HWTABLE_PTRS (0)
#define PTE_HWTABLE_OFF (0)
#define PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(u64))
@@ -48,20 +48,28 @@
#define PMD_SHIFT 21
#define PMD_SIZE (1UL << PMD_SHIFT)
-#define PMD_MASK (~(PMD_SIZE-1))
+#define PMD_MASK (~((1 << PMD_SHIFT) - 1))
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK (~(PGDIR_SIZE-1))
+#define PGDIR_MASK (~((1 << PGDIR_SHIFT) - 1))
/*
* section address mask and size definitions.
*/
#define SECTION_SHIFT 21
#define SECTION_SIZE (1UL << SECTION_SHIFT)
-#define SECTION_MASK (~(SECTION_SIZE-1))
+#define SECTION_MASK (~((1 << SECTION_SHIFT) - 1))
#define USER_PTRS_PER_PGD (PAGE_OFFSET / PGDIR_SIZE)
/*
+ * Hugetlb definitions.
+ */
+#define HPAGE_SHIFT PMD_SHIFT
+#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
+#define HPAGE_MASK (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+
+/*
* "Linux" PTE definitions for LPAE.
*
* These bits overlap with the hardware bits but the naming is preserved for
@@ -79,6 +87,11 @@
#define L_PTE_SPECIAL (_AT(pteval_t, 1) << 56) /* unused */
#define L_PTE_NONE (_AT(pteval_t, 1) << 57) /* PROT_NONE */
+#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0)
+#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
+#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 56)
+#define PMD_SECT_NONE (_AT(pmdval_t, 1) << 57)
+
/*
* To be used in assembly code with the upper page attributes.
*/
@@ -166,8 +179,83 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
clean_pmd_entry(pmdp); \
} while (0)
+/*
+ * For 3 levels of paging the PTE_EXT_NG bit will be set for user address ptes
+ * that are written to a page table but not for ptes created with mk_pte.
+ *
+ * In hugetlb_no_page, a new huge pte (new_pte) is generated and passed to
+ * hugetlb_cow, where it is compared with an entry in a page table.
+ * This comparison test fails erroneously leading ultimately to a memory leak.
+ *
+ * To correct this behaviour, we mask off PTE_EXT_NG for any pte that is
+ * present before running the comparison.
+ */
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(pte_a,pte_b) ((pte_present(pte_a) ? pte_val(pte_a) & ~PTE_EXT_NG \
+ : pte_val(pte_a)) \
+ == (pte_present(pte_b) ? pte_val(pte_b) & ~PTE_EXT_NG \
+ : pte_val(pte_b)))
+
#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,__pte(pte_val(pte)|(ext)))
+#define pte_huge(pte) (pte_val(pte) && !(pte_val(pte) & PTE_TABLE_BIT))
+#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
+
+#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF)
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY))
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
+#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#endif
+
+#define PMD_BIT_FUNC(fn,op) \
+static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+
+PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
+PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
+PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
+
+#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
+
+#define pmd_pfn(pmd) (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
+
+/* represent a notpresent pmd by zero, this is used by pmdp_invalidate */
+#define pmd_mknotpresent(pmd) (__pmd(0))
+
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+ const pmdval_t mask = PMD_SECT_USER | PMD_SECT_XN | PMD_SECT_RDONLY |
+ PMD_SECT_VALID | PMD_SECT_NONE;
+ pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
+ return pmd;
+}
+
+static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, pmd_t pmd)
+{
+ BUG_ON(addr >= TASK_SIZE);
+
+ /* create a faulting entry if PROT_NONE protected */
+ if (pmd_val(pmd) & PMD_SECT_NONE)
+ pmd_val(pmd) &= ~PMD_SECT_VALID;
+
+ *pmdp = __pmd(pmd_val(pmd) | PMD_SECT_nG);
+ flush_pmd_entry(pmdp);
+}
+
+static inline int has_transparent_hugepage(void)
+{
+ return 1;
+}
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_PGTABLE_3LEVEL_H */
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 229e0dde9c71..04aeb02d2e11 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -24,6 +24,9 @@
#include <asm/memory.h>
#include <asm/pgtable-hwdef.h>
+
+#include <asm/tlbflush.h>
+
#ifdef CONFIG_ARM_LPAE
#include <asm/pgtable-3level.h>
#else
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index f3628fb3d2b3..5324c1112f3a 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -60,7 +60,7 @@ extern struct processor {
/*
* Set the page table
*/
- void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
+ void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
/*
* Set a possibly extended PTE. Non-extended PTEs should
* ignore 'ext'.
@@ -82,7 +82,7 @@ extern void cpu_proc_init(void);
extern void cpu_proc_fin(void);
extern int cpu_do_idle(void);
extern void cpu_dcache_clean_area(void *, int);
-extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
+extern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
#ifdef CONFIG_ARM_LPAE
extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
#else
@@ -116,13 +116,25 @@ extern void cpu_resume(void);
#define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
#ifdef CONFIG_ARM_LPAE
+
+#define cpu_get_ttbr(nr) \
+ ({ \
+ u64 ttbr; \
+ __asm__("mrrc p15, " #nr ", %Q0, %R0, c2" \
+ : "=r" (ttbr)); \
+ 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() \
({ \
- unsigned long pg, pg2; \
- __asm__("mrrc p15, 0, %0, %1, c2" \
- : "=r" (pg), "=r" (pg2) \
- : \
- : "cc"); \
+ u64 pg = cpu_get_ttbr(0); \
pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1); \
(pgd_t *)phys_to_virt(pg); \
})
@@ -137,6 +149,10 @@ extern void cpu_resume(void);
})
#endif
+#else /*!CONFIG_MMU */
+
+#define cpu_switch_mm(pgd,mm) { }
+
#endif
#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/include/asm/sched_clock.h b/arch/arm/include/asm/sched_clock.h
index 3d520ddca61b..2389b71a8e7c 100644
--- a/arch/arm/include/asm/sched_clock.h
+++ b/arch/arm/include/asm/sched_clock.h
@@ -1,16 +1,4 @@
-/*
- * sched_clock.h: support for extending counters to full 64-bit ns counter
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+/* You shouldn't include this file. Use linux/sched_clock.h instead.
+ * Temporary file until all asm/sched_clock.h users are gone
*/
-#ifndef ASM_SCHED_CLOCK
-#define ASM_SCHED_CLOCK
-
-extern void sched_clock_postinit(void);
-extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
-
-extern unsigned long long (*sched_clock_func)(void);
-
-#endif
+#include <linux/sched_clock.h>
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index d3a22bebe6ce..a8cae71caceb 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -65,7 +65,10 @@ asmlinkage void secondary_start_kernel(void);
* Initial data for bringing up a secondary CPU.
*/
struct secondary_data {
- unsigned long pgdir;
+ union {
+ unsigned long mpu_rgn_szr;
+ unsigned long pgdir;
+ };
unsigned long swapper_pg_dir;
void *stack;
};
diff --git a/arch/arm/include/asm/smp_plat.h b/arch/arm/include/asm/smp_plat.h
index e78983202737..6462a721ebd4 100644
--- a/arch/arm/include/asm/smp_plat.h
+++ b/arch/arm/include/asm/smp_plat.h
@@ -26,6 +26,9 @@ static inline bool is_smp(void)
}
/* all SMP configurations have the extended CPUID registers */
+#ifndef CONFIG_MMU
+#define tlb_ops_need_broadcast() 0
+#else
static inline int tlb_ops_need_broadcast(void)
{
if (!is_smp())
@@ -33,6 +36,7 @@ static inline int tlb_ops_need_broadcast(void)
return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
}
+#endif
#if !defined(CONFIG_SMP) || __LINUX_ARM_ARCH__ >= 7
#define cache_ops_need_broadcast() 0
@@ -66,4 +70,22 @@ static inline int get_logical_index(u32 mpidr)
return -EINVAL;
}
+/*
+ * NOTE ! Assembly code relies on the following
+ * structure memory layout in order to carry out load
+ * multiple from its base address. For more
+ * information check arch/arm/kernel/sleep.S
+ */
+struct mpidr_hash {
+ u32 mask; /* used by sleep.S */
+ u32 shift_aff[3]; /* used by sleep.S */
+ u32 bits;
+};
+
+extern struct mpidr_hash mpidr_hash;
+
+static inline u32 mpidr_hash_size(void)
+{
+ return 1 << mpidr_hash.bits;
+}
#endif
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 6220e9fdf4c7..f8b8965666e9 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -97,19 +97,22 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
static inline int arch_spin_trylock(arch_spinlock_t *lock)
{
- unsigned long tmp;
+ unsigned long contended, res;
u32 slock;
- __asm__ __volatile__(
-" ldrex %0, [%2]\n"
-" subs %1, %0, %0, ror #16\n"
-" addeq %0, %0, %3\n"
-" strexeq %1, %0, [%2]"
- : "=&r" (slock), "=&r" (tmp)
- : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
- : "cc");
-
- if (tmp == 0) {
+ do {
+ __asm__ __volatile__(
+ " ldrex %0, [%3]\n"
+ " mov %2, #0\n"
+ " subs %1, %0, %0, ror #16\n"
+ " addeq %0, %0, %4\n"
+ " strexeq %2, %0, [%3]"
+ : "=&r" (slock), "=&r" (contended), "=r" (res)
+ : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
+ : "cc");
+ } while (res);
+
+ if (!contended) {
smp_mb();
return 1;
} else {
diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
index 1c0a551ae375..cd20029bcd94 100644
--- a/arch/arm/include/asm/suspend.h
+++ b/arch/arm/include/asm/suspend.h
@@ -1,6 +1,11 @@
#ifndef __ASM_ARM_SUSPEND_H
#define __ASM_ARM_SUSPEND_H
+struct sleep_save_sp {
+ u32 *save_ptr_stash;
+ u32 save_ptr_stash_phys;
+};
+
extern void cpu_resume(void);
extern int cpu_suspend(unsigned long, int (*)(unsigned long));
diff --git a/arch/arm/include/asm/system_misc.h b/arch/arm/include/asm/system_misc.h
index 21a23e378bbe..a3d61ad984af 100644
--- a/arch/arm/include/asm/system_misc.h
+++ b/arch/arm/include/asm/system_misc.h
@@ -6,11 +6,12 @@
#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/irqflags.h>
+#include <linux/reboot.h>
extern void cpu_init(void);
void soft_restart(unsigned long);
-extern void (*arm_pm_restart)(char str, const char *cmd);
+extern void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
extern void (*arm_pm_idle)(void);
#define UDBG_UNDEFINED (1 << 0)
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 1995d1a84060..214d4158089a 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -58,7 +58,7 @@ struct thread_info {
struct cpu_context_save cpu_context; /* cpu context */
__u32 syscall; /* syscall number */
__u8 used_cp[16]; /* thread used copro */
- unsigned long tp_value;
+ unsigned long tp_value[2]; /* TLS registers */
#ifdef CONFIG_CRUNCH
struct crunch_state crunchstate;
#endif
diff --git a/arch/arm/include/asm/tlb.h b/arch/arm/include/asm/tlb.h
index bdf2b8458ec1..46e7cfb3e721 100644
--- a/arch/arm/include/asm/tlb.h
+++ b/arch/arm/include/asm/tlb.h
@@ -204,6 +204,12 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
#endif
}
+static inline void
+tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
+{
+ tlb_add_flush(tlb, addr);
+}
+
#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr)
#define pmd_free_tlb(tlb, pmdp, addr) __pmd_free_tlb(tlb, pmdp, addr)
#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
diff --git a/arch/arm/include/asm/tlbflush.h b/arch/arm/include/asm/tlbflush.h
index a3625d141c1d..fdbb9e369745 100644
--- a/arch/arm/include/asm/tlbflush.h
+++ b/arch/arm/include/asm/tlbflush.h
@@ -535,8 +535,33 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
}
#endif
+#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
+
#endif
-#endif /* CONFIG_MMU */
+#elif defined(CONFIG_SMP) /* !CONFIG_MMU */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/mm_types.h>
+
+static inline void local_flush_tlb_all(void) { }
+static inline void local_flush_tlb_mm(struct mm_struct *mm) { }
+static inline void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) { }
+static inline void local_flush_tlb_kernel_page(unsigned long kaddr) { }
+static inline void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { }
+static inline void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) { }
+static inline void local_flush_bp_all(void) { }
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
+extern void flush_tlb_kernel_page(unsigned long kaddr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_bp_all(void);
+#endif /* __ASSEMBLY__ */
+
+#endif
#endif
diff --git a/arch/arm/include/asm/tls.h b/arch/arm/include/asm/tls.h
index 73409e6c0251..83259b873333 100644
--- a/arch/arm/include/asm/tls.h
+++ b/arch/arm/include/asm/tls.h
@@ -2,27 +2,30 @@
#define __ASMARM_TLS_H
#ifdef __ASSEMBLY__
- .macro set_tls_none, tp, tmp1, tmp2
+#include <asm/asm-offsets.h>
+ .macro switch_tls_none, base, tp, tpuser, tmp1, tmp2
.endm
- .macro set_tls_v6k, tp, tmp1, tmp2
+ .macro switch_tls_v6k, base, tp, tpuser, tmp1, tmp2
+ mrc p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
mcr p15, 0, \tp, c13, c0, 3 @ set TLS register
- mov \tmp1, #0
- mcr p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
+ mcr p15, 0, \tpuser, c13, c0, 2 @ and the user r/w register
+ str \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
.endm
- .macro set_tls_v6, tp, tmp1, tmp2
+ .macro switch_tls_v6, base, tp, tpuser, tmp1, tmp2
ldr \tmp1, =elf_hwcap
ldr \tmp1, [\tmp1, #0]
mov \tmp2, #0xffff0fff
tst \tmp1, #HWCAP_TLS @ hardware TLS available?
- mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
- movne \tmp1, #0
- mcrne p15, 0, \tmp1, c13, c0, 2 @ clear user r/w TLS register
streq \tp, [\tmp2, #-15] @ set TLS value at 0xffff0ff0
+ mrcne p15, 0, \tmp2, c13, c0, 2 @ get the user r/w register
+ mcrne p15, 0, \tp, c13, c0, 3 @ yes, set TLS register
+ mcrne p15, 0, \tpuser, c13, c0, 2 @ set user r/w register
+ strne \tmp2, [\base, #TI_TP_VALUE + 4] @ save it
.endm
- .macro set_tls_software, tp, tmp1, tmp2
+ .macro switch_tls_software, base, tp, tpuser, tmp1, tmp2
mov \tmp1, #0xffff0fff
str \tp, [\tmp1, #-15] @ set TLS value at 0xffff0ff0
.endm
@@ -31,19 +34,30 @@
#ifdef CONFIG_TLS_REG_EMUL
#define tls_emu 1
#define has_tls_reg 1
-#define set_tls set_tls_none
+#define switch_tls switch_tls_none
#elif defined(CONFIG_CPU_V6)
#define tls_emu 0
#define has_tls_reg (elf_hwcap & HWCAP_TLS)
-#define set_tls set_tls_v6
+#define switch_tls switch_tls_v6
#elif defined(CONFIG_CPU_32v6K)
#define tls_emu 0
#define has_tls_reg 1
-#define set_tls set_tls_v6k
+#define switch_tls switch_tls_v6k
#else
#define tls_emu 0
#define has_tls_reg 0
-#define set_tls set_tls_software
+#define switch_tls switch_tls_software
#endif
+#ifndef __ASSEMBLY__
+static inline unsigned long get_tpuser(void)
+{
+ unsigned long reg = 0;
+
+ if (has_tls_reg && !tls_emu)
+ __asm__("mrc p15, 0, %0, c13, c0, 2" : "=r" (reg));
+
+ return reg;
+}
+#endif
#endif /* __ASMARM_TLS_H */
diff --git a/arch/arm/include/asm/xen/hypercall.h b/arch/arm/include/asm/xen/hypercall.h
index 799f42ecca63..7704e28c3483 100644
--- a/arch/arm/include/asm/xen/hypercall.h
+++ b/arch/arm/include/asm/xen/hypercall.h
@@ -47,6 +47,7 @@ unsigned long HYPERVISOR_hvm_op(int op, void *arg);
int HYPERVISOR_memory_op(unsigned int cmd, void *arg);
int HYPERVISOR_physdev_op(int cmd, void *arg);
int HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args);
+int HYPERVISOR_tmem_op(void *arg);
static inline void
MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h
index 30cdacb675af..359a7b50b158 100644
--- a/arch/arm/include/asm/xen/page.h
+++ b/arch/arm/include/asm/xen/page.h
@@ -1,7 +1,6 @@
#ifndef _ASM_ARM_XEN_PAGE_H
#define _ASM_ARM_XEN_PAGE_H
-#include <asm/mach/map.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -88,6 +87,6 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn)
return __set_phys_to_machine(pfn, mfn);
}
-#define xen_remap(cookie, size) __arm_ioremap((cookie), (size), MT_MEMORY);
+#define xen_remap(cookie, size) ioremap_cached((cookie), (size));
#endif /* _ASM_ARM_XEN_PAGE_H */
diff --git a/arch/arm/include/debug/vexpress.S b/arch/arm/include/debug/vexpress.S
index dc8e882a6257..acafb229e2b6 100644
--- a/arch/arm/include/debug/vexpress.S
+++ b/arch/arm/include/debug/vexpress.S
@@ -16,6 +16,8 @@
#define DEBUG_LL_PHYS_BASE_RS1 0x1c000000
#define DEBUG_LL_UART_OFFSET_RS1 0x00090000
+#define DEBUG_LL_UART_PHYS_CRX 0xb0090000
+
#define DEBUG_LL_VIRT_BASE 0xf8000000
#if defined(CONFIG_DEBUG_VEXPRESS_UART0_DETECT)
@@ -67,6 +69,14 @@
#include <asm/hardware/debug-pl01x.S>
+#elif defined(CONFIG_DEBUG_VEXPRESS_UART0_CRX)
+
+ .macro addruart,rp,tmp,tmp2
+ ldr \rp, =DEBUG_LL_UART_PHYS_CRX
+ .endm
+
+#include <asm/hardware/debug-pl01x.S>
+
#else /* CONFIG_DEBUG_LL_UART_NONE */
.macro addruart, rp, rv, tmp
diff --git a/arch/arm/include/uapi/asm/hwcap.h b/arch/arm/include/uapi/asm/hwcap.h
index 3688fd15a32d..6d34d080372a 100644
--- a/arch/arm/include/uapi/asm/hwcap.h
+++ b/arch/arm/include/uapi/asm/hwcap.h
@@ -25,6 +25,6 @@
#define HWCAP_IDIVT (1 << 18)
#define HWCAP_VFPD32 (1 << 19) /* set if VFP has 32 regs (not 16) */
#define HWCAP_IDIV (HWCAP_IDIVA | HWCAP_IDIVT)
-
+#define HWCAP_LPAE (1 << 20)
#endif /* _UAPI__ASMARM_HWCAP_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index f4285b5ffb05..86d10dd47dc4 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -16,7 +16,7 @@ CFLAGS_REMOVE_return_address.o = -pg
# Object file lists.
obj-y := elf.o entry-common.o irq.o opcodes.o \
- process.o ptrace.o return_address.o sched_clock.o \
+ process.o ptrace.o return_address.o \
setup.o signal.o stacktrace.o sys_arm.o time.o traps.o
obj-$(CONFIG_ATAGS) += atags_parse.o
@@ -38,7 +38,10 @@ obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o
-obj-$(CONFIG_SMP) += smp.o smp_tlb.o
+obj-$(CONFIG_SMP) += smp.o
+ifdef CONFIG_MMU
+obj-$(CONFIG_SMP) += smp_tlb.o
+endif
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arch_timer.o
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 59dcdced6e30..221f07b11ccb 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -11,9 +11,9 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/sched_clock.h>
#include <asm/delay.h>
-#include <asm/sched_clock.h>
#include <clocksource/arm_arch_timer.h>
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index ee68cce6b48e..ded041711beb 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -23,6 +23,7 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/procinfo.h>
+#include <asm/suspend.h>
#include <asm/hardware/cache-l2x0.h>
#include <linux/kbuild.h>
@@ -145,6 +146,11 @@ int main(void)
#ifdef MULTI_CACHE
DEFINE(CACHE_FLUSH_KERN_ALL, offsetof(struct cpu_cache_fns, flush_kern_all));
#endif
+#ifdef CONFIG_ARM_CPU_SUSPEND
+ DEFINE(SLEEP_SAVE_SP_SZ, sizeof(struct sleep_save_sp));
+ DEFINE(SLEEP_SAVE_SP_PHYS, offsetof(struct sleep_save_sp, save_ptr_stash_phys));
+ DEFINE(SLEEP_SAVE_SP_VIRT, offsetof(struct sleep_save_sp, save_ptr_stash));
+#endif
BLANK();
DEFINE(DMA_BIDIRECTIONAL, DMA_BIDIRECTIONAL);
DEFINE(DMA_TO_DEVICE, DMA_TO_DEVICE);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 582b405befc5..a39cfc2a1f90 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -685,15 +685,16 @@ ENTRY(__switch_to)
UNWIND(.fnstart )
UNWIND(.cantunwind )
add ip, r1, #TI_CPU_SAVE
- ldr r3, [r2, #TI_TP_VALUE]
ARM( stmia ip!, {r4 - sl, fp, sp, lr} ) @ Store most regs on stack
THUMB( stmia ip!, {r4 - sl, fp} ) @ Store most regs on stack
THUMB( str sp, [ip], #4 )
THUMB( str lr, [ip], #4 )
+ ldr r4, [r2, #TI_TP_VALUE]
+ ldr r5, [r2, #TI_TP_VALUE + 4]
#ifdef CONFIG_CPU_USE_DOMAINS
ldr r6, [r2, #TI_CPU_DOMAIN]
#endif
- set_tls r3, r4, r5
+ switch_tls r1, r4, r5, r3, r7
#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
ldr r7, [r2, #TI_TASK]
ldr r8, =__stack_chk_guard
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 85a72b0809ca..94104bf69719 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -366,6 +366,16 @@ ENTRY(vector_swi)
#endif
zero_fp
+#ifdef CONFIG_ALIGNMENT_TRAP
+ ldr ip, __cr_alignment
+ ldr ip, [ip]
+ mcr p15, 0, ip, c1, c0 @ update control register
+#endif
+
+ enable_irq
+ ct_user_exit
+ get_thread_info tsk
+
/*
* Get the system call number.
*/
@@ -379,9 +389,9 @@ ENTRY(vector_swi)
#ifdef CONFIG_ARM_THUMB
tst r8, #PSR_T_BIT
movne r10, #0 @ no thumb OABI emulation
- ldreq r10, [lr, #-4] @ get SWI instruction
+ USER( ldreq r10, [lr, #-4] ) @ get SWI instruction
#else
- ldr r10, [lr, #-4] @ get SWI instruction
+ USER( ldr r10, [lr, #-4] ) @ get SWI instruction
#endif
#ifdef CONFIG_CPU_ENDIAN_BE8
rev r10, r10 @ little endian instruction
@@ -396,22 +406,13 @@ ENTRY(vector_swi)
/* Legacy ABI only, possibly thumb mode. */
tst r8, #PSR_T_BIT @ this is SPSR from save_user_regs
addne scno, r7, #__NR_SYSCALL_BASE @ put OS number in
- ldreq scno, [lr, #-4]
+ USER( ldreq scno, [lr, #-4] )
#else
/* Legacy ABI only. */
- ldr scno, [lr, #-4] @ get SWI instruction
+ USER( ldr scno, [lr, #-4] ) @ get SWI instruction
#endif
-#ifdef CONFIG_ALIGNMENT_TRAP
- ldr ip, __cr_alignment
- ldr ip, [ip]
- mcr p15, 0, ip, c1, c0 @ update control register
-#endif
- enable_irq
- ct_user_exit
-
- get_thread_info tsk
adr tbl, sys_call_table @ load syscall table pointer
#if defined(CONFIG_OABI_COMPAT)
@@ -446,6 +447,21 @@ local_restart:
eor r0, scno, #__NR_SYSCALL_BASE @ put OS number back
bcs arm_syscall
b sys_ni_syscall @ not private func
+
+#if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI)
+ /*
+ * We failed to handle a fault trying to access the page
+ * containing the swi instruction, but we're not really in a
+ * position to return -EFAULT. Instead, return back to the
+ * instruction and re-enter the user fault handling path trying
+ * to page it in. This will likely result in sending SEGV to the
+ * current task.
+ */
+9001:
+ sub lr, lr, #4
+ str lr, [sp, #S_PC]
+ b ret_fast_syscall
+#endif
ENDPROC(vector_swi)
/*
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 8812ce88f7a1..75f14cc3e073 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -17,9 +17,12 @@
#include <asm/assembler.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
+#include <asm/memory.h>
#include <asm/cp15.h>
#include <asm/thread_info.h>
#include <asm/v7m.h>
+#include <asm/mpu.h>
+#include <asm/page.h>
/*
* Kernel startup entry point.
@@ -63,12 +66,74 @@ ENTRY(stext)
movs r10, r5 @ invalid processor (r5=0)?
beq __error_p @ yes, error 'p'
- adr lr, BSYM(__after_proc_init) @ return (PIC) address
+#ifdef CONFIG_ARM_MPU
+ /* Calculate the size of a region covering just the kernel */
+ ldr r5, =PHYS_OFFSET @ Region start: PHYS_OFFSET
+ ldr r6, =(_end) @ Cover whole kernel
+ sub r6, r6, r5 @ Minimum size of region to map
+ clz r6, r6 @ Region size must be 2^N...
+ rsb r6, r6, #31 @ ...so round up region size
+ lsl r6, r6, #MPU_RSR_SZ @ Put size in right field
+ 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
ARM( add pc, r10, #PROCINFO_INITFUNC )
THUMB( add r12, r10, #PROCINFO_INITFUNC )
THUMB( mov pc, r12 )
+ 1: b __after_proc_init
ENDPROC(stext)
+#ifdef CONFIG_SMP
+ __CPUINIT
+ENTRY(secondary_startup)
+ /*
+ * Common entry point for secondary CPUs.
+ *
+ * Ensure that we're in SVC mode, and IRQs are disabled. Lookup
+ * the processor type - there is no need to check the machine type
+ * as it has already been validated by the primary processor.
+ */
+ setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
+#ifndef CONFIG_CPU_CP15
+ ldr r9, =CONFIG_PROCESSOR_ID
+#else
+ mrc p15, 0, r9, c0, c0 @ get processor id
+#endif
+ bl __lookup_processor_type @ r5=procinfo r9=cpuid
+ movs r10, r5 @ invalid processor?
+ beq __error_p @ yes, error 'p'
+
+ adr r4, __secondary_data
+ ldmia r4, {r7, r12}
+
+#ifdef CONFIG_ARM_MPU
+ /* Use MPU region info supplied by __cpu_up */
+ ldr r6, [r7] @ get secondary_data.mpu_szr
+ bl __setup_mpu @ Initialize the MPU
+#endif
+
+ adr lr, BSYM(__after_proc_init) @ return address
+ mov r13, r12 @ __secondary_switched address
+ ARM( add pc, r10, #PROCINFO_INITFUNC )
+ THUMB( add r12, r10, #PROCINFO_INITFUNC )
+ THUMB( mov pc, r12 )
+ENDPROC(secondary_startup)
+
+ENTRY(__secondary_switched)
+ ldr sp, [r7, #8] @ set up the stack pointer
+ mov fp, #0
+ b secondary_start_kernel
+ENDPROC(__secondary_switched)
+
+ .type __secondary_data, %object
+__secondary_data:
+ .long secondary_data
+ .long __secondary_switched
+#endif /* CONFIG_SMP */
+
/*
* Set the Control Register and Read the process ID.
*/
@@ -99,10 +164,97 @@ __after_proc_init:
#endif
mcr p15, 0, r0, c1, c0, 0 @ write control reg
#endif /* CONFIG_CPU_CP15 */
-
- b __mmap_switched @ clear the BSS and jump
- @ to start_kernel
+ mov pc, r13
ENDPROC(__after_proc_init)
.ltorg
+#ifdef CONFIG_ARM_MPU
+
+
+/* Set which MPU region should be programmed */
+.macro set_region_nr tmp, rgnr
+ mov \tmp, \rgnr @ Use static region numbers
+ mcr p15, 0, \tmp, c6, c2, 0 @ Write RGNR
+.endm
+
+/* Setup a single MPU region, either D or I side (D-side for unified) */
+.macro setup_region bar, acr, sr, side = MPU_DATA_SIDE
+ mcr p15, 0, \bar, c6, c1, (0 + \side) @ I/DRBAR
+ mcr p15, 0, \acr, c6, c1, (4 + \side) @ I/DRACR
+ mcr p15, 0, \sr, c6, c1, (2 + \side) @ I/DRSR
+.endm
+
+/*
+ * Setup the MPU and initial MPU Regions. We create the following regions:
+ * Region 0: Use this for probing the MPU details, so leave disabled.
+ * Region 1: Background region - covers the whole of RAM as strongly ordered
+ * Region 2: Normal, Shared, cacheable for RAM. From PHYS_OFFSET, size from r6
+ * Region 3: Normal, shared, inaccessible from PL0 to protect the vectors page
+ *
+ * r6: Value to be written to DRSR (and IRSR if required) for MPU_RAM_REGION
+*/
+
+ENTRY(__setup_mpu)
+
+ /* Probe for v7 PMSA compliance */
+ mrc p15, 0, r0, c0, c1, 4 @ Read ID_MMFR0
+ and r0, r0, #(MMFR0_PMSA) @ PMSA field
+ teq r0, #(MMFR0_PMSAv7) @ PMSA v7
+ bne __error_p @ Fail: ARM_MPU on NOT v7 PMSA
+
+ /* Determine whether the D/I-side memory map is unified. We set the
+ * flags here and continue to use them for the rest of this function */
+ mrc p15, 0, r0, c0, c0, 4 @ MPUIR
+ ands r5, r0, #MPUIR_DREGION_SZMASK @ 0 size d region => No MPU
+ beq __error_p @ Fail: ARM_MPU and no MPU
+ tst r0, #MPUIR_nU @ MPUIR_nU = 0 for unified
+
+ /* Setup second region first to free up r6 */
+ set_region_nr r0, #MPU_RAM_REGION
+ isb
+ /* Full access from PL0, PL1, shared for CONFIG_SMP, cacheable */
+ ldr r0, =PHYS_OFFSET @ RAM starts at PHYS_OFFSET
+ ldr r5,=(MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL)
+
+ setup_region r0, r5, r6, MPU_DATA_SIDE @ PHYS_OFFSET, shared, enabled
+ beq 1f @ Memory-map not unified
+ setup_region r0, r5, r6, MPU_INSTR_SIDE @ PHYS_OFFSET, shared, enabled
+1: isb
+
+ /* First/background region */
+ set_region_nr r0, #MPU_BG_REGION
+ isb
+ /* Execute Never, strongly ordered, inaccessible to PL0, rw PL1 */
+ mov r0, #0 @ BG region starts at 0x0
+ ldr r5,=(MPU_ACR_XN | MPU_RGN_STRONGLY_ORDERED | MPU_AP_PL1RW_PL0NA)
+ mov r6, #MPU_RSR_ALL_MEM @ 4GB region, enabled
+
+ setup_region r0, r5, r6, MPU_DATA_SIDE @ 0x0, BG region, enabled
+ beq 2f @ Memory-map not unified
+ setup_region r0, r5, r6, MPU_INSTR_SIDE @ 0x0, BG region, enabled
+2: isb
+
+ /* Vectors region */
+ set_region_nr r0, #MPU_VECTORS_REGION
+ isb
+ /* Shared, inaccessible to PL0, rw PL1 */
+ mov r0, #CONFIG_VECTORS_BASE @ Cover from VECTORS_BASE
+ ldr r5,=(MPU_AP_PL1RW_PL0NA | MPU_RGN_NORMAL)
+ /* Writing N to bits 5:1 (RSR_SZ) --> region size 2^N+1 */
+ mov r6, #(((PAGE_SHIFT - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN)
+
+ setup_region r0, r5, r6, MPU_DATA_SIDE @ VECTORS_BASE, PL0 NA, enabled
+ beq 3f @ Memory-map not unified
+ setup_region r0, r5, r6, MPU_INSTR_SIDE @ VECTORS_BASE, PL0 NA, enabled
+3: isb
+
+ /* Enable the MPU */
+ mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR
+ bic r0, r0, #CR_BR @ Disable the 'default mem-map'
+ orr r0, r0, #CR_M @ Set SCTRL.M (MPU on)
+ mcr p15, 0, r0, c1, c0, 0 @ Enable MPU
+ isb
+ mov pc,lr
+ENDPROC(__setup_mpu)
+#endif
#include "head-common.S"
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 8bac553fe213..45e8935cae4e 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -156,7 +156,7 @@ ENDPROC(stext)
*
* Returns:
* r0, r3, r5-r7 corrupted
- * r4 = physical page table address
+ * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
*/
__create_page_tables:
pgtbl r4, r8 @ page table address
@@ -331,6 +331,7 @@ __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
mov pc, lr
ENDPROC(__create_page_tables)
@@ -408,7 +409,7 @@ __secondary_data:
* r0 = cp#15 control register
* r1 = machine ID
* r2 = atags or dtb pointer
- * r4 = page table pointer
+ * r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
* r9 = processor ID
* r13 = *virtual* address to jump to upon completion
*/
@@ -427,10 +428,7 @@ __enable_mmu:
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
-#ifdef CONFIG_ARM_LPAE
- mov r5, #0
- mcrr p15, 0, r4, r5, c2 @ load TTBR0
-#else
+#ifndef CONFIG_ARM_LPAE
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/hyp-stub.S b/arch/arm/kernel/hyp-stub.S
index 1315c4ccfa56..4910232c4833 100644
--- a/arch/arm/kernel/hyp-stub.S
+++ b/arch/arm/kernel/hyp-stub.S
@@ -153,6 +153,13 @@ THUMB( orr r7, #(1 << 30) ) @ HSCTLR.TE
mrc p15, 4, r7, c14, c1, 0 @ CNTHCTL
orr r7, r7, #3 @ PL1PCEN | PL1PCTEN
mcr p15, 4, r7, c14, c1, 0 @ CNTHCTL
+ mov r7, #0
+ mcrr p15, 4, r7, r7, c14 @ CNTVOFF
+
+ @ Disable virtual timer in case it was counting
+ mrc p15, 0, r7, c14, c3, 1 @ CNTV_CTL
+ bic r7, #1 @ Clear ENABLE
+ mcr p15, 0, r7, c14, c3, 1 @ CNTV_CTL
1:
#endif
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 8c3094d0f7b7..d9f5cd4e533f 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -569,6 +569,7 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
return;
}
+ perf_callchain_store(entry, regs->ARM_pc);
tail = (struct frame_tail __user *)regs->ARM_fp - 1;
while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 6e8931ccf13e..d3ca4f6915af 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -32,6 +32,7 @@
#include <linux/hw_breakpoint.h>
#include <linux/cpuidle.h>
#include <linux/leds.h>
+#include <linux/reboot.h>
#include <asm/cacheflush.h>
#include <asm/idmap.h>
@@ -39,6 +40,7 @@
#include <asm/thread_notify.h>
#include <asm/stacktrace.h>
#include <asm/mach/time.h>
+#include <asm/tls.h>
#ifdef CONFIG_CC_STACKPROTECTOR
#include <linux/stackprotector.h>
@@ -112,7 +114,7 @@ void soft_restart(unsigned long addr)
BUG();
}
-static void null_restart(char mode, const char *cmd)
+static void null_restart(enum reboot_mode reboot_mode, const char *cmd)
{
}
@@ -122,7 +124,7 @@ static void null_restart(char mode, const char *cmd)
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
-void (*arm_pm_restart)(char str, const char *cmd) = null_restart;
+void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd) = null_restart;
EXPORT_SYMBOL_GPL(arm_pm_restart);
/*
@@ -174,16 +176,6 @@ void arch_cpu_idle(void)
default_idle();
}
-static char reboot_mode = 'h';
-
-int __init reboot_setup(char *str)
-{
- reboot_mode = str[0];
- return 1;
-}
-
-__setup("reboot=", reboot_setup);
-
/*
* Called by kexec, immediately prior to machine_kexec().
*
@@ -374,7 +366,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
clear_ptrace_hw_breakpoint(p);
if (clone_flags & CLONE_SETTLS)
- thread->tp_value = childregs->ARM_r3;
+ thread->tp_value[0] = childregs->ARM_r3;
+ thread->tp_value[1] = get_tpuser();
thread_notify(THREAD_NOTIFY_COPY, thread);
diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c
index 23a11424c568..219f1d73572a 100644
--- a/arch/arm/kernel/psci_smp.c
+++ b/arch/arm/kernel/psci_smp.c
@@ -68,8 +68,6 @@ void __ref psci_cpu_die(unsigned int cpu)
/* We should never return */
panic("psci: cpu %d failed to shutdown\n", cpu);
}
-#else
-#define psci_cpu_die NULL
#endif
bool __init psci_smp_available(void)
@@ -80,5 +78,7 @@ bool __init psci_smp_available(void)
struct smp_operations __initdata psci_smp_ops = {
.smp_boot_secondary = psci_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = psci_cpu_die,
+#endif
};
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 03deeffd9f6d..0dd3b79b15c3 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -849,7 +849,7 @@ long arch_ptrace(struct task_struct *child, long request,
#endif
case PTRACE_GET_THREAD_AREA:
- ret = put_user(task_thread_info(child)->tp_value,
+ ret = put_user(task_thread_info(child)->tp_value[0],
datap);
break;
@@ -886,20 +886,12 @@ long arch_ptrace(struct task_struct *child, long request,
#ifdef CONFIG_HAVE_HW_BREAKPOINT
case PTRACE_GETHBPREGS:
- if (ptrace_get_breakpoints(child) < 0)
- return -ESRCH;
-
ret = ptrace_gethbpregs(child, addr,
(unsigned long __user *)data);
- ptrace_put_breakpoints(child);
break;
case PTRACE_SETHBPREGS:
- if (ptrace_get_breakpoints(child) < 0)
- return -ESRCH;
-
ret = ptrace_sethbpregs(child, addr,
(unsigned long __user *)data);
- ptrace_put_breakpoints(child);
break;
#endif
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 1c8278de6c46..63af9a7ae512 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -74,7 +74,7 @@ __setup("fpe=", fpe_setup);
extern void paging_init(struct machine_desc *desc);
extern void sanity_check_meminfo(void);
-extern void reboot_setup(char *str);
+extern enum reboot_mode reboot_mode;
extern void setup_dma_zone(struct machine_desc *desc);
unsigned int processor_id;
@@ -367,7 +367,7 @@ void __init early_print(const char *str, ...)
static void __init cpuid_init_hwcaps(void)
{
- unsigned int divide_instrs;
+ unsigned int divide_instrs, vmsa;
if (cpu_architecture() < CPU_ARCH_ARMv7)
return;
@@ -380,6 +380,11 @@ static void __init cpuid_init_hwcaps(void)
case 1:
elf_hwcap |= HWCAP_IDIVT;
}
+
+ /* LPAE implies atomic ldrd/strd instructions */
+ vmsa = (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xf) >> 0;
+ if (vmsa >= 5)
+ elf_hwcap |= HWCAP_LPAE;
}
static void __init feat_v6_fixup(void)
@@ -470,9 +475,82 @@ void __init smp_setup_processor_id(void)
for (i = 1; i < nr_cpu_ids; ++i)
cpu_logical_map(i) = i == cpu ? 0 : i;
+ /*
+ * clear __my_cpu_offset on boot CPU to avoid hang caused by
+ * using percpu variable early, for example, lockdep will
+ * access percpu variable inside lock_release
+ */
+ set_my_cpu_offset(0);
+
printk(KERN_INFO "Booting Linux on physical CPU 0x%x\n", mpidr);
}
+struct mpidr_hash mpidr_hash;
+#ifdef CONFIG_SMP
+/**
+ * smp_build_mpidr_hash - Pre-compute shifts required at each affinity
+ * level in order to build a linear index from an
+ * MPIDR value. Resulting algorithm is a collision
+ * free hash carried out through shifting and ORing
+ */
+static void __init smp_build_mpidr_hash(void)
+{
+ u32 i, affinity;
+ u32 fs[3], bits[3], ls, mask = 0;
+ /*
+ * Pre-scan the list of MPIDRS and filter out bits that do
+ * not contribute to affinity levels, ie they never toggle.
+ */
+ for_each_possible_cpu(i)
+ mask |= (cpu_logical_map(i) ^ cpu_logical_map(0));
+ pr_debug("mask of set bits 0x%x\n", mask);
+ /*
+ * Find and stash the last and first bit set at all affinity levels to
+ * check how many bits are required to represent them.
+ */
+ for (i = 0; i < 3; i++) {
+ affinity = MPIDR_AFFINITY_LEVEL(mask, i);
+ /*
+ * Find the MSB bit and LSB bits position
+ * to determine how many bits are required
+ * to express the affinity level.
+ */
+ ls = fls(affinity);
+ fs[i] = affinity ? ffs(affinity) - 1 : 0;
+ bits[i] = ls - fs[i];
+ }
+ /*
+ * An index can be created from the MPIDR by isolating the
+ * significant bits at each affinity level and by shifting
+ * them in order to compress the 24 bits values space to a
+ * compressed set of values. This is equivalent to hashing
+ * the MPIDR through shifting and ORing. It is a collision free
+ * hash though not minimal since some levels might contain a number
+ * of CPUs that is not an exact power of 2 and their bit
+ * representation might contain holes, eg MPIDR[7:0] = {0x2, 0x80}.
+ */
+ mpidr_hash.shift_aff[0] = fs[0];
+ mpidr_hash.shift_aff[1] = MPIDR_LEVEL_BITS + fs[1] - bits[0];
+ mpidr_hash.shift_aff[2] = 2*MPIDR_LEVEL_BITS + fs[2] -
+ (bits[1] + bits[0]);
+ mpidr_hash.mask = mask;
+ mpidr_hash.bits = bits[2] + bits[1] + bits[0];
+ pr_debug("MPIDR hash: aff0[%u] aff1[%u] aff2[%u] mask[0x%x] bits[%u]\n",
+ mpidr_hash.shift_aff[0],
+ mpidr_hash.shift_aff[1],
+ mpidr_hash.shift_aff[2],
+ mpidr_hash.mask,
+ mpidr_hash.bits);
+ /*
+ * 4x is an arbitrary value used to warn on a hash table much bigger
+ * than expected on most systems.
+ */
+ if (mpidr_hash_size() > 4 * num_possible_cpus())
+ pr_warn("Large number of MPIDR hash buckets detected\n");
+ sync_cache_w(&mpidr_hash);
+}
+#endif
+
static void __init setup_processor(void)
{
struct proc_info_list *list;
@@ -783,8 +861,8 @@ void __init setup_arch(char **cmdline_p)
setup_dma_zone(mdesc);
- if (mdesc->restart_mode)
- reboot_setup(&mdesc->restart_mode);
+ if (mdesc->reboot_mode != REBOOT_HARD)
+ reboot_mode = mdesc->reboot_mode;
init_mm.start_code = (unsigned long) _text;
init_mm.end_code = (unsigned long) _etext;
@@ -820,6 +898,7 @@ void __init setup_arch(char **cmdline_p)
smp_set_ops(mdesc->smp);
}
smp_init_cpus();
+ smp_build_mpidr_hash();
}
#endif
@@ -892,6 +971,7 @@ static const char *hwcap_str[] = {
"vfpv4",
"idiva",
"idivt",
+ "lpae",
NULL
};
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 296786bdbb73..1c16c35c271a 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -392,14 +392,19 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
idx += 3;
+ /*
+ * Put the sigreturn code on the stack no matter which return
+ * mechanism we use in order to remain ABI compliant
+ */
if (__put_user(sigreturn_codes[idx], rc) ||
__put_user(sigreturn_codes[idx+1], rc+1))
return 1;
- if (cpsr & MODE32_BIT) {
+ if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) {
/*
* 32-bit code can use the new high-page
- * signal return code support.
+ * signal return code support except when the MPU has
+ * protected the vectors page from PL0
*/
retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
} else {
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index 987dcf33415c..db1536b8b30b 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -7,6 +7,49 @@
.text
/*
+ * Implementation of MPIDR hash algorithm through shifting
+ * and OR'ing.
+ *
+ * @dst: register containing hash result
+ * @rs0: register containing affinity level 0 bit shift
+ * @rs1: register containing affinity level 1 bit shift
+ * @rs2: register containing affinity level 2 bit shift
+ * @mpidr: register containing MPIDR value
+ * @mask: register containing MPIDR mask
+ *
+ * Pseudo C-code:
+ *
+ *u32 dst;
+ *
+ *compute_mpidr_hash(u32 rs0, u32 rs1, u32 rs2, u32 mpidr, u32 mask) {
+ * u32 aff0, aff1, aff2;
+ * u32 mpidr_masked = mpidr & mask;
+ * aff0 = mpidr_masked & 0xff;
+ * aff1 = mpidr_masked & 0xff00;
+ * aff2 = mpidr_masked & 0xff0000;
+ * dst = (aff0 >> rs0 | aff1 >> rs1 | aff2 >> rs2);
+ *}
+ * Input registers: rs0, rs1, rs2, mpidr, mask
+ * Output register: dst
+ * Note: input and output registers must be disjoint register sets
+ (eg: a macro instance with mpidr = r1 and dst = r1 is invalid)
+ */
+ .macro compute_mpidr_hash dst, rs0, rs1, rs2, mpidr, mask
+ and \mpidr, \mpidr, \mask @ mask out MPIDR bits
+ and \dst, \mpidr, #0xff @ mask=aff0
+ ARM( mov \dst, \dst, lsr \rs0 ) @ dst=aff0>>rs0
+ THUMB( lsr \dst, \dst, \rs0 )
+ and \mask, \mpidr, #0xff00 @ mask = aff1
+ ARM( orr \dst, \dst, \mask, lsr \rs1 ) @ dst|=(aff1>>rs1)
+ THUMB( lsr \mask, \mask, \rs1 )
+ THUMB( orr \dst, \dst, \mask )
+ and \mask, \mpidr, #0xff0000 @ mask = aff2
+ ARM( orr \dst, \dst, \mask, lsr \rs2 ) @ dst|=(aff2>>rs2)
+ THUMB( lsr \mask, \mask, \rs2 )
+ THUMB( orr \dst, \dst, \mask )
+ .endm
+
+/*
* Save CPU state for a suspend. This saves the CPU general purpose
* registers, and allocates space on the kernel stack to save the CPU
* specific registers and some other data for resume.
@@ -29,12 +72,18 @@ ENTRY(__cpu_suspend)
mov r1, r4 @ size of save block
mov r2, r5 @ virtual SP
ldr r3, =sleep_save_sp
-#ifdef CONFIG_SMP
- ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
- ALT_UP(mov lr, #0)
- and lr, lr, #15
+ ldr r3, [r3, #SLEEP_SAVE_SP_VIRT]
+ ALT_SMP(mrc p15, 0, r9, c0, c0, 5)
+ ALT_UP_B(1f)
+ ldr r8, =mpidr_hash
+ /*
+ * This ldmia relies on the memory layout of the mpidr_hash
+ * struct mpidr_hash.
+ */
+ ldmia r8, {r4-r7} @ r4 = mpidr mask (r5,r6,r7) = l[0,1,2] shifts
+ compute_mpidr_hash lr, r5, r6, r7, r9, r4
add r3, r3, lr, lsl #2
-#endif
+1:
bl __cpu_suspend_save
adr lr, BSYM(cpu_suspend_abort)
ldmfd sp!, {r0, pc} @ call suspend fn
@@ -81,15 +130,23 @@ ENDPROC(cpu_resume_after_mmu)
.data
.align
ENTRY(cpu_resume)
-#ifdef CONFIG_SMP
- adr r0, sleep_save_sp
- ALT_SMP(mrc p15, 0, r1, c0, c0, 5)
- ALT_UP(mov r1, #0)
- and r1, r1, #15
- ldr r0, [r0, r1, lsl #2] @ stack phys addr
-#else
- ldr r0, sleep_save_sp @ stack phys addr
-#endif
+ mov r1, #0
+ ALT_SMP(mrc p15, 0, r0, c0, c0, 5)
+ ALT_UP_B(1f)
+ adr r2, mpidr_hash_ptr
+ ldr r3, [r2]
+ add r2, r2, r3 @ r2 = struct mpidr_hash phys address
+ /*
+ * This ldmia relies on the memory layout of the mpidr_hash
+ * struct mpidr_hash.
+ */
+ ldmia r2, { r3-r6 } @ r3 = mpidr mask (r4,r5,r6) = l[0,1,2] shifts
+ compute_mpidr_hash r1, r4, r5, r6, r0, r3
+1:
+ adr r0, _sleep_save_sp
+ ldr r0, [r0, #SLEEP_SAVE_SP_PHYS]
+ ldr r0, [r0, r1, lsl #2]
+
setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off
@ load phys pgd, stack, resume fn
ARM( ldmia r0!, {r1, sp, pc} )
@@ -98,7 +155,11 @@ THUMB( mov sp, r2 )
THUMB( bx r3 )
ENDPROC(cpu_resume)
-sleep_save_sp:
- .rept CONFIG_NR_CPUS
- .long 0 @ preserve stack phys ptr here
- .endr
+ .align 2
+mpidr_hash_ptr:
+ .long mpidr_hash - . @ mpidr_hash struct offset
+
+ .type sleep_save_sp, #object
+ENTRY(sleep_save_sp)
+_sleep_save_sp:
+ .space SLEEP_SAVE_SP_SZ @ struct sleep_save_sp
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 5919eb451bb9..c5fb5469054b 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -45,6 +45,7 @@
#include <asm/smp_plat.h>
#include <asm/virt.h>
#include <asm/mach/arch.h>
+#include <asm/mpu.h>
/*
* as from 2.5, kernels no longer have an init_tasks structure
@@ -78,6 +79,13 @@ void __init smp_set_ops(struct smp_operations *ops)
smp_ops = *ops;
};
+static unsigned long get_arch_pgd(pgd_t *pgd)
+{
+ phys_addr_t pgdir = virt_to_phys(pgd);
+ BUG_ON(pgdir & ARCH_PGD_MASK);
+ return pgdir >> ARCH_PGD_SHIFT;
+}
+
int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
{
int ret;
@@ -87,8 +95,14 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
* its stack and the page tables.
*/
secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
- secondary_data.pgdir = virt_to_phys(idmap_pgd);
- secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
+#ifdef CONFIG_ARM_MPU
+ secondary_data.mpu_rgn_szr = mpu_rgn_info.rgns[MPU_RAM_REGION].drsr;
+#endif
+
+#ifdef CONFIG_MMU
+ secondary_data.pgdir = get_arch_pgd(idmap_pgd);
+ secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
+#endif
__cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
@@ -112,9 +126,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
}
- secondary_data.stack = NULL;
- secondary_data.pgdir = 0;
+ memset(&secondary_data, 0, sizeof(secondary_data));
return ret;
}
diff --git a/arch/arm/kernel/smp_tlb.c b/arch/arm/kernel/smp_tlb.c
index 9a52a07aa40e..a98b62dca2fa 100644
--- a/arch/arm/kernel/smp_tlb.c
+++ b/arch/arm/kernel/smp_tlb.c
@@ -103,7 +103,7 @@ static void broadcast_tlb_a15_erratum(void)
static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
{
- int cpu, this_cpu;
+ int this_cpu;
cpumask_t mask = { CPU_BITS_NONE };
if (!erratum_a15_798181())
@@ -111,21 +111,7 @@ static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
dummy_flush_tlb_a15_erratum();
this_cpu = get_cpu();
- for_each_online_cpu(cpu) {
- if (cpu == this_cpu)
- continue;
- /*
- * We only need to send an IPI if the other CPUs are running
- * the same ASID as the one being invalidated. There is no
- * need for locking around the active_asids check since the
- * switch_mm() function has at least one dmb() (as required by
- * this workaround) in case a context switch happens on
- * another CPU after the condition below.
- */
- if (atomic64_read(&mm->context.id) ==
- atomic64_read(&per_cpu(active_asids, cpu)))
- cpumask_set_cpu(cpu, &mask);
- }
+ a15_erratum_get_cpumask(this_cpu, mm, &mask);
smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
put_cpu();
}
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
index c59c97ea8268..41cf3cbf756d 100644
--- a/arch/arm/kernel/suspend.c
+++ b/arch/arm/kernel/suspend.c
@@ -1,15 +1,54 @@
#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
#include <asm/idmap.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/memory.h>
+#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include <asm/tlbflush.h>
extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
extern void cpu_resume_mmu(void);
+#ifdef CONFIG_MMU
+/*
+ * Hide the first two arguments to __cpu_suspend - these are an implementation
+ * detail which platform code shouldn't have to know about.
+ */
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+ struct mm_struct *mm = current->active_mm;
+ int ret;
+
+ if (!idmap_pgd)
+ return -EINVAL;
+
+ /*
+ * Provide a temporary page table with an identity mapping for
+ * the MMU-enable code, required for resuming. On successful
+ * resume (indicated by a zero return code), we need to switch
+ * back to the correct page tables.
+ */
+ ret = __cpu_suspend(arg, fn);
+ if (ret == 0) {
+ cpu_switch_mm(mm->pgd, mm);
+ local_flush_bp_all();
+ local_flush_tlb_all();
+ }
+
+ return ret;
+}
+#else
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+ return __cpu_suspend(arg, fn);
+}
+#define idmap_pgd NULL
+#endif
+
/*
* This is called by __cpu_suspend() to save the state, and do whatever
* flushing is required to ensure that when the CPU goes to sleep we have
@@ -47,30 +86,19 @@ void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
virt_to_phys(save_ptr) + sizeof(*save_ptr));
}
-/*
- * Hide the first two arguments to __cpu_suspend - these are an implementation
- * detail which platform code shouldn't have to know about.
- */
-int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
-{
- struct mm_struct *mm = current->active_mm;
- int ret;
-
- if (!idmap_pgd)
- return -EINVAL;
+extern struct sleep_save_sp sleep_save_sp;
- /*
- * Provide a temporary page table with an identity mapping for
- * the MMU-enable code, required for resuming. On successful
- * resume (indicated by a zero return code), we need to switch
- * back to the correct page tables.
- */
- ret = __cpu_suspend(arg, fn);
- if (ret == 0) {
- cpu_switch_mm(mm->pgd, mm);
- local_flush_bp_all();
- local_flush_tlb_all();
- }
+static int cpu_suspend_alloc_sp(void)
+{
+ void *ctx_ptr;
+ /* ctx_ptr is an array of physical addresses */
+ ctx_ptr = kcalloc(mpidr_hash_size(), sizeof(u32), GFP_KERNEL);
- return ret;
+ if (WARN_ON(!ctx_ptr))
+ return -ENOMEM;
+ sleep_save_sp.save_ptr_stash = ctx_ptr;
+ sleep_save_sp.save_ptr_stash_phys = virt_to_phys(ctx_ptr);
+ sync_cache_w(&sleep_save_sp);
+ return 0;
}
+early_initcall(cpu_suspend_alloc_sp);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index abff4e9aaee0..98aee3258398 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -24,9 +24,9 @@
#include <linux/timer.h>
#include <linux/clocksource.h>
#include <linux/irq.h>
+#include <linux/sched_clock.h>
#include <asm/thread_info.h>
-#include <asm/sched_clock.h>
#include <asm/stacktrace.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
@@ -120,6 +120,4 @@ void __init time_init(void)
machine_desc->init_time();
else
clocksource_of_init();
-
- sched_clock_postinit();
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 486e12a0f26a..cab094c234ee 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -581,7 +581,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
return regs->ARM_r0;
case NR(set_tls):
- thread->tp_value = regs->ARM_r0;
+ thread->tp_value[0] = regs->ARM_r0;
if (tls_emu)
return 0;
if (has_tls_reg) {
@@ -699,7 +699,7 @@ static int get_tp_trap(struct pt_regs *regs, unsigned int instr)
int reg = (instr >> 12) & 15;
if (reg == 15)
return 1;
- regs->uregs[reg] = current_thread_info()->tp_value;
+ regs->uregs[reg] = current_thread_info()->tp_value[0];
regs->ARM_pc += 4;
return 0;
}
diff --git a/arch/arm/kvm/Kconfig b/arch/arm/kvm/Kconfig
index 370e1a8af6ac..ebf5015508b5 100644
--- a/arch/arm/kvm/Kconfig
+++ b/arch/arm/kvm/Kconfig
@@ -41,9 +41,9 @@ config KVM_ARM_HOST
Provides host support for ARM processors.
config KVM_ARM_MAX_VCPUS
- int "Number maximum supported virtual CPUs per VM" if KVM_ARM_HOST
- default 4 if KVM_ARM_HOST
- default 0
+ int "Number maximum supported virtual CPUs per VM"
+ depends on KVM_ARM_HOST
+ default 4
help
Static number of max supported virtual CPUs per VM.
@@ -67,6 +67,4 @@ config KVM_ARM_TIMER
---help---
Adds support for the Architected Timers in virtual machines
-source drivers/virtio/Kconfig
-
endif # VIRTUALIZATION
diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile
index 53c5ed83d16f..d99bee4950e5 100644
--- a/arch/arm/kvm/Makefile
+++ b/arch/arm/kvm/Makefile
@@ -14,10 +14,11 @@ CFLAGS_mmu.o := -I.
AFLAGS_init.o := -Wa,-march=armv7-a$(plus_virt)
AFLAGS_interrupts.o := -Wa,-march=armv7-a$(plus_virt)
-kvm-arm-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
+KVM := ../../../virt/kvm
+kvm-arm-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.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
obj-y += coproc.o coproc_a15.o mmio.o psci.o perf.o
-obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
-obj-$(CONFIG_KVM_ARM_TIMER) += arch_timer.o
+obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index ef1703b9587b..741f66a2edbd 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -800,8 +800,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
static void cpu_init_hyp_mode(void *dummy)
{
- unsigned long long boot_pgd_ptr;
- unsigned long long pgd_ptr;
+ phys_addr_t boot_pgd_ptr;
+ phys_addr_t pgd_ptr;
unsigned long hyp_stack_ptr;
unsigned long stack_page;
unsigned long vector_ptr;
@@ -809,8 +809,8 @@ static void cpu_init_hyp_mode(void *dummy)
/* Switch from the HYP stub to our own HYP init vector */
__hyp_set_vectors(kvm_get_idmap_vector());
- boot_pgd_ptr = (unsigned long long)kvm_mmu_get_boot_httbr();
- pgd_ptr = (unsigned long long)kvm_mmu_get_httbr();
+ boot_pgd_ptr = kvm_mmu_get_boot_httbr();
+ pgd_ptr = kvm_mmu_get_httbr();
stack_page = __get_cpu_var(kvm_arm_hyp_stack_page);
hyp_stack_ptr = stack_page + PAGE_SIZE;
vector_ptr = (unsigned long)__kvm_hyp_vector;
diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c
index 8eea97be1ed5..4a5199070430 100644
--- a/arch/arm/kvm/coproc.c
+++ b/arch/arm/kvm/coproc.c
@@ -180,6 +180,10 @@ static const struct coproc_reg cp15_regs[] = {
NULL, reset_unknown, c6_DFAR },
{ CRn( 6), CRm( 0), Op1( 0), Op2( 2), is32,
NULL, reset_unknown, c6_IFAR },
+
+ /* PAR swapped by interrupt.S */
+ { CRn( 7), Op1( 0), is64, NULL, reset_unknown64, c7_PAR },
+
/*
* DC{C,I,CI}SW operations:
*/
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 3d74a0be47db..df4c82d47ad7 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -52,9 +52,6 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
- if (kvm_psci_call(vcpu))
- return 1;
-
kvm_inject_undefined(vcpu);
return 1;
}
diff --git a/arch/arm/kvm/interrupts.S b/arch/arm/kvm/interrupts.S
index f7793df62f58..16cd4ba5d7fd 100644
--- a/arch/arm/kvm/interrupts.S
+++ b/arch/arm/kvm/interrupts.S
@@ -49,6 +49,7 @@ __kvm_hyp_code_start:
ENTRY(__kvm_tlb_flush_vmid_ipa)
push {r2, r3}
+ dsb ishst
add r0, r0, #KVM_VTTBR
ldrd r2, r3, [r0]
mcrr p15, 6, r2, r3, c2 @ Write VTTBR
@@ -291,6 +292,7 @@ THUMB( orr r2, r2, #PSR_T_BIT )
ldr r2, =BSYM(panic)
msr ELR_hyp, r2
ldr r0, =\panic_str
+ clrex @ Clear exclusive monitor
eret
.endm
@@ -414,6 +416,10 @@ guest_trap:
mrcne p15, 4, r2, c6, c0, 4 @ HPFAR
bne 3f
+ /* Preserve PAR */
+ mrrc p15, 0, r0, r1, c7 @ PAR
+ push {r0, r1}
+
/* Resolve IPA using the xFAR */
mcr p15, 0, r2, c7, c8, 0 @ ATS1CPR
isb
@@ -424,13 +430,20 @@ guest_trap:
lsl r2, r2, #4
orr r2, r2, r1, lsl #24
+ /* Restore PAR */
+ pop {r0, r1}
+ mcrr p15, 0, r0, r1, c7 @ PAR
+
3: load_vcpu @ Load VCPU pointer to r0
str r2, [r0, #VCPU_HPFAR]
1: mov r1, #ARM_EXCEPTION_HVC
b __kvm_vcpu_return
-4: pop {r0, r1, r2} @ Failed translation, return to guest
+4: pop {r0, r1} @ Failed translation, return to guest
+ mcrr p15, 0, r0, r1, c7 @ PAR
+ clrex
+ pop {r0, r1, r2}
eret
/*
@@ -456,6 +469,7 @@ switch_to_guest_vfp:
pop {r3-r7}
pop {r0-r2}
+ clrex
eret
#endif
diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S
index 3c8f2f0b4c5e..6f18695a09cb 100644
--- a/arch/arm/kvm/interrupts_head.S
+++ b/arch/arm/kvm/interrupts_head.S
@@ -302,11 +302,14 @@ vcpu .req r0 @ vcpu pointer always in r0
.endif
mrc p15, 0, r2, c14, c1, 0 @ CNTKCTL
+ mrrc p15, 0, r4, r5, c7 @ PAR
.if \store_to_vcpu == 0
- push {r2}
+ push {r2,r4-r5}
.else
str r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+ add r12, vcpu, #CP15_OFFSET(c7_PAR)
+ strd r4, r5, [r12]
.endif
.endm
@@ -319,12 +322,15 @@ vcpu .req r0 @ vcpu pointer always in r0
*/
.macro write_cp15_state read_from_vcpu
.if \read_from_vcpu == 0
- pop {r2}
+ pop {r2,r4-r5}
.else
ldr r2, [vcpu, #CP15_OFFSET(c14_CNTKCTL)]
+ add r12, vcpu, #CP15_OFFSET(c7_PAR)
+ ldrd r4, r5, [r12]
.endif
mcr p15, 0, r2, c14, c1, 0 @ CNTKCTL
+ mcrr p15, 0, r4, r5, c7 @ PAR
.if \read_from_vcpu == 0
pop {r2-r12}
@@ -497,6 +503,10 @@ vcpu .req r0 @ vcpu pointer always in r0
add r5, vcpu, r4
strd r2, r3, [r5]
+ @ Ensure host CNTVCT == CNTPCT
+ mov r2, #0
+ mcrr p15, 4, r2, r2, c14 @ CNTVOFF
+
1:
#endif
@ Allow physical timer/counter access for the host
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 72a12f2171b2..b8e06b7a2833 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -86,12 +86,6 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
sign_extend = kvm_vcpu_dabt_issext(vcpu);
rt = kvm_vcpu_dabt_get_rd(vcpu);
- if (kvm_vcpu_reg_is_pc(vcpu, rt)) {
- /* IO memory trying to read/write pc */
- kvm_inject_pabt(vcpu, kvm_vcpu_get_hfar(vcpu));
- return 1;
- }
-
mmio->is_write = is_write;
mmio->phys_addr = fault_ipa;
mmio->len = len;
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 84ba67b982c0..ca6bea4859b4 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -382,9 +382,6 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
if (!pgd)
return -ENOMEM;
- /* stage-2 pgd must be aligned to its size */
- VM_BUG_ON((unsigned long)pgd & (S2_PGD_SIZE - 1));
-
memset(pgd, 0, PTRS_PER_S2_PGD * sizeof(pgd_t));
kvm_clean_pgd(pgd);
kvm->arch.pgd = pgd;
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index 7ee5bb7a3667..86a693a02ba3 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
* kvm_psci_call - handle PSCI call if r0 value is in range
* @vcpu: Pointer to the VCPU struct
*
- * Handle PSCI calls from guests through traps from HVC or SMC instructions.
+ * Handle PSCI calls from guests through traps from HVC instructions.
* The calling convention is similar to SMC calls to the secure world where
* the function number is placed in r0 and this function returns true if the
* function number specified in r0 is withing the PSCI range, and false
diff --git a/arch/arm/kvm/reset.c b/arch/arm/kvm/reset.c
index b80256b554cd..b7840e7aa452 100644
--- a/arch/arm/kvm/reset.c
+++ b/arch/arm/kvm/reset.c
@@ -27,6 +27,8 @@
#include <asm/kvm_arm.h>
#include <asm/kvm_coproc.h>
+#include <kvm/arm_arch_timer.h>
+
/******************************************************************************
* Cortex-A15 Reset Values
*/
@@ -37,6 +39,11 @@ static struct kvm_regs a15_regs_reset = {
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
};
+static const struct kvm_irq_level a15_vtimer_irq = {
+ .irq = 27,
+ .level = 1,
+};
+
/*******************************************************************************
* Exported reset function
@@ -52,6 +59,7 @@ static struct kvm_regs a15_regs_reset = {
int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
{
struct kvm_regs *cpu_reset;
+ const struct kvm_irq_level *cpu_vtimer_irq;
switch (vcpu->arch.target) {
case KVM_ARM_TARGET_CORTEX_A15:
@@ -59,6 +67,7 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
return -EINVAL;
cpu_reset = &a15_regs_reset;
vcpu->arch.midr = read_cpuid_id();
+ cpu_vtimer_irq = &a15_vtimer_irq;
break;
default:
return -ENODEV;
@@ -70,5 +79,8 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
/* Reset CP15 registers */
kvm_reset_coprocs(vcpu);
+ /* Reset arch_timer context */
+ kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+
return 0;
}
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 9eb574397ee1..4aad93d54d6f 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
+#include <linux/reboot.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
@@ -304,7 +305,7 @@ static void at91rm9200_idle(void)
at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
}
-static void at91rm9200_restart(char mode, const char *cmd)
+static void at91rm9200_restart(enum reboot_mode reboot_mode, const char *cmd)
{
/*
* Perform a hardware reset with the use of the Watchdog timer.
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index f6de36aefe85..dc6e2f5f804d 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -10,6 +10,7 @@
#include <linux/clkdev.h>
#include <linux/of.h>
+#include <linux/reboot.h>
/* Map io */
extern void __init at91_map_io(void);
@@ -60,8 +61,8 @@ extern void at91sam9_idle(void);
/* reset */
extern void at91_ioremap_rstc(u32 base_addr);
-extern void at91sam9_alt_restart(char, const char *);
-extern void at91sam9g45_restart(char, const char *);
+extern void at91sam9_alt_restart(enum reboot_mode, const char *);
+extern void at91sam9g45_restart(enum reboot_mode, const char *);
/* shutdown */
extern void at91_ioremap_shdwc(u32 base_addr);
diff --git a/arch/arm/mach-bcm2835/bcm2835.c b/arch/arm/mach-bcm2835/bcm2835.c
index 740fa9ebe249..40686d7ef500 100644
--- a/arch/arm/mach-bcm2835/bcm2835.c
+++ b/arch/arm/mach-bcm2835/bcm2835.c
@@ -53,7 +53,7 @@ static void bcm2835_setup_restart(void)
WARN(!wdt_regs, "failed to remap watchdog regs");
}
-static void bcm2835_restart(char mode, const char *cmd)
+static void bcm2835_restart(enum reboot_mode mode, const char *cmd)
{
u32 val;
@@ -91,7 +91,7 @@ static void bcm2835_power_off(void)
writel_relaxed(val, wdt_regs + PM_RSTS);
/* Continue with normal reset mechanism */
- bcm2835_restart(0, "");
+ bcm2835_restart(REBOOT_HARD, "");
}
static struct map_desc io_map __initdata = {
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index f6d1746366d4..4ca2f3ca2de4 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -384,7 +384,7 @@ void __init clps711x_timer_init(void)
setup_irq(IRQ_TC2OI, &clps711x_timer_irq);
}
-void clps711x_restart(char mode, const char *cmd)
+void clps711x_restart(enum reboot_mode mode, const char *cmd)
{
soft_restart(0);
}
diff --git a/arch/arm/mach-clps711x/common.h b/arch/arm/mach-clps711x/common.h
index 2a22f4c6cc75..9a6767bfdc47 100644
--- a/arch/arm/mach-clps711x/common.h
+++ b/arch/arm/mach-clps711x/common.h
@@ -4,6 +4,8 @@
* Common bits.
*/
+#include <linux/reboot.h>
+
#define CLPS711X_NR_IRQS (33)
#define CLPS711X_NR_GPIO (4 * 8 + 3)
#define CLPS711X_GPIO(prt, bit) ((prt) * 8 + (bit))
@@ -12,5 +14,5 @@ extern void clps711x_map_io(void);
extern void clps711x_init_irq(void);
extern void clps711x_timer_init(void);
extern void clps711x_handle_irq(struct pt_regs *regs);
-extern void clps711x_restart(char mode, const char *cmd);
+extern void clps711x_restart(enum reboot_mode mode, const char *cmd);
extern void clps711x_init_early(void);
diff --git a/arch/arm/mach-cns3xxx/core.h b/arch/arm/mach-cns3xxx/core.h
index b23b17b4da10..5218b6198dc2 100644
--- a/arch/arm/mach-cns3xxx/core.h
+++ b/arch/arm/mach-cns3xxx/core.h
@@ -11,6 +11,8 @@
#ifndef __CNS3XXX_CORE_H
#define __CNS3XXX_CORE_H
+#include <linux/reboot.h>
+
extern void cns3xxx_timer_init(void);
#ifdef CONFIG_CACHE_L2X0
@@ -22,6 +24,6 @@ static inline void cns3xxx_l2x0_init(void) {}
void __init cns3xxx_map_io(void);
void __init cns3xxx_init_irq(void);
void cns3xxx_power_off(void);
-void cns3xxx_restart(char, const char *);
+void cns3xxx_restart(enum reboot_mode, const char *);
#endif /* __CNS3XXX_CORE_H */
diff --git a/arch/arm/mach-cns3xxx/pm.c b/arch/arm/mach-cns3xxx/pm.c
index 79e3d47aad65..fb38c726e987 100644
--- a/arch/arm/mach-cns3xxx/pm.c
+++ b/arch/arm/mach-cns3xxx/pm.c
@@ -89,7 +89,7 @@ void cns3xxx_pwr_soft_rst(unsigned int block)
}
EXPORT_SYMBOL(cns3xxx_pwr_soft_rst);
-void cns3xxx_restart(char mode, const char *cmd)
+void cns3xxx_restart(enum reboot_mode mode, const char *cmd)
{
/*
* To reset, we hit the on-board reset register
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig
index a075b3e0c5c7..e026b19b23ea 100644
--- a/arch/arm/mach-davinci/Kconfig
+++ b/arch/arm/mach-davinci/Kconfig
@@ -40,6 +40,7 @@ config ARCH_DAVINCI_DA850
bool "DA850/OMAP-L138/AM18x based system"
select ARCH_DAVINCI_DA8XX
select ARCH_HAS_CPUFREQ
+ select CPU_FREQ_TABLE
select CP_INTC
config ARCH_DAVINCI_DA8XX
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 8a24b6c6339f..bea6793a7ede 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -985,7 +985,6 @@ static struct regulator_init_data tps65070_regulator_data[] = {
static struct touchscreen_init_data tps6507x_touchscreen_data = {
.poll_period = 30, /* ms between touch samples */
.min_pressure = 0x30, /* minimum pressure to trigger touch */
- .vref = 0, /* turn off vref when not using A/D */
.vendor = 0, /* /sys/class/input/input?/id/vendor */
.product = 65070, /* /sys/class/input/input?/id/product */
.version = 0x100, /* /sys/class/input/input?/id/version */
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 4d6933848abf..a0d4f6038b60 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -1004,7 +1004,7 @@ static const struct da850_opp da850_opp_96 = {
#define OPP(freq) \
{ \
- .index = (unsigned int) &da850_opp_##freq, \
+ .driver_data = (unsigned int) &da850_opp_##freq, \
.frequency = freq * 1000, \
}
@@ -1016,7 +1016,7 @@ static struct cpufreq_frequency_table da850_freq_table[] = {
OPP(200),
OPP(96),
{
- .index = 0,
+ .driver_data = 0,
.frequency = CPUFREQ_TABLE_END,
},
};
@@ -1044,7 +1044,7 @@ static int da850_set_voltage(unsigned int index)
if (!cvdd)
return -ENODEV;
- opp = (struct da850_opp *) cpufreq_info.freq_table[index].index;
+ opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
return regulator_set_voltage(cvdd, opp->cvdd_min, opp->cvdd_max);
}
@@ -1125,7 +1125,7 @@ static int da850_set_pll0rate(struct clk *clk, unsigned long index)
struct pll_data *pll = clk->pll_data;
int ret;
- opp = (struct da850_opp *) cpufreq_info.freq_table[index].index;
+ opp = (struct da850_opp *) cpufreq_info.freq_table[index].driver_data;
prediv = opp->prediv;
mult = opp->mult;
postdiv = opp->postdiv;
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index eb254fe861ac..71a46a348761 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -16,6 +16,7 @@
#include <linux/serial_8250.h>
#include <linux/ahci_platform.h>
#include <linux/clk.h>
+#include <linux/reboot.h>
#include <mach/cputype.h>
#include <mach/common.h>
@@ -366,7 +367,7 @@ static struct platform_device da8xx_wdt_device = {
.resource = da8xx_watchdog_resources,
};
-void da8xx_restart(char mode, const char *cmd)
+void da8xx_restart(enum reboot_mode mode, const char *cmd)
{
struct device *dev;
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
index 90b83d00fe2b..111573c0aad1 100644
--- a/arch/arm/mach-davinci/devices.c
+++ b/arch/arm/mach-davinci/devices.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
#include <linux/platform_data/i2c-davinci.h>
@@ -307,7 +308,7 @@ struct platform_device davinci_wdt_device = {
.resource = wdt_resources,
};
-void davinci_restart(char mode, const char *cmd)
+void davinci_restart(enum reboot_mode mode, const char *cmd)
{
davinci_watchdog_reset(&davinci_wdt_device);
}
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index b124b77c90c5..cce316b92c06 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/types.h>
+#include <linux/reboot.h>
extern void davinci_timer_init(void);
@@ -81,7 +82,7 @@ extern struct davinci_soc_info davinci_soc_info;
extern void davinci_common_init(struct davinci_soc_info *soc_info);
extern void davinci_init_ide(void);
-void davinci_restart(char mode, const char *cmd);
+void davinci_restart(enum reboot_mode mode, const char *cmd);
void davinci_init_late(void);
#ifdef CONFIG_DAVINCI_RESET_CLOCKS
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 3c797e2272f8..7b41a5e9bc31 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -17,6 +17,7 @@
#include <linux/davinci_emac.h>
#include <linux/spi/spi.h>
#include <linux/platform_data/davinci_asp.h>
+#include <linux/reboot.h>
#include <linux/videodev2.h>
#include <mach/serial.h>
@@ -106,7 +107,7 @@ int da850_register_vpif_display
(struct vpif_display_config *display_config);
int da850_register_vpif_capture
(struct vpif_capture_config *capture_config);
-void da8xx_restart(char mode, const char *cmd);
+void da8xx_restart(enum reboot_mode mode, const char *cmd);
void da8xx_rproc_reserve_cma(void);
int da8xx_register_rproc(void);
diff --git a/arch/arm/mach-davinci/include/mach/tnetv107x.h b/arch/arm/mach-davinci/include/mach/tnetv107x.h
index 366e975effa8..16314c64f755 100644
--- a/arch/arm/mach-davinci/include/mach/tnetv107x.h
+++ b/arch/arm/mach-davinci/include/mach/tnetv107x.h
@@ -35,6 +35,7 @@
#include <linux/serial_8250.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/ti_ssp.h>
+#include <linux/reboot.h>
#include <linux/platform_data/mmc-davinci.h>
#include <linux/platform_data/mtd-davinci.h>
@@ -54,7 +55,7 @@ extern struct platform_device tnetv107x_serial_device;
extern void tnetv107x_init(void);
extern void tnetv107x_devices_init(struct tnetv107x_device_info *);
extern void tnetv107x_irq_init(void);
-void tnetv107x_restart(char mode, const char *cmd);
+void tnetv107x_restart(enum reboot_mode mode, const char *cmd);
#endif
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index bad361ec1666..7a55b5c95971 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -18,8 +18,8 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
diff --git a/arch/arm/mach-davinci/tnetv107x.c b/arch/arm/mach-davinci/tnetv107x.c
index 3b2a70d43efa..4545667ecd3c 100644
--- a/arch/arm/mach-davinci/tnetv107x.c
+++ b/arch/arm/mach-davinci/tnetv107x.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <asm/mach/map.h>
@@ -730,7 +731,7 @@ static void tnetv107x_watchdog_reset(struct platform_device *pdev)
__raw_writel(1, &regs->kick);
}
-void tnetv107x_restart(char mode, const char *cmd)
+void tnetv107x_restart(enum reboot_mode mode, const char *cmd)
{
tnetv107x_watchdog_reset(&tnetv107x_wdt_device);
}
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index 2a9443d04d92..00247c771313 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -381,7 +381,7 @@ void __init dove_init(void)
dove_xor1_init();
}
-void dove_restart(char mode, const char *cmd)
+void dove_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Enable soft reset to assert RSTOUTn.
diff --git a/arch/arm/mach-dove/common.h b/arch/arm/mach-dove/common.h
index e86347928b67..1d725224d146 100644
--- a/arch/arm/mach-dove/common.h
+++ b/arch/arm/mach-dove/common.h
@@ -11,6 +11,8 @@
#ifndef __ARCH_DOVE_COMMON_H
#define __ARCH_DOVE_COMMON_H
+#include <linux/reboot.h>
+
struct mv643xx_eth_platform_data;
struct mv_sata_platform_data;
@@ -42,6 +44,6 @@ void dove_spi1_init(void);
void dove_i2c_init(void);
void dove_sdio0_init(void);
void dove_sdio1_init(void);
-void dove_restart(char, const char *);
+void dove_restart(enum reboot_mode, const char *);
#endif
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index b13cc74114db..68ac934d4565 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -116,7 +116,7 @@ static void __init ebsa110_map_io(void)
iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
}
-static void __iomem *ebsa110_ioremap_caller(unsigned long cookie, size_t size,
+static void __iomem *ebsa110_ioremap_caller(phys_addr_t cookie, size_t size,
unsigned int flags, void *caller)
{
return (void __iomem *)cookie;
@@ -311,7 +311,7 @@ static int __init ebsa110_init(void)
arch_initcall(ebsa110_init);
-static void ebsa110_restart(char mode, const char *cmd)
+static void ebsa110_restart(enum reboot_mode mode, const char *cmd)
{
soft_restart(0x80000000);
}
@@ -321,7 +321,6 @@ MACHINE_START(EBSA110, "EBSA110")
.atag_offset = 0x400,
.reserve_lp0 = 1,
.reserve_lp2 = 1,
- .restart_mode = 's',
.map_io = ebsa110_map_io,
.init_early = ebsa110_init_early,
.init_irq = ebsa110_init_irq,
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index c49ed3dc1aea..df8612fbbc9c 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -35,6 +35,7 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
#include <linux/irqchip/arm-vic.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
#include <linux/platform_data/video-ep93xx.h>
@@ -921,7 +922,7 @@ void __init ep93xx_init_devices(void)
gpio_led_register_device(-1, &ep93xx_led_data);
}
-void ep93xx_restart(char mode, const char *cmd)
+void ep93xx_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Set then clear the SWRST bit to initiate a software reset
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index a14e1b37beff..e256e0baec2e 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -4,6 +4,8 @@
#ifndef __ASSEMBLY__
+#include <linux/reboot.h>
+
struct i2c_gpio_platform_data;
struct i2c_board_info;
struct spi_board_info;
@@ -55,7 +57,7 @@ void ep93xx_ide_release_gpio(struct platform_device *pdev);
void ep93xx_init_devices(void);
extern void ep93xx_timer_init(void);
-void ep93xx_restart(char, const char *);
+void ep93xx_restart(enum reboot_mode, const char *);
void ep93xx_init_late(void);
#ifdef CONFIG_CRUNCH
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 2d503b3684c4..f5f65b58181e 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -93,7 +93,7 @@ config SOC_EXYNOS5440
default y
depends on ARCH_EXYNOS5
select ARCH_HAS_OPP
- select ARM_ARCH_TIMER
+ select HAVE_ARM_ARCH_TIMER
select AUTO_ZRELADDR
select MIGHT_HAVE_PCI
select PCI_DOMAINS if PCI
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 2c655db4b78e..164685bd25c8 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -285,12 +285,12 @@ static struct map_desc exynos5440_iodesc0[] __initdata = {
},
};
-void exynos4_restart(char mode, const char *cmd)
+void exynos4_restart(enum reboot_mode mode, const char *cmd)
{
__raw_writel(0x1, S5P_SWRESET);
}
-void exynos5_restart(char mode, const char *cmd)
+void exynos5_restart(enum reboot_mode mode, const char *cmd)
{
struct device_node *np;
u32 val;
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 38d45fd23be4..3e156bcddcb4 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -12,6 +12,7 @@
#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
#define __ARCH_ARM_MACH_EXYNOS_COMMON_H
+#include <linux/reboot.h>
#include <linux/of.h>
void mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1);
@@ -20,8 +21,8 @@ extern unsigned long xxti_f, xusbxti_f;
struct map_desc;
void exynos_init_io(void);
-void exynos4_restart(char mode, const char *cmd);
-void exynos5_restart(char mode, const char *cmd);
+void exynos4_restart(enum reboot_mode mode, const char *cmd);
+void exynos5_restart(enum reboot_mode mode, const char *cmd);
void exynos_init_late(void);
/* ToDo: remove these after migrating legacy exynos4 platforms to dt */
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
index 6987a09ec219..9669cc0b6318 100644
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -86,7 +86,7 @@ fixup_cats(struct tag *tags, char **cmdline, struct meminfo *mi)
MACHINE_START(CATS, "Chalice-CATS")
/* Maintainer: Philip Blundell */
.atag_offset = 0x100,
- .restart_mode = 's',
+ .reboot_mode = REBOOT_SOFT,
.fixup = fixup_cats,
.map_io = footbridge_map_io,
.init_irq = footbridge_init_irq,
diff --git a/arch/arm/mach-footbridge/common.c b/arch/arm/mach-footbridge/common.c
index a42b369bc439..2739ca2c1334 100644
--- a/arch/arm/mach-footbridge/common.c
+++ b/arch/arm/mach-footbridge/common.c
@@ -198,9 +198,9 @@ void __init footbridge_map_io(void)
}
}
-void footbridge_restart(char mode, const char *cmd)
+void footbridge_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's') {
+ if (mode == REBOOT_SOFT) {
/* Jump into the ROM */
soft_restart(0x41000000);
} else {
diff --git a/arch/arm/mach-footbridge/common.h b/arch/arm/mach-footbridge/common.h
index a846e50a07b8..56607b3a773e 100644
--- a/arch/arm/mach-footbridge/common.h
+++ b/arch/arm/mach-footbridge/common.h
@@ -1,3 +1,4 @@
+#include <linux/reboot.h>
extern void footbridge_timer_init(void);
extern void isa_timer_init(void);
@@ -8,4 +9,4 @@ extern void footbridge_map_io(void);
extern void footbridge_init_irq(void);
extern void isa_init_irq(unsigned int irq);
-extern void footbridge_restart(char, const char *);
+extern void footbridge_restart(enum reboot_mode, const char *);
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 90ea23fdce4c..1fd2cf097e30 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -634,9 +634,9 @@ fixup_netwinder(struct tag *tags, char **cmdline, struct meminfo *mi)
#endif
}
-static void netwinder_restart(char mode, const char *cmd)
+static void netwinder_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's') {
+ if (mode == REBOOT_SOFT) {
/* Jump into the ROM */
soft_restart(0x41000000);
} else {
diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h
index 3f65206a9b92..aea1ec5ab6f8 100644
--- a/arch/arm/mach-highbank/core.h
+++ b/arch/arm/mach-highbank/core.h
@@ -1,8 +1,10 @@
#ifndef __HIGHBANK_CORE_H
#define __HIGHBANK_CORE_H
+#include <linux/reboot.h>
+
extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
-extern void highbank_restart(char, const char *);
+extern void highbank_restart(enum reboot_mode, const char *);
extern void __iomem *scu_base_addr;
#ifdef CONFIG_PM_SLEEP
diff --git a/arch/arm/mach-highbank/system.c b/arch/arm/mach-highbank/system.c
index 37d8384dcf19..2df5870b7583 100644
--- a/arch/arm/mach-highbank/system.c
+++ b/arch/arm/mach-highbank/system.c
@@ -15,13 +15,14 @@
*/
#include <linux/io.h>
#include <asm/proc-fns.h>
+#include <linux/reboot.h>
#include "core.h"
#include "sysregs.h"
-void highbank_restart(char mode, const char *cmd)
+void highbank_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 'h')
+ if (mode == REBOOT_HARD)
highbank_set_pwr_hard_reset();
else
highbank_set_pwr_soft_reset();
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 60661a4b0e24..f54656091a9d 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -108,7 +108,6 @@ config SOC_IMX25
select ARCH_MXC_IOMUX_V3
select COMMON_CLK
select CPU_ARM926T
- select HAVE_CAN_FLEXCAN if CAN
select MXC_AVIC
config SOC_IMX27
@@ -134,7 +133,6 @@ config SOC_IMX35
select ARCH_MXC_IOMUX_V3
select COMMON_CLK
select CPU_V6K
- select HAVE_CAN_FLEXCAN if CAN
select HAVE_EPIT
select MXC_AVIC
select SMP_ON_UP if SMP
@@ -774,7 +772,6 @@ comment "Device tree only"
config SOC_IMX53
bool "i.MX53 support"
- select HAVE_CAN_FLEXCAN if CAN
select HAVE_IMX_SRC
select IMX_HAVE_PLATFORM_IMX2_WDT
select PINCTRL
@@ -797,7 +794,6 @@ config SOC_IMX6Q
select CPU_V7
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if LOCAL_TIMERS
- select HAVE_CAN_FLEXCAN if CAN
select HAVE_IMX_ANATOP
select HAVE_IMX_GPC
select HAVE_IMX_MMDC
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index ee78847abf47..cb6c838b63ed 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -11,6 +11,8 @@
#ifndef __ASM_ARCH_MXC_COMMON_H__
#define __ASM_ARCH_MXC_COMMON_H__
+#include <linux/reboot.h>
+
struct platform_device;
struct pt_regs;
struct clk;
@@ -71,7 +73,7 @@ extern int mx53_clocks_init_dt(void);
extern struct platform_device *mxc_register_gpio(char *name, int id,
resource_size_t iobase, resource_size_t iosize, int irq, int irq_high);
extern void mxc_set_cpu_type(unsigned int type);
-extern void mxc_restart(char, const char *);
+extern void mxc_restart(enum reboot_mode, const char *);
extern void mxc_arch_reset_init(void __iomem *);
extern void mxc_arch_reset_init_dt(void);
extern int mx53_revision(void);
diff --git a/arch/arm/mach-imx/devices-imx25.h b/arch/arm/mach-imx/devices-imx25.h
index 0d2922bc575c..769563fdeaa0 100644
--- a/arch/arm/mach-imx/devices-imx25.h
+++ b/arch/arm/mach-imx/devices-imx25.h
@@ -13,10 +13,10 @@ extern const struct imx_fec_data imx25_fec_data;
imx_add_fec(&imx25_fec_data, pdata)
extern const struct imx_flexcan_data imx25_flexcan_data[];
-#define imx25_add_flexcan(id, pdata) \
- imx_add_flexcan(&imx25_flexcan_data[id], pdata)
-#define imx25_add_flexcan0(pdata) imx25_add_flexcan(0, pdata)
-#define imx25_add_flexcan1(pdata) imx25_add_flexcan(1, pdata)
+#define imx25_add_flexcan(id) \
+ imx_add_flexcan(&imx25_flexcan_data[id])
+#define imx25_add_flexcan0() imx25_add_flexcan(0)
+#define imx25_add_flexcan1() imx25_add_flexcan(1)
extern const struct imx_fsl_usb2_udc_data imx25_fsl_usb2_udc_data;
#define imx25_add_fsl_usb2_udc(pdata) \
diff --git a/arch/arm/mach-imx/devices-imx35.h b/arch/arm/mach-imx/devices-imx35.h
index e2675f1b141c..780d8240281b 100644
--- a/arch/arm/mach-imx/devices-imx35.h
+++ b/arch/arm/mach-imx/devices-imx35.h
@@ -17,10 +17,10 @@ extern const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data;
imx_add_fsl_usb2_udc(&imx35_fsl_usb2_udc_data, pdata)
extern const struct imx_flexcan_data imx35_flexcan_data[];
-#define imx35_add_flexcan(id, pdata) \
- imx_add_flexcan(&imx35_flexcan_data[id], pdata)
-#define imx35_add_flexcan0(pdata) imx35_add_flexcan(0, pdata)
-#define imx35_add_flexcan1(pdata) imx35_add_flexcan(1, pdata)
+#define imx35_add_flexcan(id) \
+ imx_add_flexcan(&imx35_flexcan_data[id])
+#define imx35_add_flexcan0() imx35_add_flexcan(0)
+#define imx35_add_flexcan1() imx35_add_flexcan(1)
extern const struct imx_imx2_wdt_data imx35_imx2_wdt_data;
#define imx35_add_imx2_wdt() \
diff --git a/arch/arm/mach-imx/devices/Kconfig b/arch/arm/mach-imx/devices/Kconfig
index 3dd2b1b041d1..68c74fb0373c 100644
--- a/arch/arm/mach-imx/devices/Kconfig
+++ b/arch/arm/mach-imx/devices/Kconfig
@@ -4,7 +4,6 @@ config IMX_HAVE_PLATFORM_FEC
config IMX_HAVE_PLATFORM_FLEXCAN
bool
- select HAVE_CAN_FLEXCAN if CAN
config IMX_HAVE_PLATFORM_FSL_USB2_UDC
bool
diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h
index 453e20bc2657..c13b76b9f6b3 100644
--- a/arch/arm/mach-imx/devices/devices-common.h
+++ b/arch/arm/mach-imx/devices/devices-common.h
@@ -50,7 +50,6 @@ struct platform_device *__init imx_add_fec(
const struct imx_fec_data *data,
const struct fec_platform_data *pdata);
-#include <linux/can/platform/flexcan.h>
struct imx_flexcan_data {
int id;
resource_size_t iobase;
@@ -58,8 +57,7 @@ struct imx_flexcan_data {
resource_size_t irq;
};
struct platform_device *__init imx_add_flexcan(
- const struct imx_flexcan_data *data,
- const struct flexcan_platform_data *pdata);
+ const struct imx_flexcan_data *data);
#include <linux/fsl_devices.h>
struct imx_fsl_usb2_udc_data {
diff --git a/arch/arm/mach-imx/devices/platform-flexcan.c b/arch/arm/mach-imx/devices/platform-flexcan.c
index 1078bf0a94ef..55d61eaf63c6 100644
--- a/arch/arm/mach-imx/devices/platform-flexcan.c
+++ b/arch/arm/mach-imx/devices/platform-flexcan.c
@@ -38,8 +38,7 @@ const struct imx_flexcan_data imx35_flexcan_data[] __initconst = {
#endif /* ifdef CONFIG_SOC_IMX35 */
struct platform_device *__init imx_add_flexcan(
- const struct imx_flexcan_data *data,
- const struct flexcan_platform_data *pdata)
+ const struct imx_flexcan_data *data)
{
struct resource res[] = {
{
@@ -54,5 +53,5 @@ struct platform_device *__init imx_add_flexcan(
};
return imx_add_platform_device("flexcan", data->id,
- res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+ res, ARRAY_SIZE(res), NULL, 0);
}
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
index e2b70f4c1a2c..e77cc3af6db2 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
@@ -279,7 +279,7 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
imx25_add_imx_fb(&eukrea_mximxsd_fb_pdata);
imx25_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
- imx25_add_flexcan1(NULL);
+ imx25_add_flexcan1();
imx25_add_sdhci_esdhc_imx(0, &sd1_pdata);
gpio_request(GPIO_LED1, "LED1");
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
index 5a2d5ef12dd5..14d6c8249b76 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
@@ -287,7 +287,7 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
imx35_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
- imx35_add_flexcan1(NULL);
+ imx35_add_flexcan1();
imx35_add_sdhci_esdhc_imx(0, &sd1_pdata);
gpio_request(GPIO_LED1, "LED1");
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index f5965220a4d8..7be13f8e69a0 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -27,6 +27,7 @@
#include <linux/of_platform.h>
#include <linux/opp.h>
#include <linux/phy.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/micrel_phy.h>
#include <linux/mfd/syscon.h>
@@ -67,7 +68,7 @@ static void __init imx6q_init_revision(void)
mxc_set_cpu_type(rev >> 16 & 0xff);
}
-static void imx6q_restart(char mode, const char *cmd)
+static void imx6q_restart(enum reboot_mode mode, const char *cmd)
{
struct device_node *np;
void __iomem *wdog_base;
diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c
index 8bcda688a006..13490c203050 100644
--- a/arch/arm/mach-imx/mach-mx25_3ds.c
+++ b/arch/arm/mach-imx/mach-mx25_3ds.c
@@ -249,7 +249,7 @@ static void __init mx25pdk_init(void)
imx25_add_imx_i2c0(&mx25_3ds_i2c0_data);
gpio_request_one(MX25PDK_CAN_PWDN, GPIOF_OUT_INIT_LOW, "can-pwdn");
- imx25_add_flexcan0(NULL);
+ imx25_add_flexcan0();
}
static void __init mx25pdk_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index dae4cd7be040..6f424eced181 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -268,10 +268,11 @@ static struct mc13xxx_led_platform_data moboard_led[] = {
static struct mc13xxx_leds_platform_data moboard_leds = {
.num_leds = ARRAY_SIZE(moboard_led),
.led = moboard_led,
- .flags = MC13783_LED_SLEWLIMTC,
- .abmode = MC13783_LED_AB_DISABLED,
- .tc1_period = MC13783_LED_PERIOD_10MS,
- .tc2_period = MC13783_LED_PERIOD_10MS,
+ .led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0),
+ .led_control[1] = MC13783_LED_C1_SLEWLIM,
+ .led_control[2] = MC13783_LED_C2_SLEWLIM,
+ .led_control[3] = MC13783_LED_C3_PERIOD(0),
+ .led_control[4] = MC13783_LED_C3_PERIOD(0),
};
static struct mc13xxx_buttons_platform_data moboard_buttons = {
diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index 8ed533f0f8ca..b726cb1c5fdd 100644
--- a/arch/arm/mach-imx/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -385,7 +385,7 @@ static void __init pcm043_init(void)
if (!otg_mode_host)
imx35_add_fsl_usb2_udc(&otg_device_pdata);
- imx35_add_flexcan1(NULL);
+ imx35_add_flexcan1();
imx35_add_sdhci_esdhc_imx(0, &sd1_pdata);
}
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 8f0f60697f55..0884ca90d15a 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -65,7 +65,7 @@ static void imx3_idle(void)
: "=r" (reg));
}
-static void __iomem *imx3_ioremap_caller(unsigned long phys_addr, size_t size,
+static void __iomem *imx3_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller)
{
if (mtype == MT_DEVICE) {
diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c
index 7cdc79a9657c..6fe81bb4d3c9 100644
--- a/arch/arm/mach-imx/system.c
+++ b/arch/arm/mach-imx/system.c
@@ -37,7 +37,7 @@ static struct clk *wdog_clk;
/*
* Reset the system. It is called by machine_restart().
*/
-void mxc_restart(char mode, const char *cmd)
+void mxc_restart(enum reboot_mode mode, const char *cmd)
{
unsigned int wcr_enable;
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index fea91313678b..cd46529e9eaa 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -26,8 +26,8 @@
#include <linux/clockchips.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <asm/mach/time.h>
#include "common.h"
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
index 72516658be1e..ad0ac5547b2c 100644
--- a/arch/arm/mach-integrator/common.h
+++ b/arch/arm/mach-integrator/common.h
@@ -1,7 +1,8 @@
+#include <linux/reboot.h>
#include <linux/amba/serial.h>
extern struct amba_pl010_data ap_uart_data;
void integrator_init_early(void);
int integrator_init(bool is_cp);
void integrator_reserve(void);
-void integrator_restart(char, const char *);
+void integrator_restart(enum reboot_mode, const char *);
void integrator_init_sysfs(struct device *parent, u32 id);
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 81461d218717..4cdfd7365925 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -124,7 +124,7 @@ void __init integrator_reserve(void)
/*
* To reset, we hit the on-board reset register in the system FPGA
*/
-void integrator_restart(char mode, const char *cmd)
+void integrator_restart(enum reboot_mode mode, const char *cmd)
{
cm_control(CM_CTRL_RESET, CM_CTRL_RESET);
}
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index a5b15c4e8def..d9e95e612fcb 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -41,6 +41,7 @@
#include <linux/stat.h>
#include <linux/sys_soc.h>
#include <linux/termios.h>
+#include <linux/sched_clock.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -48,7 +49,6 @@
#include <asm/setup.h>
#include <asm/param.h> /* HZ */
#include <asm/mach-types.h>
-#include <asm/sched_clock.h>
#include <mach/lm.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-iop13xx/include/mach/iop13xx.h b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
index 7480f58267aa..17b40279e0a4 100644
--- a/arch/arm/mach-iop13xx/include/mach/iop13xx.h
+++ b/arch/arm/mach-iop13xx/include/mach/iop13xx.h
@@ -2,6 +2,9 @@
#define _IOP13XX_HW_H_
#ifndef __ASSEMBLY__
+
+#include <linux/reboot.h>
+
/* The ATU offsets can change based on the strapping */
extern u32 iop13xx_atux_pmmr_offset;
extern u32 iop13xx_atue_pmmr_offset;
@@ -11,7 +14,7 @@ void iop13xx_map_io(void);
void iop13xx_platform_init(void);
void iop13xx_add_tpmi_devices(void);
void iop13xx_init_irq(void);
-void iop13xx_restart(char, const char *);
+void iop13xx_restart(enum reboot_mode, const char *);
/* CPUID CP6 R0 Page 0 */
static inline int iop13xx_cpu_id(void)
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index 183dc8b5511b..faaf7d4482c5 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -23,7 +23,7 @@
#include "pci.h"
-static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
+static void __iomem *__iop13xx_ioremap_caller(phys_addr_t cookie,
size_t size, unsigned int mtype, void *caller)
{
void __iomem * retval;
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index 3181f61ea63e..96e6c7a6793b 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -469,7 +469,6 @@ void __init iop13xx_platform_init(void)
dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
dma_cap_set(DMA_XOR, plat_data->cap_mask);
dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask);
- dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
break;
case IOP13XX_INIT_ADMA_1:
@@ -479,7 +478,6 @@ void __init iop13xx_platform_init(void)
dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
dma_cap_set(DMA_XOR, plat_data->cap_mask);
dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask);
- dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
break;
case IOP13XX_INIT_ADMA_2:
@@ -489,7 +487,6 @@ void __init iop13xx_platform_init(void)
dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
dma_cap_set(DMA_XOR, plat_data->cap_mask);
dma_cap_set(DMA_XOR_VAL, plat_data->cap_mask);
- dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
dma_cap_set(DMA_PQ, plat_data->cap_mask);
dma_cap_set(DMA_PQ_VAL, plat_data->cap_mask);
@@ -597,7 +594,7 @@ __setup("iop13xx_init_adma", iop13xx_init_adma_setup);
__setup("iop13xx_init_uart", iop13xx_init_uart_setup);
__setup("iop13xx_init_i2c", iop13xx_init_i2c_setup);
-void iop13xx_restart(char mode, const char *cmd)
+void iop13xx_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Reset the internal bus (warning both cores are reset)
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index ea0984a7449e..069144300b77 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -286,7 +286,7 @@ static void n2100_power_off(void)
;
}
-static void n2100_restart(char mode, const char *cmd)
+static void n2100_restart(enum reboot_mode mode, const char *cmd)
{
gpio_line_set(N2100_HARDWARE_RESET, GPIO_LOW);
gpio_line_config(N2100_HARDWARE_RESET, GPIO_OUT);
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 6600cff6bd92..5327decde5a0 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -30,6 +30,7 @@
#include <linux/export.h>
#include <linux/gpio.h>
#include <linux/cpu.h>
+#include <linux/sched_clock.h>
#include <mach/udc.h>
#include <mach/hardware.h>
@@ -38,7 +39,6 @@
#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/irq.h>
-#include <asm/sched_clock.h>
#include <asm/system_misc.h>
#include <asm/mach/map.h>
@@ -531,9 +531,9 @@ static void __init ixp4xx_clockevent_init(void)
0xf, 0xfffffffe);
}
-void ixp4xx_restart(char mode, const char *cmd)
+void ixp4xx_restart(enum reboot_mode mode, const char *cmd)
{
- if ( 1 && mode == 's') {
+ if ( 1 && mode == REBOOT_SOFT) {
/* Jump into ROM at address 0 */
soft_restart(0);
} else {
@@ -559,7 +559,7 @@ void ixp4xx_restart(char mode, const char *cmd)
* fallback to the default.
*/
-static void __iomem *ixp4xx_ioremap_caller(unsigned long addr, size_t size,
+static void __iomem *ixp4xx_ioremap_caller(phys_addr_t addr, size_t size,
unsigned int mtype, void *caller)
{
if (!is_pci_memory(addr))
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
index 5d413f8c5700..686ef34c69f5 100644
--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -27,6 +27,7 @@
#include <linux/i2c.h>
#include <linux/i2c-gpio.h>
+#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
diff --git a/arch/arm/mach-ixp4xx/include/mach/platform.h b/arch/arm/mach-ixp4xx/include/mach/platform.h
index db5afb69c123..4c4c6a6f4526 100644
--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
@@ -13,6 +13,8 @@
#ifndef __ASSEMBLY__
+#include <linux/reboot.h>
+
#include <asm/types.h>
#ifndef __ARMEB__
@@ -123,7 +125,7 @@ extern void ixp4xx_init_early(void);
extern void ixp4xx_init_irq(void);
extern void ixp4xx_sys_init(void);
extern void ixp4xx_timer_init(void);
-extern void ixp4xx_restart(char, const char *);
+extern void ixp4xx_restart(enum reboot_mode, const char *);
extern void ixp4xx_pci_preinit(void);
struct pci_sys_data;
extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 7c72c725b711..e9238b5567ee 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -20,6 +20,7 @@
#include <linux/mv643xx_i2c.h>
#include <linux/timex.h>
#include <linux/kexec.h>
+#include <linux/reboot.h>
#include <net/dsa.h>
#include <asm/page.h>
#include <asm/mach/map.h>
@@ -722,7 +723,7 @@ void __init kirkwood_init(void)
#endif
}
-void kirkwood_restart(char mode, const char *cmd)
+void kirkwood_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Enable soft reset to assert RSTOUTn.
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 1c09f3f93fbb..fcf3ba682e24 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -11,6 +11,8 @@
#ifndef __ARCH_KIRKWOOD_COMMON_H
#define __ARCH_KIRKWOOD_COMMON_H
+#include <linux/reboot.h>
+
struct dsa_platform_data;
struct mv643xx_eth_platform_data;
struct mv_sata_platform_data;
@@ -53,7 +55,7 @@ void kirkwood_audio_init(void);
void kirkwood_cpuidle_init(void);
void kirkwood_cpufreq_init(void);
-void kirkwood_restart(char, const char *);
+void kirkwood_restart(enum reboot_mode, const char *);
void kirkwood_clk_init(void);
/* board init functions for boards not fully converted to fdt */
diff --git a/arch/arm/mach-ks8695/generic.h b/arch/arm/mach-ks8695/generic.h
index 6e97ce462d73..43253f8e6de4 100644
--- a/arch/arm/mach-ks8695/generic.h
+++ b/arch/arm/mach-ks8695/generic.h
@@ -12,5 +12,5 @@
extern __init void ks8695_map_io(void);
extern __init void ks8695_init_irq(void);
-extern void ks8695_restart(char, const char *);
+extern void ks8695_restart(enum reboot_mode, const char *);
extern void ks8695_timer_init(void);
diff --git a/arch/arm/mach-ks8695/time.c b/arch/arm/mach-ks8695/time.c
index c272a3863d5f..426c97662f5b 100644
--- a/arch/arm/mach-ks8695/time.c
+++ b/arch/arm/mach-ks8695/time.c
@@ -154,11 +154,11 @@ void __init ks8695_timer_init(void)
setup_irq(KS8695_IRQ_TIMER1, &ks8695_timer_irq);
}
-void ks8695_restart(char mode, const char *cmd)
+void ks8695_restart(enum reboot_mode reboot_mode, const char *cmd)
{
unsigned int reg;
- if (mode == 's')
+ if (reboot_mode == REBOOT_SOFT)
soft_restart(0);
/* disable timer0 */
diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
index 0d4db8c544b5..d7aa54c25c59 100644
--- a/arch/arm/mach-lpc32xx/common.c
+++ b/arch/arm/mach-lpc32xx/common.c
@@ -207,11 +207,11 @@ void __init lpc32xx_map_io(void)
iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
}
-void lpc23xx_restart(char mode, const char *cmd)
+void lpc23xx_restart(enum reboot_mode mode, const char *cmd)
{
switch (mode) {
- case 's':
- case 'h':
+ case REBOOT_SOFT:
+ case REBOOT_HARD:
lpc32xx_watchdog_reset();
break;
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
index e0b26062a272..1cd8853b2f9b 100644
--- a/arch/arm/mach-lpc32xx/common.h
+++ b/arch/arm/mach-lpc32xx/common.h
@@ -21,6 +21,7 @@
#include <mach/board.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
/*
* Other arch specific structures and functions
@@ -29,7 +30,7 @@ extern void lpc32xx_timer_init(void);
extern void __init lpc32xx_init_irq(void);
extern void __init lpc32xx_map_io(void);
extern void __init lpc32xx_serial_init(void);
-extern void lpc23xx_restart(char, const char *);
+extern void lpc23xx_restart(enum reboot_mode, const char *);
/*
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
index c1cd5a943ab1..e54f87ec2e4a 100644
--- a/arch/arm/mach-lpc32xx/phy3250.c
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -182,8 +182,8 @@ static void pl08x_put_signal(const struct pl08x_channel_data *cd, int ch)
static struct pl08x_platform_data pl08x_pd = {
.slave_channels = &pl08x_slave_channels[0],
.num_slave_channels = ARRAY_SIZE(pl08x_slave_channels),
- .get_signal = pl08x_get_signal,
- .put_signal = pl08x_put_signal,
+ .get_xfer_signal = pl08x_get_signal,
+ .put_xfer_signal = pl08x_put_signal,
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
};
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index 5b660ec09ef5..0c002099c3a3 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -210,7 +210,7 @@ struct pxa168fb_mach_info aspenite_lcd_info = {
.invert_pixclock = 0,
};
-static unsigned int aspenite_matrix_key_map[] = {
+static const unsigned int aspenite_matrix_key_map[] = {
KEY(0, 6, KEY_UP), /* SW 4 */
KEY(0, 7, KEY_DOWN), /* SW 5 */
KEY(1, 6, KEY_LEFT), /* SW 6 */
@@ -219,11 +219,15 @@ static unsigned int aspenite_matrix_key_map[] = {
KEY(4, 7, KEY_ESC), /* SW 9 */
};
+static struct matrix_keymap_data aspenite_matrix_keymap_data = {
+ .keymap = aspenite_matrix_key_map,
+ .keymap_size = ARRAY_SIZE(aspenite_matrix_key_map),
+};
+
static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
.matrix_key_rows = 5,
.matrix_key_cols = 8,
- .matrix_key_map = aspenite_matrix_key_map,
- .matrix_key_map_size = ARRAY_SIZE(aspenite_matrix_key_map),
+ .matrix_keymap_data = &aspenite_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-mmp/common.c b/arch/arm/mach-mmp/common.c
index 9292b7966e3b..c03b4ab582db 100644
--- a/arch/arm/mach-mmp/common.c
+++ b/arch/arm/mach-mmp/common.c
@@ -47,7 +47,7 @@ void __init mmp_map_io(void)
mmp_chip_id = __raw_readl(MMP_CHIPID);
}
-void mmp_restart(char mode, const char *cmd)
+void mmp_restart(enum reboot_mode mode, const char *cmd)
{
soft_restart(0);
}
diff --git a/arch/arm/mach-mmp/common.h b/arch/arm/mach-mmp/common.h
index 0bdc50b134ce..991d7e9877de 100644
--- a/arch/arm/mach-mmp/common.h
+++ b/arch/arm/mach-mmp/common.h
@@ -1,10 +1,11 @@
+#include <linux/reboot.h>
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
extern void timer_init(int irq);
extern void __init icu_init_irq(void);
extern void __init mmp_map_io(void);
-extern void mmp_restart(char, const char *);
+extern void mmp_restart(enum reboot_mode, const char *);
extern void __init pxa168_clk_init(void);
extern void __init pxa910_clk_init(void);
extern void __init mmp2_clk_init(void);
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index 7ed1df21ea1c..459c2d03eb5c 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -1,9 +1,11 @@
#ifndef __ASM_MACH_PXA168_H
#define __ASM_MACH_PXA168_H
+#include <linux/reboot.h>
+
extern void pxa168_timer_init(void);
extern void __init pxa168_init_irq(void);
-extern void pxa168_restart(char, const char *);
+extern void pxa168_restart(enum reboot_mode, const char *);
extern void pxa168_clear_keypad_wakeup(void);
#include <linux/i2c.h>
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index a30dcf3b7d9e..144e997624c0 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -172,7 +172,7 @@ int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata)
return platform_device_register(&pxa168_device_usb_host);
}
-void pxa168_restart(char mode, const char *cmd)
+void pxa168_restart(enum reboot_mode mode, const char *cmd)
{
soft_restart(0xffff0000);
}
diff --git a/arch/arm/mach-mmp/teton_bga.c b/arch/arm/mach-mmp/teton_bga.c
index e4d95b4c6bb2..6aa53fb29d26 100644
--- a/arch/arm/mach-mmp/teton_bga.c
+++ b/arch/arm/mach-mmp/teton_bga.c
@@ -61,11 +61,15 @@ static unsigned int teton_bga_matrix_key_map[] = {
KEY(1, 7, KEY_RIGHT),
};
+static struct matrix_keymap_data teton_bga_matrix_keymap_data = {
+ .keymap = teton_bga_matrix_key_map,
+ .keymap_size = ARRAY_SIZE(teton_bga_matrix_key_map),
+};
+
static struct pxa27x_keypad_platform_data teton_bga_keypad_info __initdata = {
.matrix_key_rows = 2,
.matrix_key_cols = 8,
- .matrix_key_map = teton_bga_matrix_key_map,
- .matrix_key_map_size = ARRAY_SIZE(teton_bga_matrix_key_map),
+ .matrix_keymap_data = &teton_bga_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 86a18b3d252e..7ac41e83cfef 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -28,8 +28,8 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <mach/addr-map.h>
#include <mach/regs-timers.h>
#include <mach/regs-apbc.h>
diff --git a/arch/arm/mach-msm/common.h b/arch/arm/mach-msm/common.h
index ce8215a269e5..421cf7751a80 100644
--- a/arch/arm/mach-msm/common.h
+++ b/arch/arm/mach-msm/common.h
@@ -23,7 +23,7 @@ extern void msm_map_msm8x60_io(void);
extern void msm_map_msm8960_io(void);
extern void msm_map_qsd8x50_io(void);
-extern void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
+extern void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller);
extern struct smp_operations msm_smp_ops;
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index efa113e4de86..3dc04ccaf59f 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -168,7 +168,7 @@ void __init msm_map_msm7x30_io(void)
}
#endif /* CONFIG_ARCH_MSM7X30 */
-void __iomem *__msm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__msm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller)
{
if (mtype == MT_DEVICE) {
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 284313f3e02c..b6418fd5fe0d 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -23,10 +23,10 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
#include <asm/localtimer.h>
-#include <asm/sched_clock.h>
#include "common.h"
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 749a7f8c4992..75062eff2494 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -413,7 +413,7 @@ void __init mv78xx0_init(void)
clk_init();
}
-void mv78xx0_restart(char mode, const char *cmd)
+void mv78xx0_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Enable soft reset to assert RSTOUTn.
diff --git a/arch/arm/mach-mv78xx0/common.h b/arch/arm/mach-mv78xx0/common.h
index 5e9485bad0ac..6889af26077d 100644
--- a/arch/arm/mach-mv78xx0/common.h
+++ b/arch/arm/mach-mv78xx0/common.h
@@ -11,6 +11,8 @@
#ifndef __ARCH_MV78XX0_COMMON_H
#define __ARCH_MV78XX0_COMMON_H
+#include <linux/reboot.h>
+
struct mv643xx_eth_platform_data;
struct mv_sata_platform_data;
@@ -45,7 +47,7 @@ void mv78xx0_uart1_init(void);
void mv78xx0_uart2_init(void);
void mv78xx0_uart3_init(void);
void mv78xx0_i2c_init(void);
-void mv78xx0_restart(char, const char *);
+void mv78xx0_restart(enum reboot_mode, const char *);
extern void mv78xx0_timer_init(void);
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 98defd5e92cd..e366010e1d91 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -17,7 +17,9 @@
#define ARMADA_XP_MAX_CPUS 4
-void mvebu_restart(char mode, const char *cmd);
+#include <linux/reboot.h>
+
+void mvebu_restart(enum reboot_mode mode, const char *cmd);
void armada_370_xp_init_irq(void);
void armada_370_xp_handle_irq(struct pt_regs *regs);
diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c
index b8079df8c986..f875124ff4f9 100644
--- a/arch/arm/mach-mvebu/system-controller.c
+++ b/arch/arm/mach-mvebu/system-controller.c
@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/of_address.h>
#include <linux/io.h>
+#include <linux/reboot.h>
static void __iomem *system_controller_base;
@@ -63,7 +64,7 @@ static struct of_device_id of_system_controller_table[] = {
{ /* end of list */ },
};
-void mvebu_restart(char mode, const char *cmd)
+void mvebu_restart(enum reboot_mode mode, const char *cmd)
{
if (!system_controller_base) {
pr_err("Cannot restart, system-controller not available: check the device tree\n");
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 616fe0210da1..8cde9e05b5d6 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -10,7 +10,6 @@ config SOC_IMX28
select ARM_AMBA
select ARM_CPU_SUSPEND if PM
select CPU_ARM926T
- select HAVE_CAN_FLEXCAN if CAN
select PINCTRL_IMX28
config ARCH_MXS
diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c
index 7fa611c1b287..4ce27b536dc9 100644
--- a/arch/arm/mach-mxs/mach-mxs.c
+++ b/arch/arm/mach-mxs/mach-mxs.c
@@ -14,12 +14,12 @@
#include <linux/clk/mxs.h>
#include <linux/clkdev.h>
#include <linux/clocksource.h>
-#include <linux/can/platform/flexcan.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/irqchip/mxs.h>
+#include <linux/reboot.h>
#include <linux/micrel_phy.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@@ -76,41 +76,6 @@ static inline void __mxs_togl(u32 mask, void __iomem *reg)
__raw_writel(mask, reg + MXS_TOG_ADDR);
}
-/*
- * MX28EVK_FLEXCAN_SWITCH is shared between both flexcan controllers
- */
-#define MX28EVK_FLEXCAN_SWITCH MXS_GPIO_NR(2, 13)
-
-static int flexcan0_en, flexcan1_en;
-
-static void mx28evk_flexcan_switch(void)
-{
- if (flexcan0_en || flexcan1_en)
- gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 1);
- else
- gpio_set_value(MX28EVK_FLEXCAN_SWITCH, 0);
-}
-
-static void mx28evk_flexcan0_switch(int enable)
-{
- flexcan0_en = enable;
- mx28evk_flexcan_switch();
-}
-
-static void mx28evk_flexcan1_switch(int enable)
-{
- flexcan1_en = enable;
- mx28evk_flexcan_switch();
-}
-
-static struct flexcan_platform_data flexcan_pdata[2];
-
-static struct of_dev_auxdata mxs_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80032000, NULL, &flexcan_pdata[0]),
- OF_DEV_AUXDATA("fsl,imx28-flexcan", 0x80034000, NULL, &flexcan_pdata[1]),
- { /* sentinel */ }
-};
-
#define OCOTP_WORD_OFFSET 0x20
#define OCOTP_WORD_COUNT 0x20
@@ -270,15 +235,6 @@ static void __init imx28_evk_init(void)
mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
}
-static void __init imx28_evk_post_init(void)
-{
- if (!gpio_request_one(MX28EVK_FLEXCAN_SWITCH, GPIOF_DIR_OUT,
- "flexcan-switch")) {
- flexcan_pdata[0].transceiver_switch = mx28evk_flexcan0_switch;
- flexcan_pdata[1].transceiver_switch = mx28evk_flexcan1_switch;
- }
-}
-
static int apx4devkit_phy_fixup(struct phy_device *phy)
{
phy->dev_flags |= MICREL_PHY_50MHZ_CLK;
@@ -484,13 +440,10 @@ static void __init mxs_machine_init(void)
crystalfontz_init();
of_platform_populate(NULL, of_default_bus_match_table,
- mxs_auxdata_lookup, parent);
+ NULL, parent);
if (of_machine_is_compatible("karo,tx28"))
tx28_post_init();
-
- if (of_machine_is_compatible("fsl,imx28-evk"))
- imx28_evk_post_init();
}
#define MX23_CLKCTRL_RESET_OFFSET 0x120
@@ -500,7 +453,7 @@ static void __init mxs_machine_init(void)
/*
* Reset the system. It is called by machine_restart().
*/
-static void mxs_restart(char mode, const char *cmd)
+static void mxs_restart(enum reboot_mode mode, const char *cmd)
{
struct device_node *np;
void __iomem *reset_addr;
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index 1504b68f4c66..db25b0cef3a7 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/irqchip/arm-vic.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
#include <asm/mach/map.h>
#include <mach/netx-regs.h>
@@ -187,7 +188,7 @@ static int __init netx_init(void)
subsys_initcall(netx_init);
-void netx_restart(char mode, const char *cmd)
+void netx_restart(enum reboot_mode mode, const char *cmd)
{
writel(NETX_SYSTEM_RES_CR_FIRMW_RES_EN | NETX_SYSTEM_RES_CR_FIRMW_RES,
NETX_SYSTEM_RES_CR);
diff --git a/arch/arm/mach-netx/generic.h b/arch/arm/mach-netx/generic.h
index 768b26bbb42b..bb2ce471cc28 100644
--- a/arch/arm/mach-netx/generic.h
+++ b/arch/arm/mach-netx/generic.h
@@ -17,8 +17,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/reboot.h>
+
extern void __init netx_map_io(void);
extern void __init netx_init_irq(void);
-extern void netx_restart(char, const char *);
+extern void netx_restart(enum reboot_mode, const char *);
extern void netx_timer_init(void);
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 2df209ed1a07..13e0df9c11ce 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -103,7 +103,7 @@ static void __init cpu8815_map_io(void)
iotable_init(cpu8815_io_desc, ARRAY_SIZE(cpu8815_io_desc));
}
-static void cpu8815_restart(char mode, const char *cmd)
+static void cpu8815_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *srcbase = ioremap(NOMADIK_SRC_BASE, SZ_4K);
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index 6c116e1a4b01..4677a9ccb3cb 100644
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -26,6 +26,7 @@
#include <linux/serial_reg.h>
#include <linux/smc91x.h>
#include <linux/export.h>
+#include <linux/reboot.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -215,7 +216,7 @@ void voiceblue_wdt_ping(void)
gpio_set_value(0, wdt_gpio_state);
}
-static void voiceblue_restart(char mode, const char *cmd)
+static void voiceblue_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index 14f7e9920479..abec019a5281 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -28,6 +28,7 @@
#include <linux/mtd/mtd.h>
#include <linux/i2c-omap.h>
+#include <linux/reboot.h>
#include <plat/i2c.h>
@@ -70,7 +71,7 @@ static inline int omap_serial_wakeup_init(void)
void omap1_init_early(void);
void omap1_init_irq(void);
void omap1_init_late(void);
-void omap1_restart(char, const char *);
+void omap1_restart(enum reboot_mode, const char *);
extern void __init omap_check_revision(void);
diff --git a/arch/arm/mach-omap1/reset.c b/arch/arm/mach-omap1/reset.c
index 5eebd7e889d0..72bf4bf4a702 100644
--- a/arch/arm/mach-omap1/reset.c
+++ b/arch/arm/mach-omap1/reset.c
@@ -3,6 +3,7 @@
*/
#include <linux/kernel.h>
#include <linux/io.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
@@ -22,7 +23,7 @@
#define OMAP_EXTWARM_RST_SRC_ID_SHIFT 5
-void omap1_restart(char mode, const char *cmd)
+void omap1_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 726ec23d29c7..80603d2fef77 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -43,9 +43,9 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/io.h>
+#include <linux/sched_clock.h>
#include <asm/irq.h>
-#include <asm/sched_clock.h>
#include <mach/hardware.h>
#include <asm/mach/irq.h>
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 1fdb46216590..c7b32a966f67 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -4,6 +4,7 @@ config ARCH_OMAP
config ARCH_OMAP2PLUS
bool "TI OMAP2/3/4/5 SoCs with device tree support" if (ARCH_MULTI_V6 || ARCH_MULTI_V7)
select ARCH_HAS_CPUFREQ
+ select ARCH_HAS_BANDGAP
select ARCH_HAS_HOLES_MEMORYMODEL
select ARCH_OMAP
select ARCH_REQUIRE_GPIOLIB
diff --git a/arch/arm/mach-omap2/am33xx-restart.c b/arch/arm/mach-omap2/am33xx-restart.c
index 88e4fa8af031..1eae96212315 100644
--- a/arch/arm/mach-omap2/am33xx-restart.c
+++ b/arch/arm/mach-omap2/am33xx-restart.c
@@ -6,6 +6,7 @@
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
+#include <linux/reboot.h>
#include "common.h"
#include "prm-regbits-33xx.h"
@@ -19,7 +20,7 @@
* Resets the SoC. For @cmd, see the 'reboot' syscall in
* kernel/sys.c. No return value.
*/
-void am33xx_restart(char mode, const char *cmd)
+void am33xx_restart(enum reboot_mode mode, const char *cmd)
{
/* TODO: Handle mode and cmd if necessary */
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 72cab3f4f16d..dfcc182ecff9 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -31,6 +31,7 @@
#include <linux/i2c.h>
#include <linux/i2c/twl.h>
#include <linux/i2c-omap.h>
+#include <linux/reboot.h>
#include <asm/proc-fns.h>
@@ -119,33 +120,33 @@ static inline void omap_soc_device_init(void)
#endif
#if defined(CONFIG_SOC_OMAP2420) || defined(CONFIG_SOC_OMAP2430)
-void omap2xxx_restart(char mode, const char *cmd);
+void omap2xxx_restart(enum reboot_mode mode, const char *cmd);
#else
-static inline void omap2xxx_restart(char mode, const char *cmd)
+static inline void omap2xxx_restart(enum reboot_mode mode, const char *cmd)
{
}
#endif
#ifdef CONFIG_SOC_AM33XX
-void am33xx_restart(char mode, const char *cmd);
+void am33xx_restart(enum reboot_mode mode, const char *cmd);
#else
-static inline void am33xx_restart(char mode, const char *cmd)
+static inline void am33xx_restart(enum reboot_mode mode, const char *cmd)
{
}
#endif
#ifdef CONFIG_ARCH_OMAP3
-void omap3xxx_restart(char mode, const char *cmd);
+void omap3xxx_restart(enum reboot_mode mode, const char *cmd);
#else
-static inline void omap3xxx_restart(char mode, const char *cmd)
+static inline void omap3xxx_restart(enum reboot_mode mode, const char *cmd)
{
}
#endif
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
-void omap44xx_restart(char mode, const char *cmd);
+void omap44xx_restart(enum reboot_mode mode, const char *cmd);
#else
-static inline void omap44xx_restart(char mode, const char *cmd)
+static inline void omap44xx_restart(enum reboot_mode mode, const char *cmd)
{
}
#endif
diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c
index 719b716a4494..68423e26399d 100644
--- a/arch/arm/mach-omap2/omap2-restart.c
+++ b/arch/arm/mach-omap2/omap2-restart.c
@@ -31,7 +31,7 @@ static struct clk *reset_virt_prcm_set_ck, *reset_sys_ck;
* Set the DPLL to bypass so that reboot completes successfully. No
* return value.
*/
-void omap2xxx_restart(char mode, const char *cmd)
+void omap2xxx_restart(enum reboot_mode mode, const char *cmd)
{
u32 rate;
diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c
index 923c582189e5..5de2a0c2979d 100644
--- a/arch/arm/mach-omap2/omap3-restart.c
+++ b/arch/arm/mach-omap2/omap3-restart.c
@@ -12,6 +12,7 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/reboot.h>
#include "iomap.h"
#include "common.h"
@@ -28,7 +29,7 @@
* Resets the SoC. For @cmd, see the 'reboot' syscall in
* kernel/sys.c. No return value.
*/
-void omap3xxx_restart(char mode, const char *cmd)
+void omap3xxx_restart(enum reboot_mode mode, const char *cmd)
{
omap3_ctrl_write_boot_mode((cmd ? (u8)*cmd : 0));
omap3xxx_prm_dpll3_reset(); /* never returns */
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 38cd3a69cff3..57911430324e 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -23,6 +23,7 @@
#include <linux/export.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/of_address.h>
+#include <linux/reboot.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-omap2/omap4-restart.c b/arch/arm/mach-omap2/omap4-restart.c
index f90e02e11898..41dfd7da8170 100644
--- a/arch/arm/mach-omap2/omap4-restart.c
+++ b/arch/arm/mach-omap2/omap4-restart.c
@@ -8,6 +8,7 @@
*/
#include <linux/types.h>
+#include <linux/reboot.h>
#include "prminst44xx.h"
/**
@@ -18,7 +19,7 @@
* Resets the SoC. For @cmd, see the 'reboot' syscall in
* kernel/sys.c. No return value.
*/
-void omap44xx_restart(char mode, const char *cmd)
+void omap44xx_restart(enum reboot_mode mode, const char *cmd)
{
/* XXX Should save 'cmd' into scratchpad for use after reboot */
omap4_prminst_global_warm_sw_reset(); /* never returns */
diff --git a/arch/arm/mach-omap2/omap_device.c b/arch/arm/mach-omap2/omap_device.c
index 68be532f8688..5cc92874be7e 100644
--- a/arch/arm/mach-omap2/omap_device.c
+++ b/arch/arm/mach-omap2/omap_device.c
@@ -588,11 +588,6 @@ static int _od_runtime_suspend(struct device *dev)
return ret;
}
-static int _od_runtime_idle(struct device *dev)
-{
- return pm_generic_runtime_idle(dev);
-}
-
static int _od_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -648,7 +643,7 @@ static int _od_resume_noirq(struct device *dev)
struct dev_pm_domain omap_device_pm_domain = {
.ops = {
SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
- _od_runtime_idle)
+ NULL)
USE_PLATFORM_PM_SLEEP_OPS
.suspend_noirq = _od_suspend_noirq,
.resume_noirq = _od_resume_noirq,
diff --git a/arch/arm/mach-omap2/smartreflex-class3.c b/arch/arm/mach-omap2/smartreflex-class3.c
index aee3c8940a30..7a42e1960c3b 100644
--- a/arch/arm/mach-omap2/smartreflex-class3.c
+++ b/arch/arm/mach-omap2/smartreflex-class3.c
@@ -26,14 +26,14 @@ static int sr_class3_enable(struct omap_sr *sr)
}
omap_vp_enable(sr->voltdm);
- return sr_enable(sr->voltdm, volt);
+ return sr_enable(sr, volt);
}
static int sr_class3_disable(struct omap_sr *sr, int is_volt_reset)
{
- sr_disable_errgen(sr->voltdm);
+ sr_disable_errgen(sr);
omap_vp_disable(sr->voltdm);
- sr_disable(sr->voltdm);
+ sr_disable(sr);
if (is_volt_reset)
voltdm_reset(sr->voltdm);
@@ -42,7 +42,7 @@ static int sr_class3_disable(struct omap_sr *sr, int is_volt_reset)
static int sr_class3_configure(struct omap_sr *sr)
{
- return sr_configure_errgen(sr->voltdm);
+ return sr_configure_errgen(sr);
}
/* SR class3 structure */
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index 3bdb0fb02028..29ac667b7a8b 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -41,10 +41,10 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/platform_data/dmtimer-omap.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
#include <asm/smp_twd.h>
-#include <asm/sched_clock.h>
#include "omap_hwmod.h"
#include "omap_device.h"
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index f8a6db9239bf..b41599f98a8e 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -347,7 +347,7 @@ void __init orion5x_init(void)
orion5x_wdt_init();
}
-void orion5x_restart(char mode, const char *cmd)
+void orion5x_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Enable and issue soft reset
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index cdaa01f3d186..a909afb384fb 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -1,6 +1,8 @@
#ifndef __ARCH_ORION5X_COMMON_H
#define __ARCH_ORION5X_COMMON_H
+#include <linux/reboot.h>
+
struct dsa_platform_data;
struct mv643xx_eth_platform_data;
struct mv_sata_platform_data;
@@ -29,7 +31,7 @@ void orion5x_spi_init(void);
void orion5x_uart0_init(void);
void orion5x_uart1_init(void);
void orion5x_xor_init(void);
-void orion5x_restart(char, const char *);
+void orion5x_restart(enum reboot_mode, const char *);
/*
* PCIe/PCI functions.
diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c
index 24f4e14e5893..6234977b5aea 100644
--- a/arch/arm/mach-orion5x/ls-chl-setup.c
+++ b/arch/arm/mach-orion5x/ls-chl-setup.c
@@ -139,7 +139,7 @@ static struct mv_sata_platform_data lschl_sata_data = {
static void lschl_power_off(void)
{
- orion5x_restart('h', NULL);
+ orion5x_restart(REBOOT_HARD, NULL);
}
/*****************************************************************************
diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c
index fc653bb41e78..fe04c4b64569 100644
--- a/arch/arm/mach-orion5x/ls_hgl-setup.c
+++ b/arch/arm/mach-orion5x/ls_hgl-setup.c
@@ -185,7 +185,7 @@ static struct mv_sata_platform_data ls_hgl_sata_data = {
static void ls_hgl_power_off(void)
{
- orion5x_restart('h', NULL);
+ orion5x_restart(REBOOT_HARD, NULL);
}
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
index 18e66e617dc2..ca4dbe973daf 100644
--- a/arch/arm/mach-orion5x/lsmini-setup.c
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -185,7 +185,7 @@ static struct mv_sata_platform_data lsmini_sata_data = {
static void lsmini_power_off(void)
{
- orion5x_restart('h', NULL);
+ orion5x_restart(REBOOT_HARD, NULL);
}
diff --git a/arch/arm/mach-picoxcell/common.c b/arch/arm/mach-picoxcell/common.c
index b13f51bc35cf..ec79fea82704 100644
--- a/arch/arm/mach-picoxcell/common.c
+++ b/arch/arm/mach-picoxcell/common.c
@@ -11,6 +11,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
+#include <linux/reboot.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -63,7 +64,7 @@ static const char *picoxcell_dt_match[] = {
NULL
};
-static void picoxcell_wdt_restart(char mode, const char *cmd)
+static void picoxcell_wdt_restart(enum reboot_mode mode, const char *cmd)
{
/*
* Configure the watchdog to reset with the shortest possible timeout
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index 81135cd88e54..a6304858474a 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -10,6 +10,8 @@
#define __MACH_PRIMA2_COMMON_H__
#include <linux/init.h>
+#include <linux/reboot.h>
+
#include <asm/mach/time.h>
#include <asm/exception.h>
@@ -22,7 +24,7 @@ extern void sirfsoc_cpu_die(unsigned int cpu);
extern void __init sirfsoc_of_irq_init(void);
extern void __init sirfsoc_of_clk_init(void);
-extern void sirfsoc_restart(char, const char *);
+extern void sirfsoc_restart(enum reboot_mode, const char *);
extern asmlinkage void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs);
#ifndef CONFIG_DEBUG_LL
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
index d5e0cbc934c0..ccb53391147a 100644
--- a/arch/arm/mach-prima2/rstc.c
+++ b/arch/arm/mach-prima2/rstc.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/reboot.h>
void __iomem *sirfsoc_rstc_base;
static DEFINE_MUTEX(rstc_lock);
@@ -84,7 +85,7 @@ int sirfsoc_reset_device(struct device *dev)
#define SIRFSOC_SYS_RST_BIT BIT(31)
-void sirfsoc_restart(char mode, const char *cmd)
+void sirfsoc_restart(enum reboot_mode mode, const char *cmd)
{
writel(SIRFSOC_SYS_RST_BIT, sirfsoc_rstc_base);
}
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 96100dbf5a2e..a8427115ee07 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -615,12 +615,14 @@ endmenu
config PXA25x
bool
select CPU_XSCALE
+ select CPU_FREQ_TABLE if CPU_FREQ
help
Select code specific to PXA21x/25x/26x variants
config PXA27x
bool
select CPU_XSCALE
+ select CPU_FREQ_TABLE if CPU_FREQ
help
Select code specific to PXA27x variants
@@ -633,6 +635,7 @@ config CPU_PXA26x
config PXA3xx
bool
select CPU_XSC3
+ select CPU_FREQ_TABLE if CPU_FREQ
help
Select code specific to PXA3xx variants
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index a5b8fead7d61..f162f1b77cd2 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -663,16 +663,16 @@ static void corgi_poweroff(void)
/* Green LED off tells the bootloader to halt */
gpio_set_value(CORGI_GPIO_LED_GREEN, 0);
- pxa_restart('h', NULL);
+ pxa_restart(REBOOT_HARD, NULL);
}
-static void corgi_restart(char mode, const char *cmd)
+static void corgi_restart(enum reboot_mode mode, const char *cmd)
{
if (!machine_is_corgi())
/* Green LED on tells the bootloader to reboot */
gpio_set_value(CORGI_GPIO_LED_GREEN, 1);
- pxa_restart('h', cmd);
+ pxa_restart(REBOOT_HARD, cmd);
}
static void __init corgi_init(void)
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 446563a7d1ad..f6726bb4eb95 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -833,21 +833,25 @@ static inline void em_x270_init_ac97(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int em_x270_module_matrix_keys[] = {
+static const unsigned int em_x270_module_matrix_keys[] = {
KEY(0, 0, KEY_A), KEY(1, 0, KEY_UP), KEY(2, 1, KEY_B),
KEY(0, 2, KEY_LEFT), KEY(1, 1, KEY_ENTER), KEY(2, 0, KEY_RIGHT),
KEY(0, 1, KEY_C), KEY(1, 2, KEY_DOWN), KEY(2, 2, KEY_D),
};
+static struct matrix_keymap_data em_x270_matrix_keymap_data = {
+ .keymap = em_x270_module_matrix_keys,
+ .keymap_size = ARRAY_SIZE(em_x270_module_matrix_keys),
+};
+
struct pxa27x_keypad_platform_data em_x270_module_keypad_info = {
/* code map for the matrix keys */
.matrix_key_rows = 3,
.matrix_key_cols = 3,
- .matrix_key_map = em_x270_module_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(em_x270_module_matrix_keys),
+ .matrix_keymap_data = &em_x270_matrix_keymap_data,
};
-static unsigned int em_x270_exeda_matrix_keys[] = {
+static const unsigned int em_x270_exeda_matrix_keys[] = {
KEY(0, 0, KEY_RIGHTSHIFT), KEY(0, 1, KEY_RIGHTCTRL),
KEY(0, 2, KEY_RIGHTALT), KEY(0, 3, KEY_SPACE),
KEY(0, 4, KEY_LEFTALT), KEY(0, 5, KEY_LEFTCTRL),
@@ -889,12 +893,16 @@ static unsigned int em_x270_exeda_matrix_keys[] = {
KEY(7, 6, 0), KEY(7, 7, 0),
};
+static struct matrix_keymap_data em_x270_exeda_matrix_keymap_data = {
+ .keymap = em_x270_exeda_matrix_keys,
+ .keymap_size = ARRAY_SIZE(em_x270_exeda_matrix_keys),
+};
+
struct pxa27x_keypad_platform_data em_x270_exeda_keypad_info = {
/* code map for the matrix keys */
.matrix_key_rows = 8,
.matrix_key_cols = 8,
- .matrix_key_map = em_x270_exeda_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(em_x270_exeda_matrix_keys),
+ .matrix_keymap_data = &em_x270_exeda_matrix_keymap_data,
};
static void __init em_x270_init_keypad(void)
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index dca10709be8f..fe2eb8394dff 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -392,7 +392,7 @@ static unsigned long e6_pin_config[] __initdata = {
/* KEYPAD */
#ifdef CONFIG_MACH_EZX_A780
-static unsigned int a780_key_map[] = {
+static const unsigned int a780_key_map[] = {
KEY(0, 0, KEY_SEND),
KEY(0, 1, KEY_BACK),
KEY(0, 2, KEY_END),
@@ -424,11 +424,15 @@ static unsigned int a780_key_map[] = {
KEY(4, 4, KEY_DOWN),
};
+static struct matrix_keymap_data a780_matrix_keymap_data = {
+ .keymap = a780_key_map,
+ .keymap_size = ARRAY_SIZE(a780_key_map),
+};
+
static struct pxa27x_keypad_platform_data a780_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 5,
- .matrix_key_map = a780_key_map,
- .matrix_key_map_size = ARRAY_SIZE(a780_key_map),
+ .matrix_keymap_data = &a780_matrix_keymap_data,
.direct_key_map = { KEY_CAMERA },
.direct_key_num = 1,
@@ -438,7 +442,7 @@ static struct pxa27x_keypad_platform_data a780_keypad_platform_data = {
#endif /* CONFIG_MACH_EZX_A780 */
#ifdef CONFIG_MACH_EZX_E680
-static unsigned int e680_key_map[] = {
+static const unsigned int e680_key_map[] = {
KEY(0, 0, KEY_UP),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_RESERVED),
@@ -455,11 +459,15 @@ static unsigned int e680_key_map[] = {
KEY(2, 3, KEY_KPENTER),
};
+static struct matrix_keymap_data e680_matrix_keymap_data = {
+ .keymap = e680_key_map,
+ .keymap_size = ARRAY_SIZE(e680_key_map),
+};
+
static struct pxa27x_keypad_platform_data e680_keypad_platform_data = {
.matrix_key_rows = 3,
.matrix_key_cols = 4,
- .matrix_key_map = e680_key_map,
- .matrix_key_map_size = ARRAY_SIZE(e680_key_map),
+ .matrix_keymap_data = &e680_matrix_keymap_data,
.direct_key_map = {
KEY_CAMERA,
@@ -476,7 +484,7 @@ static struct pxa27x_keypad_platform_data e680_keypad_platform_data = {
#endif /* CONFIG_MACH_EZX_E680 */
#ifdef CONFIG_MACH_EZX_A1200
-static unsigned int a1200_key_map[] = {
+static const unsigned int a1200_key_map[] = {
KEY(0, 0, KEY_RESERVED),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_PAGEDOWN),
@@ -513,18 +521,22 @@ static unsigned int a1200_key_map[] = {
KEY(4, 5, KEY_RESERVED),
};
+static struct matrix_keymap_data a1200_matrix_keymap_data = {
+ .keymap = a1200_key_map,
+ .keymap_size = ARRAY_SIZE(a1200_key_map),
+};
+
static struct pxa27x_keypad_platform_data a1200_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
- .matrix_key_map = a1200_key_map,
- .matrix_key_map_size = ARRAY_SIZE(a1200_key_map),
+ .matrix_keymap_data = &a1200_matrix_keymap_data,
.debounce_interval = 30,
};
#endif /* CONFIG_MACH_EZX_A1200 */
#ifdef CONFIG_MACH_EZX_E6
-static unsigned int e6_key_map[] = {
+static const unsigned int e6_key_map[] = {
KEY(0, 0, KEY_RESERVED),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_PAGEDOWN),
@@ -561,18 +573,22 @@ static unsigned int e6_key_map[] = {
KEY(4, 5, KEY_PREVIOUSSONG),
};
+static struct matrix_keymap_data e6_keymap_data = {
+ .keymap = e6_key_map,
+ .keymap_size = ARRAY_SIZE(e6_key_map),
+};
+
static struct pxa27x_keypad_platform_data e6_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
- .matrix_key_map = e6_key_map,
- .matrix_key_map_size = ARRAY_SIZE(e6_key_map),
+ .matrix_keymap_data = &e6_keymap_data,
.debounce_interval = 30,
};
#endif /* CONFIG_MACH_EZX_E6 */
#ifdef CONFIG_MACH_EZX_A910
-static unsigned int a910_key_map[] = {
+static const unsigned int a910_key_map[] = {
KEY(0, 0, KEY_NUMERIC_6),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_PAGEDOWN),
@@ -609,18 +625,22 @@ static unsigned int a910_key_map[] = {
KEY(4, 5, KEY_RESERVED),
};
+static struct matrix_keymap_data a910_matrix_keymap_data = {
+ .keymap = a910_key_map,
+ .keymap_size = ARRAY_SIZE(a910_key_map),
+};
+
static struct pxa27x_keypad_platform_data a910_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
- .matrix_key_map = a910_key_map,
- .matrix_key_map_size = ARRAY_SIZE(a910_key_map),
+ .matrix_keymap_data = &a910_matrix_keymap_data,
.debounce_interval = 30,
};
#endif /* CONFIG_MACH_EZX_A910 */
#ifdef CONFIG_MACH_EZX_E2
-static unsigned int e2_key_map[] = {
+static const unsigned int e2_key_map[] = {
KEY(0, 0, KEY_NUMERIC_6),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_NUMERIC_9),
@@ -657,11 +677,15 @@ static unsigned int e2_key_map[] = {
KEY(4, 5, KEY_RESERVED),
};
+static struct matrix_keymap_data e2_matrix_keymap_data = {
+ .keymap = e2_key_map,
+ .keymap_size = ARRAY_SIZE(e2_key_map),
+};
+
static struct pxa27x_keypad_platform_data e2_keypad_platform_data = {
.matrix_key_rows = 5,
.matrix_key_cols = 6,
- .matrix_key_map = e2_key_map,
- .matrix_key_map_size = ARRAY_SIZE(e2_key_map),
+ .matrix_keymap_data = &e2_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index fd7ea39b78c0..8963984d1f43 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -9,6 +9,8 @@
* published by the Free Software Foundation.
*/
+#include <linux/reboot.h>
+
struct irq_data;
extern void pxa_timer_init(void);
@@ -56,4 +58,4 @@ void __init pxa_set_btuart_info(void *info);
void __init pxa_set_stuart_info(void *info);
void __init pxa_set_hwuart_info(void *info);
-void pxa_restart(char, const char *);
+void pxa_restart(enum reboot_mode, const char *);
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index e848c4607baf..5d665588c7eb 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -222,7 +222,7 @@ static inline void littleton_init_spi(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int littleton_matrix_key_map[] = {
+static const unsigned int littleton_matrix_key_map[] = {
/* KEY(row, col, key_code) */
KEY(1, 3, KEY_0), KEY(0, 0, KEY_1), KEY(1, 0, KEY_2), KEY(2, 0, KEY_3),
KEY(0, 1, KEY_4), KEY(1, 1, KEY_5), KEY(2, 1, KEY_6), KEY(0, 2, KEY_7),
@@ -249,11 +249,15 @@ static unsigned int littleton_matrix_key_map[] = {
KEY(3, 1, KEY_F23), /* soft2 */
};
+static struct matrix_keymap_data littleton_matrix_keymap_data = {
+ .keymap = littleton_matrix_key_map,
+ .keymap_size = ARRAY_SIZE(littleton_matrix_key_map),
+};
+
static struct pxa27x_keypad_platform_data littleton_keypad_info = {
.matrix_key_rows = 6,
.matrix_key_cols = 5,
- .matrix_key_map = littleton_matrix_key_map,
- .matrix_key_map_size = ARRAY_SIZE(littleton_matrix_key_map),
+ .matrix_keymap_data = &littleton_matrix_keymap_data,
.enable_rotary0 = 1,
.rotary0_up_key = KEY_UP,
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 7a12c1ba90ff..d2c652318376 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -498,7 +498,7 @@ static struct pxaohci_platform_data mainstone_ohci_platform_data = {
};
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int mainstone_matrix_keys[] = {
+static const unsigned int mainstone_matrix_keys[] = {
KEY(0, 0, KEY_A), KEY(1, 0, KEY_B), KEY(2, 0, KEY_C),
KEY(3, 0, KEY_D), KEY(4, 0, KEY_E), KEY(5, 0, KEY_F),
KEY(0, 1, KEY_G), KEY(1, 1, KEY_H), KEY(2, 1, KEY_I),
@@ -527,11 +527,15 @@ static unsigned int mainstone_matrix_keys[] = {
KEY(4, 6, KEY_SELECT),
};
+static struct matrix_keymap_data mainstone_matrix_keymap_data = {
+ .keymap = mainstone_matrix_keys,
+ .keymap_size = ARRAY_SIZE(mainstone_matrix_keys),
+};
+
struct pxa27x_keypad_platform_data mainstone_keypad_info = {
.matrix_key_rows = 6,
.matrix_key_cols = 7,
- .matrix_key_map = mainstone_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(mainstone_matrix_keys),
+ .matrix_keymap_data = &mainstone_matrix_keymap_data,
.enable_rotary0 = 1,
.rotary0_up_key = KEY_UP,
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index f8979b943cbf..acc9d3cc0762 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -37,6 +37,7 @@
#include <linux/wm97xx.h>
#include <linux/mtd/physmap.h>
#include <linux/usb/gpio_vbus.h>
+#include <linux/reboot.h>
#include <linux/regulator/max1586.h>
#include <linux/slab.h>
#include <linux/i2c/pxa-i2c.h>
@@ -222,7 +223,7 @@ static struct pxafb_mach_info mioa701_pxafb_info = {
/*
* Keyboard configuration
*/
-static unsigned int mioa701_matrix_keys[] = {
+static const unsigned int mioa701_matrix_keys[] = {
KEY(0, 0, KEY_UP),
KEY(0, 1, KEY_RIGHT),
KEY(0, 2, KEY_MEDIA),
@@ -233,11 +234,16 @@ static unsigned int mioa701_matrix_keys[] = {
KEY(2, 1, KEY_PHONE), /* Phone Green key */
KEY(2, 2, KEY_CAMERA) /* Camera key */
};
+
+static struct matrix_keymap_data mioa701_matrix_keymap_data = {
+ .keymap = mioa701_matrix_keys,
+ .keymap_size = ARRAY_SIZE(mioa701_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data mioa701_keypad_info = {
.matrix_key_rows = 3,
.matrix_key_cols = 3,
- .matrix_key_map = mioa701_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(mioa701_matrix_keys),
+ .matrix_keymap_data = &mioa701_matrix_keymap_data,
};
/*
@@ -691,13 +697,13 @@ static void mioa701_machine_exit(void);
static void mioa701_poweroff(void)
{
mioa701_machine_exit();
- pxa_restart('s', NULL);
+ pxa_restart(REBOOT_SOFT, NULL);
}
-static void mioa701_restart(char c, const char *cmd)
+static void mioa701_restart(enum reboot_mode c, const char *cmd)
{
mioa701_machine_exit();
- pxa_restart('s', cmd);
+ pxa_restart(REBOOT_SOFT, cmd);
}
static struct gpio global_gpios[] = {
@@ -756,7 +762,6 @@ static void mioa701_machine_exit(void)
MACHINE_START(MIOA701, "MIO A701")
.atag_offset = 0x100,
- .restart_mode = 's',
.map_io = &pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
.init_irq = &pxa27x_init_irq,
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index 909b713e5789..cf210b11ffcc 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -173,7 +173,7 @@ static inline void palmld_nor_init(void) {}
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int palmld_matrix_keys[] = {
+static const unsigned int palmld_matrix_keys[] = {
KEY(0, 1, KEY_F2),
KEY(0, 2, KEY_UP),
@@ -190,11 +190,15 @@ static unsigned int palmld_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
+static struct matrix_keymap_data palmld_matrix_keymap_data = {
+ .keymap = palmld_matrix_keys,
+ .keymap_size = ARRAY_SIZE(palmld_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data palmld_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
- .matrix_key_map = palmld_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(palmld_matrix_keys),
+ .matrix_keymap_data = &palmld_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/palmt5.c b/arch/arm/mach-pxa/palmt5.c
index 5033fd07968f..3ed9b029428b 100644
--- a/arch/arm/mach-pxa/palmt5.c
+++ b/arch/arm/mach-pxa/palmt5.c
@@ -108,7 +108,7 @@ static unsigned long palmt5_pin_config[] __initdata = {
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int palmt5_matrix_keys[] = {
+static const unsigned int palmt5_matrix_keys[] = {
KEY(0, 0, KEY_POWER),
KEY(0, 1, KEY_F1),
KEY(0, 2, KEY_ENTER),
@@ -124,11 +124,15 @@ static unsigned int palmt5_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
+static struct matrix_keymap_data palmt5_matrix_keymap_data = {
+ .keymap = palmt5_matrix_keys,
+ .keymap_size = ARRAY_SIZE(palmt5_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data palmt5_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
- .matrix_key_map = palmt5_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(palmt5_matrix_keys),
+ .matrix_keymap_data = &palmt5_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index d82a50b4a803..d8b937c870de 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -168,7 +168,7 @@ static unsigned long centro685_pin_config[] __initdata = {
* GPIO keyboard
******************************************************************************/
#if IS_ENABLED(CONFIG_KEYBOARD_PXA27x)
-static unsigned int treo680_matrix_keys[] = {
+static const unsigned int treo680_matrix_keys[] = {
KEY(0, 0, KEY_F8), /* Red/Off/Power */
KEY(0, 1, KEY_LEFT),
KEY(0, 2, KEY_LEFTCTRL), /* Alternate */
@@ -227,7 +227,7 @@ static unsigned int treo680_matrix_keys[] = {
KEY(7, 5, KEY_I),
};
-static unsigned int centro_matrix_keys[] = {
+static const unsigned int centro_matrix_keys[] = {
KEY(0, 0, KEY_F9), /* Home */
KEY(0, 1, KEY_LEFT),
KEY(0, 2, KEY_LEFTCTRL), /* Alternate */
@@ -286,11 +286,20 @@ static unsigned int centro_matrix_keys[] = {
KEY(7, 5, KEY_I),
};
+static struct matrix_keymap_data treo680_matrix_keymap_data = {
+ .keymap = treo680_matrix_keys,
+ .keymap_size = ARRAY_SIZE(treo680_matrix_keys),
+};
+
+static struct matrix_keymap_data centro_matrix_keymap_data = {
+ .keymap = centro_matrix_keys,
+ .keymap_size = ARRAY_SIZE(centro_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data treo680_keypad_pdata = {
.matrix_key_rows = 8,
.matrix_key_cols = 7,
- .matrix_key_map = treo680_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(treo680_matrix_keys),
+ .matrix_keymap_data = &treo680_matrix_keymap_data,
.direct_key_map = { KEY_CONNECT },
.direct_key_num = 1,
@@ -301,10 +310,8 @@ static void __init palmtreo_kpc_init(void)
{
static struct pxa27x_keypad_platform_data *data = &treo680_keypad_pdata;
- if (machine_is_centro()) {
- data->matrix_key_map = centro_matrix_keys;
- data->matrix_key_map_size = ARRAY_SIZE(centro_matrix_keys);
- }
+ if (machine_is_centro())
+ data->matrix_keymap_data = &centro_matrix_keymap_data;
pxa_set_keypad_info(&treo680_keypad_pdata);
}
diff --git a/arch/arm/mach-pxa/palmtx.c b/arch/arm/mach-pxa/palmtx.c
index 627c93a7364c..83f830dd8ad8 100644
--- a/arch/arm/mach-pxa/palmtx.c
+++ b/arch/arm/mach-pxa/palmtx.c
@@ -176,7 +176,7 @@ static inline void palmtx_nor_init(void) {}
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int palmtx_matrix_keys[] = {
+static const unsigned int palmtx_matrix_keys[] = {
KEY(0, 0, KEY_POWER),
KEY(0, 1, KEY_F1),
KEY(0, 2, KEY_ENTER),
@@ -192,11 +192,15 @@ static unsigned int palmtx_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
+static struct matrix_keymap_data palmtx_matrix_keymap_data = {
+ .keymap = palmtx_matrix_keys,
+ .keymap_size = ARRAY_SIZE(palmtx_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data palmtx_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
- .matrix_key_map = palmtx_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(palmtx_matrix_keys),
+ .matrix_keymap_data = &palmtx_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index 18b7fcd98592..1a35ddf218da 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -140,7 +140,7 @@ static unsigned long palmz72_pin_config[] __initdata = {
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int palmz72_matrix_keys[] = {
+static const unsigned int palmz72_matrix_keys[] = {
KEY(0, 0, KEY_POWER),
KEY(0, 1, KEY_F1),
KEY(0, 2, KEY_ENTER),
@@ -156,11 +156,15 @@ static unsigned int palmz72_matrix_keys[] = {
KEY(3, 2, KEY_LEFT),
};
+static struct matrix_keymap_data almz72_matrix_keymap_data = {
+ .keymap = palmz72_matrix_keys,
+ .keymap_size = ARRAY_SIZE(palmz72_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data palmz72_keypad_platform_data = {
.matrix_key_rows = 4,
.matrix_key_cols = 3,
- .matrix_key_map = palmz72_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(palmz72_matrix_keys),
+ .matrix_keymap_data = &almz72_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 50ccd5f1d560..711d37e26bd8 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -422,7 +422,7 @@ static struct i2c_board_info __initdata poodle_i2c_devices[] = {
static void poodle_poweroff(void)
{
- pxa_restart('h', NULL);
+ pxa_restart(REBOOT_HARD, NULL);
}
static void __init poodle_init(void)
diff --git a/arch/arm/mach-pxa/reset.c b/arch/arm/mach-pxa/reset.c
index 3fab583755d4..0d5dd646f61f 100644
--- a/arch/arm/mach-pxa/reset.c
+++ b/arch/arm/mach-pxa/reset.c
@@ -83,7 +83,7 @@ static void do_hw_reset(void)
writel_relaxed(readl_relaxed(OSCR) + 368640, OSMR3);
}
-void pxa_restart(char mode, const char *cmd)
+void pxa_restart(enum reboot_mode mode, const char *cmd)
{
local_irq_disable();
local_fiq_disable();
@@ -91,14 +91,14 @@ void pxa_restart(char mode, const char *cmd)
clear_reset_status(RESET_STATUS_ALL);
switch (mode) {
- case 's':
+ case REBOOT_SOFT:
/* Jump into ROM at address 0 */
soft_restart(0);
break;
- case 'g':
+ case REBOOT_GPIO:
do_gpio_reset();
break;
- case 'h':
+ case REBOOT_HARD:
default:
do_hw_reset();
break;
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 362726c49c70..2125df0444e7 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -31,6 +31,7 @@
#include <linux/regulator/machine.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/reboot.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -924,10 +925,10 @@ static inline void spitz_i2c_init(void) {}
******************************************************************************/
static void spitz_poweroff(void)
{
- pxa_restart('g', NULL);
+ pxa_restart(REBOOT_GPIO, NULL);
}
-static void spitz_restart(char mode, const char *cmd)
+static void spitz_restart(enum reboot_mode mode, const char *cmd)
{
uint32_t msc0 = __raw_readl(MSC0);
/* Bootloader magic for a reboot */
@@ -979,7 +980,6 @@ static void __init spitz_fixup(struct tag *tags, char **cmdline,
#ifdef CONFIG_MACH_SPITZ
MACHINE_START(SPITZ, "SHARP Spitz")
- .restart_mode = 'g',
.fixup = spitz_fixup,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
@@ -993,7 +993,6 @@ MACHINE_END
#ifdef CONFIG_MACH_BORZOI
MACHINE_START(BORZOI, "SHARP Borzoi")
- .restart_mode = 'g',
.fixup = spitz_fixup,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
@@ -1007,7 +1006,6 @@ MACHINE_END
#ifdef CONFIG_MACH_AKITA
MACHINE_START(AKITA, "SHARP Akita")
- .restart_mode = 'g',
.fixup = spitz_fixup,
.map_io = pxa27x_map_io,
.nr_irqs = PXA_NR_IRQS,
diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c
index f55979c09a5f..4680efe55345 100644
--- a/arch/arm/mach-pxa/tavorevb.c
+++ b/arch/arm/mach-pxa/tavorevb.c
@@ -106,7 +106,7 @@ static struct platform_device smc91x_device = {
};
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int tavorevb_matrix_key_map[] = {
+static const unsigned int tavorevb_matrix_key_map[] = {
/* KEY(row, col, key_code) */
KEY(0, 4, KEY_A), KEY(0, 5, KEY_B), KEY(0, 6, KEY_C),
KEY(1, 4, KEY_E), KEY(1, 5, KEY_F), KEY(1, 6, KEY_G),
@@ -147,11 +147,15 @@ static unsigned int tavorevb_matrix_key_map[] = {
KEY(3, 3, KEY_F23), /* soft2 */
};
+static struct matrix_keymap_data tavorevb_matrix_keymap_data = {
+ .keymap = tavorevb_matrix_key_map,
+ .keymap_size = ARRAY_SIZE(tavorevb_matrix_key_map),
+};
+
static struct pxa27x_keypad_platform_data tavorevb_keypad_info = {
.matrix_key_rows = 7,
.matrix_key_cols = 7,
- .matrix_key_map = tavorevb_matrix_key_map,
- .matrix_key_map_size = ARRAY_SIZE(tavorevb_matrix_key_map),
+ .matrix_keymap_data = &tavorevb_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 8f1ee92aea30..9aa852a8fab9 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -16,11 +16,11 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/clockchips.h>
+#include <linux/sched_clock.h>
#include <asm/div64.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-#include <asm/sched_clock.h>
#include <mach/regs-ost.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 3d91d2e5bf3a..0206b915a6f6 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -36,6 +36,7 @@
#include <linux/input/matrix_keypad.h>
#include <linux/i2c/pxa-i2c.h>
#include <linux/usb/gpio_vbus.h>
+#include <linux/reboot.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -911,10 +912,10 @@ static struct platform_device *devices[] __initdata = {
static void tosa_poweroff(void)
{
- pxa_restart('g', NULL);
+ pxa_restart(REBOOT_GPIO, NULL);
}
-static void tosa_restart(char mode, const char *cmd)
+static void tosa_restart(enum reboot_mode mode, const char *cmd)
{
uint32_t msc0 = __raw_readl(MSC0);
@@ -969,7 +970,6 @@ static void __init fixup_tosa(struct tag *tags, char **cmdline,
}
MACHINE_START(TOSA, "SHARP Tosa")
- .restart_mode = 'g',
.fixup = fixup_tosa,
.map_io = pxa25x_map_io,
.nr_irqs = TOSA_NR_IRQS,
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index 989903a7e467..2513d8f4931f 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -345,7 +345,7 @@ static inline void z2_leds_init(void) {}
* GPIO keyboard
******************************************************************************/
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int z2_matrix_keys[] = {
+static const unsigned int z2_matrix_keys[] = {
KEY(0, 0, KEY_OPTION),
KEY(1, 0, KEY_UP),
KEY(2, 0, KEY_DOWN),
@@ -405,11 +405,15 @@ static unsigned int z2_matrix_keys[] = {
KEY(5, 7, KEY_DOT),
};
+static struct matrix_keymap_data z2_matrix_keymap_data = {
+ .keymap = z2_matrix_keys,
+ .keymap_size = ARRAY_SIZE(z2_matrix_keys),
+};
+
static struct pxa27x_keypad_platform_data z2_keypad_platform_data = {
.matrix_key_rows = 7,
.matrix_key_cols = 8,
- .matrix_key_map = z2_matrix_keys,
- .matrix_key_map_size = ARRAY_SIZE(z2_matrix_keys),
+ .matrix_keymap_data = &z2_matrix_keymap_data,
.debounce_interval = 30,
};
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 1f00d650ac27..36cf7cf95ec1 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -263,7 +263,7 @@ static inline void zylonite_init_mmc(void) {}
#endif
#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULE)
-static unsigned int zylonite_matrix_key_map[] = {
+static const unsigned int zylonite_matrix_key_map[] = {
/* KEY(row, col, key_code) */
KEY(0, 0, KEY_A), KEY(0, 1, KEY_B), KEY(0, 2, KEY_C), KEY(0, 5, KEY_D),
KEY(1, 0, KEY_E), KEY(1, 1, KEY_F), KEY(1, 2, KEY_G), KEY(1, 5, KEY_H),
@@ -306,11 +306,15 @@ static unsigned int zylonite_matrix_key_map[] = {
KEY(0, 3, KEY_AUX), /* contact */
};
+static struct matrix_keymap_data zylonite_matrix_keymap_data = {
+ .keymap = zylonite_matrix_key_map,
+ .keymap_size = ARRAY_SIZE(zylonite_matrix_key_map),
+};
+
static struct pxa27x_keypad_platform_data zylonite_keypad_info = {
.matrix_key_rows = 8,
.matrix_key_cols = 8,
- .matrix_key_map = zylonite_matrix_key_map,
- .matrix_key_map_size = ARRAY_SIZE(zylonite_matrix_key_map),
+ .matrix_keymap_data = &zylonite_matrix_keymap_data,
.enable_rotary0 = 1,
.rotary0_up_key = KEY_UP,
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 5b1c8bfe6fa9..c85ddb2a0ad0 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -418,7 +419,7 @@ static void __init realview_eb_timer_init(void)
realview_eb_twd_init();
}
-static void realview_eb_restart(char mode, const char *cmd)
+static void realview_eb_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c
index d5e83a1f6982..c5eade76461b 100644
--- a/arch/arm/mach-realview/realview_pb1176.c
+++ b/arch/arm/mach-realview/realview_pb1176.c
@@ -31,6 +31,7 @@
#include <linux/io.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -329,7 +330,7 @@ static void __init realview_pb1176_timer_init(void)
realview_timer_init(IRQ_DC1176_TIMER0);
}
-static void realview_pb1176_restart(char mode, const char *cmd)
+static void realview_pb1176_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index c3cfe213b5e6..f4b0962578fe 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
+#include <linux/reboot.h>
#include <mach/hardware.h>
#include <asm/irq.h>
@@ -316,7 +317,7 @@ static void __init realview_pb11mp_timer_init(void)
realview_pb11mp_twd_init();
}
-static void realview_pb11mp_restart(char mode, const char *cmd)
+static void realview_pb11mp_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c
index dde652a59620..10a3e1d76891 100644
--- a/arch/arm/mach-realview/realview_pba8.c
+++ b/arch/arm/mach-realview/realview_pba8.c
@@ -29,6 +29,7 @@
#include <linux/io.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
+#include <linux/reboot.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -264,7 +265,7 @@ static void __init realview_pba8_timer_init(void)
realview_timer_init(IRQ_PBA8_TIMER0_1);
}
-static void realview_pba8_restart(char mode, const char *cmd)
+static void realview_pba8_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index 54f0185b01e3..9d75493e3f0c 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/platform_data/clk-realview.h>
+#include <linux/reboot.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
@@ -344,7 +345,7 @@ static void realview_pbx_fixup(struct tag *tags, char **from,
#endif
}
-static void realview_pbx_restart(char mode, const char *cmd)
+static void realview_pbx_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *reset_ctrl = __io_address(REALVIEW_SYS_RESETCTL);
void __iomem *lock_ctrl = __io_address(REALVIEW_SYS_LOCK);
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index a302cf5e0fc7..09d602b10d57 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -20,6 +20,7 @@
#include <linux/ata_platform.h>
#include <linux/io.h>
#include <linux/i2c.h>
+#include <linux/reboot.h>
#include <asm/elf.h>
#include <asm/mach-types.h>
@@ -201,7 +202,7 @@ static int __init rpc_init(void)
arch_initcall(rpc_init);
-static void rpc_restart(char mode, const char *cmd)
+static void rpc_restart(enum reboot_mode mode, const char *cmd)
{
iomd_writeb(0, IOMD_ROMCR0);
diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h
index 307c3714be55..84b280654f4c 100644
--- a/arch/arm/mach-s3c24xx/common.h
+++ b/arch/arm/mach-s3c24xx/common.h
@@ -12,6 +12,8 @@
#ifndef __ARCH_ARM_MACH_S3C24XX_COMMON_H
#define __ARCH_ARM_MACH_S3C24XX_COMMON_H __FILE__
+#include <linux/reboot.h>
+
struct s3c2410_uartcfg;
#ifdef CONFIG_CPU_S3C2410
@@ -20,7 +22,7 @@ extern int s3c2410a_init(void);
extern void s3c2410_map_io(void);
extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c2410_init_clocks(int xtal);
-extern void s3c2410_restart(char mode, const char *cmd);
+extern void s3c2410_restart(enum reboot_mode mode, const char *cmd);
extern void s3c2410_init_irq(void);
#else
#define s3c2410_init_clocks NULL
@@ -36,7 +38,7 @@ extern void s3c2412_map_io(void);
extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c2412_init_clocks(int xtal);
extern int s3c2412_baseclk_add(void);
-extern void s3c2412_restart(char mode, const char *cmd);
+extern void s3c2412_restart(enum reboot_mode mode, const char *cmd);
extern void s3c2412_init_irq(void);
#else
#define s3c2412_init_clocks NULL
@@ -51,7 +53,7 @@ extern void s3c2416_map_io(void);
extern void s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c2416_init_clocks(int xtal);
extern int s3c2416_baseclk_add(void);
-extern void s3c2416_restart(char mode, const char *cmd);
+extern void s3c2416_restart(enum reboot_mode mode, const char *cmd);
extern void s3c2416_init_irq(void);
extern struct syscore_ops s3c2416_irq_syscore_ops;
@@ -66,7 +68,7 @@ extern struct syscore_ops s3c2416_irq_syscore_ops;
extern void s3c244x_map_io(void);
extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c244x_init_clocks(int xtal);
-extern void s3c244x_restart(char mode, const char *cmd);
+extern void s3c244x_restart(enum reboot_mode mode, const char *cmd);
#else
#define s3c244x_init_clocks NULL
#define s3c244x_init_uarts NULL
@@ -96,7 +98,7 @@ extern void s3c2443_map_io(void);
extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no);
extern void s3c2443_init_clocks(int xtal);
extern int s3c2443_baseclk_add(void);
-extern void s3c2443_restart(char mode, const char *cmd);
+extern void s3c2443_restart(enum reboot_mode mode, const char *cmd);
extern void s3c2443_init_irq(void);
#else
#define s3c2443_init_clocks NULL
diff --git a/arch/arm/mach-s3c24xx/cpufreq-utils.c b/arch/arm/mach-s3c24xx/cpufreq-utils.c
index ddd8280e3875..2a0aa5684e72 100644
--- a/arch/arm/mach-s3c24xx/cpufreq-utils.c
+++ b/arch/arm/mach-s3c24xx/cpufreq-utils.c
@@ -60,5 +60,5 @@ void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg)
*/
void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg)
{
- __raw_writel(cfg->pll.index, S3C2410_MPLLCON);
+ __raw_writel(cfg->pll.driver_data, S3C2410_MPLLCON);
}
diff --git a/arch/arm/mach-s3c24xx/pll-s3c2410.c b/arch/arm/mach-s3c24xx/pll-s3c2410.c
index dcf3420a3271..5e37d368594b 100644
--- a/arch/arm/mach-s3c24xx/pll-s3c2410.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2410.c
@@ -33,36 +33,36 @@
#include <plat/cpu-freq-core.h>
static struct cpufreq_frequency_table pll_vals_12MHz[] = {
- { .frequency = 34000000, .index = PLLVAL(82, 2, 3), },
- { .frequency = 45000000, .index = PLLVAL(82, 1, 3), },
- { .frequency = 51000000, .index = PLLVAL(161, 3, 3), },
- { .frequency = 48000000, .index = PLLVAL(120, 2, 3), },
- { .frequency = 56000000, .index = PLLVAL(142, 2, 3), },
- { .frequency = 68000000, .index = PLLVAL(82, 2, 2), },
- { .frequency = 79000000, .index = PLLVAL(71, 1, 2), },
- { .frequency = 85000000, .index = PLLVAL(105, 2, 2), },
- { .frequency = 90000000, .index = PLLVAL(112, 2, 2), },
- { .frequency = 101000000, .index = PLLVAL(127, 2, 2), },
- { .frequency = 113000000, .index = PLLVAL(105, 1, 2), },
- { .frequency = 118000000, .index = PLLVAL(150, 2, 2), },
- { .frequency = 124000000, .index = PLLVAL(116, 1, 2), },
- { .frequency = 135000000, .index = PLLVAL(82, 2, 1), },
- { .frequency = 147000000, .index = PLLVAL(90, 2, 1), },
- { .frequency = 152000000, .index = PLLVAL(68, 1, 1), },
- { .frequency = 158000000, .index = PLLVAL(71, 1, 1), },
- { .frequency = 170000000, .index = PLLVAL(77, 1, 1), },
- { .frequency = 180000000, .index = PLLVAL(82, 1, 1), },
- { .frequency = 186000000, .index = PLLVAL(85, 1, 1), },
- { .frequency = 192000000, .index = PLLVAL(88, 1, 1), },
- { .frequency = 203000000, .index = PLLVAL(161, 3, 1), },
+ { .frequency = 34000000, .driver_data = PLLVAL(82, 2, 3), },
+ { .frequency = 45000000, .driver_data = PLLVAL(82, 1, 3), },
+ { .frequency = 51000000, .driver_data = PLLVAL(161, 3, 3), },
+ { .frequency = 48000000, .driver_data = PLLVAL(120, 2, 3), },
+ { .frequency = 56000000, .driver_data = PLLVAL(142, 2, 3), },
+ { .frequency = 68000000, .driver_data = PLLVAL(82, 2, 2), },
+ { .frequency = 79000000, .driver_data = PLLVAL(71, 1, 2), },
+ { .frequency = 85000000, .driver_data = PLLVAL(105, 2, 2), },
+ { .frequency = 90000000, .driver_data = PLLVAL(112, 2, 2), },
+ { .frequency = 101000000, .driver_data = PLLVAL(127, 2, 2), },
+ { .frequency = 113000000, .driver_data = PLLVAL(105, 1, 2), },
+ { .frequency = 118000000, .driver_data = PLLVAL(150, 2, 2), },
+ { .frequency = 124000000, .driver_data = PLLVAL(116, 1, 2), },
+ { .frequency = 135000000, .driver_data = PLLVAL(82, 2, 1), },
+ { .frequency = 147000000, .driver_data = PLLVAL(90, 2, 1), },
+ { .frequency = 152000000, .driver_data = PLLVAL(68, 1, 1), },
+ { .frequency = 158000000, .driver_data = PLLVAL(71, 1, 1), },
+ { .frequency = 170000000, .driver_data = PLLVAL(77, 1, 1), },
+ { .frequency = 180000000, .driver_data = PLLVAL(82, 1, 1), },
+ { .frequency = 186000000, .driver_data = PLLVAL(85, 1, 1), },
+ { .frequency = 192000000, .driver_data = PLLVAL(88, 1, 1), },
+ { .frequency = 203000000, .driver_data = PLLVAL(161, 3, 1), },
/* 2410A extras */
- { .frequency = 210000000, .index = PLLVAL(132, 2, 1), },
- { .frequency = 226000000, .index = PLLVAL(105, 1, 1), },
- { .frequency = 266000000, .index = PLLVAL(125, 1, 1), },
- { .frequency = 268000000, .index = PLLVAL(126, 1, 1), },
- { .frequency = 270000000, .index = PLLVAL(127, 1, 1), },
+ { .frequency = 210000000, .driver_data = PLLVAL(132, 2, 1), },
+ { .frequency = 226000000, .driver_data = PLLVAL(105, 1, 1), },
+ { .frequency = 266000000, .driver_data = PLLVAL(125, 1, 1), },
+ { .frequency = 268000000, .driver_data = PLLVAL(126, 1, 1), },
+ { .frequency = 270000000, .driver_data = PLLVAL(127, 1, 1), },
};
static int s3c2410_plls_add(struct device *dev, struct subsys_interface *sif)
diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
index 673781758319..a19460e6e7b0 100644
--- a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
@@ -21,33 +21,33 @@
#include <plat/cpu-freq-core.h>
static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = {
- { .frequency = 75000000, .index = PLLVAL(0x75, 3, 3), }, /* FVco 600.000000 */
- { .frequency = 80000000, .index = PLLVAL(0x98, 4, 3), }, /* FVco 640.000000 */
- { .frequency = 90000000, .index = PLLVAL(0x70, 2, 3), }, /* FVco 720.000000 */
- { .frequency = 100000000, .index = PLLVAL(0x5c, 1, 3), }, /* FVco 800.000000 */
- { .frequency = 110000000, .index = PLLVAL(0x66, 1, 3), }, /* FVco 880.000000 */
- { .frequency = 120000000, .index = PLLVAL(0x70, 1, 3), }, /* FVco 960.000000 */
- { .frequency = 150000000, .index = PLLVAL(0x75, 3, 2), }, /* FVco 600.000000 */
- { .frequency = 160000000, .index = PLLVAL(0x98, 4, 2), }, /* FVco 640.000000 */
- { .frequency = 170000000, .index = PLLVAL(0x4d, 1, 2), }, /* FVco 680.000000 */
- { .frequency = 180000000, .index = PLLVAL(0x70, 2, 2), }, /* FVco 720.000000 */
- { .frequency = 190000000, .index = PLLVAL(0x57, 1, 2), }, /* FVco 760.000000 */
- { .frequency = 200000000, .index = PLLVAL(0x5c, 1, 2), }, /* FVco 800.000000 */
- { .frequency = 210000000, .index = PLLVAL(0x84, 2, 2), }, /* FVco 840.000000 */
- { .frequency = 220000000, .index = PLLVAL(0x66, 1, 2), }, /* FVco 880.000000 */
- { .frequency = 230000000, .index = PLLVAL(0x6b, 1, 2), }, /* FVco 920.000000 */
- { .frequency = 240000000, .index = PLLVAL(0x70, 1, 2), }, /* FVco 960.000000 */
- { .frequency = 300000000, .index = PLLVAL(0x75, 3, 1), }, /* FVco 600.000000 */
- { .frequency = 310000000, .index = PLLVAL(0x93, 4, 1), }, /* FVco 620.000000 */
- { .frequency = 320000000, .index = PLLVAL(0x98, 4, 1), }, /* FVco 640.000000 */
- { .frequency = 330000000, .index = PLLVAL(0x66, 2, 1), }, /* FVco 660.000000 */
- { .frequency = 340000000, .index = PLLVAL(0x4d, 1, 1), }, /* FVco 680.000000 */
- { .frequency = 350000000, .index = PLLVAL(0xa7, 4, 1), }, /* FVco 700.000000 */
- { .frequency = 360000000, .index = PLLVAL(0x70, 2, 1), }, /* FVco 720.000000 */
- { .frequency = 370000000, .index = PLLVAL(0xb1, 4, 1), }, /* FVco 740.000000 */
- { .frequency = 380000000, .index = PLLVAL(0x57, 1, 1), }, /* FVco 760.000000 */
- { .frequency = 390000000, .index = PLLVAL(0x7a, 2, 1), }, /* FVco 780.000000 */
- { .frequency = 400000000, .index = PLLVAL(0x5c, 1, 1), }, /* FVco 800.000000 */
+ { .frequency = 75000000, .driver_data = PLLVAL(0x75, 3, 3), }, /* FVco 600.000000 */
+ { .frequency = 80000000, .driver_data = PLLVAL(0x98, 4, 3), }, /* FVco 640.000000 */
+ { .frequency = 90000000, .driver_data = PLLVAL(0x70, 2, 3), }, /* FVco 720.000000 */
+ { .frequency = 100000000, .driver_data = PLLVAL(0x5c, 1, 3), }, /* FVco 800.000000 */
+ { .frequency = 110000000, .driver_data = PLLVAL(0x66, 1, 3), }, /* FVco 880.000000 */
+ { .frequency = 120000000, .driver_data = PLLVAL(0x70, 1, 3), }, /* FVco 960.000000 */
+ { .frequency = 150000000, .driver_data = PLLVAL(0x75, 3, 2), }, /* FVco 600.000000 */
+ { .frequency = 160000000, .driver_data = PLLVAL(0x98, 4, 2), }, /* FVco 640.000000 */
+ { .frequency = 170000000, .driver_data = PLLVAL(0x4d, 1, 2), }, /* FVco 680.000000 */
+ { .frequency = 180000000, .driver_data = PLLVAL(0x70, 2, 2), }, /* FVco 720.000000 */
+ { .frequency = 190000000, .driver_data = PLLVAL(0x57, 1, 2), }, /* FVco 760.000000 */
+ { .frequency = 200000000, .driver_data = PLLVAL(0x5c, 1, 2), }, /* FVco 800.000000 */
+ { .frequency = 210000000, .driver_data = PLLVAL(0x84, 2, 2), }, /* FVco 840.000000 */
+ { .frequency = 220000000, .driver_data = PLLVAL(0x66, 1, 2), }, /* FVco 880.000000 */
+ { .frequency = 230000000, .driver_data = PLLVAL(0x6b, 1, 2), }, /* FVco 920.000000 */
+ { .frequency = 240000000, .driver_data = PLLVAL(0x70, 1, 2), }, /* FVco 960.000000 */
+ { .frequency = 300000000, .driver_data = PLLVAL(0x75, 3, 1), }, /* FVco 600.000000 */
+ { .frequency = 310000000, .driver_data = PLLVAL(0x93, 4, 1), }, /* FVco 620.000000 */
+ { .frequency = 320000000, .driver_data = PLLVAL(0x98, 4, 1), }, /* FVco 640.000000 */
+ { .frequency = 330000000, .driver_data = PLLVAL(0x66, 2, 1), }, /* FVco 660.000000 */
+ { .frequency = 340000000, .driver_data = PLLVAL(0x4d, 1, 1), }, /* FVco 680.000000 */
+ { .frequency = 350000000, .driver_data = PLLVAL(0xa7, 4, 1), }, /* FVco 700.000000 */
+ { .frequency = 360000000, .driver_data = PLLVAL(0x70, 2, 1), }, /* FVco 720.000000 */
+ { .frequency = 370000000, .driver_data = PLLVAL(0xb1, 4, 1), }, /* FVco 740.000000 */
+ { .frequency = 380000000, .driver_data = PLLVAL(0x57, 1, 1), }, /* FVco 760.000000 */
+ { .frequency = 390000000, .driver_data = PLLVAL(0x7a, 2, 1), }, /* FVco 780.000000 */
+ { .frequency = 400000000, .driver_data = PLLVAL(0x5c, 1, 1), }, /* FVco 800.000000 */
};
static int s3c2440_plls12_add(struct device *dev, struct subsys_interface *sif)
diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
index debfa106289b..1191b2905625 100644
--- a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
@@ -21,61 +21,61 @@
#include <plat/cpu-freq-core.h>
static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = {
- { .frequency = 78019200, .index = PLLVAL(121, 5, 3), }, /* FVco 624.153600 */
- { .frequency = 84067200, .index = PLLVAL(131, 5, 3), }, /* FVco 672.537600 */
- { .frequency = 90115200, .index = PLLVAL(141, 5, 3), }, /* FVco 720.921600 */
- { .frequency = 96163200, .index = PLLVAL(151, 5, 3), }, /* FVco 769.305600 */
- { .frequency = 102135600, .index = PLLVAL(185, 6, 3), }, /* FVco 817.084800 */
- { .frequency = 108259200, .index = PLLVAL(171, 5, 3), }, /* FVco 866.073600 */
- { .frequency = 114307200, .index = PLLVAL(127, 3, 3), }, /* FVco 914.457600 */
- { .frequency = 120234240, .index = PLLVAL(134, 3, 3), }, /* FVco 961.873920 */
- { .frequency = 126161280, .index = PLLVAL(141, 3, 3), }, /* FVco 1009.290240 */
- { .frequency = 132088320, .index = PLLVAL(148, 3, 3), }, /* FVco 1056.706560 */
- { .frequency = 138015360, .index = PLLVAL(155, 3, 3), }, /* FVco 1104.122880 */
- { .frequency = 144789120, .index = PLLVAL(163, 3, 3), }, /* FVco 1158.312960 */
- { .frequency = 150100363, .index = PLLVAL(187, 9, 2), }, /* FVco 600.401454 */
- { .frequency = 156038400, .index = PLLVAL(121, 5, 2), }, /* FVco 624.153600 */
- { .frequency = 162086400, .index = PLLVAL(126, 5, 2), }, /* FVco 648.345600 */
- { .frequency = 168134400, .index = PLLVAL(131, 5, 2), }, /* FVco 672.537600 */
- { .frequency = 174048000, .index = PLLVAL(177, 7, 2), }, /* FVco 696.192000 */
- { .frequency = 180230400, .index = PLLVAL(141, 5, 2), }, /* FVco 720.921600 */
- { .frequency = 186278400, .index = PLLVAL(124, 4, 2), }, /* FVco 745.113600 */
- { .frequency = 192326400, .index = PLLVAL(151, 5, 2), }, /* FVco 769.305600 */
- { .frequency = 198132480, .index = PLLVAL(109, 3, 2), }, /* FVco 792.529920 */
- { .frequency = 204271200, .index = PLLVAL(185, 6, 2), }, /* FVco 817.084800 */
- { .frequency = 210268800, .index = PLLVAL(141, 4, 2), }, /* FVco 841.075200 */
- { .frequency = 216518400, .index = PLLVAL(171, 5, 2), }, /* FVco 866.073600 */
- { .frequency = 222264000, .index = PLLVAL(97, 2, 2), }, /* FVco 889.056000 */
- { .frequency = 228614400, .index = PLLVAL(127, 3, 2), }, /* FVco 914.457600 */
- { .frequency = 234259200, .index = PLLVAL(158, 4, 2), }, /* FVco 937.036800 */
- { .frequency = 240468480, .index = PLLVAL(134, 3, 2), }, /* FVco 961.873920 */
- { .frequency = 246960000, .index = PLLVAL(167, 4, 2), }, /* FVco 987.840000 */
- { .frequency = 252322560, .index = PLLVAL(141, 3, 2), }, /* FVco 1009.290240 */
- { .frequency = 258249600, .index = PLLVAL(114, 2, 2), }, /* FVco 1032.998400 */
- { .frequency = 264176640, .index = PLLVAL(148, 3, 2), }, /* FVco 1056.706560 */
- { .frequency = 270950400, .index = PLLVAL(120, 2, 2), }, /* FVco 1083.801600 */
- { .frequency = 276030720, .index = PLLVAL(155, 3, 2), }, /* FVco 1104.122880 */
- { .frequency = 282240000, .index = PLLVAL(92, 1, 2), }, /* FVco 1128.960000 */
- { .frequency = 289578240, .index = PLLVAL(163, 3, 2), }, /* FVco 1158.312960 */
- { .frequency = 294235200, .index = PLLVAL(131, 2, 2), }, /* FVco 1176.940800 */
- { .frequency = 300200727, .index = PLLVAL(187, 9, 1), }, /* FVco 600.401454 */
- { .frequency = 306358690, .index = PLLVAL(191, 9, 1), }, /* FVco 612.717380 */
- { .frequency = 312076800, .index = PLLVAL(121, 5, 1), }, /* FVco 624.153600 */
- { .frequency = 318366720, .index = PLLVAL(86, 3, 1), }, /* FVco 636.733440 */
- { .frequency = 324172800, .index = PLLVAL(126, 5, 1), }, /* FVco 648.345600 */
- { .frequency = 330220800, .index = PLLVAL(109, 4, 1), }, /* FVco 660.441600 */
- { .frequency = 336268800, .index = PLLVAL(131, 5, 1), }, /* FVco 672.537600 */
- { .frequency = 342074880, .index = PLLVAL(93, 3, 1), }, /* FVco 684.149760 */
- { .frequency = 348096000, .index = PLLVAL(177, 7, 1), }, /* FVco 696.192000 */
- { .frequency = 355622400, .index = PLLVAL(118, 4, 1), }, /* FVco 711.244800 */
- { .frequency = 360460800, .index = PLLVAL(141, 5, 1), }, /* FVco 720.921600 */
- { .frequency = 366206400, .index = PLLVAL(165, 6, 1), }, /* FVco 732.412800 */
- { .frequency = 372556800, .index = PLLVAL(124, 4, 1), }, /* FVco 745.113600 */
- { .frequency = 378201600, .index = PLLVAL(126, 4, 1), }, /* FVco 756.403200 */
- { .frequency = 384652800, .index = PLLVAL(151, 5, 1), }, /* FVco 769.305600 */
- { .frequency = 391608000, .index = PLLVAL(177, 6, 1), }, /* FVco 783.216000 */
- { .frequency = 396264960, .index = PLLVAL(109, 3, 1), }, /* FVco 792.529920 */
- { .frequency = 402192000, .index = PLLVAL(87, 2, 1), }, /* FVco 804.384000 */
+ { .frequency = 78019200, .driver_data = PLLVAL(121, 5, 3), }, /* FVco 624.153600 */
+ { .frequency = 84067200, .driver_data = PLLVAL(131, 5, 3), }, /* FVco 672.537600 */
+ { .frequency = 90115200, .driver_data = PLLVAL(141, 5, 3), }, /* FVco 720.921600 */
+ { .frequency = 96163200, .driver_data = PLLVAL(151, 5, 3), }, /* FVco 769.305600 */
+ { .frequency = 102135600, .driver_data = PLLVAL(185, 6, 3), }, /* FVco 817.084800 */
+ { .frequency = 108259200, .driver_data = PLLVAL(171, 5, 3), }, /* FVco 866.073600 */
+ { .frequency = 114307200, .driver_data = PLLVAL(127, 3, 3), }, /* FVco 914.457600 */
+ { .frequency = 120234240, .driver_data = PLLVAL(134, 3, 3), }, /* FVco 961.873920 */
+ { .frequency = 126161280, .driver_data = PLLVAL(141, 3, 3), }, /* FVco 1009.290240 */
+ { .frequency = 132088320, .driver_data = PLLVAL(148, 3, 3), }, /* FVco 1056.706560 */
+ { .frequency = 138015360, .driver_data = PLLVAL(155, 3, 3), }, /* FVco 1104.122880 */
+ { .frequency = 144789120, .driver_data = PLLVAL(163, 3, 3), }, /* FVco 1158.312960 */
+ { .frequency = 150100363, .driver_data = PLLVAL(187, 9, 2), }, /* FVco 600.401454 */
+ { .frequency = 156038400, .driver_data = PLLVAL(121, 5, 2), }, /* FVco 624.153600 */
+ { .frequency = 162086400, .driver_data = PLLVAL(126, 5, 2), }, /* FVco 648.345600 */
+ { .frequency = 168134400, .driver_data = PLLVAL(131, 5, 2), }, /* FVco 672.537600 */
+ { .frequency = 174048000, .driver_data = PLLVAL(177, 7, 2), }, /* FVco 696.192000 */
+ { .frequency = 180230400, .driver_data = PLLVAL(141, 5, 2), }, /* FVco 720.921600 */
+ { .frequency = 186278400, .driver_data = PLLVAL(124, 4, 2), }, /* FVco 745.113600 */
+ { .frequency = 192326400, .driver_data = PLLVAL(151, 5, 2), }, /* FVco 769.305600 */
+ { .frequency = 198132480, .driver_data = PLLVAL(109, 3, 2), }, /* FVco 792.529920 */
+ { .frequency = 204271200, .driver_data = PLLVAL(185, 6, 2), }, /* FVco 817.084800 */
+ { .frequency = 210268800, .driver_data = PLLVAL(141, 4, 2), }, /* FVco 841.075200 */
+ { .frequency = 216518400, .driver_data = PLLVAL(171, 5, 2), }, /* FVco 866.073600 */
+ { .frequency = 222264000, .driver_data = PLLVAL(97, 2, 2), }, /* FVco 889.056000 */
+ { .frequency = 228614400, .driver_data = PLLVAL(127, 3, 2), }, /* FVco 914.457600 */
+ { .frequency = 234259200, .driver_data = PLLVAL(158, 4, 2), }, /* FVco 937.036800 */
+ { .frequency = 240468480, .driver_data = PLLVAL(134, 3, 2), }, /* FVco 961.873920 */
+ { .frequency = 246960000, .driver_data = PLLVAL(167, 4, 2), }, /* FVco 987.840000 */
+ { .frequency = 252322560, .driver_data = PLLVAL(141, 3, 2), }, /* FVco 1009.290240 */
+ { .frequency = 258249600, .driver_data = PLLVAL(114, 2, 2), }, /* FVco 1032.998400 */
+ { .frequency = 264176640, .driver_data = PLLVAL(148, 3, 2), }, /* FVco 1056.706560 */
+ { .frequency = 270950400, .driver_data = PLLVAL(120, 2, 2), }, /* FVco 1083.801600 */
+ { .frequency = 276030720, .driver_data = PLLVAL(155, 3, 2), }, /* FVco 1104.122880 */
+ { .frequency = 282240000, .driver_data = PLLVAL(92, 1, 2), }, /* FVco 1128.960000 */
+ { .frequency = 289578240, .driver_data = PLLVAL(163, 3, 2), }, /* FVco 1158.312960 */
+ { .frequency = 294235200, .driver_data = PLLVAL(131, 2, 2), }, /* FVco 1176.940800 */
+ { .frequency = 300200727, .driver_data = PLLVAL(187, 9, 1), }, /* FVco 600.401454 */
+ { .frequency = 306358690, .driver_data = PLLVAL(191, 9, 1), }, /* FVco 612.717380 */
+ { .frequency = 312076800, .driver_data = PLLVAL(121, 5, 1), }, /* FVco 624.153600 */
+ { .frequency = 318366720, .driver_data = PLLVAL(86, 3, 1), }, /* FVco 636.733440 */
+ { .frequency = 324172800, .driver_data = PLLVAL(126, 5, 1), }, /* FVco 648.345600 */
+ { .frequency = 330220800, .driver_data = PLLVAL(109, 4, 1), }, /* FVco 660.441600 */
+ { .frequency = 336268800, .driver_data = PLLVAL(131, 5, 1), }, /* FVco 672.537600 */
+ { .frequency = 342074880, .driver_data = PLLVAL(93, 3, 1), }, /* FVco 684.149760 */
+ { .frequency = 348096000, .driver_data = PLLVAL(177, 7, 1), }, /* FVco 696.192000 */
+ { .frequency = 355622400, .driver_data = PLLVAL(118, 4, 1), }, /* FVco 711.244800 */
+ { .frequency = 360460800, .driver_data = PLLVAL(141, 5, 1), }, /* FVco 720.921600 */
+ { .frequency = 366206400, .driver_data = PLLVAL(165, 6, 1), }, /* FVco 732.412800 */
+ { .frequency = 372556800, .driver_data = PLLVAL(124, 4, 1), }, /* FVco 745.113600 */
+ { .frequency = 378201600, .driver_data = PLLVAL(126, 4, 1), }, /* FVco 756.403200 */
+ { .frequency = 384652800, .driver_data = PLLVAL(151, 5, 1), }, /* FVco 769.305600 */
+ { .frequency = 391608000, .driver_data = PLLVAL(177, 6, 1), }, /* FVco 783.216000 */
+ { .frequency = 396264960, .driver_data = PLLVAL(109, 3, 1), }, /* FVco 792.529920 */
+ { .frequency = 402192000, .driver_data = PLLVAL(87, 2, 1), }, /* FVco 804.384000 */
};
static int s3c2440_plls169344_add(struct device *dev,
diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c
index ff384acc65b2..34676d1d5fec 100644
--- a/arch/arm/mach-s3c24xx/s3c2410.c
+++ b/arch/arm/mach-s3c24xx/s3c2410.c
@@ -22,6 +22,7 @@
#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/io.h>
#include <asm/mach/arch.h>
@@ -196,9 +197,9 @@ int __init s3c2410a_init(void)
return s3c2410_init();
}
-void s3c2410_restart(char mode, const char *cmd)
+void s3c2410_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's') {
+ if (mode == REBOOT_SOFT) {
soft_restart(0);
}
diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c
index 0f864d4c97de..0251650cbf80 100644
--- a/arch/arm/mach-s3c24xx/s3c2412.c
+++ b/arch/arm/mach-s3c24xx/s3c2412.c
@@ -22,6 +22,7 @@
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/reboot.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -129,9 +130,9 @@ static void s3c2412_idle(void)
cpu_do_idle();
}
-void s3c2412_restart(char mode, const char *cmd)
+void s3c2412_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's')
+ if (mode == REBOOT_SOFT)
soft_restart(0);
/* errata "Watch-dog/Software Reset Problem" specifies that
diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c
index b9c5d382dafb..9ef3ccfbe196 100644
--- a/arch/arm/mach-s3c24xx/s3c2416.c
+++ b/arch/arm/mach-s3c24xx/s3c2416.c
@@ -35,6 +35,7 @@
#include <linux/syscore_ops.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/reboot.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -79,9 +80,9 @@ static struct device s3c2416_dev = {
.bus = &s3c2416_subsys,
};
-void s3c2416_restart(char mode, const char *cmd)
+void s3c2416_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's')
+ if (mode == REBOOT_SOFT)
soft_restart(0);
__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c
index 8328cd65bf3d..b6c71918b25c 100644
--- a/arch/arm/mach-s3c24xx/s3c2443.c
+++ b/arch/arm/mach-s3c24xx/s3c2443.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/reboot.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -59,9 +60,9 @@ static struct device s3c2443_dev = {
.bus = &s3c2443_subsys,
};
-void s3c2443_restart(char mode, const char *cmd)
+void s3c2443_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's')
+ if (mode == REBOOT_SOFT)
soft_restart(0);
__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST);
diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c
index d0423e2544c1..911b555029fc 100644
--- a/arch/arm/mach-s3c24xx/s3c244x.c
+++ b/arch/arm/mach-s3c24xx/s3c244x.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/device.h>
#include <linux/syscore_ops.h>
#include <linux/clk.h>
@@ -198,9 +199,9 @@ struct syscore_ops s3c244x_pm_syscore_ops = {
.resume = s3c244x_resume,
};
-void s3c244x_restart(char mode, const char *cmd)
+void s3c244x_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's')
+ if (mode == REBOOT_SOFT)
soft_restart(0);
samsung_wdt_reset();
diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c
index 1aed6f4be1ce..3f62e467b129 100644
--- a/arch/arm/mach-s3c64xx/common.c
+++ b/arch/arm/mach-s3c64xx/common.c
@@ -21,6 +21,7 @@
#include <linux/ioport.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/irq.h>
@@ -381,9 +382,9 @@ static int __init s3c64xx_init_irq_eint(void)
}
arch_initcall(s3c64xx_init_irq_eint);
-void s3c64xx_restart(char mode, const char *cmd)
+void s3c64xx_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode != 's')
+ if (mode != REBOOT_SOFT)
samsung_wdt_reset();
/* if all else fails, or mode was for soft, jump to 0 */
diff --git a/arch/arm/mach-s3c64xx/common.h b/arch/arm/mach-s3c64xx/common.h
index 6cfc99bdfb37..e8f990b37665 100644
--- a/arch/arm/mach-s3c64xx/common.h
+++ b/arch/arm/mach-s3c64xx/common.h
@@ -17,13 +17,15 @@
#ifndef __ARCH_ARM_MACH_S3C64XX_COMMON_H
#define __ARCH_ARM_MACH_S3C64XX_COMMON_H
+#include <linux/reboot.h>
+
void s3c64xx_init_irq(u32 vic0, u32 vic1);
void s3c64xx_init_io(struct map_desc *mach_desc, int size);
void s3c64xx_register_clocks(unsigned long xtal, unsigned armclk_limit);
void s3c64xx_setup_clocks(void);
-void s3c64xx_restart(char mode, const char *cmd);
+void s3c64xx_restart(enum reboot_mode mode, const char *cmd);
void s3c64xx_init_late(void);
#ifdef CONFIG_CPU_S3C6400
diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c
index 76d0053bf564..dfdfdc320ce7 100644
--- a/arch/arm/mach-s5p64x0/common.c
+++ b/arch/arm/mach-s5p64x0/common.c
@@ -24,6 +24,7 @@
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/irq.h>
+#include <linux/reboot.h>
#include <asm/irq.h>
#include <asm/proc-fns.h>
@@ -439,9 +440,9 @@ static int __init s5p64x0_init_irq_eint(void)
}
arch_initcall(s5p64x0_init_irq_eint);
-void s5p64x0_restart(char mode, const char *cmd)
+void s5p64x0_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode != 's')
+ if (mode != REBOOT_SOFT)
samsung_wdt_reset();
soft_restart(0);
diff --git a/arch/arm/mach-s5p64x0/common.h b/arch/arm/mach-s5p64x0/common.h
index f8a60fdc5884..f3a9b43cba4a 100644
--- a/arch/arm/mach-s5p64x0/common.h
+++ b/arch/arm/mach-s5p64x0/common.h
@@ -12,6 +12,8 @@
#ifndef __ARCH_ARM_MACH_S5P64X0_COMMON_H
#define __ARCH_ARM_MACH_S5P64X0_COMMON_H
+#include <linux/reboot.h>
+
void s5p6440_init_irq(void);
void s5p6450_init_irq(void);
void s5p64x0_init_io(struct map_desc *mach_desc, int size);
@@ -22,7 +24,7 @@ void s5p6440_setup_clocks(void);
void s5p6450_register_clocks(void);
void s5p6450_setup_clocks(void);
-void s5p64x0_restart(char mode, const char *cmd);
+void s5p64x0_restart(enum reboot_mode mode, const char *cmd);
#ifdef CONFIG_CPU_S5P6440
diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c
index 511031564d35..4bdfecf6d024 100644
--- a/arch/arm/mach-s5pc100/common.c
+++ b/arch/arm/mach-s5pc100/common.c
@@ -24,6 +24,7 @@
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
+#include <linux/reboot.h>
#include <asm/irq.h>
#include <asm/proc-fns.h>
@@ -217,9 +218,9 @@ void __init s5pc100_init_uarts(struct s3c2410_uartcfg *cfg, int no)
s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
}
-void s5pc100_restart(char mode, const char *cmd)
+void s5pc100_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode != 's')
+ if (mode != REBOOT_SOFT)
samsung_wdt_reset();
soft_restart(0);
diff --git a/arch/arm/mach-s5pc100/common.h b/arch/arm/mach-s5pc100/common.h
index c41f912e9e1f..08d782d65d7b 100644
--- a/arch/arm/mach-s5pc100/common.h
+++ b/arch/arm/mach-s5pc100/common.h
@@ -12,13 +12,15 @@
#ifndef __ARCH_ARM_MACH_S5PC100_COMMON_H
#define __ARCH_ARM_MACH_S5PC100_COMMON_H
+#include <linux/reboot.h>
+
void s5pc100_init_io(struct map_desc *mach_desc, int size);
void s5pc100_init_irq(void);
void s5pc100_register_clocks(void);
void s5pc100_setup_clocks(void);
-void s5pc100_restart(char mode, const char *cmd);
+void s5pc100_restart(enum reboot_mode mode, const char *cmd);
extern int s5pc100_init(void);
extern void s5pc100_map_io(void);
diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c
index 9dfe93e2624d..023f1a796a9c 100644
--- a/arch/arm/mach-s5pv210/common.c
+++ b/arch/arm/mach-s5pv210/common.c
@@ -143,7 +143,7 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
}
};
-void s5pv210_restart(char mode, const char *cmd)
+void s5pv210_restart(enum reboot_mode mode, const char *cmd)
{
__raw_writel(0x1, S5P_SWRESET);
}
diff --git a/arch/arm/mach-s5pv210/common.h b/arch/arm/mach-s5pv210/common.h
index 0a1cc0aef720..fe1beb54e548 100644
--- a/arch/arm/mach-s5pv210/common.h
+++ b/arch/arm/mach-s5pv210/common.h
@@ -12,13 +12,15 @@
#ifndef __ARCH_ARM_MACH_S5PV210_COMMON_H
#define __ARCH_ARM_MACH_S5PV210_COMMON_H
+#include <linux/reboot.h>
+
void s5pv210_init_io(struct map_desc *mach_desc, int size);
void s5pv210_init_irq(void);
void s5pv210_register_clocks(void);
void s5pv210_setup_clocks(void);
-void s5pv210_restart(char mode, const char *cmd);
+void s5pv210_restart(enum reboot_mode mode, const char *cmd);
extern int s5pv210_init(void);
extern void s5pv210_map_io(void);
diff --git a/arch/arm/mach-s5pv210/mach-aquila.c b/arch/arm/mach-s5pv210/mach-aquila.c
index ed2b85485b9d..ad40ab0f5dbd 100644
--- a/arch/arm/mach-s5pv210/mach-aquila.c
+++ b/arch/arm/mach-s5pv210/mach-aquila.c
@@ -377,12 +377,8 @@ static struct max8998_platform_data aquila_max8998_pdata = {
.buck1_set1 = S5PV210_GPH0(3),
.buck1_set2 = S5PV210_GPH0(4),
.buck2_set3 = S5PV210_GPH0(5),
- .buck1_voltage1 = 1200000,
- .buck1_voltage2 = 1200000,
- .buck1_voltage3 = 1200000,
- .buck1_voltage4 = 1200000,
- .buck2_voltage1 = 1200000,
- .buck2_voltage2 = 1200000,
+ .buck1_voltage = { 1200000, 1200000, 1200000, 1200000 },
+ .buck2_voltage = { 1200000, 1200000 },
};
#endif
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 30b24ad84f49..e5cd9fbf19e9 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -580,12 +580,8 @@ static struct max8998_platform_data goni_max8998_pdata = {
.buck1_set1 = S5PV210_GPH0(3),
.buck1_set2 = S5PV210_GPH0(4),
.buck2_set3 = S5PV210_GPH0(5),
- .buck1_voltage1 = 1200000,
- .buck1_voltage2 = 1200000,
- .buck1_voltage3 = 1200000,
- .buck1_voltage4 = 1200000,
- .buck2_voltage1 = 1200000,
- .buck2_voltage2 = 1200000,
+ .buck1_voltage = { 1200000, 1200000, 1200000, 1200000 },
+ .buck2_voltage = { 1200000, 1200000 },
};
#endif
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
index 9db3e98e8b85..f25b6119e028 100644
--- a/arch/arm/mach-sa1100/generic.c
+++ b/arch/arm/mach-sa1100/generic.c
@@ -19,6 +19,7 @@
#include <linux/cpufreq.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <video/sa1100fb.h>
@@ -131,9 +132,9 @@ static void sa1100_power_off(void)
PMCR = PMCR_SF;
}
-void sa11x0_restart(char mode, const char *cmd)
+void sa11x0_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's') {
+ if (mode == REBOOT_SOFT) {
/* Jump into ROM at address 0 */
soft_restart(0);
} else {
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h
index 2abc6a1f6e86..9a33695c9492 100644
--- a/arch/arm/mach-sa1100/generic.h
+++ b/arch/arm/mach-sa1100/generic.h
@@ -3,12 +3,13 @@
*
* Author: Nicolas Pitre
*/
+#include <linux/reboot.h>
extern void sa1100_timer_init(void);
extern void __init sa1100_map_io(void);
extern void __init sa1100_init_irq(void);
extern void __init sa1100_init_gpio(void);
-extern void sa11x0_restart(char, const char *);
+extern void sa11x0_restart(enum reboot_mode, const char *);
extern void sa11x0_init_late(void);
#define SET_BANK(__nr,__start,__size) \
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index a59a13a665a6..713c86cd3d64 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -14,9 +14,9 @@
#include <linux/irq.h>
#include <linux/timex.h>
#include <linux/clockchips.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
-#include <asm/sched_clock.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 153555724988..1d32c5e8eab6 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -11,6 +11,7 @@
#include <linux/serial_8250.h>
#include <linux/io.h>
#include <linux/cpu.h>
+#include <linux/reboot.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -24,7 +25,7 @@
#define ROMCARD_SIZE 0x08000000
#define ROMCARD_START 0x10000000
-static void shark_restart(char mode, const char *cmd)
+static void shark_restart(enum reboot_mode mode, const char *cmd)
{
short temp;
/* Reset the Machine via pc[3] of the sequoia chipset */
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index db27e8eef192..3912ce91fee4 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -23,7 +23,7 @@ config ARCH_R8A73A4
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARM_GIC
select CPU_V7
- select ARM_ARCH_TIMER
+ select HAVE_ARM_ARCH_TIMER
select SH_CLK_CPG
select RENESAS_IRQC
@@ -59,7 +59,7 @@ config ARCH_R8A7790
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARM_GIC
select CPU_V7
- select ARM_ARCH_TIMER
+ select HAVE_ARM_ARCH_TIMER
select SH_CLK_CPG
select RENESAS_IRQC
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index 44a621505eeb..e115f6742107 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -42,6 +42,7 @@
#include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/i2c-gpio.h>
+#include <linux/reboot.h>
#include <mach/common.h>
#include <mach/irqs.h>
#include <mach/r8a7740.h>
@@ -377,7 +378,7 @@ static struct resource sh_eth_resources[] = {
};
static struct platform_device sh_eth_device = {
- .name = "sh-eth",
+ .name = "r8a7740-gether",
.id = -1,
.dev = {
.platform_data = &sh_eth_platdata,
@@ -1259,7 +1260,7 @@ static void __init eva_add_early_devices(void)
}
#define RESCNT2 IOMEM(0xe6188020)
-static void eva_restart(char mode, const char *cmd)
+static void eva_restart(enum reboot_mode mode, const char *cmd)
{
/* Do soft power on reset */
writel((1 << 31), RESCNT2);
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index 165483c9bee2..1068120d339f 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -34,6 +34,7 @@
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/smsc911x.h>
@@ -890,7 +891,7 @@ static void __init kzm_init(void)
sh73a0_pm_init();
}
-static void kzm9g_restart(char mode, const char *cmd)
+static void kzm9g_restart(enum reboot_mode mode, const char *cmd)
{
#define RESCNT2 IOMEM(0xe6188020)
/* Do soft power on reset */
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index 7fd32d604e34..de10fd78bf2b 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -594,7 +594,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("e6860000.sdhi", &mstp_clks[MSTP313]),
CLKDEV_DEV_ID("sh_mmcif", &mstp_clks[MSTP312]),
CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]),
- CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP309]),
+ CLKDEV_DEV_ID("r8a7740-gether", &mstp_clks[MSTP309]),
CLKDEV_DEV_ID("e9a00000.sh-eth", &mstp_clks[MSTP309]),
CLKDEV_DEV_ID("renesas_tpu_pwm", &mstp_clks[MSTP304]),
diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c
index 53798e5037d7..a0e9eb72e46d 100644
--- a/arch/arm/mach-shmobile/clock-r8a7778.c
+++ b/arch/arm/mach-shmobile/clock-r8a7778.c
@@ -145,7 +145,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP323]), /* SDHI0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP322]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */
- CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP114]), /* Ether */
+ CLKDEV_DEV_ID("r8a777x-ether", &mstp_clks[MSTP114]), /* Ether */
CLKDEV_DEV_ID("ehci-platform", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */
CLKDEV_DEV_ID("ohci-platform", &mstp_clks[MSTP100]), /* USB OHCI port0/1 */
CLKDEV_DEV_ID("i2c-rcar.0", &mstp_clks[MSTP030]), /* I2C0 */
diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c
index 9daeb8c37483..10340f5becbb 100644
--- a/arch/arm/mach-shmobile/clock-r8a7779.c
+++ b/arch/arm/mach-shmobile/clock-r8a7779.c
@@ -165,7 +165,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("rcar-pcie", &mstp_clks[MSTP116]), /* PCIe */
CLKDEV_DEV_ID("sata_rcar", &mstp_clks[MSTP115]), /* SATA */
CLKDEV_DEV_ID("fc600000.sata", &mstp_clks[MSTP115]), /* SATA w/DT */
- CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP114]), /* Ether */
+ CLKDEV_DEV_ID("r8a777x-ether", &mstp_clks[MSTP114]), /* Ether */
CLKDEV_DEV_ID("ehci-platform.1", &mstp_clks[MSTP101]), /* USB EHCI port2 */
CLKDEV_DEV_ID("ohci-platform.1", &mstp_clks[MSTP101]), /* USB OHCI port2 */
CLKDEV_DEV_ID("ehci-platform.0", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 7e105932c09d..5390c6bbbc02 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -142,15 +142,15 @@ static void pllc2_table_rebuild(struct clk *clk)
/* Initialise PLLC2 frequency table */
for (i = 0; i < ARRAY_SIZE(pllc2_freq_table) - 2; i++) {
pllc2_freq_table[i].frequency = clk->parent->rate * (i + 20) * 2;
- pllc2_freq_table[i].index = i;
+ pllc2_freq_table[i].driver_data = i;
}
/* This is a special entry - switching PLL off makes it a repeater */
pllc2_freq_table[i].frequency = clk->parent->rate;
- pllc2_freq_table[i].index = i;
+ pllc2_freq_table[i].driver_data = i;
pllc2_freq_table[++i].frequency = CPUFREQ_TABLE_END;
- pllc2_freq_table[i].index = i;
+ pllc2_freq_table[i].driver_data = i;
}
static unsigned long pllc2_recalc(struct clk *clk)
diff --git a/arch/arm/mach-socfpga/socfpga.c b/arch/arm/mach-socfpga/socfpga.c
index 8ea11b472b91..bfce9641e32f 100644
--- a/arch/arm/mach-socfpga/socfpga.c
+++ b/arch/arm/mach-socfpga/socfpga.c
@@ -19,6 +19,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/reboot.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
@@ -89,13 +90,13 @@ static void __init socfpga_init_irq(void)
socfpga_sysmgr_init();
}
-static void socfpga_cyclone5_restart(char mode, const char *cmd)
+static void socfpga_cyclone5_restart(enum reboot_mode mode, const char *cmd)
{
u32 temp;
temp = readl(rst_manager_base_addr + SOCFPGA_RSTMGR_CTRL);
- if (mode == 'h')
+ if (mode == REBOOT_HARD)
temp |= RSTMGR_CTRL_SWCOLDRSTREQ;
else
temp |= RSTMGR_CTRL_SWWARMRSTREQ;
diff --git a/arch/arm/mach-spear/generic.h b/arch/arm/mach-spear/generic.h
index a9fd45362fee..904f2c907b46 100644
--- a/arch/arm/mach-spear/generic.h
+++ b/arch/arm/mach-spear/generic.h
@@ -16,6 +16,8 @@
#include <linux/dmaengine.h>
#include <linux/amba/pl08x.h>
#include <linux/init.h>
+#include <linux/reboot.h>
+
#include <asm/mach/time.h>
extern void spear13xx_timer_init(void);
@@ -32,7 +34,7 @@ void __init spear6xx_clk_init(void __iomem *misc_base);
void __init spear13xx_map_io(void);
void __init spear13xx_l2x0_init(void);
-void spear_restart(char, const char *);
+void spear_restart(enum reboot_mode, const char *);
void spear13xx_secondary_startup(void);
void __cpuinit spear13xx_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-spear/restart.c b/arch/arm/mach-spear/restart.c
index 2b44500bb718..ce5e098c4888 100644
--- a/arch/arm/mach-spear/restart.c
+++ b/arch/arm/mach-spear/restart.c
@@ -12,14 +12,15 @@
*/
#include <linux/io.h>
#include <linux/amba/sp810.h>
+#include <linux/reboot.h>
#include <asm/system_misc.h>
#include <mach/spear.h>
#include "generic.h"
#define SPEAR13XX_SYS_SW_RES (VA_MISC_BASE + 0x204)
-void spear_restart(char mode, const char *cmd)
+void spear_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's') {
+ if (mode == REBOOT_SOFT) {
/* software reset, Jump into ROM at address 0 */
soft_restart(0);
} else {
diff --git a/arch/arm/mach-spear/spear3xx.c b/arch/arm/mach-spear/spear3xx.c
index 0227c97797cd..bf3b1fd8cb23 100644
--- a/arch/arm/mach-spear/spear3xx.c
+++ b/arch/arm/mach-spear/spear3xx.c
@@ -56,8 +56,8 @@ struct pl08x_platform_data pl080_plat_data = {
},
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
- .get_signal = pl080_get_signal,
- .put_signal = pl080_put_signal,
+ .get_xfer_signal = pl080_get_signal,
+ .put_xfer_signal = pl080_put_signal,
};
/*
diff --git a/arch/arm/mach-spear/spear6xx.c b/arch/arm/mach-spear/spear6xx.c
index 8b0295a41226..da26fa5b68d7 100644
--- a/arch/arm/mach-spear/spear6xx.c
+++ b/arch/arm/mach-spear/spear6xx.c
@@ -334,8 +334,8 @@ static struct pl08x_platform_data spear6xx_pl080_plat_data = {
},
.lli_buses = PL08X_AHB1,
.mem_buses = PL08X_AHB1,
- .get_signal = pl080_get_signal,
- .put_signal = pl080_put_signal,
+ .get_xfer_signal = pl080_get_signal,
+ .put_xfer_signal = pl080_put_signal,
.slave_channels = spear600_dma_info,
.num_slave_channels = ARRAY_SIZE(spear600_dma_info),
};
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 84485a10fc3a..38a3c55527c8 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -18,6 +18,7 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/io.h>
+#include <linux/reboot.h>
#include <linux/clk/sunxi.h>
@@ -33,7 +34,7 @@
static void __iomem *wdt_base;
-static void sun4i_restart(char mode, const char *cmd)
+static void sun4i_restart(enum reboot_mode mode, const char *cmd)
{
if (!wdt_base)
return;
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 84d72fc36dfe..ef3a8da49b2d 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -28,7 +28,6 @@ config ARCH_TEGRA_2x_SOC
select ARM_ERRATA_754327 if SMP
select ARM_ERRATA_764369 if SMP
select ARM_GIC
- select CPU_FREQ_TABLE if CPU_FREQ
select CPU_V7
select PINCTRL
select PINCTRL_TEGRA20
@@ -46,7 +45,6 @@ config ARCH_TEGRA_3x_SOC
select ARM_ERRATA_754322
select ARM_ERRATA_764369 if SMP
select ARM_GIC
- select CPU_FREQ_TABLE if CPU_FREQ
select CPU_V7
select PINCTRL
select PINCTRL_TEGRA30
@@ -60,10 +58,9 @@ config ARCH_TEGRA_3x_SOC
config ARCH_TEGRA_114_SOC
bool "Enable support for Tegra114 family"
- select ARM_ARCH_TIMER
+ select HAVE_ARM_ARCH_TIMER
select ARM_GIC
select ARM_L1_CACHE_SHIFT_6
- select CPU_FREQ_TABLE if CPU_FREQ
select CPU_V7
select PINCTRL
select PINCTRL_TEGRA114
diff --git a/arch/arm/mach-tegra/board.h b/arch/arm/mach-tegra/board.h
index 1787327fae3a..9a6659fe2dc2 100644
--- a/arch/arm/mach-tegra/board.h
+++ b/arch/arm/mach-tegra/board.h
@@ -23,8 +23,9 @@
#define __MACH_TEGRA_BOARD_H
#include <linux/types.h>
+#include <linux/reboot.h>
-void tegra_assert_system_reset(char mode, const char *cmd);
+void tegra_assert_system_reset(enum reboot_mode mode, const char *cmd);
void __init tegra_init_early(void);
void __init tegra_map_common_io(void);
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index ec5836b1e713..94a119a35af8 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -22,8 +22,9 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/reboot.h>
#include <linux/irqchip.h>
-#include <linux/clk/tegra.h>
+#include <linux/clk-provider.h>
#include <asm/hardware/cache-l2x0.h>
@@ -60,7 +61,7 @@ u32 tegra_uart_config[4] = {
#ifdef CONFIG_OF
void __init tegra_dt_init_irq(void)
{
- tegra_clocks_init();
+ of_clk_init(NULL);
tegra_pmc_init();
tegra_init_irq();
irqchip_init();
@@ -68,7 +69,7 @@ void __init tegra_dt_init_irq(void)
}
#endif
-void tegra_assert_system_reset(char mode, const char *cmd)
+void tegra_assert_system_reset(enum reboot_mode mode, const char *cmd)
{
void __iomem *reset = IO_ADDRESS(TEGRA_PMC_BASE + 0);
u32 reg;
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index 4f7ac2a11452..35670b15f281 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -300,11 +300,11 @@ static void __init u300_init_check_chip(void)
/* Forward declare this function from the watchdog */
void coh901327_watchdog_reset(void);
-static void u300_restart(char mode, const char *cmd)
+static void u300_restart(enum reboot_mode mode, const char *cmd)
{
switch (mode) {
- case 's':
- case 'h':
+ case REBOOT_SOFT:
+ case REBOOT_HARD:
#ifdef CONFIG_COH901327_WATCHDOG
coh901327_watchdog_reset();
#endif
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 390ae5feb1d0..b5db207dfd1e 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -21,9 +21,9 @@
#include <linux/delay.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
/* Generic stuff */
-#include <asm/sched_clock.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index b6145ea51641..e6fb0239151b 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -76,13 +76,15 @@ void __init ux500_init_irq(void)
} else if (cpu_is_u9540()) {
prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1);
ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1);
- u8500_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
+ 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();
+ u8540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
+ U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
+ U8500_CLKRST6_BASE);
}
}
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 54bb80b012ac..3b0572f30d56 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -38,6 +38,7 @@
#include <linux/clkdev.h>
#include <linux/mtd/physmap.h>
#include <linux/bitops.h>
+#include <linux/reboot.h>
#include <asm/irq.h>
#include <asm/hardware/arm_timer.h>
@@ -733,7 +734,7 @@ static void versatile_leds_event(led_event_t ledevt)
}
#endif /* CONFIG_LEDS */
-void versatile_restart(char mode, const char *cmd)
+void versatile_restart(enum reboot_mode mode, const char *cmd)
{
void __iomem *sys = __io_address(VERSATILE_SYS_BASE);
u32 val;
diff --git a/arch/arm/mach-versatile/core.h b/arch/arm/mach-versatile/core.h
index 5c1b87d1da6b..f06d5768e428 100644
--- a/arch/arm/mach-versatile/core.h
+++ b/arch/arm/mach-versatile/core.h
@@ -24,13 +24,14 @@
#include <linux/amba/bus.h>
#include <linux/of_platform.h>
+#include <linux/reboot.h>
extern void __init versatile_init(void);
extern void __init versatile_init_early(void);
extern void __init versatile_init_irq(void);
extern void __init versatile_map_io(void);
extern void versatile_timer_init(void);
-extern void versatile_restart(char, const char *);
+extern void versatile_restart(enum reboot_mode, const char *);
extern unsigned int mmc_status(struct device *dev);
#ifdef CONFIG_OF
extern struct of_dev_auxdata versatile_auxdata_lookup[];
diff --git a/arch/arm/mach-virt/Kconfig b/arch/arm/mach-virt/Kconfig
index 8958f0d896bc..081d46929436 100644
--- a/arch/arm/mach-virt/Kconfig
+++ b/arch/arm/mach-virt/Kconfig
@@ -2,7 +2,7 @@ config ARCH_VIRT
bool "Dummy Virtual Machine" if ARCH_MULTI_V7
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARM_GIC
- select ARM_ARCH_TIMER
+ select HAVE_ARM_ARCH_TIMER
select ARM_PSCI
select HAVE_SMP
select CPU_V7
diff --git a/arch/arm/mach-vt8500/vt8500.c b/arch/arm/mach-vt8500/vt8500.c
index f8f2f00856e0..eefaa60d6614 100644
--- a/arch/arm/mach-vt8500/vt8500.c
+++ b/arch/arm/mach-vt8500/vt8500.c
@@ -21,6 +21,7 @@
#include <linux/clocksource.h>
#include <linux/io.h>
#include <linux/pm.h>
+#include <linux/reboot.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -46,7 +47,7 @@
static void __iomem *pmc_base;
-void vt8500_restart(char mode, const char *cmd)
+void vt8500_restart(enum reboot_mode mode, const char *cmd)
{
if (pmc_base)
writel(1, pmc_base + VT8500_PMSR_REG);
diff --git a/arch/arm/mach-w90x900/cpu.c b/arch/arm/mach-w90x900/cpu.c
index 9e4dd8b63c4a..b1eabaad50a5 100644
--- a/arch/arm/mach-w90x900/cpu.c
+++ b/arch/arm/mach-w90x900/cpu.c
@@ -230,9 +230,9 @@ void __init nuc900_init_clocks(void)
#define WTE (1 << 7)
#define WTRE (1 << 1)
-void nuc9xx_restart(char mode, const char *cmd)
+void nuc9xx_restart(enum reboot_mode mode, const char *cmd)
{
- if (mode == 's') {
+ if (mode == REBOOT_SOFT) {
/* Jump into ROM at address 0 */
soft_restart(0);
} else {
diff --git a/arch/arm/mach-w90x900/nuc9xx.h b/arch/arm/mach-w90x900/nuc9xx.h
index 88ef4b267089..e3ab1e1381f1 100644
--- a/arch/arm/mach-w90x900/nuc9xx.h
+++ b/arch/arm/mach-w90x900/nuc9xx.h
@@ -14,10 +14,13 @@
* published by the Free Software Foundation.
*
*/
+
+#include <linux/reboot.h>
+
struct map_desc;
/* core initialisation functions */
extern void nuc900_init_irq(void);
extern void nuc900_timer_init(void);
-extern void nuc9xx_restart(char, const char *);
+extern void nuc9xx_restart(enum reboot_mode, const char *);
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9e8101ecd63e..6cacdc8dd654 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -392,7 +392,8 @@ config CPU_V7
select CPU_CACHE_V7
select CPU_CACHE_VIPT
select CPU_COPY_V6 if MMU
- select CPU_CP15_MMU
+ select CPU_CP15_MMU if MMU
+ select CPU_CP15_MPU if !MMU
select CPU_HAS_ASID if MMU
select CPU_PABRT_V7
select CPU_TLB_V7 if MMU
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index ee558a01f390..ecfe6e53f6e0 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -16,6 +16,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_CPU_ABRT_NOMMU) += abort-nommu.o
obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index c465faca51b0..d70e0aba0c9d 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -523,6 +523,147 @@ static void aurora_flush_range(unsigned long start, unsigned long end)
}
}
+/*
+ * For certain Broadcom SoCs, depending on the address range, different offsets
+ * need to be added to the address before passing it to L2 for
+ * invalidation/clean/flush
+ *
+ * Section Address Range Offset EMI
+ * 1 0x00000000 - 0x3FFFFFFF 0x80000000 VC
+ * 2 0x40000000 - 0xBFFFFFFF 0x40000000 SYS
+ * 3 0xC0000000 - 0xFFFFFFFF 0x80000000 VC
+ *
+ * When the start and end addresses have crossed two different sections, we
+ * need to break the L2 operation into two, each within its own section.
+ * For example, if we need to invalidate addresses starts at 0xBFFF0000 and
+ * ends at 0xC0001000, we need do invalidate 1) 0xBFFF0000 - 0xBFFFFFFF and 2)
+ * 0xC0000000 - 0xC0001000
+ *
+ * Note 1:
+ * By breaking a single L2 operation into two, we may potentially suffer some
+ * performance hit, but keep in mind the cross section case is very rare
+ *
+ * Note 2:
+ * We do not need to handle the case when the start address is in
+ * Section 1 and the end address is in Section 3, since it is not a valid use
+ * case
+ *
+ * Note 3:
+ * Section 1 in practical terms can no longer be used on rev A2. Because of
+ * that the code does not need to handle section 1 at all.
+ *
+ */
+#define BCM_SYS_EMI_START_ADDR 0x40000000UL
+#define BCM_VC_EMI_SEC3_START_ADDR 0xC0000000UL
+
+#define BCM_SYS_EMI_OFFSET 0x40000000UL
+#define BCM_VC_EMI_OFFSET 0x80000000UL
+
+static inline int bcm_addr_is_sys_emi(unsigned long addr)
+{
+ return (addr >= BCM_SYS_EMI_START_ADDR) &&
+ (addr < BCM_VC_EMI_SEC3_START_ADDR);
+}
+
+static inline unsigned long bcm_l2_phys_addr(unsigned long addr)
+{
+ if (bcm_addr_is_sys_emi(addr))
+ return addr + BCM_SYS_EMI_OFFSET;
+ else
+ return addr + BCM_VC_EMI_OFFSET;
+}
+
+static void bcm_inv_range(unsigned long start, unsigned long end)
+{
+ unsigned long new_start, new_end;
+
+ BUG_ON(start < BCM_SYS_EMI_START_ADDR);
+
+ if (unlikely(end <= start))
+ return;
+
+ new_start = bcm_l2_phys_addr(start);
+ new_end = bcm_l2_phys_addr(end);
+
+ /* normal case, no cross section between start and end */
+ if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
+ l2x0_inv_range(new_start, new_end);
+ return;
+ }
+
+ /* They cross sections, so it can only be a cross from section
+ * 2 to section 3
+ */
+ l2x0_inv_range(new_start,
+ bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
+ l2x0_inv_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+ new_end);
+}
+
+static void bcm_clean_range(unsigned long start, unsigned long end)
+{
+ unsigned long new_start, new_end;
+
+ BUG_ON(start < BCM_SYS_EMI_START_ADDR);
+
+ if (unlikely(end <= start))
+ return;
+
+ if ((end - start) >= l2x0_size) {
+ l2x0_clean_all();
+ return;
+ }
+
+ new_start = bcm_l2_phys_addr(start);
+ new_end = bcm_l2_phys_addr(end);
+
+ /* normal case, no cross section between start and end */
+ if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
+ l2x0_clean_range(new_start, new_end);
+ return;
+ }
+
+ /* They cross sections, so it can only be a cross from section
+ * 2 to section 3
+ */
+ l2x0_clean_range(new_start,
+ bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
+ l2x0_clean_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+ new_end);
+}
+
+static void bcm_flush_range(unsigned long start, unsigned long end)
+{
+ unsigned long new_start, new_end;
+
+ BUG_ON(start < BCM_SYS_EMI_START_ADDR);
+
+ if (unlikely(end <= start))
+ return;
+
+ if ((end - start) >= l2x0_size) {
+ l2x0_flush_all();
+ return;
+ }
+
+ new_start = bcm_l2_phys_addr(start);
+ new_end = bcm_l2_phys_addr(end);
+
+ /* normal case, no cross section between start and end */
+ if (likely(bcm_addr_is_sys_emi(end) || !bcm_addr_is_sys_emi(start))) {
+ l2x0_flush_range(new_start, new_end);
+ return;
+ }
+
+ /* They cross sections, so it can only be a cross from section
+ * 2 to section 3
+ */
+ l2x0_flush_range(new_start,
+ bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR-1));
+ l2x0_flush_range(bcm_l2_phys_addr(BCM_VC_EMI_SEC3_START_ADDR),
+ new_end);
+}
+
static void __init l2x0_of_setup(const struct device_node *np,
u32 *aux_val, u32 *aux_mask)
{
@@ -765,6 +906,21 @@ static const struct l2x0_of_data aurora_no_outer_data = {
},
};
+static const struct l2x0_of_data bcm_l2x0_data = {
+ .setup = pl310_of_setup,
+ .save = pl310_save,
+ .outer_cache = {
+ .resume = pl310_resume,
+ .inv_range = bcm_inv_range,
+ .clean_range = bcm_clean_range,
+ .flush_range = bcm_flush_range,
+ .sync = l2x0_cache_sync,
+ .flush_all = l2x0_flush_all,
+ .inv_all = l2x0_inv_all,
+ .disable = l2x0_disable,
+ },
+};
+
static const struct of_device_id l2x0_ids[] __initconst = {
{ .compatible = "arm,pl310-cache", .data = (void *)&pl310_data },
{ .compatible = "arm,l220-cache", .data = (void *)&l2x0_data },
@@ -773,6 +929,8 @@ static const struct of_device_id l2x0_ids[] __initconst = {
.data = (void *)&aurora_no_outer_data},
{ .compatible = "marvell,aurora-outer-cache",
.data = (void *)&aurora_with_outer_data},
+ { .compatible = "bcm,bcm11351-a2-pl310-cache",
+ .data = (void *)&bcm_l2x0_data},
{}
};
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 2ac37372ef52..b55b1015724b 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -20,6 +20,7 @@
#include <asm/smp_plat.h>
#include <asm/thread_notify.h>
#include <asm/tlbflush.h>
+#include <asm/proc-fns.h>
/*
* On ARMv6, we have the following structure in the Context ID:
@@ -39,33 +40,51 @@
* non 64-bit operations.
*/
#define ASID_FIRST_VERSION (1ULL << ASID_BITS)
-#define NUM_USER_ASIDS (ASID_FIRST_VERSION - 1)
-
-#define ASID_TO_IDX(asid) ((asid & ~ASID_MASK) - 1)
-#define IDX_TO_ASID(idx) ((idx + 1) & ~ASID_MASK)
+#define NUM_USER_ASIDS ASID_FIRST_VERSION
static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION);
static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS);
-DEFINE_PER_CPU(atomic64_t, active_asids);
+static DEFINE_PER_CPU(atomic64_t, active_asids);
static DEFINE_PER_CPU(u64, reserved_asids);
static cpumask_t tlb_flush_pending;
+#ifdef CONFIG_ARM_ERRATA_798181
+void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
+ cpumask_t *mask)
+{
+ int cpu;
+ unsigned long flags;
+ u64 context_id, asid;
+
+ raw_spin_lock_irqsave(&cpu_asid_lock, flags);
+ context_id = mm->context.id.counter;
+ for_each_online_cpu(cpu) {
+ if (cpu == this_cpu)
+ continue;
+ /*
+ * We only need to send an IPI if the other CPUs are
+ * running the same ASID as the one being invalidated.
+ */
+ asid = per_cpu(active_asids, cpu).counter;
+ if (asid == 0)
+ asid = per_cpu(reserved_asids, cpu);
+ if (context_id == asid)
+ cpumask_set_cpu(cpu, mask);
+ }
+ raw_spin_unlock_irqrestore(&cpu_asid_lock, flags);
+}
+#endif
+
#ifdef CONFIG_ARM_LPAE
static void cpu_set_reserved_ttbr0(void)
{
- unsigned long ttbl = __pa(swapper_pg_dir);
- unsigned long ttbh = 0;
-
/*
* Set TTBR0 to swapper_pg_dir which contains only global entries. The
* ASID is set to 0.
*/
- asm volatile(
- " mcrr p15, 0, %0, %1, c2 @ set TTBR0\n"
- :
- : "r" (ttbl), "r" (ttbh));
+ cpu_set_ttbr(0, __pa(swapper_pg_dir));
isb();
}
#else
@@ -128,7 +147,16 @@ static void flush_context(unsigned int cpu)
asid = 0;
} else {
asid = atomic64_xchg(&per_cpu(active_asids, i), 0);
- __set_bit(ASID_TO_IDX(asid), asid_map);
+ /*
+ * If this CPU has already been through a
+ * rollover, but hasn't run another task in
+ * the meantime, we must preserve its reserved
+ * ASID, as this is the only trace we have of
+ * the process it is still running.
+ */
+ if (asid == 0)
+ asid = per_cpu(reserved_asids, i);
+ __set_bit(asid & ~ASID_MASK, asid_map);
}
per_cpu(reserved_asids, i) = asid;
}
@@ -167,17 +195,19 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
/*
* Allocate a free ASID. If we can't find one, take a
* note of the currently active ASIDs and mark the TLBs
- * as requiring flushes.
+ * as requiring flushes. We always count from ASID #1,
+ * as we reserve ASID #0 to switch via TTBR0 and indicate
+ * rollover events.
*/
- asid = find_first_zero_bit(asid_map, NUM_USER_ASIDS);
+ asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
if (asid == NUM_USER_ASIDS) {
generation = atomic64_add_return(ASID_FIRST_VERSION,
&asid_generation);
flush_context(cpu);
- asid = find_first_zero_bit(asid_map, NUM_USER_ASIDS);
+ asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, 1);
}
__set_bit(asid, asid_map);
- asid = generation | IDX_TO_ASID(asid);
+ asid |= generation;
cpumask_clear(mm_cpumask(mm));
}
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index ef3e0f3aac96..7f9b1798c6cf 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -250,7 +250,7 @@ static void __dma_free_buffer(struct page *page, size_t size)
#ifdef CONFIG_MMU
#ifdef CONFIG_HUGETLB_PAGE
-#error ARM Coherent DMA allocator does not (yet) support huge TLB
+#warning ARM Coherent DMA allocator does not (yet) support huge TLB
#endif
static void *__alloc_from_contiguous(struct device *dev, size_t size,
@@ -880,10 +880,24 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
/*
- * Mark the D-cache clean for this page to avoid extra flushing.
+ * Mark the D-cache clean for these pages to avoid extra flushing.
*/
- if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
- set_bit(PG_dcache_clean, &page->flags);
+ if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) {
+ unsigned long pfn;
+ size_t left = size;
+
+ pfn = page_to_pfn(page) + off / PAGE_SIZE;
+ off %= PAGE_SIZE;
+ if (off) {
+ pfn++;
+ left -= PAGE_SIZE - off;
+ }
+ while (left >= PAGE_SIZE) {
+ page = pfn_to_page(pfn++);
+ set_bit(PG_dcache_clean, &page->flags);
+ left -= PAGE_SIZE;
+ }
+ }
}
/**
@@ -1314,6 +1328,15 @@ static void *arm_iommu_alloc_attrs(struct device *dev, size_t size,
if (gfp & GFP_ATOMIC)
return __iommu_alloc_atomic(dev, size, handle);
+ /*
+ * Following is a work-around (a.k.a. hack) to prevent pages
+ * with __GFP_COMP being passed to split_page() which cannot
+ * handle them. The real problem is that this flag probably
+ * should be 0 on ARM as it is not supported on this
+ * platform; see CONFIG_HUGETLBFS.
+ */
+ gfp &= ~(__GFP_COMP);
+
pages = __iommu_alloc_buffer(dev, size, gfp, attrs);
if (!pages)
return NULL;
@@ -1372,16 +1395,17 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
void arm_iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, struct dma_attrs *attrs)
{
- struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+ struct page **pages;
size = PAGE_ALIGN(size);
- if (!pages) {
- WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
+ if (__in_atomic_pool(cpu_addr, size)) {
+ __iommu_free_atomic(dev, cpu_addr, handle, size);
return;
}
- if (__in_atomic_pool(cpu_addr, size)) {
- __iommu_free_atomic(dev, cpu_addr, handle, size);
+ pages = __iommu_get_pages(cpu_addr, attrs);
+ if (!pages) {
+ WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr);
return;
}
@@ -1636,13 +1660,27 @@ static dma_addr_t arm_coherent_iommu_map_page(struct device *dev, struct page *p
{
struct dma_iommu_mapping *mapping = dev->archdata.mapping;
dma_addr_t dma_addr;
- int ret, len = PAGE_ALIGN(size + offset);
+ int ret, prot, len = PAGE_ALIGN(size + offset);
dma_addr = __alloc_iova(mapping, len);
if (dma_addr == DMA_ERROR_CODE)
return dma_addr;
- ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, 0);
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ prot = IOMMU_READ | IOMMU_WRITE;
+ break;
+ case DMA_TO_DEVICE:
+ prot = IOMMU_READ;
+ break;
+ case DMA_FROM_DEVICE:
+ prot = IOMMU_WRITE;
+ break;
+ default:
+ prot = 0;
+ }
+
+ ret = iommu_map(mapping->domain, dma_addr, page_to_phys(page), len, prot);
if (ret < 0)
goto fail;
@@ -1907,7 +1945,7 @@ void arm_iommu_detach_device(struct device *dev)
iommu_detach_device(mapping->domain, dev);
kref_put(&mapping->kref, release_iommu_mapping);
- mapping = NULL;
+ dev->archdata.mapping = NULL;
set_dma_ops(dev, NULL);
pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 5dbf13f954f6..c97f7940cb95 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -491,12 +491,14 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
* Some section permission faults need to be handled gracefully.
* They can happen due to a __{get,put}_user during an oops.
*/
+#ifndef CONFIG_ARM_LPAE
static int
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
do_bad_area(addr, fsr, regs);
return 0;
}
+#endif /* CONFIG_ARM_LPAE */
/*
* This abort handler always returns "fault".
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 32aa5861119f..6d5ba9afb16a 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -17,6 +17,7 @@
#include <asm/highmem.h>
#include <asm/smp_plat.h>
#include <asm/tlbflush.h>
+#include <linux/hugetlb.h>
#include "mm.h"
@@ -168,19 +169,23 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
* coherent with the kernels mapping.
*/
if (!PageHighMem(page)) {
- __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
+ size_t page_size = PAGE_SIZE << compound_order(page);
+ __cpuc_flush_dcache_area(page_address(page), page_size);
} else {
- void *addr;
-
+ unsigned long i;
if (cache_is_vipt_nonaliasing()) {
- addr = kmap_atomic(page);
- __cpuc_flush_dcache_area(addr, PAGE_SIZE);
- kunmap_atomic(addr);
- } else {
- addr = kmap_high_get(page);
- if (addr) {
+ for (i = 0; i < (1 << compound_order(page)); i++) {
+ void *addr = kmap_atomic(page);
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
- kunmap_high(page);
+ kunmap_atomic(addr);
+ }
+ } else {
+ for (i = 0; i < (1 << compound_order(page)); i++) {
+ void *addr = kmap_high_get(page);
+ if (addr) {
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ kunmap_high(page);
+ }
}
}
}
@@ -287,7 +292,7 @@ void flush_dcache_page(struct page *page)
mapping = page_mapping(page);
if (!cache_ops_need_broadcast() &&
- mapping && !mapping_mapped(mapping))
+ mapping && !page_mapped(page))
clear_bit(PG_dcache_clean, &page->flags);
else {
__flush_dcache_page(mapping, page);
diff --git a/arch/arm/mm/fsr-3level.c b/arch/arm/mm/fsr-3level.c
index 05a4e9431836..ab4409a2307e 100644
--- a/arch/arm/mm/fsr-3level.c
+++ b/arch/arm/mm/fsr-3level.c
@@ -9,11 +9,11 @@ static struct fsr_info fsr_info[] = {
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
{ do_bad, SIGBUS, 0, "reserved access flag fault" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
{ do_bad, SIGBUS, 0, "reserved permission fault" },
{ do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
- { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
{ do_bad, SIGBUS, 0, "synchronous external abort" },
{ do_bad, SIGBUS, 0, "asynchronous external abort" },
diff --git a/arch/arm/mm/hugetlbpage.c b/arch/arm/mm/hugetlbpage.c
new file mode 100644
index 000000000000..3d1e4a205b0b
--- /dev/null
+++ b/arch/arm/mm/hugetlbpage.c
@@ -0,0 +1,101 @@
+/*
+ * arch/arm/mm/hugetlbpage.c
+ *
+ * Copyright (C) 2012 ARM Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h and Bill Carson's patches
+ *
+ * This program is free software; you can 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
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/sysctl.h>
+#include <asm/mman.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
+
+/*
+ * On ARM, huge pages are backed by pmd's rather than pte's, so we do a lot
+ * of type casting from pmd_t * to pte_t *.
+ */
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd_present(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (pud_present(*pud))
+ pmd = pmd_offset(pud, addr);
+ }
+
+ return (pte_t *)pmd;
+}
+
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+ int write)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+int pud_huge(pud_t pud)
+{
+ return 0;
+}
+
+int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+{
+ return 0;
+}
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+ unsigned long addr, unsigned long sz)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pte_t *pte = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ pud = pud_alloc(mm, pgd, addr);
+ if (pud)
+ pte = (pte_t *)pmd_alloc(mm, pud, addr);
+
+ return pte;
+}
+
+struct page *
+follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+ pmd_t *pmd, int write)
+{
+ struct page *page;
+
+ page = pte_page(*(pte_t *)pmd);
+ if (page)
+ page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
+ return page;
+}
+
+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 9a5cdc01fcdf..6833cbead6cc 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -36,12 +36,13 @@
#include "mm.h"
-static unsigned long phys_initrd_start __initdata = 0;
+static phys_addr_t phys_initrd_start __initdata = 0;
static unsigned long phys_initrd_size __initdata = 0;
static int __init early_initrd(char *p)
{
- unsigned long start, size;
+ phys_addr_t start;
+ unsigned long size;
char *endp;
start = memparse(p, &endp);
@@ -350,14 +351,14 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
#ifdef CONFIG_BLK_DEV_INITRD
if (phys_initrd_size &&
!memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
- pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
- phys_initrd_start, phys_initrd_size);
+ pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
+ (u64)phys_initrd_start, phys_initrd_size);
phys_initrd_start = phys_initrd_size = 0;
}
if (phys_initrd_size &&
memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
- pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
- phys_initrd_start, phys_initrd_size);
+ pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
+ (u64)phys_initrd_start, phys_initrd_size);
phys_initrd_start = phys_initrd_size = 0;
}
if (phys_initrd_size) {
@@ -442,7 +443,7 @@ static inline void
free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
struct page *start_pg, *end_pg;
- unsigned long pg, pgend;
+ phys_addr_t pg, pgend;
/*
* Convert start_pfn/end_pfn to a struct page pointer.
@@ -454,8 +455,8 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
* Convert to physical addresses, and
* round start upwards and end downwards.
*/
- pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
- pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
+ pg = PAGE_ALIGN(__pa(start_pg));
+ pgend = __pa(end_pg) & PAGE_MASK;
/*
* If there are free pages between these,
@@ -582,9 +583,6 @@ static void __init free_highpages(void)
*/
void __init mem_init(void)
{
- unsigned long reserved_pages, free_pages;
- struct memblock_region *reg;
- int i;
#ifdef CONFIG_HAVE_TCM
/* These pointers are filled in on TCM detection */
extern u32 dtcm_end;
@@ -595,57 +593,16 @@ void __init mem_init(void)
/* this will put all unused low memory onto the freelists */
free_unused_memmap(&meminfo);
-
- totalram_pages += free_all_bootmem();
+ free_all_bootmem();
#ifdef CONFIG_SA1111
/* now that our DMA memory is actually so designated, we can free it */
- free_reserved_area(__va(PHYS_PFN_OFFSET), swapper_pg_dir, 0, NULL);
+ free_reserved_area(__va(PHYS_PFN_OFFSET), swapper_pg_dir, -1, NULL);
#endif
free_highpages();
- reserved_pages = free_pages = 0;
-
- for_each_bank(i, &meminfo) {
- struct membank *bank = &meminfo.bank[i];
- unsigned int pfn1, pfn2;
- struct page *page, *end;
-
- pfn1 = bank_pfn_start(bank);
- pfn2 = bank_pfn_end(bank);
-
- page = pfn_to_page(pfn1);
- end = pfn_to_page(pfn2 - 1) + 1;
-
- do {
- if (PageReserved(page))
- reserved_pages++;
- else if (!page_count(page))
- free_pages++;
- page++;
- } while (page < end);
- }
-
- /*
- * Since our memory may not be contiguous, calculate the
- * real number of pages we have in this system
- */
- printk(KERN_INFO "Memory:");
- num_physpages = 0;
- for_each_memblock(memory, reg) {
- unsigned long pages = memblock_region_memory_end_pfn(reg) -
- memblock_region_memory_base_pfn(reg);
- num_physpages += pages;
- printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
- }
- printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-
- printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- free_pages << (PAGE_SHIFT-10),
- reserved_pages << (PAGE_SHIFT-10),
- totalhigh_pages << (PAGE_SHIFT-10));
+ mem_init_print_info(NULL);
#define MLK(b, t) b, t, ((t) - (b)) >> 10
#define MLM(b, t) b, t, ((t) - (b)) >> 20
@@ -711,7 +668,7 @@ void __init mem_init(void)
BUG_ON(PKMAP_BASE + LAST_PKMAP * PAGE_SIZE > PAGE_OFFSET);
#endif
- if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+ if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
extern int sysctl_overcommit_memory;
/*
* On a machine this small we won't get
@@ -728,12 +685,12 @@ void free_initmem(void)
extern char __tcm_start, __tcm_end;
poison_init_mem(&__tcm_start, &__tcm_end - &__tcm_start);
- free_reserved_area(&__tcm_start, &__tcm_end, 0, "TCM link");
+ free_reserved_area(&__tcm_start, &__tcm_end, -1, "TCM link");
#endif
poison_init_mem(__init_begin, __init_end - __init_begin);
if (!machine_is_integrator() && !machine_is_cintegrator())
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -744,7 +701,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
{
if (!keep_initrd) {
poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
}
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 04d9006eab1f..f123d6eb074b 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -331,10 +331,10 @@ void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
return (void __iomem *) (offset + addr);
}
-void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller)
{
- unsigned long last_addr;
+ phys_addr_t last_addr;
unsigned long offset = phys_addr & ~PAGE_MASK;
unsigned long pfn = __phys_to_pfn(phys_addr);
@@ -367,12 +367,12 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
}
EXPORT_SYMBOL(__arm_ioremap_pfn);
-void __iomem * (*arch_ioremap_caller)(unsigned long, size_t,
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
unsigned int, void *) =
__arm_ioremap_caller;
void __iomem *
-__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{
return arch_ioremap_caller(phys_addr, size, mtype,
__builtin_return_address(0));
@@ -387,7 +387,7 @@ EXPORT_SYMBOL(__arm_ioremap);
* CONFIG_GENERIC_ALLOCATOR for allocating external memory.
*/
void __iomem *
-__arm_ioremap_exec(unsigned long phys_addr, size_t size, bool cached)
+__arm_ioremap_exec(phys_addr_t phys_addr, size_t size, bool cached)
{
unsigned int mtype;
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 10062ceadd1c..0c6356255fe3 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -181,11 +181,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base(random_factor);
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index d1d1cefa1f93..d7229d28c7f8 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -675,7 +675,8 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
}
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
- unsigned long end, unsigned long phys, const struct mem_type *type)
+ unsigned long end, phys_addr_t phys,
+ const struct mem_type *type)
{
pud_t *pud = pud_offset(pgd, addr);
unsigned long next;
@@ -989,27 +990,28 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
void __init sanity_check_meminfo(void)
{
int i, j, highmem = 0;
+ phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
struct membank *bank = &meminfo.bank[j];
- *bank = meminfo.bank[i];
+ phys_addr_t size_limit;
- if (bank->start > ULONG_MAX)
- highmem = 1;
+ *bank = meminfo.bank[i];
+ size_limit = bank->size;
-#ifdef CONFIG_HIGHMEM
- if (__va(bank->start) >= vmalloc_min ||
- __va(bank->start) < (void *)PAGE_OFFSET)
+ if (bank->start >= vmalloc_limit)
highmem = 1;
+ else
+ size_limit = vmalloc_limit - bank->start;
bank->highmem = highmem;
+#ifdef CONFIG_HIGHMEM
/*
* Split those memory banks which are partially overlapping
* the vmalloc area greatly simplifying things later.
*/
- if (!highmem && __va(bank->start) < vmalloc_min &&
- bank->size > vmalloc_min - __va(bank->start)) {
+ if (!highmem && bank->size > size_limit) {
if (meminfo.nr_banks >= NR_BANKS) {
printk(KERN_CRIT "NR_BANKS too low, "
"ignoring high memory\n");
@@ -1018,16 +1020,14 @@ void __init sanity_check_meminfo(void)
(meminfo.nr_banks - i) * sizeof(*bank));
meminfo.nr_banks++;
i++;
- bank[1].size -= vmalloc_min - __va(bank->start);
- bank[1].start = __pa(vmalloc_min - 1) + 1;
+ bank[1].size -= size_limit;
+ bank[1].start = vmalloc_limit;
bank[1].highmem = highmem = 1;
j++;
}
- bank->size = vmalloc_min - __va(bank->start);
+ bank->size = size_limit;
}
#else
- bank->highmem = highmem;
-
/*
* Highmem banks not allowed with !CONFIG_HIGHMEM.
*/
@@ -1040,31 +1040,16 @@ void __init sanity_check_meminfo(void)
}
/*
- * Check whether this memory bank would entirely overlap
- * the vmalloc area.
- */
- if (__va(bank->start) >= vmalloc_min ||
- __va(bank->start) < (void *)PAGE_OFFSET) {
- printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
- "(vmalloc region overlap).\n",
- (unsigned long long)bank->start,
- (unsigned long long)bank->start + bank->size - 1);
- continue;
- }
-
- /*
* Check whether this memory bank would partially overlap
* the vmalloc area.
*/
- if (__va(bank->start + bank->size - 1) >= vmalloc_min ||
- __va(bank->start + bank->size - 1) <= __va(bank->start)) {
- unsigned long newsize = vmalloc_min - __va(bank->start);
+ if (bank->size > size_limit) {
printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
"to -%.8llx (vmalloc region overlap).\n",
(unsigned long long)bank->start,
(unsigned long long)bank->start + bank->size - 1,
- (unsigned long long)bank->start + newsize - 1);
- bank->size = newsize;
+ (unsigned long long)bank->start + size_limit - 1);
+ bank->size = size_limit;
}
#endif
if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit)
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 5a3aba614a40..1fa50100ab6a 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -8,6 +8,7 @@
#include <linux/pagemap.h>
#include <linux/io.h>
#include <linux/memblock.h>
+#include <linux/kernel.h>
#include <asm/cacheflush.h>
#include <asm/sections.h>
@@ -15,9 +16,260 @@
#include <asm/setup.h>
#include <asm/traps.h>
#include <asm/mach/arch.h>
+#include <asm/cputype.h>
+#include <asm/mpu.h>
#include "mm.h"
+#ifdef CONFIG_ARM_MPU
+struct mpu_rgn_info mpu_rgn_info;
+
+/* Region number */
+static void rgnr_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c2, 0" : : "r" (v));
+}
+
+/* Data-side / unified region attributes */
+
+/* Region access control register */
+static void dracr_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c1, 4" : : "r" (v));
+}
+
+/* Region size register */
+static void drsr_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c1, 2" : : "r" (v));
+}
+
+/* Region base address register */
+static void drbar_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c1, 0" : : "r" (v));
+}
+
+static u32 drbar_read(void)
+{
+ u32 v;
+ asm("mrc p15, 0, %0, c6, c1, 0" : "=r" (v));
+ return v;
+}
+/* Optional instruction-side region attributes */
+
+/* I-side Region access control register */
+static void iracr_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c1, 5" : : "r" (v));
+}
+
+/* I-side Region size register */
+static void irsr_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c1, 3" : : "r" (v));
+}
+
+/* I-side Region base address register */
+static void irbar_write(u32 v)
+{
+ asm("mcr p15, 0, %0, c6, c1, 1" : : "r" (v));
+}
+
+static unsigned long irbar_read(void)
+{
+ unsigned long v;
+ asm("mrc p15, 0, %0, c6, c1, 1" : "=r" (v));
+ return v;
+}
+
+/* MPU initialisation functions */
+void __init sanity_check_meminfo_mpu(void)
+{
+ int i;
+ struct membank *bank = meminfo.bank;
+ phys_addr_t phys_offset = PHYS_OFFSET;
+ phys_addr_t aligned_region_size, specified_mem_size, rounded_mem_size;
+
+ /* Initially only use memory continuous from PHYS_OFFSET */
+ if (bank_phys_start(&bank[0]) != phys_offset)
+ panic("First memory bank must be contiguous from PHYS_OFFSET");
+
+ /* Banks have already been sorted by start address */
+ for (i = 1; i < meminfo.nr_banks; i++) {
+ if (bank[i].start <= bank_phys_end(&bank[0]) &&
+ bank_phys_end(&bank[i]) > bank_phys_end(&bank[0])) {
+ bank[0].size = bank_phys_end(&bank[i]) - bank[0].start;
+ } else {
+ pr_notice("Ignoring RAM after 0x%.8lx. "
+ "First non-contiguous (ignored) bank start: 0x%.8lx\n",
+ (unsigned long)bank_phys_end(&bank[0]),
+ (unsigned long)bank_phys_start(&bank[i]));
+ break;
+ }
+ }
+ /* All contiguous banks are now merged in to the first bank */
+ meminfo.nr_banks = 1;
+ specified_mem_size = bank[0].size;
+
+ /*
+ * MPU has curious alignment requirements: Size must be power of 2, and
+ * region start must be aligned to the region size
+ */
+ if (phys_offset != 0)
+ pr_info("PHYS_OFFSET != 0 => MPU Region size constrained by alignment requirements\n");
+
+ /*
+ * Maximum aligned region might overflow phys_addr_t if phys_offset is
+ * 0. Hence we keep everything below 4G until we take the smaller of
+ * the aligned_region_size and rounded_mem_size, one of which is
+ * guaranteed to be smaller than the maximum physical address.
+ */
+ aligned_region_size = (phys_offset - 1) ^ (phys_offset);
+ /* Find the max power-of-two sized region that fits inside our bank */
+ rounded_mem_size = (1 << __fls(bank[0].size)) - 1;
+
+ /* The actual region size is the smaller of the two */
+ aligned_region_size = aligned_region_size < rounded_mem_size
+ ? aligned_region_size + 1
+ : rounded_mem_size + 1;
+
+ if (aligned_region_size != specified_mem_size)
+ pr_warn("Truncating memory from 0x%.8lx to 0x%.8lx (MPU region constraints)",
+ (unsigned long)specified_mem_size,
+ (unsigned long)aligned_region_size);
+
+ meminfo.bank[0].size = aligned_region_size;
+ pr_debug("MPU Region from 0x%.8lx size 0x%.8lx (end 0x%.8lx))\n",
+ (unsigned long)phys_offset,
+ (unsigned long)aligned_region_size,
+ (unsigned long)bank_phys_end(&bank[0]));
+
+}
+
+static int mpu_present(void)
+{
+ return ((read_cpuid_ext(CPUID_EXT_MMFR0) & MMFR0_PMSA) == MMFR0_PMSAv7);
+}
+
+static int mpu_max_regions(void)
+{
+ /*
+ * We don't support a different number of I/D side regions so if we
+ * have separate instruction and data memory maps then return
+ * whichever side has a smaller number of supported regions.
+ */
+ u32 dregions, iregions, mpuir;
+ mpuir = read_cpuid(CPUID_MPUIR);
+
+ dregions = iregions = (mpuir & MPUIR_DREGION_SZMASK) >> MPUIR_DREGION;
+
+ /* Check for separate d-side and i-side memory maps */
+ if (mpuir & MPUIR_nU)
+ iregions = (mpuir & MPUIR_IREGION_SZMASK) >> MPUIR_IREGION;
+
+ /* Use the smallest of the two maxima */
+ return min(dregions, iregions);
+}
+
+static int mpu_iside_independent(void)
+{
+ /* MPUIR.nU specifies whether there is *not* a unified memory map */
+ return read_cpuid(CPUID_MPUIR) & MPUIR_nU;
+}
+
+static int mpu_min_region_order(void)
+{
+ u32 drbar_result, irbar_result;
+ /* We've kept a region free for this probing */
+ rgnr_write(MPU_PROBE_REGION);
+ isb();
+ /*
+ * As per ARM ARM, write 0xFFFFFFFC to DRBAR to find the minimum
+ * region order
+ */
+ drbar_write(0xFFFFFFFC);
+ drbar_result = irbar_result = drbar_read();
+ drbar_write(0x0);
+ /* If the MPU is non-unified, we use the larger of the two minima*/
+ if (mpu_iside_independent()) {
+ irbar_write(0xFFFFFFFC);
+ irbar_result = irbar_read();
+ irbar_write(0x0);
+ }
+ isb(); /* Ensure that MPU region operations have completed */
+ /* Return whichever result is larger */
+ return __ffs(max(drbar_result, irbar_result));
+}
+
+static int mpu_setup_region(unsigned int number, phys_addr_t start,
+ unsigned int size_order, unsigned int properties)
+{
+ u32 size_data;
+
+ /* We kept a region free for probing resolution of MPU regions*/
+ if (number > mpu_max_regions() || number == MPU_PROBE_REGION)
+ return -ENOENT;
+
+ if (size_order > 32)
+ return -ENOMEM;
+
+ if (size_order < mpu_min_region_order())
+ return -ENOMEM;
+
+ /* Writing N to bits 5:1 (RSR_SZ) specifies region size 2^N+1 */
+ size_data = ((size_order - 1) << MPU_RSR_SZ) | 1 << MPU_RSR_EN;
+
+ dsb(); /* Ensure all previous data accesses occur with old mappings */
+ rgnr_write(number);
+ isb();
+ drbar_write(start);
+ dracr_write(properties);
+ isb(); /* Propagate properties before enabling region */
+ drsr_write(size_data);
+
+ /* Check for independent I-side registers */
+ if (mpu_iside_independent()) {
+ irbar_write(start);
+ iracr_write(properties);
+ isb();
+ irsr_write(size_data);
+ }
+ isb();
+
+ /* Store region info (we treat i/d side the same, so only store d) */
+ mpu_rgn_info.rgns[number].dracr = properties;
+ mpu_rgn_info.rgns[number].drbar = start;
+ mpu_rgn_info.rgns[number].drsr = size_data;
+ return 0;
+}
+
+/*
+* Set up default MPU regions, doing nothing if there is no MPU
+*/
+void __init mpu_setup(void)
+{
+ int region_err;
+ if (!mpu_present())
+ return;
+
+ region_err = mpu_setup_region(MPU_RAM_REGION, PHYS_OFFSET,
+ ilog2(meminfo.bank[0].size),
+ MPU_AP_PL1RW_PL0RW | MPU_RGN_NORMAL);
+ if (region_err) {
+ panic("MPU region initialization failure! %d", region_err);
+ } else {
+ pr_info("Using ARMv7 PMSA Compliant MPU. "
+ "Region independence: %s, Max regions: %d\n",
+ mpu_iside_independent() ? "Yes" : "No",
+ mpu_max_regions());
+ }
+}
+#else
+static void sanity_check_meminfo_mpu(void) {}
+static void __init mpu_setup(void) {}
+#endif /* CONFIG_ARM_MPU */
+
void __init arm_mm_memblock_reserve(void)
{
#ifndef CONFIG_CPU_V7M
@@ -37,7 +289,9 @@ void __init arm_mm_memblock_reserve(void)
void __init sanity_check_meminfo(void)
{
- phys_addr_t end = bank_phys_end(&meminfo.bank[meminfo.nr_banks - 1]);
+ phys_addr_t end;
+ sanity_check_meminfo_mpu();
+ end = bank_phys_end(&meminfo.bank[meminfo.nr_banks - 1]);
high_memory = __va(end - 1) + 1;
}
@@ -48,6 +302,7 @@ void __init sanity_check_meminfo(void)
void __init paging_init(struct machine_desc *mdesc)
{
early_trap_init((void *)CONFIG_VECTORS_BASE);
+ mpu_setup();
bootmem_init();
}
@@ -94,16 +349,16 @@ void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
return __arm_ioremap_pfn(pfn, offset, size, mtype);
}
-void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap(phys_addr_t phys_addr, size_t size,
unsigned int mtype)
{
return (void __iomem *)phys_addr;
}
EXPORT_SYMBOL(__arm_ioremap);
-void __iomem * (*arch_ioremap_caller)(unsigned long, size_t, unsigned int, void *);
+void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, unsigned int, void *);
-void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
+void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller)
{
return __arm_ioremap(phys_addr, size, mtype);
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 919405e20b80..2d1ef87328a1 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -140,8 +140,10 @@ ENTRY(cpu_v6_set_pte_ext)
ENTRY(cpu_v6_do_suspend)
stmfd sp!, {r4 - r9, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
+#ifdef CONFIG_MMU
mrc p15, 0, r5, c3, c0, 0 @ Domain ID
mrc p15, 0, r6, c2, c0, 1 @ Translation table base 1
+#endif
mrc p15, 0, r7, c1, c0, 1 @ auxiliary control register
mrc p15, 0, r8, c1, c0, 2 @ co-processor access control
mrc p15, 0, r9, c1, c0, 0 @ control register
@@ -158,14 +160,16 @@ ENTRY(cpu_v6_do_resume)
mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
ldmia r0, {r4 - r9}
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
+#ifdef CONFIG_MMU
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
ALT_UP(orr r1, r1, #TTB_FLAGS_UP)
mcr p15, 0, r1, c2, c0, 0 @ Translation table base 0
mcr p15, 0, r6, c2, c0, 1 @ Translation table base 1
+ mcr p15, 0, ip, c2, c0, 2 @ TTB control register
+#endif
mcr p15, 0, r7, c1, c0, 1 @ auxiliary control register
mcr p15, 0, r8, c1, c0, 2 @ co-processor access control
- mcr p15, 0, ip, c2, c0, 2 @ TTB control register
mcr p15, 0, ip, c7, c5, 4 @ ISB
mov r0, r9 @ control register
b cpu_resume_mmu
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index 363027e811d6..5ffe1956c6d9 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -39,6 +39,14 @@
#define TTB_FLAGS_SMP (TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA)
#define PMD_FLAGS_SMP (PMD_SECT_WBWA|PMD_SECT_S)
+#ifndef __ARMEB__
+# define rpgdl r0
+# define rpgdh r1
+#else
+# define rpgdl r1
+# define rpgdh r0
+#endif
+
/*
* cpu_v7_switch_mm(pgd_phys, tsk)
*
@@ -47,10 +55,10 @@
*/
ENTRY(cpu_v7_switch_mm)
#ifdef CONFIG_MMU
- mmid r1, r1 @ get mm->context.id
- asid r3, r1
- mov r3, r3, lsl #(48 - 32) @ ASID
- mcrr p15, 0, r0, r3, c2 @ set TTB 0
+ mmid r2, r2
+ asid r2, r2
+ orr rpgdh, rpgdh, r2, lsl #(48 - 32) @ upper 32-bits of pgd
+ mcrr p15, 0, rpgdl, rpgdh, c2 @ set TTB 0
isb
#endif
mov pc, lr
@@ -106,7 +114,8 @@ ENDPROC(cpu_v7_set_pte_ext)
*/
.macro v7_ttb_setup, zero, ttbr0, ttbr1, tmp
ldr \tmp, =swapper_pg_dir @ swapper_pg_dir virtual address
- cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET? (branch below)
+ mov \tmp, \tmp, lsr #ARCH_PGD_SHIFT
+ cmp \ttbr1, \tmp @ PHYS_OFFSET > PAGE_OFFSET?
mrc p15, 0, \tmp, c2, c0, 2 @ TTB control register
orr \tmp, \tmp, #TTB_EAE
ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP)
@@ -114,27 +123,21 @@ ENDPROC(cpu_v7_set_pte_ext)
ALT_SMP(orr \tmp, \tmp, #TTB_FLAGS_SMP << 16)
ALT_UP(orr \tmp, \tmp, #TTB_FLAGS_UP << 16)
/*
- * TTBR0/TTBR1 split (PAGE_OFFSET):
- * 0x40000000: T0SZ = 2, T1SZ = 0 (not used)
- * 0x80000000: T0SZ = 0, T1SZ = 1
- * 0xc0000000: T0SZ = 0, T1SZ = 2
- *
- * Only use this feature if PHYS_OFFSET <= PAGE_OFFSET, otherwise
- * booting secondary CPUs would end up using TTBR1 for the identity
- * mapping set up in TTBR0.
+ * Only use split TTBRs if PHYS_OFFSET <= PAGE_OFFSET (cmp above),
+ * otherwise booting secondary CPUs would end up using TTBR1 for the
+ * identity mapping set up in TTBR0.
*/
- bhi 9001f @ PHYS_OFFSET > PAGE_OFFSET?
- orr \tmp, \tmp, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ
-#if defined CONFIG_VMSPLIT_2G
- /* PAGE_OFFSET == 0x80000000, T1SZ == 1 */
- add \ttbr1, \ttbr1, #1 << 4 @ skip two L1 entries
-#elif defined CONFIG_VMSPLIT_3G
- /* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */
- add \ttbr1, \ttbr1, #4096 * (1 + 3) @ only L2 used, skip pgd+3*pmd
-#endif
- /* CONFIG_VMSPLIT_1G does not need TTBR1 adjustment */
-9001: mcr p15, 0, \tmp, c2, c0, 2 @ TTB control register
- mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1
+ 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
+ addls \ttbr1, \ttbr1, #TTBR1_OFFSET
+ mcrr p15, 1, \ttbr1, \zero, 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, \zero, c2 @ load TTBR0
+ mcrr p15, 1, \ttbr1, \zero, c2 @ load TTBR1
+ mcrr p15, 0, \ttbr0, \zero, c2 @ load TTBR0
.endm
__CPUINIT
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index e35fec34453e..7ef3ad05df39 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -98,9 +98,11 @@ ENTRY(cpu_v7_do_suspend)
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID
stmia r0!, {r4 - r5}
+#ifdef CONFIG_MMU
mrc p15, 0, r6, c3, c0, 0 @ Domain ID
mrc p15, 0, r7, c2, c0, 1 @ TTB 1
mrc p15, 0, r11, c2, c0, 2 @ TTB control register
+#endif
mrc p15, 0, r8, c1, c0, 0 @ Control register
mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register
mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control
@@ -110,13 +112,14 @@ ENDPROC(cpu_v7_do_suspend)
ENTRY(cpu_v7_do_resume)
mov ip, #0
- mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
ldmia r0!, {r4 - r5}
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
mcr p15, 0, r5, c13, c0, 3 @ User r/o thread ID
ldmia r0, {r6 - r11}
+#ifdef CONFIG_MMU
+ mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r6, c3, c0, 0 @ Domain ID
#ifndef CONFIG_ARM_LPAE
ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
@@ -125,14 +128,15 @@ ENTRY(cpu_v7_do_resume)
mcr p15, 0, r1, c2, c0, 0 @ TTB 0
mcr p15, 0, r7, c2, c0, 1 @ TTB 1
mcr p15, 0, r11, c2, c0, 2 @ TTB control register
- mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
- teq r4, r9 @ Is it already set?
- mcrne p15, 0, r9, c1, c0, 1 @ No, so write it
- mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control
ldr r4, =PRRR @ PRRR
ldr r5, =NMRR @ NMRR
mcr p15, 0, r4, c10, c2, 0 @ write PRRR
mcr p15, 0, r5, c10, c2, 1 @ write NMRR
+#endif /* CONFIG_MMU */
+ mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
+ teq r4, r9 @ Is it already set?
+ mcrne p15, 0, r9, c1, c0, 1 @ No, so write it
+ mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control
isb
dsb
mov r0, r8 @ control register
@@ -178,7 +182,8 @@ ENDPROC(cpu_pj4b_do_idle)
*/
__v7_ca5mp_setup:
__v7_ca9mp_setup:
- mov r10, #(1 << 0) @ TLB ops broadcasting
+__v7_cr7mp_setup:
+ mov r10, #(1 << 0) @ Cache/TLB ops broadcasting
b 1f
__v7_ca7mp_setup:
__v7_ca15mp_setup:
@@ -443,6 +448,16 @@ __v7_pj4b_proc_info:
#endif
/*
+ * ARM Ltd. Cortex R7 processor.
+ */
+ .type __v7_cr7mp_proc_info, #object
+__v7_cr7mp_proc_info:
+ .long 0x410fc170
+ .long 0xff0ffff0
+ __v7_proc __v7_cr7mp_setup
+ .size __v7_cr7mp_proc_info, . - __v7_cr7mp_proc_info
+
+ /*
* ARM Ltd. Cortex A7 processor.
*/
.type __v7_ca7mp_proc_info, #object
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 1a643ee8e082..f50d223a0bd3 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -900,8 +900,7 @@ void bpf_jit_compile(struct sk_filter *fp)
#endif
alloc_size = 4 * ctx.idx;
- ctx.target = module_alloc(max(sizeof(struct work_struct),
- alloc_size));
+ ctx.target = module_alloc(alloc_size);
if (unlikely(ctx.target == NULL))
goto out;
@@ -927,19 +926,8 @@ out:
return;
}
-static void bpf_jit_free_worker(struct work_struct *work)
-{
- module_free(NULL, work);
-}
-
void bpf_jit_free(struct sk_filter *fp)
{
- struct work_struct *work;
-
- if (fp->bpf_func != sk_run_filter) {
- work = (struct work_struct *)fp->bpf_func;
-
- INIT_WORK(work, bpf_jit_free_worker);
- schedule_work(work);
- }
+ if (fp->bpf_func != sk_run_filter)
+ module_free(NULL, fp->bpf_func);
}
diff --git a/arch/arm/plat-iop/adma.c b/arch/arm/plat-iop/adma.c
index 1ff6a37e893c..a4d1f8de3b5b 100644
--- a/arch/arm/plat-iop/adma.c
+++ b/arch/arm/plat-iop/adma.c
@@ -192,12 +192,10 @@ static int __init iop3xx_adma_cap_init(void)
#ifdef CONFIG_ARCH_IOP32X /* the 32x AAU does not perform zero sum */
dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask);
- dma_cap_set(DMA_MEMSET, iop3xx_aau_data.cap_mask);
dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask);
#else
dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask);
dma_cap_set(DMA_XOR_VAL, iop3xx_aau_data.cap_mask);
- dma_cap_set(DMA_MEMSET, iop3xx_aau_data.cap_mask);
dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask);
#endif
diff --git a/arch/arm/plat-iop/gpio.c b/arch/arm/plat-iop/gpio.c
index e4de9be78feb..697de6dc4936 100644
--- a/arch/arm/plat-iop/gpio.c
+++ b/arch/arm/plat-iop/gpio.c
@@ -17,6 +17,7 @@
#include <linux/gpio.h>
#include <linux/export.h>
#include <asm/hardware/iop3xx.h>
+#include <mach/gpio.h>
void gpio_line_config(int line, int direction)
{
diff --git a/arch/arm/plat-iop/restart.c b/arch/arm/plat-iop/restart.c
index 33fa699a4d28..3a4d5e5fde52 100644
--- a/arch/arm/plat-iop/restart.c
+++ b/arch/arm/plat-iop/restart.c
@@ -11,7 +11,7 @@
#include <asm/system_misc.h>
#include <mach/hardware.h>
-void iop3xx_restart(char mode, const char *cmd)
+void iop3xx_restart(enum reboot_mode mode, const char *cmd)
{
*IOP3XX_PCSR = 0x30;
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 837a2d52e9db..29606bd75f3f 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -22,9 +22,9 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/export.h>
+#include <linux/sched_clock.h>
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/sched_clock.h>
#include <asm/uaccess.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
diff --git a/arch/arm/plat-omap/counter_32k.c b/arch/arm/plat-omap/counter_32k.c
index 5b0b86bb34bb..d9bc98eb2a6b 100644
--- a/arch/arm/plat-omap/counter_32k.c
+++ b/arch/arm/plat-omap/counter_32k.c
@@ -18,9 +18,9 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clocksource.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
-#include <asm/sched_clock.h>
#include <plat/counter-32k.h>
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
index c019b7aaf776..c66d163d7a2a 100644
--- a/arch/arm/plat-orion/common.c
+++ b/arch/arm/plat-orion/common.c
@@ -666,14 +666,9 @@ void __init orion_xor0_init(unsigned long mapbase_low,
orion_xor0_shared_resources[3].start = irq_1;
orion_xor0_shared_resources[3].end = irq_1;
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[0].cap_mask);
dma_cap_set(DMA_XOR, orion_xor0_channels_data[0].cap_mask);
- dma_cap_set(DMA_MEMSET, orion_xor0_channels_data[1].cap_mask);
dma_cap_set(DMA_MEMCPY, orion_xor0_channels_data[1].cap_mask);
dma_cap_set(DMA_XOR, orion_xor0_channels_data[1].cap_mask);
@@ -732,14 +727,9 @@ void __init orion_xor1_init(unsigned long mapbase_low,
orion_xor1_shared_resources[3].start = irq_1;
orion_xor1_shared_resources[3].end = irq_1;
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[0].cap_mask);
dma_cap_set(DMA_XOR, orion_xor1_channels_data[0].cap_mask);
- dma_cap_set(DMA_MEMSET, orion_xor1_channels_data[1].cap_mask);
dma_cap_set(DMA_MEMCPY, orion_xor1_channels_data[1].cap_mask);
dma_cap_set(DMA_XOR, orion_xor1_channels_data[1].cap_mask);
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
index 5d5ac0f05422..9d2b2ac74938 100644
--- a/arch/arm/plat-orion/time.c
+++ b/arch/arm/plat-orion/time.c
@@ -16,7 +16,7 @@
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
/*
* MBus bridge block registers.
diff --git a/arch/arm/plat-samsung/include/plat/cpu-freq-core.h b/arch/arm/plat-samsung/include/plat/cpu-freq-core.h
index d7e17150028a..7231c8e4975e 100644
--- a/arch/arm/plat-samsung/include/plat/cpu-freq-core.h
+++ b/arch/arm/plat-samsung/include/plat/cpu-freq-core.h
@@ -285,7 +285,7 @@ static inline int s3c_cpufreq_addfreq(struct cpufreq_frequency_table *table,
s3c_freq_dbg("%s: { %d = %u kHz }\n",
__func__, index, freq);
- table[index].index = index;
+ table[index].driver_data = index;
table[index].frequency = freq;
}
diff --git a/arch/arm/plat-samsung/samsung-time.c b/arch/arm/plat-samsung/samsung-time.c
index f899cbc9b288..2957075ca836 100644
--- a/arch/arm/plat-samsung/samsung-time.c
+++ b/arch/arm/plat-samsung/samsung-time.c
@@ -15,12 +15,12 @@
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/platform_device.h>
+#include <linux/sched_clock.h>
#include <asm/smp_twd.h>
#include <asm/mach/time.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <asm/sched_clock.h>
#include <mach/map.h>
#include <plat/devs.h>
diff --git a/arch/arm/plat-versatile/headsmp.S b/arch/arm/plat-versatile/headsmp.S
index b178d44e9eaa..2677bc3762d7 100644
--- a/arch/arm/plat-versatile/headsmp.S
+++ b/arch/arm/plat-versatile/headsmp.S
@@ -11,8 +11,6 @@
#include <linux/linkage.h>
#include <linux/init.h>
- __INIT
-
/*
* Realview/Versatile Express specific entry point for secondary CPUs.
* This provides a "holding pen" into which all secondary cores are held
diff --git a/arch/arm/plat-versatile/sched-clock.c b/arch/arm/plat-versatile/sched-clock.c
index b33b74c87232..51b109e3b6c3 100644
--- a/arch/arm/plat-versatile/sched-clock.c
+++ b/arch/arm/plat-versatile/sched-clock.c
@@ -20,8 +20,8 @@
*/
#include <linux/kernel.h>
#include <linux/io.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <plat/sched_clock.h>
static void __iomem *ctr;
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index 13609e01f4b7..f71c37edca26 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -314,4 +314,5 @@ EXPORT_SYMBOL_GPL(HYPERVISOR_hvm_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op);
EXPORT_SYMBOL_GPL(privcmd_call);
diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S
index 199cb2da7663..d1cf7b7c2200 100644
--- a/arch/arm/xen/hypercall.S
+++ b/arch/arm/xen/hypercall.S
@@ -88,6 +88,7 @@ HYPERCALL2(hvm_op);
HYPERCALL2(memory_op);
HYPERCALL2(physdev_op);
HYPERCALL3(vcpu_op);
+HYPERCALL1(tmem_op);
ENTRY(privcmd_call)
stmdb sp!, {r4}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 56b3f6d447ae..9737e97f9f38 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -7,6 +7,7 @@ config ARM64
select ARM_AMBA
select ARM_ARCH_TIMER
select ARM_GIC
+ select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS
select COMMON_CLK
select GENERIC_CLOCKEVENTS
@@ -111,6 +112,11 @@ config ARCH_VEXPRESS
This enables support for the ARMv8 software model (Versatile
Express).
+config ARCH_XGENE
+ bool "AppliedMicro X-Gene SOC Family"
+ help
+ This enables support for AppliedMicro X-Gene SOC Family
+
endmenu
menu "Bus support"
@@ -148,6 +154,8 @@ config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
depends on SMP
+ # These have to remain sorted largest to smallest
+ default "8" if ARCH_XGENE
default "4"
source kernel/Kconfig.preempt
@@ -180,8 +188,35 @@ config HW_PERF_EVENTS
Enable hardware performance counter support for perf events. If
disabled, perf events will use software events only.
+config SYS_SUPPORTS_HUGETLBFS
+ def_bool y
+
+config ARCH_WANT_GENERAL_HUGETLB
+ def_bool y
+
+config ARCH_WANT_HUGE_PMD_SHARE
+ def_bool y if !ARM64_64K_PAGES
+
+config HAVE_ARCH_TRANSPARENT_HUGEPAGE
+ def_bool y
+
source "mm/Kconfig"
+config XEN_DOM0
+ def_bool y
+ depends on XEN
+
+config XEN
+ bool "Xen guest support on ARM64 (EXPERIMENTAL)"
+ depends on ARM64 && OF
+ help
+ Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
+
+config FORCE_MAX_ZONEORDER
+ int
+ default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
+ default "11"
+
endmenu
menu "Boot options"
@@ -235,6 +270,8 @@ source "drivers/Kconfig"
source "fs/Kconfig"
+source "arch/arm64/kvm/Kconfig"
+
source "arch/arm64/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index c95c5cb212fd..d90cf79f233a 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -37,6 +37,8 @@ TEXT_OFFSET := 0x00080000
export TEXT_OFFSET GZFLAGS
core-y += arch/arm64/kernel/ arch/arm64/mm/
+core-$(CONFIG_KVM) += arch/arm64/kvm/
+core-$(CONFIG_XEN) += arch/arm64/xen/
libs-y := arch/arm64/lib/ $(libs-y)
libs-y += $(LIBGCC)
@@ -60,6 +62,10 @@ zinstall install: vmlinux
dtbs: scripts
$(Q)$(MAKE) $(build)=$(boot)/dts dtbs
+PHONY += vdso_install
+vdso_install:
+ $(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso $@
+
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 68457e9e0975..c52bdb051f66 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb
+dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
targets += dtbs
targets += $(dtb-y)
diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm-mustang.dts
new file mode 100644
index 000000000000..1247ca1200b1
--- /dev/null
+++ b/arch/arm64/boot/dts/apm-mustang.dts
@@ -0,0 +1,26 @@
+/*
+ * dts file for AppliedMicro (APM) Mustang Board
+ *
+ * Copyright (C) 2013, Applied Micro Circuits Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+/dts-v1/;
+
+/include/ "apm-storm.dtsi"
+
+/ {
+ model = "APM X-Gene Mustang board";
+ compatible = "apm,mustang", "apm,xgene-storm";
+
+ chosen { };
+
+ memory {
+ device_type = "memory";
+ reg = < 0x1 0x00000000 0x0 0x80000000 >; /* Updated by bootloader */
+ };
+};
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm-storm.dtsi
new file mode 100644
index 000000000000..bfdc57834929
--- /dev/null
+++ b/arch/arm64/boot/dts/apm-storm.dtsi
@@ -0,0 +1,116 @@
+/*
+ * dts file for AppliedMicro (APM) X-Gene Storm SOC
+ *
+ * Copyright (C) 2013, Applied Micro Circuits Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+/ {
+ compatible = "apm,xgene-storm";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu@000 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x000>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@001 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x001>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@100 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x100>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@101 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x101>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@200 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x200>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@201 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x201>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@300 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x300>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@301 {
+ device_type = "cpu";
+ compatible = "apm,potenza", "arm,armv8";
+ reg = <0x0 0x301>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ };
+
+ gic: interrupt-controller@78010000 {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x0 0x78010000 0x0 0x1000>, /* GIC Dist */
+ <0x0 0x78020000 0x0 0x1000>, /* GIC CPU */
+ <0x0 0x78040000 0x0 0x2000>, /* GIC VCPU Control */
+ <0x0 0x78060000 0x0 0x2000>; /* GIC VCPU */
+ interrupts = <1 9 0xf04>; /* GIC Maintenence IRQ */
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 0 0xff01>, /* Secure Phys IRQ */
+ <1 13 0xff01>, /* Non-secure Phys IRQ */
+ <1 14 0xff01>, /* Virt IRQ */
+ <1 15 0xff01>; /* Hyp IRQ */
+ clock-frequency = <50000000>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ serial0: serial@1c020000 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0 0x1c020000 0x0 0x1000>;
+ reg-shift = <2>;
+ clock-frequency = <10000000>; /* Updated by bootloader */
+ interrupt-parent = <&gic>;
+ interrupts = <0x0 0x4c 0x4>;
+ };
+ };
+};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 8d9696adb440..5b3e83217b03 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -24,6 +24,7 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
CONFIG_ARCH_VEXPRESS=y
+CONFIG_ARCH_XGENE=y
CONFIG_SMP=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_CMDLINE="console=ttyAMA0"
@@ -54,6 +55,9 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
CONFIG_LEGACY_PTY_COUNT=16
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_HW_RANDOM is not set
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index bf6ab242f047..d56ed11ba9a3 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -110,16 +110,6 @@ static inline void __cpuinit arch_counter_set_user_access(void)
asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
}
-static inline u64 arch_counter_get_cntpct(void)
-{
- u64 cval;
-
- isb();
- asm volatile("mrs %0, cntpct_el0" : "=r" (cval));
-
- return cval;
-}
-
static inline u64 arch_counter_get_cntvct(void)
{
u64 cval;
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 3300cbd18a89..fea9ee327206 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -123,9 +123,6 @@ static inline void __flush_icache_all(void)
#define flush_dcache_mmap_unlock(mapping) \
spin_unlock_irq(&(mapping)->tree_lock)
-#define flush_icache_user_range(vma,page,addr,len) \
- flush_dcache_page(page)
-
/*
* We don't appear to need to do anything here. In fact, if we did, we'd
* duplicate cache flushing elsewhere performed by flush_dcache_page().
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index cf2749488cd4..5fe138e0b828 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -37,11 +37,14 @@
})
#define ARM_CPU_IMP_ARM 0x41
+#define ARM_CPU_IMP_APM 0x50
#define ARM_CPU_PART_AEM_V8 0xD0F0
#define ARM_CPU_PART_FOUNDATION 0xD000
#define ARM_CPU_PART_CORTEX_A57 0xD070
+#define APM_CPU_PART_POTENZA 0x0000
+
#ifndef __ASSEMBLY__
/*
diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h
index 7eaa0b302493..ef8235c68c09 100644
--- a/arch/arm64/include/asm/debug-monitors.h
+++ b/arch/arm64/include/asm/debug-monitors.h
@@ -83,6 +83,15 @@ static inline int reinstall_suspended_bps(struct pt_regs *regs)
}
#endif
+#ifdef CONFIG_COMPAT
+int aarch32_break_handler(struct pt_regs *regs);
+#else
+static int aarch32_break_handler(struct pt_regs *regs)
+{
+ return -EFAULT;
+}
+#endif
+
#endif /* __ASSEMBLY */
#endif /* __KERNEL__ */
#endif /* __ASM_DEBUG_MONITORS_H */
diff --git a/arch/arm64/include/asm/device.h b/arch/arm64/include/asm/device.h
index 0d8453c755a8..cf98b362094b 100644
--- a/arch/arm64/include/asm/device.h
+++ b/arch/arm64/include/asm/device.h
@@ -18,6 +18,9 @@
struct dev_archdata {
struct dma_map_ops *dma_ops;
+#ifdef CONFIG_IOMMU_API
+ void *iommu; /* private IOMMU data */
+#endif
};
struct pdev_archdata {
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index 994776894198..8d1810001aef 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -81,8 +81,12 @@ static inline void dma_mark_clean(void *addr, size_t size)
{
}
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flags)
+#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
+#define dma_free_coherent(d, s, h, f) dma_free_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 flags,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
void *vaddr;
@@ -90,13 +94,14 @@ static inline void *dma_alloc_coherent(struct device *dev, size_t size,
if (dma_alloc_from_coherent(dev, size, dma_handle, &vaddr))
return vaddr;
- vaddr = ops->alloc(dev, size, dma_handle, flags, NULL);
+ vaddr = ops->alloc(dev, size, dma_handle, flags, attrs);
debug_dma_alloc_coherent(dev, size, *dma_handle, vaddr);
return vaddr;
}
-static inline void dma_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dev_addr)
+static inline void dma_free_attrs(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dev_addr,
+ struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
@@ -104,7 +109,7 @@ static inline void dma_free_coherent(struct device *dev, size_t size,
return;
debug_dma_free_coherent(dev, size, vaddr, dev_addr);
- ops->free(dev, size, vaddr, dev_addr, NULL);
+ ops->free(dev, size, vaddr, dev_addr, attrs);
}
/*
diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h
new file mode 100644
index 000000000000..5b7ca8ace95f
--- /dev/null
+++ b/arch/arm64/include/asm/hugetlb.h
@@ -0,0 +1,117 @@
+/*
+ * arch/arm64/include/asm/hugetlb.h
+ *
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * Based on arch/x86/include/asm/hugetlb.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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_HUGETLB_H
+#define __ASM_HUGETLB_H
+
+#include <asm-generic/hugetlb.h>
+#include <asm/page.h>
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ set_pte_at(mm, addr, ptep, pte);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_clear_flush(vma, addr, ptep);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr, unsigned long len)
+{
+ return 0;
+}
+
+static inline int prepare_hugepage_range(struct file *file,
+ unsigned long addr, unsigned long len)
+{
+ struct hstate *h = hstate_file(file);
+ if (len & ~huge_page_mask(h))
+ return -EINVAL;
+ if (addr & ~huge_page_mask(h))
+ return -EINVAL;
+ 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);
+}
+
+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);
+}
+
+#endif /* __ASM_HUGETLB_H */
diff --git a/arch/arm64/include/asm/hypervisor.h b/arch/arm64/include/asm/hypervisor.h
new file mode 100644
index 000000000000..d2c79049ff11
--- /dev/null
+++ b/arch/arm64/include/asm/hypervisor.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_ARM64_HYPERVISOR_H
+#define _ASM_ARM64_HYPERVISOR_H
+
+#include <asm/xen/hypervisor.h>
+
+#endif
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 2e12258aa7e4..1d12f89140ba 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -228,10 +228,12 @@ extern void __iounmap(volatile void __iomem *addr);
#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY)
#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC))
+#define PROT_NORMAL (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
#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_cached(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL))
#define iounmap __iounmap
#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF)
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
new file mode 100644
index 000000000000..a5f28e2720c7
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_ARM_H__
+#define __ARM64_KVM_ARM_H__
+
+#include <asm/types.h>
+
+/* Hyp Configuration Register (HCR) bits */
+#define HCR_ID (UL(1) << 33)
+#define HCR_CD (UL(1) << 32)
+#define HCR_RW_SHIFT 31
+#define HCR_RW (UL(1) << HCR_RW_SHIFT)
+#define HCR_TRVM (UL(1) << 30)
+#define HCR_HCD (UL(1) << 29)
+#define HCR_TDZ (UL(1) << 28)
+#define HCR_TGE (UL(1) << 27)
+#define HCR_TVM (UL(1) << 26)
+#define HCR_TTLB (UL(1) << 25)
+#define HCR_TPU (UL(1) << 24)
+#define HCR_TPC (UL(1) << 23)
+#define HCR_TSW (UL(1) << 22)
+#define HCR_TAC (UL(1) << 21)
+#define HCR_TIDCP (UL(1) << 20)
+#define HCR_TSC (UL(1) << 19)
+#define HCR_TID3 (UL(1) << 18)
+#define HCR_TID2 (UL(1) << 17)
+#define HCR_TID1 (UL(1) << 16)
+#define HCR_TID0 (UL(1) << 15)
+#define HCR_TWE (UL(1) << 14)
+#define HCR_TWI (UL(1) << 13)
+#define HCR_DC (UL(1) << 12)
+#define HCR_BSU (3 << 10)
+#define HCR_BSU_IS (UL(1) << 10)
+#define HCR_FB (UL(1) << 9)
+#define HCR_VA (UL(1) << 8)
+#define HCR_VI (UL(1) << 7)
+#define HCR_VF (UL(1) << 6)
+#define HCR_AMO (UL(1) << 5)
+#define HCR_IMO (UL(1) << 4)
+#define HCR_FMO (UL(1) << 3)
+#define HCR_PTW (UL(1) << 2)
+#define HCR_SWIO (UL(1) << 1)
+#define HCR_VM (UL(1) << 0)
+
+/*
+ * The bits we set in HCR:
+ * RW: 64bit by default, can be overriden for 32bit VMs
+ * TAC: Trap ACTLR
+ * TSC: Trap SMC
+ * TSW: Trap cache operations by set/way
+ * TWI: Trap WFI
+ * TIDCP: Trap L2CTLR/L2ECTLR
+ * BSU_IS: Upgrade barriers to the inner shareable domain
+ * FB: Force broadcast of all maintainance operations
+ * AMO: Override CPSR.A and enable signaling with VA
+ * IMO: Override CPSR.I and enable signaling with VI
+ * FMO: Override CPSR.F and enable signaling with VF
+ * SWIO: Turn set/way invalidates into set/way clean+invalidate
+ */
+#define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWI | HCR_VM | HCR_BSU_IS | \
+ HCR_FB | HCR_TAC | HCR_AMO | HCR_IMO | HCR_FMO | \
+ HCR_SWIO | HCR_TIDCP | HCR_RW)
+#define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+
+/* Hyp System Control Register (SCTLR_EL2) bits */
+#define SCTLR_EL2_EE (1 << 25)
+#define SCTLR_EL2_WXN (1 << 19)
+#define SCTLR_EL2_I (1 << 12)
+#define SCTLR_EL2_SA (1 << 3)
+#define SCTLR_EL2_C (1 << 2)
+#define SCTLR_EL2_A (1 << 1)
+#define SCTLR_EL2_M 1
+#define SCTLR_EL2_FLAGS (SCTLR_EL2_M | SCTLR_EL2_A | SCTLR_EL2_C | \
+ SCTLR_EL2_SA | SCTLR_EL2_I)
+
+/* TCR_EL2 Registers bits */
+#define TCR_EL2_TBI (1 << 20)
+#define TCR_EL2_PS (7 << 16)
+#define TCR_EL2_PS_40B (2 << 16)
+#define TCR_EL2_TG0 (1 << 14)
+#define TCR_EL2_SH0 (3 << 12)
+#define TCR_EL2_ORGN0 (3 << 10)
+#define TCR_EL2_IRGN0 (3 << 8)
+#define TCR_EL2_T0SZ 0x3f
+#define TCR_EL2_MASK (TCR_EL2_TG0 | TCR_EL2_SH0 | \
+ TCR_EL2_ORGN0 | TCR_EL2_IRGN0 | TCR_EL2_T0SZ)
+
+#define TCR_EL2_FLAGS (TCR_EL2_PS_40B)
+
+/* VTCR_EL2 Registers bits */
+#define VTCR_EL2_PS_MASK (7 << 16)
+#define VTCR_EL2_PS_40B (2 << 16)
+#define VTCR_EL2_TG0_MASK (1 << 14)
+#define VTCR_EL2_TG0_4K (0 << 14)
+#define VTCR_EL2_TG0_64K (1 << 14)
+#define VTCR_EL2_SH0_MASK (3 << 12)
+#define VTCR_EL2_SH0_INNER (3 << 12)
+#define VTCR_EL2_ORGN0_MASK (3 << 10)
+#define VTCR_EL2_ORGN0_WBWA (1 << 10)
+#define VTCR_EL2_IRGN0_MASK (3 << 8)
+#define VTCR_EL2_IRGN0_WBWA (1 << 8)
+#define VTCR_EL2_SL0_MASK (3 << 6)
+#define VTCR_EL2_SL0_LVL1 (1 << 6)
+#define VTCR_EL2_T0SZ_MASK 0x3f
+#define VTCR_EL2_T0SZ_40B 24
+
+#ifdef CONFIG_ARM64_64K_PAGES
+/*
+ * Stage2 translation configuration:
+ * 40bits output (PS = 2)
+ * 40bits input (T0SZ = 24)
+ * 64kB pages (TG0 = 1)
+ * 2 level page tables (SL = 1)
+ */
+#define VTCR_EL2_FLAGS (VTCR_EL2_PS_40B | VTCR_EL2_TG0_64K | \
+ VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
+ VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
+ VTCR_EL2_T0SZ_40B)
+#define VTTBR_X (38 - VTCR_EL2_T0SZ_40B)
+#else
+/*
+ * Stage2 translation configuration:
+ * 40bits output (PS = 2)
+ * 40bits input (T0SZ = 24)
+ * 4kB pages (TG0 = 0)
+ * 3 level page tables (SL = 1)
+ */
+#define VTCR_EL2_FLAGS (VTCR_EL2_PS_40B | VTCR_EL2_TG0_4K | \
+ VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
+ VTCR_EL2_IRGN0_WBWA | VTCR_EL2_SL0_LVL1 | \
+ VTCR_EL2_T0SZ_40B)
+#define VTTBR_X (37 - VTCR_EL2_T0SZ_40B)
+#endif
+
+#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
+#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_VMID_SHIFT (48LLU)
+#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT)
+
+/* Hyp System Trap Register */
+#define HSTR_EL2_TTEE (1 << 16)
+#define HSTR_EL2_T(x) (1 << x)
+
+/* Hyp Coprocessor Trap Register */
+#define CPTR_EL2_TCPAC (1 << 31)
+#define CPTR_EL2_TTA (1 << 20)
+#define CPTR_EL2_TFP (1 << 10)
+
+/* Hyp Debug Configuration Register bits */
+#define MDCR_EL2_TDRA (1 << 11)
+#define MDCR_EL2_TDOSA (1 << 10)
+#define MDCR_EL2_TDA (1 << 9)
+#define MDCR_EL2_TDE (1 << 8)
+#define MDCR_EL2_HPME (1 << 7)
+#define MDCR_EL2_TPM (1 << 6)
+#define MDCR_EL2_TPMCR (1 << 5)
+#define MDCR_EL2_HPMN_MASK (0x1F)
+
+/* Exception Syndrome Register (ESR) bits */
+#define ESR_EL2_EC_SHIFT (26)
+#define ESR_EL2_EC (0x3fU << ESR_EL2_EC_SHIFT)
+#define ESR_EL2_IL (1U << 25)
+#define ESR_EL2_ISS (ESR_EL2_IL - 1)
+#define ESR_EL2_ISV_SHIFT (24)
+#define ESR_EL2_ISV (1U << ESR_EL2_ISV_SHIFT)
+#define ESR_EL2_SAS_SHIFT (22)
+#define ESR_EL2_SAS (3U << ESR_EL2_SAS_SHIFT)
+#define ESR_EL2_SSE (1 << 21)
+#define ESR_EL2_SRT_SHIFT (16)
+#define ESR_EL2_SRT_MASK (0x1f << ESR_EL2_SRT_SHIFT)
+#define ESR_EL2_SF (1 << 15)
+#define ESR_EL2_AR (1 << 14)
+#define ESR_EL2_EA (1 << 9)
+#define ESR_EL2_CM (1 << 8)
+#define ESR_EL2_S1PTW (1 << 7)
+#define ESR_EL2_WNR (1 << 6)
+#define ESR_EL2_FSC (0x3f)
+#define ESR_EL2_FSC_TYPE (0x3c)
+
+#define ESR_EL2_CV_SHIFT (24)
+#define ESR_EL2_CV (1U << ESR_EL2_CV_SHIFT)
+#define ESR_EL2_COND_SHIFT (20)
+#define ESR_EL2_COND (0xfU << ESR_EL2_COND_SHIFT)
+
+
+#define FSC_FAULT (0x04)
+#define FSC_PERM (0x0c)
+
+/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
+#define HPFAR_MASK (~0xFUL)
+
+#define ESR_EL2_EC_UNKNOWN (0x00)
+#define ESR_EL2_EC_WFI (0x01)
+#define ESR_EL2_EC_CP15_32 (0x03)
+#define ESR_EL2_EC_CP15_64 (0x04)
+#define ESR_EL2_EC_CP14_MR (0x05)
+#define ESR_EL2_EC_CP14_LS (0x06)
+#define ESR_EL2_EC_FP_ASIMD (0x07)
+#define ESR_EL2_EC_CP10_ID (0x08)
+#define ESR_EL2_EC_CP14_64 (0x0C)
+#define ESR_EL2_EC_ILL_ISS (0x0E)
+#define ESR_EL2_EC_SVC32 (0x11)
+#define ESR_EL2_EC_HVC32 (0x12)
+#define ESR_EL2_EC_SMC32 (0x13)
+#define ESR_EL2_EC_SVC64 (0x15)
+#define ESR_EL2_EC_HVC64 (0x16)
+#define ESR_EL2_EC_SMC64 (0x17)
+#define ESR_EL2_EC_SYS64 (0x18)
+#define ESR_EL2_EC_IABT (0x20)
+#define ESR_EL2_EC_IABT_HYP (0x21)
+#define ESR_EL2_EC_PC_ALIGN (0x22)
+#define ESR_EL2_EC_DABT (0x24)
+#define ESR_EL2_EC_DABT_HYP (0x25)
+#define ESR_EL2_EC_SP_ALIGN (0x26)
+#define ESR_EL2_EC_FP_EXC32 (0x28)
+#define ESR_EL2_EC_FP_EXC64 (0x2C)
+#define ESR_EL2_EC_SERRROR (0x2F)
+#define ESR_EL2_EC_BREAKPT (0x30)
+#define ESR_EL2_EC_BREAKPT_HYP (0x31)
+#define ESR_EL2_EC_SOFTSTP (0x32)
+#define ESR_EL2_EC_SOFTSTP_HYP (0x33)
+#define ESR_EL2_EC_WATCHPT (0x34)
+#define ESR_EL2_EC_WATCHPT_HYP (0x35)
+#define ESR_EL2_EC_BKPT32 (0x38)
+#define ESR_EL2_EC_VECTOR32 (0x3A)
+#define ESR_EL2_EC_BRK64 (0x3C)
+
+#define ESR_EL2_EC_xABT_xFSR_EXTABT 0x10
+
+#endif /* __ARM64_KVM_ARM_H__ */
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
new file mode 100644
index 000000000000..c92de4163eba
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM_KVM_ASM_H__
+#define __ARM_KVM_ASM_H__
+
+/*
+ * 0 is reserved as an invalid value.
+ * Order *must* be kept in sync with the hyp switch code.
+ */
+#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 CPACR_EL1 5 /* Coprocessor Access Control */
+#define TTBR0_EL1 6 /* Translation Table Base Register 0 */
+#define TTBR1_EL1 7 /* Translation Table Base Register 1 */
+#define TCR_EL1 8 /* Translation Control Register */
+#define ESR_EL1 9 /* Exception Syndrome Register */
+#define AFSR0_EL1 10 /* Auxilary Fault Status Register 0 */
+#define AFSR1_EL1 11 /* Auxilary Fault Status Register 1 */
+#define FAR_EL1 12 /* Fault Address Register */
+#define MAIR_EL1 13 /* Memory Attribute Indirection Register */
+#define VBAR_EL1 14 /* Vector Base Address Register */
+#define CONTEXTIDR_EL1 15 /* Context ID Register */
+#define TPIDR_EL0 16 /* Thread ID, User R/W */
+#define TPIDRRO_EL0 17 /* Thread ID, User R/O */
+#define TPIDR_EL1 18 /* Thread ID, Privileged */
+#define AMAIR_EL1 19 /* Aux Memory Attribute Indirection Register */
+#define CNTKCTL_EL1 20 /* Timer Control Register (EL1) */
+/* 32bit specific registers. Keep them at the end of the range */
+#define DACR32_EL2 21 /* Domain Access Control Register */
+#define IFSR32_EL2 22 /* Instruction Fault Status Register */
+#define FPEXC32_EL2 23 /* Floating-Point Exception Control Register */
+#define DBGVCR32_EL2 24 /* Debug Vector Catch Register */
+#define TEECR32_EL1 25 /* ThumbEE Configuration Register */
+#define TEEHBR32_EL1 26 /* ThumbEE Handler Base Register */
+#define NR_SYS_REGS 27
+
+/* 32bit mapping */
+#define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
+#define c0_CSSELR (CSSELR_EL1 * 2)/* Cache Size Selection Register */
+#define c1_SCTLR (SCTLR_EL1 * 2) /* System Control Register */
+#define c1_ACTLR (ACTLR_EL1 * 2) /* Auxiliary Control Register */
+#define c1_CPACR (CPACR_EL1 * 2) /* Coprocessor Access Control */
+#define c2_TTBR0 (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
+#define c2_TTBR0_high (c2_TTBR0 + 1) /* TTBR0 top 32 bits */
+#define c2_TTBR1 (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
+#define c2_TTBR1_high (c2_TTBR1 + 1) /* TTBR1 top 32 bits */
+#define c2_TTBCR (TCR_EL1 * 2) /* Translation Table Base Control R. */
+#define c3_DACR (DACR32_EL2 * 2)/* Domain Access Control Register */
+#define c5_DFSR (ESR_EL1 * 2) /* Data Fault Status Register */
+#define c5_IFSR (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
+#define c5_ADFSR (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
+#define c5_AIFSR (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
+#define c6_DFAR (FAR_EL1 * 2) /* Data Fault Address Register */
+#define c6_IFAR (c6_DFAR + 1) /* Instruction Fault Address Register */
+#define c10_PRRR (MAIR_EL1 * 2) /* Primary Region Remap Register */
+#define c10_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */
+#define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */
+#define c13_CID (CONTEXTIDR_EL1 * 2) /* Context ID Register */
+#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
+#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
+#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
+#define c10_AMAIR (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
+#define NR_CP15_REGS (NR_SYS_REGS * 2)
+
+#define ARM_EXCEPTION_IRQ 0
+#define ARM_EXCEPTION_TRAP 1
+
+#ifndef __ASSEMBLY__
+struct kvm;
+struct kvm_vcpu;
+
+extern char __kvm_hyp_init[];
+extern char __kvm_hyp_init_end[];
+
+extern char __kvm_hyp_vector[];
+
+extern char __kvm_hyp_code_start[];
+extern char __kvm_hyp_code_end[];
+
+extern void __kvm_flush_vm_context(void);
+extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
+
+extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+#endif
+
+#endif /* __ARM_KVM_ASM_H__ */
diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h
new file mode 100644
index 000000000000..9a59301cd014
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_coproc.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/asm/kvm_coproc.h
+ * Copyright (C) 2012 Rusty Russell IBM 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __ARM64_KVM_COPROC_H__
+#define __ARM64_KVM_COPROC_H__
+
+#include <linux/kvm_host.h>
+
+void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
+
+struct kvm_sys_reg_table {
+ const struct sys_reg_desc *table;
+ size_t num;
+};
+
+struct kvm_sys_reg_target_table {
+ struct kvm_sys_reg_table table64;
+ struct kvm_sys_reg_table table32;
+};
+
+void kvm_register_target_sys_reg_table(unsigned int target,
+ struct kvm_sys_reg_target_table *table);
+
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
+#define kvm_coproc_table_init kvm_sys_reg_table_init
+void kvm_sys_reg_table_init(void);
+
+struct kvm_one_reg;
+int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
+int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
+unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
+
+#endif /* __ARM64_KVM_COPROC_H__ */
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
new file mode 100644
index 000000000000..eec073875218
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/kvm_emulate.h
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_EMULATE_H__
+#define __ARM64_KVM_EMULATE_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmio.h>
+#include <asm/ptrace.h>
+
+unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num);
+unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu);
+
+bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
+void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr);
+
+void kvm_inject_undefined(struct kvm_vcpu *vcpu);
+void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr);
+void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
+
+static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pc;
+}
+
+static inline unsigned long *vcpu_elr_el1(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu_gp_regs(vcpu)->elr_el1;
+}
+
+static inline unsigned long *vcpu_cpsr(const struct kvm_vcpu *vcpu)
+{
+ return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.pstate;
+}
+
+static inline bool vcpu_mode_is_32bit(const struct kvm_vcpu *vcpu)
+{
+ return !!(*vcpu_cpsr(vcpu) & PSR_MODE32_BIT);
+}
+
+static inline bool kvm_condition_valid(const struct kvm_vcpu *vcpu)
+{
+ if (vcpu_mode_is_32bit(vcpu))
+ return kvm_condition_valid32(vcpu);
+
+ return true;
+}
+
+static inline void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr)
+{
+ if (vcpu_mode_is_32bit(vcpu))
+ kvm_skip_instr32(vcpu, is_wide_instr);
+ else
+ *vcpu_pc(vcpu) += 4;
+}
+
+static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
+{
+ *vcpu_cpsr(vcpu) |= COMPAT_PSR_T_BIT;
+}
+
+static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num)
+{
+ if (vcpu_mode_is_32bit(vcpu))
+ return vcpu_reg32(vcpu, reg_num);
+
+ return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num];
+}
+
+/* Get vcpu SPSR for current mode */
+static inline unsigned long *vcpu_spsr(const struct kvm_vcpu *vcpu)
+{
+ if (vcpu_mode_is_32bit(vcpu))
+ return vcpu_spsr32(vcpu);
+
+ return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[KVM_SPSR_EL1];
+}
+
+static inline bool vcpu_mode_priv(const struct kvm_vcpu *vcpu)
+{
+ u32 mode = *vcpu_cpsr(vcpu) & PSR_MODE_MASK;
+
+ if (vcpu_mode_is_32bit(vcpu))
+ return mode > COMPAT_PSR_MODE_USR;
+
+ return mode != PSR_MODE_EL0t;
+}
+
+static inline u32 kvm_vcpu_get_hsr(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.fault.esr_el2;
+}
+
+static inline unsigned long kvm_vcpu_get_hfar(const struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.fault.far_el2;
+}
+
+static inline phys_addr_t kvm_vcpu_get_fault_ipa(const struct kvm_vcpu *vcpu)
+{
+ return ((phys_addr_t)vcpu->arch.fault.hpfar_el2 & HPFAR_MASK) << 8;
+}
+
+static inline bool kvm_vcpu_dabt_isvalid(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_ISV);
+}
+
+static inline bool kvm_vcpu_dabt_iswrite(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_WNR);
+}
+
+static inline bool kvm_vcpu_dabt_issext(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SSE);
+}
+
+static inline int kvm_vcpu_dabt_get_rd(const struct kvm_vcpu *vcpu)
+{
+ return (kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SRT_MASK) >> ESR_EL2_SRT_SHIFT;
+}
+
+static inline bool kvm_vcpu_dabt_isextabt(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_EA);
+}
+
+static inline bool kvm_vcpu_dabt_iss1tw(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_S1PTW);
+}
+
+static inline int kvm_vcpu_dabt_get_as(const struct kvm_vcpu *vcpu)
+{
+ return 1 << ((kvm_vcpu_get_hsr(vcpu) & ESR_EL2_SAS) >> ESR_EL2_SAS_SHIFT);
+}
+
+/* This one is not specific to Data Abort */
+static inline bool kvm_vcpu_trap_il_is32bit(const struct kvm_vcpu *vcpu)
+{
+ return !!(kvm_vcpu_get_hsr(vcpu) & ESR_EL2_IL);
+}
+
+static inline u8 kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_get_hsr(vcpu) >> ESR_EL2_EC_SHIFT;
+}
+
+static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_trap_get_class(vcpu) == ESR_EL2_EC_IABT;
+}
+
+static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu)
+{
+ return kvm_vcpu_get_hsr(vcpu) & ESR_EL2_FSC_TYPE;
+}
+
+#endif /* __ARM64_KVM_EMULATE_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
new file mode 100644
index 000000000000..644d73956864
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/asm/kvm_host.h:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_HOST_H__
+#define __ARM64_KVM_HOST_H__
+
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmio.h>
+
+#define KVM_MAX_VCPUS 4
+#define KVM_USER_MEM_SLOTS 32
+#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+
+#include <kvm/arm_vgic.h>
+#include <kvm/arm_arch_timer.h>
+
+#define KVM_VCPU_MAX_FEATURES 2
+
+/* We don't currently support large pages. */
+#define KVM_HPAGE_GFN_SHIFT(x) 0
+#define KVM_NR_PAGE_SIZES 1
+#define KVM_PAGES_PER_HPAGE(x) (1UL<<31)
+
+struct kvm_vcpu;
+int kvm_target_cpu(void);
+int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
+int kvm_arch_dev_ioctl_check_extension(long ext);
+
+struct kvm_arch {
+ /* The VMID generation used for the virt. memory system */
+ u64 vmid_gen;
+ u32 vmid;
+
+ /* 1-level 2nd stage table and lock */
+ spinlock_t pgd_lock;
+ pgd_t *pgd;
+
+ /* VTTBR value associated with above pgd and vmid */
+ u64 vttbr;
+
+ /* Interrupt controller */
+ struct vgic_dist vgic;
+
+ /* Timer */
+ struct arch_timer_kvm timer;
+};
+
+#define KVM_NR_MEM_OBJS 40
+
+/*
+ * We don't want allocation failures within the mmu code, so we preallocate
+ * enough memory for a single page fault in a cache.
+ */
+struct kvm_mmu_memory_cache {
+ int nobjs;
+ void *objects[KVM_NR_MEM_OBJS];
+};
+
+struct kvm_vcpu_fault_info {
+ u32 esr_el2; /* Hyp Syndrom Register */
+ u64 far_el2; /* Hyp Fault Address Register */
+ u64 hpfar_el2; /* Hyp IPA Fault Address Register */
+};
+
+struct kvm_cpu_context {
+ struct kvm_regs gp_regs;
+ union {
+ u64 sys_regs[NR_SYS_REGS];
+ u32 cp15[NR_CP15_REGS];
+ };
+};
+
+typedef struct kvm_cpu_context kvm_cpu_context_t;
+
+struct kvm_vcpu_arch {
+ struct kvm_cpu_context ctxt;
+
+ /* HYP configuration */
+ u64 hcr_el2;
+
+ /* Exception Information */
+ struct kvm_vcpu_fault_info fault;
+
+ /* Pointer to host CPU context */
+ kvm_cpu_context_t *host_cpu_context;
+
+ /* VGIC state */
+ struct vgic_cpu vgic_cpu;
+ struct arch_timer_cpu timer_cpu;
+
+ /*
+ * Anything that is not used directly from assembly code goes
+ * here.
+ */
+ /* dcache set/way operation pending */
+ int last_pcpu;
+ cpumask_t require_dcache_flush;
+
+ /* Don't run the guest */
+ bool pause;
+
+ /* IO related fields */
+ struct kvm_decode mmio_decode;
+
+ /* Interrupt related fields */
+ u64 irq_lines; /* IRQ and FIQ levels */
+
+ /* Cache some mmu pages needed inside spinlock regions */
+ struct kvm_mmu_memory_cache mmu_page_cache;
+
+ /* Target CPU and feature flags */
+ u32 target;
+ DECLARE_BITMAP(features, KVM_VCPU_MAX_FEATURES);
+
+ /* Detect first run of a vcpu */
+ bool has_run_once;
+};
+
+#define vcpu_gp_regs(v) (&(v)->arch.ctxt.gp_regs)
+#define vcpu_sys_reg(v,r) ((v)->arch.ctxt.sys_regs[(r)])
+#define vcpu_cp15(v,r) ((v)->arch.ctxt.cp15[(r)])
+
+struct kvm_vm_stat {
+ u32 remote_tlb_flush;
+};
+
+struct kvm_vcpu_stat {
+ u32 halt_wakeup;
+};
+
+struct kvm_vcpu_init;
+int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+ const struct kvm_vcpu_init *init);
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
+struct kvm_one_reg;
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
+
+#define KVM_ARCH_WANT_MMU_NOTIFIER
+struct kvm;
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+int kvm_unmap_hva_range(struct kvm *kvm,
+ unsigned long start, unsigned long end);
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
+
+/* We do not have shadow page tables, hence the empty hooks */
+static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+ return 0;
+}
+
+static inline int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+ return 0;
+}
+
+struct kvm_vcpu *kvm_arm_get_running_vcpu(void);
+struct kvm_vcpu __percpu **kvm_get_running_vcpus(void);
+
+u64 kvm_call_hyp(void *hypfn, ...);
+
+int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ int exception_index);
+
+int kvm_perf_init(void);
+int kvm_perf_teardown(void);
+
+static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
+ phys_addr_t pgd_ptr,
+ unsigned long hyp_stack_ptr,
+ unsigned long vector_ptr)
+{
+ /*
+ * Call initialization code, and switch to the full blown
+ * HYP code.
+ */
+ kvm_call_hyp((void *)boot_pgd_ptr, pgd_ptr,
+ hyp_stack_ptr, vector_ptr);
+}
+
+#endif /* __ARM64_KVM_HOST_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
new file mode 100644
index 000000000000..fc2f689c0694
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_mmio.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_MMIO_H__
+#define __ARM64_KVM_MMIO_H__
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+/*
+ * This is annoying. The mmio code requires this, even if we don't
+ * need any decoding. To be fixed.
+ */
+struct kvm_decode {
+ unsigned long rt;
+ bool sign_extend;
+};
+
+/*
+ * The in-kernel MMIO emulation code wants to use a copy of run->mmio,
+ * which is an anonymous type. Use our own type instead.
+ */
+struct kvm_exit_mmio {
+ phys_addr_t phys_addr;
+ u8 data[8];
+ u32 len;
+ bool is_write;
+};
+
+static inline void kvm_prepare_mmio(struct kvm_run *run,
+ struct kvm_exit_mmio *mmio)
+{
+ run->mmio.phys_addr = mmio->phys_addr;
+ run->mmio.len = mmio->len;
+ run->mmio.is_write = mmio->is_write;
+ memcpy(run->mmio.data, mmio->data, mmio->len);
+ run->exit_reason = KVM_EXIT_MMIO;
+}
+
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
+int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ phys_addr_t fault_ipa);
+
+#endif /* __ARM64_KVM_MMIO_H__ */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
new file mode 100644
index 000000000000..efe609c6a3c9
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_MMU_H__
+#define __ARM64_KVM_MMU_H__
+
+#include <asm/page.h>
+#include <asm/memory.h>
+
+/*
+ * As we only have the TTBR0_EL2 register, we cannot express
+ * "negative" addresses. This makes it impossible to directly share
+ * mappings with the kernel.
+ *
+ * Instead, give the HYP mode its own VA region at a fixed offset from
+ * the kernel by just masking the top bits (which are all ones for a
+ * kernel address).
+ */
+#define HYP_PAGE_OFFSET_SHIFT VA_BITS
+#define HYP_PAGE_OFFSET_MASK ((UL(1) << HYP_PAGE_OFFSET_SHIFT) - 1)
+#define HYP_PAGE_OFFSET (PAGE_OFFSET & HYP_PAGE_OFFSET_MASK)
+
+/*
+ * Our virtual mapping for the idmap-ed MMU-enable code. Must be
+ * shared across all the page-tables. Conveniently, we use the last
+ * possible page, where no kernel mapping will ever exist.
+ */
+#define TRAMPOLINE_VA (HYP_PAGE_OFFSET_MASK & PAGE_MASK)
+
+#ifdef __ASSEMBLY__
+
+/*
+ * Convert a kernel VA into a HYP VA.
+ * reg: VA to be converted.
+ */
+.macro kern_hyp_va reg
+ and \reg, \reg, #HYP_PAGE_OFFSET_MASK
+.endm
+
+#else
+
+#include <asm/cachetype.h>
+#include <asm/cacheflush.h>
+
+#define KERN_TO_HYP(kva) ((unsigned long)kva - PAGE_OFFSET + HYP_PAGE_OFFSET)
+
+/*
+ * Align KVM with the kernel's view of physical memory. Should be
+ * 40bit IPA, with PGD being 8kB aligned in the 4KB page configuration.
+ */
+#define KVM_PHYS_SHIFT PHYS_MASK_SHIFT
+#define KVM_PHYS_SIZE (1UL << KVM_PHYS_SHIFT)
+#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1UL)
+
+/* Make sure we get the right size, and thus the right alignment */
+#define PTRS_PER_S2_PGD (1 << (KVM_PHYS_SHIFT - PGDIR_SHIFT))
+#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
+
+int create_hyp_mappings(void *from, void *to);
+int create_hyp_io_mappings(void *from, void *to, phys_addr_t);
+void free_boot_hyp_pgd(void);
+void free_hyp_pgds(void);
+
+int kvm_alloc_stage2_pgd(struct kvm *kvm);
+void kvm_free_stage2_pgd(struct kvm *kvm);
+int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
+ phys_addr_t pa, unsigned long size);
+
+int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
+
+void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu);
+
+phys_addr_t kvm_mmu_get_httbr(void);
+phys_addr_t kvm_mmu_get_boot_httbr(void);
+phys_addr_t kvm_get_idmap_vector(void);
+int kvm_mmu_init(void);
+void kvm_clear_hyp_idmap(void);
+
+#define kvm_set_pte(ptep, pte) set_pte(ptep, pte)
+
+static inline bool kvm_is_write_fault(unsigned long esr)
+{
+ unsigned long esr_ec = esr >> ESR_EL2_EC_SHIFT;
+
+ if (esr_ec == ESR_EL2_EC_IABT)
+ return false;
+
+ if ((esr & ESR_EL2_ISV) && !(esr & ESR_EL2_WNR))
+ return false;
+
+ return true;
+}
+
+static inline void kvm_clean_dcache_area(void *addr, size_t size) {}
+static inline void kvm_clean_pgd(pgd_t *pgd) {}
+static inline void kvm_clean_pmd_entry(pmd_t *pmd) {}
+static inline void kvm_clean_pte(pte_t *pte) {}
+static inline void kvm_clean_pte_entry(pte_t *pte) {}
+
+static inline void kvm_set_s2pte_writable(pte_t *pte)
+{
+ pte_val(*pte) |= PTE_S2_RDWR;
+}
+
+struct kvm;
+
+static inline void coherent_icache_guest_page(struct kvm *kvm, gfn_t gfn)
+{
+ if (!icache_is_aliasing()) { /* PIPT */
+ unsigned long hva = gfn_to_hva(kvm, gfn);
+ flush_icache_range(hva, hva + PAGE_SIZE);
+ } else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */
+ /* any kind of VIPT cache */
+ __flush_icache_all();
+ }
+}
+
+#define kvm_flush_dcache_to_poc(a,l) __flush_dcache_area((a), (l))
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h
new file mode 100644
index 000000000000..e301a4816355
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_psci.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_PSCI_H__
+#define __ARM64_KVM_PSCI_H__
+
+bool kvm_psci_call(struct kvm_vcpu *vcpu);
+
+#endif /* __ARM64_KVM_PSCI_H__ */
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 381f556b664e..20925bcf4e2a 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -90,6 +90,12 @@
#define MT_NORMAL_NC 3
#define MT_NORMAL 4
+/*
+ * Memory types for Stage-2 translation
+ */
+#define MT_S2_NORMAL 0xf
+#define MT_S2_DEVICE_nGnRE 0x1
+
#ifndef __ASSEMBLY__
extern phys_addr_t memstart_addr;
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index e2bc385adb6b..a9eee33dfa62 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -151,12 +151,6 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
{
unsigned int cpu = smp_processor_id();
-#ifdef CONFIG_SMP
- /* check for possible thread migration */
- if (!cpumask_empty(mm_cpumask(next)) &&
- !cpumask_test_cpu(cpu, mm_cpumask(next)))
- __flush_icache_all();
-#endif
if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)) || prev != next)
check_and_switch_context(next, tsk);
}
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 75fd13d289b9..e182a356c979 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -25,16 +25,27 @@
/*
* Hardware page table definitions.
*
+ * Level 1 descriptor (PUD).
+ */
+
+#define PUD_TABLE_BIT (_AT(pgdval_t, 1) << 1)
+
+/*
* Level 2 descriptor (PMD).
*/
#define PMD_TYPE_MASK (_AT(pmdval_t, 3) << 0)
#define PMD_TYPE_FAULT (_AT(pmdval_t, 0) << 0)
#define PMD_TYPE_TABLE (_AT(pmdval_t, 3) << 0)
#define PMD_TYPE_SECT (_AT(pmdval_t, 1) << 0)
+#define PMD_TABLE_BIT (_AT(pmdval_t, 1) << 1)
/*
* Section
*/
+#define PMD_SECT_VALID (_AT(pmdval_t, 1) << 0)
+#define PMD_SECT_PROT_NONE (_AT(pmdval_t, 1) << 2)
+#define PMD_SECT_USER (_AT(pmdval_t, 1) << 6) /* AP[1] */
+#define PMD_SECT_RDONLY (_AT(pmdval_t, 1) << 7) /* AP[2] */
#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
#define PMD_SECT_NG (_AT(pmdval_t, 1) << 11)
@@ -53,6 +64,7 @@
#define PTE_TYPE_MASK (_AT(pteval_t, 3) << 0)
#define PTE_TYPE_FAULT (_AT(pteval_t, 0) << 0)
#define PTE_TYPE_PAGE (_AT(pteval_t, 3) << 0)
+#define PTE_TABLE_BIT (_AT(pteval_t, 1) << 1)
#define PTE_USER (_AT(pteval_t, 1) << 6) /* AP[1] */
#define PTE_RDONLY (_AT(pteval_t, 1) << 7) /* AP[2] */
#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
@@ -68,6 +80,24 @@
#define PTE_ATTRINDX_MASK (_AT(pteval_t, 7) << 2)
/*
+ * 2nd stage PTE definitions
+ */
+#define PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[2:1] */
+#define PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
+
+/*
+ * Memory Attribute override for Stage-2 (MemAttr[3:0])
+ */
+#define PTE_S2_MEMATTR(t) (_AT(pteval_t, (t)) << 2)
+#define PTE_S2_MEMATTR_MASK (_AT(pteval_t, 0xf) << 2)
+
+/*
+ * EL2/HYP PTE/PMD definitions
+ */
+#define PMD_HYP PMD_SECT_USER
+#define PTE_HYP PTE_USER
+
+/*
* 40-bit physical address supported.
*/
#define PHYS_MASK_SHIFT (40)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 3a768e96cf0e..f0bebc5e22cd 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -25,8 +25,8 @@
* Software defined PTE bits definition.
*/
#define PTE_VALID (_AT(pteval_t, 1) << 0)
-#define PTE_PROT_NONE (_AT(pteval_t, 1) << 1) /* only when !PTE_VALID */
-#define PTE_FILE (_AT(pteval_t, 1) << 2) /* only when !pte_present() */
+#define PTE_PROT_NONE (_AT(pteval_t, 1) << 2) /* only when !PTE_VALID */
+#define PTE_FILE (_AT(pteval_t, 1) << 3) /* only when !pte_present() */
#define PTE_DIRTY (_AT(pteval_t, 1) << 55)
#define PTE_SPECIAL (_AT(pteval_t, 1) << 56)
@@ -66,7 +66,7 @@ extern pgprot_t pgprot_default;
#define _MOD_PROT(p, b) __pgprot_modify(p, 0, b)
-#define PAGE_NONE __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE)
+#define PAGE_NONE __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
#define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
#define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
@@ -76,7 +76,13 @@ extern pgprot_t pgprot_default;
#define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY)
#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY)
-#define __PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE)
+#define PAGE_HYP _MOD_PROT(pgprot_default, PTE_HYP)
+#define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
+
+#define PAGE_S2 __pgprot_modify(pgprot_default, PTE_S2_MEMATTR_MASK, PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
+#define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDWR | PTE_UXN)
+
+#define __PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
#define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
#define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
#define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
@@ -119,7 +125,7 @@ extern struct page *empty_zero_page;
#define pte_none(pte) (!pte_val(pte))
#define pte_clear(mm,addr,ptep) set_pte(ptep, __pte(0))
#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
-#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + __pte_index(addr))
+#define pte_offset_kernel(dir,addr) (pmd_page_vaddr(*(dir)) + pte_index(addr))
#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
@@ -173,12 +179,76 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
/*
* Huge pte definitions.
*/
-#define pte_huge(pte) ((pte_val(pte) & PTE_TYPE_MASK) == PTE_TYPE_HUGEPAGE)
-#define pte_mkhuge(pte) (__pte((pte_val(pte) & ~PTE_TYPE_MASK) | PTE_TYPE_HUGEPAGE))
+#define pte_huge(pte) (!(pte_val(pte) & PTE_TABLE_BIT))
+#define pte_mkhuge(pte) (__pte(pte_val(pte) & ~PTE_TABLE_BIT))
+
+/*
+ * Hugetlb definitions.
+ */
+#define HUGE_MAX_HSTATE 2
+#define HPAGE_SHIFT PMD_SHIFT
+#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
+#define HPAGE_MASK (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
#define __HAVE_ARCH_PTE_SPECIAL
/*
+ * Software PMD bits for THP
+ */
+
+#define PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
+#define PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 57)
+
+/*
+ * THP definitions.
+ */
+#define pmd_young(pmd) (pmd_val(pmd) & PMD_SECT_AF)
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd) (!(pmd_val(pmd) & PMD_SECT_RDONLY))
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
+#define pmd_trans_splitting(pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)
+#endif
+
+#define PMD_BIT_FUNC(fn,op) \
+static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
+
+PMD_BIT_FUNC(wrprotect, |= PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
+PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING);
+PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY);
+PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY);
+PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
+PMD_BIT_FUNC(mknotpresent, &= ~PMD_TYPE_MASK);
+
+#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
+
+#define pmd_pfn(pmd) (((pmd_val(pmd) & PMD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
+#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
+
+#define pmd_page(pmd) pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
+
+static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+ const pmdval_t mask = PMD_SECT_USER | PMD_SECT_PXN | PMD_SECT_UXN |
+ PMD_SECT_RDONLY | PMD_SECT_PROT_NONE |
+ PMD_SECT_VALID;
+ pmd_val(pmd) = (pmd_val(pmd) & ~mask) | (pgprot_val(newprot) & mask);
+ return pmd;
+}
+
+#define set_pmd_at(mm, addr, pmdp, pmd) set_pmd(pmdp, pmd)
+
+static inline int has_transparent_hugepage(void)
+{
+ return 1;
+}
+
+/*
* Mark the prot value as uncacheable and unbufferable.
*/
#define pgprot_noncached(prot) \
@@ -197,6 +267,12 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
#define pmd_bad(pmd) (!(pmd_val(pmd) & 2))
+#define pmd_table(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
+ PMD_TYPE_TABLE)
+#define pmd_sect(pmd) ((pmd_val(pmd) & PMD_TYPE_MASK) == \
+ PMD_TYPE_SECT)
+
+
static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
*pmdp = pmd;
@@ -263,7 +339,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
#endif
/* Find an entry in the third-level page table.. */
-#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
@@ -281,12 +357,12 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
/*
* Encode and decode a swap entry:
- * bits 0-1: present (must be zero)
- * bit 2: PTE_FILE
- * bits 3-8: swap type
+ * bits 0, 2: present (must both be zero)
+ * bit 3: PTE_FILE
+ * bits 4-8: swap type
* bits 9-63: swap offset
*/
-#define __SWP_TYPE_SHIFT 3
+#define __SWP_TYPE_SHIFT 4
#define __SWP_TYPE_BITS 6
#define __SWP_TYPE_MASK ((1 << __SWP_TYPE_BITS) - 1)
#define __SWP_OFFSET_SHIFT (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
@@ -306,15 +382,15 @@ extern pgd_t idmap_pg_dir[PTRS_PER_PGD];
/*
* Encode and decode a file entry:
- * bits 0-1: present (must be zero)
- * bit 2: PTE_FILE
- * bits 3-63: file offset / PAGE_SIZE
+ * bits 0, 2: present (must both be zero)
+ * bit 3: PTE_FILE
+ * bits 4-63: file offset / PAGE_SIZE
*/
#define pte_file(pte) (pte_val(pte) & PTE_FILE)
-#define pte_to_pgoff(x) (pte_val(x) >> 3)
-#define pgoff_to_pte(x) __pte(((x) << 3) | PTE_FILE)
+#define pte_to_pgoff(x) (pte_val(x) >> 4)
+#define pgoff_to_pte(x) __pte(((x) << 4) | PTE_FILE)
-#define PTE_FILE_MAX_BITS 61
+#define PTE_FILE_MAX_BITS 60
extern int kern_addr_valid(unsigned long addr);
diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h
index 41a71ee4c3df..0dacbbf9458b 100644
--- a/arch/arm64/include/asm/ptrace.h
+++ b/arch/arm64/include/asm/ptrace.h
@@ -171,7 +171,5 @@ extern unsigned long profile_pc(struct pt_regs *regs);
#define profile_pc(regs) instruction_pointer(regs)
#endif
-extern int aarch32_break_trap(struct pt_regs *regs);
-
#endif /* __ASSEMBLY__ */
#endif
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index 7065e920149d..0defa0728a9b 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -59,9 +59,10 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
unsigned int tmp;
asm volatile(
- " ldaxr %w0, %1\n"
+ "2: ldaxr %w0, %1\n"
" cbnz %w0, 1f\n"
" stxr %w0, %w2, %1\n"
+ " cbnz %w0, 2b\n"
"1:\n"
: "=&r" (tmp), "+Q" (lock->lock)
: "r" (1)
diff --git a/arch/arm64/include/asm/sync_bitops.h b/arch/arm64/include/asm/sync_bitops.h
new file mode 100644
index 000000000000..8da0bf4f7659
--- /dev/null
+++ b/arch/arm64/include/asm/sync_bitops.h
@@ -0,0 +1,26 @@
+#ifndef __ASM_SYNC_BITOPS_H__
+#define __ASM_SYNC_BITOPS_H__
+
+#include <asm/bitops.h>
+#include <asm/cmpxchg.h>
+
+/* sync_bitops functions are equivalent to the SMP implementation of the
+ * original functions, independently from CONFIG_SMP being defined.
+ *
+ * We need them because _set_bit etc are not SMP safe if !CONFIG_SMP. But
+ * under Xen you might be communicating with a completely external entity
+ * who might be on another CPU (e.g. two uniprocessor guests communicating
+ * via event channels and grant tables). So we need a variant of the bit
+ * ops which are SMP safe even on a UP kernel.
+ */
+
+#define sync_set_bit(nr, p) set_bit(nr, p)
+#define sync_clear_bit(nr, p) clear_bit(nr, p)
+#define sync_change_bit(nr, p) change_bit(nr, p)
+#define sync_test_and_set_bit(nr, p) test_and_set_bit(nr, p)
+#define sync_test_and_clear_bit(nr, p) test_and_clear_bit(nr, p)
+#define sync_test_and_change_bit(nr, p) test_and_change_bit(nr, p)
+#define sync_test_bit(nr, addr) test_bit(nr, addr)
+#define sync_cmpxchg cmpxchg
+
+#endif
diff --git a/arch/arm64/include/asm/timex.h b/arch/arm64/include/asm/timex.h
index b24a31a7e2c9..81a076eb37fa 100644
--- a/arch/arm64/include/asm/timex.h
+++ b/arch/arm64/include/asm/timex.h
@@ -16,14 +16,14 @@
#ifndef __ASM_TIMEX_H
#define __ASM_TIMEX_H
+#include <asm/arch_timer.h>
+
/*
* Use the current timer as a cycle counter since this is what we use for
* the delay loop.
*/
-#define get_cycles() ({ cycles_t c; read_current_timer(&c); c; })
+#define get_cycles() arch_counter_get_cntvct()
#include <asm-generic/timex.h>
-#define ARCH_HAS_READ_CURRENT_TIMER
-
#endif
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index 654f0968030b..46b3beb4b773 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -187,4 +187,10 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
#define tlb_migrate_finish(mm) do { } while (0)
+static inline void
+tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp, unsigned long addr)
+{
+ tlb_add_flush(tlb, addr);
+}
+
#endif
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 122d6320f745..8b482035cfc2 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -117,6 +117,8 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
dsb();
}
+#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0)
+
#endif
#endif
diff --git a/arch/arm64/include/asm/xen/events.h b/arch/arm64/include/asm/xen/events.h
new file mode 100644
index 000000000000..86553213c132
--- /dev/null
+++ b/arch/arm64/include/asm/xen/events.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_ARM64_XEN_EVENTS_H
+#define _ASM_ARM64_XEN_EVENTS_H
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+enum ipi_vector {
+ XEN_PLACEHOLDER_VECTOR,
+
+ /* Xen IPIs go here */
+ XEN_NR_IPIS,
+};
+
+static inline int xen_irqs_disabled(struct pt_regs *regs)
+{
+ return raw_irqs_disabled_flags((unsigned long) regs->pstate);
+}
+
+#define xchg_xen_ulong(ptr, val) xchg((ptr), (val))
+
+#endif /* _ASM_ARM64_XEN_EVENTS_H */
diff --git a/arch/arm64/include/asm/xen/hypercall.h b/arch/arm64/include/asm/xen/hypercall.h
new file mode 100644
index 000000000000..74b0c423ff5b
--- /dev/null
+++ b/arch/arm64/include/asm/xen/hypercall.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/hypercall.h>
diff --git a/arch/arm64/include/asm/xen/hypervisor.h b/arch/arm64/include/asm/xen/hypervisor.h
new file mode 100644
index 000000000000..f263da8e8769
--- /dev/null
+++ b/arch/arm64/include/asm/xen/hypervisor.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/hypervisor.h>
diff --git a/arch/arm64/include/asm/xen/interface.h b/arch/arm64/include/asm/xen/interface.h
new file mode 100644
index 000000000000..44457aebeed4
--- /dev/null
+++ b/arch/arm64/include/asm/xen/interface.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/interface.h>
diff --git a/arch/arm64/include/asm/xen/page.h b/arch/arm64/include/asm/xen/page.h
new file mode 100644
index 000000000000..bed87ec36780
--- /dev/null
+++ b/arch/arm64/include/asm/xen/page.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/xen/page.h>
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
new file mode 100644
index 000000000000..5031f4263937
--- /dev/null
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/include/uapi/asm/kvm.h:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM_KVM_H__
+#define __ARM_KVM_H__
+
+#define KVM_SPSR_EL1 0
+#define KVM_SPSR_SVC KVM_SPSR_EL1
+#define KVM_SPSR_ABT 1
+#define KVM_SPSR_UND 2
+#define KVM_SPSR_IRQ 3
+#define KVM_SPSR_FIQ 4
+#define KVM_NR_SPSR 5
+
+#ifndef __ASSEMBLY__
+#include <asm/types.h>
+#include <asm/ptrace.h>
+
+#define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_IRQ_LINE
+
+#define KVM_REG_SIZE(id) \
+ (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
+
+struct kvm_regs {
+ struct user_pt_regs regs; /* sp = sp_el0 */
+
+ __u64 sp_el1;
+ __u64 elr_el1;
+
+ __u64 spsr[KVM_NR_SPSR];
+
+ struct user_fpsimd_state fp_regs;
+};
+
+/* Supported Processor Types */
+#define KVM_ARM_TARGET_AEM_V8 0
+#define KVM_ARM_TARGET_FOUNDATION_V8 1
+#define KVM_ARM_TARGET_CORTEX_A57 2
+
+#define KVM_ARM_NUM_TARGETS 3
+
+/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
+#define KVM_ARM_DEVICE_TYPE_SHIFT 0
+#define KVM_ARM_DEVICE_TYPE_MASK (0xffff << KVM_ARM_DEVICE_TYPE_SHIFT)
+#define KVM_ARM_DEVICE_ID_SHIFT 16
+#define KVM_ARM_DEVICE_ID_MASK (0xffff << KVM_ARM_DEVICE_ID_SHIFT)
+
+/* Supported device IDs */
+#define KVM_ARM_DEVICE_VGIC_V2 0
+
+/* Supported VGIC address types */
+#define KVM_VGIC_V2_ADDR_TYPE_DIST 0
+#define KVM_VGIC_V2_ADDR_TYPE_CPU 1
+
+#define KVM_VGIC_V2_DIST_SIZE 0x1000
+#define KVM_VGIC_V2_CPU_SIZE 0x2000
+
+#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
+#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
+
+struct kvm_vcpu_init {
+ __u32 target;
+ __u32 features[7];
+};
+
+struct kvm_sregs {
+};
+
+struct kvm_fpu {
+};
+
+struct kvm_guest_debug_arch {
+};
+
+struct kvm_debug_exit_arch {
+};
+
+struct kvm_sync_regs {
+};
+
+struct kvm_arch_memory_slot {
+};
+
+/* If you need to interpret the index values, here is the key: */
+#define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
+#define KVM_REG_ARM_COPROC_SHIFT 16
+
+/* Normal registers are mapped as coprocessor 16. */
+#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / sizeof(__u32))
+
+/* Some registers need more space to represent values. */
+#define KVM_REG_ARM_DEMUX (0x0011 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM_DEMUX_ID_MASK 0x000000000000FF00
+#define KVM_REG_ARM_DEMUX_ID_SHIFT 8
+#define KVM_REG_ARM_DEMUX_ID_CCSIDR (0x00 << KVM_REG_ARM_DEMUX_ID_SHIFT)
+#define KVM_REG_ARM_DEMUX_VAL_MASK 0x00000000000000FF
+#define KVM_REG_ARM_DEMUX_VAL_SHIFT 0
+
+/* AArch64 system registers */
+#define KVM_REG_ARM64_SYSREG (0x0013 << KVM_REG_ARM_COPROC_SHIFT)
+#define KVM_REG_ARM64_SYSREG_OP0_MASK 0x000000000000c000
+#define KVM_REG_ARM64_SYSREG_OP0_SHIFT 14
+#define KVM_REG_ARM64_SYSREG_OP1_MASK 0x0000000000003800
+#define KVM_REG_ARM64_SYSREG_OP1_SHIFT 11
+#define KVM_REG_ARM64_SYSREG_CRN_MASK 0x0000000000000780
+#define KVM_REG_ARM64_SYSREG_CRN_SHIFT 7
+#define KVM_REG_ARM64_SYSREG_CRM_MASK 0x0000000000000078
+#define KVM_REG_ARM64_SYSREG_CRM_SHIFT 3
+#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
+#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0
+
+/* KVM_IRQ_LINE irq field index values */
+#define KVM_ARM_IRQ_TYPE_SHIFT 24
+#define KVM_ARM_IRQ_TYPE_MASK 0xff
+#define KVM_ARM_IRQ_VCPU_SHIFT 16
+#define KVM_ARM_IRQ_VCPU_MASK 0xff
+#define KVM_ARM_IRQ_NUM_SHIFT 0
+#define KVM_ARM_IRQ_NUM_MASK 0xffff
+
+/* irq_type field */
+#define KVM_ARM_IRQ_TYPE_CPU 0
+#define KVM_ARM_IRQ_TYPE_SPI 1
+#define KVM_ARM_IRQ_TYPE_PPI 2
+
+/* out-of-kernel GIC cpu interrupt injection irq_number field */
+#define KVM_ARM_IRQ_CPU_IRQ 0
+#define KVM_ARM_IRQ_CPU_FIQ 1
+
+/* Highest supported SPI, from VGIC_NR_IRQS */
+#define KVM_ARM_IRQ_GIC_MAX 127
+
+/* PSCI interface */
+#define KVM_PSCI_FN_BASE 0x95c1ba5e
+#define KVM_PSCI_FN(n) (KVM_PSCI_FN_BASE + (n))
+
+#define KVM_PSCI_FN_CPU_SUSPEND KVM_PSCI_FN(0)
+#define KVM_PSCI_FN_CPU_OFF KVM_PSCI_FN(1)
+#define KVM_PSCI_FN_CPU_ON KVM_PSCI_FN(2)
+#define KVM_PSCI_FN_MIGRATE KVM_PSCI_FN(3)
+
+#define KVM_PSCI_RET_SUCCESS 0
+#define KVM_PSCI_RET_NI ((unsigned long)-1)
+#define KVM_PSCI_RET_INVAL ((unsigned long)-2)
+#define KVM_PSCI_RET_DENIED ((unsigned long)-3)
+
+#endif
+
+#endif /* __ARM_KVM_H__ */
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index a2a4d810bea3..666e231d410b 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -21,6 +21,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#include <linux/kvm_host.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/cputable.h>
@@ -104,5 +105,38 @@ int main(void)
BLANK();
DEFINE(TZ_MINWEST, offsetof(struct timezone, tz_minuteswest));
DEFINE(TZ_DSTTIME, offsetof(struct timezone, tz_dsttime));
+ BLANK();
+#ifdef CONFIG_KVM_ARM_HOST
+ DEFINE(VCPU_CONTEXT, offsetof(struct kvm_vcpu, arch.ctxt));
+ DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs));
+ DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs));
+ DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs));
+ DEFINE(CPU_SP_EL1, offsetof(struct kvm_regs, sp_el1));
+ DEFINE(CPU_ELR_EL1, offsetof(struct kvm_regs, elr_el1));
+ DEFINE(CPU_SPSR, offsetof(struct kvm_regs, spsr));
+ DEFINE(CPU_SYSREGS, offsetof(struct kvm_cpu_context, sys_regs));
+ DEFINE(VCPU_ESR_EL2, offsetof(struct kvm_vcpu, arch.fault.esr_el2));
+ DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2));
+ DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2));
+ DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
+ DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
+ DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context));
+ DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
+ DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
+ DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
+ DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
+ DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
+ DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
+ DEFINE(VGIC_CPU_HCR, offsetof(struct vgic_cpu, vgic_hcr));
+ DEFINE(VGIC_CPU_VMCR, offsetof(struct vgic_cpu, vgic_vmcr));
+ DEFINE(VGIC_CPU_MISR, offsetof(struct vgic_cpu, vgic_misr));
+ DEFINE(VGIC_CPU_EISR, offsetof(struct vgic_cpu, vgic_eisr));
+ DEFINE(VGIC_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_elrsr));
+ DEFINE(VGIC_CPU_APR, offsetof(struct vgic_cpu, vgic_apr));
+ DEFINE(VGIC_CPU_LR, offsetof(struct vgic_cpu, vgic_lr));
+ DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
+ DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
+ DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
+#endif
return 0;
}
diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c
index f4726dc054b3..08018e3df580 100644
--- a/arch/arm64/kernel/debug-monitors.c
+++ b/arch/arm64/kernel/debug-monitors.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/stat.h>
+#include <linux/uaccess.h>
#include <asm/debug-monitors.h>
#include <asm/local.h>
@@ -226,13 +227,74 @@ static int single_step_handler(unsigned long addr, unsigned int esr,
return 0;
}
-static int __init single_step_init(void)
+static int brk_handler(unsigned long addr, unsigned int esr,
+ struct pt_regs *regs)
+{
+ siginfo_t info;
+
+ if (!user_mode(regs))
+ return -EFAULT;
+
+ info = (siginfo_t) {
+ .si_signo = SIGTRAP,
+ .si_errno = 0,
+ .si_code = TRAP_BRKPT,
+ .si_addr = (void __user *)instruction_pointer(regs),
+ };
+
+ force_sig_info(SIGTRAP, &info, current);
+ return 0;
+}
+
+int aarch32_break_handler(struct pt_regs *regs)
+{
+ siginfo_t info;
+ unsigned int instr;
+ bool bp = false;
+ void __user *pc = (void __user *)instruction_pointer(regs);
+
+ if (!compat_user_mode(regs))
+ return -EFAULT;
+
+ if (compat_thumb_mode(regs)) {
+ /* get 16-bit Thumb instruction */
+ get_user(instr, (u16 __user *)pc);
+ if (instr == AARCH32_BREAK_THUMB2_LO) {
+ /* get second half of 32-bit Thumb-2 instruction */
+ get_user(instr, (u16 __user *)(pc + 2));
+ bp = instr == AARCH32_BREAK_THUMB2_HI;
+ } else {
+ bp = instr == AARCH32_BREAK_THUMB;
+ }
+ } else {
+ /* 32-bit ARM instruction */
+ get_user(instr, (u32 __user *)pc);
+ bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
+ }
+
+ if (!bp)
+ return -EFAULT;
+
+ info = (siginfo_t) {
+ .si_signo = SIGTRAP,
+ .si_errno = 0,
+ .si_code = TRAP_BRKPT,
+ .si_addr = pc,
+ };
+
+ force_sig_info(SIGTRAP, &info, current);
+ return 0;
+}
+
+static int __init debug_traps_init(void)
{
hook_debug_fault_code(DBG_ESR_EVT_HWSS, single_step_handler, SIGTRAP,
TRAP_HWBKPT, "single-step handler");
+ hook_debug_fault_code(DBG_ESR_EVT_BRK, brk_handler, SIGTRAP,
+ TRAP_BRKPT, "ptrace BRK handler");
return 0;
}
-arch_initcall(single_step_init);
+arch_initcall(debug_traps_init);
/* Re-enable single step for syscall restarting. */
void user_rewind_single_step(struct task_struct *task)
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 6e1e77f1831c..fecdbf7de82e 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -53,28 +53,6 @@ void ptrace_disable(struct task_struct *child)
{
}
-/*
- * Handle hitting a breakpoint.
- */
-static int ptrace_break(struct pt_regs *regs)
-{
- siginfo_t info = {
- .si_signo = SIGTRAP,
- .si_errno = 0,
- .si_code = TRAP_BRKPT,
- .si_addr = (void __user *)instruction_pointer(regs),
- };
-
- force_sig_info(SIGTRAP, &info, current);
- return 0;
-}
-
-static int arm64_break_trap(unsigned long addr, unsigned int esr,
- struct pt_regs *regs)
-{
- return ptrace_break(regs);
-}
-
#ifdef CONFIG_HAVE_HW_BREAKPOINT
/*
* Handle hitting a HW-breakpoint.
@@ -817,33 +795,6 @@ static const struct user_regset_view user_aarch32_view = {
.regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets)
};
-int aarch32_break_trap(struct pt_regs *regs)
-{
- unsigned int instr;
- bool bp = false;
- void __user *pc = (void __user *)instruction_pointer(regs);
-
- if (compat_thumb_mode(regs)) {
- /* get 16-bit Thumb instruction */
- get_user(instr, (u16 __user *)pc);
- if (instr == AARCH32_BREAK_THUMB2_LO) {
- /* get second half of 32-bit Thumb-2 instruction */
- get_user(instr, (u16 __user *)(pc + 2));
- bp = instr == AARCH32_BREAK_THUMB2_HI;
- } else {
- bp = instr == AARCH32_BREAK_THUMB;
- }
- } else {
- /* 32-bit ARM instruction */
- get_user(instr, (u32 __user *)pc);
- bp = (instr & ~0xf0000000) == AARCH32_BREAK_ARM;
- }
-
- if (bp)
- return ptrace_break(regs);
- return 1;
-}
-
static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off,
compat_ulong_t __user *ret)
{
@@ -1111,16 +1062,6 @@ long arch_ptrace(struct task_struct *child, long request,
return ptrace_request(child, request, addr, data);
}
-
-static int __init ptrace_break_init(void)
-{
- hook_debug_fault_code(DBG_ESR_EVT_BRK, arm64_break_trap, SIGTRAP,
- TRAP_BRKPT, "ptrace BRK handler");
- return 0;
-}
-core_initcall(ptrace_break_init);
-
-
asmlinkage int syscall_trace(int dir, struct pt_regs *regs)
{
unsigned long saved_reg;
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index a551f88ae2c1..03dc3718eb13 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -68,12 +68,6 @@ unsigned long long notrace sched_clock(void)
return arch_timer_read_counter() * sched_clock_mult;
}
-int read_current_timer(unsigned long *timer_value)
-{
- *timer_value = arch_timer_read_counter();
- return 0;
-}
-
void __init time_init(void)
{
u32 arch_timer_rate;
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index f30852d28590..7ffadddb645d 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -32,6 +32,7 @@
#include <linux/syscalls.h>
#include <asm/atomic.h>
+#include <asm/debug-monitors.h>
#include <asm/traps.h>
#include <asm/stacktrace.h>
#include <asm/exception.h>
@@ -261,11 +262,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
siginfo_t info;
void __user *pc = (void __user *)instruction_pointer(regs);
-#ifdef CONFIG_COMPAT
/* check for AArch32 breakpoint instructions */
- if (compat_user_mode(regs) && aarch32_break_trap(regs) == 0)
+ if (!aarch32_break_handler(regs))
return;
-#endif
if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
printk_ratelimit()) {
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 3fae2be8b016..f5e55747242f 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -17,6 +17,19 @@ ENTRY(stext)
jiffies = jiffies_64;
+#define HYPERVISOR_TEXT \
+ /* \
+ * Force the alignment to be compatible with \
+ * the vectors requirements \
+ */ \
+ . = ALIGN(2048); \
+ VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
+ *(.hyp.idmap.text) \
+ VMLINUX_SYMBOL(__hyp_idmap_text_end) = .; \
+ VMLINUX_SYMBOL(__hyp_text_start) = .; \
+ *(.hyp.text) \
+ VMLINUX_SYMBOL(__hyp_text_end) = .;
+
SECTIONS
{
/*
@@ -49,6 +62,7 @@ SECTIONS
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
+ HYPERVISOR_TEXT
*(.fixup)
*(.gnu.warning)
. = ALIGN(16);
@@ -56,7 +70,7 @@ SECTIONS
}
RO_DATA(PAGE_SIZE)
-
+ EXCEPTION_TABLE(8)
_etext = .; /* End of text and rodata section */
. = ALIGN(PAGE_SIZE);
@@ -99,14 +113,6 @@ SECTIONS
READ_MOSTLY_DATA(64)
/*
- * The exception fixup table (might need resorting at runtime)
- */
- . = ALIGN(32);
- __start___ex_table = .;
- *(__ex_table)
- __stop___ex_table = .;
-
- /*
* and the usual data section
*/
DATA_DATA
@@ -124,3 +130,9 @@ SECTIONS
STABS_DEBUG
.comment 0 : { *(.comment) }
}
+
+/*
+ * The HYP init code can't be more than a page long.
+ */
+ASSERT(((__hyp_idmap_text_start + PAGE_SIZE) > __hyp_idmap_text_end),
+ "HYP init code too big")
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
new file mode 100644
index 000000000000..21e90820bd23
--- /dev/null
+++ b/arch/arm64/kvm/Kconfig
@@ -0,0 +1,51 @@
+#
+# KVM configuration
+#
+
+source "virt/kvm/Kconfig"
+
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
+ ---help---
+ Say Y here to get to see options for using your Linux host to run
+ other operating systems inside virtual machines (guests).
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and
+ disabled.
+
+if VIRTUALIZATION
+
+config KVM
+ bool "Kernel-based Virtual Machine (KVM) support"
+ select MMU_NOTIFIER
+ select PREEMPT_NOTIFIERS
+ select ANON_INODES
+ select KVM_MMIO
+ select KVM_ARM_HOST
+ select KVM_ARM_VGIC
+ select KVM_ARM_TIMER
+ ---help---
+ Support hosting virtualized guest machines.
+
+ If unsure, say N.
+
+config KVM_ARM_HOST
+ bool
+ ---help---
+ Provides host support for ARM processors.
+
+config KVM_ARM_VGIC
+ bool
+ depends on KVM_ARM_HOST && OF
+ select HAVE_KVM_IRQCHIP
+ ---help---
+ Adds support for a hardware assisted, in-kernel GIC emulation.
+
+config KVM_ARM_TIMER
+ bool
+ depends on KVM_ARM_VGIC
+ ---help---
+ Adds support for the Architected Timers in virtual machines.
+
+endif # VIRTUALIZATION
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
new file mode 100644
index 000000000000..72a9fd583ad3
--- /dev/null
+++ b/arch/arm64/kvm/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for Kernel-based Virtual Machine module
+#
+
+ccflags-y += -Ivirt/kvm -Iarch/arm64/kvm
+CFLAGS_arm.o := -I.
+CFLAGS_mmu.o := -I.
+
+KVM=../../../virt/kvm
+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-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/psci.o $(ARM)/perf.o
+
+kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
+kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
+kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
+
+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/emulate.c b/arch/arm64/kvm/emulate.c
new file mode 100644
index 000000000000..124418d17049
--- /dev/null
+++ b/arch/arm64/kvm/emulate.c
@@ -0,0 +1,158 @@
+/*
+ * (not much of an) Emulation layer for 32bit guests.
+ *
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * based on arch/arm/kvm/emulate.c
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+
+/*
+ * stolen from arch/arm/kernel/opcodes.c
+ *
+ * condition code lookup table
+ * index into the table is test code: EQ, NE, ... LT, GT, AL, NV
+ *
+ * bit position in short is condition code: NZCV
+ */
+static const unsigned short cc_map[16] = {
+ 0xF0F0, /* EQ == Z set */
+ 0x0F0F, /* NE */
+ 0xCCCC, /* CS == C set */
+ 0x3333, /* CC */
+ 0xFF00, /* MI == N set */
+ 0x00FF, /* PL */
+ 0xAAAA, /* VS == V set */
+ 0x5555, /* VC */
+ 0x0C0C, /* HI == C set && Z clear */
+ 0xF3F3, /* LS == C clear || Z set */
+ 0xAA55, /* GE == (N==V) */
+ 0x55AA, /* LT == (N!=V) */
+ 0x0A05, /* GT == (!Z && (N==V)) */
+ 0xF5FA, /* LE == (Z || (N!=V)) */
+ 0xFFFF, /* AL always */
+ 0 /* NV */
+};
+
+static int kvm_vcpu_get_condition(const struct kvm_vcpu *vcpu)
+{
+ u32 esr = kvm_vcpu_get_hsr(vcpu);
+
+ if (esr & ESR_EL2_CV)
+ return (esr & ESR_EL2_COND) >> ESR_EL2_COND_SHIFT;
+
+ return -1;
+}
+
+/*
+ * Check if a trapped instruction should have been executed or not.
+ */
+bool kvm_condition_valid32(const struct kvm_vcpu *vcpu)
+{
+ unsigned long cpsr;
+ u32 cpsr_cond;
+ int cond;
+
+ /* Top two bits non-zero? Unconditional. */
+ if (kvm_vcpu_get_hsr(vcpu) >> 30)
+ return true;
+
+ /* Is condition field valid? */
+ cond = kvm_vcpu_get_condition(vcpu);
+ if (cond == 0xE)
+ return true;
+
+ cpsr = *vcpu_cpsr(vcpu);
+
+ if (cond < 0) {
+ /* This can happen in Thumb mode: examine IT state. */
+ unsigned long it;
+
+ it = ((cpsr >> 8) & 0xFC) | ((cpsr >> 25) & 0x3);
+
+ /* it == 0 => unconditional. */
+ if (it == 0)
+ return true;
+
+ /* The cond for this insn works out as the top 4 bits. */
+ cond = (it >> 4);
+ }
+
+ cpsr_cond = cpsr >> 28;
+
+ if (!((cc_map[cond] >> cpsr_cond) & 1))
+ return false;
+
+ return true;
+}
+
+/**
+ * adjust_itstate - adjust ITSTATE when emulating instructions in IT-block
+ * @vcpu: The VCPU pointer
+ *
+ * When exceptions occur while instructions are executed in Thumb IF-THEN
+ * blocks, the ITSTATE field of the CPSR is not advanced (updated), so we have
+ * to do this little bit of work manually. The fields map like this:
+ *
+ * IT[7:0] -> CPSR[26:25],CPSR[15:10]
+ */
+static void kvm_adjust_itstate(struct kvm_vcpu *vcpu)
+{
+ unsigned long itbits, cond;
+ unsigned long cpsr = *vcpu_cpsr(vcpu);
+ bool is_arm = !(cpsr & COMPAT_PSR_T_BIT);
+
+ BUG_ON(is_arm && (cpsr & COMPAT_PSR_IT_MASK));
+
+ if (!(cpsr & COMPAT_PSR_IT_MASK))
+ return;
+
+ cond = (cpsr & 0xe000) >> 13;
+ itbits = (cpsr & 0x1c00) >> (10 - 2);
+ itbits |= (cpsr & (0x3 << 25)) >> 25;
+
+ /* Perform ITAdvance (see page A2-52 in ARM DDI 0406C) */
+ if ((itbits & 0x7) == 0)
+ itbits = cond = 0;
+ else
+ itbits = (itbits << 1) & 0x1f;
+
+ cpsr &= ~COMPAT_PSR_IT_MASK;
+ cpsr |= cond << 13;
+ cpsr |= (itbits & 0x1c) << (10 - 2);
+ cpsr |= (itbits & 0x3) << 25;
+ *vcpu_cpsr(vcpu) = cpsr;
+}
+
+/**
+ * kvm_skip_instr - skip a trapped instruction and proceed to the next
+ * @vcpu: The vcpu pointer
+ */
+void kvm_skip_instr32(struct kvm_vcpu *vcpu, bool is_wide_instr)
+{
+ bool is_thumb;
+
+ is_thumb = !!(*vcpu_cpsr(vcpu) & COMPAT_PSR_T_BIT);
+ if (is_thumb && !is_wide_instr)
+ *vcpu_pc(vcpu) += 2;
+ else
+ *vcpu_pc(vcpu) += 4;
+ kvm_adjust_itstate(vcpu);
+}
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
new file mode 100644
index 000000000000..2c3ff67a8ecb
--- /dev/null
+++ b/arch/arm64/kvm/guest.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/guest.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <asm/cputype.h>
+#include <asm/uaccess.h>
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+
+struct kvm_stats_debugfs_item debugfs_entries[] = {
+ { NULL }
+};
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
+ return 0;
+}
+
+static u64 core_reg_offset_from_id(u64 id)
+{
+ return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
+}
+
+static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /*
+ * Because the kvm_regs structure is a mix of 32, 64 and
+ * 128bit fields, we index it as if it was a 32bit
+ * array. Hence below, nr_regs is the number of entries, and
+ * off the index in the "array".
+ */
+ __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
+ struct kvm_regs *regs = vcpu_gp_regs(vcpu);
+ int nr_regs = sizeof(*regs) / sizeof(__u32);
+ u32 off;
+
+ /* Our ID is an index into the kvm_regs struct. */
+ off = core_reg_offset_from_id(reg->id);
+ if (off >= nr_regs ||
+ (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
+ return -ENOENT;
+
+ if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ __u32 __user *uaddr = (__u32 __user *)(unsigned long)reg->addr;
+ struct kvm_regs *regs = vcpu_gp_regs(vcpu);
+ int nr_regs = sizeof(*regs) / sizeof(__u32);
+ __uint128_t tmp;
+ void *valp = &tmp;
+ u64 off;
+ int err = 0;
+
+ /* Our ID is an index into the kvm_regs struct. */
+ off = core_reg_offset_from_id(reg->id);
+ if (off >= nr_regs ||
+ (off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
+ return -ENOENT;
+
+ if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
+ return -EINVAL;
+
+ if (copy_from_user(valp, uaddr, KVM_REG_SIZE(reg->id))) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ if (off == KVM_REG_ARM_CORE_REG(regs.pstate)) {
+ u32 mode = (*(u32 *)valp) & COMPAT_PSR_MODE_MASK;
+ switch (mode) {
+ case COMPAT_PSR_MODE_USR:
+ case COMPAT_PSR_MODE_FIQ:
+ case COMPAT_PSR_MODE_IRQ:
+ case COMPAT_PSR_MODE_SVC:
+ case COMPAT_PSR_MODE_ABT:
+ case COMPAT_PSR_MODE_UND:
+ case PSR_MODE_EL0t:
+ case PSR_MODE_EL1t:
+ case PSR_MODE_EL1h:
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ memcpy((u32 *)regs + off, valp, KVM_REG_SIZE(reg->id));
+out:
+ return err;
+}
+
+int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
+{
+ return -EINVAL;
+}
+
+static unsigned long num_core_regs(void)
+{
+ return sizeof(struct kvm_regs) / sizeof(__u32);
+}
+
+/**
+ * kvm_arm_num_regs - how many registers do we present via KVM_GET_ONE_REG
+ *
+ * This is for all registers.
+ */
+unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
+{
+ return num_core_regs() + kvm_arm_num_sys_reg_descs(vcpu);
+}
+
+/**
+ * kvm_arm_copy_reg_indices - get indices of all registers.
+ *
+ * We do core registers right here, then we apppend system regs.
+ */
+int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ unsigned int i;
+ const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 | KVM_REG_ARM_CORE;
+
+ for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
+ if (put_user(core_reg | i, uindices))
+ return -EFAULT;
+ uindices++;
+ }
+
+ return kvm_arm_copy_sys_reg_indices(vcpu, uindices);
+}
+
+int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /* We currently use nothing arch-specific in upper 32 bits */
+ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
+ return -EINVAL;
+
+ /* Register group 16 means we want a core register. */
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
+ return get_core_reg(vcpu, reg);
+
+ return kvm_arm_sys_reg_get_reg(vcpu, reg);
+}
+
+int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ /* We currently use nothing arch-specific in upper 32 bits */
+ if ((reg->id & ~KVM_REG_SIZE_MASK) >> 32 != KVM_REG_ARM64 >> 32)
+ return -EINVAL;
+
+ /* Register group 16 means we set a core register. */
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_CORE)
+ return set_core_reg(vcpu, reg);
+
+ return kvm_arm_sys_reg_set_reg(vcpu, reg);
+}
+
+int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ return -EINVAL;
+}
+
+int __attribute_const__ kvm_target_cpu(void)
+{
+ unsigned long implementor = read_cpuid_implementor();
+ unsigned long part_number = read_cpuid_part_number();
+
+ if (implementor != ARM_CPU_IMP_ARM)
+ return -EINVAL;
+
+ switch (part_number) {
+ case ARM_CPU_PART_AEM_V8:
+ return KVM_ARM_TARGET_AEM_V8;
+ case ARM_CPU_PART_FOUNDATION:
+ return KVM_ARM_TARGET_FOUNDATION_V8;
+ case ARM_CPU_PART_CORTEX_A57:
+ /* Currently handled by the generic backend */
+ return KVM_ARM_TARGET_CORTEX_A57;
+ default:
+ return -EINVAL;
+ }
+}
+
+int kvm_vcpu_set_target(struct kvm_vcpu *vcpu,
+ const struct kvm_vcpu_init *init)
+{
+ unsigned int i;
+ int phys_target = kvm_target_cpu();
+
+ if (init->target != phys_target)
+ return -EINVAL;
+
+ vcpu->arch.target = phys_target;
+ bitmap_zero(vcpu->arch.features, KVM_VCPU_MAX_FEATURES);
+
+ /* -ENOENT for unknown features, -EINVAL for invalid combinations. */
+ for (i = 0; i < sizeof(init->features) * 8; i++) {
+ if (init->features[i / 32] & (1 << (i % 32))) {
+ if (i >= KVM_VCPU_MAX_FEATURES)
+ return -ENOENT;
+ set_bit(i, vcpu->arch.features);
+ }
+ }
+
+ /* Now we know what it is, we can reset it. */
+ return kvm_reset_vcpu(vcpu);
+}
+
+int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ return -EINVAL;
+}
+
+int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
+ struct kvm_translation *tr)
+{
+ return -EINVAL;
+}
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
new file mode 100644
index 000000000000..9beaca033437
--- /dev/null
+++ b/arch/arm64/kvm/handle_exit.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/handle_exit.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <asm/kvm_mmu.h>
+#include <asm/kvm_psci.h>
+
+typedef int (*exit_handle_fn)(struct kvm_vcpu *, struct kvm_run *);
+
+static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ if (kvm_psci_call(vcpu))
+ return 1;
+
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ if (kvm_psci_call(vcpu))
+ return 1;
+
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu: the vcpu pointer
+ *
+ * Simply call kvm_vcpu_block(), which will halt execution of
+ * world-switches and schedule other host processes until there is an
+ * incoming IRQ or FIQ to the VM.
+ */
+static int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ kvm_vcpu_block(vcpu);
+ return 1;
+}
+
+static exit_handle_fn arm_exit_handlers[] = {
+ [ESR_EL2_EC_WFI] = kvm_handle_wfi,
+ [ESR_EL2_EC_CP15_32] = kvm_handle_cp15_32,
+ [ESR_EL2_EC_CP15_64] = kvm_handle_cp15_64,
+ [ESR_EL2_EC_CP14_MR] = kvm_handle_cp14_access,
+ [ESR_EL2_EC_CP14_LS] = kvm_handle_cp14_load_store,
+ [ESR_EL2_EC_CP14_64] = kvm_handle_cp14_access,
+ [ESR_EL2_EC_HVC32] = handle_hvc,
+ [ESR_EL2_EC_SMC32] = handle_smc,
+ [ESR_EL2_EC_HVC64] = handle_hvc,
+ [ESR_EL2_EC_SMC64] = handle_smc,
+ [ESR_EL2_EC_SYS64] = kvm_handle_sys_reg,
+ [ESR_EL2_EC_IABT] = kvm_handle_guest_abort,
+ [ESR_EL2_EC_DABT] = kvm_handle_guest_abort,
+};
+
+static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu)
+{
+ u8 hsr_ec = kvm_vcpu_trap_get_class(vcpu);
+
+ if (hsr_ec >= ARRAY_SIZE(arm_exit_handlers) ||
+ !arm_exit_handlers[hsr_ec]) {
+ kvm_err("Unkown exception class: hsr: %#08x\n",
+ (unsigned int)kvm_vcpu_get_hsr(vcpu));
+ BUG();
+ }
+
+ return arm_exit_handlers[hsr_ec];
+}
+
+/*
+ * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
+ * proper exit to userspace.
+ */
+int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ int exception_index)
+{
+ exit_handle_fn exit_handler;
+
+ switch (exception_index) {
+ case ARM_EXCEPTION_IRQ:
+ return 1;
+ case ARM_EXCEPTION_TRAP:
+ /*
+ * See ARM ARM B1.14.1: "Hyp traps on instructions
+ * that fail their condition code check"
+ */
+ if (!kvm_condition_valid(vcpu)) {
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+ return 1;
+ }
+
+ exit_handler = kvm_get_exit_handler(vcpu);
+
+ return exit_handler(vcpu, run);
+ default:
+ kvm_pr_unimpl("Unsupported exception type: %d",
+ exception_index);
+ run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
+ return 0;
+ }
+}
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
new file mode 100644
index 000000000000..ba84e6705e20
--- /dev/null
+++ b/arch/arm64/kvm/hyp-init.S
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+ .text
+ .pushsection .hyp.idmap.text, "ax"
+
+ .align 11
+
+ENTRY(__kvm_hyp_init)
+ ventry __invalid // Synchronous EL2t
+ ventry __invalid // IRQ EL2t
+ ventry __invalid // FIQ EL2t
+ ventry __invalid // Error EL2t
+
+ ventry __invalid // Synchronous EL2h
+ ventry __invalid // IRQ EL2h
+ ventry __invalid // FIQ EL2h
+ ventry __invalid // Error EL2h
+
+ ventry __do_hyp_init // Synchronous 64-bit EL1
+ ventry __invalid // IRQ 64-bit EL1
+ ventry __invalid // FIQ 64-bit EL1
+ ventry __invalid // Error 64-bit EL1
+
+ ventry __invalid // Synchronous 32-bit EL1
+ ventry __invalid // IRQ 32-bit EL1
+ ventry __invalid // FIQ 32-bit EL1
+ ventry __invalid // Error 32-bit EL1
+
+__invalid:
+ b .
+
+ /*
+ * x0: HYP boot pgd
+ * x1: HYP pgd
+ * x2: HYP stack
+ * x3: HYP vectors
+ */
+__do_hyp_init:
+
+ msr ttbr0_el2, x0
+
+ mrs x4, tcr_el1
+ ldr x5, =TCR_EL2_MASK
+ and x4, x4, x5
+ ldr x5, =TCR_EL2_FLAGS
+ orr x4, x4, x5
+ msr tcr_el2, x4
+
+ ldr x4, =VTCR_EL2_FLAGS
+ msr vtcr_el2, x4
+
+ mrs x4, mair_el1
+ msr mair_el2, x4
+ isb
+
+ mov x4, #SCTLR_EL2_FLAGS
+ msr sctlr_el2, x4
+ isb
+
+ /* MMU is now enabled. Get ready for the trampoline dance */
+ ldr x4, =TRAMPOLINE_VA
+ adr x5, target
+ bfi x4, x5, #0, #PAGE_SHIFT
+ br x4
+
+target: /* We're now in the trampoline code, switch page tables */
+ msr ttbr0_el2, x1
+ isb
+
+ /* Invalidate the old TLBs */
+ tlbi alle2
+ dsb sy
+
+ /* Set the stack and new vectors */
+ kern_hyp_va x2
+ mov sp, x2
+ kern_hyp_va x3
+ msr vbar_el2, x3
+
+ /* Hello, World! */
+ eret
+ENDPROC(__kvm_hyp_init)
+
+ .ltorg
+
+ .popsection
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
new file mode 100644
index 000000000000..ff985e3d8b72
--- /dev/null
+++ b/arch/arm64/kvm/hyp.S
@@ -0,0 +1,831 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/irqchip/arm-gic.h>
+
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/asm-offsets.h>
+#include <asm/fpsimdmacros.h>
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+#define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
+#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
+#define CPU_SPSR_OFFSET(x) CPU_GP_REG_OFFSET(CPU_SPSR + 8*x)
+#define CPU_SYSREG_OFFSET(x) (CPU_SYSREGS + 8*x)
+
+ .text
+ .pushsection .hyp.text, "ax"
+ .align PAGE_SHIFT
+
+__kvm_hyp_code_start:
+ .globl __kvm_hyp_code_start
+
+.macro save_common_regs
+ // x2: base address for cpu context
+ // x3: tmp register
+
+ add x3, x2, #CPU_XREG_OFFSET(19)
+ stp x19, x20, [x3]
+ stp x21, x22, [x3, #16]
+ stp x23, x24, [x3, #32]
+ stp x25, x26, [x3, #48]
+ stp x27, x28, [x3, #64]
+ stp x29, lr, [x3, #80]
+
+ mrs x19, sp_el0
+ mrs x20, elr_el2 // EL1 PC
+ mrs x21, spsr_el2 // EL1 pstate
+
+ stp x19, x20, [x3, #96]
+ str x21, [x3, #112]
+
+ mrs x22, sp_el1
+ mrs x23, elr_el1
+ mrs x24, spsr_el1
+
+ str x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
+ str x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
+ str x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
+.endm
+
+.macro restore_common_regs
+ // x2: base address for cpu context
+ // x3: tmp register
+
+ ldr x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
+ ldr x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
+ ldr x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
+
+ msr sp_el1, x22
+ msr elr_el1, x23
+ msr spsr_el1, x24
+
+ add x3, x2, #CPU_XREG_OFFSET(31) // SP_EL0
+ ldp x19, x20, [x3]
+ ldr x21, [x3, #16]
+
+ msr sp_el0, x19
+ msr elr_el2, x20 // EL1 PC
+ msr spsr_el2, x21 // EL1 pstate
+
+ add x3, x2, #CPU_XREG_OFFSET(19)
+ ldp x19, x20, [x3]
+ ldp x21, x22, [x3, #16]
+ ldp x23, x24, [x3, #32]
+ ldp x25, x26, [x3, #48]
+ ldp x27, x28, [x3, #64]
+ ldp x29, lr, [x3, #80]
+.endm
+
+.macro save_host_regs
+ save_common_regs
+.endm
+
+.macro restore_host_regs
+ restore_common_regs
+.endm
+
+.macro save_fpsimd
+ // x2: cpu context address
+ // x3, x4: tmp regs
+ add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+ fpsimd_save x3, 4
+.endm
+
+.macro restore_fpsimd
+ // x2: cpu context address
+ // x3, x4: tmp regs
+ add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+ fpsimd_restore x3, 4
+.endm
+
+.macro save_guest_regs
+ // x0 is the vcpu address
+ // x1 is the return code, do not corrupt!
+ // x2 is the cpu context
+ // x3 is a tmp register
+ // Guest's x0-x3 are on the stack
+
+ // Compute base to save registers
+ add x3, x2, #CPU_XREG_OFFSET(4)
+ stp x4, x5, [x3]
+ stp x6, x7, [x3, #16]
+ stp x8, x9, [x3, #32]
+ stp x10, x11, [x3, #48]
+ stp x12, x13, [x3, #64]
+ stp x14, x15, [x3, #80]
+ stp x16, x17, [x3, #96]
+ str x18, [x3, #112]
+
+ pop x6, x7 // x2, x3
+ pop x4, x5 // x0, x1
+
+ add x3, x2, #CPU_XREG_OFFSET(0)
+ stp x4, x5, [x3]
+ stp x6, x7, [x3, #16]
+
+ save_common_regs
+.endm
+
+.macro restore_guest_regs
+ // x0 is the vcpu address.
+ // x2 is the cpu context
+ // x3 is a tmp register
+
+ // Prepare x0-x3 for later restore
+ add x3, x2, #CPU_XREG_OFFSET(0)
+ ldp x4, x5, [x3]
+ ldp x6, x7, [x3, #16]
+ push x4, x5 // Push x0-x3 on the stack
+ push x6, x7
+
+ // x4-x18
+ ldp x4, x5, [x3, #32]
+ ldp x6, x7, [x3, #48]
+ ldp x8, x9, [x3, #64]
+ ldp x10, x11, [x3, #80]
+ ldp x12, x13, [x3, #96]
+ ldp x14, x15, [x3, #112]
+ ldp x16, x17, [x3, #128]
+ ldr x18, [x3, #144]
+
+ // x19-x29, lr, sp*, elr*, spsr*
+ restore_common_regs
+
+ // Last bits of the 64bit state
+ pop x2, x3
+ pop x0, x1
+
+ // Do not touch any register after this!
+.endm
+
+/*
+ * Macros to perform system register save/restore.
+ *
+ * Ordering here is absolutely critical, and must be kept consistent
+ * in {save,restore}_sysregs, {save,restore}_guest_32bit_state,
+ * and in kvm_asm.h.
+ *
+ * In other words, don't touch any of these unless you know what
+ * you are doing.
+ */
+.macro save_sysregs
+ // x2: base address for cpu context
+ // x3: tmp register
+
+ add x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
+
+ mrs x4, vmpidr_el2
+ mrs x5, csselr_el1
+ mrs x6, sctlr_el1
+ mrs x7, actlr_el1
+ mrs x8, cpacr_el1
+ mrs x9, ttbr0_el1
+ mrs x10, ttbr1_el1
+ mrs x11, tcr_el1
+ mrs x12, esr_el1
+ mrs x13, afsr0_el1
+ mrs x14, afsr1_el1
+ mrs x15, far_el1
+ mrs x16, mair_el1
+ mrs x17, vbar_el1
+ mrs x18, contextidr_el1
+ mrs x19, tpidr_el0
+ mrs x20, tpidrro_el0
+ mrs x21, tpidr_el1
+ mrs x22, amair_el1
+ mrs x23, cntkctl_el1
+
+ stp x4, x5, [x3]
+ stp x6, x7, [x3, #16]
+ stp x8, x9, [x3, #32]
+ stp x10, x11, [x3, #48]
+ stp x12, x13, [x3, #64]
+ stp x14, x15, [x3, #80]
+ stp x16, x17, [x3, #96]
+ stp x18, x19, [x3, #112]
+ stp x20, x21, [x3, #128]
+ stp x22, x23, [x3, #144]
+.endm
+
+.macro restore_sysregs
+ // x2: base address for cpu context
+ // x3: tmp register
+
+ add x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
+
+ ldp x4, x5, [x3]
+ ldp x6, x7, [x3, #16]
+ ldp x8, x9, [x3, #32]
+ ldp x10, x11, [x3, #48]
+ ldp x12, x13, [x3, #64]
+ ldp x14, x15, [x3, #80]
+ ldp x16, x17, [x3, #96]
+ ldp x18, x19, [x3, #112]
+ ldp x20, x21, [x3, #128]
+ ldp x22, x23, [x3, #144]
+
+ msr vmpidr_el2, x4
+ msr csselr_el1, x5
+ msr sctlr_el1, x6
+ msr actlr_el1, x7
+ msr cpacr_el1, x8
+ msr ttbr0_el1, x9
+ msr ttbr1_el1, x10
+ msr tcr_el1, x11
+ msr esr_el1, x12
+ msr afsr0_el1, x13
+ msr afsr1_el1, x14
+ msr far_el1, x15
+ msr mair_el1, x16
+ msr vbar_el1, x17
+ msr contextidr_el1, x18
+ msr tpidr_el0, x19
+ msr tpidrro_el0, x20
+ msr tpidr_el1, x21
+ msr amair_el1, x22
+ msr cntkctl_el1, x23
+.endm
+
+.macro skip_32bit_state tmp, target
+ // Skip 32bit state if not needed
+ mrs \tmp, hcr_el2
+ tbnz \tmp, #HCR_RW_SHIFT, \target
+.endm
+
+.macro skip_tee_state tmp, target
+ // Skip ThumbEE state if not needed
+ mrs \tmp, id_pfr0_el1
+ tbz \tmp, #12, \target
+.endm
+
+.macro save_guest_32bit_state
+ skip_32bit_state x3, 1f
+
+ add x3, x2, #CPU_SPSR_OFFSET(KVM_SPSR_ABT)
+ mrs x4, spsr_abt
+ mrs x5, spsr_und
+ mrs x6, spsr_irq
+ mrs x7, spsr_fiq
+ stp x4, x5, [x3]
+ stp x6, x7, [x3, #16]
+
+ add x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
+ mrs x4, dacr32_el2
+ mrs x5, ifsr32_el2
+ mrs x6, fpexc32_el2
+ mrs x7, dbgvcr32_el2
+ stp x4, x5, [x3]
+ stp x6, x7, [x3, #16]
+
+ skip_tee_state x8, 1f
+
+ add x3, x2, #CPU_SYSREG_OFFSET(TEECR32_EL1)
+ mrs x4, teecr32_el1
+ mrs x5, teehbr32_el1
+ stp x4, x5, [x3]
+1:
+.endm
+
+.macro restore_guest_32bit_state
+ skip_32bit_state x3, 1f
+
+ add x3, x2, #CPU_SPSR_OFFSET(KVM_SPSR_ABT)
+ ldp x4, x5, [x3]
+ ldp x6, x7, [x3, #16]
+ msr spsr_abt, x4
+ msr spsr_und, x5
+ msr spsr_irq, x6
+ msr spsr_fiq, x7
+
+ add x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
+ ldp x4, x5, [x3]
+ ldp x6, x7, [x3, #16]
+ msr dacr32_el2, x4
+ msr ifsr32_el2, x5
+ msr fpexc32_el2, x6
+ msr dbgvcr32_el2, x7
+
+ skip_tee_state x8, 1f
+
+ add x3, x2, #CPU_SYSREG_OFFSET(TEECR32_EL1)
+ ldp x4, x5, [x3]
+ msr teecr32_el1, x4
+ msr teehbr32_el1, x5
+1:
+.endm
+
+.macro activate_traps
+ ldr x2, [x0, #VCPU_IRQ_LINES]
+ ldr x1, [x0, #VCPU_HCR_EL2]
+ orr x2, x2, x1
+ msr hcr_el2, x2
+
+ ldr x2, =(CPTR_EL2_TTA)
+ msr cptr_el2, x2
+
+ ldr x2, =(1 << 15) // Trap CP15 Cr=15
+ msr hstr_el2, x2
+
+ mrs x2, mdcr_el2
+ and x2, x2, #MDCR_EL2_HPMN_MASK
+ orr x2, x2, #(MDCR_EL2_TPM | MDCR_EL2_TPMCR)
+ msr mdcr_el2, x2
+.endm
+
+.macro deactivate_traps
+ mov x2, #HCR_RW
+ msr hcr_el2, x2
+ msr cptr_el2, xzr
+ msr hstr_el2, xzr
+
+ mrs x2, mdcr_el2
+ and x2, x2, #MDCR_EL2_HPMN_MASK
+ msr mdcr_el2, x2
+.endm
+
+.macro activate_vm
+ ldr x1, [x0, #VCPU_KVM]
+ kern_hyp_va x1
+ ldr x2, [x1, #KVM_VTTBR]
+ msr vttbr_el2, x2
+.endm
+
+.macro deactivate_vm
+ msr vttbr_el2, xzr
+.endm
+
+/*
+ * Save the VGIC CPU state into memory
+ * x0: Register pointing to VCPU struct
+ * Do not corrupt x1!!!
+ */
+.macro save_vgic_state
+ /* Get VGIC VCTRL base into x2 */
+ ldr x2, [x0, #VCPU_KVM]
+ kern_hyp_va x2
+ ldr x2, [x2, #KVM_VGIC_VCTRL]
+ kern_hyp_va x2
+ cbz x2, 2f // disabled
+
+ /* Compute the address of struct vgic_cpu */
+ 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]
+ ldr w8, [x2, #GICH_EISR1]
+ ldr w9, [x2, #GICH_ELRSR0]
+ ldr w10, [x2, #GICH_ELRSR1]
+ ldr w11, [x2, #GICH_APR]
+
+ str w4, [x3, #VGIC_CPU_HCR]
+ str w5, [x3, #VGIC_CPU_VMCR]
+ str w6, [x3, #VGIC_CPU_MISR]
+ str w7, [x3, #VGIC_CPU_EISR]
+ str w8, [x3, #(VGIC_CPU_EISR + 4)]
+ str w9, [x3, #VGIC_CPU_ELRSR]
+ str w10, [x3, #(VGIC_CPU_ELRSR + 4)]
+ str w11, [x3, #VGIC_CPU_APR]
+
+ /* Clear GICH_HCR */
+ str wzr, [x2, #GICH_HCR]
+
+ /* Save list registers */
+ add x2, x2, #GICH_LR0
+ ldr w4, [x3, #VGIC_CPU_NR_LR]
+ add x3, x3, #VGIC_CPU_LR
+1: ldr w5, [x2], #4
+ str w5, [x3], #4
+ sub w4, w4, #1
+ cbnz w4, 1b
+2:
+.endm
+
+/*
+ * Restore the VGIC CPU state from memory
+ * x0: Register pointing to VCPU struct
+ */
+.macro restore_vgic_state
+ /* Get VGIC VCTRL base into x2 */
+ ldr x2, [x0, #VCPU_KVM]
+ kern_hyp_va x2
+ ldr x2, [x2, #KVM_VGIC_VCTRL]
+ kern_hyp_va x2
+ cbz x2, 2f // disabled
+
+ /* Compute the address of struct vgic_cpu */
+ add x3, x0, #VCPU_VGIC_CPU
+
+ /* We only restore a minimal set of registers */
+ ldr w4, [x3, #VGIC_CPU_HCR]
+ ldr w5, [x3, #VGIC_CPU_VMCR]
+ ldr w6, [x3, #VGIC_CPU_APR]
+
+ str w4, [x2, #GICH_HCR]
+ str w5, [x2, #GICH_VMCR]
+ str w6, [x2, #GICH_APR]
+
+ /* Restore list registers */
+ add x2, x2, #GICH_LR0
+ ldr w4, [x3, #VGIC_CPU_NR_LR]
+ add x3, x3, #VGIC_CPU_LR
+1: ldr w5, [x3], #4
+ str w5, [x2], #4
+ sub w4, w4, #1
+ cbnz w4, 1b
+2:
+.endm
+
+.macro save_timer_state
+ // x0: vcpu pointer
+ ldr x2, [x0, #VCPU_KVM]
+ kern_hyp_va x2
+ ldr w3, [x2, #KVM_TIMER_ENABLED]
+ cbz w3, 1f
+
+ mrs x3, cntv_ctl_el0
+ and x3, x3, #3
+ str w3, [x0, #VCPU_TIMER_CNTV_CTL]
+ bic x3, x3, #1 // Clear Enable
+ msr cntv_ctl_el0, x3
+
+ isb
+
+ mrs x3, cntv_cval_el0
+ str x3, [x0, #VCPU_TIMER_CNTV_CVAL]
+
+1:
+ // Allow physical timer/counter access for the host
+ mrs x2, cnthctl_el2
+ orr x2, x2, #3
+ msr cnthctl_el2, x2
+
+ // Clear cntvoff for the host
+ msr cntvoff_el2, xzr
+.endm
+
+.macro restore_timer_state
+ // x0: vcpu pointer
+ // Disallow physical timer access for the guest
+ // Physical counter access is allowed
+ mrs x2, cnthctl_el2
+ orr x2, x2, #1
+ bic x2, x2, #2
+ msr cnthctl_el2, x2
+
+ ldr x2, [x0, #VCPU_KVM]
+ kern_hyp_va x2
+ ldr w3, [x2, #KVM_TIMER_ENABLED]
+ cbz w3, 1f
+
+ ldr x3, [x2, #KVM_TIMER_CNTVOFF]
+ msr cntvoff_el2, x3
+ ldr x2, [x0, #VCPU_TIMER_CNTV_CVAL]
+ msr cntv_cval_el0, x2
+ isb
+
+ ldr w2, [x0, #VCPU_TIMER_CNTV_CTL]
+ and x2, x2, #3
+ msr cntv_ctl_el0, x2
+1:
+.endm
+
+__save_sysregs:
+ save_sysregs
+ ret
+
+__restore_sysregs:
+ restore_sysregs
+ ret
+
+__save_fpsimd:
+ save_fpsimd
+ ret
+
+__restore_fpsimd:
+ restore_fpsimd
+ ret
+
+/*
+ * u64 __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+ *
+ * This is the world switch. The first half of the function
+ * deals with entering the guest, and anything from __kvm_vcpu_return
+ * to the end of the function deals with reentering the host.
+ * On the enter path, only x0 (vcpu pointer) must be preserved until
+ * the last moment. On the exit path, x0 (vcpu pointer) and x1 (exception
+ * code) must both be preserved until the epilogue.
+ * In both cases, x2 points to the CPU context we're saving/restoring from/to.
+ */
+ENTRY(__kvm_vcpu_run)
+ kern_hyp_va x0
+ msr tpidr_el2, x0 // Save the vcpu register
+
+ // Host context
+ ldr x2, [x0, #VCPU_HOST_CONTEXT]
+ kern_hyp_va x2
+
+ save_host_regs
+ bl __save_fpsimd
+ bl __save_sysregs
+
+ activate_traps
+ activate_vm
+
+ restore_vgic_state
+ restore_timer_state
+
+ // Guest context
+ add x2, x0, #VCPU_CONTEXT
+
+ bl __restore_sysregs
+ bl __restore_fpsimd
+ restore_guest_32bit_state
+ restore_guest_regs
+
+ // That's it, no more messing around.
+ eret
+
+__kvm_vcpu_return:
+ // Assume x0 is the vcpu pointer, x1 the return code
+ // Guest's x0-x3 are on the stack
+
+ // Guest context
+ add x2, x0, #VCPU_CONTEXT
+
+ save_guest_regs
+ bl __save_fpsimd
+ bl __save_sysregs
+ save_guest_32bit_state
+
+ save_timer_state
+ save_vgic_state
+
+ deactivate_traps
+ deactivate_vm
+
+ // Host context
+ ldr x2, [x0, #VCPU_HOST_CONTEXT]
+ kern_hyp_va x2
+
+ bl __restore_sysregs
+ bl __restore_fpsimd
+ restore_host_regs
+
+ mov x0, x1
+ ret
+END(__kvm_vcpu_run)
+
+// void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
+ENTRY(__kvm_tlb_flush_vmid_ipa)
+ kern_hyp_va x0
+ ldr x2, [x0, #KVM_VTTBR]
+ msr vttbr_el2, x2
+ isb
+
+ /*
+ * We could do so much better if we had the VA as well.
+ * Instead, we invalidate Stage-2 for this IPA, and the
+ * whole of Stage-1. Weep...
+ */
+ tlbi ipas2e1is, x1
+ dsb sy
+ tlbi vmalle1is
+ dsb sy
+ isb
+
+ msr vttbr_el2, xzr
+ ret
+ENDPROC(__kvm_tlb_flush_vmid_ipa)
+
+ENTRY(__kvm_flush_vm_context)
+ tlbi alle1is
+ ic ialluis
+ dsb sy
+ ret
+ENDPROC(__kvm_flush_vm_context)
+
+__kvm_hyp_panic:
+ // Guess the context by looking at VTTBR:
+ // If zero, then we're already a host.
+ // Otherwise restore a minimal host context before panicing.
+ mrs x0, vttbr_el2
+ cbz x0, 1f
+
+ mrs x0, tpidr_el2
+
+ deactivate_traps
+ deactivate_vm
+
+ ldr x2, [x0, #VCPU_HOST_CONTEXT]
+ kern_hyp_va x2
+
+ bl __restore_sysregs
+
+1: adr x0, __hyp_panic_str
+ adr x1, 2f
+ ldp x2, x3, [x1]
+ sub x0, x0, x2
+ add x0, x0, x3
+ mrs x1, spsr_el2
+ mrs x2, elr_el2
+ mrs x3, esr_el2
+ mrs x4, far_el2
+ mrs x5, hpfar_el2
+ mrs x6, par_el1
+ mrs x7, tpidr_el2
+
+ mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
+ PSR_MODE_EL1h)
+ msr spsr_el2, lr
+ ldr lr, =panic
+ msr elr_el2, lr
+ eret
+
+ .align 3
+2: .quad HYP_PAGE_OFFSET
+ .quad PAGE_OFFSET
+ENDPROC(__kvm_hyp_panic)
+
+__hyp_panic_str:
+ .ascii "HYP panic:\nPS:%08x PC:%p ESR:%p\nFAR:%p HPFAR:%p PAR:%p\nVCPU:%p\n\0"
+
+ .align 2
+
+ENTRY(kvm_call_hyp)
+ hvc #0
+ ret
+ENDPROC(kvm_call_hyp)
+
+.macro invalid_vector label, target
+ .align 2
+\label:
+ b \target
+ENDPROC(\label)
+.endm
+
+ /* None of these should ever happen */
+ invalid_vector el2t_sync_invalid, __kvm_hyp_panic
+ invalid_vector el2t_irq_invalid, __kvm_hyp_panic
+ invalid_vector el2t_fiq_invalid, __kvm_hyp_panic
+ invalid_vector el2t_error_invalid, __kvm_hyp_panic
+ invalid_vector el2h_sync_invalid, __kvm_hyp_panic
+ invalid_vector el2h_irq_invalid, __kvm_hyp_panic
+ invalid_vector el2h_fiq_invalid, __kvm_hyp_panic
+ invalid_vector el2h_error_invalid, __kvm_hyp_panic
+ invalid_vector el1_sync_invalid, __kvm_hyp_panic
+ invalid_vector el1_irq_invalid, __kvm_hyp_panic
+ invalid_vector el1_fiq_invalid, __kvm_hyp_panic
+ invalid_vector el1_error_invalid, __kvm_hyp_panic
+
+el1_sync: // Guest trapped into EL2
+ push x0, x1
+ push x2, x3
+
+ mrs x1, esr_el2
+ lsr x2, x1, #ESR_EL2_EC_SHIFT
+
+ cmp x2, #ESR_EL2_EC_HVC64
+ b.ne el1_trap
+
+ mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest
+ cbnz x3, el1_trap // called HVC
+
+ /* Here, we're pretty sure the host called HVC. */
+ pop x2, x3
+ pop x0, x1
+
+ push lr, xzr
+
+ /*
+ * Compute the function address in EL2, and shuffle the parameters.
+ */
+ kern_hyp_va x0
+ mov lr, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ blr lr
+
+ pop lr, xzr
+ eret
+
+el1_trap:
+ /*
+ * x1: ESR
+ * x2: ESR_EC
+ */
+ cmp x2, #ESR_EL2_EC_DABT
+ mov x0, #ESR_EL2_EC_IABT
+ ccmp x2, x0, #4, ne
+ b.ne 1f // Not an abort we care about
+
+ /* This is an abort. Check for permission fault */
+ and x2, x1, #ESR_EL2_FSC_TYPE
+ cmp x2, #FSC_PERM
+ b.ne 1f // Not a permission fault
+
+ /*
+ * Check for Stage-1 page table walk, which is guaranteed
+ * to give a valid HPFAR_EL2.
+ */
+ tbnz x1, #7, 1f // S1PTW is set
+
+ /*
+ * Permission fault, HPFAR_EL2 is invalid.
+ * Resolve the IPA the hard way using the guest VA.
+ * Stage-1 translation already validated the memory access rights.
+ * As such, we can use the EL1 translation regime, and don't have
+ * to distinguish between EL0 and EL1 access.
+ */
+ mrs x2, far_el2
+ at s1e1r, x2
+ isb
+
+ /* Read result */
+ mrs x3, par_el1
+ tbnz x3, #0, 3f // Bail out if we failed the translation
+ ubfx x3, x3, #12, #36 // Extract IPA
+ lsl x3, x3, #4 // and present it like HPFAR
+ b 2f
+
+1: mrs x3, hpfar_el2
+ mrs x2, far_el2
+
+2: mrs x0, tpidr_el2
+ str x1, [x0, #VCPU_ESR_EL2]
+ str x2, [x0, #VCPU_FAR_EL2]
+ str x3, [x0, #VCPU_HPFAR_EL2]
+
+ mov x1, #ARM_EXCEPTION_TRAP
+ b __kvm_vcpu_return
+
+ /*
+ * Translation failed. Just return to the guest and
+ * let it fault again. Another CPU is probably playing
+ * behind our back.
+ */
+3: pop x2, x3
+ pop x0, x1
+
+ eret
+
+el1_irq:
+ push x0, x1
+ push x2, x3
+ mrs x0, tpidr_el2
+ mov x1, #ARM_EXCEPTION_IRQ
+ b __kvm_vcpu_return
+
+ .ltorg
+
+ .align 11
+
+ENTRY(__kvm_hyp_vector)
+ ventry el2t_sync_invalid // Synchronous EL2t
+ ventry el2t_irq_invalid // IRQ EL2t
+ ventry el2t_fiq_invalid // FIQ EL2t
+ ventry el2t_error_invalid // Error EL2t
+
+ ventry el2h_sync_invalid // Synchronous EL2h
+ ventry el2h_irq_invalid // IRQ EL2h
+ ventry el2h_fiq_invalid // FIQ EL2h
+ ventry el2h_error_invalid // Error EL2h
+
+ ventry el1_sync // Synchronous 64-bit EL1
+ ventry el1_irq // IRQ 64-bit EL1
+ ventry el1_fiq_invalid // FIQ 64-bit EL1
+ ventry el1_error_invalid // Error 64-bit EL1
+
+ ventry el1_sync // Synchronous 32-bit EL1
+ ventry el1_irq // IRQ 32-bit EL1
+ ventry el1_fiq_invalid // FIQ 32-bit EL1
+ ventry el1_error_invalid // Error 32-bit EL1
+ENDPROC(__kvm_hyp_vector)
+
+__kvm_hyp_code_end:
+ .globl __kvm_hyp_code_end
+
+ .popsection
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
new file mode 100644
index 000000000000..81a02a8762b0
--- /dev/null
+++ b/arch/arm64/kvm/inject_fault.c
@@ -0,0 +1,203 @@
+/*
+ * Fault injection for both 32 and 64bit guests.
+ *
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Based on arch/arm/kvm/emulate.c
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/esr.h>
+
+#define PSTATE_FAULT_BITS_64 (PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | \
+ PSR_I_BIT | PSR_D_BIT)
+#define EL1_EXCEPT_SYNC_OFFSET 0x200
+
+static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
+{
+ unsigned long cpsr;
+ unsigned long new_spsr_value = *vcpu_cpsr(vcpu);
+ bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT);
+ u32 return_offset = (is_thumb) ? 4 : 0;
+ u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR);
+
+ cpsr = mode | COMPAT_PSR_I_BIT;
+
+ if (sctlr & (1 << 30))
+ cpsr |= COMPAT_PSR_T_BIT;
+ if (sctlr & (1 << 25))
+ cpsr |= COMPAT_PSR_E_BIT;
+
+ *vcpu_cpsr(vcpu) = cpsr;
+
+ /* Note: These now point to the banked copies */
+ *vcpu_spsr(vcpu) = new_spsr_value;
+ *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
+
+ /* Branch to exception vector */
+ if (sctlr & (1 << 13))
+ vect_offset += 0xffff0000;
+ else /* always have security exceptions */
+ vect_offset += vcpu_cp15(vcpu, c12_VBAR);
+
+ *vcpu_pc(vcpu) = vect_offset;
+}
+
+static void inject_undef32(struct kvm_vcpu *vcpu)
+{
+ prepare_fault32(vcpu, COMPAT_PSR_MODE_UND, 4);
+}
+
+/*
+ * Modelled after TakeDataAbortException() and TakePrefetchAbortException
+ * pseudocode.
+ */
+static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt,
+ unsigned long addr)
+{
+ u32 vect_offset;
+ u32 *far, *fsr;
+ bool is_lpae;
+
+ if (is_pabt) {
+ vect_offset = 12;
+ far = &vcpu_cp15(vcpu, c6_IFAR);
+ fsr = &vcpu_cp15(vcpu, c5_IFSR);
+ } else { /* !iabt */
+ vect_offset = 16;
+ far = &vcpu_cp15(vcpu, c6_DFAR);
+ fsr = &vcpu_cp15(vcpu, c5_DFSR);
+ }
+
+ prepare_fault32(vcpu, COMPAT_PSR_MODE_ABT | COMPAT_PSR_A_BIT, vect_offset);
+
+ *far = addr;
+
+ /* Give the guest an IMPLEMENTATION DEFINED exception */
+ is_lpae = (vcpu_cp15(vcpu, c2_TTBCR) >> 31);
+ if (is_lpae)
+ *fsr = 1 << 9 | 0x34;
+ else
+ *fsr = 0x14;
+}
+
+static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
+{
+ unsigned long cpsr = *vcpu_cpsr(vcpu);
+ bool is_aarch32;
+ u32 esr = 0;
+
+ is_aarch32 = vcpu_mode_is_32bit(vcpu);
+
+ *vcpu_spsr(vcpu) = cpsr;
+ *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+
+ *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+ *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
+
+ vcpu_sys_reg(vcpu, FAR_EL1) = addr;
+
+ /*
+ * Build an {i,d}abort, depending on the level and the
+ * instruction set. Report an external synchronous abort.
+ */
+ if (kvm_vcpu_trap_il_is32bit(vcpu))
+ esr |= ESR_EL1_IL;
+
+ /*
+ * Here, the guest runs in AArch64 mode when in EL1. If we get
+ * an AArch32 fault, it means we managed to trap an EL0 fault.
+ */
+ if (is_aarch32 || (cpsr & PSR_MODE_MASK) == PSR_MODE_EL0t)
+ esr |= (ESR_EL1_EC_IABT_EL0 << ESR_EL1_EC_SHIFT);
+ else
+ esr |= (ESR_EL1_EC_IABT_EL1 << ESR_EL1_EC_SHIFT);
+
+ if (!is_iabt)
+ esr |= ESR_EL1_EC_DABT_EL0;
+
+ vcpu_sys_reg(vcpu, ESR_EL1) = esr | ESR_EL2_EC_xABT_xFSR_EXTABT;
+}
+
+static void inject_undef64(struct kvm_vcpu *vcpu)
+{
+ unsigned long cpsr = *vcpu_cpsr(vcpu);
+ u32 esr = (ESR_EL1_EC_UNKNOWN << ESR_EL1_EC_SHIFT);
+
+ *vcpu_spsr(vcpu) = cpsr;
+ *vcpu_elr_el1(vcpu) = *vcpu_pc(vcpu);
+
+ *vcpu_cpsr(vcpu) = PSTATE_FAULT_BITS_64;
+ *vcpu_pc(vcpu) = vcpu_sys_reg(vcpu, VBAR_EL1) + EL1_EXCEPT_SYNC_OFFSET;
+
+ /*
+ * Build an unknown exception, depending on the instruction
+ * set.
+ */
+ if (kvm_vcpu_trap_il_is32bit(vcpu))
+ esr |= ESR_EL1_IL;
+
+ vcpu_sys_reg(vcpu, ESR_EL1) = esr;
+}
+
+/**
+ * kvm_inject_dabt - inject a data abort into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_dabt(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+ if (!(vcpu->arch.hcr_el2 & HCR_RW))
+ inject_abt32(vcpu, false, addr);
+
+ inject_abt64(vcpu, false, addr);
+}
+
+/**
+ * kvm_inject_pabt - inject a prefetch abort into the guest
+ * @vcpu: The VCPU to receive the undefined exception
+ * @addr: The address to report in the DFAR
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr)
+{
+ if (!(vcpu->arch.hcr_el2 & HCR_RW))
+ inject_abt32(vcpu, true, addr);
+
+ inject_abt64(vcpu, true, addr);
+}
+
+/**
+ * kvm_inject_undefined - inject an undefined instruction into the guest
+ *
+ * It is assumed that this code is called from the VCPU thread and that the
+ * VCPU therefore is not currently executing guest code.
+ */
+void kvm_inject_undefined(struct kvm_vcpu *vcpu)
+{
+ if (!(vcpu->arch.hcr_el2 & HCR_RW))
+ inject_undef32(vcpu);
+
+ inject_undef64(vcpu);
+}
diff --git a/arch/arm64/kvm/regmap.c b/arch/arm64/kvm/regmap.c
new file mode 100644
index 000000000000..bbc6ae32e4af
--- /dev/null
+++ b/arch/arm64/kvm/regmap.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/emulate.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mm.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/ptrace.h>
+
+#define VCPU_NR_MODES 6
+#define REG_OFFSET(_reg) \
+ (offsetof(struct user_pt_regs, _reg) / sizeof(unsigned long))
+
+#define USR_REG_OFFSET(R) REG_OFFSET(compat_usr(R))
+
+static const unsigned long vcpu_reg_offsets[VCPU_NR_MODES][16] = {
+ /* USR Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12), USR_REG_OFFSET(13), USR_REG_OFFSET(14),
+ REG_OFFSET(pc)
+ },
+
+ /* FIQ Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7),
+ REG_OFFSET(compat_r8_fiq), /* r8 */
+ REG_OFFSET(compat_r9_fiq), /* r9 */
+ REG_OFFSET(compat_r10_fiq), /* r10 */
+ REG_OFFSET(compat_r11_fiq), /* r11 */
+ REG_OFFSET(compat_r12_fiq), /* r12 */
+ REG_OFFSET(compat_sp_fiq), /* r13 */
+ REG_OFFSET(compat_lr_fiq), /* r14 */
+ REG_OFFSET(pc)
+ },
+
+ /* IRQ Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(compat_sp_irq), /* r13 */
+ REG_OFFSET(compat_lr_irq), /* r14 */
+ REG_OFFSET(pc)
+ },
+
+ /* SVC Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(compat_sp_svc), /* r13 */
+ REG_OFFSET(compat_lr_svc), /* r14 */
+ REG_OFFSET(pc)
+ },
+
+ /* ABT Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(compat_sp_abt), /* r13 */
+ REG_OFFSET(compat_lr_abt), /* r14 */
+ REG_OFFSET(pc)
+ },
+
+ /* UND Registers */
+ {
+ USR_REG_OFFSET(0), USR_REG_OFFSET(1), USR_REG_OFFSET(2),
+ USR_REG_OFFSET(3), USR_REG_OFFSET(4), USR_REG_OFFSET(5),
+ USR_REG_OFFSET(6), USR_REG_OFFSET(7), USR_REG_OFFSET(8),
+ USR_REG_OFFSET(9), USR_REG_OFFSET(10), USR_REG_OFFSET(11),
+ USR_REG_OFFSET(12),
+ REG_OFFSET(compat_sp_und), /* r13 */
+ REG_OFFSET(compat_lr_und), /* r14 */
+ REG_OFFSET(pc)
+ },
+};
+
+/*
+ * Return a pointer to the register number valid in the current mode of
+ * the virtual CPU.
+ */
+unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num)
+{
+ unsigned long *reg_array = (unsigned long *)&vcpu->arch.ctxt.gp_regs.regs;
+ unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
+
+ switch (mode) {
+ case COMPAT_PSR_MODE_USR ... COMPAT_PSR_MODE_SVC:
+ mode &= ~PSR_MODE32_BIT; /* 0 ... 3 */
+ break;
+
+ case COMPAT_PSR_MODE_ABT:
+ mode = 4;
+ break;
+
+ case COMPAT_PSR_MODE_UND:
+ mode = 5;
+ break;
+
+ case COMPAT_PSR_MODE_SYS:
+ mode = 0; /* SYS maps to USR */
+ break;
+
+ default:
+ BUG();
+ }
+
+ return reg_array + vcpu_reg_offsets[mode][reg_num];
+}
+
+/*
+ * Return the SPSR for the current mode of the virtual CPU.
+ */
+unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu)
+{
+ unsigned long mode = *vcpu_cpsr(vcpu) & COMPAT_PSR_MODE_MASK;
+ switch (mode) {
+ case COMPAT_PSR_MODE_SVC:
+ mode = KVM_SPSR_SVC;
+ break;
+ case COMPAT_PSR_MODE_ABT:
+ mode = KVM_SPSR_ABT;
+ break;
+ case COMPAT_PSR_MODE_UND:
+ mode = KVM_SPSR_UND;
+ break;
+ case COMPAT_PSR_MODE_IRQ:
+ mode = KVM_SPSR_IRQ;
+ break;
+ case COMPAT_PSR_MODE_FIQ:
+ mode = KVM_SPSR_FIQ;
+ break;
+ default:
+ BUG();
+ }
+
+ return (unsigned long *)&vcpu_gp_regs(vcpu)->spsr[mode];
+}
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
new file mode 100644
index 000000000000..70a7816535cd
--- /dev/null
+++ b/arch/arm64/kvm/reset.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/reset.c
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Author: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/errno.h>
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+
+#include <kvm/arm_arch_timer.h>
+
+#include <asm/cputype.h>
+#include <asm/ptrace.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_coproc.h>
+
+/*
+ * ARMv8 Reset Values
+ */
+static const struct kvm_regs default_regs_reset = {
+ .regs.pstate = (PSR_MODE_EL1h | PSR_A_BIT | PSR_I_BIT |
+ PSR_F_BIT | PSR_D_BIT),
+};
+
+static const struct kvm_regs default_regs_reset32 = {
+ .regs.pstate = (COMPAT_PSR_MODE_SVC | COMPAT_PSR_A_BIT |
+ COMPAT_PSR_I_BIT | COMPAT_PSR_F_BIT),
+};
+
+static const struct kvm_irq_level default_vtimer_irq = {
+ .irq = 27,
+ .level = 1,
+};
+
+static bool cpu_has_32bit_el1(void)
+{
+ u64 pfr0;
+
+ pfr0 = read_cpuid(ID_AA64PFR0_EL1);
+ return !!(pfr0 & 0x20);
+}
+
+int kvm_arch_dev_ioctl_check_extension(long ext)
+{
+ int r;
+
+ switch (ext) {
+ case KVM_CAP_ARM_EL1_32BIT:
+ r = cpu_has_32bit_el1();
+ break;
+ default:
+ r = 0;
+ }
+
+ return r;
+}
+
+/**
+ * kvm_reset_vcpu - sets core registers and sys_regs to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on
+ * the virtual CPU struct to their architectually defined reset
+ * values.
+ */
+int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
+{
+ const struct kvm_irq_level *cpu_vtimer_irq;
+ const struct kvm_regs *cpu_reset;
+
+ switch (vcpu->arch.target) {
+ default:
+ if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features)) {
+ if (!cpu_has_32bit_el1())
+ return -EINVAL;
+ cpu_reset = &default_regs_reset32;
+ vcpu->arch.hcr_el2 &= ~HCR_RW;
+ } else {
+ cpu_reset = &default_regs_reset;
+ }
+
+ cpu_vtimer_irq = &default_vtimer_irq;
+ break;
+ }
+
+ /* Reset core registers */
+ memcpy(vcpu_gp_regs(vcpu), cpu_reset, sizeof(*cpu_reset));
+
+ /* Reset system registers */
+ kvm_reset_sys_regs(vcpu);
+
+ /* Reset timer */
+ kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);
+
+ return 0;
+}
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
new file mode 100644
index 000000000000..94923609753b
--- /dev/null
+++ b/arch/arm64/kvm/sys_regs.c
@@ -0,0 +1,1050 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/coproc.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Rusty Russell <rusty@rustcorp.com.au>
+ * Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/mm.h>
+#include <linux/kvm_host.h>
+#include <linux/uaccess.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <trace/events/kvm.h>
+
+#include "sys_regs.h"
+
+/*
+ * All of this file is extremly similar to the ARM coproc.c, but the
+ * types are different. My gut feeling is that it should be pretty
+ * easy to merge, but that would be an ABI breakage -- again. VFP
+ * would also need to be abstracted.
+ *
+ * For AArch32, we only take care of what is being trapped. Anything
+ * that has to do with init and userspace access has to go via the
+ * 64bit interface.
+ */
+
+/* 3 bits per cache level, as per CLIDR, but non-existent caches always 0 */
+static u32 cache_levels;
+
+/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */
+#define CSSELR_MAX 12
+
+/* Which cache CCSIDR represents depends on CSSELR value. */
+static u32 get_ccsidr(u32 csselr)
+{
+ u32 ccsidr;
+
+ /* Make sure noone else changes CSSELR during this! */
+ local_irq_disable();
+ /* Put value into CSSELR */
+ asm volatile("msr csselr_el1, %x0" : : "r" (csselr));
+ isb();
+ /* Read result out of CCSIDR */
+ asm volatile("mrs %0, ccsidr_el1" : "=r" (ccsidr));
+ local_irq_enable();
+
+ return ccsidr;
+}
+
+static void do_dc_cisw(u32 val)
+{
+ asm volatile("dc cisw, %x0" : : "r" (val));
+ dsb();
+}
+
+static void do_dc_csw(u32 val)
+{
+ asm volatile("dc csw, %x0" : : "r" (val));
+ dsb();
+}
+
+/* See note at ARM ARM B1.14.4 */
+static bool access_dcsw(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ unsigned long val;
+ int cpu;
+
+ if (!p->is_write)
+ return read_from_write_only(vcpu, p);
+
+ cpu = get_cpu();
+
+ cpumask_setall(&vcpu->arch.require_dcache_flush);
+ cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
+
+ /* If we were already preempted, take the long way around */
+ if (cpu != vcpu->arch.last_pcpu) {
+ flush_cache_all();
+ goto done;
+ }
+
+ val = *vcpu_reg(vcpu, p->Rt);
+
+ switch (p->CRm) {
+ case 6: /* Upgrade DCISW to DCCISW, as per HCR.SWIO */
+ case 14: /* DCCISW */
+ do_dc_cisw(val);
+ break;
+
+ case 10: /* DCCSW */
+ do_dc_csw(val);
+ break;
+ }
+
+done:
+ put_cpu();
+
+ return true;
+}
+
+/*
+ * We could trap ID_DFR0 and tell the guest we don't support performance
+ * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was
+ * NAKed, so it will read the PMCR anyway.
+ *
+ * Therefore we tell the guest we have 0 counters. Unfortunately, we
+ * must always support PMCCNTR (the cycle counter): we just RAZ/WI for
+ * all PM registers, which doesn't crash the guest kernel at least.
+ */
+static bool pm_fake(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ if (p->is_write)
+ return ignore_write(vcpu, p);
+ else
+ return read_zero(vcpu, p);
+}
+
+static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ u64 amair;
+
+ asm volatile("mrs %0, amair_el1\n" : "=r" (amair));
+ vcpu_sys_reg(vcpu, AMAIR_EL1) = amair;
+}
+
+static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ /*
+ * Simply map the vcpu_id into the Aff0 field of the MPIDR.
+ */
+ vcpu_sys_reg(vcpu, MPIDR_EL1) = (1UL << 31) | (vcpu->vcpu_id & 0xff);
+}
+
+/*
+ * Architected system registers.
+ * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
+ */
+static const struct sys_reg_desc sys_reg_descs[] = {
+ /* DC ISW */
+ { Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b0110), Op2(0b010),
+ access_dcsw },
+ /* DC CSW */
+ { Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b1010), Op2(0b010),
+ access_dcsw },
+ /* DC CISW */
+ { Op0(0b01), Op1(0b000), CRn(0b0111), CRm(0b1110), Op2(0b010),
+ access_dcsw },
+
+ /* TEECR32_EL1 */
+ { Op0(0b10), Op1(0b010), CRn(0b0000), CRm(0b0000), Op2(0b000),
+ NULL, reset_val, TEECR32_EL1, 0 },
+ /* TEEHBR32_EL1 */
+ { Op0(0b10), Op1(0b010), CRn(0b0001), CRm(0b0000), Op2(0b000),
+ NULL, reset_val, TEEHBR32_EL1, 0 },
+ /* DBGVCR32_EL2 */
+ { Op0(0b10), Op1(0b100), CRn(0b0000), CRm(0b0111), Op2(0b000),
+ NULL, reset_val, DBGVCR32_EL2, 0 },
+
+ /* MPIDR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0000), Op2(0b101),
+ NULL, reset_mpidr, MPIDR_EL1 },
+ /* SCTLR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
+ NULL, reset_val, SCTLR_EL1, 0x00C50078 },
+ /* CPACR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
+ NULL, reset_val, CPACR_EL1, 0 },
+ /* TTBR0_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b000),
+ NULL, reset_unknown, TTBR0_EL1 },
+ /* TTBR1_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b001),
+ NULL, reset_unknown, TTBR1_EL1 },
+ /* TCR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0010), CRm(0b0000), Op2(0b010),
+ NULL, reset_val, TCR_EL1, 0 },
+
+ /* AFSR0_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b000),
+ NULL, reset_unknown, AFSR0_EL1 },
+ /* AFSR1_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0001), Op2(0b001),
+ NULL, reset_unknown, AFSR1_EL1 },
+ /* ESR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0101), CRm(0b0010), Op2(0b000),
+ NULL, reset_unknown, ESR_EL1 },
+ /* FAR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0110), CRm(0b0000), Op2(0b000),
+ NULL, reset_unknown, FAR_EL1 },
+
+ /* PMINTENSET_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b001),
+ pm_fake },
+ /* PMINTENCLR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1001), CRm(0b1110), Op2(0b010),
+ pm_fake },
+
+ /* MAIR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0010), Op2(0b000),
+ NULL, reset_unknown, MAIR_EL1 },
+ /* AMAIR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1010), CRm(0b0011), Op2(0b000),
+ NULL, reset_amair_el1, AMAIR_EL1 },
+
+ /* VBAR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000),
+ NULL, reset_val, VBAR_EL1, 0 },
+ /* CONTEXTIDR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001),
+ NULL, reset_val, CONTEXTIDR_EL1, 0 },
+ /* TPIDR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b100),
+ NULL, reset_unknown, TPIDR_EL1 },
+
+ /* CNTKCTL_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b1110), CRm(0b0001), Op2(0b000),
+ NULL, reset_val, CNTKCTL_EL1, 0},
+
+ /* CSSELR_EL1 */
+ { Op0(0b11), Op1(0b010), CRn(0b0000), CRm(0b0000), Op2(0b000),
+ NULL, reset_unknown, CSSELR_EL1 },
+
+ /* PMCR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b000),
+ pm_fake },
+ /* PMCNTENSET_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b001),
+ pm_fake },
+ /* PMCNTENCLR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b010),
+ pm_fake },
+ /* PMOVSCLR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b011),
+ pm_fake },
+ /* PMSWINC_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b100),
+ pm_fake },
+ /* PMSELR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b101),
+ pm_fake },
+ /* PMCEID0_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b110),
+ pm_fake },
+ /* PMCEID1_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1100), Op2(0b111),
+ pm_fake },
+ /* PMCCNTR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b000),
+ pm_fake },
+ /* PMXEVTYPER_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001),
+ pm_fake },
+ /* PMXEVCNTR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010),
+ pm_fake },
+ /* PMUSERENR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b000),
+ pm_fake },
+ /* PMOVSSET_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1110), Op2(0b011),
+ pm_fake },
+
+ /* TPIDR_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b010),
+ NULL, reset_unknown, TPIDR_EL0 },
+ /* TPIDRRO_EL0 */
+ { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b0000), Op2(0b011),
+ NULL, reset_unknown, TPIDRRO_EL0 },
+
+ /* DACR32_EL2 */
+ { Op0(0b11), Op1(0b100), CRn(0b0011), CRm(0b0000), Op2(0b000),
+ NULL, reset_unknown, DACR32_EL2 },
+ /* IFSR32_EL2 */
+ { Op0(0b11), Op1(0b100), CRn(0b0101), CRm(0b0000), Op2(0b001),
+ NULL, reset_unknown, IFSR32_EL2 },
+ /* FPEXC32_EL2 */
+ { Op0(0b11), Op1(0b100), CRn(0b0101), CRm(0b0011), Op2(0b000),
+ NULL, reset_val, FPEXC32_EL2, 0x70 },
+};
+
+/* Trapped cp15 registers */
+static const struct sys_reg_desc cp15_regs[] = {
+ /*
+ * DC{C,I,CI}SW operations:
+ */
+ { Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw },
+ { Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw },
+ { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 0), pm_fake },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 1), pm_fake },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 2), pm_fake },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 3), pm_fake },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 5), pm_fake },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 6), pm_fake },
+ { Op1( 0), CRn( 9), CRm(12), Op2( 7), pm_fake },
+ { Op1( 0), CRn( 9), CRm(13), Op2( 0), pm_fake },
+ { Op1( 0), CRn( 9), CRm(13), Op2( 1), pm_fake },
+ { Op1( 0), CRn( 9), CRm(13), Op2( 2), pm_fake },
+ { Op1( 0), CRn( 9), CRm(14), Op2( 0), pm_fake },
+ { Op1( 0), CRn( 9), CRm(14), Op2( 1), pm_fake },
+ { Op1( 0), CRn( 9), CRm(14), Op2( 2), pm_fake },
+};
+
+/* Target specific emulation tables */
+static struct kvm_sys_reg_target_table *target_tables[KVM_ARM_NUM_TARGETS];
+
+void kvm_register_target_sys_reg_table(unsigned int target,
+ struct kvm_sys_reg_target_table *table)
+{
+ target_tables[target] = table;
+}
+
+/* Get specific register table for this target. */
+static const struct sys_reg_desc *get_target_table(unsigned target,
+ bool mode_is_64,
+ size_t *num)
+{
+ struct kvm_sys_reg_target_table *table;
+
+ table = target_tables[target];
+ if (mode_is_64) {
+ *num = table->table64.num;
+ return table->table64.table;
+ } else {
+ *num = table->table32.num;
+ return table->table32.table;
+ }
+}
+
+static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
+ const struct sys_reg_desc table[],
+ unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < num; i++) {
+ const struct sys_reg_desc *r = &table[i];
+
+ if (params->Op0 != r->Op0)
+ continue;
+ if (params->Op1 != r->Op1)
+ continue;
+ if (params->CRn != r->CRn)
+ continue;
+ if (params->CRm != r->CRm)
+ continue;
+ if (params->Op2 != r->Op2)
+ continue;
+
+ return r;
+ }
+ return NULL;
+}
+
+int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+int kvm_handle_cp14_access(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+static void emulate_cp15(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *params)
+{
+ size_t num;
+ const struct sys_reg_desc *table, *r;
+
+ table = get_target_table(vcpu->arch.target, false, &num);
+
+ /* Search target-specific then generic table. */
+ r = find_reg(params, table, num);
+ if (!r)
+ r = find_reg(params, cp15_regs, ARRAY_SIZE(cp15_regs));
+
+ if (likely(r)) {
+ /*
+ * Not having an accessor means that we have
+ * configured a trap that we don't know how to
+ * handle. This certainly qualifies as a gross bug
+ * that should be fixed right away.
+ */
+ BUG_ON(!r->access);
+
+ if (likely(r->access(vcpu, params, r))) {
+ /* Skip instruction, since it was emulated */
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+ return;
+ }
+ /* If access function fails, it should complain. */
+ }
+
+ kvm_err("Unsupported guest CP15 access at: %08lx\n", *vcpu_pc(vcpu));
+ print_sys_reg_instr(params);
+ kvm_inject_undefined(vcpu);
+}
+
+/**
+ * kvm_handle_cp15_64 -- handles a mrrc/mcrr trap on a guest CP15 access
+ * @vcpu: The VCPU pointer
+ * @run: The kvm_run struct
+ */
+int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ struct sys_reg_params params;
+ u32 hsr = kvm_vcpu_get_hsr(vcpu);
+ int Rt2 = (hsr >> 10) & 0xf;
+
+ params.CRm = (hsr >> 1) & 0xf;
+ params.Rt = (hsr >> 5) & 0xf;
+ params.is_write = ((hsr & 1) == 0);
+
+ params.Op0 = 0;
+ params.Op1 = (hsr >> 16) & 0xf;
+ params.Op2 = 0;
+ params.CRn = 0;
+
+ /*
+ * Massive hack here. Store Rt2 in the top 32bits so we only
+ * have one register to deal with. As we use the same trap
+ * backends between AArch32 and AArch64, we get away with it.
+ */
+ if (params.is_write) {
+ u64 val = *vcpu_reg(vcpu, params.Rt);
+ val &= 0xffffffff;
+ val |= *vcpu_reg(vcpu, Rt2) << 32;
+ *vcpu_reg(vcpu, params.Rt) = val;
+ }
+
+ emulate_cp15(vcpu, &params);
+
+ /* Do the opposite hack for the read side */
+ if (!params.is_write) {
+ u64 val = *vcpu_reg(vcpu, params.Rt);
+ val >>= 32;
+ *vcpu_reg(vcpu, Rt2) = val;
+ }
+
+ return 1;
+}
+
+/**
+ * kvm_handle_cp15_32 -- handles a mrc/mcr trap on a guest CP15 access
+ * @vcpu: The VCPU pointer
+ * @run: The kvm_run struct
+ */
+int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ struct sys_reg_params params;
+ u32 hsr = kvm_vcpu_get_hsr(vcpu);
+
+ params.CRm = (hsr >> 1) & 0xf;
+ params.Rt = (hsr >> 5) & 0xf;
+ params.is_write = ((hsr & 1) == 0);
+ params.CRn = (hsr >> 10) & 0xf;
+ params.Op0 = 0;
+ params.Op1 = (hsr >> 14) & 0x7;
+ params.Op2 = (hsr >> 17) & 0x7;
+
+ emulate_cp15(vcpu, &params);
+ return 1;
+}
+
+static int emulate_sys_reg(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *params)
+{
+ size_t num;
+ const struct sys_reg_desc *table, *r;
+
+ table = get_target_table(vcpu->arch.target, true, &num);
+
+ /* Search target-specific then generic table. */
+ r = find_reg(params, table, num);
+ if (!r)
+ r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+
+ if (likely(r)) {
+ /*
+ * Not having an accessor means that we have
+ * configured a trap that we don't know how to
+ * handle. This certainly qualifies as a gross bug
+ * that should be fixed right away.
+ */
+ BUG_ON(!r->access);
+
+ if (likely(r->access(vcpu, params, r))) {
+ /* Skip instruction, since it was emulated */
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
+ return 1;
+ }
+ /* If access function fails, it should complain. */
+ } else {
+ kvm_err("Unsupported guest sys_reg access at: %lx\n",
+ *vcpu_pc(vcpu));
+ print_sys_reg_instr(params);
+ }
+ kvm_inject_undefined(vcpu);
+ return 1;
+}
+
+static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *table, size_t num)
+{
+ unsigned long i;
+
+ for (i = 0; i < num; i++)
+ if (table[i].reset)
+ table[i].reset(vcpu, &table[i]);
+}
+
+/**
+ * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access
+ * @vcpu: The VCPU pointer
+ * @run: The kvm_run struct
+ */
+int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ struct sys_reg_params params;
+ unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+
+ params.Op0 = (esr >> 20) & 3;
+ params.Op1 = (esr >> 14) & 0x7;
+ params.CRn = (esr >> 10) & 0xf;
+ params.CRm = (esr >> 1) & 0xf;
+ params.Op2 = (esr >> 17) & 0x7;
+ params.Rt = (esr >> 5) & 0x1f;
+ params.is_write = !(esr & 1);
+
+ return emulate_sys_reg(vcpu, &params);
+}
+
+/******************************************************************************
+ * Userspace API
+ *****************************************************************************/
+
+static bool index_to_params(u64 id, struct sys_reg_params *params)
+{
+ switch (id & KVM_REG_SIZE_MASK) {
+ case KVM_REG_SIZE_U64:
+ /* Any unused index bits means it's not valid. */
+ if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK
+ | KVM_REG_ARM_COPROC_MASK
+ | KVM_REG_ARM64_SYSREG_OP0_MASK
+ | KVM_REG_ARM64_SYSREG_OP1_MASK
+ | KVM_REG_ARM64_SYSREG_CRN_MASK
+ | KVM_REG_ARM64_SYSREG_CRM_MASK
+ | KVM_REG_ARM64_SYSREG_OP2_MASK))
+ return false;
+ params->Op0 = ((id & KVM_REG_ARM64_SYSREG_OP0_MASK)
+ >> KVM_REG_ARM64_SYSREG_OP0_SHIFT);
+ params->Op1 = ((id & KVM_REG_ARM64_SYSREG_OP1_MASK)
+ >> KVM_REG_ARM64_SYSREG_OP1_SHIFT);
+ params->CRn = ((id & KVM_REG_ARM64_SYSREG_CRN_MASK)
+ >> KVM_REG_ARM64_SYSREG_CRN_SHIFT);
+ params->CRm = ((id & KVM_REG_ARM64_SYSREG_CRM_MASK)
+ >> KVM_REG_ARM64_SYSREG_CRM_SHIFT);
+ params->Op2 = ((id & KVM_REG_ARM64_SYSREG_OP2_MASK)
+ >> KVM_REG_ARM64_SYSREG_OP2_SHIFT);
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Decode an index value, and find the sys_reg_desc entry. */
+static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu,
+ u64 id)
+{
+ size_t num;
+ const struct sys_reg_desc *table, *r;
+ struct sys_reg_params params;
+
+ /* We only do sys_reg for now. */
+ if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG)
+ return NULL;
+
+ if (!index_to_params(id, &params))
+ return NULL;
+
+ table = get_target_table(vcpu->arch.target, true, &num);
+ r = find_reg(&params, table, num);
+ if (!r)
+ r = find_reg(&params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+
+ /* Not saved in the sys_reg array? */
+ if (r && !r->reg)
+ r = NULL;
+
+ return r;
+}
+
+/*
+ * These are the invariant sys_reg registers: we let the guest see the
+ * host versions of these, so they're part of the guest state.
+ *
+ * A future CPU may provide a mechanism to present different values to
+ * the guest, or a future kvm may trap them.
+ */
+
+#define FUNCTION_INVARIANT(reg) \
+ static void get_##reg(struct kvm_vcpu *v, \
+ const struct sys_reg_desc *r) \
+ { \
+ u64 val; \
+ \
+ asm volatile("mrs %0, " __stringify(reg) "\n" \
+ : "=r" (val)); \
+ ((struct sys_reg_desc *)r)->val = val; \
+ }
+
+FUNCTION_INVARIANT(midr_el1)
+FUNCTION_INVARIANT(ctr_el0)
+FUNCTION_INVARIANT(revidr_el1)
+FUNCTION_INVARIANT(id_pfr0_el1)
+FUNCTION_INVARIANT(id_pfr1_el1)
+FUNCTION_INVARIANT(id_dfr0_el1)
+FUNCTION_INVARIANT(id_afr0_el1)
+FUNCTION_INVARIANT(id_mmfr0_el1)
+FUNCTION_INVARIANT(id_mmfr1_el1)
+FUNCTION_INVARIANT(id_mmfr2_el1)
+FUNCTION_INVARIANT(id_mmfr3_el1)
+FUNCTION_INVARIANT(id_isar0_el1)
+FUNCTION_INVARIANT(id_isar1_el1)
+FUNCTION_INVARIANT(id_isar2_el1)
+FUNCTION_INVARIANT(id_isar3_el1)
+FUNCTION_INVARIANT(id_isar4_el1)
+FUNCTION_INVARIANT(id_isar5_el1)
+FUNCTION_INVARIANT(clidr_el1)
+FUNCTION_INVARIANT(aidr_el1)
+
+/* ->val is filled in by kvm_sys_reg_table_init() */
+static struct sys_reg_desc invariant_sys_regs[] = {
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0000), Op2(0b000),
+ NULL, get_midr_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0000), Op2(0b110),
+ NULL, get_revidr_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b000),
+ NULL, get_id_pfr0_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b001),
+ NULL, get_id_pfr1_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b010),
+ NULL, get_id_dfr0_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b011),
+ NULL, get_id_afr0_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b100),
+ NULL, get_id_mmfr0_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b101),
+ NULL, get_id_mmfr1_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b110),
+ NULL, get_id_mmfr2_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0001), Op2(0b111),
+ NULL, get_id_mmfr3_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b000),
+ NULL, get_id_isar0_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b001),
+ NULL, get_id_isar1_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b010),
+ NULL, get_id_isar2_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b011),
+ NULL, get_id_isar3_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b100),
+ NULL, get_id_isar4_el1 },
+ { Op0(0b11), Op1(0b000), CRn(0b0000), CRm(0b0010), Op2(0b101),
+ NULL, get_id_isar5_el1 },
+ { Op0(0b11), Op1(0b001), CRn(0b0000), CRm(0b0000), Op2(0b001),
+ NULL, get_clidr_el1 },
+ { Op0(0b11), Op1(0b001), CRn(0b0000), CRm(0b0000), Op2(0b111),
+ NULL, get_aidr_el1 },
+ { Op0(0b11), Op1(0b011), CRn(0b0000), CRm(0b0000), Op2(0b001),
+ NULL, get_ctr_el0 },
+};
+
+static int reg_from_user(void *val, const void __user *uaddr, u64 id)
+{
+ /* This Just Works because we are little endian. */
+ if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0)
+ return -EFAULT;
+ return 0;
+}
+
+static int reg_to_user(void __user *uaddr, const void *val, u64 id)
+{
+ /* This Just Works because we are little endian. */
+ if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0)
+ return -EFAULT;
+ return 0;
+}
+
+static int get_invariant_sys_reg(u64 id, void __user *uaddr)
+{
+ struct sys_reg_params params;
+ const struct sys_reg_desc *r;
+
+ if (!index_to_params(id, &params))
+ return -ENOENT;
+
+ r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+ if (!r)
+ return -ENOENT;
+
+ return reg_to_user(uaddr, &r->val, id);
+}
+
+static int set_invariant_sys_reg(u64 id, void __user *uaddr)
+{
+ struct sys_reg_params params;
+ const struct sys_reg_desc *r;
+ int err;
+ u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */
+
+ if (!index_to_params(id, &params))
+ return -ENOENT;
+ r = find_reg(&params, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs));
+ if (!r)
+ return -ENOENT;
+
+ err = reg_from_user(&val, uaddr, id);
+ if (err)
+ return err;
+
+ /* This is what we mean by invariant: you can't change it. */
+ if (r->val != val)
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool is_valid_cache(u32 val)
+{
+ u32 level, ctype;
+
+ if (val >= CSSELR_MAX)
+ return -ENOENT;
+
+ /* Bottom bit is Instruction or Data bit. Next 3 bits are level. */
+ level = (val >> 1);
+ ctype = (cache_levels >> (level * 3)) & 7;
+
+ switch (ctype) {
+ case 0: /* No cache */
+ return false;
+ case 1: /* Instruction cache only */
+ return (val & 1);
+ case 2: /* Data cache only */
+ case 4: /* Unified cache */
+ return !(val & 1);
+ case 3: /* Separate instruction and data caches */
+ return true;
+ default: /* Reserved: we can't know instruction or data. */
+ return false;
+ }
+}
+
+static int demux_c15_get(u64 id, void __user *uaddr)
+{
+ u32 val;
+ u32 __user *uval = uaddr;
+
+ /* Fail if we have unknown bits set. */
+ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+ | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+ return -ENOENT;
+
+ switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
+ case KVM_REG_ARM_DEMUX_ID_CCSIDR:
+ if (KVM_REG_SIZE(id) != 4)
+ return -ENOENT;
+ val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
+ >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
+ if (!is_valid_cache(val))
+ return -ENOENT;
+
+ return put_user(get_ccsidr(val), uval);
+ default:
+ return -ENOENT;
+ }
+}
+
+static int demux_c15_set(u64 id, void __user *uaddr)
+{
+ u32 val, newval;
+ u32 __user *uval = uaddr;
+
+ /* Fail if we have unknown bits set. */
+ if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK
+ | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1)))
+ return -ENOENT;
+
+ switch (id & KVM_REG_ARM_DEMUX_ID_MASK) {
+ case KVM_REG_ARM_DEMUX_ID_CCSIDR:
+ if (KVM_REG_SIZE(id) != 4)
+ return -ENOENT;
+ val = (id & KVM_REG_ARM_DEMUX_VAL_MASK)
+ >> KVM_REG_ARM_DEMUX_VAL_SHIFT;
+ if (!is_valid_cache(val))
+ return -ENOENT;
+
+ if (get_user(newval, uval))
+ return -EFAULT;
+
+ /* This is also invariant: you can't change it. */
+ if (newval != get_ccsidr(val))
+ return -EINVAL;
+ return 0;
+ default:
+ return -ENOENT;
+ }
+}
+
+int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ const struct sys_reg_desc *r;
+ void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+ return demux_c15_get(reg->id, uaddr);
+
+ if (KVM_REG_SIZE(reg->id) != sizeof(__u64))
+ return -ENOENT;
+
+ r = index_to_sys_reg_desc(vcpu, reg->id);
+ if (!r)
+ return get_invariant_sys_reg(reg->id, uaddr);
+
+ return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id);
+}
+
+int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
+{
+ const struct sys_reg_desc *r;
+ void __user *uaddr = (void __user *)(unsigned long)reg->addr;
+
+ if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX)
+ return demux_c15_set(reg->id, uaddr);
+
+ if (KVM_REG_SIZE(reg->id) != sizeof(__u64))
+ return -ENOENT;
+
+ r = index_to_sys_reg_desc(vcpu, reg->id);
+ if (!r)
+ return set_invariant_sys_reg(reg->id, uaddr);
+
+ return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id);
+}
+
+static unsigned int num_demux_regs(void)
+{
+ unsigned int i, count = 0;
+
+ for (i = 0; i < CSSELR_MAX; i++)
+ if (is_valid_cache(i))
+ count++;
+
+ return count;
+}
+
+static int write_demux_regids(u64 __user *uindices)
+{
+ u64 val = KVM_REG_ARM | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX;
+ unsigned int i;
+
+ val |= KVM_REG_ARM_DEMUX_ID_CCSIDR;
+ for (i = 0; i < CSSELR_MAX; i++) {
+ if (!is_valid_cache(i))
+ continue;
+ if (put_user(val | i, uindices))
+ return -EFAULT;
+ uindices++;
+ }
+ return 0;
+}
+
+static u64 sys_reg_to_index(const struct sys_reg_desc *reg)
+{
+ return (KVM_REG_ARM64 | KVM_REG_SIZE_U64 |
+ KVM_REG_ARM64_SYSREG |
+ (reg->Op0 << KVM_REG_ARM64_SYSREG_OP0_SHIFT) |
+ (reg->Op1 << KVM_REG_ARM64_SYSREG_OP1_SHIFT) |
+ (reg->CRn << KVM_REG_ARM64_SYSREG_CRN_SHIFT) |
+ (reg->CRm << KVM_REG_ARM64_SYSREG_CRM_SHIFT) |
+ (reg->Op2 << KVM_REG_ARM64_SYSREG_OP2_SHIFT));
+}
+
+static bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind)
+{
+ if (!*uind)
+ return true;
+
+ if (put_user(sys_reg_to_index(reg), *uind))
+ return false;
+
+ (*uind)++;
+ return true;
+}
+
+/* Assumed ordered tables, see kvm_sys_reg_table_init. */
+static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind)
+{
+ const struct sys_reg_desc *i1, *i2, *end1, *end2;
+ unsigned int total = 0;
+ size_t num;
+
+ /* We check for duplicates here, to allow arch-specific overrides. */
+ i1 = get_target_table(vcpu->arch.target, true, &num);
+ end1 = i1 + num;
+ i2 = sys_reg_descs;
+ end2 = sys_reg_descs + ARRAY_SIZE(sys_reg_descs);
+
+ BUG_ON(i1 == end1 || i2 == end2);
+
+ /* Walk carefully, as both tables may refer to the same register. */
+ while (i1 || i2) {
+ int cmp = cmp_sys_reg(i1, i2);
+ /* target-specific overrides generic entry. */
+ if (cmp <= 0) {
+ /* Ignore registers we trap but don't save. */
+ if (i1->reg) {
+ if (!copy_reg_to_user(i1, &uind))
+ return -EFAULT;
+ total++;
+ }
+ } else {
+ /* Ignore registers we trap but don't save. */
+ if (i2->reg) {
+ if (!copy_reg_to_user(i2, &uind))
+ return -EFAULT;
+ total++;
+ }
+ }
+
+ if (cmp <= 0 && ++i1 == end1)
+ i1 = NULL;
+ if (cmp >= 0 && ++i2 == end2)
+ i2 = NULL;
+ }
+ return total;
+}
+
+unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu)
+{
+ return ARRAY_SIZE(invariant_sys_regs)
+ + num_demux_regs()
+ + walk_sys_regs(vcpu, (u64 __user *)NULL);
+}
+
+int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
+{
+ unsigned int i;
+ int err;
+
+ /* Then give them all the invariant registers' indices. */
+ for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) {
+ if (put_user(sys_reg_to_index(&invariant_sys_regs[i]), uindices))
+ return -EFAULT;
+ uindices++;
+ }
+
+ err = walk_sys_regs(vcpu, uindices);
+ if (err < 0)
+ return err;
+ uindices += err;
+
+ return write_demux_regids(uindices);
+}
+
+void kvm_sys_reg_table_init(void)
+{
+ unsigned int i;
+ struct sys_reg_desc clidr;
+
+ /* Make sure tables are unique and in order. */
+ for (i = 1; i < ARRAY_SIZE(sys_reg_descs); i++)
+ BUG_ON(cmp_sys_reg(&sys_reg_descs[i-1], &sys_reg_descs[i]) >= 0);
+
+ /* We abuse the reset function to overwrite the table itself. */
+ for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++)
+ invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]);
+
+ /*
+ * CLIDR format is awkward, so clean it up. See ARM B4.1.20:
+ *
+ * If software reads the Cache Type fields from Ctype1
+ * upwards, once it has seen a value of 0b000, no caches
+ * exist at further-out levels of the hierarchy. So, for
+ * example, if Ctype3 is the first Cache Type field with a
+ * value of 0b000, the values of Ctype4 to Ctype7 must be
+ * ignored.
+ */
+ get_clidr_el1(NULL, &clidr); /* Ugly... */
+ cache_levels = clidr.val;
+ for (i = 0; i < 7; i++)
+ if (((cache_levels >> (i*3)) & 7) == 0)
+ break;
+ /* Clear all higher bits. */
+ cache_levels &= (1 << (i*3))-1;
+}
+
+/**
+ * kvm_reset_sys_regs - sets system registers to reset value
+ * @vcpu: The VCPU pointer
+ *
+ * This function finds the right table above and sets the registers on the
+ * virtual CPU struct to their architecturally defined reset values.
+ */
+void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
+{
+ size_t num;
+ const struct sys_reg_desc *table;
+
+ /* Catch someone adding a register without putting in reset entry. */
+ memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));
+
+ /* Generic chip reset first (so target could override). */
+ reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+
+ table = get_target_table(vcpu->arch.target, true, &num);
+ reset_sys_reg_descs(vcpu, table, num);
+
+ for (num = 1; num < NR_SYS_REGS; num++)
+ if (vcpu_sys_reg(vcpu, num) == 0x4242424242424242)
+ panic("Didn't reset vcpu_sys_reg(%zi)", num);
+}
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
new file mode 100644
index 000000000000..d50d3722998e
--- /dev/null
+++ b/arch/arm64/kvm/sys_regs.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Derived from arch/arm/kvm/coproc.h
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
+#define __ARM64_KVM_SYS_REGS_LOCAL_H__
+
+struct sys_reg_params {
+ u8 Op0;
+ u8 Op1;
+ u8 CRn;
+ u8 CRm;
+ u8 Op2;
+ u8 Rt;
+ bool is_write;
+};
+
+struct sys_reg_desc {
+ /* MRS/MSR instruction which accesses it. */
+ u8 Op0;
+ u8 Op1;
+ u8 CRn;
+ u8 CRm;
+ u8 Op2;
+
+ /* Trapped access from guest, if non-NULL. */
+ bool (*access)(struct kvm_vcpu *,
+ const struct sys_reg_params *,
+ const struct sys_reg_desc *);
+
+ /* Initialization for vcpu. */
+ void (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *);
+
+ /* Index into sys_reg[], or 0 if we don't need to save it. */
+ int reg;
+
+ /* Value (usually reset value) */
+ u64 val;
+};
+
+static inline void print_sys_reg_instr(const struct sys_reg_params *p)
+{
+ /* Look, we even formatted it for you to paste into the table! */
+ kvm_pr_unimpl(" { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
+ p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
+}
+
+static inline bool ignore_write(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p)
+{
+ return true;
+}
+
+static inline bool read_zero(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p)
+{
+ *vcpu_reg(vcpu, p->Rt) = 0;
+ return true;
+}
+
+static inline bool write_to_read_only(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *params)
+{
+ kvm_debug("sys_reg write to read-only register at: %lx\n",
+ *vcpu_pc(vcpu));
+ print_sys_reg_instr(params);
+ return false;
+}
+
+static inline bool read_from_write_only(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *params)
+{
+ kvm_debug("sys_reg read to write-only register at: %lx\n",
+ *vcpu_pc(vcpu));
+ print_sys_reg_instr(params);
+ return false;
+}
+
+/* Reset functions */
+static inline void reset_unknown(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *r)
+{
+ BUG_ON(!r->reg);
+ BUG_ON(r->reg >= NR_SYS_REGS);
+ vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
+}
+
+static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ BUG_ON(!r->reg);
+ BUG_ON(r->reg >= NR_SYS_REGS);
+ vcpu_sys_reg(vcpu, r->reg) = r->val;
+}
+
+static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
+ const struct sys_reg_desc *i2)
+{
+ BUG_ON(i1 == i2);
+ if (!i1)
+ return 1;
+ else if (!i2)
+ return -1;
+ if (i1->Op0 != i2->Op0)
+ return i1->Op0 - i2->Op0;
+ if (i1->Op1 != i2->Op1)
+ return i1->Op1 - i2->Op1;
+ if (i1->CRn != i2->CRn)
+ return i1->CRn - i2->CRn;
+ if (i1->CRm != i2->CRm)
+ return i1->CRm - i2->CRm;
+ return i1->Op2 - i2->Op2;
+}
+
+
+#define Op0(_x) .Op0 = _x
+#define Op1(_x) .Op1 = _x
+#define CRn(_x) .CRn = _x
+#define CRm(_x) .CRm = _x
+#define Op2(_x) .Op2 = _x
+
+#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
new file mode 100644
index 000000000000..4268ab9356b1
--- /dev/null
+++ b/arch/arm64/kvm/sys_regs_generic_v8.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * Based on arch/arm/kvm/coproc_a15.c:
+ * Copyright (C) 2012 - Virtual Open Systems and Columbia University
+ * Authors: Rusty Russell <rusty@rustcorp.au>
+ * Christoffer Dall <c.dall@virtualopensystems.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kvm_host.h>
+#include <asm/cputype.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_host.h>
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_coproc.h>
+#include <linux/init.h>
+
+#include "sys_regs.h"
+
+static bool access_actlr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_params *p,
+ const struct sys_reg_desc *r)
+{
+ if (p->is_write)
+ return ignore_write(vcpu, p);
+
+ *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1);
+ return true;
+}
+
+static void reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
+{
+ u64 actlr;
+
+ asm volatile("mrs %0, actlr_el1\n" : "=r" (actlr));
+ vcpu_sys_reg(vcpu, ACTLR_EL1) = actlr;
+}
+
+/*
+ * Implementation specific sys-reg registers.
+ * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
+ */
+static const struct sys_reg_desc genericv8_sys_regs[] = {
+ /* ACTLR_EL1 */
+ { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b001),
+ access_actlr, reset_actlr, ACTLR_EL1 },
+};
+
+static const struct sys_reg_desc genericv8_cp15_regs[] = {
+ /* ACTLR */
+ { Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b001),
+ access_actlr },
+};
+
+static struct kvm_sys_reg_target_table genericv8_target_table = {
+ .table64 = {
+ .table = genericv8_sys_regs,
+ .num = ARRAY_SIZE(genericv8_sys_regs),
+ },
+ .table32 = {
+ .table = genericv8_cp15_regs,
+ .num = ARRAY_SIZE(genericv8_cp15_regs),
+ },
+};
+
+static int __init sys_reg_genericv8_init(void)
+{
+ unsigned int i;
+
+ for (i = 1; i < ARRAY_SIZE(genericv8_sys_regs); i++)
+ BUG_ON(cmp_sys_reg(&genericv8_sys_regs[i-1],
+ &genericv8_sys_regs[i]) >= 0);
+
+ kvm_register_target_sys_reg_table(KVM_ARM_TARGET_AEM_V8,
+ &genericv8_target_table);
+ kvm_register_target_sys_reg_table(KVM_ARM_TARGET_FOUNDATION_V8,
+ &genericv8_target_table);
+ kvm_register_target_sys_reg_table(KVM_ARM_TARGET_CORTEX_A57,
+ &genericv8_target_table);
+ return 0;
+}
+late_initcall(sys_reg_genericv8_init);
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 3140a2abcdc2..b51d36401d83 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -2,3 +2,4 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
cache.o copypage.o flush.o \
ioremap.o mmap.o pgd.o mmu.o \
context.o tlb.o proc.o
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 1426468b77f3..0ecac8980aae 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -365,17 +365,6 @@ static int __kprobes do_translation_fault(unsigned long addr,
}
/*
- * Some section permission faults need to be handled gracefully. They can
- * happen due to a __{get,put}_user during an oops.
- */
-static int do_sect_fault(unsigned long addr, unsigned int esr,
- struct pt_regs *regs)
-{
- do_bad_area(addr, esr, regs);
- return 0;
-}
-
-/*
* This abort handler always returns "fault".
*/
static int do_bad(unsigned long addr, unsigned int esr, struct pt_regs *regs)
@@ -398,12 +387,12 @@ static struct fault_info {
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
{ do_bad, SIGBUS, 0, "reserved access flag fault" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
{ do_bad, SIGBUS, 0, "reserved permission fault" },
- { do_bad, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
- { do_sect_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
{ do_bad, SIGBUS, 0, "synchronous external abort" },
{ do_bad, SIGBUS, 0, "asynchronous external abort" },
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
index 88611c3a421a..e4193e3adc7f 100644
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -70,23 +70,16 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
#endif
}
-void __flush_dcache_page(struct page *page)
-{
- __flush_dcache_area(page_address(page), PAGE_SIZE);
-}
-
void __sync_icache_dcache(pte_t pte, unsigned long addr)
{
- unsigned long pfn;
- struct page *page;
+ struct page *page = pte_page(pte);
- pfn = pte_pfn(pte);
- if (!pfn_valid(pfn))
+ /* no flushing needed for anonymous pages */
+ if (!page_mapping(page))
return;
- page = pfn_to_page(pfn);
if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
- __flush_dcache_page(page);
+ __flush_dcache_area(page_address(page), PAGE_SIZE);
__flush_icache_all();
} else if (icache_is_aivivt()) {
__flush_icache_all();
@@ -94,28 +87,14 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
}
/*
- * Ensure cache coherency between kernel mapping and userspace mapping of this
- * page.
+ * This function is called when a page has been modified by the kernel. Mark
+ * it as dirty for later flushing when mapped in user space (if executable,
+ * see __sync_icache_dcache).
*/
void flush_dcache_page(struct page *page)
{
- struct address_space *mapping;
-
- /*
- * The zero page is never written to, so never has any dirty cache
- * lines, and therefore never needs to be flushed.
- */
- if (page == ZERO_PAGE(0))
- return;
-
- mapping = page_mapping(page);
- if (mapping && mapping_mapped(mapping)) {
- __flush_dcache_page(page);
- __flush_icache_all();
- set_bit(PG_dcache_clean, &page->flags);
- } else {
+ if (test_bit(PG_dcache_clean, &page->flags))
clear_bit(PG_dcache_clean, &page->flags);
- }
}
EXPORT_SYMBOL(flush_dcache_page);
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
new file mode 100644
index 000000000000..2fc8258bab2d
--- /dev/null
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -0,0 +1,70 @@
+/*
+ * arch/arm64/mm/hugetlbpage.c
+ *
+ * Copyright (C) 2013 Linaro Ltd.
+ *
+ * Based on arch/x86/mm/hugetlbpage.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/sysctl.h>
+#include <asm/mman.h>
+#include <asm/tlb.h>
+#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
+
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+ int write)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+int pmd_huge(pmd_t pmd)
+{
+ return !(pmd_val(pmd) & PMD_TABLE_BIT);
+}
+
+int pud_huge(pud_t pud)
+{
+ return !(pud_val(pud) & PUD_TABLE_BIT);
+}
+
+static __init int setup_hugepagesz(char *opt)
+{
+ unsigned long ps = memparse(opt, &opt);
+ if (ps == PMD_SIZE) {
+ hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
+ } else if (ps == PUD_SIZE) {
+ hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+ } else {
+ pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
+ return 0;
+ }
+ return 1;
+}
+__setup("hugepagesz=", setup_hugepagesz);
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index f497ca77925a..67e8d7ce3fe7 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -197,14 +197,6 @@ void __init bootmem_init(void)
max_pfn = max_low_pfn = max;
}
-/*
- * Poison init memory with an undefined instruction (0x0).
- */
-static inline void poison_init_mem(void *s, size_t count)
-{
- memset(s, 0, count);
-}
-
#ifndef CONFIG_SPARSEMEM_VMEMMAP
static inline void free_memmap(unsigned long start_pfn, unsigned long end_pfn)
{
@@ -280,59 +272,17 @@ static void __init free_unused_memmap(void)
*/
void __init mem_init(void)
{
- unsigned long reserved_pages, free_pages;
- struct memblock_region *reg;
-
arm64_swiotlb_init();
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
#ifndef CONFIG_SPARSEMEM_VMEMMAP
- /* this will put all unused low memory onto the freelists */
free_unused_memmap();
#endif
+ /* this will put all unused low memory onto the freelists */
+ free_all_bootmem();
- totalram_pages += free_all_bootmem();
-
- reserved_pages = free_pages = 0;
-
- for_each_memblock(memory, reg) {
- unsigned int pfn1, pfn2;
- struct page *page, *end;
-
- pfn1 = __phys_to_pfn(reg->base);
- pfn2 = pfn1 + __phys_to_pfn(reg->size);
-
- page = pfn_to_page(pfn1);
- end = pfn_to_page(pfn2 - 1) + 1;
-
- do {
- if (PageReserved(page))
- reserved_pages++;
- else if (!page_count(page))
- free_pages++;
- page++;
- } while (page < end);
- }
-
- /*
- * Since our memory may not be contiguous, calculate the real number
- * of pages we have in this system.
- */
- pr_info("Memory:");
- num_physpages = 0;
- for_each_memblock(memory, reg) {
- unsigned long pages = memblock_region_memory_end_pfn(reg) -
- memblock_region_memory_base_pfn(reg);
- num_physpages += pages;
- printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
- }
- printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-
- pr_notice("Memory: %luk/%luk available, %luk reserved\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- free_pages << (PAGE_SHIFT-10),
- reserved_pages << (PAGE_SHIFT-10));
+ mem_init_print_info(NULL);
#define MLK(b, t) b, t, ((t) - (b)) >> 10
#define MLM(b, t) b, t, ((t) - (b)) >> 20
@@ -374,7 +324,7 @@ void __init mem_init(void)
BUILD_BUG_ON(TASK_SIZE_64 > MODULES_VADDR);
BUG_ON(TASK_SIZE_64 > MODULES_VADDR);
- if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+ if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
extern int sysctl_overcommit_memory;
/*
* On a machine this small we won't get anywhere without
@@ -386,7 +336,6 @@ void __init mem_init(void)
void free_initmem(void)
{
- poison_init_mem(__init_begin, __init_end - __init_begin);
free_initmem_default(0);
}
@@ -396,10 +345,8 @@ static int keep_initrd;
void free_initrd_mem(unsigned long start, unsigned long end)
{
- if (!keep_initrd) {
- poison_init_mem((void *)start, PAGE_ALIGN(end) - start);
- free_reserved_area(start, end, 0, "initrd");
- }
+ if (!keep_initrd)
+ free_reserved_area((void *)start, (void *)end, 0, "initrd");
}
static int __init keepinitrd_setup(char *__unused)
diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h
index 916701e6d040..d519f4f50c8c 100644
--- a/arch/arm64/mm/mm.h
+++ b/arch/arm64/mm/mm.h
@@ -1,3 +1,2 @@
-extern void __flush_dcache_page(struct page *page);
extern void __init bootmem_init(void);
extern void __init arm64_swiotlb_init(void);
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 7c7be7855638..8ed6cb1a900f 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -90,11 +90,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base();
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
EXPORT_SYMBOL_GPL(arch_pick_mmap_layout);
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index eeecc9c8ed68..a8d1059b91b2 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -297,6 +297,16 @@ static void __init map_mem(void)
{
struct memblock_region *reg;
+ /*
+ * Temporarily limit the memblock range. We need to do this as
+ * create_mapping requires puds, pmds and ptes to be allocated from
+ * memory addressable from the initial direct kernel mapping.
+ *
+ * The initial direct kernel mapping, located at swapper_pg_dir,
+ * gives us PGDIR_SIZE memory starting from PHYS_OFFSET (aligned).
+ */
+ memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
+
/* map all the memory banks */
for_each_memblock(memory, reg) {
phys_addr_t start = reg->base;
@@ -307,6 +317,9 @@ static void __init map_mem(void)
create_mapping(start, __phys_to_virt(start), end - start);
}
+
+ /* Limit no longer required. */
+ memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
}
/*
@@ -317,12 +330,6 @@ void __init paging_init(void)
{
void *zero_page;
- /*
- * Maximum PGDIR_SIZE addressable via the initial direct kernel
- * mapping in swapper_pg_dir.
- */
- memblock_set_current_limit((PHYS_OFFSET & PGDIR_MASK) + PGDIR_SIZE);
-
init_mem_pgprot();
map_mem();
@@ -339,7 +346,6 @@ void __init paging_init(void)
bootmem_init();
empty_zero_page = virt_to_page(zero_page);
- __flush_dcache_page(empty_zero_page);
/*
* TTBR0 is only used for the identity mapping at this stage. Make it
diff --git a/arch/arm64/xen/Makefile b/arch/arm64/xen/Makefile
new file mode 100644
index 000000000000..be240404ba96
--- /dev/null
+++ b/arch/arm64/xen/Makefile
@@ -0,0 +1,2 @@
+xen-arm-y += $(addprefix ../../arm/xen/, enlighten.o grant-table.o)
+obj-y := xen-arm.o hypercall.o
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
new file mode 100644
index 000000000000..531342ec4bcf
--- /dev/null
+++ b/arch/arm64/xen/hypercall.S
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * hypercall.S
+ *
+ * Xen hypercall wrappers
+ *
+ * Stefano Stabellini <stefano.stabellini@eu.citrix.com>, Citrix, 2012
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 Xen hypercall calling convention is very similar to the procedure
+ * call standard for the ARM 64-bit architecture: the first parameter is
+ * passed in x0, the second in x1, the third in x2, the fourth in x3 and
+ * the fifth in x4.
+ *
+ * The hypercall number is passed in x16.
+ *
+ * The return value is in x0.
+ *
+ * The hvc ISS is required to be 0xEA1, that is the Xen specific ARM
+ * hypercall tag.
+ *
+ * Parameter structs passed to hypercalls are laid out according to
+ * the ARM 64-bit EABI standard.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <xen/interface/xen.h>
+
+
+#define XEN_IMM 0xEA1
+
+#define HYPERCALL_SIMPLE(hypercall) \
+ENTRY(HYPERVISOR_##hypercall) \
+ mov x16, #__HYPERVISOR_##hypercall; \
+ hvc XEN_IMM; \
+ ret; \
+ENDPROC(HYPERVISOR_##hypercall)
+
+#define HYPERCALL0 HYPERCALL_SIMPLE
+#define HYPERCALL1 HYPERCALL_SIMPLE
+#define HYPERCALL2 HYPERCALL_SIMPLE
+#define HYPERCALL3 HYPERCALL_SIMPLE
+#define HYPERCALL4 HYPERCALL_SIMPLE
+#define HYPERCALL5 HYPERCALL_SIMPLE
+
+ .text
+
+HYPERCALL2(xen_version);
+HYPERCALL3(console_io);
+HYPERCALL3(grant_table_op);
+HYPERCALL2(sched_op);
+HYPERCALL2(event_channel_op);
+HYPERCALL2(hvm_op);
+HYPERCALL2(memory_op);
+HYPERCALL2(physdev_op);
+HYPERCALL3(vcpu_op);
+HYPERCALL1(tmem_op);
+
+ENTRY(privcmd_call)
+ mov x16, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ mov x3, x4
+ mov x4, x5
+ hvc XEN_IMM
+ ret
+ENDPROC(privcmd_call);
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 37401f535126..79b61798ebf8 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -74,4 +74,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* __ASM_AVR32_SOCKET_H */
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index b4247f478065..209ae5ad3495 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -555,7 +555,7 @@ void __init setup_arch (char **cmdline_p)
{
struct clk *cpu_clk;
- init_mm.start_code = (unsigned long)_text;
+ 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)_end;
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index 9cd2bd91d64a..a4589176bed5 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -23,7 +23,7 @@ SECTIONS
{
. = CONFIG_ENTRY_ADDRESS;
.init : AT(ADDR(.init) - LOAD_OFFSET) {
- _stext = .;
+ _text = .;
__init_begin = .;
_sinittext = .;
*(.text.reset)
@@ -46,7 +46,7 @@ SECTIONS
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_evba = .;
- _text = .;
+ _stext = .;
*(.ex.text)
*(.irq.text)
KPROBES_TEXT
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 7c2f6685bf43..7f8759a8a92a 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -1060,7 +1060,9 @@ struct platform_device *__init at32_add_device_usart(unsigned int id)
void __init at32_setup_serial_console(unsigned int usart_id)
{
+#ifdef CONFIG_SERIAL_ATMEL
atmel_default_console_device = at32_usarts[usart_id];
+#endif
}
/* --------------------------------------------------------------------
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index e66e8406f992..def5391d927a 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -100,60 +100,26 @@ void __init paging_init(void)
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
- int nid, i;
+ pg_data_t *pgdat;
- reservedpages = 0;
high_memory = NULL;
+ for_each_online_pgdat(pgdat)
+ high_memory = max_t(void *, high_memory,
+ __va(pgdat_end_pfn(pgdat) << PAGE_SHIFT));
- /* this will put all low memory onto the freelists */
- for_each_online_node(nid) {
- pg_data_t *pgdat = NODE_DATA(nid);
- unsigned long node_pages = 0;
- void *node_high_memory;
-
- num_physpages += pgdat->node_present_pages;
-
- if (pgdat->node_spanned_pages != 0)
- node_pages = free_all_bootmem_node(pgdat);
-
- totalram_pages += node_pages;
-
- for (i = 0; i < node_pages; i++)
- if (PageReserved(pgdat->node_mem_map + i))
- reservedpages++;
-
- node_high_memory = (void *)((pgdat->node_start_pfn
- + pgdat->node_spanned_pages)
- << PAGE_SHIFT);
- if (node_high_memory > high_memory)
- high_memory = node_high_memory;
- }
-
- max_mapnr = MAP_NR(high_memory);
-
- codesize = (unsigned long)_etext - (unsigned long)_text;
- datasize = (unsigned long)_edata - (unsigned long)_data;
- initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
-
- printk ("Memory: %luk/%luk available (%dk kernel code, "
- "%dk reserved, %dk data, %dk init)\n",
- nr_free_pages() << (PAGE_SHIFT - 10),
- totalram_pages << (PAGE_SHIFT - 10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT - 10),
- datasize >> 10,
- initsize >> 10);
+ set_max_mapnr(MAP_NR(high_memory));
+ free_all_bootmem();
+ mem_init_print_info(NULL);
}
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index b573827d0416..3b6abc54b015 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -41,6 +41,7 @@ config BLACKFIN
select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
+ select HAVE_DEBUG_STACKOVERFLOW
config GENERIC_CSUM
def_bool y
@@ -282,7 +283,7 @@ config BF_REV_0_0
config BF_REV_0_1
bool "0.1"
- depends on (BF51x || BF52x || (BF54x && !BF54xM))
+ depends on (BF51x || BF52x || (BF54x && !BF54xM) || BF60x)
config BF_REV_0_2
bool "0.2"
diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug
index 79594694ee90..f3337ee03621 100644
--- a/arch/blackfin/Kconfig.debug
+++ b/arch/blackfin/Kconfig.debug
@@ -2,13 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config DEBUG_VERBOSE
bool "Verbose fault messages"
default y
diff --git a/arch/blackfin/include/asm/bfin6xx_spi.h b/arch/blackfin/include/asm/bfin_spi3.h
index 89370b653dcd..0957e65a54be 100644
--- a/arch/blackfin/include/asm/bfin6xx_spi.h
+++ b/arch/blackfin/include/asm/bfin_spi3.h
@@ -240,7 +240,7 @@ struct bfin_spi_regs {
#define MAX_CTRL_CS 8 /* cs in spi controller */
/* device.platform_data for SSP controller devices */
-struct bfin6xx_spi_master {
+struct bfin_spi3_master {
u16 num_chipselect;
u16 pin_req[7];
};
@@ -248,7 +248,7 @@ struct bfin6xx_spi_master {
/* spi_board_info.controller_data for SPI slave devices,
* copied to spi_device.platform_data ... mostly for dma tuning
*/
-struct bfin6xx_spi_chip {
+struct bfin_spi3_chip {
u32 control;
u16 cs_chg_udelay; /* Some devices require 16-bit delays */
u32 tx_dummy_val; /* tx value for rx only transfer */
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index b882ce22c347..fa53faeeb0e9 100644
--- a/arch/blackfin/kernel/kgdb.c
+++ b/arch/blackfin/kernel/kgdb.c
@@ -9,6 +9,7 @@
#include <linux/ptrace.h> /* for linux pt_regs struct */
#include <linux/kgdb.h>
#include <linux/uaccess.h>
+#include <asm/irq_regs.h>
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
diff --git a/arch/blackfin/mach-bf527/boards/ad7160eval.c b/arch/blackfin/mach-bf527/boards/ad7160eval.c
index d58f50e5aa4b..1e7be62fccb6 100644
--- a/arch/blackfin/mach-bf527/boards/ad7160eval.c
+++ b/arch/blackfin/mach-bf527/boards/ad7160eval.c
@@ -283,14 +283,6 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
-};
-#endif
-
static struct spi_board_info bfin_spi_board_info[] __initdata = {
#if defined(CONFIG_MTD_M25P80) \
|| defined(CONFIG_MTD_M25P80_MODULE)
@@ -800,10 +792,6 @@ static struct platform_device *stamp_devices[] __initdata = {
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
&bfin_i2s,
#endif
-
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm,
-#endif
};
static int __init ad7160eval_init(void)
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 29f16e5c37b9..d0a0c5e527cd 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -493,8 +493,7 @@ static const struct ad7879_platform_data bfin_ad7879_ts_info = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
- defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
static const u16 bfin_snd_pin[][7] = {
{P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
@@ -549,13 +548,6 @@ static struct platform_device bfin_i2s_pcm = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
- .name = "bfin-tdm-pcm-audio",
- .id = -1,
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
static struct platform_device bfin_ac97_pcm = {
.name = "bfin-ac97-pcm-audio",
@@ -575,22 +567,10 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
- .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
- .dev = {
- .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
- },
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
|| defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
static const char * const ad1836_link[] = {
- "bfin-tdm.0",
+ "bfin-i2s.0",
"spi0.4",
};
static struct platform_device bfin_ad1836_machine = {
@@ -1269,10 +1249,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_i2s_pcm,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm_pcm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97_pcm,
#endif
@@ -1281,10 +1257,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AD1836) || \
defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
&bfin_ad1836_machine,
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index 07811c209b9d..90fb0d14b147 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -450,14 +450,6 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
static struct platform_device bfin_ac97 = {
.name = "bfin-ac97",
@@ -516,10 +508,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97,
#endif
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index 6fca8698bf3b..4a8c2e3fd7e5 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -542,8 +542,7 @@ static struct platform_device bfin_dpmc = {
};
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
- defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) \
- || defined(CONFIG_SND_BF5XX_AC97) || \
+ defined(CONFIG_SND_BF5XX_AC97) || \
defined(CONFIG_SND_BF5XX_AC97_MODULE)
#include <asm/bfin_sport.h>
@@ -603,13 +602,6 @@ static struct platform_device bfin_i2s_pcm = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
- .name = "bfin-tdm-pcm-audio",
- .id = -1,
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
static struct platform_device bfin_ac97_pcm = {
.name = "bfin-ac97-pcm-audio",
@@ -620,7 +612,7 @@ static struct platform_device bfin_ac97_pcm = {
#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
|| defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
static const char * const ad1836_link[] = {
- "bfin-tdm.0",
+ "bfin-i2s.0",
"spi0.4",
};
static struct platform_device bfin_ad1836_machine = {
@@ -675,20 +667,6 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
- defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- .num_resources =
- ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
- .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
- .dev = {
- .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
- },
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
static struct platform_device bfin_ac97 = {
@@ -761,10 +739,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_i2s_pcm,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm_pcm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97_pcm,
#endif
@@ -792,11 +766,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || \
- defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
- &bfin_tdm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AC97) || \
defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
&bfin_ac97,
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 6a3a14bcd3a1..44fd1d4682ac 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -2570,7 +2570,6 @@ static struct platform_device bfin_dpmc = {
};
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
- defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
#define SPORT_REQ(x) \
@@ -2628,13 +2627,6 @@ static struct platform_device bfin_i2s_pcm = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
- .name = "bfin-tdm-pcm-audio",
- .id = -1,
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
static struct platform_device bfin_ac97_pcm = {
.name = "bfin-ac97-pcm-audio",
@@ -2645,7 +2637,7 @@ static struct platform_device bfin_ac97_pcm = {
#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
|| defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
static const char * const ad1836_link[] = {
- "bfin-tdm.0",
+ "bfin-i2s.0",
"spi0.4",
};
static struct platform_device bfin_ad1836_machine = {
@@ -2699,18 +2691,6 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
- .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
- .dev = {
- .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
- },
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
static struct platform_device bfin_ac97 = {
.name = "bfin-ac97",
@@ -2935,10 +2915,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_i2s_pcm,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm_pcm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97_pcm,
#endif
@@ -2961,10 +2937,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
- &bfin_tdm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
&bfin_ac97,
#endif
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index c4d07f040947..372eb54944ef 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -1393,7 +1393,6 @@ static struct platform_device bfin_dpmc = {
};
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
- defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
#define SPORT_REQ(x) \
@@ -1461,13 +1460,6 @@ static struct platform_device bfin_i2s_pcm = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm_pcm = {
- .name = "bfin-tdm-pcm-audio",
- .id = -1,
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
static struct platform_device bfin_ac97_pcm = {
.name = "bfin-ac97-pcm-audio",
@@ -1501,18 +1493,6 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
- .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
- .dev = {
- .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
- },
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
static struct platform_device bfin_ac97 = {
.name = "bfin-ac97",
@@ -1646,9 +1626,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
&bfin_i2s_pcm,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm_pcm,
-#endif
+
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97_pcm,
#endif
@@ -1661,10 +1639,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97,
#endif
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index 551f866172cf..92938e79b9e3 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -523,14 +523,6 @@ static struct platform_device bfin_i2s = {
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
-static struct platform_device bfin_tdm = {
- .name = "bfin-tdm",
- .id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
-};
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
static struct platform_device bfin_ac97 = {
.name = "bfin-ac97",
@@ -542,7 +534,7 @@ static struct platform_device bfin_ac97 = {
#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
|| defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
static const char * const ad1836_link[] = {
- "bfin-tdm.0",
+ "bfin-i2s.0",
"spi0.4",
};
static struct platform_device bfin_ad1836_machine = {
@@ -611,10 +603,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
- &bfin_tdm,
-#endif
-
#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
&bfin_ac97,
#endif
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index ab1c617b9cfc..c77a23bc9de3 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -69,7 +69,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
SSYNC();
/* We are done with local CPU inits, unblock the boot CPU. */
- set_cpu_online(cpu, true);
spin_lock(&boot_lock);
spin_unlock(&boot_lock);
}
@@ -91,7 +90,9 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
SSYNC();
}
- timeout = jiffies + 1 * HZ;
+ timeout = jiffies + HZ;
+ /* release the lock and let coreb run */
+ spin_unlock(&boot_lock);
while (time_before(jiffies, timeout)) {
if (cpu_online(cpu))
break;
@@ -100,8 +101,6 @@ int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle
}
if (cpu_online(cpu)) {
- /* release the lock and let coreb run */
- spin_unlock(&boot_lock);
return 0;
} else
panic("CPU%u: processor failed to boot\n", cpu);
diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c
index 97d701639585..0bc47231540b 100644
--- a/arch/blackfin/mach-bf609/boards/ezkit.c
+++ b/arch/blackfin/mach-bf609/boards/ezkit.c
@@ -17,7 +17,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/usb/musb.h>
-#include <asm/bfin6xx_spi.h>
+#include <asm/bfin_spi3.h>
#include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/nand.h>
@@ -108,7 +108,6 @@ static struct platform_device bfin_rotary_device = {
static unsigned short pins[] = P_RMII0;
static struct stmmac_mdio_bus_data phy_private_data = {
- .bus_id = 0,
.phy_mask = 1,
};
@@ -745,13 +744,13 @@ static struct flash_platform_data bfin_spi_flash_data = {
.type = "w25q32",
};
-static struct bfin6xx_spi_chip spi_flash_chip_info = {
+static struct bfin_spi3_chip spi_flash_chip_info = {
.enable_dma = true, /* use dma transfer with this chip*/
};
#endif
#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
-static struct bfin6xx_spi_chip spidev_chip_info = {
+static struct bfin_spi3_chip spidev_chip_info = {
.enable_dma = true,
};
#endif
@@ -821,7 +820,7 @@ static struct platform_device bfin_i2s = {
#if defined(CONFIG_SND_BF5XX_SOC_AD1836) \
|| defined(CONFIG_SND_BF5XX_SOC_AD1836_MODULE)
static const char * const ad1836_link[] = {
- "bfin-tdm.0",
+ "bfin-i2s.0",
"spi0.76",
};
static struct platform_device bfin_ad1836_machine = {
@@ -1296,7 +1295,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
},
#endif
};
-#if defined(CONFIG_SPI_BFIN6XX) || defined(CONFIG_SPI_BFIN6XX_MODULE)
+#if IS_ENABLED(CONFIG_SPI_BFIN_V3)
/* SPI (0) */
static struct resource bfin_spi0_resource[] = {
{
@@ -1337,13 +1336,13 @@ static struct resource bfin_spi1_resource[] = {
};
/* SPI controller data */
-static struct bfin6xx_spi_master bf60x_spi_master_info0 = {
+static struct bfin_spi3_master bf60x_spi_master_info0 = {
.num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
.pin_req = {P_SPI0_SCK, P_SPI0_MISO, P_SPI0_MOSI, 0},
};
static struct platform_device bf60x_spi_master0 = {
- .name = "bfin-spi",
+ .name = "bfin-spi3",
.id = 0, /* Bus number */
.num_resources = ARRAY_SIZE(bfin_spi0_resource),
.resource = bfin_spi0_resource,
@@ -1352,13 +1351,13 @@ static struct platform_device bf60x_spi_master0 = {
},
};
-static struct bfin6xx_spi_master bf60x_spi_master_info1 = {
+static struct bfin_spi3_master bf60x_spi_master_info1 = {
.num_chipselect = MAX_CTRL_CS + MAX_BLACKFIN_GPIOS,
.pin_req = {P_SPI1_SCK, P_SPI1_MISO, P_SPI1_MOSI, 0},
};
static struct platform_device bf60x_spi_master1 = {
- .name = "bfin-spi",
+ .name = "bfin-spi3",
.id = 1, /* Bus number */
.num_resources = ARRAY_SIZE(bfin_spi1_resource),
.resource = bfin_spi1_resource,
@@ -1534,7 +1533,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bfin_sdh_device,
#endif
-#if defined(CONFIG_SPI_BFIN6XX) || defined(CONFIG_SPI_BFIN6XX_MODULE)
+#if IS_ENABLED(CONFIG_SPI_BFIN_V3)
&bf60x_spi_master0,
&bf60x_spi_master1,
#endif
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index 1bc2ce6f3c94..961d8392e5e3 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -49,6 +49,7 @@ unsigned long blackfin_iflush_l1_entry[NR_CPUS];
struct blackfin_initial_pda __cpuinitdata initial_pda_coreb;
enum ipi_message_type {
+ BFIN_IPI_NONE,
BFIN_IPI_TIMER,
BFIN_IPI_RESCHEDULE,
BFIN_IPI_CALL_FUNC,
@@ -72,8 +73,8 @@ static DEFINE_SPINLOCK(stop_lock);
/* Simple FIFO buffer, overflow leads to panic */
struct ipi_data {
- unsigned long count;
- unsigned long bits;
+ atomic_t count;
+ atomic_t bits;
};
static DEFINE_PER_CPU(struct ipi_data, bfin_ipi);
@@ -146,7 +147,6 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
platform_clear_ipi(cpu, IRQ_SUPPLE_1);
bfin_ipi_data = &__get_cpu_var(bfin_ipi);
- smp_mb();
while ((pending = xchg(&bfin_ipi_data->bits, 0)) != 0) {
msg = 0;
do {
@@ -170,9 +170,8 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
ipi_cpu_stop(cpu);
break;
}
+ atomic_dec(&bfin_ipi_data->count);
} while (msg < BITS_PER_LONG);
-
- smp_mb();
}
return IRQ_HANDLED;
}
@@ -195,12 +194,10 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg)
unsigned long flags;
local_irq_save(flags);
- smp_mb();
for_each_cpu(cpu, cpumask) {
bfin_ipi_data = &per_cpu(bfin_ipi, cpu);
- smp_mb();
- set_bit(msg, &bfin_ipi_data->bits);
- bfin_ipi_data->count++;
+ atomic_set_mask((1 << msg), &bfin_ipi_data->bits);
+ atomic_inc(&bfin_ipi_data->count);
platform_send_ipi_cpu(cpu, IRQ_SUPPLE_1);
}
@@ -319,7 +316,6 @@ void __cpuinit secondary_start_kernel(void)
setup_secondary(cpu);
platform_secondary_init(cpu);
-
/* setup local core timer */
bfin_local_timer_setup();
@@ -335,6 +331,8 @@ void __cpuinit secondary_start_kernel(void)
*/
calibrate_delay();
+ /* We are done with local CPU inits, unblock the boot CPU. */
+ set_cpu_online(cpu, true);
cpu_startup_entry(CPUHP_ONLINE);
}
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index 82d01a71207f..166842de3dc7 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -90,50 +90,24 @@ asmlinkage void __init init_pda(void)
void __init mem_init(void)
{
- unsigned int codek = 0, datak = 0, initk = 0;
- unsigned int reservedpages = 0, freepages = 0;
- unsigned long tmp;
- unsigned long start_mem = memory_start;
- unsigned long end_mem = memory_end;
+ char buf[64];
- end_mem &= PAGE_MASK;
- high_memory = (void *)end_mem;
-
- start_mem = PAGE_ALIGN(start_mem);
- max_mapnr = num_physpages = MAP_NR(high_memory);
- printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", num_physpages);
+ high_memory = (void *)(memory_end & PAGE_MASK);
+ max_mapnr = MAP_NR(high_memory);
+ printk(KERN_DEBUG "Kernel managed physical pages: %lu\n", max_mapnr);
/* This will put all low memory onto the freelists. */
- totalram_pages = free_all_bootmem();
-
- reservedpages = 0;
- for (tmp = ARCH_PFN_OFFSET; tmp < max_mapnr; tmp++)
- if (PageReserved(pfn_to_page(tmp)))
- reservedpages++;
- freepages = max_mapnr - ARCH_PFN_OFFSET - reservedpages;
-
- /* do not count in kernel image between _rambase and _ramstart */
- reservedpages -= (_ramstart - _rambase) >> PAGE_SHIFT;
-#if (defined(CONFIG_BFIN_EXTMEM_ICACHEABLE) && ANOMALY_05000263)
- reservedpages += (_ramend - memory_end - DMA_UNCACHED_REGION) >> PAGE_SHIFT;
-#endif
-
- codek = (_etext - _stext) >> 10;
- initk = (__init_end - __init_begin) >> 10;
- datak = ((_ramstart - _rambase) >> 10) - codek - initk;
+ free_all_bootmem();
- printk(KERN_INFO
- "Memory available: %luk/%luk RAM, "
- "(%uk init code, %uk kernel code, %uk data, %uk dma, %uk reserved)\n",
- (unsigned long) freepages << (PAGE_SHIFT-10), (_ramend - CONFIG_PHY_RAM_BASE_ADDRESS) >> 10,
- initk, codek, datak, DMA_UNCACHED_REGION >> 10, (reservedpages << (PAGE_SHIFT-10)));
+ snprintf(buf, sizeof(buf) - 1, "%uK DMA", DMA_UNCACHED_REGION >> 10);
+ mem_init_print_info(buf);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
#ifndef CONFIG_MPU
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
#endif
}
#endif
@@ -141,7 +115,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
void __init_refok free_initmem(void)
{
#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
- free_initmem_default(0);
+ free_initmem_default(-1);
if (memory_start == (unsigned long)(&__init_end))
memory_start = (unsigned long)(&__init_begin);
#endif
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index 4258b088aa93..e49f918531ad 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -55,3 +55,4 @@ generic-y += types.h
generic-y += ucontext.h
generic-y += user.h
generic-y += vga.h
+generic-y += xor.h
diff --git a/arch/c6x/kernel/vmlinux.lds.S b/arch/c6x/kernel/vmlinux.lds.S
index 1d81c4c129ec..279d80725128 100644
--- a/arch/c6x/kernel/vmlinux.lds.S
+++ b/arch/c6x/kernel/vmlinux.lds.S
@@ -54,16 +54,15 @@ SECTIONS
}
. = ALIGN(PAGE_SIZE);
+ __init_begin = .;
.init :
{
- _stext = .;
_sinittext = .;
HEAD_TEXT
INIT_TEXT
_einittext = .;
}
- __init_begin = _stext;
INIT_DATA_SECTION(16)
PERCPU_SECTION(128)
@@ -74,6 +73,7 @@ SECTIONS
.text :
{
_text = .;
+ _stext = .;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
diff --git a/arch/c6x/mm/init.c b/arch/c6x/mm/init.c
index a9fcd89b251b..63f5560d6eb2 100644
--- a/arch/c6x/mm/init.c
+++ b/arch/c6x/mm/init.c
@@ -18,6 +18,7 @@
#include <linux/initrd.h>
#include <asm/sections.h>
+#include <asm/uaccess.h>
/*
* ZERO_PAGE is a special page that is used for zero-initialized
@@ -57,31 +58,22 @@ void __init paging_init(void)
void __init mem_init(void)
{
- int codek, datak;
- unsigned long tmp;
- unsigned long len = memory_end - memory_start;
-
high_memory = (void *)(memory_end & PAGE_MASK);
/* this will put all memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
- codek = (_etext - _stext) >> 10;
- datak = (_end - _sdata) >> 10;
+ free_all_bootmem();
- tmp = nr_free_pages() << PAGE_SHIFT;
- printk(KERN_INFO "Memory: %luk/%luk RAM (%dk kernel code, %dk data)\n",
- tmp >> 10, len >> 10, codek, datak);
+ mem_init_print_info(NULL);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
void __init free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 8769a9045a54..3201ddb8da6a 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -134,11 +134,13 @@ config SVINTO_SIM
config ETRAXFS
bool "ETRAX-FS-V32"
+ select CPU_FREQ_TABLE if CPU_FREQ
help
Support CRIS V32.
config CRIS_MACH_ARTPEC3
bool "ARTPEC-3"
+ select CPU_FREQ_TABLE if CPU_FREQ
help
Support Axis ARTPEC-3.
@@ -637,40 +639,10 @@ endchoice
endmenu
-source "drivers/base/Kconfig"
-
-# standard linux drivers
-source "drivers/mtd/Kconfig"
-
-source "drivers/parport/Kconfig"
-
-source "drivers/pnp/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/net/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-source "drivers/rtc/Kconfig"
-
-#
-# input before char - char/joystick depends on it. As does USB.
-#
-source "drivers/input/Kconfig"
-
-source "drivers/char/Kconfig"
+source "drivers/Kconfig"
source "fs/Kconfig"
-source "drivers/usb/Kconfig"
-
-source "drivers/uwb/Kconfig"
-
-source "drivers/staging/Kconfig"
-
source "arch/cris/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
index 5f2cdb3e428c..daf5f19b61a1 100644
--- a/arch/cris/arch-v10/drivers/Kconfig
+++ b/arch/cris/arch-v10/drivers/Kconfig
@@ -2,9 +2,7 @@ if ETRAX_ARCH_V10
config ETRAX_ETHERNET
bool "Ethernet support"
- depends on ETRAX_ARCH_V10
- select ETHERNET
- select NET_CORE
+ depends on ETRAX_ARCH_V10 && NETDEVICES
select MII
help
This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c
index 37e6d2c50b76..22d846bfc570 100644
--- a/arch/cris/arch-v10/kernel/kgdb.c
+++ b/arch/cris/arch-v10/kernel/kgdb.c
@@ -230,46 +230,6 @@ struct register_image
unsigned int usp; /* 0x66 User mode stack pointer */
} registers;
-/************** Prototypes for local library functions ***********************/
-
-/* Copy of strcpy from libc. */
-static char *gdb_cris_strcpy (char *s1, const char *s2);
-
-/* Copy of strlen from libc. */
-static int gdb_cris_strlen (const char *s);
-
-/* Copy of memchr from libc. */
-static void *gdb_cris_memchr (const void *s, int c, int n);
-
-/* Copy of strtol from libc. Does only support base 16. */
-static int gdb_cris_strtol (const char *s, char **endptr, int base);
-
-/********************** Prototypes for local functions. **********************/
-/* Copy the content of a register image into another. The size n is
- the size of the register image. Due to struct assignment generation of
- memcpy in libc. */
-static void copy_registers (registers *dptr, registers *sptr, int n);
-
-/* Copy the stored registers from the stack. Put the register contents
- of thread thread_id in the struct reg. */
-static void copy_registers_from_stack (int thread_id, registers *reg);
-
-/* Copy the registers to the stack. Put the register contents of thread
- thread_id from struct reg to the stack. */
-static void copy_registers_to_stack (int thread_id, registers *reg);
-
-/* Write a value to a specified register regno in the register image
- of the current thread. */
-static int write_register (int regno, char *val);
-
-/* Write a value to a specified register in the stack of a thread other
- than the current thread. */
-static int write_stack_register(int thread_id, int regno, char *valptr);
-
-/* Read a value from a specified register in the register image. Returns the
- status of the read operation. The register value is returned in valptr. */
-static int read_register (char regno, unsigned int *valptr);
-
/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
int getDebugChar (void);
@@ -278,42 +238,6 @@ void putDebugChar (int val);
void enableDebugIRQ (void);
-/* Returns the integer equivalent of a hexadecimal character. */
-static int hex (char ch);
-
-/* Convert the memory, pointed to by mem into hexadecimal representation.
- Put the result in buf, and return a pointer to the last character
- in buf (null). */
-static char *mem2hex (char *buf, unsigned char *mem, int count);
-
-/* Convert the array, in hexadecimal representation, pointed to by buf into
- binary representation. Put the result in mem, and return a pointer to
- the character after the last byte written. */
-static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);
-
-/* Put the content of the array, in binary representation, pointed to by buf
- into memory pointed to by mem, and return a pointer to
- the character after the last byte written. */
-static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);
-
-/* Await the sequence $<data>#<checksum> and store <data> in the array buffer
- returned. */
-static void getpacket (char *buffer);
-
-/* Send $<data>#<checksum> from the <data> in the array buffer. */
-static void putpacket (char *buffer);
-
-/* Build and send a response packet in order to inform the host the
- stub is stopped. */
-static void stub_is_stopped (int sigval);
-
-/* All expected commands are sent from remote.c. Send a response according
- to the description in remote.c. */
-static void handle_exception (int sigval);
-
-/* Performs a complete re-start from scratch. ETRAX specific. */
-static void kill_restart (void);
-
/******************** Prototypes for global functions. ***********************/
/* The string str is prepended with the GDB printout token and sent. */
@@ -336,10 +260,6 @@ extern unsigned char executing_task;
/* The number of characters used for a 64 bit thread identifier. */
#define HEXCHARS_IN_THREAD_ID 16
-/* Avoid warning as the internal_stack is not used in the C-code. */
-#define USEDVAR(name) { if (name) { ; } }
-#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) }
-
/********************************** Packet I/O ******************************/
/* BUFMAX defines the maximum number of characters in
inbound/outbound buffers */
@@ -405,7 +325,7 @@ static int register_size[] =
/* Contains the register image of the executing thread in the assembler
part of the code in order to avoid horrible addressing modes. */
-static registers reg;
+registers cris_reg;
/* FIXME: Should this be used? Delete otherwise. */
/* Contains the assumed consistency state of the register image. Uses the
@@ -413,7 +333,7 @@ static registers reg;
static int consistency_status = SUCCESS;
/********************************** Handle exceptions ************************/
-/* The variable reg contains the register image associated with the
+/* The variable cris_reg contains the register image associated with the
current_thread_c variable. It is a complete register image created at
entry. The reg_g contains a register image of a task where the general
registers are taken from the stack and all special registers are taken
@@ -421,18 +341,10 @@ static int consistency_status = SUCCESS;
in order to provide access mainly for 'g', 'G' and 'P'.
*/
-/* Need two task id pointers in order to handle Hct and Hgt commands. */
-static int current_thread_c = 0;
-static int current_thread_g = 0;
-
-/* Need two register images in order to handle Hct and Hgt commands. The
- variable reg_g is in addition to reg above. */
-static registers reg_g;
-
/********************************** Breakpoint *******************************/
/* Use an internal stack in the breakpoint and interrupt response routines */
#define INTERNAL_STACK_SIZE 1024
-static char internal_stack[INTERNAL_STACK_SIZE];
+char internal_stack[INTERNAL_STACK_SIZE];
/* Due to the breakpoint return pointer, a state variable is needed to keep
track of whether it is a static (compiled) or dynamic (gdb-invoked)
@@ -500,164 +412,6 @@ gdb_cris_strtol (const char *s, char **endptr, int base)
return x;
}
-/********************************* Register image ****************************/
-/* Copy the content of a register image into another. The size n is
- the size of the register image. Due to struct assignment generation of
- memcpy in libc. */
-static void
-copy_registers (registers *dptr, registers *sptr, int n)
-{
- unsigned char *dreg;
- unsigned char *sreg;
-
- for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--)
- *dreg++ = *sreg++;
-}
-
-#ifdef PROCESS_SUPPORT
-/* Copy the stored registers from the stack. Put the register contents
- of thread thread_id in the struct reg. */
-static void
-copy_registers_from_stack (int thread_id, registers *regptr)
-{
- int j;
- stack_registers *s = (stack_registers *)stack_list[thread_id];
- unsigned int *d = (unsigned int *)regptr;
-
- for (j = 13; j >= 0; j--)
- *d++ = s->r[j];
- regptr->sp = (unsigned int)stack_list[thread_id];
- regptr->pc = s->pc;
- regptr->dccr = s->dccr;
- regptr->srp = s->srp;
-}
-
-/* Copy the registers to the stack. Put the register contents of thread
- thread_id from struct reg to the stack. */
-static void
-copy_registers_to_stack (int thread_id, registers *regptr)
-{
- int i;
- stack_registers *d = (stack_registers *)stack_list[thread_id];
- unsigned int *s = (unsigned int *)regptr;
-
- for (i = 0; i < 14; i++) {
- d->r[i] = *s++;
- }
- d->pc = regptr->pc;
- d->dccr = regptr->dccr;
- d->srp = regptr->srp;
-}
-#endif
-
-/* Write a value to a specified register in the register image of the current
- thread. Returns status code SUCCESS, E02 or E05. */
-static int
-write_register (int regno, char *val)
-{
- int status = SUCCESS;
- registers *current_reg = &reg;
-
- if (regno >= R0 && regno <= PC) {
- /* 32-bit register with simple offset. */
- hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
- val, sizeof(unsigned int));
- }
- else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
- /* Do not support read-only registers. */
- status = E02;
- }
- else if (regno == CCR) {
- /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented,
- and P7 (MOF) is 32 bits in ETRAX 100LX. */
- hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
- val, sizeof(unsigned short));
- }
- else if (regno >= MOF && regno <= USP) {
- /* 32 bit register with complex offset. (P8 has been taken care of.) */
- hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
- val, sizeof(unsigned int));
- }
- else {
- /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
- status = E05;
- }
- return status;
-}
-
-#ifdef PROCESS_SUPPORT
-/* Write a value to a specified register in the stack of a thread other
- than the current thread. Returns status code SUCCESS or E07. */
-static int
-write_stack_register (int thread_id, int regno, char *valptr)
-{
- int status = SUCCESS;
- stack_registers *d = (stack_registers *)stack_list[thread_id];
- unsigned int val;
-
- hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int));
- if (regno >= R0 && regno < SP) {
- d->r[regno] = val;
- }
- else if (regno == SP) {
- stack_list[thread_id] = val;
- }
- else if (regno == PC) {
- d->pc = val;
- }
- else if (regno == SRP) {
- d->srp = val;
- }
- else if (regno == DCCR) {
- d->dccr = val;
- }
- else {
- /* Do not support registers in the current thread. */
- status = E07;
- }
- return status;
-}
-#endif
-
-/* Read a value from a specified register in the register image. Returns the
- value in the register or -1 for non-implemented registers.
- Should check consistency_status after a call which may be E05 after changes
- in the implementation. */
-static int
-read_register (char regno, unsigned int *valptr)
-{
- registers *current_reg = &reg;
-
- if (regno >= R0 && regno <= PC) {
- /* 32-bit register with simple offset. */
- *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
- return SUCCESS;
- }
- else if (regno == P0 || regno == VR) {
- /* 8 bit register with complex offset. */
- *valptr = (unsigned int)(*(unsigned char *)
- ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
- return SUCCESS;
- }
- else if (regno == P4 || regno == CCR) {
- /* 16 bit register with complex offset. */
- *valptr = (unsigned int)(*(unsigned short *)
- ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
- return SUCCESS;
- }
- else if (regno >= MOF && regno <= USP) {
- /* 32 bit register with complex offset. */
- *valptr = *(unsigned int *)((char *)&(current_reg->p8)
- + (regno-P8) * sizeof(unsigned int));
- return SUCCESS;
- }
- else {
- /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
- consistency_status = E05;
- return E05;
- }
-}
-
/********************************** Packet I/O ******************************/
/* Returns the integer equivalent of a hexadecimal character. */
static int
@@ -676,8 +430,6 @@ hex (char ch)
Put the result in buf, and return a pointer to the last character
in buf (null). */
-static int do_printk = 0;
-
static char *
mem2hex(char *buf, unsigned char *mem, int count)
{
@@ -761,7 +513,7 @@ getpacket (char *buffer)
xmitcsum = -1;
count = 0;
/* Read until a # or the end of the buffer is reached */
- while (count < BUFMAX) {
+ while (count < BUFMAX - 1) {
ch = getDebugChar ();
if (ch == '#')
break;
@@ -845,6 +597,81 @@ putDebugString (const unsigned char *str, int length)
putpacket(remcomOutBuffer);
}
+/********************************* Register image ****************************/
+/* Write a value to a specified register in the register image of the current
+ thread. Returns status code SUCCESS, E02 or E05. */
+static int
+write_register (int regno, char *val)
+{
+ int status = SUCCESS;
+ registers *current_reg = &cris_reg;
+
+ if (regno >= R0 && regno <= PC) {
+ /* 32-bit register with simple offset. */
+ hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int),
+ val, sizeof(unsigned int));
+ }
+ else if (regno == P0 || regno == VR || regno == P4 || regno == P8) {
+ /* Do not support read-only registers. */
+ status = E02;
+ }
+ else if (regno == CCR) {
+ /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented,
+ and P7 (MOF) is 32 bits in ETRAX 100LX. */
+ hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short),
+ val, sizeof(unsigned short));
+ }
+ else if (regno >= MOF && regno <= USP) {
+ /* 32 bit register with complex offset. (P8 has been taken care of.) */
+ hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int),
+ val, sizeof(unsigned int));
+ }
+ else {
+ /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+ status = E05;
+ }
+ return status;
+}
+
+/* Read a value from a specified register in the register image. Returns the
+ value in the register or -1 for non-implemented registers.
+ Should check consistency_status after a call which may be E05 after changes
+ in the implementation. */
+static int
+read_register (char regno, unsigned int *valptr)
+{
+ registers *current_reg = &cris_reg;
+
+ if (regno >= R0 && regno <= PC) {
+ /* 32-bit register with simple offset. */
+ *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int));
+ return SUCCESS;
+ }
+ else if (regno == P0 || regno == VR) {
+ /* 8 bit register with complex offset. */
+ *valptr = (unsigned int)(*(unsigned char *)
+ ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char)));
+ return SUCCESS;
+ }
+ else if (regno == P4 || regno == CCR) {
+ /* 16 bit register with complex offset. */
+ *valptr = (unsigned int)(*(unsigned short *)
+ ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short)));
+ return SUCCESS;
+ }
+ else if (regno >= MOF && regno <= USP) {
+ /* 32 bit register with complex offset. */
+ *valptr = *(unsigned int *)((char *)&(current_reg->p8)
+ + (regno-P8) * sizeof(unsigned int));
+ return SUCCESS;
+ }
+ else {
+ /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */
+ consistency_status = E05;
+ return E05;
+ }
+}
+
/********************************** Handle exceptions ************************/
/* Build and send a response packet in order to inform the host the
stub is stopped. TAAn...:r...;n...:r...;n...:r...;
@@ -891,26 +718,6 @@ stub_is_stopped(int sigval)
}
-#ifdef PROCESS_SUPPORT
- /* Store the registers of the executing thread. Assume that both step,
- continue, and register content requests are with respect to this
- thread. The executing task is from the operating system scheduler. */
-
- current_thread_c = executing_task;
- current_thread_g = executing_task;
-
- /* A struct assignment translates into a libc memcpy call. Avoid
- all libc functions in order to prevent recursive break points. */
- copy_registers (&reg_g, &reg, sizeof(registers));
-
- /* Store thread:r...; with the executing task TID. */
- gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:");
- pos += gdb_cris_strlen ("thread:");
- remcomOutBuffer[pos++] = hex_asc_hi(executing_task);
- remcomOutBuffer[pos++] = hex_asc_lo(executing_task);
- gdb_cris_strcpy (&remcomOutBuffer[pos], ";");
-#endif
-
/* null-terminate and send it off */
*ptr = 0;
@@ -918,16 +725,18 @@ stub_is_stopped(int sigval)
putpacket (remcomOutBuffer);
}
+/* Performs a complete re-start from scratch. */
+static void
+kill_restart (void)
+{
+ machine_restart("");
+}
+
/* All expected commands are sent from remote.c. Send a response according
to the description in remote.c. */
-static void
+void
handle_exception (int sigval)
{
- /* Avoid warning of not used. */
-
- USEDFUN(handle_exception);
- USEDVAR(internal_stack[0]);
-
/* Send response. */
stub_is_stopped (sigval);
@@ -943,19 +752,7 @@ handle_exception (int sigval)
in a register are in the same order the machine uses.
Failure: void. */
- {
-#ifdef PROCESS_SUPPORT
- /* Use the special register content in the executing thread. */
- copy_registers (&reg_g, &reg, sizeof(registers));
- /* Replace the content available on the stack. */
- if (current_thread_g != executing_task) {
- copy_registers_from_stack (current_thread_g, &reg_g);
- }
- mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)&reg_g, sizeof(registers));
-#else
- mem2hex(remcomOutBuffer, (char *)&reg, sizeof(registers));
-#endif
- }
+ mem2hex(remcomOutBuffer, (char *)&cris_reg, sizeof(registers));
break;
case 'G':
@@ -963,17 +760,7 @@ handle_exception (int sigval)
Each byte of register data is described by two hex digits.
Success: OK
Failure: void. */
-#ifdef PROCESS_SUPPORT
- hex2mem ((unsigned char *)&reg_g, &remcomInBuffer[1], sizeof(registers));
- if (current_thread_g == executing_task) {
- copy_registers (&reg, &reg_g, sizeof(registers));
- }
- else {
- copy_registers_to_stack(current_thread_g, &reg_g);
- }
-#else
- hex2mem((char *)&reg, &remcomInBuffer[1], sizeof(registers));
-#endif
+ hex2mem((char *)&cris_reg, &remcomInBuffer[1], sizeof(registers));
gdb_cris_strcpy (remcomOutBuffer, "OK");
break;
@@ -989,12 +776,7 @@ handle_exception (int sigval)
char *suffix;
int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16);
int status;
-#ifdef PROCESS_SUPPORT
- if (current_thread_g != executing_task)
- status = write_stack_register (current_thread_g, regno, suffix+1);
- else
-#endif
- status = write_register (regno, suffix+1);
+ status = write_register (regno, suffix+1);
switch (status) {
case E02:
@@ -1073,7 +855,7 @@ handle_exception (int sigval)
Success: return to the executing thread.
Failure: will never know. */
if (remcomInBuffer[1] != '\0') {
- reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
+ cris_reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
}
enableDebugIRQ();
return;
@@ -1129,119 +911,6 @@ handle_exception (int sigval)
Not supported: E04 */
gdb_cris_strcpy (remcomOutBuffer, error_message[E04]);
break;
-#ifdef PROCESS_SUPPORT
-
- case 'T':
- /* Thread alive. TXX
- Is thread XX alive?
- Success: OK, thread XX is alive.
- Failure: E03, thread XX is dead. */
- {
- int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16);
- /* Cannot tell whether it is alive or not. */
- if (thread_id >= 0 && thread_id < number_of_tasks)
- gdb_cris_strcpy (remcomOutBuffer, "OK");
- }
- break;
-
- case 'H':
- /* Set thread for subsequent operations: Hct
- c = 'c' for thread used in step and continue;
- t can be -1 for all threads.
- c = 'g' for thread used in other operations.
- t = 0 means pick any thread.
- Success: OK
- Failure: E01 */
- {
- int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16);
- if (remcomInBuffer[1] == 'c') {
- /* c = 'c' for thread used in step and continue */
- /* Do not change current_thread_c here. It would create a mess in
- the scheduler. */
- gdb_cris_strcpy (remcomOutBuffer, "OK");
- }
- else if (remcomInBuffer[1] == 'g') {
- /* c = 'g' for thread used in other operations.
- t = 0 means pick any thread. Impossible since the scheduler does
- not allow that. */
- if (thread_id >= 0 && thread_id < number_of_tasks) {
- current_thread_g = thread_id;
- gdb_cris_strcpy (remcomOutBuffer, "OK");
- }
- else {
- /* Not expected - send an error message. */
- gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
- }
- }
- else {
- /* Not expected - send an error message. */
- gdb_cris_strcpy (remcomOutBuffer, error_message[E01]);
- }
- }
- break;
-
- case 'q':
- case 'Q':
- /* Query of general interest. qXXXX
- Set general value XXXX. QXXXX=yyyy */
- {
- int pos;
- int nextpos;
- int thread_id;
-
- switch (remcomInBuffer[1]) {
- case 'C':
- /* Identify the remote current thread. */
- gdb_cris_strcpy (&remcomOutBuffer[0], "QC");
- remcomOutBuffer[2] = hex_asc_hi(current_thread_c);
- remcomOutBuffer[3] = hex_asc_lo(current_thread_c);
- remcomOutBuffer[4] = '\0';
- break;
- case 'L':
- gdb_cris_strcpy (&remcomOutBuffer[0], "QM");
- /* Reply with number of threads. */
- if (os_is_started()) {
- remcomOutBuffer[2] = hex_asc_hi(number_of_tasks);
- remcomOutBuffer[3] = hex_asc_lo(number_of_tasks);
- }
- else {
- remcomOutBuffer[2] = hex_asc_hi(0);
- remcomOutBuffer[3] = hex_asc_lo(1);
- }
- /* Done with the reply. */
- remcomOutBuffer[4] = hex_asc_lo(1);
- pos = 5;
- /* Expects the argument thread id. */
- for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++)
- remcomOutBuffer[pos] = remcomInBuffer[pos];
- /* Reply with the thread identifiers. */
- if (os_is_started()) {
- /* Store the thread identifiers of all tasks. */
- for (thread_id = 0; thread_id < number_of_tasks; thread_id++) {
- nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
- for (; pos < nextpos; pos ++)
- remcomOutBuffer[pos] = hex_asc_lo(0);
- remcomOutBuffer[pos++] = hex_asc_lo(thread_id);
- }
- }
- else {
- /* Store the thread identifier of the boot task. */
- nextpos = pos + HEXCHARS_IN_THREAD_ID - 1;
- for (; pos < nextpos; pos ++)
- remcomOutBuffer[pos] = hex_asc_lo(0);
- remcomOutBuffer[pos++] = hex_asc_lo(current_thread_c);
- }
- remcomOutBuffer[pos] = '\0';
- break;
- default:
- /* Not supported: "" */
- /* Request information about section offsets: qOffsets. */
- remcomOutBuffer[0] = 0;
- break;
- }
- }
- break;
-#endif /* PROCESS_SUPPORT */
default:
/* The stub should ignore other request and send an empty
@@ -1254,13 +923,6 @@ handle_exception (int sigval)
}
}
-/* Performs a complete re-start from scratch. */
-static void
-kill_restart ()
-{
- machine_restart("");
-}
-
/********************************** Breakpoint *******************************/
/* The hook for both a static (compiled) and a dynamic breakpoint set by GDB.
An internal stack is used by the stub. The register image of the caller is
@@ -1270,93 +932,93 @@ kill_restart ()
void kgdb_handle_breakpoint(void);
-asm ("
- .global kgdb_handle_breakpoint
-kgdb_handle_breakpoint:
-;;
-;; Response to the break-instruction
-;;
-;; Create a register image of the caller
-;;
- move $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts
- di ; Disable interrupts
- move.d $r0,[reg] ; Save R0
- move.d $r1,[reg+0x04] ; Save R1
- move.d $r2,[reg+0x08] ; Save R2
- move.d $r3,[reg+0x0C] ; Save R3
- move.d $r4,[reg+0x10] ; Save R4
- move.d $r5,[reg+0x14] ; Save R5
- move.d $r6,[reg+0x18] ; Save R6
- move.d $r7,[reg+0x1C] ; Save R7
- move.d $r8,[reg+0x20] ; Save R8
- move.d $r9,[reg+0x24] ; Save R9
- move.d $r10,[reg+0x28] ; Save R10
- move.d $r11,[reg+0x2C] ; Save R11
- move.d $r12,[reg+0x30] ; Save R12
- move.d $r13,[reg+0x34] ; Save R13
- move.d $sp,[reg+0x38] ; Save SP (R14)
-;; Due to the old assembler-versions BRP might not be recognized
- .word 0xE670 ; move brp,$r0
- subq 2,$r0 ; Set to address of previous instruction.
- move.d $r0,[reg+0x3c] ; Save the address in PC (R15)
- clear.b [reg+0x40] ; Clear P0
- move $vr,[reg+0x41] ; Save special register P1
- clear.w [reg+0x42] ; Clear P4
- move $ccr,[reg+0x44] ; Save special register CCR
- move $mof,[reg+0x46] ; P7
- clear.d [reg+0x4A] ; Clear P8
- move $ibr,[reg+0x4E] ; P9,
- move $irp,[reg+0x52] ; P10,
- move $srp,[reg+0x56] ; P11,
- move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
- ; P13, register DCCR already saved
-;; Due to the old assembler-versions BRP might not be recognized
- .word 0xE670 ; move brp,r0
-;; Static (compiled) breakpoints must return to the next instruction in order
-;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction
-;; in order to execute it when execution is continued.
- test.b [is_dyn_brkp] ; Is this a dynamic breakpoint?
- beq is_static ; No, a static breakpoint
- nop
- subq 2,$r0 ; rerun the instruction the break replaced
-is_static:
- moveq 1,$r1
- move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint
- move.d $r0,[reg+0x62] ; Save the return address in BRP
- move $usp,[reg+0x66] ; USP
-;;
-;; Handle the communication
-;;
- move.d internal_stack+1020,$sp ; Use the internal stack which grows upward
- moveq 5,$r10 ; SIGTRAP
- jsr handle_exception ; Interactive routine
-;;
-;; Return to the caller
-;;
- move.d [reg],$r0 ; Restore R0
- move.d [reg+0x04],$r1 ; Restore R1
- move.d [reg+0x08],$r2 ; Restore R2
- move.d [reg+0x0C],$r3 ; Restore R3
- move.d [reg+0x10],$r4 ; Restore R4
- move.d [reg+0x14],$r5 ; Restore R5
- move.d [reg+0x18],$r6 ; Restore R6
- move.d [reg+0x1C],$r7 ; Restore R7
- move.d [reg+0x20],$r8 ; Restore R8
- move.d [reg+0x24],$r9 ; Restore R9
- move.d [reg+0x28],$r10 ; Restore R10
- move.d [reg+0x2C],$r11 ; Restore R11
- move.d [reg+0x30],$r12 ; Restore R12
- move.d [reg+0x34],$r13 ; Restore R13
-;;
-;; FIXME: Which registers should be restored?
-;;
- move.d [reg+0x38],$sp ; Restore SP (R14)
- move [reg+0x56],$srp ; Restore the subroutine return pointer.
- move [reg+0x5E],$dccr ; Restore DCCR
- move [reg+0x66],$usp ; Restore USP
- jump [reg+0x62] ; A jump to the content in register BRP works.
- nop ;
-");
+asm ("\n"
+" .global kgdb_handle_breakpoint\n"
+"kgdb_handle_breakpoint:\n"
+";;\n"
+";; Response to the break-instruction\n"
+";;\n"
+";; Create a register image of the caller\n"
+";;\n"
+" move $dccr,[cris_reg+0x5E] ; Save the flags in DCCR before disable interrupts\n"
+" di ; Disable interrupts\n"
+" move.d $r0,[cris_reg] ; Save R0\n"
+" move.d $r1,[cris_reg+0x04] ; Save R1\n"
+" move.d $r2,[cris_reg+0x08] ; Save R2\n"
+" move.d $r3,[cris_reg+0x0C] ; Save R3\n"
+" move.d $r4,[cris_reg+0x10] ; Save R4\n"
+" move.d $r5,[cris_reg+0x14] ; Save R5\n"
+" move.d $r6,[cris_reg+0x18] ; Save R6\n"
+" move.d $r7,[cris_reg+0x1C] ; Save R7\n"
+" move.d $r8,[cris_reg+0x20] ; Save R8\n"
+" move.d $r9,[cris_reg+0x24] ; Save R9\n"
+" move.d $r10,[cris_reg+0x28] ; Save R10\n"
+" move.d $r11,[cris_reg+0x2C] ; Save R11\n"
+" move.d $r12,[cris_reg+0x30] ; Save R12\n"
+" move.d $r13,[cris_reg+0x34] ; Save R13\n"
+" move.d $sp,[cris_reg+0x38] ; Save SP (R14)\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+" .word 0xE670 ; move brp,$r0\n"
+" subq 2,$r0 ; Set to address of previous instruction.\n"
+" move.d $r0,[cris_reg+0x3c] ; Save the address in PC (R15)\n"
+" clear.b [cris_reg+0x40] ; Clear P0\n"
+" move $vr,[cris_reg+0x41] ; Save special register P1\n"
+" clear.w [cris_reg+0x42] ; Clear P4\n"
+" move $ccr,[cris_reg+0x44] ; Save special register CCR\n"
+" move $mof,[cris_reg+0x46] ; P7\n"
+" clear.d [cris_reg+0x4A] ; Clear P8\n"
+" move $ibr,[cris_reg+0x4E] ; P9,\n"
+" move $irp,[cris_reg+0x52] ; P10,\n"
+" move $srp,[cris_reg+0x56] ; P11,\n"
+" move $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n"
+" ; P13, register DCCR already saved\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+" .word 0xE670 ; move brp,r0\n"
+";; Static (compiled) breakpoints must return to the next instruction in order\n"
+";; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction\n"
+";; in order to execute it when execution is continued.\n"
+" test.b [is_dyn_brkp] ; Is this a dynamic breakpoint?\n"
+" beq is_static ; No, a static breakpoint\n"
+" nop\n"
+" subq 2,$r0 ; rerun the instruction the break replaced\n"
+"is_static:\n"
+" moveq 1,$r1\n"
+" move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint\n"
+" move.d $r0,[cris_reg+0x62] ; Save the return address in BRP\n"
+" move $usp,[cris_reg+0x66] ; USP\n"
+";;\n"
+";; Handle the communication\n"
+";;\n"
+" move.d internal_stack+1020,$sp ; Use the internal stack which grows upward\n"
+" moveq 5,$r10 ; SIGTRAP\n"
+" jsr handle_exception ; Interactive routine\n"
+";;\n"
+";; Return to the caller\n"
+";;\n"
+" move.d [cris_reg],$r0 ; Restore R0\n"
+" move.d [cris_reg+0x04],$r1 ; Restore R1\n"
+" move.d [cris_reg+0x08],$r2 ; Restore R2\n"
+" move.d [cris_reg+0x0C],$r3 ; Restore R3\n"
+" move.d [cris_reg+0x10],$r4 ; Restore R4\n"
+" move.d [cris_reg+0x14],$r5 ; Restore R5\n"
+" move.d [cris_reg+0x18],$r6 ; Restore R6\n"
+" move.d [cris_reg+0x1C],$r7 ; Restore R7\n"
+" move.d [cris_reg+0x20],$r8 ; Restore R8\n"
+" move.d [cris_reg+0x24],$r9 ; Restore R9\n"
+" move.d [cris_reg+0x28],$r10 ; Restore R10\n"
+" move.d [cris_reg+0x2C],$r11 ; Restore R11\n"
+" move.d [cris_reg+0x30],$r12 ; Restore R12\n"
+" move.d [cris_reg+0x34],$r13 ; Restore R13\n"
+";;\n"
+";; FIXME: Which registers should be restored?\n"
+";;\n"
+" move.d [cris_reg+0x38],$sp ; Restore SP (R14)\n"
+" move [cris_reg+0x56],$srp ; Restore the subroutine return pointer.\n"
+" move [cris_reg+0x5E],$dccr ; Restore DCCR\n"
+" move [cris_reg+0x66],$usp ; Restore USP\n"
+" jump [cris_reg+0x62] ; A jump to the content in register BRP works.\n"
+" nop ;\n"
+"\n");
/* The hook for an interrupt generated by GDB. An internal stack is used
by the stub. The register image of the caller is stored in the structure
@@ -1367,94 +1029,94 @@ is_static:
void kgdb_handle_serial(void);
-asm ("
- .global kgdb_handle_serial
-kgdb_handle_serial:
-;;
-;; Response to a serial interrupt
-;;
-
- move $dccr,[reg+0x5E] ; Save the flags in DCCR
- di ; Disable interrupts
- move.d $r0,[reg] ; Save R0
- move.d $r1,[reg+0x04] ; Save R1
- move.d $r2,[reg+0x08] ; Save R2
- move.d $r3,[reg+0x0C] ; Save R3
- move.d $r4,[reg+0x10] ; Save R4
- move.d $r5,[reg+0x14] ; Save R5
- move.d $r6,[reg+0x18] ; Save R6
- move.d $r7,[reg+0x1C] ; Save R7
- move.d $r8,[reg+0x20] ; Save R8
- move.d $r9,[reg+0x24] ; Save R9
- move.d $r10,[reg+0x28] ; Save R10
- move.d $r11,[reg+0x2C] ; Save R11
- move.d $r12,[reg+0x30] ; Save R12
- move.d $r13,[reg+0x34] ; Save R13
- move.d $sp,[reg+0x38] ; Save SP (R14)
- move $irp,[reg+0x3c] ; Save the address in PC (R15)
- clear.b [reg+0x40] ; Clear P0
- move $vr,[reg+0x41] ; Save special register P1,
- clear.w [reg+0x42] ; Clear P4
- move $ccr,[reg+0x44] ; Save special register CCR
- move $mof,[reg+0x46] ; P7
- clear.d [reg+0x4A] ; Clear P8
- move $ibr,[reg+0x4E] ; P9,
- move $irp,[reg+0x52] ; P10,
- move $srp,[reg+0x56] ; P11,
- move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR
- ; P13, register DCCR already saved
-;; Due to the old assembler-versions BRP might not be recognized
- .word 0xE670 ; move brp,r0
- move.d $r0,[reg+0x62] ; Save the return address in BRP
- move $usp,[reg+0x66] ; USP
-
-;; get the serial character (from debugport.c) and check if it is a ctrl-c
-
- jsr getDebugChar
- cmp.b 3, $r10
- bne goback
- nop
-
- move.d [reg+0x5E], $r10 ; Get DCCR
- btstq 8, $r10 ; Test the U-flag.
- bmi goback
- nop
-
-;;
-;; Handle the communication
-;;
- move.d internal_stack+1020,$sp ; Use the internal stack
- moveq 2,$r10 ; SIGINT
- jsr handle_exception ; Interactive routine
-
-goback:
-;;
-;; Return to the caller
-;;
- move.d [reg],$r0 ; Restore R0
- move.d [reg+0x04],$r1 ; Restore R1
- move.d [reg+0x08],$r2 ; Restore R2
- move.d [reg+0x0C],$r3 ; Restore R3
- move.d [reg+0x10],$r4 ; Restore R4
- move.d [reg+0x14],$r5 ; Restore R5
- move.d [reg+0x18],$r6 ; Restore R6
- move.d [reg+0x1C],$r7 ; Restore R7
- move.d [reg+0x20],$r8 ; Restore R8
- move.d [reg+0x24],$r9 ; Restore R9
- move.d [reg+0x28],$r10 ; Restore R10
- move.d [reg+0x2C],$r11 ; Restore R11
- move.d [reg+0x30],$r12 ; Restore R12
- move.d [reg+0x34],$r13 ; Restore R13
-;;
-;; FIXME: Which registers should be restored?
-;;
- move.d [reg+0x38],$sp ; Restore SP (R14)
- move [reg+0x56],$srp ; Restore the subroutine return pointer.
- move [reg+0x5E],$dccr ; Restore DCCR
- move [reg+0x66],$usp ; Restore USP
- reti ; Return from the interrupt routine
- nop
-");
+asm ("\n"
+" .global kgdb_handle_serial\n"
+"kgdb_handle_serial:\n"
+";;\n"
+";; Response to a serial interrupt\n"
+";;\n"
+"\n"
+" move $dccr,[cris_reg+0x5E] ; Save the flags in DCCR\n"
+" di ; Disable interrupts\n"
+" move.d $r0,[cris_reg] ; Save R0\n"
+" move.d $r1,[cris_reg+0x04] ; Save R1\n"
+" move.d $r2,[cris_reg+0x08] ; Save R2\n"
+" move.d $r3,[cris_reg+0x0C] ; Save R3\n"
+" move.d $r4,[cris_reg+0x10] ; Save R4\n"
+" move.d $r5,[cris_reg+0x14] ; Save R5\n"
+" move.d $r6,[cris_reg+0x18] ; Save R6\n"
+" move.d $r7,[cris_reg+0x1C] ; Save R7\n"
+" move.d $r8,[cris_reg+0x20] ; Save R8\n"
+" move.d $r9,[cris_reg+0x24] ; Save R9\n"
+" move.d $r10,[cris_reg+0x28] ; Save R10\n"
+" move.d $r11,[cris_reg+0x2C] ; Save R11\n"
+" move.d $r12,[cris_reg+0x30] ; Save R12\n"
+" move.d $r13,[cris_reg+0x34] ; Save R13\n"
+" move.d $sp,[cris_reg+0x38] ; Save SP (R14)\n"
+" move $irp,[cris_reg+0x3c] ; Save the address in PC (R15)\n"
+" clear.b [cris_reg+0x40] ; Clear P0\n"
+" move $vr,[cris_reg+0x41] ; Save special register P1,\n"
+" clear.w [cris_reg+0x42] ; Clear P4\n"
+" move $ccr,[cris_reg+0x44] ; Save special register CCR\n"
+" move $mof,[cris_reg+0x46] ; P7\n"
+" clear.d [cris_reg+0x4A] ; Clear P8\n"
+" move $ibr,[cris_reg+0x4E] ; P9,\n"
+" move $irp,[cris_reg+0x52] ; P10,\n"
+" move $srp,[cris_reg+0x56] ; P11,\n"
+" move $dtp0,[cris_reg+0x5A] ; P12, register BAR, assembler might not know BAR\n"
+" ; P13, register DCCR already saved\n"
+";; Due to the old assembler-versions BRP might not be recognized\n"
+" .word 0xE670 ; move brp,r0\n"
+" move.d $r0,[cris_reg+0x62] ; Save the return address in BRP\n"
+" move $usp,[cris_reg+0x66] ; USP\n"
+"\n"
+";; get the serial character (from debugport.c) and check if it is a ctrl-c\n"
+"\n"
+" jsr getDebugChar\n"
+" cmp.b 3, $r10\n"
+" bne goback\n"
+" nop\n"
+"\n"
+" move.d [cris_reg+0x5E], $r10 ; Get DCCR\n"
+" btstq 8, $r10 ; Test the U-flag.\n"
+" bmi goback\n"
+" nop\n"
+"\n"
+";;\n"
+";; Handle the communication\n"
+";;\n"
+" move.d internal_stack+1020,$sp ; Use the internal stack\n"
+" moveq 2,$r10 ; SIGINT\n"
+" jsr handle_exception ; Interactive routine\n"
+"\n"
+"goback:\n"
+";;\n"
+";; Return to the caller\n"
+";;\n"
+" move.d [cris_reg],$r0 ; Restore R0\n"
+" move.d [cris_reg+0x04],$r1 ; Restore R1\n"
+" move.d [cris_reg+0x08],$r2 ; Restore R2\n"
+" move.d [cris_reg+0x0C],$r3 ; Restore R3\n"
+" move.d [cris_reg+0x10],$r4 ; Restore R4\n"
+" move.d [cris_reg+0x14],$r5 ; Restore R5\n"
+" move.d [cris_reg+0x18],$r6 ; Restore R6\n"
+" move.d [cris_reg+0x1C],$r7 ; Restore R7\n"
+" move.d [cris_reg+0x20],$r8 ; Restore R8\n"
+" move.d [cris_reg+0x24],$r9 ; Restore R9\n"
+" move.d [cris_reg+0x28],$r10 ; Restore R10\n"
+" move.d [cris_reg+0x2C],$r11 ; Restore R11\n"
+" move.d [cris_reg+0x30],$r12 ; Restore R12\n"
+" move.d [cris_reg+0x34],$r13 ; Restore R13\n"
+";;\n"
+";; FIXME: Which registers should be restored?\n"
+";;\n"
+" move.d [cris_reg+0x38],$sp ; Restore SP (R14)\n"
+" move [cris_reg+0x56],$srp ; Restore the subroutine return pointer.\n"
+" move [cris_reg+0x5E],$dccr ; Restore DCCR\n"
+" move [cris_reg+0x66],$usp ; Restore USP\n"
+" reti ; Return from the interrupt routine\n"
+" nop\n"
+"\n");
/* Use this static breakpoint in the start-up only. */
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index ab725edbc680..1d866d3ee2f8 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -2,9 +2,7 @@ if ETRAX_ARCH_V32
config ETRAX_ETHERNET
bool "Ethernet support"
- depends on ETRAX_ARCH_V32
- select ETHERNET
- select NET_CORE
+ depends on ETRAX_ARCH_V32 && NETDEVICES
select MII
help
This option enables the ETRAX FS built-in 10/100Mbit Ethernet
@@ -640,8 +638,6 @@ config ETRAX_STREAMCOPROC
This option enables a driver for the stream co-processor
for cryptographic operations.
-source drivers/mmc/Kconfig
-
config ETRAX_MMC_IOP
tristate "MMC/SD host driver using IO-processor"
depends on ETRAX_ARCH_V32 && MMC
@@ -833,9 +829,4 @@ config ETRAX_SPI_MMC_WP_GPIO_PIN
The pin to use for the SD/MMC write-protect signal for a memory
card. If defined as " " (space), the card is considered writable.
-# Avoid choices causing non-working configs by conditionalizing the inclusion.
-if ETRAX_SPI_MMC
-source drivers/spi/Kconfig
-endif
-
endif
diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild
index f1e79edc9dd2..c8325455520e 100644
--- a/arch/cris/include/asm/Kbuild
+++ b/arch/cris/include/asm/Kbuild
@@ -5,5 +5,9 @@ header-y += arch-v32/
generic-y += clkdev.h
generic-y += exec.h
+generic-y += kvm_para.h
+generic-y += linkage.h
generic-y += module.h
generic-y += trace_clock.h
+generic-y += vga.h
+generic-y += xor.h
diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h
index ac12ae2b9286..5d3047e5563b 100644
--- a/arch/cris/include/asm/io.h
+++ b/arch/cris/include/asm/io.h
@@ -167,6 +167,9 @@ static inline void outsl(unsigned int port, const void *addr,
cris_iops->write_io(port, (void *)addr, 4, count);
}
+#define inb_p(port) inb(port)
+#define outb_p(val, port) outb((val), (port))
+
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access
diff --git a/arch/cris/include/asm/linkage.h b/arch/cris/include/asm/linkage.h
deleted file mode 100644
index 291c2d01c44f..000000000000
--- a/arch/cris/include/asm/linkage.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_LINKAGE_H
-#define __ASM_LINKAGE_H
-
-/* Nothing to see here... */
-
-#endif
diff --git a/arch/cris/include/asm/page.h b/arch/cris/include/asm/page.h
index be45ee366be9..dfc53f9b88ec 100644
--- a/arch/cris/include/asm/page.h
+++ b/arch/cris/include/asm/page.h
@@ -51,7 +51,6 @@ typedef struct page *pgtable_t;
*/
#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT))
-#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr)
#define virt_addr_valid(kaddr) pfn_valid((unsigned)(kaddr) >> PAGE_SHIFT)
/* convert a page (based on mem_map and forward) to a physical address
diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h
index ba409c9947bc..47b1ec55092d 100644
--- a/arch/cris/include/uapi/asm/socket.h
+++ b/arch/cris/include/uapi/asm/socket.h
@@ -76,6 +76,8 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
index 9ac80946dada..c81af5bd9167 100644
--- a/arch/cris/mm/init.c
+++ b/arch/cris/mm/init.c
@@ -19,9 +19,6 @@ unsigned long empty_zero_page;
void __init
mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
- unsigned long tmp;
-
BUG_ON(!mem_map);
/* max/min_low_pfn was set by setup.c
@@ -29,35 +26,9 @@ mem_init(void)
*
* high_memory was also set in setup.c
*/
-
- max_mapnr = num_physpages = max_low_pfn - min_low_pfn;
-
- /* this will put all memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
- reservedpages = 0;
- for (tmp = 0; tmp < max_mapnr; tmp++) {
- /*
- * Only count reserved RAM pages
- */
- if (PageReserved(mem_map + tmp))
- reservedpages++;
- }
-
- codesize = (unsigned long) &_etext - (unsigned long) &_stext;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk(KERN_INFO
- "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, "
- "%dk init)\n" ,
- nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10
- );
+ max_mapnr = max_low_pfn - min_low_pfn;
+ free_all_bootmem();
+ mem_init_print_info(NULL);
}
/* free the pages occupied by initialization code */
@@ -65,5 +36,5 @@ mem_init(void)
void
free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 2ce731f9aa4d..4b6628ea381e 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -14,6 +14,7 @@ config FRV
select ARCH_WANT_IPC_PARSE_VERSION
select OLD_SIGSUSPEND3
select OLD_SIGACTION
+ select HAVE_DEBUG_STACKOVERFLOW
config ZONE_DMA
bool
diff --git a/arch/frv/Kconfig.debug b/arch/frv/Kconfig.debug
index 211f01bc4caa..98c99a3ed2be 100644
--- a/arch/frv/Kconfig.debug
+++ b/arch/frv/Kconfig.debug
@@ -2,10 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
-
config GDBSTUB
bool "Remote GDB kernel debugging"
depends on DEBUG_KERNEL
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index 31dbb5d8e13d..dbc08520f22c 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -74,5 +74,7 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/frv/kernel/head.S b/arch/frv/kernel/head.S
index e9a8cc63ac94..a7d0bea9c036 100644
--- a/arch/frv/kernel/head.S
+++ b/arch/frv/kernel/head.S
@@ -479,11 +479,6 @@ __head_mmu_enabled:
LEDS 0x000c
- # initialise the processor and the peripherals
- #call SYMBOL_NAME(processor_init)
- #call SYMBOL_NAME(unit_init)
- #LEDS 0x0aff
-
sethi.p #0xe5e5,gr3
setlo #0xe5e5,gr3
or.p gr3,gr0,gr4
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index 0b579927439d..ac767d94a880 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -150,7 +150,7 @@ static int user_atoi(char __user *ubuf, size_t len)
/*
* Send us to sleep.
*/
-static int sysctl_pm_do_suspend(ctl_table *ctl, int write,
+static int sysctl_pm_do_suspend(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *fpos)
{
int mode;
@@ -197,7 +197,7 @@ static int try_set_cmode(int new_cmode)
}
-static int cmode_procctl(ctl_table *ctl, int write,
+static int cmode_procctl(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *fpos)
{
int new_cmode;
@@ -269,7 +269,7 @@ static int try_set_cm(int new_cm)
return 0;
}
-static int p0_procctl(ctl_table *ctl, int write,
+static int p0_procctl(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *fpos)
{
int new_p0;
@@ -282,7 +282,7 @@ static int p0_procctl(ctl_table *ctl, int write,
return try_set_p0(new_p0)?:*lenp;
}
-static int cm_procctl(ctl_table *ctl, int write,
+static int cm_procctl(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *fpos)
{
int new_cm;
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index a5136474c6fd..ae3a6706419b 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -735,7 +735,7 @@ static void __init parse_cmdline_early(char *cmdline)
/* "mem=XXX[kKmM]" sets SDRAM size to <mem>, overriding the value we worked
* out from the SDRAM controller mask register
*/
- if (!memcmp(cmdline, "mem=", 4)) {
+ if (!strncmp(cmdline, "mem=", 4)) {
unsigned long long mem_size;
mem_size = memparse(cmdline + 4, &cmdline);
@@ -876,6 +876,7 @@ late_initcall(setup_arch_serial);
static void __init setup_linux_memory(void)
{
unsigned long bootmap_size, low_top_pfn, kstart, kend, high_mem;
+ unsigned long physpages;
kstart = (unsigned long) &__kernel_image_start - PAGE_OFFSET;
kend = (unsigned long) &__kernel_image_end - PAGE_OFFSET;
@@ -893,19 +894,19 @@ static void __init setup_linux_memory(void)
);
/* pass the memory that the kernel can immediately use over to the bootmem allocator */
- max_mapnr = num_physpages = (memory_end - memory_start) >> PAGE_SHIFT;
+ max_mapnr = physpages = (memory_end - memory_start) >> PAGE_SHIFT;
low_top_pfn = (KERNEL_LOWMEM_END - KERNEL_LOWMEM_START) >> PAGE_SHIFT;
high_mem = 0;
- if (num_physpages > low_top_pfn) {
+ if (physpages > low_top_pfn) {
#ifdef CONFIG_HIGHMEM
- high_mem = num_physpages - low_top_pfn;
+ high_mem = physpages - low_top_pfn;
#else
- max_mapnr = num_physpages = low_top_pfn;
+ max_mapnr = physpages = low_top_pfn;
#endif
}
else {
- low_top_pfn = num_physpages;
+ low_top_pfn = physpages;
}
min_low_pfn = memory_start >> PAGE_SHIFT;
@@ -979,7 +980,7 @@ static void __init setup_uclinux_memory(void)
free_bootmem(memory_start, memory_end - memory_start);
high_memory = (void *) (memory_end & PAGE_MASK);
- max_mapnr = num_physpages = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
+ max_mapnr = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
min_low_pfn = memory_start >> PAGE_SHIFT;
max_low_pfn = memory_end >> PAGE_SHIFT;
diff --git a/arch/frv/kernel/sysctl.c b/arch/frv/kernel/sysctl.c
index 6c155d69da29..f4dfae2c75ad 100644
--- a/arch/frv/kernel/sysctl.c
+++ b/arch/frv/kernel/sysctl.c
@@ -46,7 +46,7 @@ static void frv_change_dcache_mode(unsigned long newmode)
/*
* handle requests to dynamically switch the write caching mode delivered by /proc
*/
-static int procctl_frv_cachemode(ctl_table *table, int write,
+static int procctl_frv_cachemode(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
@@ -121,7 +121,7 @@ static int procctl_frv_cachemode(ctl_table *table, int write,
* permit the mm_struct the nominated process is using have its MMU context ID pinned
*/
#ifdef CONFIG_MMU
-static int procctl_frv_pin_cxnr(ctl_table *table, int write,
+static int procctl_frv_pin_cxnr(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index 4bff48c19d29..a6d105d61b26 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -523,7 +523,7 @@ void die_if_kernel(const char *str, ...)
return;
va_start(va, str);
- vsprintf(buffer, str, va);
+ vsnprintf(buffer, sizeof(buffer), str, va);
va_end(va);
console_verbose();
diff --git a/arch/frv/mm/init.c b/arch/frv/mm/init.c
index dee354fa6b64..88a159743528 100644
--- a/arch/frv/mm/init.c
+++ b/arch/frv/mm/init.c
@@ -78,7 +78,7 @@ void __init paging_init(void)
memset((void *) empty_zero_page, 0, PAGE_SIZE);
#ifdef CONFIG_HIGHMEM
- if (num_physpages - num_mappedpages) {
+ if (get_num_physpages() - num_mappedpages) {
pgd_t *pge;
pud_t *pue;
pmd_t *pme;
@@ -96,7 +96,7 @@ void __init paging_init(void)
*/
zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = num_physpages - num_mappedpages;
+ zones_size[ZONE_HIGHMEM] = get_num_physpages() - num_mappedpages;
#endif
free_area_init(zones_size);
@@ -114,45 +114,24 @@ void __init paging_init(void)
*/
void __init mem_init(void)
{
- unsigned long npages = (memory_end - memory_start) >> PAGE_SHIFT;
- unsigned long tmp;
-#ifdef CONFIG_MMU
- unsigned long loop, pfn;
- int datapages = 0;
-#endif
- int codek = 0, datak = 0;
+ unsigned long code_size = _etext - _stext;
/* this will put all low memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
-#ifdef CONFIG_MMU
- for (loop = 0 ; loop < npages ; loop++)
- if (PageReserved(&mem_map[loop]))
- datapages++;
-
-#ifdef CONFIG_HIGHMEM
- for (pfn = num_physpages - 1; pfn >= num_mappedpages; pfn--)
- free_highmem_page(&mem_map[pfn]);
-#endif
-
- codek = ((unsigned long) &_etext - (unsigned long) &_stext) >> 10;
- datak = datapages << (PAGE_SHIFT - 10);
-
-#else
- codek = (_etext - _stext) >> 10;
- datak = 0; //(__bss_stop - _sdata) >> 10;
+ free_all_bootmem();
+#if defined(CONFIG_MMU) && defined(CONFIG_HIGHMEM)
+ {
+ unsigned long pfn;
+
+ for (pfn = get_num_physpages() - 1;
+ pfn >= num_mappedpages; pfn--)
+ free_highmem_page(&mem_map[pfn]);
+ }
#endif
- tmp = nr_free_pages() << PAGE_SHIFT;
- printk("Memory available: %luKiB/%luKiB RAM, %luKiB/%luKiB ROM (%dKiB kernel code, %dKiB data)\n",
- tmp >> 10,
- npages << (PAGE_SHIFT - 10),
- (rom_length > 0) ? ((rom_length >> 10) - codek) : 0,
- rom_length >> 10,
- codek,
- datak
- );
-
+ mem_init_print_info(NULL);
+ if (rom_length > 0 && rom_length >= code_size)
+ printk("Memory available: %luKiB/%luKiB ROM\n",
+ (rom_length - code_size) >> 10, rom_length >> 10);
} /* end mem_init() */
/*****************************************************************************/
@@ -162,7 +141,7 @@ void __init mem_init(void)
void free_initmem(void)
{
#if defined(CONFIG_RAMKERNEL) && !defined(CONFIG_PROTECT_KERNEL)
- free_initmem_default(0);
+ free_initmem_default(-1);
#endif
} /* end free_initmem() */
@@ -173,6 +152,6 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
} /* end free_initrd_mem() */
#endif
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 303e4f9a79d1..3d6759ee382f 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -94,126 +94,10 @@ endmenu
source "net/Kconfig"
-source "drivers/base/Kconfig"
-
-source "drivers/mtd/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
+source "drivers/Kconfig"
source "arch/h8300/Kconfig.ide"
-source "drivers/net/Kconfig"
-
-#
-# input - input/joystick depends on it. As does USB.
-#
-source "drivers/input/Kconfig"
-
-menu "Character devices"
-
-config VT
- bool "Virtual terminal"
- ---help---
- If you say Y here, you will get support for terminal devices with
- display and keyboard devices. These are called "virtual" because you
- can run several virtual terminals (also called virtual consoles) on
- one physical terminal. This is rather useful, for example one
- virtual terminal can collect system messages and warnings, another
- one can be used for a text-mode user session, and a third could run
- an X session, all in parallel. Switching between virtual terminals
- is done with certain key combinations, usually Alt-<function key>.
-
- The setterm command ("man setterm") can be used to change the
- properties (such as colors or beeping) of a virtual terminal. The
- man page console_codes(4) ("man console_codes") contains the special
- character sequences that can be used to change those properties
- directly. The fonts used on virtual terminals can be changed with
- the setfont ("man setfont") command and the key bindings are defined
- with the loadkeys ("man loadkeys") command.
-
- You need at least one virtual terminal device in order to make use
- of your keyboard and monitor. Therefore, only people configuring an
- embedded system would want to say N here in order to save some
- memory; the only way to log into such a system is then via a serial
- or network connection.
-
- If unsure, say Y, or else you won't be able to do much with your new
- shiny Linux system :-)
-
-config VT_CONSOLE
- bool "Support for console on virtual terminal"
- depends on VT
- ---help---
- The system console is the device which receives all kernel messages
- and warnings and which allows logins in single user mode. If you
- answer Y here, a virtual terminal (the device used to interact with
- a physical terminal) can be used as system console. This is the most
- common mode of operations, so you should say Y here unless you want
- the kernel messages be output only to a serial port (in which case
- you should say Y to "Console on serial port", below).
-
- If you do say Y here, by default the currently visible virtual
- terminal (/dev/tty0) will be used as system console. You can change
- that with a kernel command line option such as "console=tty3" which
- would use the third virtual terminal as system console. (Try "man
- bootparam" or see the documentation of your boot loader (lilo or
- loadlin) about how to pass options to the kernel at boot time.)
-
- If unsure, say Y.
-
-config HW_CONSOLE
- bool
- depends on VT
- default y
-
-comment "Unix98 PTY support"
-
-config UNIX98_PTYS
- bool "Unix98 PTY support"
- ---help---
- A pseudo terminal (PTY) is a software device consisting of two
- halves: a master and a slave. The slave device behaves identical to
- a physical terminal; the master device is used by a process to
- read data from and write data to the slave, thereby emulating a
- terminal. Typical programs for the master side are telnet servers
- and xterms.
-
- Linux has traditionally used the BSD-like names /dev/ptyxx for
- masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
- has a number of problems. The GNU C library glibc 2.1 and later,
- however, supports the Unix98 naming standard: in order to acquire a
- pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
- terminal is then made available to the process and the pseudo
- terminal slave can be accessed as /dev/pts/<number>. What was
- traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
- The entries in /dev/pts/ are created on the fly by a virtual
- file system; therefore, if you say Y here you should say Y to
- "/dev/pts file system for Unix98 PTYs" as well.
-
- If you want to say Y here, you need to have the C library glibc 2.1
- or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
- Read the instructions in <file:Documentation/Changes> pertaining to
- pseudo terminals. It's safe to say N.
-
-source "drivers/char/pcmcia/Kconfig"
-
-source "drivers/tty/serial/Kconfig"
-
-source "drivers/i2c/Kconfig"
-
-source "drivers/hwmon/Kconfig"
-
-source "drivers/usb/Kconfig"
-
-source "drivers/uwb/Kconfig"
-
-endmenu
-
-source "drivers/staging/Kconfig"
-
source "fs/Kconfig"
source "arch/h8300/Kconfig.debug"
diff --git a/arch/h8300/Kconfig.cpu b/arch/h8300/Kconfig.cpu
index 321f3922728b..cdee771460ed 100644
--- a/arch/h8300/Kconfig.cpu
+++ b/arch/h8300/Kconfig.cpu
@@ -64,6 +64,7 @@ choice
config H83002
bool "H8/3001,3002,3003"
+ depends on BROKEN
select CPU_H8300H
config H83007
@@ -72,6 +73,7 @@ config H83007
config H83048
bool "H8/3044,3045,3046,3047,3048,3052"
+ depends on BROKEN
select CPU_H8300H
config H83068
@@ -155,10 +157,12 @@ config H8300_TIMER16_CH
config H8300_ITU_CH
int "ITU channel"
depends on H8300_ITU
+ range 0 4
config H8300_TPU_CH
int "TPU channel"
depends on H8300_TPU
+ range 0 4
source "kernel/Kconfig.preempt"
diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile
index 6745cb1ffb4f..a6c98fe3bbc3 100644
--- a/arch/h8300/boot/compressed/Makefile
+++ b/arch/h8300/boot/compressed/Makefile
@@ -16,7 +16,7 @@ OBJECTS = $(obj)/head.o $(obj)/misc.o
#
CONFIG_MEMORY_START ?= 0x00400000
CONFIG_BOOT_LINK_OFFSET ?= 0x00140000
-IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
+IMAGE_OFFSET := $(shell printf "0x%08x" $$(($(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET))))
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup $(obj)/vmlinux.lds
diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c
index 51ab6cbd030f..4a1e3dd43948 100644
--- a/arch/h8300/boot/compressed/misc.c
+++ b/arch/h8300/boot/compressed/misc.c
@@ -79,7 +79,6 @@ static void error(char *m);
int puts(const char *);
-extern int _text; /* Defined in vmlinux.lds.S */
extern int _end;
static unsigned long free_mem_ptr;
static unsigned long free_mem_end_ptr;
diff --git a/arch/h8300/include/asm/Kbuild b/arch/h8300/include/asm/Kbuild
index 995eb47e01bb..8ada3cf0c98d 100644
--- a/arch/h8300/include/asm/Kbuild
+++ b/arch/h8300/include/asm/Kbuild
@@ -1,6 +1,8 @@
generic-y += clkdev.h
generic-y += exec.h
+generic-y += linkage.h
generic-y += mmu.h
generic-y += module.h
generic-y += trace_clock.h
+generic-y += xor.h
diff --git a/arch/h8300/include/asm/barrier.h b/arch/h8300/include/asm/barrier.h
index c7283c343c55..9e0aa9fc195d 100644
--- a/arch/h8300/include/asm/barrier.h
+++ b/arch/h8300/include/asm/barrier.h
@@ -12,6 +12,8 @@
#define wmb() asm volatile ("" : : :"memory")
#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define read_barrier_depends() do { } while (0)
+
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
diff --git a/arch/h8300/include/asm/linkage.h b/arch/h8300/include/asm/linkage.h
deleted file mode 100644
index 1d81604fb0ad..000000000000
--- a/arch/h8300/include/asm/linkage.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _H8300_LINKAGE_H
-#define _H8300_LINKAGE_H
-
-#undef SYMBOL_NAME_LABEL
-#define SYMBOL_NAME_LABEL(_name_) _##_name_##:
-#endif
diff --git a/arch/h8300/include/asm/tlb.h b/arch/h8300/include/asm/tlb.h
index 3dea80ad9e6f..7f0743051ad5 100644
--- a/arch/h8300/include/asm/tlb.h
+++ b/arch/h8300/include/asm/tlb.h
@@ -1,16 +1,3 @@
-/*
- include/asm-h8300/tlb.h
-*/
-
-#ifndef __H8300_TLB_H__
-#define __H8300_TLB_H__
-
-#define tlb_flush(tlb) do { } while(0)
-
-/*
- include/asm-h8300/tlb.h
-*/
-
#ifndef __H8300_TLB_H__
#define __H8300_TLB_H__
@@ -19,5 +6,3 @@
#include <asm-generic/tlb.h>
#endif
-
-#endif
diff --git a/arch/h8300/include/uapi/asm/socket.h b/arch/h8300/include/uapi/asm/socket.h
index 5d1c6d0870e6..a38d38a6520b 100644
--- a/arch/h8300/include/uapi/asm/socket.h
+++ b/arch/h8300/include/uapi/asm/socket.h
@@ -74,4 +74,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/h8300/kernel/entry.S b/arch/h8300/kernel/entry.S
index 617a6878787f..94bd30f11df6 100644
--- a/arch/h8300/kernel/entry.S
+++ b/arch/h8300/kernel/entry.S
@@ -87,13 +87,13 @@ INTERRUPTS = 128
bne 5f
/* user mode */
- mov.l sp,@SYMBOL_NAME(sw_usp)
+ mov.l sp,@_sw_usp
mov.l @sp,er0 /* restore saved er0 */
orc #0x10,ccr /* switch kernel stack */
- mov.l @SYMBOL_NAME(sw_ksp),sp
+ mov.l @_sw_ksp,sp
sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
SAVEREGS
- mov.l @SYMBOL_NAME(sw_usp),er0
+ mov.l @_sw_usp,er0
mov.l @(USERRET:16,er0),er1 /* copy the RET addr */
mov.l er1,@(LRET-LER3:16,sp)
SAVEEXR
@@ -128,7 +128,7 @@ INTERRUPTS = 128
bne 7f
orc #0x80,ccr
- mov.l @SYMBOL_NAME(sw_usp),er0
+ mov.l @_sw_usp,er0
mov.l @(LER0-LER1:16,sp),er1 /* restore ER0 */
mov.l er1,@er0
RESTOREEXR
@@ -141,7 +141,7 @@ INTERRUPTS = 128
mov.l @sp+,er1
add.l #(LRET-LER1),sp /* remove LORIG - LRET */
- mov.l sp,@SYMBOL_NAME(sw_ksp)
+ mov.l sp,@_sw_ksp
andc #0xef,ccr /* switch to user mode */
mov.l er0,sp
bra 8f
@@ -155,20 +155,20 @@ INTERRUPTS = 128
rte
.endm
-.globl SYMBOL_NAME(system_call)
-.globl SYMBOL_NAME(ret_from_exception)
-.globl SYMBOL_NAME(ret_from_fork)
-.globl SYMBOL_NAME(ret_from_kernel_thread)
-.globl SYMBOL_NAME(ret_from_interrupt)
-.globl SYMBOL_NAME(interrupt_redirect_table)
-.globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp)
-.globl SYMBOL_NAME(resume)
-.globl SYMBOL_NAME(interrupt_entry)
-.globl SYMBOL_NAME(trace_break)
+.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
#if defined(CONFIG_ROMKERNEL)
.section .int_redirect,"ax"
-SYMBOL_NAME_LABEL(interrupt_redirect_table)
+_interrupt_redirect_table:
#if defined(CONFIG_CPU_H8300H)
.rept 7
.long 0
@@ -178,54 +178,54 @@ SYMBOL_NAME_LABEL(interrupt_redirect_table)
.rept 5
.long 0
.endr
- jmp @SYMBOL_NAME(trace_break)
+ jmp @_trace_break
.long 0
#endif
- jsr @SYMBOL_NAME(interrupt_entry) /* NMI */
- jmp @SYMBOL_NAME(system_call) /* TRAPA #0 (System call) */
+ jsr @_interrupt_entry /* NMI */
+ jmp @_system_call /* TRAPA #0 (System call) */
.long 0
.long 0
- jmp @SYMBOL_NAME(trace_break) /* TRAPA #3 (breakpoint) */
+ jmp @_trace_break /* TRAPA #3 (breakpoint) */
.rept INTERRUPTS-12
- jsr @SYMBOL_NAME(interrupt_entry)
+ jsr @_interrupt_entry
.endr
#endif
#if defined(CONFIG_RAMKERNEL)
-.globl SYMBOL_NAME(interrupt_redirect_table)
+.globl _interrupt_redirect_table
.section .bss
-SYMBOL_NAME_LABEL(interrupt_redirect_table)
+_interrupt_redirect_table:
.space 4
#endif
.section .text
.align 2
-SYMBOL_NAME_LABEL(interrupt_entry)
+_interrupt_entry:
SAVE_ALL
mov.l sp,er0
add.l #LVEC,er0
btst #4,r1l
bne 1f
/* user LVEC */
- mov.l @SYMBOL_NAME(sw_usp),er0
+ mov.l @_sw_usp,er0
adds #4,er0
1:
mov.l @er0,er0 /* LVEC address */
#if defined(CONFIG_ROMKERNEL)
- sub.l #SYMBOL_NAME(interrupt_redirect_table),er0
+ sub.l #_interrupt_redirect_table,er0
#endif
#if defined(CONFIG_RAMKERNEL)
- mov.l @SYMBOL_NAME(interrupt_redirect_table),er1
+ 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 */
- jsr @SYMBOL_NAME(do_IRQ)
- jmp @SYMBOL_NAME(ret_from_interrupt)
+ jsr @_do_IRQ
+ jmp @_ret_from_interrupt
-SYMBOL_NAME_LABEL(system_call)
+_system_call:
subs #4,sp /* dummy LVEC */
SAVE_ALL
andc #0x7f,ccr
@@ -233,21 +233,21 @@ SYMBOL_NAME_LABEL(system_call)
/* save top of frame */
mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
+ jsr @_set_esp0
mov.l sp,er2
and.w #0xe000,r2
mov.b @((TI_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
btst #(TIF_SYSCALL_TRACE & 7),r2l
beq 1f
- jsr @SYMBOL_NAME(do_syscall_trace)
+ jsr @_do_syscall_trace
1:
cmp.l #NR_syscalls,er4
bcc badsys
SHLL2 er4
- mov.l #SYMBOL_NAME(sys_call_table),er0
+ mov.l #_sys_call_table,er0
add.l er4,er0
mov.l @er0,er4
- beq SYMBOL_NAME(ret_from_exception):16
+ beq _ret_from_exception:16
mov.l @(LER1:16,sp),er0
mov.l @(LER2:16,sp),er1
mov.l @(LER3:16,sp),er2
@@ -258,10 +258,10 @@ SYMBOL_NAME_LABEL(system_call)
mov.b @((TI_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
btst #(TIF_SYSCALL_TRACE & 7),r2l
beq 2f
- jsr @SYMBOL_NAME(do_syscall_trace)
+ jsr @_do_syscall_trace
2:
#if defined(CONFIG_SYSCALL_PRINT)
- jsr @SYMBOL_NAME(syscall_print)
+ jsr @_syscall_print
#endif
orc #0x80,ccr
bra resume_userspace
@@ -275,11 +275,11 @@ badsys:
#define resume_kernel restore_all
#endif
-SYMBOL_NAME_LABEL(ret_from_exception)
+_ret_from_exception:
#if defined(CONFIG_PREEMPT)
orc #0x80,ccr
#endif
-SYMBOL_NAME_LABEL(ret_from_interrupt)
+_ret_from_interrupt:
mov.b @(LCCR+1:16,sp),r0l
btst #4,r0l
bne resume_kernel:8 /* return from kernel */
@@ -296,12 +296,12 @@ work_pending:
/* work notifysig */
mov.l sp,er0
subs #4,er0 /* er0: pt_regs */
- jsr @SYMBOL_NAME(do_notify_resume)
+ jsr @_do_notify_resume
bra restore_all:8
work_resched:
mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
- jsr @SYMBOL_NAME(schedule)
+ jsr @_set_esp0
+ jsr @_schedule
bra resume_userspace:8
restore_all:
RESTORE_ALL /* Does RTE */
@@ -320,26 +320,26 @@ need_resched:
mov.l er0,@(TI_PRE_COUNT:16,er4)
andc #0x7f,ccr
mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
- jsr @SYMBOL_NAME(schedule)
+ jsr @_set_esp0
+ jsr @_schedule
orc #0x80,ccr
bra need_resched:8
#endif
-SYMBOL_NAME_LABEL(ret_from_fork)
+_ret_from_fork:
mov.l er2,er0
- jsr @SYMBOL_NAME(schedule_tail)
- jmp @SYMBOL_NAME(ret_from_exception)
+ jsr @_schedule_tail
+ jmp @_ret_from_exception
-SYMBOL_NAME_LABEL(ret_from_kernel_thread)
+_ret_from_kernel_thread:
mov.l er2,er0
- jsr @SYMBOL_NAME(schedule_tail)
+ jsr @_schedule_tail
mov.l @(LER4:16,sp),er0
mov.l @(LER5:16,sp),er1
jsr @er1
- jmp @SYMBOL_NAME(ret_from_exception)
+ jmp @_ret_from_exception
-SYMBOL_NAME_LABEL(resume)
+_resume:
/*
* Beware - when entering resume, offset of tss is in d1,
* prev (the current task) is in a0, next (the new task)
@@ -355,7 +355,7 @@ SYMBOL_NAME_LABEL(resume)
/* disable interrupts */
orc #0x80,ccr
- mov.l @SYMBOL_NAME(sw_usp),er3
+ mov.l @_sw_usp,er3
mov.l er3,@(THREAD_USP:16,er0)
mov.l sp,@(THREAD_KSP:16,er0)
@@ -363,7 +363,7 @@ SYMBOL_NAME_LABEL(resume)
/* FIXME: what did we hack out of here, this does nothing! */
mov.l @(THREAD_USP:16,er1),er0
- mov.l er0,@SYMBOL_NAME(sw_usp)
+ mov.l er0,@_sw_usp
mov.l @(THREAD_KSP:16,er1),sp
/* restore status register */
@@ -372,15 +372,15 @@ SYMBOL_NAME_LABEL(resume)
ldc r3l,ccr
rts
-SYMBOL_NAME_LABEL(trace_break)
+_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 @SYMBOL_NAME(set_esp0)
- mov.l @SYMBOL_NAME(sw_usp),er0
+ jsr @_set_esp0
+ mov.l @_sw_usp,er0
mov.l @er0,er1
mov.w @(-2:16,er1),r2
cmp.w #0x5730,r2
@@ -390,13 +390,13 @@ SYMBOL_NAME_LABEL(trace_break)
1:
and.w #0xff,e1
mov.l er1,er0
- jsr @SYMBOL_NAME(trace_trap)
- jmp @SYMBOL_NAME(ret_from_exception)
+ jsr @_trace_trap
+ jmp @_ret_from_exception
.section .bss
-SYMBOL_NAME_LABEL(sw_ksp)
+_sw_ksp:
.space 4
-SYMBOL_NAME_LABEL(sw_usp)
+_sw_usp:
.space 4
.end
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index 5c2168fb9b9e..c55e0ed270d5 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -2,8 +2,10 @@
#include <linux/sys.h>
#include <asm/linkage.h>
#include <asm/unistd.h>
-
-.globl SYMBOL_NAME(sys_call_table)
+
+#define CALL(x) .long _ ## x
+
+.globl _sys_call_table
#if defined(CONFIG_CPU_H8300H)
.h8300h
@@ -13,324 +15,324 @@
#endif
.section .text
.align 2
-SYMBOL_NAME_LABEL(sys_call_table)
- .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
- .long SYMBOL_NAME(sys_exit)
- .long SYMBOL_NAME(sys_fork)
- .long SYMBOL_NAME(sys_read)
- .long SYMBOL_NAME(sys_write)
- .long SYMBOL_NAME(sys_open) /* 5 */
- .long SYMBOL_NAME(sys_close)
- .long SYMBOL_NAME(sys_waitpid)
- .long SYMBOL_NAME(sys_creat)
- .long SYMBOL_NAME(sys_link)
- .long SYMBOL_NAME(sys_unlink) /* 10 */
- .long SYMBOL_NAME(sys_execve)
- .long SYMBOL_NAME(sys_chdir)
- .long SYMBOL_NAME(sys_time)
- .long SYMBOL_NAME(sys_mknod)
- .long SYMBOL_NAME(sys_chmod) /* 15 */
- .long SYMBOL_NAME(sys_chown16)
- .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
- .long SYMBOL_NAME(sys_stat)
- .long SYMBOL_NAME(sys_lseek)
- .long SYMBOL_NAME(sys_getpid) /* 20 */
- .long SYMBOL_NAME(sys_mount)
- .long SYMBOL_NAME(sys_oldumount)
- .long SYMBOL_NAME(sys_setuid16)
- .long SYMBOL_NAME(sys_getuid16)
- .long SYMBOL_NAME(sys_stime) /* 25 */
- .long SYMBOL_NAME(sys_ptrace)
- .long SYMBOL_NAME(sys_alarm)
- .long SYMBOL_NAME(sys_fstat)
- .long SYMBOL_NAME(sys_pause)
- .long SYMBOL_NAME(sys_utime) /* 30 */
- .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
- .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
- .long SYMBOL_NAME(sys_access)
- .long SYMBOL_NAME(sys_nice)
- .long SYMBOL_NAME(sys_ni_syscall) /* 35 old ftime syscall holder */
- .long SYMBOL_NAME(sys_sync)
- .long SYMBOL_NAME(sys_kill)
- .long SYMBOL_NAME(sys_rename)
- .long SYMBOL_NAME(sys_mkdir)
- .long SYMBOL_NAME(sys_rmdir) /* 40 */
- .long SYMBOL_NAME(sys_dup)
- .long SYMBOL_NAME(sys_pipe)
- .long SYMBOL_NAME(sys_times)
- .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
- .long SYMBOL_NAME(sys_brk) /* 45 */
- .long SYMBOL_NAME(sys_setgid16)
- .long SYMBOL_NAME(sys_getgid16)
- .long SYMBOL_NAME(sys_signal)
- .long SYMBOL_NAME(sys_geteuid16)
- .long SYMBOL_NAME(sys_getegid16) /* 50 */
- .long SYMBOL_NAME(sys_acct)
- .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */
- .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
- .long SYMBOL_NAME(sys_ioctl)
- .long SYMBOL_NAME(sys_fcntl) /* 55 */
- .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
- .long SYMBOL_NAME(sys_setpgid)
- .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_umask) /* 60 */
- .long SYMBOL_NAME(sys_chroot)
- .long SYMBOL_NAME(sys_ustat)
- .long SYMBOL_NAME(sys_dup2)
- .long SYMBOL_NAME(sys_getppid)
- .long SYMBOL_NAME(sys_getpgrp) /* 65 */
- .long SYMBOL_NAME(sys_setsid)
- .long SYMBOL_NAME(sys_sigaction)
- .long SYMBOL_NAME(sys_sgetmask)
- .long SYMBOL_NAME(sys_ssetmask)
- .long SYMBOL_NAME(sys_setreuid16) /* 70 */
- .long SYMBOL_NAME(sys_setregid16)
- .long SYMBOL_NAME(sys_sigsuspend)
- .long SYMBOL_NAME(sys_sigpending)
- .long SYMBOL_NAME(sys_sethostname)
- .long SYMBOL_NAME(sys_setrlimit) /* 75 */
- .long SYMBOL_NAME(sys_old_getrlimit)
- .long SYMBOL_NAME(sys_getrusage)
- .long SYMBOL_NAME(sys_gettimeofday)
- .long SYMBOL_NAME(sys_settimeofday)
- .long SYMBOL_NAME(sys_getgroups16) /* 80 */
- .long SYMBOL_NAME(sys_setgroups16)
- .long SYMBOL_NAME(sys_old_select)
- .long SYMBOL_NAME(sys_symlink)
- .long SYMBOL_NAME(sys_lstat)
- .long SYMBOL_NAME(sys_readlink) /* 85 */
- .long SYMBOL_NAME(sys_uselib)
- .long SYMBOL_NAME(sys_swapon)
- .long SYMBOL_NAME(sys_reboot)
- .long SYMBOL_NAME(sys_old_readdir)
- .long SYMBOL_NAME(sys_old_mmap) /* 90 */
- .long SYMBOL_NAME(sys_munmap)
- .long SYMBOL_NAME(sys_truncate)
- .long SYMBOL_NAME(sys_ftruncate)
- .long SYMBOL_NAME(sys_fchmod)
- .long SYMBOL_NAME(sys_fchown16) /* 95 */
- .long SYMBOL_NAME(sys_getpriority)
- .long SYMBOL_NAME(sys_setpriority)
- .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
- .long SYMBOL_NAME(sys_statfs)
- .long SYMBOL_NAME(sys_fstatfs) /* 100 */
- .long SYMBOL_NAME(sys_ni_syscall) /* ioperm for i386 */
- .long SYMBOL_NAME(sys_socketcall)
- .long SYMBOL_NAME(sys_syslog)
- .long SYMBOL_NAME(sys_setitimer)
- .long SYMBOL_NAME(sys_getitimer) /* 105 */
- .long SYMBOL_NAME(sys_newstat)
- .long SYMBOL_NAME(sys_newlstat)
- .long SYMBOL_NAME(sys_newfstat)
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_ni_syscall) /* iopl for i386 */ /* 110 */
- .long SYMBOL_NAME(sys_vhangup)
- .long SYMBOL_NAME(sys_ni_syscall) /* obsolete idle() syscall */
- .long SYMBOL_NAME(sys_ni_syscall) /* vm86old for i386 */
- .long SYMBOL_NAME(sys_wait4)
- .long SYMBOL_NAME(sys_swapoff) /* 115 */
- .long SYMBOL_NAME(sys_sysinfo)
- .long SYMBOL_NAME(sys_ipc)
- .long SYMBOL_NAME(sys_fsync)
- .long SYMBOL_NAME(sys_sigreturn)
- .long SYMBOL_NAME(sys_clone) /* 120 */
- .long SYMBOL_NAME(sys_setdomainname)
- .long SYMBOL_NAME(sys_newuname)
- .long SYMBOL_NAME(sys_cacheflush) /* modify_ldt for i386 */
- .long SYMBOL_NAME(sys_adjtimex)
- .long SYMBOL_NAME(sys_ni_syscall) /* 125 sys_mprotect */
- .long SYMBOL_NAME(sys_sigprocmask)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_create_module */
- .long SYMBOL_NAME(sys_init_module)
- .long SYMBOL_NAME(sys_delete_module)
- .long SYMBOL_NAME(sys_ni_syscall) /* 130 sys_get_kernel_syms */
- .long SYMBOL_NAME(sys_quotactl)
- .long SYMBOL_NAME(sys_getpgid)
- .long SYMBOL_NAME(sys_fchdir)
- .long SYMBOL_NAME(sys_bdflush)
- .long SYMBOL_NAME(sys_sysfs) /* 135 */
- .long SYMBOL_NAME(sys_personality)
- .long SYMBOL_NAME(sys_ni_syscall) /* for afs_syscall */
- .long SYMBOL_NAME(sys_setfsuid16)
- .long SYMBOL_NAME(sys_setfsgid16)
- .long SYMBOL_NAME(sys_llseek) /* 140 */
- .long SYMBOL_NAME(sys_getdents)
- .long SYMBOL_NAME(sys_select)
- .long SYMBOL_NAME(sys_flock)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_msync */
- .long SYMBOL_NAME(sys_readv) /* 145 */
- .long SYMBOL_NAME(sys_writev)
- .long SYMBOL_NAME(sys_getsid)
- .long SYMBOL_NAME(sys_fdatasync)
- .long SYMBOL_NAME(sys_sysctl)
- .long SYMBOL_NAME(sys_ni_syscall) /* 150 sys_mlock */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_munlock */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_mlockall */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_munlockall */
- .long SYMBOL_NAME(sys_sched_setparam)
- .long SYMBOL_NAME(sys_sched_getparam) /* 155 */
- .long SYMBOL_NAME(sys_sched_setscheduler)
- .long SYMBOL_NAME(sys_sched_getscheduler)
- .long SYMBOL_NAME(sys_sched_yield)
- .long SYMBOL_NAME(sys_sched_get_priority_max)
- .long SYMBOL_NAME(sys_sched_get_priority_min) /* 160 */
- .long SYMBOL_NAME(sys_sched_rr_get_interval)
- .long SYMBOL_NAME(sys_nanosleep)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_mremap */
- .long SYMBOL_NAME(sys_setresuid16)
- .long SYMBOL_NAME(sys_getresuid16) /* 165 */
- .long SYMBOL_NAME(sys_ni_syscall) /* for vm86 */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_query_module */
- .long SYMBOL_NAME(sys_poll)
- .long SYMBOL_NAME(sys_ni_syscall) /* old nfsservctl */
- .long SYMBOL_NAME(sys_setresgid16) /* 170 */
- .long SYMBOL_NAME(sys_getresgid16)
- .long SYMBOL_NAME(sys_prctl)
- .long SYMBOL_NAME(sys_rt_sigreturn)
- .long SYMBOL_NAME(sys_rt_sigaction)
- .long SYMBOL_NAME(sys_rt_sigprocmask) /* 175 */
- .long SYMBOL_NAME(sys_rt_sigpending)
- .long SYMBOL_NAME(sys_rt_sigtimedwait)
- .long SYMBOL_NAME(sys_rt_sigqueueinfo)
- .long SYMBOL_NAME(sys_rt_sigsuspend)
- .long SYMBOL_NAME(sys_pread64) /* 180 */
- .long SYMBOL_NAME(sys_pwrite64)
- .long SYMBOL_NAME(sys_lchown16);
- .long SYMBOL_NAME(sys_getcwd)
- .long SYMBOL_NAME(sys_capget)
- .long SYMBOL_NAME(sys_capset) /* 185 */
- .long SYMBOL_NAME(sys_sigaltstack)
- .long SYMBOL_NAME(sys_sendfile)
- .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
- .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
- .long SYMBOL_NAME(sys_vfork) /* 190 */
- .long SYMBOL_NAME(sys_getrlimit)
- .long SYMBOL_NAME(sys_mmap_pgoff)
- .long SYMBOL_NAME(sys_truncate64)
- .long SYMBOL_NAME(sys_ftruncate64)
- .long SYMBOL_NAME(sys_stat64) /* 195 */
- .long SYMBOL_NAME(sys_lstat64)
- .long SYMBOL_NAME(sys_fstat64)
- .long SYMBOL_NAME(sys_chown)
- .long SYMBOL_NAME(sys_getuid)
- .long SYMBOL_NAME(sys_getgid) /* 200 */
- .long SYMBOL_NAME(sys_geteuid)
- .long SYMBOL_NAME(sys_getegid)
- .long SYMBOL_NAME(sys_setreuid)
- .long SYMBOL_NAME(sys_setregid)
- .long SYMBOL_NAME(sys_getgroups) /* 205 */
- .long SYMBOL_NAME(sys_setgroups)
- .long SYMBOL_NAME(sys_fchown)
- .long SYMBOL_NAME(sys_setresuid)
- .long SYMBOL_NAME(sys_getresuid)
- .long SYMBOL_NAME(sys_setresgid) /* 210 */
- .long SYMBOL_NAME(sys_getresgid)
- .long SYMBOL_NAME(sys_lchown)
- .long SYMBOL_NAME(sys_setuid)
- .long SYMBOL_NAME(sys_setgid)
- .long SYMBOL_NAME(sys_setfsuid) /* 215 */
- .long SYMBOL_NAME(sys_setfsgid)
- .long SYMBOL_NAME(sys_pivot_root)
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_getdents64) /* 220 */
- .long SYMBOL_NAME(sys_fcntl64)
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved TUX */
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved Security */
- .long SYMBOL_NAME(sys_gettid)
- .long SYMBOL_NAME(sys_readahead) /* 225 */
- .long SYMBOL_NAME(sys_setxattr)
- .long SYMBOL_NAME(sys_lsetxattr)
- .long SYMBOL_NAME(sys_fsetxattr)
- .long SYMBOL_NAME(sys_getxattr)
- .long SYMBOL_NAME(sys_lgetxattr) /* 230 */
- .long SYMBOL_NAME(sys_fgetxattr)
- .long SYMBOL_NAME(sys_listxattr)
- .long SYMBOL_NAME(sys_llistxattr)
- .long SYMBOL_NAME(sys_flistxattr)
- .long SYMBOL_NAME(sys_removexattr) /* 235 */
- .long SYMBOL_NAME(sys_lremovexattr)
- .long SYMBOL_NAME(sys_fremovexattr)
- .long SYMBOL_NAME(sys_tkill)
- .long SYMBOL_NAME(sys_sendfile64)
- .long SYMBOL_NAME(sys_futex) /* 240 */
- .long SYMBOL_NAME(sys_sched_setaffinity)
- .long SYMBOL_NAME(sys_sched_getaffinity)
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_io_setup) /* 245 */
- .long SYMBOL_NAME(sys_io_destroy)
- .long SYMBOL_NAME(sys_io_getevents)
- .long SYMBOL_NAME(sys_io_submit)
- .long SYMBOL_NAME(sys_io_cancel)
- .long SYMBOL_NAME(sys_fadvise64) /* 250 */
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_exit_group)
- .long SYMBOL_NAME(sys_lookup_dcookie)
- .long SYMBOL_NAME(sys_epoll_create)
- .long SYMBOL_NAME(sys_epoll_ctl) /* 255 */
- .long SYMBOL_NAME(sys_epoll_wait)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_remap_file_pages */
- .long SYMBOL_NAME(sys_set_tid_address)
- .long SYMBOL_NAME(sys_timer_create)
- .long SYMBOL_NAME(sys_timer_settime) /* 260 */
- .long SYMBOL_NAME(sys_timer_gettime)
- .long SYMBOL_NAME(sys_timer_getoverrun)
- .long SYMBOL_NAME(sys_timer_delete)
- .long SYMBOL_NAME(sys_clock_settime)
- .long SYMBOL_NAME(sys_clock_gettime) /* 265 */
- .long SYMBOL_NAME(sys_clock_getres)
- .long SYMBOL_NAME(sys_clock_nanosleep)
- .long SYMBOL_NAME(sys_statfs64)
- .long SYMBOL_NAME(sys_fstatfs64)
- .long SYMBOL_NAME(sys_tgkill) /* 270 */
- .long SYMBOL_NAME(sys_utimes)
- .long SYMBOL_NAME(sys_fadvise64_64)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_vserver */
- .long SYMBOL_NAME(sys_ni_syscall)
- .long SYMBOL_NAME(sys_get_mempolicy) /* 275 */
- .long SYMBOL_NAME(sys_set_mempolicy)
- .long SYMBOL_NAME(sys_mq_open)
- .long SYMBOL_NAME(sys_mq_unlink)
- .long SYMBOL_NAME(sys_mq_timedsend)
- .long SYMBOL_NAME(sys_mq_timedreceive) /* 280 */
- .long SYMBOL_NAME(sys_mq_notify)
- .long SYMBOL_NAME(sys_mq_getsetattr)
- .long SYMBOL_NAME(sys_waitid)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_kexec_load */
- .long SYMBOL_NAME(sys_add_key) /* 285 */
- .long SYMBOL_NAME(sys_request_key)
- .long SYMBOL_NAME(sys_keyctl)
- .long SYMBOL_NAME(sys_ioprio_set)
- .long SYMBOL_NAME(sys_ioprio_get) /* 290 */
- .long SYMBOL_NAME(sys_inotify_init)
- .long SYMBOL_NAME(sys_inotify_add_watch)
- .long SYMBOL_NAME(sys_inotify_rm_watch)
- .long SYMBOL_NAME(sys_migrate_pages)
- .long SYMBOL_NAME(sys_openat) /* 295 */
- .long SYMBOL_NAME(sys_mkdirat)
- .long SYMBOL_NAME(sys_mknodat)
- .long SYMBOL_NAME(sys_fchownat)
- .long SYMBOL_NAME(sys_futimesat)
- .long SYMBOL_NAME(sys_fstatat64) /* 300 */
- .long SYMBOL_NAME(sys_unlinkat)
- .long SYMBOL_NAME(sys_renameat)
- .long SYMBOL_NAME(sys_linkat)
- .long SYMBOL_NAME(sys_symlinkat)
- .long SYMBOL_NAME(sys_readlinkat) /* 305 */
- .long SYMBOL_NAME(sys_fchmodat)
- .long SYMBOL_NAME(sys_faccessat)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_pselect6 */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_ppoll */
- .long SYMBOL_NAME(sys_unshare) /* 310 */
- .long SYMBOL_NAME(sys_set_robust_list)
- .long SYMBOL_NAME(sys_get_robust_list)
- .long SYMBOL_NAME(sys_splice)
- .long SYMBOL_NAME(sys_sync_file_range)
- .long SYMBOL_NAME(sys_tee) /* 315 */
- .long SYMBOL_NAME(sys_vmsplice)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_move_pages */
- .long SYMBOL_NAME(sys_getcpu)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_pwait */
- .long SYMBOL_NAME(sys_setns) /* 320 */
+_sys_call_table:
+ CALL(sys_ni_syscall) /* 0 - old "setup()" system call*/
+ CALL(sys_exit)
+ CALL(sys_fork)
+ CALL(sys_read)
+ CALL(sys_write)
+ CALL(sys_open) /* 5 */
+ CALL(sys_close)
+ CALL(sys_waitpid)
+ CALL(sys_creat)
+ CALL(sys_link)
+ CALL(sys_unlink) /* 10 */
+ CALL(sys_execve)
+ CALL(sys_chdir)
+ CALL(sys_time)
+ CALL(sys_mknod)
+ CALL(sys_chmod) /* 15 */
+ CALL(sys_chown16)
+ CALL(sys_ni_syscall) /* old break syscall holder */
+ CALL(sys_stat)
+ CALL(sys_lseek)
+ CALL(sys_getpid) /* 20 */
+ CALL(sys_mount)
+ CALL(sys_oldumount)
+ CALL(sys_setuid16)
+ CALL(sys_getuid16)
+ CALL(sys_stime) /* 25 */
+ CALL(sys_ptrace)
+ CALL(sys_alarm)
+ CALL(sys_fstat)
+ CALL(sys_pause)
+ CALL(sys_utime) /* 30 */
+ CALL(sys_ni_syscall) /* old stty syscall holder */
+ CALL(sys_ni_syscall) /* old gtty syscall holder */
+ CALL(sys_access)
+ CALL(sys_nice)
+ CALL(sys_ni_syscall) /* 35 old ftime syscall holder */
+ CALL(sys_sync)
+ CALL(sys_kill)
+ CALL(sys_rename)
+ CALL(sys_mkdir)
+ CALL(sys_rmdir) /* 40 */
+ CALL(sys_dup)
+ CALL(sys_pipe)
+ CALL(sys_times)
+ CALL(sys_ni_syscall) /* old prof syscall holder */
+ CALL(sys_brk) /* 45 */
+ CALL(sys_setgid16)
+ CALL(sys_getgid16)
+ CALL(sys_signal)
+ CALL(sys_geteuid16)
+ CALL(sys_getegid16) /* 50 */
+ CALL(sys_acct)
+ CALL(sys_umount) /* recycled never used phys() */
+ CALL(sys_ni_syscall) /* old lock syscall holder */
+ CALL(sys_ioctl)
+ CALL(sys_fcntl) /* 55 */
+ CALL(sys_ni_syscall) /* old mpx syscall holder */
+ CALL(sys_setpgid)
+ CALL(sys_ni_syscall) /* old ulimit syscall holder */
+ CALL(sys_ni_syscall)
+ CALL(sys_umask) /* 60 */
+ CALL(sys_chroot)
+ CALL(sys_ustat)
+ CALL(sys_dup2)
+ CALL(sys_getppid)
+ CALL(sys_getpgrp) /* 65 */
+ CALL(sys_setsid)
+ CALL(sys_sigaction)
+ CALL(sys_sgetmask)
+ CALL(sys_ssetmask)
+ CALL(sys_setreuid16) /* 70 */
+ CALL(sys_setregid16)
+ CALL(sys_sigsuspend)
+ CALL(sys_sigpending)
+ CALL(sys_sethostname)
+ CALL(sys_setrlimit) /* 75 */
+ CALL(sys_old_getrlimit)
+ CALL(sys_getrusage)
+ CALL(sys_gettimeofday)
+ CALL(sys_settimeofday)
+ CALL(sys_getgroups16) /* 80 */
+ CALL(sys_setgroups16)
+ CALL(sys_old_select)
+ CALL(sys_symlink)
+ CALL(sys_lstat)
+ CALL(sys_readlink) /* 85 */
+ CALL(sys_uselib)
+ CALL(sys_swapon)
+ CALL(sys_reboot)
+ CALL(sys_old_readdir)
+ CALL(sys_old_mmap) /* 90 */
+ CALL(sys_munmap)
+ CALL(sys_truncate)
+ CALL(sys_ftruncate)
+ CALL(sys_fchmod)
+ CALL(sys_fchown16) /* 95 */
+ CALL(sys_getpriority)
+ CALL(sys_setpriority)
+ CALL(sys_ni_syscall) /* old profil syscall holder */
+ CALL(sys_statfs)
+ CALL(sys_fstatfs) /* 100 */
+ CALL(sys_ni_syscall) /* ioperm for i386 */
+ CALL(sys_socketcall)
+ CALL(sys_syslog)
+ CALL(sys_setitimer)
+ CALL(sys_getitimer) /* 105 */
+ CALL(sys_newstat)
+ CALL(sys_newlstat)
+ CALL(sys_newfstat)
+ CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall) /* iopl for i386 */ /* 110 */
+ CALL(sys_vhangup)
+ CALL(sys_ni_syscall) /* obsolete idle() syscall */
+ CALL(sys_ni_syscall) /* vm86old for i386 */
+ CALL(sys_wait4)
+ CALL(sys_swapoff) /* 115 */
+ CALL(sys_sysinfo)
+ CALL(sys_ipc)
+ CALL(sys_fsync)
+ CALL(sys_sigreturn)
+ CALL(sys_clone) /* 120 */
+ CALL(sys_setdomainname)
+ CALL(sys_newuname)
+ CALL(sys_cacheflush) /* modify_ldt for i386 */
+ CALL(sys_adjtimex)
+ CALL(sys_ni_syscall) /* 125 sys_mprotect */
+ CALL(sys_sigprocmask)
+ CALL(sys_ni_syscall) /* sys_create_module */
+ CALL(sys_init_module)
+ CALL(sys_delete_module)
+ CALL(sys_ni_syscall) /* 130 sys_get_kernel_syms */
+ CALL(sys_quotactl)
+ CALL(sys_getpgid)
+ CALL(sys_fchdir)
+ CALL(sys_bdflush)
+ CALL(sys_sysfs) /* 135 */
+ CALL(sys_personality)
+ CALL(sys_ni_syscall) /* for afs_syscall */
+ CALL(sys_setfsuid16)
+ CALL(sys_setfsgid16)
+ CALL(sys_llseek) /* 140 */
+ CALL(sys_getdents)
+ CALL(sys_select)
+ CALL(sys_flock)
+ CALL(sys_ni_syscall) /* sys_msync */
+ CALL(sys_readv) /* 145 */
+ CALL(sys_writev)
+ CALL(sys_getsid)
+ CALL(sys_fdatasync)
+ CALL(sys_sysctl)
+ CALL(sys_ni_syscall) /* 150 sys_mlock */
+ CALL(sys_ni_syscall) /* sys_munlock */
+ CALL(sys_ni_syscall) /* sys_mlockall */
+ CALL(sys_ni_syscall) /* sys_munlockall */
+ CALL(sys_sched_setparam)
+ CALL(sys_sched_getparam) /* 155 */
+ CALL(sys_sched_setscheduler)
+ CALL(sys_sched_getscheduler)
+ CALL(sys_sched_yield)
+ CALL(sys_sched_get_priority_max)
+ CALL(sys_sched_get_priority_min) /* 160 */
+ CALL(sys_sched_rr_get_interval)
+ CALL(sys_nanosleep)
+ CALL(sys_ni_syscall) /* sys_mremap */
+ CALL(sys_setresuid16)
+ CALL(sys_getresuid16) /* 165 */
+ CALL(sys_ni_syscall) /* for vm86 */
+ CALL(sys_ni_syscall) /* sys_query_module */
+ CALL(sys_poll)
+ CALL(sys_ni_syscall) /* old nfsservctl */
+ CALL(sys_setresgid16) /* 170 */
+ CALL(sys_getresgid16)
+ CALL(sys_prctl)
+ CALL(sys_rt_sigreturn)
+ CALL(sys_rt_sigaction)
+ CALL(sys_rt_sigprocmask) /* 175 */
+ CALL(sys_rt_sigpending)
+ CALL(sys_rt_sigtimedwait)
+ CALL(sys_rt_sigqueueinfo)
+ CALL(sys_rt_sigsuspend)
+ CALL(sys_pread64) /* 180 */
+ CALL(sys_pwrite64)
+ CALL(sys_lchown16);
+ CALL(sys_getcwd)
+ CALL(sys_capget)
+ CALL(sys_capset) /* 185 */
+ CALL(sys_sigaltstack)
+ CALL(sys_sendfile)
+ CALL(sys_ni_syscall) /* streams1 */
+ CALL(sys_ni_syscall) /* streams2 */
+ CALL(sys_vfork) /* 190 */
+ CALL(sys_getrlimit)
+ CALL(sys_mmap_pgoff)
+ CALL(sys_truncate64)
+ CALL(sys_ftruncate64)
+ CALL(sys_stat64) /* 195 */
+ CALL(sys_lstat64)
+ CALL(sys_fstat64)
+ CALL(sys_chown)
+ CALL(sys_getuid)
+ CALL(sys_getgid) /* 200 */
+ CALL(sys_geteuid)
+ CALL(sys_getegid)
+ CALL(sys_setreuid)
+ CALL(sys_setregid)
+ CALL(sys_getgroups) /* 205 */
+ CALL(sys_setgroups)
+ CALL(sys_fchown)
+ CALL(sys_setresuid)
+ CALL(sys_getresuid)
+ CALL(sys_setresgid) /* 210 */
+ CALL(sys_getresgid)
+ CALL(sys_lchown)
+ CALL(sys_setuid)
+ CALL(sys_setgid)
+ CALL(sys_setfsuid) /* 215 */
+ CALL(sys_setfsgid)
+ CALL(sys_pivot_root)
+ CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall)
+ CALL(sys_getdents64) /* 220 */
+ CALL(sys_fcntl64)
+ CALL(sys_ni_syscall) /* reserved TUX */
+ CALL(sys_ni_syscall) /* reserved Security */
+ CALL(sys_gettid)
+ CALL(sys_readahead) /* 225 */
+ CALL(sys_setxattr)
+ CALL(sys_lsetxattr)
+ CALL(sys_fsetxattr)
+ CALL(sys_getxattr)
+ CALL(sys_lgetxattr) /* 230 */
+ CALL(sys_fgetxattr)
+ CALL(sys_listxattr)
+ CALL(sys_llistxattr)
+ CALL(sys_flistxattr)
+ CALL(sys_removexattr) /* 235 */
+ CALL(sys_lremovexattr)
+ CALL(sys_fremovexattr)
+ CALL(sys_tkill)
+ CALL(sys_sendfile64)
+ CALL(sys_futex) /* 240 */
+ CALL(sys_sched_setaffinity)
+ CALL(sys_sched_getaffinity)
+ CALL(sys_ni_syscall)
+ CALL(sys_ni_syscall)
+ CALL(sys_io_setup) /* 245 */
+ CALL(sys_io_destroy)
+ CALL(sys_io_getevents)
+ CALL(sys_io_submit)
+ CALL(sys_io_cancel)
+ CALL(sys_fadvise64) /* 250 */
+ CALL(sys_ni_syscall)
+ CALL(sys_exit_group)
+ CALL(sys_lookup_dcookie)
+ CALL(sys_epoll_create)
+ CALL(sys_epoll_ctl) /* 255 */
+ CALL(sys_epoll_wait)
+ CALL(sys_ni_syscall) /* sys_remap_file_pages */
+ CALL(sys_set_tid_address)
+ CALL(sys_timer_create)
+ CALL(sys_timer_settime) /* 260 */
+ CALL(sys_timer_gettime)
+ CALL(sys_timer_getoverrun)
+ CALL(sys_timer_delete)
+ CALL(sys_clock_settime)
+ CALL(sys_clock_gettime) /* 265 */
+ CALL(sys_clock_getres)
+ CALL(sys_clock_nanosleep)
+ CALL(sys_statfs64)
+ CALL(sys_fstatfs64)
+ CALL(sys_tgkill) /* 270 */
+ CALL(sys_utimes)
+ CALL(sys_fadvise64_64)
+ CALL(sys_ni_syscall) /* sys_vserver */
+ CALL(sys_ni_syscall)
+ CALL(sys_get_mempolicy) /* 275 */
+ CALL(sys_set_mempolicy)
+ CALL(sys_mq_open)
+ CALL(sys_mq_unlink)
+ CALL(sys_mq_timedsend)
+ CALL(sys_mq_timedreceive) /* 280 */
+ CALL(sys_mq_notify)
+ CALL(sys_mq_getsetattr)
+ CALL(sys_waitid)
+ CALL(sys_ni_syscall) /* sys_kexec_load */
+ CALL(sys_add_key) /* 285 */
+ CALL(sys_request_key)
+ CALL(sys_keyctl)
+ CALL(sys_ioprio_set)
+ CALL(sys_ioprio_get) /* 290 */
+ CALL(sys_inotify_init)
+ CALL(sys_inotify_add_watch)
+ CALL(sys_inotify_rm_watch)
+ CALL(sys_migrate_pages)
+ CALL(sys_openat) /* 295 */
+ CALL(sys_mkdirat)
+ CALL(sys_mknodat)
+ CALL(sys_fchownat)
+ CALL(sys_futimesat)
+ CALL(sys_fstatat64) /* 300 */
+ CALL(sys_unlinkat)
+ CALL(sys_renameat)
+ CALL(sys_linkat)
+ CALL(sys_symlinkat)
+ CALL(sys_readlinkat) /* 305 */
+ CALL(sys_fchmodat)
+ CALL(sys_faccessat)
+ CALL(sys_ni_syscall) /* sys_pselect6 */
+ CALL(sys_ni_syscall) /* sys_ppoll */
+ CALL(sys_unshare) /* 310 */
+ CALL(sys_set_robust_list)
+ CALL(sys_get_robust_list)
+ CALL(sys_splice)
+ CALL(sys_sync_file_range)
+ CALL(sys_tee) /* 315 */
+ CALL(sys_vmsplice)
+ CALL(sys_ni_syscall) /* sys_move_pages */
+ CALL(sys_getcpu)
+ CALL(sys_ni_syscall) /* sys_epoll_pwait */
+ CALL(sys_setns) /* 320 */
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index 03d356d96e5d..3253fed42ac1 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -132,10 +132,12 @@ SECTIONS
{
. = ALIGN(0x4) ;
__sbss = . ;
+ ___bss_start = . ;
*(.bss*)
. = ALIGN(0x4) ;
*(COMMON)
. = ALIGN(0x4) ;
+ ___bss_stop = . ;
__ebss = . ;
__end = . ;
__ramstart = .;
diff --git a/arch/h8300/lib/abs.S b/arch/h8300/lib/abs.S
index cabdd46b41db..ddd1fb3d01ad 100644
--- a/arch/h8300/lib/abs.S
+++ b/arch/h8300/lib/abs.S
@@ -9,10 +9,10 @@
.h8300s
#endif
.text
-.global SYMBOL_NAME(abs)
+.global _abs
;;; int abs(int n)
-SYMBOL_NAME_LABEL(abs)
+_abs:
mov.l er0,er0
bpl 1f
neg.l er0
diff --git a/arch/h8300/lib/memcpy.S b/arch/h8300/lib/memcpy.S
index fdcbc1ee673c..cad325e2c0e8 100644
--- a/arch/h8300/lib/memcpy.S
+++ b/arch/h8300/lib/memcpy.S
@@ -10,10 +10,10 @@
#endif
.text
-.global SYMBOL_NAME(memcpy)
+.global _memcpy
;;; void *memcpy(void *to, void *from, size_t n)
-SYMBOL_NAME_LABEL(memcpy)
+_memcpy:
mov.l er2,er2
bne 1f
rts
diff --git a/arch/h8300/lib/memset.S b/arch/h8300/lib/memset.S
index 59abdf9485a5..4549a64c5b79 100644
--- a/arch/h8300/lib/memset.S
+++ b/arch/h8300/lib/memset.S
@@ -10,13 +10,13 @@
#endif
.text
-.global SYMBOL_NAME(memset)
+.global _memset
;;void *memset(*ptr, int c, size_t count)
;; ptr = er0
;; c = er1(r1l)
;; count = er2
-SYMBOL_NAME_LABEL(memset)
+_memset:
btst #0,r0l
beq 2f
diff --git a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
index ff349d70a29b..6c1251e491af 100644
--- a/arch/h8300/mm/init.c
+++ b/arch/h8300/mm/init.c
@@ -121,47 +121,27 @@ void __init paging_init(void)
void __init mem_init(void)
{
- int codek = 0, datak = 0, initk = 0;
- /* DAVIDM look at setup memory map generically with reserved area */
- unsigned long tmp;
- extern unsigned long _ramend, _ramstart;
- unsigned long len = &_ramend - &_ramstart;
- unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
- unsigned long end_mem = memory_end; /* DAVIDM - this must not include kernel stack at top */
+ unsigned long codesize = _etext - _stext;
-#ifdef DEBUG
- printk(KERN_DEBUG "Mem_init: start=%lx, end=%lx\n", start_mem, end_mem);
-#endif
+ pr_devel("Mem_init: start=%lx, end=%lx\n", memory_start, memory_end);
- end_mem &= PAGE_MASK;
- high_memory = (void *) end_mem;
-
- start_mem = PAGE_ALIGN(start_mem);
- max_mapnr = num_physpages = MAP_NR(high_memory);
+ high_memory = (void *) (memory_end & PAGE_MASK);
+ max_mapnr = MAP_NR(high_memory);
/* this will put all low memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
- codek = (_etext - _stext) >> 10;
- datak = (__bss_stop - _sdata) >> 10;
- initk = (__init_begin - __init_end) >> 10;
-
- tmp = nr_free_pages() << PAGE_SHIFT;
- printk(KERN_INFO "Memory available: %luk/%luk RAM, %luk/%luk ROM (%dk kernel code, %dk data)\n",
- tmp >> 10,
- len >> 10,
- (rom_length > 0) ? ((rom_length >> 10) - codek) : 0,
- rom_length >> 10,
- codek,
- datak
- );
+ free_all_bootmem();
+
+ mem_init_print_info(NULL);
+ if (rom_length > 0 && rom_length > codesize)
+ pr_info("Memory available: %luK/%luK ROM\n",
+ (rom_length - codesize) >> 10, rom_length >> 10);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
@@ -169,7 +149,7 @@ void
free_initmem(void)
{
#ifdef CONFIG_RAMKERNEL
- free_initmem_default(0);
+ free_initmem_default(-1);
#endif
}
diff --git a/arch/h8300/platform/h8300h/aki3068net/crt0_ram.S b/arch/h8300/platform/h8300h/aki3068net/crt0_ram.S
index ecaeb31ae9a4..b2ad0f2d0417 100644
--- a/arch/h8300/platform/h8300h/aki3068net/crt0_ram.S
+++ b/arch/h8300/platform/h8300h/aki3068net/crt0_ram.S
@@ -22,10 +22,10 @@
#define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
#endif
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global _command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300h
@@ -33,7 +33,7 @@
.file "crt0_ram.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #RAMEND,sp
ldc #0x80,ccr
@@ -59,13 +59,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(command_line),er6
+ mov.l #_command_line,er6
mov.w #512,r4
eepmov.w
/* uClinux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
@@ -107,4 +107,4 @@ __target_name:
.asciz "AE-3068"
.section .bootvec,"ax"
- jmp @SYMBOL_NAME(_start)
+ jmp @__start
diff --git a/arch/h8300/platform/h8300h/generic/crt0_ram.S b/arch/h8300/platform/h8300h/generic/crt0_ram.S
index 80d0e16a4499..5ab7d9c12910 100644
--- a/arch/h8300/platform/h8300h/generic/crt0_ram.S
+++ b/arch/h8300/platform/h8300h/generic/crt0_ram.S
@@ -22,10 +22,10 @@
#define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
#endif
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global _command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300h
@@ -33,7 +33,7 @@
.file "crt0_ram.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #RAMEND,sp
ldc #0x80,ccr
@@ -59,13 +59,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(command_line),er6
+ mov.l #_command_line,er6
mov.w #512,r4
eepmov.w
/* uClinux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
diff --git a/arch/h8300/platform/h8300h/generic/crt0_rom.S b/arch/h8300/platform/h8300h/generic/crt0_rom.S
index 120add7ca832..dda1dfa15a5e 100644
--- a/arch/h8300/platform/h8300h/generic/crt0_rom.S
+++ b/arch/h8300/platform/h8300h/generic/crt0_rom.S
@@ -12,17 +12,17 @@
#include <asm/linkage.h>
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(_command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global __command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300h
.section .text
.file "crt0_rom.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #__ramend,sp
ldc #0x80,ccr
@@ -60,13 +60,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(_command_line),er6
+ mov.l #__command_line,er6
mov.w #512,r4
eepmov.w
/* linux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
diff --git a/arch/h8300/platform/h8300h/h8max/crt0_ram.S b/arch/h8300/platform/h8300h/h8max/crt0_ram.S
index efcbefb91b67..6a0d4e2d9ec6 100644
--- a/arch/h8300/platform/h8300h/h8max/crt0_ram.S
+++ b/arch/h8300/platform/h8300h/h8max/crt0_ram.S
@@ -22,10 +22,10 @@
#define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
#endif
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global _command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300h
@@ -33,7 +33,7 @@
.file "crt0_ram.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #RAMEND,sp
ldc #0x80,ccr
@@ -59,13 +59,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(command_line),er6
+ mov.l #_command_line,er6
mov.w #512,r4
eepmov.w
/* uClinux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
@@ -107,4 +107,4 @@ __target_name:
.asciz "H8MAX"
.section .bootvec,"ax"
- jmp @SYMBOL_NAME(_start)
+ jmp @__start
diff --git a/arch/h8300/platform/h8s/edosk2674/crt0_ram.S b/arch/h8300/platform/h8s/edosk2674/crt0_ram.S
index d12b0debe478..5ed191b37cde 100644
--- a/arch/h8300/platform/h8s/edosk2674/crt0_ram.S
+++ b/arch/h8300/platform/h8s/edosk2674/crt0_ram.S
@@ -23,10 +23,10 @@
#define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
#endif
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(_command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global __command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300s
@@ -34,7 +34,7 @@
.file "crt0_ram.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #RAMEND,sp
ldc #0x80,ccr
ldc #0x00,exr
@@ -66,13 +66,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(command_line),er6
+ mov.l #_command_line,er6
mov.w #512,r4
eepmov.w
/* uClinux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
@@ -127,4 +127,4 @@ __target_name:
.asciz "EDOSK-2674"
.section .bootvec,"ax"
- jmp @SYMBOL_NAME(_start)
+ jmp @__start
diff --git a/arch/h8300/platform/h8s/edosk2674/crt0_rom.S b/arch/h8300/platform/h8s/edosk2674/crt0_rom.S
index c03d23c6fe12..06d1d7f324ca 100644
--- a/arch/h8300/platform/h8s/edosk2674/crt0_rom.S
+++ b/arch/h8300/platform/h8s/edosk2674/crt0_rom.S
@@ -13,17 +13,17 @@
#include <asm/linkage.h>
#include <asm/regs267x.h>
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(_command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global __command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300s
.section .text
.file "crt0_rom.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #__ramend,sp
ldc #0x80,ccr
ldc #0,exr
@@ -82,13 +82,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(_command_line),er6
+ mov.l #__command_line,er6
mov.w #512,r4
eepmov.w
/* linux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
diff --git a/arch/h8300/platform/h8s/generic/crt0_ram.S b/arch/h8300/platform/h8s/generic/crt0_ram.S
index b04541069976..7018915de74f 100644
--- a/arch/h8300/platform/h8s/generic/crt0_ram.S
+++ b/arch/h8300/platform/h8s/generic/crt0_ram.S
@@ -23,10 +23,10 @@
#define RAMEND CONFIG_BLKDEV_RESERVE_ADDRESS
#endif
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(_command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global __command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300s
@@ -34,7 +34,7 @@
.file "crt0_ram.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #RAMEND,sp
ldc #0x80,ccr
ldc #0x00,exr
@@ -63,13 +63,13 @@ SYMBOL_NAME_LABEL(_start)
/* copy kernel commandline */
mov.l #COMMAND_START,er5
- mov.l #SYMBOL_NAME(command_line),er6
+ mov.l #_command_line,er6
mov.w #512,r4
eepmov.w
/* uClinux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
@@ -124,4 +124,4 @@ __target_name:
.asciz "generic"
.section .bootvec,"ax"
- jmp @SYMBOL_NAME(_start)
+ jmp @__start
diff --git a/arch/h8300/platform/h8s/generic/crt0_rom.S b/arch/h8300/platform/h8s/generic/crt0_rom.S
index 95b6f2898f52..623ba7828193 100644
--- a/arch/h8300/platform/h8s/generic/crt0_rom.S
+++ b/arch/h8300/platform/h8s/generic/crt0_rom.S
@@ -13,17 +13,17 @@
#include <asm/linkage.h>
#include <asm/regs267x.h>
- .global SYMBOL_NAME(_start)
- .global SYMBOL_NAME(_command_line)
- .global SYMBOL_NAME(_platform_gpio_table)
- .global SYMBOL_NAME(_target_name)
+ .global __start
+ .global __command_line
+ .global __platform_gpio_table
+ .global __target_name
.h8300s
.section .text
.file "crt0_rom.S"
/* CPU Reset entry */
-SYMBOL_NAME_LABEL(_start)
+__start:
mov.l #__ramend,sp
ldc #0x80,ccr
ldc #0,exr
@@ -61,7 +61,7 @@ SYMBOL_NAME_LABEL(_start)
/* linux kernel start */
ldc #0x90,ccr /* running kernel */
- mov.l #SYMBOL_NAME(init_thread_union),sp
+ mov.l #_init_thread_union,sp
add.l #0x2000,sp
jsr @_start_kernel
_exit:
diff --git a/arch/hexagon/mm/init.c b/arch/hexagon/mm/init.c
index 2561d259a296..88977e42af0a 100644
--- a/arch/hexagon/mm/init.c
+++ b/arch/hexagon/mm/init.c
@@ -70,10 +70,8 @@ unsigned long long kmap_generation;
void __init mem_init(void)
{
/* No idea where this is actually declared. Seems to evade LXR. */
- totalram_pages += free_all_bootmem();
- num_physpages = bootmem_lastpg-ARCH_PFN_OFFSET;
-
- printk(KERN_INFO "totalram_pages = %ld\n", totalram_pages);
+ free_all_bootmem();
+ mem_init_print_info(NULL);
/*
* To-Do: someone somewhere should wipe out the bootmem map
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index bcda5b2d121a..d43daf192b21 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -2042,7 +2042,8 @@ sba_map_ioc_to_node(struct ioc *ioc, acpi_handle handle)
#endif
static int __init
-acpi_sba_ioc_add(struct acpi_device *device)
+acpi_sba_ioc_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
{
struct ioc *ioc;
acpi_status status;
@@ -2090,14 +2091,18 @@ static const struct acpi_device_id hp_ioc_iommu_device_ids[] = {
{"HWP0004", 0},
{"", 0},
};
-static struct acpi_driver acpi_sba_ioc_driver = {
- .name = "IOC IOMMU Driver",
- .ids = hp_ioc_iommu_device_ids,
- .ops = {
- .add = acpi_sba_ioc_add,
- },
+static struct acpi_scan_handler acpi_sba_ioc_handler = {
+ .ids = hp_ioc_iommu_device_ids,
+ .attach = acpi_sba_ioc_add,
};
+static int __init acpi_sba_ioc_init_acpi(void)
+{
+ return acpi_scan_add_handler(&acpi_sba_ioc_handler);
+}
+/* This has to run before acpi_scan_init(). */
+arch_initcall(acpi_sba_ioc_init_acpi);
+
extern struct dma_map_ops swiotlb_dma_ops;
static int __init
@@ -2122,7 +2127,10 @@ sba_init(void)
}
#endif
- acpi_bus_register_driver(&acpi_sba_ioc_driver);
+ /*
+ * ioc_list should be populated by the acpi_sba_ioc_handler's .attach()
+ * routine, but that only happens if acpi_scan_init() has already run.
+ */
if (!ioc_list) {
#ifdef CONFIG_IA64_GENERIC
/*
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 271f412bda1a..87bf9ad8cf0f 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -290,16 +290,16 @@ sys_fw_init (const char *args, int arglen)
efi_runtime->hdr.signature = EFI_RUNTIME_SERVICES_SIGNATURE;
efi_runtime->hdr.revision = EFI_RUNTIME_SERVICES_REVISION;
efi_runtime->hdr.headersize = sizeof(efi_runtime->hdr);
- efi_runtime->get_time = __pa(&fw_efi_get_time);
- efi_runtime->set_time = __pa(&efi_unimplemented);
- efi_runtime->get_wakeup_time = __pa(&efi_unimplemented);
- efi_runtime->set_wakeup_time = __pa(&efi_unimplemented);
- efi_runtime->set_virtual_address_map = __pa(&efi_unimplemented);
- efi_runtime->get_variable = __pa(&efi_unimplemented);
- efi_runtime->get_next_variable = __pa(&efi_unimplemented);
- efi_runtime->set_variable = __pa(&efi_unimplemented);
- efi_runtime->get_next_high_mono_count = __pa(&efi_unimplemented);
- efi_runtime->reset_system = __pa(&efi_reset_system);
+ efi_runtime->get_time = (void *)__pa(&fw_efi_get_time);
+ efi_runtime->set_time = (void *)__pa(&efi_unimplemented);
+ efi_runtime->get_wakeup_time = (void *)__pa(&efi_unimplemented);
+ efi_runtime->set_wakeup_time = (void *)__pa(&efi_unimplemented);
+ efi_runtime->set_virtual_address_map = (void *)__pa(&efi_unimplemented);
+ efi_runtime->get_variable = (void *)__pa(&efi_unimplemented);
+ efi_runtime->get_next_variable = (void *)__pa(&efi_unimplemented);
+ efi_runtime->set_variable = (void *)__pa(&efi_unimplemented);
+ efi_runtime->get_next_high_mono_count = (void *)__pa(&efi_unimplemented);
+ efi_runtime->reset_system = (void *)__pa(&efi_reset_system);
efi_tables->guid = SAL_SYSTEM_TABLE_GUID;
efi_tables->table = __pa(sal_systab);
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index c13064e422df..d1b04c4c95e3 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -268,7 +268,7 @@ static __inline__ int dev_is_ethdev(struct net_device *dev)
static int
simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct simeth_local *local;
struct in_device *in_dev;
struct in_ifaddr **ifap = NULL;
diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
index 331de723c676..3a428f19a001 100644
--- a/arch/ia64/hp/sim/simscsi.c
+++ b/arch/ia64/hp/sim/simscsi.c
@@ -88,8 +88,8 @@ simscsi_setup (char *s)
if (strlen(s) > MAX_ROOT_LEN) {
printk(KERN_ERR "simscsi_setup: prefix too long---using default %s\n",
simscsi_root);
- }
- simscsi_root = s;
+ } else
+ simscsi_root = s;
return 1;
}
diff --git a/arch/ia64/include/asm/pci.h b/arch/ia64/include/asm/pci.h
index 5e04b591e423..80775f55f03f 100644
--- a/arch/ia64/include/asm/pci.h
+++ b/arch/ia64/include/asm/pci.h
@@ -89,9 +89,9 @@ extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
#define pci_legacy_read platform_pci_legacy_read
#define pci_legacy_write platform_pci_legacy_write
-struct pci_window {
- struct resource resource;
- u64 offset;
+struct iospace_resource {
+ struct list_head list;
+ struct resource res;
};
struct pci_controller {
@@ -100,12 +100,10 @@ struct pci_controller {
int segment;
int node; /* nearest node with memory or -1 for global allocation */
- unsigned int windows;
- struct pci_window *window;
-
void *platform_data;
};
+
#define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata)
#define pci_domain_nr(busdev) (PCI_CONTROLLER(busdev)->segment)
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index 6b4329f18b29..d3358b760681 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -83,4 +83,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 335eb07480fe..5eb71d22c3d5 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -807,7 +807,7 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
* ACPI based hotplug CPU support
*/
#ifdef CONFIG_ACPI_HOTPLUG_CPU
-static __cpuinit
+static
int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid)
{
#ifdef CONFIG_ACPI_NUMA
@@ -882,7 +882,7 @@ __init void prefill_possible_map(void)
set_cpu_possible(i, true);
}
-static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
+static int _acpi_map_lsapic(acpi_handle handle, int *pcpu)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index f034563aeae5..51bce594eb83 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -1116,11 +1116,6 @@ efi_memmap_init(u64 *s, u64 *e)
if (!is_memory_available(md))
continue;
-#ifdef CONFIG_CRASH_DUMP
- /* saved_max_pfn should ignore max_addr= command line arg */
- if (saved_max_pfn < (efi_md_end(md) >> PAGE_SHIFT))
- saved_max_pfn = (efi_md_end(md) >> PAGE_SHIFT);
-#endif
/*
* Round ends inward to granule boundaries
* Give trimmings to uncached allocator
diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
index 2d67317a1ec2..f59c0b844e88 100644
--- a/arch/ia64/kernel/err_inject.c
+++ b/arch/ia64/kernel/err_inject.c
@@ -225,17 +225,17 @@ static struct attribute_group err_inject_attr_group = {
.name = "err_inject"
};
/* Add/Remove err_inject interface for CPU device */
-static int __cpuinit err_inject_add_dev(struct device * sys_dev)
+static int err_inject_add_dev(struct device *sys_dev)
{
return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
}
-static int __cpuinit err_inject_remove_dev(struct device * sys_dev)
+static int err_inject_remove_dev(struct device *sys_dev)
{
sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
return 0;
}
-static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
+static int err_inject_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -256,7 +256,7 @@ static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
+static struct notifier_block err_inject_cpu_notifier =
{
.notifier_call = err_inject_cpu_callback,
};
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index d7396dbb07bb..b8edfa75a83f 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -631,7 +631,7 @@ ia64_mca_register_cpev (int cpev)
* Outputs
* None
*/
-void __cpuinit
+void
ia64_mca_cmc_vector_setup (void)
{
cmcv_reg_t cmcv;
@@ -1814,7 +1814,7 @@ static struct irqaction mca_cpep_irqaction = {
* format most of the fields.
*/
-static void __cpuinit
+static void
format_mca_init_stack(void *mca_data, unsigned long offset,
const char *type, int cpu)
{
@@ -1844,7 +1844,7 @@ static void * __init_refok mca_bootmem(void)
}
/* Do per-CPU MCA-related initialization. */
-void __cpuinit
+void
ia64_mca_cpu_init(void *cpu_data)
{
void *pal_vaddr;
@@ -1896,7 +1896,7 @@ ia64_mca_cpu_init(void *cpu_data)
PAGE_KERNEL));
}
-static void __cpuinit ia64_mca_cmc_vector_adjust(void *dummy)
+static void ia64_mca_cmc_vector_adjust(void *dummy)
{
unsigned long flags;
@@ -1906,7 +1906,7 @@ static void __cpuinit ia64_mca_cmc_vector_adjust(void *dummy)
local_irq_restore(flags);
}
-static int __cpuinit mca_cpu_callback(struct notifier_block *nfb,
+static int mca_cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
@@ -1922,7 +1922,7 @@ static int __cpuinit mca_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block mca_cpu_notifier __cpuinitdata = {
+static struct notifier_block mca_cpu_notifier = {
.notifier_call = mca_cpu_callback
};
diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c
index c93420c97409..d288cde93606 100644
--- a/arch/ia64/kernel/numa.c
+++ b/arch/ia64/kernel/numa.c
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(cpu_to_node_map);
cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
EXPORT_SYMBOL(node_to_cpu_mask);
-void __cpuinit map_cpu_to_node(int cpu, int nid)
+void map_cpu_to_node(int cpu, int nid)
{
int oldnid;
if (nid < 0) { /* just initialize by zero */
@@ -51,7 +51,7 @@ void __cpuinit map_cpu_to_node(int cpu, int nid)
return;
}
-void __cpuinit unmap_cpu_from_node(int cpu, int nid)
+void unmap_cpu_from_node(int cpu, int nid)
{
WARN_ON(!cpu_isset(cpu, node_to_cpu_mask[nid]));
WARN_ON(cpu_to_node_map[cpu] != nid);
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index 2b3c2d79256f..ab333284f4b2 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -932,7 +932,7 @@ static const struct file_operations proc_palinfo_fops = {
.release = single_release,
};
-static void __cpuinit
+static void
create_palinfo_proc_entries(unsigned int cpu)
{
pal_func_cpu_u_t f;
@@ -962,7 +962,7 @@ remove_palinfo_proc_entries(unsigned int hcpu)
remove_proc_subtree(cpustr, palinfo_dir);
}
-static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
+static int palinfo_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int hotcpu = (unsigned long)hcpu;
diff --git a/arch/ia64/kernel/pci-dma.c b/arch/ia64/kernel/pci-dma.c
index 1ddcfe5ef353..992c1098c522 100644
--- a/arch/ia64/kernel/pci-dma.c
+++ b/arch/ia64/kernel/pci-dma.c
@@ -33,15 +33,6 @@ int force_iommu __read_mostly;
int iommu_pass_through;
-/* Dummy device used for NULL arguments (normally ISA). Better would
- be probably a smaller DMA mask, but this is bug-to-bug compatible
- to i386. */
-struct device fallback_dev = {
- .init_name = "fallback device",
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .dma_mask = &fallback_dev.coherent_dma_mask,
-};
-
extern struct dma_map_ops intel_dma_ops;
static int __init pci_iommu_init(void)
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 9ea25fce06d5..5a9ff1c3c3e9 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -5647,24 +5647,8 @@ pfm_proc_show_header(struct seq_file *m)
list_for_each(pos, &pfm_buffer_fmt_list) {
entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list);
- seq_printf(m, "format : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n",
- entry->fmt_uuid[0],
- entry->fmt_uuid[1],
- entry->fmt_uuid[2],
- entry->fmt_uuid[3],
- entry->fmt_uuid[4],
- entry->fmt_uuid[5],
- entry->fmt_uuid[6],
- entry->fmt_uuid[7],
- entry->fmt_uuid[8],
- entry->fmt_uuid[9],
- entry->fmt_uuid[10],
- entry->fmt_uuid[11],
- entry->fmt_uuid[12],
- entry->fmt_uuid[13],
- entry->fmt_uuid[14],
- entry->fmt_uuid[15],
- entry->fmt_name);
+ seq_printf(m, "format : %16phD %s\n",
+ entry->fmt_uuid, entry->fmt_name);
}
spin_unlock(&pfm_buffer_fmt_lock);
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index 4bc580af67b3..960a396f5929 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -568,7 +568,7 @@ static const struct file_operations salinfo_data_fops = {
.llseek = default_llseek,
};
-static int __cpuinit
+static int
salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
{
unsigned int i, cpu = (unsigned long)hcpu;
@@ -609,7 +609,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
return NOTIFY_OK;
}
-static struct notifier_block salinfo_cpu_notifier __cpuinitdata =
+static struct notifier_block salinfo_cpu_notifier =
{
.notifier_call = salinfo_cpu_callback,
.priority = 0,
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 13bfdd22afc8..4fc2e9569bb2 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -748,7 +748,7 @@ const struct seq_operations cpuinfo_op = {
#define MAX_BRANDS 8
static char brandname[MAX_BRANDS][128];
-static char * __cpuinit
+static char *
get_model_name(__u8 family, __u8 model)
{
static int overflow;
@@ -778,7 +778,7 @@ get_model_name(__u8 family, __u8 model)
return "Unknown";
}
-static void __cpuinit
+static void
identify_cpu (struct cpuinfo_ia64 *c)
{
union {
@@ -850,7 +850,7 @@ identify_cpu (struct cpuinfo_ia64 *c)
* 2. the minimum of the i-cache stride sizes for "flush_icache_range()".
* 3. the minimum of the cache stride sizes for "clflush_cache_range()".
*/
-static void __cpuinit
+static void
get_cache_info(void)
{
unsigned long line_size, max = 1;
@@ -915,10 +915,10 @@ get_cache_info(void)
* cpu_init() initializes state that is per-CPU. This function acts
* as a 'CPU state barrier', nothing should get across.
*/
-void __cpuinit
+void
cpu_init (void)
{
- extern void __cpuinit ia64_mmu_init (void *);
+ extern void ia64_mmu_init(void *);
static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG;
unsigned long num_phys_stacked;
pal_vm_info_2_u_t vmi;
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 8d87168d218d..547a48d78bd7 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -351,7 +351,7 @@ static inline void smp_setup_percpu_timer(void)
{
}
-static void __cpuinit
+static void
smp_callin (void)
{
int cpuid, phys_id, itc_master;
@@ -442,7 +442,7 @@ smp_callin (void)
/*
* Activate a secondary processor. head.S calls this.
*/
-int __cpuinit
+int
start_secondary (void *unused)
{
/* Early console may use I/O ports */
@@ -459,7 +459,7 @@ start_secondary (void *unused)
return 0;
}
-static int __cpuinit
+static int
do_boot_cpu (int sapicid, int cpu, struct task_struct *idle)
{
int timeout;
@@ -728,7 +728,7 @@ static inline void set_cpu_sibling_map(int cpu)
}
}
-int __cpuinit
+int
__cpu_up(unsigned int cpu, struct task_struct *tidle)
{
int ret;
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index dc00b2c1b42a..ca69a5a96dcc 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -135,11 +135,11 @@ struct cpu_cache_info {
struct kobject kobj;
};
-static struct cpu_cache_info all_cpu_cache_info[NR_CPUS] __cpuinitdata;
+static struct cpu_cache_info all_cpu_cache_info[NR_CPUS];
#define LEAF_KOBJECT_PTR(x,y) (&all_cpu_cache_info[x].cache_leaves[y])
#ifdef CONFIG_SMP
-static void __cpuinit cache_shared_cpu_map_setup( unsigned int cpu,
+static void cache_shared_cpu_map_setup(unsigned int cpu,
struct cache_info * this_leaf)
{
pal_cache_shared_info_t csi;
@@ -174,7 +174,7 @@ static void __cpuinit cache_shared_cpu_map_setup( unsigned int cpu,
&csi) == PAL_STATUS_SUCCESS);
}
#else
-static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu,
+static void cache_shared_cpu_map_setup(unsigned int cpu,
struct cache_info * this_leaf)
{
cpu_set(cpu, this_leaf->shared_cpu_map);
@@ -298,7 +298,7 @@ static struct kobj_type cache_ktype_percpu_entry = {
.sysfs_ops = &cache_sysfs_ops,
};
-static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu)
+static void cpu_cache_sysfs_exit(unsigned int cpu)
{
kfree(all_cpu_cache_info[cpu].cache_leaves);
all_cpu_cache_info[cpu].cache_leaves = NULL;
@@ -307,7 +307,7 @@ static void __cpuinit cpu_cache_sysfs_exit(unsigned int cpu)
return;
}
-static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu)
+static int cpu_cache_sysfs_init(unsigned int cpu)
{
unsigned long i, levels, unique_caches;
pal_cache_config_info_t cci;
@@ -351,7 +351,7 @@ static int __cpuinit cpu_cache_sysfs_init(unsigned int cpu)
}
/* Add cache interface for CPU device */
-static int __cpuinit cache_add_dev(struct device * sys_dev)
+static int cache_add_dev(struct device *sys_dev)
{
unsigned int cpu = sys_dev->id;
unsigned long i, j;
@@ -401,7 +401,7 @@ static int __cpuinit cache_add_dev(struct device * sys_dev)
}
/* Remove cache interface for CPU device */
-static int __cpuinit cache_remove_dev(struct device * sys_dev)
+static int cache_remove_dev(struct device *sys_dev)
{
unsigned int cpu = sys_dev->id;
unsigned long i;
@@ -425,7 +425,7 @@ static int __cpuinit cache_remove_dev(struct device * sys_dev)
* When a cpu is hot-plugged, do a check and initiate
* cache kobject if necessary
*/
-static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
+static int cache_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -445,7 +445,7 @@ static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata cache_cpu_notifier =
+static struct notifier_block cache_cpu_notifier =
{
.notifier_call = cache_cpu_callback
};
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index f7f9f9c6caf0..d3636e67a98e 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -630,7 +630,7 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
printk(KERN_ERR " iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx\n",
iip, ifa, isr);
force_sig(SIGSEGV, current);
- break;
+ return;
case 46:
printk(KERN_ERR "Unexpected IA-32 intercept trap (Trap 46)\n");
diff --git a/arch/ia64/kvm/Makefile b/arch/ia64/kvm/Makefile
index 1a4053789d01..18e45ec49bbf 100644
--- a/arch/ia64/kvm/Makefile
+++ b/arch/ia64/kvm/Makefile
@@ -47,12 +47,13 @@ FORCE : $(obj)/$(offsets-file)
ccflags-y := -Ivirt/kvm -Iarch/ia64/kvm/
asflags-y := -Ivirt/kvm -Iarch/ia64/kvm/
+KVM := ../../../virt/kvm
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
- coalesced_mmio.o irq_comm.o)
+common-objs = $(KVM)/kvm_main.o $(KVM)/ioapic.o \
+ $(KVM)/coalesced_mmio.o $(KVM)/irq_comm.o
ifeq ($(CONFIG_KVM_DEVICE_ASSIGNMENT),y)
-common-objs += $(addprefix ../../../virt/kvm/, assigned-dev.o iommu.o)
+common-objs += $(KVM)/assigned-dev.o $(KVM)/iommu.o
endif
kvm-objs := $(common-objs) kvm-ia64.o kvm_fw.o
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 67c59ebec899..da5237d636d6 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -156,8 +156,7 @@ static void *cpu_data;
*
* Allocate and setup per-cpu data areas.
*/
-void * __cpuinit
-per_cpu_init (void)
+void *per_cpu_init(void)
{
static bool first_time = true;
void *cpu0_data = __cpu0_per_cpu;
@@ -295,14 +294,6 @@ find_memory (void)
alloc_per_cpu_data();
}
-static int count_pages(u64 start, u64 end, void *arg)
-{
- unsigned long *count = arg;
-
- *count += (end - start) >> PAGE_SHIFT;
- return 0;
-}
-
/*
* Set up the page tables.
*/
@@ -313,9 +304,6 @@ paging_init (void)
unsigned long max_dma;
unsigned long max_zone_pfns[MAX_NR_ZONES];
- num_physpages = 0;
- efi_memmap_walk(count_pages, &num_physpages);
-
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
#ifdef CONFIG_ZONE_DMA
max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index ae4db4bd6d97..2de08f4d9930 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -37,7 +37,6 @@ struct early_node_data {
struct ia64_node_data *node_data;
unsigned long pernode_addr;
unsigned long pernode_size;
- unsigned long num_physpages;
#ifdef CONFIG_ZONE_DMA
unsigned long num_dma_physpages;
#endif
@@ -593,7 +592,7 @@ void __init find_memory(void)
* find_pernode_space() does most of this already, we just need to set
* local_per_cpu_offset
*/
-void __cpuinit *per_cpu_init(void)
+void *per_cpu_init(void)
{
int cpu;
static int first_time = 1;
@@ -732,7 +731,6 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
{
unsigned long end = start + len;
- mem_data[node].num_physpages += len >> PAGE_SHIFT;
#ifdef CONFIG_ZONE_DMA
if (start <= __pa(MAX_DMA_ADDRESS))
mem_data[node].num_dma_physpages +=
@@ -778,7 +776,6 @@ void __init paging_init(void)
#endif
for_each_online_node(node) {
- num_physpages += mem_data[node].num_physpages;
pfn_offset = mem_data[node].min_pfn;
#ifdef CONFIG_VIRTUAL_MEM_MAP
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index d1fe4b402601..b6f7f43424ec 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -154,9 +154,8 @@ ia64_init_addr_space (void)
void
free_initmem (void)
{
- free_reserved_area((unsigned long)ia64_imva(__init_begin),
- (unsigned long)ia64_imva(__init_end),
- 0, "unused kernel");
+ free_reserved_area(ia64_imva(__init_begin), ia64_imva(__init_end),
+ -1, "unused kernel");
}
void __init
@@ -546,19 +545,6 @@ int __init register_active_ranges(u64 start, u64 len, int nid)
return 0;
}
-static int __init
-count_reserved_pages(u64 start, u64 end, void *arg)
-{
- unsigned long num_reserved = 0;
- unsigned long *count = arg;
-
- for (; start < end; start += PAGE_SIZE)
- if (PageReserved(virt_to_page(start)))
- ++num_reserved;
- *count += num_reserved;
- return 0;
-}
-
int
find_max_min_low_pfn (u64 start, u64 end, void *arg)
{
@@ -597,8 +583,6 @@ __setup("nolwsys", nolwsys_setup);
void __init
mem_init (void)
{
- long reserved_pages, codesize, datasize, initsize;
- pg_data_t *pgdat;
int i;
BUG_ON(PTRS_PER_PGD * sizeof(pgd_t) != PAGE_SIZE);
@@ -616,27 +600,12 @@ mem_init (void)
#ifdef CONFIG_FLATMEM
BUG_ON(!mem_map);
- max_mapnr = max_low_pfn;
#endif
+ set_max_mapnr(max_low_pfn);
high_memory = __va(max_low_pfn * PAGE_SIZE);
-
- for_each_online_pgdat(pgdat)
- if (pgdat->bdata->node_bootmem_map)
- totalram_pages += free_all_bootmem_node(pgdat);
-
- reserved_pages = 0;
- efi_memmap_walk(count_reserved_pages, &reserved_pages);
-
- codesize = (unsigned long) _etext - (unsigned long) _stext;
- datasize = (unsigned long) _edata - (unsigned long) _etext;
- initsize = (unsigned long) __init_end - (unsigned long) __init_begin;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%luk code, %luk reserved, "
- "%luk data, %luk init)\n", nr_free_pages() << (PAGE_SHIFT - 10),
- num_physpages << (PAGE_SHIFT - 10), codesize >> 10,
- reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10);
-
+ free_all_bootmem();
+ mem_init_print_info(NULL);
/*
* For fsyscall entrpoints with no light-weight handler, use the ordinary
diff --git a/arch/ia64/mm/numa.c b/arch/ia64/mm/numa.c
index 4248492b9321..ea21d4cad540 100644
--- a/arch/ia64/mm/numa.c
+++ b/arch/ia64/mm/numa.c
@@ -86,7 +86,7 @@ int __meminit __early_pfn_to_nid(unsigned long pfn)
return -1;
}
-void __cpuinit numa_clear_node(int cpu)
+void numa_clear_node(int cpu)
{
unmap_cpu_from_node(cpu, NUMA_NO_NODE);
}
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index de1474ff0bc5..2326790b7d8b 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -134,6 +134,10 @@ struct pci_root_info {
struct acpi_device *bridge;
struct pci_controller *controller;
struct list_head resources;
+ struct resource *res;
+ resource_size_t *res_offset;
+ unsigned int res_num;
+ struct list_head io_resources;
char *name;
};
@@ -153,7 +157,7 @@ new_space (u64 phys_base, int sparse)
return i;
if (num_io_spaces == MAX_IO_SPACES) {
- printk(KERN_ERR "PCI: Too many IO port spaces "
+ pr_err("PCI: Too many IO port spaces "
"(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES);
return ~0;
}
@@ -168,25 +172,22 @@ new_space (u64 phys_base, int sparse)
static u64 add_io_space(struct pci_root_info *info,
struct acpi_resource_address64 *addr)
{
+ struct iospace_resource *iospace;
struct resource *resource;
char *name;
unsigned long base, min, max, base_port;
unsigned int sparse = 0, space_nr, len;
- resource = kzalloc(sizeof(*resource), GFP_KERNEL);
- if (!resource) {
- printk(KERN_ERR "PCI: No memory for %s I/O port space\n",
- info->name);
+ len = strlen(info->name) + 32;
+ iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL);
+ if (!iospace) {
+ dev_err(&info->bridge->dev,
+ "PCI: No memory for %s I/O port space\n",
+ info->name);
goto out;
}
- len = strlen(info->name) + 32;
- name = kzalloc(len, GFP_KERNEL);
- if (!name) {
- printk(KERN_ERR "PCI: No memory for %s I/O port space name\n",
- info->name);
- goto free_resource;
- }
+ name = (char *)(iospace + 1);
min = addr->minimum;
max = min + addr->address_length - 1;
@@ -195,7 +196,7 @@ static u64 add_io_space(struct pci_root_info *info,
space_nr = new_space(addr->translation_offset, sparse);
if (space_nr == ~0)
- goto free_name;
+ goto free_resource;
base = __pa(io_space[space_nr].mmio_base);
base_port = IO_SPACE_BASE(space_nr);
@@ -210,18 +211,23 @@ static u64 add_io_space(struct pci_root_info *info,
if (space_nr == 0)
sparse = 1;
+ resource = &iospace->res;
resource->name = name;
resource->flags = IORESOURCE_MEM;
resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
- insert_resource(&iomem_resource, resource);
+ if (insert_resource(&iomem_resource, resource)) {
+ dev_err(&info->bridge->dev,
+ "can't allocate host bridge io space resource %pR\n",
+ resource);
+ goto free_resource;
+ }
+ list_add_tail(&iospace->list, &info->io_resources);
return base_port;
-free_name:
- kfree(name);
free_resource:
- kfree(resource);
+ kfree(iospace);
out:
return ~0;
}
@@ -265,7 +271,7 @@ static acpi_status count_window(struct acpi_resource *resource, void *data)
static acpi_status add_window(struct acpi_resource *res, void *data)
{
struct pci_root_info *info = data;
- struct pci_window *window;
+ struct resource *resource;
struct acpi_resource_address64 addr;
acpi_status status;
unsigned long flags, offset = 0;
@@ -289,55 +295,146 @@ static acpi_status add_window(struct acpi_resource *res, void *data)
} else
return AE_OK;
- window = &info->controller->window[info->controller->windows++];
- window->resource.name = info->name;
- window->resource.flags = flags;
- window->resource.start = addr.minimum + offset;
- window->resource.end = window->resource.start + addr.address_length - 1;
- window->offset = offset;
+ resource = &info->res[info->res_num];
+ resource->name = info->name;
+ resource->flags = flags;
+ resource->start = addr.minimum + offset;
+ resource->end = resource->start + addr.address_length - 1;
+ info->res_offset[info->res_num] = offset;
- if (insert_resource(root, &window->resource)) {
+ if (insert_resource(root, resource)) {
dev_err(&info->bridge->dev,
"can't allocate host bridge window %pR\n",
- &window->resource);
+ resource);
} else {
if (offset)
dev_info(&info->bridge->dev, "host bridge window %pR "
"(PCI address [%#llx-%#llx])\n",
- &window->resource,
- window->resource.start - offset,
- window->resource.end - offset);
+ resource,
+ resource->start - offset,
+ resource->end - offset);
else
dev_info(&info->bridge->dev,
- "host bridge window %pR\n",
- &window->resource);
+ "host bridge window %pR\n", resource);
}
-
/* HP's firmware has a hack to work around a Windows bug.
* Ignore these tiny memory ranges */
- if (!((window->resource.flags & IORESOURCE_MEM) &&
- (window->resource.end - window->resource.start < 16)))
- pci_add_resource_offset(&info->resources, &window->resource,
- window->offset);
+ if (!((resource->flags & IORESOURCE_MEM) &&
+ (resource->end - resource->start < 16)))
+ pci_add_resource_offset(&info->resources, resource,
+ info->res_offset[info->res_num]);
+ info->res_num++;
return AE_OK;
}
+static void free_pci_root_info_res(struct pci_root_info *info)
+{
+ struct iospace_resource *iospace, *tmp;
+
+ list_for_each_entry_safe(iospace, tmp, &info->io_resources, list)
+ kfree(iospace);
+
+ kfree(info->name);
+ kfree(info->res);
+ info->res = NULL;
+ kfree(info->res_offset);
+ info->res_offset = NULL;
+ info->res_num = 0;
+ kfree(info->controller);
+ info->controller = NULL;
+}
+
+static void __release_pci_root_info(struct pci_root_info *info)
+{
+ int i;
+ struct resource *res;
+ struct iospace_resource *iospace;
+
+ list_for_each_entry(iospace, &info->io_resources, list)
+ release_resource(&iospace->res);
+
+ for (i = 0; i < info->res_num; i++) {
+ res = &info->res[i];
+
+ if (!res->parent)
+ continue;
+
+ if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
+ continue;
+
+ release_resource(res);
+ }
+
+ free_pci_root_info_res(info);
+ kfree(info);
+}
+
+static void release_pci_root_info(struct pci_host_bridge *bridge)
+{
+ struct pci_root_info *info = bridge->release_data;
+
+ __release_pci_root_info(info);
+}
+
+static int
+probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
+ int busnum, int domain)
+{
+ char *name;
+
+ name = kmalloc(16, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ sprintf(name, "PCI Bus %04x:%02x", domain, busnum);
+ info->bridge = device;
+ info->name = name;
+
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
+ &info->res_num);
+ if (info->res_num) {
+ info->res =
+ kzalloc_node(sizeof(*info->res) * info->res_num,
+ GFP_KERNEL, info->controller->node);
+ if (!info->res) {
+ kfree(name);
+ return -ENOMEM;
+ }
+
+ info->res_offset =
+ kzalloc_node(sizeof(*info->res_offset) * info->res_num,
+ GFP_KERNEL, info->controller->node);
+ if (!info->res_offset) {
+ kfree(name);
+ kfree(info->res);
+ info->res = NULL;
+ return -ENOMEM;
+ }
+
+ info->res_num = 0;
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+ add_window, info);
+ } else
+ kfree(name);
+
+ return 0;
+}
+
struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_device *device = root->device;
int domain = root->segment;
int bus = root->secondary.start;
struct pci_controller *controller;
- unsigned int windows = 0;
- struct pci_root_info info;
+ struct pci_root_info *info = NULL;
+ int busnum = root->secondary.start;
struct pci_bus *pbus;
- char *name;
- int pxm;
+ int pxm, ret;
controller = alloc_pci_controller(domain);
if (!controller)
- goto out1;
+ return NULL;
controller->acpi_handle = device->handle;
@@ -347,29 +444,27 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
controller->node = pxm_to_node(pxm);
#endif
- INIT_LIST_HEAD(&info.resources);
- /* insert busn resource at first */
- pci_add_resource(&info.resources, &root->secondary);
- acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
- &windows);
- if (windows) {
- controller->window =
- kzalloc_node(sizeof(*controller->window) * windows,
- GFP_KERNEL, controller->node);
- if (!controller->window)
- goto out2;
-
- name = kmalloc(16, GFP_KERNEL);
- if (!name)
- goto out3;
-
- sprintf(name, "PCI Bus %04x:%02x", domain, bus);
- info.bridge = device;
- info.controller = controller;
- info.name = name;
- acpi_walk_resources(device->handle, METHOD_NAME__CRS,
- add_window, &info);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&device->dev,
+ "pci_bus %04x:%02x: ignored (out of memory)\n",
+ domain, busnum);
+ kfree(controller);
+ return NULL;
}
+
+ info->controller = controller;
+ INIT_LIST_HEAD(&info->io_resources);
+ INIT_LIST_HEAD(&info->resources);
+
+ ret = probe_pci_root_info(info, device, busnum, domain);
+ if (ret) {
+ kfree(info->controller);
+ kfree(info);
+ return NULL;
+ }
+ /* insert busn resource at first */
+ pci_add_resource(&info->resources, &root->secondary);
/*
* See arch/x86/pci/acpi.c.
* The desired pci bus might already be scanned in a quirk. We
@@ -377,21 +472,17 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
* such quirk. So we just ignore the case now.
*/
pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller,
- &info.resources);
+ &info->resources);
if (!pbus) {
- pci_free_resource_list(&info.resources);
+ pci_free_resource_list(&info->resources);
+ __release_pci_root_info(info);
return NULL;
}
+ pci_set_host_bridge_release(to_pci_host_bridge(pbus->bridge),
+ release_pci_root_info, info);
pci_scan_child_bus(pbus);
return pbus;
-
-out3:
- kfree(controller->window);
-out2:
- kfree(controller);
-out1:
- return NULL;
}
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
@@ -691,7 +782,7 @@ static void __init set_pci_dfl_cacheline_size(void)
status = ia64_pal_cache_summary(&levels, &unique_caches);
if (status != 0) {
- printk(KERN_ERR "%s: ia64_pal_cache_summary() failed "
+ pr_err("%s: ia64_pal_cache_summary() failed "
"(status=%ld)\n", __func__, status);
return;
}
@@ -699,7 +790,7 @@ static void __init set_pci_dfl_cacheline_size(void)
status = ia64_pal_cache_config_info(levels - 1,
/* cache_type (data_or_unified)= */ 2, &cci);
if (status != 0) {
- printk(KERN_ERR "%s: ia64_pal_cache_config_info() failed "
+ pr_err("%s: ia64_pal_cache_config_info() failed "
"(status=%ld)\n", __func__, status);
return;
}
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 238e2c511d94..0b5ce82d203d 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -118,76 +118,26 @@ static void __init sn_fixup_ionodes(void)
}
/*
- * sn_pci_legacy_window_fixup - Create PCI controller windows for
+ * sn_pci_legacy_window_fixup - Setup PCI resources for
* legacy IO and MEM space. This needs to
* be done here, as the PROM does not have
* ACPI support defining the root buses
* and their resources (_CRS),
*/
static void
-sn_legacy_pci_window_fixup(struct pci_controller *controller,
- u64 legacy_io, u64 legacy_mem)
+sn_legacy_pci_window_fixup(struct resource *res,
+ u64 legacy_io, u64 legacy_mem)
{
- controller->window = kcalloc(2, sizeof(struct pci_window),
- GFP_KERNEL);
- BUG_ON(controller->window == NULL);
- controller->window[0].offset = legacy_io;
- controller->window[0].resource.name = "legacy_io";
- controller->window[0].resource.flags = IORESOURCE_IO;
- controller->window[0].resource.start = legacy_io;
- controller->window[0].resource.end =
- controller->window[0].resource.start + 0xffff;
- controller->window[0].resource.parent = &ioport_resource;
- controller->window[1].offset = legacy_mem;
- controller->window[1].resource.name = "legacy_mem";
- controller->window[1].resource.flags = IORESOURCE_MEM;
- controller->window[1].resource.start = legacy_mem;
- controller->window[1].resource.end =
- controller->window[1].resource.start + (1024 * 1024) - 1;
- controller->window[1].resource.parent = &iomem_resource;
- controller->windows = 2;
-}
-
-/*
- * sn_pci_window_fixup() - Create a pci_window for each device resource.
- * It will setup pci_windows for use by
- * pcibios_bus_to_resource(), pcibios_resource_to_bus(),
- * etc.
- */
-static void
-sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
- s64 * pci_addrs)
-{
- struct pci_controller *controller = PCI_CONTROLLER(dev->bus);
- unsigned int i;
- unsigned int idx;
- unsigned int new_count;
- struct pci_window *new_window;
-
- if (count == 0)
- return;
- idx = controller->windows;
- new_count = controller->windows + count;
- new_window = kcalloc(new_count, sizeof(struct pci_window), GFP_KERNEL);
- BUG_ON(new_window == NULL);
- if (controller->window) {
- memcpy(new_window, controller->window,
- sizeof(struct pci_window) * controller->windows);
- kfree(controller->window);
- }
-
- /* Setup a pci_window for each device resource. */
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- if (pci_addrs[i] == -1)
- continue;
-
- new_window[idx].offset = dev->resource[i].start - pci_addrs[i];
- new_window[idx].resource = dev->resource[i];
- idx++;
- }
-
- controller->windows = new_count;
- controller->window = new_window;
+ res[0].name = "legacy_io";
+ res[0].flags = IORESOURCE_IO;
+ res[0].start = legacy_io;
+ res[0].end = res[0].start + 0xffff;
+ res[0].parent = &ioport_resource;
+ res[1].name = "legacy_mem";
+ res[1].flags = IORESOURCE_MEM;
+ res[1].start = legacy_mem;
+ res[1].end = res[1].start + (1024 * 1024) - 1;
+ res[1].parent = &iomem_resource;
}
/*
@@ -199,9 +149,7 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
void
sn_io_slot_fixup(struct pci_dev *dev)
{
- unsigned int count = 0;
int idx;
- s64 pci_addrs[PCI_ROM_RESOURCE + 1];
unsigned long addr, end, size, start;
struct pcidev_info *pcidev_info;
struct sn_irq_info *sn_irq_info;
@@ -229,7 +177,6 @@ sn_io_slot_fixup(struct pci_dev *dev)
for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
if (!pcidev_info->pdi_pio_mapped_addr[idx]) {
- pci_addrs[idx] = -1;
continue;
}
@@ -237,11 +184,8 @@ sn_io_slot_fixup(struct pci_dev *dev)
end = dev->resource[idx].end;
size = end - start;
if (size == 0) {
- pci_addrs[idx] = -1;
continue;
}
- pci_addrs[idx] = start;
- count++;
addr = pcidev_info->pdi_pio_mapped_addr[idx];
addr = ((addr << 4) >> 4) | __IA64_UNCACHED_OFFSET;
dev->resource[idx].start = addr;
@@ -276,11 +220,6 @@ sn_io_slot_fixup(struct pci_dev *dev)
IORESOURCE_ROM_BIOS_COPY;
}
}
- /* Create a pci_window in the pci_controller struct for
- * each device resource.
- */
- if (count > 0)
- sn_pci_window_fixup(dev, count, pci_addrs);
sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
}
@@ -297,8 +236,8 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
s64 status = 0;
struct pci_controller *controller;
struct pcibus_bussoft *prom_bussoft_ptr;
+ struct resource *res;
LIST_HEAD(resources);
- int i;
status = sal_get_pcibus_info((u64) segment, (u64) busnum,
(u64) ia64_tpa(&prom_bussoft_ptr));
@@ -310,32 +249,29 @@ sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
BUG_ON(!controller);
controller->segment = segment;
+ res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
+ BUG_ON(!res);
+
/*
* Temporarily save the prom_bussoft_ptr for use by sn_bus_fixup().
* (platform_data will be overwritten later in sn_common_bus_fixup())
*/
controller->platform_data = prom_bussoft_ptr;
- sn_legacy_pci_window_fixup(controller,
- prom_bussoft_ptr->bs_legacy_io,
- prom_bussoft_ptr->bs_legacy_mem);
- for (i = 0; i < controller->windows; i++)
- pci_add_resource_offset(&resources,
- &controller->window[i].resource,
- controller->window[i].offset);
+ sn_legacy_pci_window_fixup(res,
+ prom_bussoft_ptr->bs_legacy_io,
+ prom_bussoft_ptr->bs_legacy_mem);
+ pci_add_resource_offset(&resources, &res[0],
+ prom_bussoft_ptr->bs_legacy_io);
+ pci_add_resource_offset(&resources, &res[1],
+ prom_bussoft_ptr->bs_legacy_mem);
+
bus = pci_scan_root_bus(NULL, busnum, &pci_root_ops, controller,
&resources);
- if (bus == NULL)
- goto error_return; /* error, or bus already scanned */
-
- bus->sysdata = controller;
-
- return;
-
-error_return:
-
- kfree(controller);
- return;
+ if (bus == NULL) {
+ kfree(res);
+ kfree(controller);
+ }
}
/*
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index f82e7b462b7b..53b01b8e2f19 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -192,7 +192,7 @@ void __init early_sn_setup(void)
}
extern int platform_intr_list[];
-static int __cpuinitdata shub_1_1_found;
+static int shub_1_1_found;
/*
* sn_check_for_wars
@@ -200,7 +200,7 @@ static int __cpuinitdata shub_1_1_found;
* Set flag for enabling shub specific wars
*/
-static inline int __cpuinit is_shub_1_1(int nasid)
+static inline int is_shub_1_1(int nasid)
{
unsigned long id;
int rev;
@@ -212,7 +212,7 @@ static inline int __cpuinit is_shub_1_1(int nasid)
return rev <= 2;
}
-static void __cpuinit sn_check_for_wars(void)
+static void sn_check_for_wars(void)
{
int cnode;
@@ -558,7 +558,7 @@ static void __init sn_init_pdas(char **cmdline_p)
* Also sets up a few fields in the nodepda. Also known as
* platform_cpu_init() by the ia64 machvec code.
*/
-void __cpuinit sn_cpu_init(void)
+void sn_cpu_init(void)
{
int cpuid;
int cpuphyid;
diff --git a/arch/ia64/xen/hypervisor.c b/arch/ia64/xen/hypervisor.c
index 52172eee8591..fab62528a80b 100644
--- a/arch/ia64/xen/hypervisor.c
+++ b/arch/ia64/xen/hypervisor.c
@@ -74,7 +74,7 @@ void __init xen_setup_vcpu_info_placement(void)
xen_vcpu_setup(cpu);
}
-void __cpuinit
+void
xen_cpu_init(void)
{
xen_smp_intr_init();
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index bcd17b206571..29a7ef4e448b 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -16,6 +16,7 @@ config M32R
select GENERIC_ATOMIC64
select ARCH_USES_GETTIMEOFFSET
select MODULES_USE_ELF_RELA
+ select HAVE_DEBUG_STACKOVERFLOW
config SBUS
bool
diff --git a/arch/m32r/Kconfig.debug b/arch/m32r/Kconfig.debug
index bb1afc1a31cc..6c612b7691b0 100644
--- a/arch/m32r/Kconfig.debug
+++ b/arch/m32r/Kconfig.debug
@@ -2,13 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config DEBUG_PAGEALLOC
bool "Debug page memory allocations"
depends on DEBUG_KERNEL && BROKEN
diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h
index 2a3b59e0e171..44aaf4639a4a 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -74,4 +74,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c
index 2c468e8b5853..27196303ce36 100644
--- a/arch/m32r/mm/discontig.c
+++ b/arch/m32r/mm/discontig.c
@@ -129,11 +129,10 @@ unsigned long __init setup_memory(void)
#define START_PFN(nid) (NODE_DATA(nid)->bdata->node_min_pfn)
#define MAX_LOW_PFN(nid) (NODE_DATA(nid)->bdata->node_low_pfn)
-unsigned long __init zone_sizes_init(void)
+void __init zone_sizes_init(void)
{
unsigned long zones_size[MAX_NR_ZONES], zholes_size[MAX_NR_ZONES];
unsigned long low, start_pfn;
- unsigned long holes = 0;
int nid, i;
mem_prof_t *mp;
@@ -147,7 +146,6 @@ unsigned long __init zone_sizes_init(void)
low = MAX_LOW_PFN(nid);
zones_size[ZONE_DMA] = low - start_pfn;
zholes_size[ZONE_DMA] = mp->holes;
- holes += zholes_size[ZONE_DMA];
node_set_state(nid, N_NORMAL_MEMORY);
free_area_init_node(nid, zones_size, start_pfn, zholes_size);
@@ -161,6 +159,4 @@ unsigned long __init zone_sizes_init(void)
NODE_DATA(1)->node_zones->watermark[WMARK_MIN] = 0;
NODE_DATA(1)->node_zones->watermark[WMARK_LOW] = 0;
NODE_DATA(1)->node_zones->watermark[WMARK_HIGH] = 0;
-
- return holes;
}
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
index ab4cbce91a9b..0d4146f644dc 100644
--- a/arch/m32r/mm/init.c
+++ b/arch/m32r/mm/init.c
@@ -40,7 +40,6 @@ unsigned long mmu_context_cache_dat;
#else
unsigned long mmu_context_cache_dat[NR_CPUS];
#endif
-static unsigned long hole_pages;
/*
* function prototype
@@ -57,7 +56,7 @@ void free_initrd_mem(unsigned long, unsigned long);
#define MAX_LOW_PFN(nid) (NODE_DATA(nid)->bdata->node_low_pfn)
#ifndef CONFIG_DISCONTIGMEM
-unsigned long __init zone_sizes_init(void)
+void __init zone_sizes_init(void)
{
unsigned long zones_size[MAX_NR_ZONES] = {0, };
unsigned long max_dma;
@@ -83,11 +82,9 @@ unsigned long __init zone_sizes_init(void)
#endif /* CONFIG_MMU */
free_area_init_node(0, zones_size, start_pfn, 0);
-
- return 0;
}
#else /* CONFIG_DISCONTIGMEM */
-extern unsigned long zone_sizes_init(void);
+extern void zone_sizes_init(void);
#endif /* CONFIG_DISCONTIGMEM */
/*======================================================================*
@@ -105,24 +102,7 @@ void __init paging_init(void)
for (i = 0 ; i < USER_PTRS_PER_PGD * 2 ; i++)
pgd_val(pg_dir[i]) = 0;
#endif /* CONFIG_MMU */
- hole_pages = zone_sizes_init();
-}
-
-int __init reservedpages_count(void)
-{
- int reservedpages, nid, i;
-
- reservedpages = 0;
- for_each_online_node(nid) {
- unsigned long flags;
- pgdat_resize_lock(NODE_DATA(nid), &flags);
- for (i = 0 ; i < MAX_LOW_PFN(nid) - START_PFN(nid) ; i++)
- if (PageReserved(nid_page_nr(nid, i)))
- reservedpages++;
- pgdat_resize_unlock(NODE_DATA(nid), &flags);
- }
-
- return reservedpages;
+ zone_sizes_init();
}
/*======================================================================*
@@ -131,48 +111,20 @@ int __init reservedpages_count(void)
*======================================================================*/
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
- int nid;
#ifndef CONFIG_MMU
extern unsigned long memory_end;
-#endif
-
- num_physpages = 0;
- for_each_online_node(nid)
- num_physpages += MAX_LOW_PFN(nid) - START_PFN(nid) + 1;
-
- num_physpages -= hole_pages;
-#ifndef CONFIG_DISCONTIGMEM
- max_mapnr = num_physpages;
-#endif /* CONFIG_DISCONTIGMEM */
-
-#ifdef CONFIG_MMU
- high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0)));
-#else
high_memory = (void *)(memory_end & PAGE_MASK);
+#else
+ high_memory = (void *)__va(PFN_PHYS(MAX_LOW_PFN(0)));
#endif /* CONFIG_MMU */
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
- /* this will put all low memory onto the freelists */
- for_each_online_node(nid)
- totalram_pages += free_all_bootmem_node(NODE_DATA(nid));
-
- reservedpages = reservedpages_count() - hole_pages;
- codesize = (unsigned long) &_etext - (unsigned long)&_text;
- datasize = (unsigned long) &_edata - (unsigned long)&_etext;
- initsize = (unsigned long) &__init_end - (unsigned long)&__init_begin;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
- "%dk reserved, %dk data, %dk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10);
+ set_max_mapnr(get_num_physpages());
+ free_all_bootmem();
+ mem_init_print_info(NULL);
}
/*======================================================================*
@@ -181,7 +133,7 @@ void __init mem_init(void)
*======================================================================*/
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -191,6 +143,6 @@ void free_initmem(void)
*======================================================================*/
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/m68k/Kconfig.debug b/arch/m68k/Kconfig.debug
index fa12283d58fc..229682721240 100644
--- a/arch/m68k/Kconfig.debug
+++ b/arch/m68k/Kconfig.debug
@@ -11,9 +11,8 @@ config BOOTPARAM_STRING
depends on BOOTPARAM
config EARLY_PRINTK
- bool "Early printk" if EMBEDDED
+ bool "Early printk"
depends on MVME16x || MAC
- default y
help
Write kernel log output directly to a serial port.
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 0f795d8e65fa..b17a8837f0e1 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -214,6 +214,7 @@ CONFIG_DEVTMPFS=y
# CONFIG_FW_LOADER_USER_HELPER is not set
CONFIG_CONNECTOR=m
CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
CONFIG_PARPORT_AMIGA=m
CONFIG_PARPORT_MFC3=m
CONFIG_PARPORT_ATARI=m
@@ -325,6 +326,7 @@ CONFIG_ZORRO8390=y
# CONFIG_NET_VENDOR_SEEQ is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PLIP=m
CONFIG_PPP=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_DEFLATE=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 8982370e8b42..be1496ed9b66 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -199,6 +199,9 @@ CONFIG_DEVTMPFS=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
# CONFIG_FW_LOADER_USER_HELPER is not set
CONFIG_CONNECTOR=m
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_1284=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
@@ -267,6 +270,7 @@ CONFIG_NE2000=m
# CONFIG_NET_VENDOR_SMSC is not set
# CONFIG_NET_VENDOR_STMICRO is not set
# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PLIP=m
CONFIG_PPP=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_DEFLATE=m
@@ -292,9 +296,11 @@ CONFIG_SERIO_Q40KBD=y
CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
+CONFIG_PRINTER=m
# CONFIG_HW_RANDOM is not set
CONFIG_NTP_PPS=y
CONFIG_PPS_CLIENT_LDISC=m
+CONFIG_PPS_CLIENT_PARPORT=m
CONFIG_PTP_1588_CLOCK=m
# CONFIG_HWMON is not set
CONFIG_FB=y
diff --git a/arch/m68k/include/asm/parport.h b/arch/m68k/include/asm/parport.h
index 5ea75e6a7399..c85cece778e8 100644
--- a/arch/m68k/include/asm/parport.h
+++ b/arch/m68k/include/asm/parport.h
@@ -11,6 +11,8 @@
#ifndef _ASM_M68K_PARPORT_H
#define _ASM_M68K_PARPORT_H 1
+#undef insl
+#undef outsl
#define insl(port,buf,len) isa_insb(port,buf,(len)<<2)
#define outsl(port,buf,len) isa_outsb(port,buf,(len)<<2)
diff --git a/arch/m68k/include/asm/string.h b/arch/m68k/include/asm/string.h
index 9aea9f11fa25..c30c03d98581 100644
--- a/arch/m68k/include/asm/string.h
+++ b/arch/m68k/include/asm/string.h
@@ -4,20 +4,6 @@
#include <linux/types.h>
#include <linux/compiler.h>
-static inline char *__kernel_strcpy(char *dest, const char *src)
-{
- char *xdest = dest;
-
- asm volatile ("\n"
- "1: move.b (%1)+,(%0)+\n"
- " jne 1b"
- : "+a" (dest), "+a" (src)
- : : "memory");
- return xdest;
-}
-
-#ifndef __IN_STRING_C
-
#define __HAVE_ARCH_STRNLEN
static inline size_t strnlen(const char *s, size_t count)
{
@@ -34,16 +20,6 @@ static inline size_t strnlen(const char *s, size_t count)
return sc - s;
}
-#define __HAVE_ARCH_STRCPY
-#if __GNUC__ >= 4
-#define strcpy(d, s) (__builtin_constant_p(s) && \
- __builtin_strlen(s) <= 32 ? \
- __builtin_strcpy(d, s) : \
- __kernel_strcpy(d, s))
-#else
-#define strcpy(d, s) __kernel_strcpy(d, s)
-#endif
-
#define __HAVE_ARCH_STRNCPY
static inline char *strncpy(char *dest, const char *src, size_t n)
{
@@ -61,12 +37,6 @@ static inline char *strncpy(char *dest, const char *src, size_t n)
return xdest;
}
-#define __HAVE_ARCH_STRCAT
-#define strcat(d, s) ({ \
- char *__d = (d); \
- strcpy(__d + strlen(__d), (s)); \
-})
-
#ifndef CONFIG_COLDFIRE
#define __HAVE_ARCH_STRCMP
static inline int strcmp(const char *cs, const char *ct)
@@ -100,6 +70,4 @@ extern void *memset(void *, int, __kernel_size_t);
extern void *memcpy(void *, const void *, __kernel_size_t);
#define memcpy(d, s, n) __builtin_memcpy(d, s, n)
-#endif
-
#endif /* _M68K_STRING_H_ */
diff --git a/arch/m68k/include/asm/uaccess_mm.h b/arch/m68k/include/asm/uaccess_mm.h
index 472c891a4aee..15901db435b9 100644
--- a/arch/m68k/include/asm/uaccess_mm.h
+++ b/arch/m68k/include/asm/uaccess_mm.h
@@ -90,7 +90,7 @@ asm volatile ("\n" \
__put_user_asm(__pu_err, __pu_val, ptr, b, d, -EFAULT); \
break; \
case 2: \
- __put_user_asm(__pu_err, __pu_val, ptr, w, d, -EFAULT); \
+ __put_user_asm(__pu_err, __pu_val, ptr, w, r, -EFAULT); \
break; \
case 4: \
__put_user_asm(__pu_err, __pu_val, ptr, l, r, -EFAULT); \
@@ -158,7 +158,7 @@ asm volatile ("\n" \
__get_user_asm(__gu_err, x, ptr, u8, b, d, -EFAULT); \
break; \
case 2: \
- __get_user_asm(__gu_err, x, ptr, u16, w, d, -EFAULT); \
+ __get_user_asm(__gu_err, x, ptr, u16, w, r, -EFAULT); \
break; \
case 4: \
__get_user_asm(__gu_err, x, ptr, u32, l, r, -EFAULT); \
@@ -245,7 +245,7 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
__get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1);
break;
case 2:
- __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2);
+ __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, r, 2);
break;
case 3:
__constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
@@ -326,7 +326,7 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
__put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
break;
case 2:
- __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2);
+ __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, r, 2);
break;
case 3:
__constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index a972b00cd77d..8b7b22846366 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -77,7 +77,7 @@ int main(void)
DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
DEFINE(BIR_DATA, offsetof(struct bi_record, data));
- /* offsets into font_desc (drivers/video/console/font.h) */
+ /* offsets into the font_desc struct */
DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 6b32b64bac35..4d7da384eea0 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -101,7 +101,7 @@ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt)
BUG_ON(IRQ_USER + cnt > NR_IRQS);
m68k_first_user_vec = vec;
for (i = 0; i < cnt; i++)
- irq_set_chip(IRQ_USER + i, &user_irq_chip);
+ irq_set_chip_and_handler(i, &user_irq_chip, handle_simple_irq);
*user_irqvec_fixup = vec - IRQ_USER;
flush_icache();
}
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index a9d782d34276..fcd8eb1d7c7d 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -6,7 +6,7 @@
lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
memcpy.o memset.o memmove.o
-lib-$(CONFIG_MMU) += string.o uaccess.o
+lib-$(CONFIG_MMU) += uaccess.o
lib-$(CONFIG_CPU_HAS_NO_MULDIV64) += mulsi3.o divsi3.o udivsi3.o
lib-$(CONFIG_CPU_HAS_NO_MULDIV64) += modsi3.o umodsi3.o
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
deleted file mode 100644
index 4d61fa8a112c..000000000000
--- a/arch/m68k/lib/string.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * 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.
- */
-
-#define __IN_STRING_C
-
-#include <linux/module.h>
-#include <linux/string.h>
-
-char *strcpy(char *dest, const char *src)
-{
- return __kernel_strcpy(dest, src);
-}
-EXPORT_SYMBOL(strcpy);
-
-char *strcat(char *dest, const char *src)
-{
- return __kernel_strcpy(dest + strlen(dest), src);
-}
-EXPORT_SYMBOL(strcat);
diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c
index 5e97f2ee7c11..35d1442dee89 100644
--- a/arch/m68k/lib/uaccess.c
+++ b/arch/m68k/lib/uaccess.c
@@ -52,7 +52,7 @@ unsigned long __generic_copy_from_user(void *to, const void __user *from,
" .long 3b,30b\n"
" .long 5b,50b\n"
" .previous"
- : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
+ : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp)
: "0" (n / 4), "d" (n & 3));
return res;
@@ -96,7 +96,7 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from,
" .long 7b,50b\n"
" .long 8b,50b\n"
" .previous"
- : "=d" (res), "+a" (from), "+a" (to), "=&r" (tmp)
+ : "=d" (res), "+a" (from), "+a" (to), "=&d" (tmp)
: "0" (n / 4), "d" (n & 3));
return res;
@@ -141,7 +141,7 @@ unsigned long __clear_user(void __user *to, unsigned long n)
" .long 7b,40b\n"
" .previous"
: "=d" (res), "+a" (to)
- : "r" (0), "0" (n / 4), "d" (n & 3));
+ : "d" (0), "0" (n / 4), "d" (n & 3));
return res;
}
diff --git a/arch/m68k/math-emu/fp_arith.c b/arch/m68k/math-emu/fp_arith.c
index 08f286db3c5a..239eb1990184 100644
--- a/arch/m68k/math-emu/fp_arith.c
+++ b/arch/m68k/math-emu/fp_arith.c
@@ -519,7 +519,7 @@ static void fp_roundint(struct fp_ext *dest, int mode)
return;
break;
case 0x401e:
- if (!(oldmant.m32[1] >= 0))
+ if (oldmant.m32[1] & 0x80000000)
return;
if (oldmant.m32[0] & 1)
break;
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index 1af2ca3411f6..6b4baa6e4d31 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -110,7 +110,7 @@ void __init paging_init(void)
void free_initmem(void)
{
#ifndef CONFIG_MMU_SUN3
- free_initmem_default(0);
+ free_initmem_default(-1);
#endif /* CONFIG_MMU_SUN3 */
}
@@ -146,38 +146,11 @@ void __init print_memmap(void)
MLK_ROUNDUP(__bss_start, __bss_stop));
}
-void __init mem_init(void)
+static inline void init_pointer_tables(void)
{
- pg_data_t *pgdat;
- int codepages = 0;
- int datapages = 0;
- int initpages = 0;
+#if defined(CONFIG_MMU) && !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
int i;
- /* this will put all memory onto the freelists */
- totalram_pages = num_physpages = 0;
- for_each_online_pgdat(pgdat) {
- num_physpages += pgdat->node_present_pages;
-
- totalram_pages += free_all_bootmem_node(pgdat);
- for (i = 0; i < pgdat->node_spanned_pages; i++) {
- struct page *page = pgdat->node_mem_map + i;
- char *addr = page_to_virt(page);
-
- if (!PageReserved(page))
- continue;
- if (addr >= _text &&
- addr < _etext)
- codepages++;
- else if (addr >= __init_begin &&
- addr < __init_end)
- initpages++;
- else
- datapages++;
- }
- }
-
-#if defined(CONFIG_MMU) && !defined(CONFIG_SUN3) && !defined(CONFIG_COLDFIRE)
/* insert pointer tables allocated so far into the tablelist */
init_pointer_table((unsigned long)kernel_pg_dir);
for (i = 0; i < PTRS_PER_PGD; i++) {
@@ -189,19 +162,20 @@ void __init mem_init(void)
if (zero_pgtable)
init_pointer_table((unsigned long)zero_pgtable);
#endif
+}
- pr_info("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- totalram_pages << (PAGE_SHIFT-10),
- codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10),
- initpages << (PAGE_SHIFT-10));
+void __init mem_init(void)
+{
+ /* this will put all memory onto the freelists */
+ free_all_bootmem();
+ init_pointer_tables();
+ mem_init_print_info(NULL);
print_memmap();
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/m68k/platform/coldfire/pci.c b/arch/m68k/platform/coldfire/pci.c
index 8572246db84d..b33f97a13e6d 100644
--- a/arch/m68k/platform/coldfire/pci.c
+++ b/arch/m68k/platform/coldfire/pci.c
@@ -320,7 +320,6 @@ static int __init mcf_pci_init(void)
pci_bus_size_bridges(rootbus);
pci_bus_assign_resources(rootbus);
pci_enable_bridges(rootbus);
- pci_bus_add_devices(rootbus);
return 0;
}
diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c
index ca0966cac72a..cab54482ca34 100644
--- a/arch/m68k/sun3/sun3dvma.c
+++ b/arch/m68k/sun3/sun3dvma.c
@@ -275,7 +275,7 @@ void dvma_init(void)
}
-inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
+unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
{
unsigned long baddr;
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig
index dcd94406030e..cfd831c29824 100644
--- a/arch/metag/Kconfig
+++ b/arch/metag/Kconfig
@@ -30,6 +30,7 @@ config METAG
select OF
select OF_EARLY_FLATTREE
select SPARSE_IRQ
+ select HAVE_DEBUG_STACKOVERFLOW
config STACKTRACE_SUPPORT
def_bool y
diff --git a/arch/metag/Kconfig.debug b/arch/metag/Kconfig.debug
index e45bbf6a7a5d..cb5c92860540 100644
--- a/arch/metag/Kconfig.debug
+++ b/arch/metag/Kconfig.debug
@@ -6,13 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
depends on DEBUG_KERNEL
diff --git a/arch/metag/Kconfig.soc b/arch/metag/Kconfig.soc
index ec079cfb7c6a..2a3c860c7525 100644
--- a/arch/metag/Kconfig.soc
+++ b/arch/metag/Kconfig.soc
@@ -14,6 +14,18 @@ config META21_FPGA
help
This is a Meta 2.1 FPGA bitstream, just a bare CPU.
+config SOC_TZ1090
+ bool "Toumaz Xenif TZ1090 SoC (Comet)"
+ select METAG_LNKGET_AROUND_CACHE
+ select METAG_META21
+ select METAG_SMP_WRITE_REORDERING
+ select PINCTRL
+ select PINCTRL_TZ1090
+ select PINCTRL_TZ1090_PDC
+ help
+ This is a Toumaz Technology Xenif TZ1090 (A.K.A. Comet) SoC containing
+ a 2-threaded HTP.
+
endchoice
menu "SoC configuration"
diff --git a/arch/metag/Makefile b/arch/metag/Makefile
index b566116b171b..9739857bdedc 100644
--- a/arch/metag/Makefile
+++ b/arch/metag/Makefile
@@ -20,7 +20,7 @@ checkflags-$(CONFIG_METAG_META12) += -DMETAC_1_2
checkflags-$(CONFIG_METAG_META21) += -DMETAC_2_1
CHECKFLAGS += -D__metag__ $(checkflags-y)
-KBUILD_DEFCONFIG := meta2_defconfig
+KBUILD_DEFCONFIG := tz1090_defconfig
sflags-$(CONFIG_METAG_META12) += -mmetac=1.2
ifeq ($(CONFIG_METAG_META12),y)
diff --git a/arch/metag/boot/.gitignore b/arch/metag/boot/.gitignore
index a021da201156..2d6c0c160884 100644
--- a/arch/metag/boot/.gitignore
+++ b/arch/metag/boot/.gitignore
@@ -1,4 +1,4 @@
vmlinux*
uImage*
ramdisk.*
-*.dtb
+*.dtb*
diff --git a/arch/metag/boot/dts/Makefile b/arch/metag/boot/dts/Makefile
index dbd95217733a..72c121879426 100644
--- a/arch/metag/boot/dts/Makefile
+++ b/arch/metag/boot/dts/Makefile
@@ -1,7 +1,9 @@
dtb-y += skeleton.dtb
+dtb-y += tz1090_generic.dtb
# Built-in dtb
builtindtb-y := skeleton
+builtindtb-$(CONFIG_SOC_TZ1090) := tz1090_generic
ifneq ($(CONFIG_METAG_BUILTIN_DTB_NAME),"")
builtindtb-y := $(patsubst "%",%,$(CONFIG_METAG_BUILTIN_DTB_NAME))
diff --git a/arch/metag/boot/dts/include/dt-bindings b/arch/metag/boot/dts/include/dt-bindings
new file mode 120000
index 000000000000..08c00e4972fa
--- /dev/null
+++ b/arch/metag/boot/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../../include/dt-bindings \ No newline at end of file
diff --git a/arch/metag/boot/dts/skeleton.dts b/arch/metag/boot/dts/skeleton.dts
index 7244d1f0d555..7a49aeb365d0 100644
--- a/arch/metag/boot/dts/skeleton.dts
+++ b/arch/metag/boot/dts/skeleton.dts
@@ -7,4 +7,4 @@
*/
/dts-v1/;
-/include/ "skeleton.dtsi"
+#include "skeleton.dtsi"
diff --git a/arch/metag/boot/dts/tz1090.dtsi b/arch/metag/boot/dts/tz1090.dtsi
new file mode 100644
index 000000000000..853744652b93
--- /dev/null
+++ b/arch/metag/boot/dts/tz1090.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 Imagination Technologies 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 "skeleton.dtsi"
+
+/ {
+ compatible = "toumaz,tz1090", "img,meta";
+
+ interrupt-parent = <&intc>;
+
+ intc: interrupt-controller {
+ compatible = "img,meta-intc";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ num-banks = <2>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pinctrl: pinctrl@02005800 {
+ #gpio-range-cells = <3>;
+ compatible = "img,tz1090-pinctrl";
+ reg = <0x02005800 0xe4>;
+ };
+
+ pdc_pinctrl: pinctrl@02006500 {
+ #gpio-range-cells = <3>;
+ compatible = "img,tz1090-pdc-pinctrl";
+ reg = <0x02006500 0x100>;
+ };
+ };
+};
diff --git a/arch/metag/boot/dts/tz1090_generic.dts b/arch/metag/boot/dts/tz1090_generic.dts
new file mode 100644
index 000000000000..f96090955964
--- /dev/null
+++ b/arch/metag/boot/dts/tz1090_generic.dts
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2012 Imagination Technologies 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.
+ */
+/dts-v1/;
+
+#include "tz1090.dtsi"
diff --git a/arch/metag/configs/tz1090_defconfig b/arch/metag/configs/tz1090_defconfig
new file mode 100644
index 000000000000..9f9316a6df27
--- /dev/null
+++ b/arch/metag/configs/tz1090_defconfig
@@ -0,0 +1,42 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+CONFIG_SLAB=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_SOC_TZ1090=y
+CONFIG_METAG_HALT_ON_PANIC=y
+# CONFIG_METAG_FPU is not set
+CONFIG_METAG_DA=y
+CONFIG_HZ_100=y
+CONFIG_DEVTMPFS=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_DA_TTY=y
+CONFIG_DA_CONSOLE=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIOLIB=y
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_DEBUG_INFO=y
diff --git a/arch/metag/include/asm/bug.h b/arch/metag/include/asm/bug.h
index d04b48cefecc..9f8967f10f8c 100644
--- a/arch/metag/include/asm/bug.h
+++ b/arch/metag/include/asm/bug.h
@@ -6,7 +6,7 @@
struct pt_regs;
extern const char *trap_name(int trapno);
-extern void die(const char *str, struct pt_regs *regs, long err,
- unsigned long addr) __attribute__ ((noreturn));
+extern void __noreturn die(const char *str, struct pt_regs *regs, long err,
+ unsigned long addr);
#endif
diff --git a/arch/metag/include/asm/checksum.h b/arch/metag/include/asm/checksum.h
index 999bf761a732..08dd1cc65799 100644
--- a/arch/metag/include/asm/checksum.h
+++ b/arch/metag/include/asm/checksum.h
@@ -64,7 +64,8 @@ static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
__wsum sum)
{
unsigned long len_proto = (proto + len) << 8;
- asm ("ADD %0, %0, %1\n"
+ asm ("ADDS %0, %0, %1\n"
+ "ADDCS %0, %0, #1\n"
"ADDS %0, %0, %2\n"
"ADDCS %0, %0, #1\n"
"ADDS %0, %0, %3\n"
diff --git a/arch/metag/include/asm/clock.h b/arch/metag/include/asm/clock.h
index 3e2915a280c7..ded4ab2e1fd0 100644
--- a/arch/metag/include/asm/clock.h
+++ b/arch/metag/include/asm/clock.h
@@ -19,6 +19,8 @@
* core frequency will be determined like this:
* Meta 1: based on loops_per_jiffy.
* Meta 2: (EXPAND_TIMER_DIV + 1) MHz.
+ * If a "core" clock is provided by the device tree, it
+ * will override this function.
*/
struct meta_clock_desc {
unsigned long (*get_core_freq)(void);
@@ -27,6 +29,12 @@ struct meta_clock_desc {
extern struct meta_clock_desc _meta_clock;
/*
+ * Perform platform clock initialisation, reading clocks from device tree etc.
+ * Only accessible during boot.
+ */
+void init_metag_clocks(void);
+
+/*
* Set up the default clock, ensuring all callbacks are valid - only accessible
* during boot.
*/
diff --git a/arch/metag/include/asm/irq.h b/arch/metag/include/asm/irq.h
index be0c8f3c5a5d..ad6bd0edbc3b 100644
--- a/arch/metag/include/asm/irq.h
+++ b/arch/metag/include/asm/irq.h
@@ -17,6 +17,7 @@ struct pt_regs;
int tbisig_map(unsigned int hw);
extern void do_IRQ(int irq, struct pt_regs *regs);
+extern void init_IRQ(void);
#ifdef CONFIG_METAG_SUSPEND_MEM
int traps_save_context(void);
diff --git a/arch/metag/include/asm/processor.h b/arch/metag/include/asm/processor.h
index 9b029a7911c3..f16477d1f571 100644
--- a/arch/metag/include/asm/processor.h
+++ b/arch/metag/include/asm/processor.h
@@ -199,4 +199,6 @@ extern void (*soc_halt)(void);
extern void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs);
+extern const struct seq_operations cpuinfo_op;
+
#endif
diff --git a/arch/metag/kernel/cachepart.c b/arch/metag/kernel/cachepart.c
index 954548b1bea8..0a2385fa2a1d 100644
--- a/arch/metag/kernel/cachepart.c
+++ b/arch/metag/kernel/cachepart.c
@@ -100,22 +100,23 @@ void check_for_cache_aliasing(int thread_id)
thread_cache_size =
get_thread_cache_size(cache_type, thread_id);
if (thread_cache_size < 0)
- pr_emerg("Can't read %s cache size", \
+ pr_emerg("Can't read %s cache size\n",
cache_type ? "DCACHE" : "ICACHE");
else if (thread_cache_size == 0)
/* Cache is off. No need to check for aliasing */
continue;
if (thread_cache_size / CACHE_ASSOCIATIVITY > PAGE_SIZE) {
- pr_emerg("Cache aliasing detected in %s on Thread %d",
+ pr_emerg("Potential cache aliasing detected in %s on Thread %d\n",
cache_type ? "DCACHE" : "ICACHE", thread_id);
- pr_warn("Total %s size: %u bytes",
- cache_type ? "DCACHE" : "ICACHE ",
+ pr_warn("Total %s size: %u bytes\n",
+ cache_type ? "DCACHE" : "ICACHE",
cache_type ? get_dcache_size()
: get_icache_size());
- pr_warn("Thread %s size: %d bytes",
+ pr_warn("Thread %s size: %d bytes\n",
cache_type ? "CACHE" : "ICACHE",
thread_cache_size);
- pr_warn("Page Size: %lu bytes", PAGE_SIZE);
+ pr_warn("Page Size: %lu bytes\n", PAGE_SIZE);
+ panic("Potential cache aliasing detected");
}
}
}
diff --git a/arch/metag/kernel/clock.c b/arch/metag/kernel/clock.c
index defc84056f18..6339c9c6d0ab 100644
--- a/arch/metag/kernel/clock.c
+++ b/arch/metag/kernel/clock.c
@@ -8,8 +8,10 @@
* published by the Free Software Foundation.
*/
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <asm/param.h>
#include <asm/clock.h>
@@ -34,8 +36,63 @@ static unsigned long get_core_freq_default(void)
#endif
}
+static struct clk *clk_core;
+
+/* Clk based get_core_freq callback. */
+static unsigned long get_core_freq_clk(void)
+{
+ return clk_get_rate(clk_core);
+}
+
+/**
+ * init_metag_core_clock() - Set up core clock from devicetree.
+ *
+ * Checks to see if a "core" clock is provided in the device tree, and overrides
+ * the get_core_freq callback to use it.
+ */
+static void __init init_metag_core_clock(void)
+{
+ /*
+ * See if a core clock is provided by the devicetree (and
+ * registered by the init callback above).
+ */
+ struct device_node *node;
+ node = of_find_compatible_node(NULL, NULL, "img,meta");
+ if (!node) {
+ pr_warn("%s: no compatible img,meta DT node found\n",
+ __func__);
+ return;
+ }
+
+ clk_core = of_clk_get_by_name(node, "core");
+ if (IS_ERR(clk_core)) {
+ pr_warn("%s: no core clock found in DT\n",
+ __func__);
+ return;
+ }
+
+ /*
+ * Override the core frequency callback to use
+ * this clk.
+ */
+ _meta_clock.get_core_freq = get_core_freq_clk;
+}
+
+/**
+ * init_metag_clocks() - Set up clocks from devicetree.
+ *
+ * Set up important clocks from device tree. In particular any needed for clock
+ * sources.
+ */
+void __init init_metag_clocks(void)
+{
+ init_metag_core_clock();
+
+ pr_info("Core clock frequency: %lu Hz\n", get_coreclock());
+}
+
/**
- * setup_meta_clocks() - Set up the Meta clock.
+ * setup_meta_clocks() - Early set up of the Meta clock.
* @desc: Clock descriptor usually provided by machine description
*
* Ensures all callbacks are valid.
diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c
index 87707efeb0a3..2a2c9d55187e 100644
--- a/arch/metag/kernel/irq.c
+++ b/arch/metag/kernel/irq.c
@@ -25,7 +25,7 @@ static union irq_ctx *hardirq_ctx[NR_CPUS] __read_mostly;
static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
#endif
-struct irq_domain *root_domain;
+static struct irq_domain *root_domain;
static unsigned int startup_meta_irq(struct irq_data *data)
{
@@ -279,11 +279,12 @@ static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irq_chip *chip = irq_data_get_irq_chip(data);
+ unsigned long flags;
- raw_spin_lock_irq(&desc->lock);
+ raw_spin_lock_irqsave(&desc->lock, flags);
if (chip->irq_set_affinity)
chip->irq_set_affinity(data, cpumask_of(cpu), false);
- raw_spin_unlock_irq(&desc->lock);
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
}
/*
diff --git a/arch/metag/kernel/kick.c b/arch/metag/kernel/kick.c
index 50fcbec98cd2..beb377621322 100644
--- a/arch/metag/kernel/kick.c
+++ b/arch/metag/kernel/kick.c
@@ -26,6 +26,8 @@
* pass it as an argument.
*/
#include <linux/export.h>
+#include <linux/hardirq.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/types.h>
@@ -66,6 +68,7 @@ EXPORT_SYMBOL(kick_unregister_func);
TBIRES
kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
{
+ struct pt_regs *old_regs;
struct kick_irq_handler *kh;
struct list_head *lh;
int handled = 0;
@@ -79,6 +82,9 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
trace_hardirqs_off();
+ old_regs = set_irq_regs((struct pt_regs *)State.Sig.pCtx);
+ irq_enter();
+
/*
* There is no need to disable interrupts here because we
* can't nest KICK interrupts in a KICK interrupt handler.
@@ -97,5 +103,8 @@ kick_handler(TBIRES State, int SigNum, int Triggers, int Inst, PTBI pTBI)
WARN_ON(!handled);
+ irq_exit();
+ set_irq_regs(old_regs);
+
return tail_end(ret);
}
diff --git a/arch/metag/kernel/metag_ksyms.c b/arch/metag/kernel/metag_ksyms.c
index ec872ef14eb1..215c94ad63ac 100644
--- a/arch/metag/kernel/metag_ksyms.c
+++ b/arch/metag/kernel/metag_ksyms.c
@@ -1,5 +1,7 @@
#include <linux/export.h>
+#include <linux/types.h>
+#include <asm/checksum.h>
#include <asm/div64.h>
#include <asm/ftrace.h>
#include <asm/page.h>
@@ -15,6 +17,9 @@ EXPORT_SYMBOL(max_pfn);
EXPORT_SYMBOL(min_low_pfn);
#endif
+/* Network checksum functions */
+EXPORT_SYMBOL(csum_partial);
+
/* TBI symbols */
EXPORT_SYMBOL(__TBI);
EXPORT_SYMBOL(__TBIFindSeg);
diff --git a/arch/metag/kernel/setup.c b/arch/metag/kernel/setup.c
index 4f5726f1a55b..c396cd0b425f 100644
--- a/arch/metag/kernel/setup.c
+++ b/arch/metag/kernel/setup.c
@@ -20,6 +20,7 @@
#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
#include <linux/pfn.h>
#include <linux/root_dev.h>
#include <linux/sched.h>
@@ -424,6 +425,9 @@ static int __init customize_machine(void)
/* customizes platform devices, or adds new ones */
if (machine_desc->init_machine)
machine_desc->init_machine();
+ else
+ of_platform_populate(NULL, of_default_bus_match_table, NULL,
+ NULL);
return 0;
}
arch_initcall(customize_machine);
@@ -587,20 +591,20 @@ PTBI pTBI_get(unsigned int cpu)
EXPORT_SYMBOL(pTBI_get);
#if defined(CONFIG_METAG_DSP) && defined(CONFIG_METAG_FPU)
-char capabilites[] = "dsp fpu";
+static char capabilities[] = "dsp fpu";
#elif defined(CONFIG_METAG_DSP)
-char capabilites[] = "dsp";
+static char capabilities[] = "dsp";
#elif defined(CONFIG_METAG_FPU)
-char capabilites[] = "fpu";
+static char capabilities[] = "fpu";
#else
-char capabilites[] = "";
+static char capabilities[] = "";
#endif
static struct ctl_table caps_kern_table[] = {
{
.procname = "capabilities",
- .data = capabilites,
- .maxlen = sizeof(capabilites),
+ .data = capabilities,
+ .maxlen = sizeof(capabilities),
.mode = 0444,
.proc_handler = proc_dostring,
},
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index f443ec9a7cbe..e413875cf6d2 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/atomic.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -62,6 +63,8 @@ static DEFINE_PER_CPU(struct ipi_data, ipi_data) = {
static DEFINE_SPINLOCK(boot_lock);
+static DECLARE_COMPLETION(cpu_running);
+
/*
* "thread" is assumed to be a valid Meta hardware thread ID.
*/
@@ -235,20 +238,12 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
*/
ret = boot_secondary(thread, idle);
if (ret == 0) {
- unsigned long timeout;
-
/*
* CPU was successfully started, wait for it
* to come online or time out.
*/
- timeout = jiffies + HZ;
- while (time_before(jiffies, timeout)) {
- if (cpu_online(cpu))
- break;
-
- udelay(10);
- barrier();
- }
+ wait_for_completion_timeout(&cpu_running,
+ msecs_to_jiffies(1000));
if (!cpu_online(cpu))
ret = -EIO;
@@ -276,7 +271,6 @@ static DECLARE_COMPLETION(cpu_killed);
int __cpuexit __cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
- struct task_struct *p;
/*
* Take this CPU offline. Once we clear this, we can't return,
@@ -296,12 +290,7 @@ int __cpuexit __cpu_disable(void)
flush_cache_all();
local_flush_tlb_all();
- read_lock(&tasklist_lock);
- for_each_process(p) {
- if (p->mm)
- cpumask_clear_cpu(cpu, mm_cpumask(p->mm));
- }
- read_unlock(&tasklist_lock);
+ clear_tasks_mm_cpumask(cpu);
return 0;
}
@@ -385,12 +374,7 @@ asmlinkage void secondary_start_kernel(void)
setup_priv();
- /*
- * Enable local interrupts.
- */
- tbi_startup_interrupt(TBID_SIGNUM_TRT);
notify_cpu_starting(cpu);
- local_irq_enable();
pr_info("CPU%u (thread %u): Booted secondary processor\n",
cpu, cpu_2_hwthread_id[cpu]);
@@ -402,12 +386,13 @@ asmlinkage void secondary_start_kernel(void)
* OK, now it's safe to let the boot CPU continue
*/
set_cpu_online(cpu, true);
+ complete(&cpu_running);
/*
- * Check for cache aliasing.
- * Preemption is disabled
+ * Enable local interrupts.
*/
- check_for_cache_aliasing(cpu);
+ tbi_startup_interrupt(TBID_SIGNUM_TRT);
+ local_irq_enable();
/*
* OK, it's off to the idle thread for us
diff --git a/arch/metag/kernel/time.c b/arch/metag/kernel/time.c
index 17dc10733b2f..f1c8c53dace7 100644
--- a/arch/metag/kernel/time.c
+++ b/arch/metag/kernel/time.c
@@ -5,11 +5,21 @@
*
*/
-#include <linux/init.h>
-
#include <clocksource/metag_generic.h>
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+#include <asm/clock.h>
void __init time_init(void)
{
+#ifdef CONFIG_COMMON_CLK
+ /* Init clocks from device tree */
+ of_clk_init(NULL);
+#endif
+
+ /* Init meta clocks, particularly the core clock */
+ init_metag_clocks();
+
+ /* Set up the timer clock sources */
metag_generic_timer_init();
}
diff --git a/arch/metag/kernel/traps.c b/arch/metag/kernel/traps.c
index 2ceeaae5b199..c00ade0228ef 100644
--- a/arch/metag/kernel/traps.c
+++ b/arch/metag/kernel/traps.c
@@ -33,6 +33,7 @@
#include <asm/siginfo.h>
#include <asm/traps.h>
#include <asm/hwthread.h>
+#include <asm/setup.h>
#include <asm/switch.h>
#include <asm/user_gateway.h>
#include <asm/syscall.h>
@@ -87,8 +88,8 @@ const char *trap_name(int trapno)
static DEFINE_SPINLOCK(die_lock);
-void die(const char *str, struct pt_regs *regs, long err,
- unsigned long addr)
+void __noreturn die(const char *str, struct pt_regs *regs,
+ long err, unsigned long addr)
{
static int die_counter;
diff --git a/arch/metag/lib/checksum.c b/arch/metag/lib/checksum.c
index 44d2e1913560..5d6a98a05e9d 100644
--- a/arch/metag/lib/checksum.c
+++ b/arch/metag/lib/checksum.c
@@ -124,7 +124,6 @@ __wsum csum_partial(const void *buff, int len, __wsum wsum)
result += 1;
return (__force __wsum)result;
}
-EXPORT_SYMBOL(csum_partial);
/*
* this routine is used for miscellaneous IP-like checksums, mainly
diff --git a/arch/metag/mm/cache.c b/arch/metag/mm/cache.c
index b5d3b2e7c160..a62285284ab8 100644
--- a/arch/metag/mm/cache.c
+++ b/arch/metag/mm/cache.c
@@ -45,7 +45,7 @@ static volatile u32 lnkget_testdata[16] __initdata __aligned(64);
#define LNKGET_CONSTANT 0xdeadbeef
-void __init metag_lnkget_probe(void)
+static void __init metag_lnkget_probe(void)
{
int temp;
long flags;
diff --git a/arch/metag/mm/fault.c b/arch/metag/mm/fault.c
index 2c75bf7357c5..8fddf46e6c62 100644
--- a/arch/metag/mm/fault.c
+++ b/arch/metag/mm/fault.c
@@ -224,8 +224,10 @@ do_sigbus:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (user_mode(regs))
- do_group_exit(SIGKILL);
+ if (user_mode(regs)) {
+ pagefault_out_of_memory();
+ return 1;
+ }
no_context:
/* Are we prepared to handle this kernel fault? */
diff --git a/arch/metag/mm/init.c b/arch/metag/mm/init.c
index d05b8455c44c..28813f164730 100644
--- a/arch/metag/mm/init.c
+++ b/arch/metag/mm/init.c
@@ -376,34 +376,21 @@ void __init paging_init(unsigned long mem_end)
void __init mem_init(void)
{
- int nid;
-
#ifdef CONFIG_HIGHMEM
unsigned long tmp;
+
+ /*
+ * Explicitly reset zone->managed_pages because highmem pages are
+ * freed before calling free_all_bootmem();
+ */
+ reset_all_zones_managed_pages();
for (tmp = highstart_pfn; tmp < highend_pfn; tmp++)
free_highmem_page(pfn_to_page(tmp));
- num_physpages += totalhigh_pages;
#endif /* CONFIG_HIGHMEM */
- for_each_online_node(nid) {
- pg_data_t *pgdat = NODE_DATA(nid);
- unsigned long node_pages = 0;
-
- num_physpages += pgdat->node_present_pages;
-
- if (pgdat->node_spanned_pages)
- node_pages = free_all_bootmem_node(pgdat);
-
- totalram_pages += node_pages;
- }
-
- pr_info("Memory: %luk/%luk available\n",
- (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10),
- num_physpages << (PAGE_SHIFT - 10));
-
+ free_all_bootmem();
+ mem_init_print_info(NULL);
show_mem(0);
-
- return;
}
void free_initmem(void)
@@ -414,7 +401,8 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/microblaze/configs/mmu_defconfig b/arch/microblaze/configs/mmu_defconfig
index 3649a8b150c0..deaf45ab6429 100644
--- a/arch/microblaze/configs/mmu_defconfig
+++ b/arch/microblaze/configs/mmu_defconfig
@@ -1,4 +1,3 @@
-CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_FHANDLE=y
@@ -81,6 +80,9 @@ CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_SLAB=y
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_INFO=y
+CONFIG_KGDB=y
+CONFIG_KGDB_TESTS=y
+CONFIG_KGDB_KDB=y
CONFIG_EARLY_PRINTK=y
CONFIG_KEYS=y
CONFIG_ENCRYPTED_KEYS=y
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index 85a5ae8e9bd0..fd850879854d 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -168,7 +168,6 @@ extern int page_is_ram(unsigned long pfn);
# else /* CONFIG_MMU */
# define ARCH_PFN_OFFSET (memory_start >> PAGE_SHIFT)
# define pfn_valid(pfn) ((pfn) < (max_mapnr + ARCH_PFN_OFFSET))
-# define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
# endif /* CONFIG_MMU */
# endif /* __ASSEMBLY__ */
diff --git a/arch/microblaze/include/asm/unistd.h b/arch/microblaze/include/asm/unistd.h
index 6dece2d002dc..b14232b6878f 100644
--- a/arch/microblaze/include/asm/unistd.h
+++ b/arch/microblaze/include/asm/unistd.h
@@ -38,4 +38,7 @@
#define __ARCH_WANT_SYS_FORK
#endif /* __ASSEMBLY__ */
+
+#define __NR_syscalls 381
+
#endif /* _ASM_MICROBLAZE_UNISTD_H */
diff --git a/arch/microblaze/include/uapi/asm/unistd.h b/arch/microblaze/include/uapi/asm/unistd.h
index 5f7fe7582f3a..20043b67d158 100644
--- a/arch/microblaze/include/uapi/asm/unistd.h
+++ b/arch/microblaze/include/uapi/asm/unistd.h
@@ -397,6 +397,4 @@
#define __NR_kcmp 379
#define __NR_finit_module 380
-#define __NR_syscalls 381
-
#endif /* _UAPI_ASM_MICROBLAZE_UNISTD_H */
diff --git a/arch/microblaze/kernel/kgdb.c b/arch/microblaze/kernel/kgdb.c
index 8adc92443100..09a5e8286137 100644
--- a/arch/microblaze/kernel/kgdb.c
+++ b/arch/microblaze/kernel/kgdb.c
@@ -141,7 +141,7 @@ void kgdb_arch_exit(void)
/*
* Global data
*/
-const struct kgdb_arch arch_kgdb_ops = {
+struct kgdb_arch arch_kgdb_ops = {
#ifdef __MICROBLAZEEL__
.gdb_bpt_instr = {0x18, 0x00, 0x0c, 0xba}, /* brki r16, 0x18 */
#else
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index b38ae3acfeb4..74c7bcc1e82d 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -71,24 +71,17 @@ static void __init highmem_init(void)
kmap_prot = PAGE_KERNEL;
}
-static unsigned long highmem_setup(void)
+static void highmem_setup(void)
{
unsigned long pfn;
- unsigned long reservedpages = 0;
for (pfn = max_low_pfn; pfn < max_pfn; ++pfn) {
struct page *page = pfn_to_page(pfn);
/* FIXME not sure about */
- if (memblock_is_reserved(pfn << PAGE_SHIFT))
- continue;
- free_highmem_page(page);
- reservedpages++;
+ if (!memblock_is_reserved(pfn << PAGE_SHIFT))
+ free_highmem_page(page);
}
- pr_info("High memory: %luk\n",
- totalhigh_pages << (PAGE_SHIFT-10));
-
- return reservedpages;
}
#endif /* CONFIG_HIGHMEM */
@@ -167,13 +160,12 @@ void __init setup_memory(void)
* min_low_pfn - the first page (mm/bootmem.c - node_boot_start)
* max_low_pfn
* max_mapnr - the first unused page (mm/bootmem.c - node_low_pfn)
- * num_physpages - number of all pages
*/
/* memory start is from the kernel end (aligned) to higher addr */
min_low_pfn = memory_start >> PAGE_SHIFT; /* minimum for allocation */
/* RAM is assumed contiguous */
- num_physpages = max_mapnr = memory_size >> PAGE_SHIFT;
+ max_mapnr = memory_size >> PAGE_SHIFT;
max_low_pfn = ((u64)memory_start + (u64)lowmem_size) >> PAGE_SHIFT;
max_pfn = ((u64)memory_start + (u64)memory_size) >> PAGE_SHIFT;
@@ -235,57 +227,26 @@ void __init setup_memory(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
void __init mem_init(void)
{
- pg_data_t *pgdat;
- unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
-
high_memory = (void *)__va(memory_start + lowmem_size - 1);
/* this will put all memory onto the freelists */
- totalram_pages += free_all_bootmem();
-
- for_each_online_pgdat(pgdat) {
- unsigned long i;
- struct page *page;
-
- for (i = 0; i < pgdat->node_spanned_pages; i++) {
- if (!pfn_valid(pgdat->node_start_pfn + i))
- continue;
- page = pgdat_page_nr(pgdat, i);
- if (PageReserved(page))
- reservedpages++;
- }
- }
-
+ free_all_bootmem();
#ifdef CONFIG_HIGHMEM
- reservedpages -= highmem_setup();
+ highmem_setup();
#endif
- codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
- datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
- initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
- bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
-
- pr_info("Memory: %luk/%luk available (%luk kernel code, ",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10);
- pr_cont("%luk reserved, %luk data, %luk bss, %luk init)\n",
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- bsssize >> 10,
- initsize >> 10);
-
+ mem_init_print_info(NULL);
#ifdef CONFIG_MMU
pr_info("Kernel virtual memory layout:\n");
pr_info(" * 0x%08lx..0x%08lx : fixmap\n", FIXADDR_START, FIXADDR_TOP);
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e433b90507fb..beeff436b22f 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -42,6 +42,7 @@ config MIPS
select MODULES_USE_ELF_REL if MODULES
select MODULES_USE_ELF_RELA if MODULES && 64BIT
select CLONE_BACKWARDS
+ select HAVE_DEBUG_STACKOVERFLOW
menu "Machine selection"
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 5a43aa0798ca..37871f0de15e 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -67,15 +67,6 @@ config CMDLINE_OVERRIDE
Normally, you will choose 'N' here.
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit(2GB on MIPS). The debugging option
- provides another way to check stack overflow happened on kernel mode
- stack usually caused by nested interruption.
-
config SMTC_IDLE_HOOK_DEBUG
bool "Enable additional debug checks before going into CPU idle loop"
depends on DEBUG_KERNEL && MIPS_MT_SMTC
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
index a9505c4867e8..9c0ddafafb6c 100644
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -845,6 +845,10 @@ int __init board_register_devices(void)
!bcm63xx_nvram_get_mac_address(board.enet1.mac_addr))
bcm63xx_enet_register(1, &board.enet1);
+ if (board.has_enetsw &&
+ !bcm63xx_nvram_get_mac_address(board.enetsw.mac_addr))
+ bcm63xx_enetsw_register(&board.enetsw);
+
if (board.has_usbd)
bcm63xx_usbd_register(&board.usbd);
diff --git a/arch/mips/bcm63xx/dev-enet.c b/arch/mips/bcm63xx/dev-enet.c
index 39c23366c5c7..52bc01df9bfe 100644
--- a/arch/mips/bcm63xx/dev-enet.c
+++ b/arch/mips/bcm63xx/dev-enet.c
@@ -9,16 +9,60 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/export.h>
#include <bcm63xx_dev_enet.h>
#include <bcm63xx_io.h>
#include <bcm63xx_regs.h>
+#ifdef BCMCPU_RUNTIME_DETECT
+static const unsigned long bcm6348_regs_enetdmac[] = {
+ [ENETDMAC_CHANCFG] = ENETDMAC_CHANCFG_REG,
+ [ENETDMAC_IR] = ENETDMAC_IR_REG,
+ [ENETDMAC_IRMASK] = ENETDMAC_IRMASK_REG,
+ [ENETDMAC_MAXBURST] = ENETDMAC_MAXBURST_REG,
+};
+
+static const unsigned long bcm6345_regs_enetdmac[] = {
+ [ENETDMAC_CHANCFG] = ENETDMA_6345_CHANCFG_REG,
+ [ENETDMAC_IR] = ENETDMA_6345_IR_REG,
+ [ENETDMAC_IRMASK] = ENETDMA_6345_IRMASK_REG,
+ [ENETDMAC_MAXBURST] = ENETDMA_6345_MAXBURST_REG,
+ [ENETDMAC_BUFALLOC] = ENETDMA_6345_BUFALLOC_REG,
+ [ENETDMAC_RSTART] = ENETDMA_6345_RSTART_REG,
+ [ENETDMAC_FC] = ENETDMA_6345_FC_REG,
+ [ENETDMAC_LEN] = ENETDMA_6345_LEN_REG,
+};
+
+const unsigned long *bcm63xx_regs_enetdmac;
+EXPORT_SYMBOL(bcm63xx_regs_enetdmac);
+
+static __init void bcm63xx_enetdmac_regs_init(void)
+{
+ if (BCMCPU_IS_6345())
+ bcm63xx_regs_enetdmac = bcm6345_regs_enetdmac;
+ else
+ bcm63xx_regs_enetdmac = bcm6348_regs_enetdmac;
+}
+#else
+static __init void bcm63xx_enetdmac_regs_init(void) { }
+#endif
+
static struct resource shared_res[] = {
{
.start = -1, /* filled at runtime */
.end = -1, /* filled at runtime */
.flags = IORESOURCE_MEM,
},
+ {
+ .start = -1, /* filled at runtime */
+ .end = -1, /* filled at runtime */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = -1, /* filled at runtime */
+ .end = -1, /* filled at runtime */
+ .flags = IORESOURCE_MEM,
+ },
};
static struct platform_device bcm63xx_enet_shared_device = {
@@ -94,6 +138,71 @@ static struct platform_device bcm63xx_enet1_device = {
},
};
+static struct resource enetsw_res[] = {
+ {
+ /* start & end filled at runtime */
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* start filled at runtime */
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ /* start filled at runtime */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct bcm63xx_enetsw_platform_data enetsw_pd;
+
+static struct platform_device bcm63xx_enetsw_device = {
+ .name = "bcm63xx_enetsw",
+ .num_resources = ARRAY_SIZE(enetsw_res),
+ .resource = enetsw_res,
+ .dev = {
+ .platform_data = &enetsw_pd,
+ },
+};
+
+static int __init register_shared(void)
+{
+ int ret, chan_count;
+
+ if (shared_device_registered)
+ return 0;
+
+ bcm63xx_enetdmac_regs_init();
+
+ shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
+ shared_res[0].end = shared_res[0].start;
+ if (BCMCPU_IS_6345())
+ shared_res[0].end += (RSET_6345_ENETDMA_SIZE) - 1;
+ else
+ shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
+
+ if (BCMCPU_IS_6328() || BCMCPU_IS_6362() || BCMCPU_IS_6368())
+ chan_count = 32;
+ else if (BCMCPU_IS_6345())
+ chan_count = 8;
+ else
+ chan_count = 16;
+
+ shared_res[1].start = bcm63xx_regset_address(RSET_ENETDMAC);
+ shared_res[1].end = shared_res[1].start;
+ shared_res[1].end += RSET_ENETDMAC_SIZE(chan_count) - 1;
+
+ shared_res[2].start = bcm63xx_regset_address(RSET_ENETDMAS);
+ shared_res[2].end = shared_res[2].start;
+ shared_res[2].end += RSET_ENETDMAS_SIZE(chan_count) - 1;
+
+ ret = platform_device_register(&bcm63xx_enet_shared_device);
+ if (ret)
+ return ret;
+ shared_device_registered = 1;
+
+ return 0;
+}
+
int __init bcm63xx_enet_register(int unit,
const struct bcm63xx_enet_platform_data *pd)
{
@@ -104,22 +213,12 @@ int __init bcm63xx_enet_register(int unit,
if (unit > 1)
return -ENODEV;
- if (unit == 1 && BCMCPU_IS_6338())
+ if (unit == 1 && (BCMCPU_IS_6338() || BCMCPU_IS_6345()))
return -ENODEV;
- if (!shared_device_registered) {
- shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
- shared_res[0].end = shared_res[0].start;
- if (BCMCPU_IS_6338())
- shared_res[0].end += (RSET_ENETDMA_SIZE / 2) - 1;
- else
- shared_res[0].end += (RSET_ENETDMA_SIZE) - 1;
-
- ret = platform_device_register(&bcm63xx_enet_shared_device);
- if (ret)
- return ret;
- shared_device_registered = 1;
- }
+ ret = register_shared();
+ if (ret)
+ return ret;
if (unit == 0) {
enet0_res[0].start = bcm63xx_regset_address(RSET_ENET0);
@@ -155,8 +254,62 @@ int __init bcm63xx_enet_register(int unit,
dpd->phy_interrupt = bcm63xx_get_irq_number(IRQ_ENET_PHY);
}
+ dpd->dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
+ dpd->dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
+ if (BCMCPU_IS_6345()) {
+ dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_CHAINING_MASK;
+ dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_WRAP_EN_MASK;
+ dpd->dma_chan_en_mask |= ENETDMAC_CHANCFG_FLOWC_EN_MASK;
+ dpd->dma_chan_int_mask |= ENETDMA_IR_BUFDONE_MASK;
+ dpd->dma_chan_int_mask |= ENETDMA_IR_NOTOWNER_MASK;
+ dpd->dma_chan_width = ENETDMA_6345_CHAN_WIDTH;
+ dpd->dma_desc_shift = ENETDMA_6345_DESC_SHIFT;
+ } else {
+ dpd->dma_has_sram = true;
+ dpd->dma_chan_width = ENETDMA_CHAN_WIDTH;
+ }
+
ret = platform_device_register(pdev);
if (ret)
return ret;
return 0;
}
+
+int __init
+bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd)
+{
+ int ret;
+
+ if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362() && !BCMCPU_IS_6368())
+ return -ENODEV;
+
+ ret = register_shared();
+ if (ret)
+ return ret;
+
+ enetsw_res[0].start = bcm63xx_regset_address(RSET_ENETSW);
+ enetsw_res[0].end = enetsw_res[0].start;
+ enetsw_res[0].end += RSET_ENETSW_SIZE - 1;
+ enetsw_res[1].start = bcm63xx_get_irq_number(IRQ_ENETSW_RXDMA0);
+ enetsw_res[2].start = bcm63xx_get_irq_number(IRQ_ENETSW_TXDMA0);
+ if (!enetsw_res[2].start)
+ enetsw_res[2].start = -1;
+
+ memcpy(bcm63xx_enetsw_device.dev.platform_data, pd, sizeof(*pd));
+
+ if (BCMCPU_IS_6328())
+ enetsw_pd.num_ports = ENETSW_PORTS_6328;
+ else if (BCMCPU_IS_6362() || BCMCPU_IS_6368())
+ enetsw_pd.num_ports = ENETSW_PORTS_6368;
+
+ enetsw_pd.dma_has_sram = true;
+ enetsw_pd.dma_chan_width = ENETDMA_CHAN_WIDTH;
+ enetsw_pd.dma_chan_en_mask = ENETDMAC_CHANCFG_EN_MASK;
+ enetsw_pd.dma_chan_int_mask = ENETDMAC_IR_PKTDONE_MASK;
+
+ ret = platform_device_register(&bcm63xx_enetsw_device);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
index 336228990808..e6e65dc7d502 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
@@ -173,7 +173,10 @@ enum bcm63xx_regs_set {
#define BCM_6358_RSET_SPI_SIZE 1804
#define BCM_6368_RSET_SPI_SIZE 1804
#define RSET_ENET_SIZE 2048
-#define RSET_ENETDMA_SIZE 2048
+#define RSET_ENETDMA_SIZE 256
+#define RSET_6345_ENETDMA_SIZE 64
+#define RSET_ENETDMAC_SIZE(chans) (16 * (chans))
+#define RSET_ENETDMAS_SIZE(chans) (16 * (chans))
#define RSET_ENETSW_SIZE 65536
#define RSET_UART_SIZE 24
#define RSET_UDC_SIZE 256
@@ -298,7 +301,7 @@ enum bcm63xx_regs_set {
#define BCM_6345_USBDMA_BASE (0xfffe2800)
#define BCM_6345_ENET0_BASE (0xfffe1800)
#define BCM_6345_ENETDMA_BASE (0xfffe2800)
-#define BCM_6345_ENETDMAC_BASE (0xfffe2900)
+#define BCM_6345_ENETDMAC_BASE (0xfffe2840)
#define BCM_6345_ENETDMAS_BASE (0xfffe2a00)
#define BCM_6345_ENETSW_BASE (0xdeadbeef)
#define BCM_6345_PCMCIA_BASE (0xfffe2028)
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
index d53f611184b9..753953e86242 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_enet.h
@@ -4,6 +4,8 @@
#include <linux/if_ether.h>
#include <linux/init.h>
+#include <bcm63xx_regs.h>
+
/*
* on board ethernet platform data
*/
@@ -37,9 +39,129 @@ struct bcm63xx_enet_platform_data {
int phy_id, int reg),
void (*mii_write)(struct net_device *dev,
int phy_id, int reg, int val));
+
+ /* DMA channel enable mask */
+ u32 dma_chan_en_mask;
+
+ /* DMA channel interrupt mask */
+ u32 dma_chan_int_mask;
+
+ /* DMA engine has internal SRAM */
+ bool dma_has_sram;
+
+ /* DMA channel register width */
+ unsigned int dma_chan_width;
+
+ /* DMA descriptor shift */
+ unsigned int dma_desc_shift;
+};
+
+/*
+ * on board ethernet switch platform data
+ */
+#define ENETSW_MAX_PORT 8
+#define ENETSW_PORTS_6328 5 /* 4 FE PHY + 1 RGMII */
+#define ENETSW_PORTS_6368 6 /* 4 FE PHY + 2 RGMII */
+
+#define ENETSW_RGMII_PORT0 4
+
+struct bcm63xx_enetsw_port {
+ int used;
+ int phy_id;
+
+ int bypass_link;
+ int force_speed;
+ int force_duplex_full;
+
+ const char *name;
+};
+
+struct bcm63xx_enetsw_platform_data {
+ char mac_addr[ETH_ALEN];
+ int num_ports;
+ struct bcm63xx_enetsw_port used_ports[ENETSW_MAX_PORT];
+
+ /* DMA channel enable mask */
+ u32 dma_chan_en_mask;
+
+ /* DMA channel interrupt mask */
+ u32 dma_chan_int_mask;
+
+ /* DMA channel register width */
+ unsigned int dma_chan_width;
+
+ /* DMA engine has internal SRAM */
+ bool dma_has_sram;
};
int __init bcm63xx_enet_register(int unit,
const struct bcm63xx_enet_platform_data *pd);
+int bcm63xx_enetsw_register(const struct bcm63xx_enetsw_platform_data *pd);
+
+enum bcm63xx_regs_enetdmac {
+ ENETDMAC_CHANCFG,
+ ENETDMAC_IR,
+ ENETDMAC_IRMASK,
+ ENETDMAC_MAXBURST,
+ ENETDMAC_BUFALLOC,
+ ENETDMAC_RSTART,
+ ENETDMAC_FC,
+ ENETDMAC_LEN,
+};
+
+static inline unsigned long bcm63xx_enetdmacreg(enum bcm63xx_regs_enetdmac reg)
+{
+#ifdef BCMCPU_RUNTIME_DETECT
+ extern const unsigned long *bcm63xx_regs_enetdmac;
+
+ return bcm63xx_regs_enetdmac[reg];
+#else
+#ifdef CONFIG_BCM63XX_CPU_6345
+ switch (reg) {
+ case ENETDMAC_CHANCFG:
+ return ENETDMA_6345_CHANCFG_REG;
+ case ENETDMAC_IR:
+ return ENETDMA_6345_IR_REG;
+ case ENETDMAC_IRMASK:
+ return ENETDMA_6345_IRMASK_REG;
+ case ENETDMAC_MAXBURST:
+ return ENETDMA_6345_MAXBURST_REG;
+ case ENETDMAC_BUFALLOC:
+ return ENETDMA_6345_BUFALLOC_REG;
+ case ENETDMAC_RSTART:
+ return ENETDMA_6345_RSTART_REG;
+ case ENETDMAC_FC:
+ return ENETDMA_6345_FC_REG;
+ case ENETDMAC_LEN:
+ return ENETDMA_6345_LEN_REG;
+ }
+#endif
+#if defined(CONFIG_BCM63XX_CPU_6328) || \
+ defined(CONFIG_BCM63XX_CPU_6338) || \
+ defined(CONFIG_BCM63XX_CPU_6348) || \
+ defined(CONFIG_BCM63XX_CPU_6358) || \
+ defined(CONFIG_BCM63XX_CPU_6362) || \
+ defined(CONFIG_BCM63XX_CPU_6368)
+ switch (reg) {
+ case ENETDMAC_CHANCFG:
+ return ENETDMAC_CHANCFG_REG;
+ case ENETDMAC_IR:
+ return ENETDMAC_IR_REG;
+ case ENETDMAC_IRMASK:
+ return ENETDMAC_IRMASK_REG;
+ case ENETDMAC_MAXBURST:
+ return ENETDMAC_MAXBURST_REG;
+ case ENETDMAC_BUFALLOC:
+ case ENETDMAC_RSTART:
+ case ENETDMAC_FC:
+ case ENETDMAC_LEN:
+ return 0;
+ }
+#endif
+#endif
+ return 0;
+}
+
+
#endif /* ! BCM63XX_DEV_ENET_H_ */
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
index 3203fe49b34d..eff7ca7d12b0 100644
--- a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
+++ b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
@@ -727,6 +727,8 @@
/*************************************************************************
* _REG relative to RSET_ENETDMA
*************************************************************************/
+#define ENETDMA_CHAN_WIDTH 0x10
+#define ENETDMA_6345_CHAN_WIDTH 0x40
/* Controller Configuration Register */
#define ENETDMA_CFG_REG (0x0)
@@ -782,31 +784,56 @@
/* State Ram Word 4 */
#define ENETDMA_SRAM4_REG(x) (0x20c + (x) * 0x10)
+/* Broadcom 6345 ENET DMA definitions */
+#define ENETDMA_6345_CHANCFG_REG (0x00)
+
+#define ENETDMA_6345_MAXBURST_REG (0x40)
+
+#define ENETDMA_6345_RSTART_REG (0x08)
+
+#define ENETDMA_6345_LEN_REG (0x0C)
+
+#define ENETDMA_6345_IR_REG (0x14)
+
+#define ENETDMA_6345_IRMASK_REG (0x18)
+
+#define ENETDMA_6345_FC_REG (0x1C)
+
+#define ENETDMA_6345_BUFALLOC_REG (0x20)
+
+/* Shift down for EOP, SOP and WRAP bits */
+#define ENETDMA_6345_DESC_SHIFT (3)
/*************************************************************************
* _REG relative to RSET_ENETDMAC
*************************************************************************/
/* Channel Configuration register */
-#define ENETDMAC_CHANCFG_REG(x) ((x) * 0x10)
+#define ENETDMAC_CHANCFG_REG (0x0)
#define ENETDMAC_CHANCFG_EN_SHIFT 0
#define ENETDMAC_CHANCFG_EN_MASK (1 << ENETDMAC_CHANCFG_EN_SHIFT)
#define ENETDMAC_CHANCFG_PKTHALT_SHIFT 1
#define ENETDMAC_CHANCFG_PKTHALT_MASK (1 << ENETDMAC_CHANCFG_PKTHALT_SHIFT)
#define ENETDMAC_CHANCFG_BUFHALT_SHIFT 2
#define ENETDMAC_CHANCFG_BUFHALT_MASK (1 << ENETDMAC_CHANCFG_BUFHALT_SHIFT)
+#define ENETDMAC_CHANCFG_CHAINING_SHIFT 2
+#define ENETDMAC_CHANCFG_CHAINING_MASK (1 << ENETDMAC_CHANCFG_CHAINING_SHIFT)
+#define ENETDMAC_CHANCFG_WRAP_EN_SHIFT 3
+#define ENETDMAC_CHANCFG_WRAP_EN_MASK (1 << ENETDMAC_CHANCFG_WRAP_EN_SHIFT)
+#define ENETDMAC_CHANCFG_FLOWC_EN_SHIFT 4
+#define ENETDMAC_CHANCFG_FLOWC_EN_MASK (1 << ENETDMAC_CHANCFG_FLOWC_EN_SHIFT)
/* Interrupt Control/Status register */
-#define ENETDMAC_IR_REG(x) (0x4 + (x) * 0x10)
+#define ENETDMAC_IR_REG (0x4)
#define ENETDMAC_IR_BUFDONE_MASK (1 << 0)
#define ENETDMAC_IR_PKTDONE_MASK (1 << 1)
#define ENETDMAC_IR_NOTOWNER_MASK (1 << 2)
/* Interrupt Mask register */
-#define ENETDMAC_IRMASK_REG(x) (0x8 + (x) * 0x10)
+#define ENETDMAC_IRMASK_REG (0x8)
/* Maximum Burst Length */
-#define ENETDMAC_MAXBURST_REG(x) (0xc + (x) * 0x10)
+#define ENETDMAC_MAXBURST_REG (0xc)
/*************************************************************************
@@ -814,26 +841,76 @@
*************************************************************************/
/* Ring Start Address register */
-#define ENETDMAS_RSTART_REG(x) ((x) * 0x10)
+#define ENETDMAS_RSTART_REG (0x0)
/* State Ram Word 2 */
-#define ENETDMAS_SRAM2_REG(x) (0x4 + (x) * 0x10)
+#define ENETDMAS_SRAM2_REG (0x4)
/* State Ram Word 3 */
-#define ENETDMAS_SRAM3_REG(x) (0x8 + (x) * 0x10)
+#define ENETDMAS_SRAM3_REG (0x8)
/* State Ram Word 4 */
-#define ENETDMAS_SRAM4_REG(x) (0xc + (x) * 0x10)
+#define ENETDMAS_SRAM4_REG (0xc)
/*************************************************************************
* _REG relative to RSET_ENETSW
*************************************************************************/
+/* Port traffic control */
+#define ENETSW_PTCTRL_REG(x) (0x0 + (x))
+#define ENETSW_PTCTRL_RXDIS_MASK (1 << 0)
+#define ENETSW_PTCTRL_TXDIS_MASK (1 << 1)
+
+/* Switch mode register */
+#define ENETSW_SWMODE_REG (0xb)
+#define ENETSW_SWMODE_FWD_EN_MASK (1 << 1)
+
+/* IMP override Register */
+#define ENETSW_IMPOV_REG (0xe)
+#define ENETSW_IMPOV_FORCE_MASK (1 << 7)
+#define ENETSW_IMPOV_TXFLOW_MASK (1 << 5)
+#define ENETSW_IMPOV_RXFLOW_MASK (1 << 4)
+#define ENETSW_IMPOV_1000_MASK (1 << 3)
+#define ENETSW_IMPOV_100_MASK (1 << 2)
+#define ENETSW_IMPOV_FDX_MASK (1 << 1)
+#define ENETSW_IMPOV_LINKUP_MASK (1 << 0)
+
+/* Port override Register */
+#define ENETSW_PORTOV_REG(x) (0x58 + (x))
+#define ENETSW_PORTOV_ENABLE_MASK (1 << 6)
+#define ENETSW_PORTOV_TXFLOW_MASK (1 << 5)
+#define ENETSW_PORTOV_RXFLOW_MASK (1 << 4)
+#define ENETSW_PORTOV_1000_MASK (1 << 3)
+#define ENETSW_PORTOV_100_MASK (1 << 2)
+#define ENETSW_PORTOV_FDX_MASK (1 << 1)
+#define ENETSW_PORTOV_LINKUP_MASK (1 << 0)
+
+/* MDIO control register */
+#define ENETSW_MDIOC_REG (0xb0)
+#define ENETSW_MDIOC_EXT_MASK (1 << 16)
+#define ENETSW_MDIOC_REG_SHIFT 20
+#define ENETSW_MDIOC_PHYID_SHIFT 25
+#define ENETSW_MDIOC_RD_MASK (1 << 30)
+#define ENETSW_MDIOC_WR_MASK (1 << 31)
+
+/* MDIO data register */
+#define ENETSW_MDIOD_REG (0xb4)
+
+/* Global Management Configuration Register */
+#define ENETSW_GMCR_REG (0x200)
+#define ENETSW_GMCR_RST_MIB_MASK (1 << 0)
+
/* MIB register */
#define ENETSW_MIB_REG(x) (0x2800 + (x) * 4)
#define ENETSW_MIB_REG_COUNT 47
+/* Jumbo control register port mask register */
+#define ENETSW_JMBCTL_PORT_REG (0x4004)
+
+/* Jumbo control mib good frame register */
+#define ENETSW_JMBCTL_MAXSIZE_REG (0x4008)
+
/*************************************************************************
* _REG relative to RSET_OHCI_PRIV
diff --git a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
index 682bcf3b492a..d9aee1a833f3 100644
--- a/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
+++ b/arch/mips/include/asm/mach-bcm63xx/board_bcm963xx.h
@@ -24,6 +24,7 @@ struct board_info {
/* enabled feature/device */
unsigned int has_enet0:1;
unsigned int has_enet1:1;
+ unsigned int has_enetsw:1;
unsigned int has_pci:1;
unsigned int has_pccard:1;
unsigned int has_ohci0:1;
@@ -36,6 +37,7 @@ struct board_info {
/* ethernet config */
struct bcm63xx_enet_platform_data enet0;
struct bcm63xx_enet_platform_data enet1;
+ struct bcm63xx_enetsw_platform_data enetsw;
/* USB config */
struct bcm63xx_usbd_platform_data usbd;
diff --git a/arch/mips/include/asm/mach-jz4740/dma.h b/arch/mips/include/asm/mach-jz4740/dma.h
index 98b4e7c0dbae..509cd5828044 100644
--- a/arch/mips/include/asm/mach-jz4740/dma.h
+++ b/arch/mips/include/asm/mach-jz4740/dma.h
@@ -16,8 +16,6 @@
#ifndef __ASM_MACH_JZ4740_DMA_H__
#define __ASM_MACH_JZ4740_DMA_H__
-struct jz4740_dma_chan;
-
enum jz4740_dma_request_type {
JZ4740_DMA_TYPE_AUTO_REQUEST = 8,
JZ4740_DMA_TYPE_UART_TRANSMIT = 20,
@@ -33,58 +31,4 @@ enum jz4740_dma_request_type {
JZ4740_DMA_TYPE_SLCD = 30,
};
-enum jz4740_dma_width {
- JZ4740_DMA_WIDTH_32BIT = 0,
- JZ4740_DMA_WIDTH_8BIT = 1,
- JZ4740_DMA_WIDTH_16BIT = 2,
-};
-
-enum jz4740_dma_transfer_size {
- JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0,
- JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1,
- JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2,
- JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3,
- JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4,
-};
-
-enum jz4740_dma_flags {
- JZ4740_DMA_SRC_AUTOINC = 0x2,
- JZ4740_DMA_DST_AUTOINC = 0x1,
-};
-
-enum jz4740_dma_mode {
- JZ4740_DMA_MODE_SINGLE = 0,
- JZ4740_DMA_MODE_BLOCK = 1,
-};
-
-struct jz4740_dma_config {
- enum jz4740_dma_width src_width;
- enum jz4740_dma_width dst_width;
- enum jz4740_dma_transfer_size transfer_size;
- enum jz4740_dma_request_type request_type;
- enum jz4740_dma_flags flags;
- enum jz4740_dma_mode mode;
-};
-
-typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int, void *);
-
-struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name);
-void jz4740_dma_free(struct jz4740_dma_chan *dma);
-
-void jz4740_dma_configure(struct jz4740_dma_chan *dma,
- const struct jz4740_dma_config *config);
-
-
-void jz4740_dma_enable(struct jz4740_dma_chan *dma);
-void jz4740_dma_disable(struct jz4740_dma_chan *dma);
-
-void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src);
-void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst);
-void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count);
-
-uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma);
-
-void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
- jz4740_dma_complete_callback_t cb);
-
#endif /* __ASM_JZ4740_DMA_H__ */
diff --git a/arch/mips/include/asm/mach-jz4740/platform.h b/arch/mips/include/asm/mach-jz4740/platform.h
index 72cfebdb5a47..05988c2d6565 100644
--- a/arch/mips/include/asm/mach-jz4740/platform.h
+++ b/arch/mips/include/asm/mach-jz4740/platform.h
@@ -32,6 +32,7 @@ extern struct platform_device jz4740_codec_device;
extern struct platform_device jz4740_adc_device;
extern struct platform_device jz4740_wdt_device;
extern struct platform_device jz4740_pwm_device;
+extern struct platform_device jz4740_dma_device;
void jz4740_serial_device_register(void);
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index 3b211507be7f..6a07992ba6c6 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -92,4 +92,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mips/jz4740/Makefile b/arch/mips/jz4740/Makefile
index 63bad0e491d0..28e5535dfa9e 100644
--- a/arch/mips/jz4740/Makefile
+++ b/arch/mips/jz4740/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y += prom.o irq.o time.o reset.o setup.o dma.o \
+obj-y += prom.o irq.o time.o reset.o setup.o \
gpio.o clock.o platform.o timer.o serial.o
obj-$(CONFIG_DEBUG_FS) += clock-debugfs.o
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index be2b3deeef1d..8a5ec0eedeb0 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -438,6 +438,7 @@ static struct platform_device *jz_platform_devices[] __initdata = {
&jz4740_rtc_device,
&jz4740_adc_device,
&jz4740_pwm_device,
+ &jz4740_dma_device,
&qi_lb60_gpio_keys,
&qi_lb60_pwm_beeper,
&qi_lb60_charger_device,
diff --git a/arch/mips/jz4740/clock.c b/arch/mips/jz4740/clock.c
index 484d38a0864f..1b5f55426cad 100644
--- a/arch/mips/jz4740/clock.c
+++ b/arch/mips/jz4740/clock.c
@@ -687,7 +687,7 @@ static struct clk jz4740_clock_simple_clks[] = {
[3] = {
.name = "dma",
.parent = &jz_clk_high_speed_peripheral.clk,
- .gate_bit = JZ_CLOCK_GATE_UART0,
+ .gate_bit = JZ_CLOCK_GATE_DMAC,
.ops = &jz_clk_simple_ops,
},
[4] = {
diff --git a/arch/mips/jz4740/dma.c b/arch/mips/jz4740/dma.c
deleted file mode 100644
index 317ec6fffb12..000000000000
--- a/arch/mips/jz4740/dma.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
- * JZ4740 SoC DMA support
- *
- * 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.
- *
- * 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.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-#include <linux/dma-mapping.h>
-#include <asm/mach-jz4740/dma.h>
-#include <asm/mach-jz4740/base.h>
-
-#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20)
-#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20)
-#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20)
-#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20)
-#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20)
-#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20)
-#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20)
-
-#define JZ_REG_DMA_CTRL 0x300
-#define JZ_REG_DMA_IRQ 0x304
-#define JZ_REG_DMA_DOORBELL 0x308
-#define JZ_REG_DMA_DOORBELL_SET 0x30C
-
-#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31)
-#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6)
-#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4)
-#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3)
-#define JZ_DMA_STATUS_CTRL_HALT BIT(2)
-#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1)
-#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0)
-
-#define JZ_DMA_CMD_SRC_INC BIT(23)
-#define JZ_DMA_CMD_DST_INC BIT(22)
-#define JZ_DMA_CMD_RDIL_MASK (0xf << 16)
-#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14)
-#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12)
-#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8)
-#define JZ_DMA_CMD_BLOCK_MODE BIT(7)
-#define JZ_DMA_CMD_DESC_VALID BIT(4)
-#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3)
-#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2)
-#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1)
-#define JZ_DMA_CMD_LINK_ENABLE BIT(0)
-
-#define JZ_DMA_CMD_FLAGS_OFFSET 22
-#define JZ_DMA_CMD_RDIL_OFFSET 16
-#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14
-#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12
-#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8
-#define JZ_DMA_CMD_MODE_OFFSET 7
-
-#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8)
-#define JZ_DMA_CTRL_HALT BIT(3)
-#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2)
-#define JZ_DMA_CTRL_ENABLE BIT(0)
-
-
-static void __iomem *jz4740_dma_base;
-static spinlock_t jz4740_dma_lock;
-
-static inline uint32_t jz4740_dma_read(size_t reg)
-{
- return readl(jz4740_dma_base + reg);
-}
-
-static inline void jz4740_dma_write(size_t reg, uint32_t val)
-{
- writel(val, jz4740_dma_base + reg);
-}
-
-static inline void jz4740_dma_write_mask(size_t reg, uint32_t val, uint32_t mask)
-{
- uint32_t val2;
- val2 = jz4740_dma_read(reg);
- val2 &= ~mask;
- val2 |= val;
- jz4740_dma_write(reg, val2);
-}
-
-struct jz4740_dma_chan {
- unsigned int id;
- void *dev;
- const char *name;
-
- enum jz4740_dma_flags flags;
- uint32_t transfer_shift;
-
- jz4740_dma_complete_callback_t complete_cb;
-
- unsigned used:1;
-};
-
-#define JZ4740_DMA_CHANNEL(_id) { .id = _id }
-
-struct jz4740_dma_chan jz4740_dma_channels[] = {
- JZ4740_DMA_CHANNEL(0),
- JZ4740_DMA_CHANNEL(1),
- JZ4740_DMA_CHANNEL(2),
- JZ4740_DMA_CHANNEL(3),
- JZ4740_DMA_CHANNEL(4),
- JZ4740_DMA_CHANNEL(5),
-};
-
-struct jz4740_dma_chan *jz4740_dma_request(void *dev, const char *name)
-{
- unsigned int i;
- struct jz4740_dma_chan *dma = NULL;
-
- spin_lock(&jz4740_dma_lock);
-
- for (i = 0; i < ARRAY_SIZE(jz4740_dma_channels); ++i) {
- if (!jz4740_dma_channels[i].used) {
- dma = &jz4740_dma_channels[i];
- dma->used = 1;
- break;
- }
- }
-
- spin_unlock(&jz4740_dma_lock);
-
- if (!dma)
- return NULL;
-
- dma->dev = dev;
- dma->name = name;
-
- return dma;
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_request);
-
-void jz4740_dma_configure(struct jz4740_dma_chan *dma,
- const struct jz4740_dma_config *config)
-{
- uint32_t cmd;
-
- switch (config->transfer_size) {
- case JZ4740_DMA_TRANSFER_SIZE_2BYTE:
- dma->transfer_shift = 1;
- break;
- case JZ4740_DMA_TRANSFER_SIZE_4BYTE:
- dma->transfer_shift = 2;
- break;
- case JZ4740_DMA_TRANSFER_SIZE_16BYTE:
- dma->transfer_shift = 4;
- break;
- case JZ4740_DMA_TRANSFER_SIZE_32BYTE:
- dma->transfer_shift = 5;
- break;
- default:
- dma->transfer_shift = 0;
- break;
- }
-
- cmd = config->flags << JZ_DMA_CMD_FLAGS_OFFSET;
- cmd |= config->src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET;
- cmd |= config->dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET;
- cmd |= config->transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET;
- cmd |= config->mode << JZ_DMA_CMD_MODE_OFFSET;
- cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE;
-
- jz4740_dma_write(JZ_REG_DMA_CMD(dma->id), cmd);
- jz4740_dma_write(JZ_REG_DMA_STATUS_CTRL(dma->id), 0);
- jz4740_dma_write(JZ_REG_DMA_REQ_TYPE(dma->id), config->request_type);
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_configure);
-
-void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src)
-{
- jz4740_dma_write(JZ_REG_DMA_SRC_ADDR(dma->id), src);
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_set_src_addr);
-
-void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst)
-{
- jz4740_dma_write(JZ_REG_DMA_DST_ADDR(dma->id), dst);
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_set_dst_addr);
-
-void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count)
-{
- count >>= dma->transfer_shift;
- jz4740_dma_write(JZ_REG_DMA_TRANSFER_COUNT(dma->id), count);
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_set_transfer_count);
-
-void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
- jz4740_dma_complete_callback_t cb)
-{
- dma->complete_cb = cb;
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_set_complete_cb);
-
-void jz4740_dma_free(struct jz4740_dma_chan *dma)
-{
- dma->dev = NULL;
- dma->complete_cb = NULL;
- dma->used = 0;
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_free);
-
-void jz4740_dma_enable(struct jz4740_dma_chan *dma)
-{
- jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id),
- JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE,
- JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC |
- JZ_DMA_STATUS_CTRL_ENABLE);
-
- jz4740_dma_write_mask(JZ_REG_DMA_CTRL,
- JZ_DMA_CTRL_ENABLE,
- JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE);
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_enable);
-
-void jz4740_dma_disable(struct jz4740_dma_chan *dma)
-{
- jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
- JZ_DMA_STATUS_CTRL_ENABLE);
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_disable);
-
-uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma)
-{
- uint32_t residue;
- residue = jz4740_dma_read(JZ_REG_DMA_TRANSFER_COUNT(dma->id));
- return residue << dma->transfer_shift;
-}
-EXPORT_SYMBOL_GPL(jz4740_dma_get_residue);
-
-static void jz4740_dma_chan_irq(struct jz4740_dma_chan *dma)
-{
- (void) jz4740_dma_read(JZ_REG_DMA_STATUS_CTRL(dma->id));
-
- jz4740_dma_write_mask(JZ_REG_DMA_STATUS_CTRL(dma->id), 0,
- JZ_DMA_STATUS_CTRL_ENABLE | JZ_DMA_STATUS_CTRL_TRANSFER_DONE);
-
- if (dma->complete_cb)
- dma->complete_cb(dma, 0, dma->dev);
-}
-
-static irqreturn_t jz4740_dma_irq(int irq, void *dev_id)
-{
- uint32_t irq_status;
- unsigned int i;
-
- irq_status = readl(jz4740_dma_base + JZ_REG_DMA_IRQ);
-
- for (i = 0; i < 6; ++i) {
- if (irq_status & (1 << i))
- jz4740_dma_chan_irq(&jz4740_dma_channels[i]);
- }
-
- return IRQ_HANDLED;
-}
-
-static int jz4740_dma_init(void)
-{
- unsigned int ret;
-
- jz4740_dma_base = ioremap(JZ4740_DMAC_BASE_ADDR, 0x400);
-
- if (!jz4740_dma_base)
- return -EBUSY;
-
- spin_lock_init(&jz4740_dma_lock);
-
- ret = request_irq(JZ4740_IRQ_DMAC, jz4740_dma_irq, 0, "DMA", NULL);
-
- if (ret)
- printk(KERN_ERR "JZ4740 DMA: Failed to request irq: %d\n", ret);
-
- return ret;
-}
-arch_initcall(jz4740_dma_init);
diff --git a/arch/mips/jz4740/platform.c b/arch/mips/jz4740/platform.c
index e9348fd26a35..df65677f3d0b 100644
--- a/arch/mips/jz4740/platform.c
+++ b/arch/mips/jz4740/platform.c
@@ -329,3 +329,24 @@ struct platform_device jz4740_pwm_device = {
.name = "jz4740-pwm",
.id = -1,
};
+
+/* DMA */
+static struct resource jz4740_dma_resources[] = {
+ {
+ .start = JZ4740_DMAC_BASE_ADDR,
+ .end = JZ4740_DMAC_BASE_ADDR + 0x400 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JZ4740_IRQ_DMAC,
+ .end = JZ4740_IRQ_DMAC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device jz4740_dma_device = {
+ .name = "jz4740-dma",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(jz4740_dma_resources),
+ .resource = jz4740_dma_resources,
+};
diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c
index 3be9e7bb30ff..f291cf99b03a 100644
--- a/arch/mips/kernel/crash_dump.c
+++ b/arch/mips/kernel/crash_dump.c
@@ -4,16 +4,6 @@
#include <asm/uaccess.h>
#include <linux/slab.h>
-static int __init parse_savemaxmem(char *p)
-{
- if (p)
- saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
-
- return 1;
-}
-__setup("savemaxmem=", parse_savemaxmem);
-
-
static void *kdump_buf_page;
/**
diff --git a/arch/mips/loongson/lemote-2f/clock.c b/arch/mips/loongson/lemote-2f/clock.c
index bc739d4bab2e..4dc2f5fa3f67 100644
--- a/arch/mips/loongson/lemote-2f/clock.c
+++ b/arch/mips/loongson/lemote-2f/clock.c
@@ -121,7 +121,8 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
clk->rate = rate;
regval = LOONGSON_CHIPCFG0;
- regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);
+ regval = (regval & ~0x7) |
+ (loongson2_clockmod_table[i].driver_data - 1);
LOONGSON_CHIPCFG0 = regval;
return ret;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 9b973e0af9cb..4e73f10a7519 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -359,11 +359,24 @@ void __init paging_init(void)
static struct kcore_list kcore_kseg0;
#endif
-void __init mem_init(void)
+static inline void mem_init_free_highmem(void)
{
- unsigned long codesize, reservedpages, datasize, initsize;
- unsigned long tmp, ram;
+#ifdef CONFIG_HIGHMEM
+ unsigned long tmp;
+ for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
+ struct page *page = pfn_to_page(tmp);
+
+ if (!page_is_ram(tmp))
+ SetPageReserved(page);
+ else
+ free_highmem_page(page);
+ }
+#endif
+}
+
+void __init mem_init(void)
+{
#ifdef CONFIG_HIGHMEM
#ifdef CONFIG_DISCONTIGMEM
#error "CONFIG_HIGHMEM and CONFIG_DISCONTIGMEM dont work together yet"
@@ -374,34 +387,10 @@ void __init mem_init(void)
#endif
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
- totalram_pages += free_all_bootmem();
+ free_all_bootmem();
setup_zero_pages(); /* Setup zeroed pages. */
-
- reservedpages = ram = 0;
- for (tmp = 0; tmp < max_low_pfn; tmp++)
- if (page_is_ram(tmp) && pfn_valid(tmp)) {
- ram++;
- if (PageReserved(pfn_to_page(tmp)))
- reservedpages++;
- }
- num_physpages = ram;
-
-#ifdef CONFIG_HIGHMEM
- for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) {
- struct page *page = pfn_to_page(tmp);
-
- if (!page_is_ram(tmp)) {
- SetPageReserved(page);
- continue;
- }
- free_highmem_page(page);
- }
- num_physpages += totalhigh_pages;
-#endif
-
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+ mem_init_free_highmem();
+ mem_init_print_info(NULL);
#ifdef CONFIG_64BIT
if ((unsigned long) &_text > (unsigned long) CKSEG0)
@@ -410,16 +399,6 @@ void __init mem_init(void)
kclist_add(&kcore_kseg0, (void *) CKSEG0,
0x80000000 - 4, KCORE_TEXT);
#endif
-
- printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
- "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- ram << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10,
- totalhigh_pages << (PAGE_SHIFT-10));
}
#endif /* !CONFIG_NEED_MULTIPLE_NODES */
@@ -440,7 +419,8 @@ void free_init_pages(const char *what, unsigned long begin, unsigned long end)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
index 7e5fe2790d8a..f1baadd56e82 100644
--- a/arch/mips/mm/mmap.c
+++ b/arch/mips/mm/mmap.c
@@ -158,11 +158,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base(random_factor);
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
index 879077b01155..cb1ef9984069 100644
--- a/arch/mips/pci/pci-lantiq.c
+++ b/arch/mips/pci/pci-lantiq.c
@@ -89,7 +89,7 @@ static inline u32 ltq_calc_bar11mask(void)
u32 mem, bar11mask;
/* BAR11MASK value depends on available memory on system. */
- mem = num_physpages * PAGE_SIZE;
+ mem = get_num_physpages() * PAGE_SIZE;
bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
return bar11mask;
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index 1230f56429d7..a95c00f5fb96 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -357,8 +357,6 @@ static void __init szmem(void)
int slot;
cnodeid_t node;
- num_physpages = 0;
-
for_each_online_node(node) {
nodebytes = 0;
for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
@@ -381,7 +379,6 @@ static void __init szmem(void)
slot = MAX_MEM_SLOTS;
continue;
}
- num_physpages += slot_psize;
memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)),
PFN_PHYS(slot_psize), node);
}
@@ -480,32 +477,8 @@ void __init paging_init(void)
void __init mem_init(void)
{
- unsigned long codesize, datasize, initsize, tmp;
- unsigned node;
-
- high_memory = (void *) __va(num_physpages << PAGE_SHIFT);
-
- for_each_online_node(node) {
- /*
- * This will free up the bootmem, ie, slot 0 memory.
- */
- totalram_pages += free_all_bootmem_node(NODE_DATA(node));
- }
-
+ high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
+ free_all_bootmem();
setup_zero_pages(); /* This comes from node 0 */
-
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- tmp = nr_free_pages();
- printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
- "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
- tmp << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- (num_physpages - tmp) << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10,
- totalhigh_pages << (PAGE_SHIFT-10));
+ mem_init_print_info(NULL);
}
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
index 729a50991780..b7eccbd17bf7 100644
--- a/arch/mips/txx9/generic/setup_tx4939.c
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -331,7 +331,8 @@ static int tx4939_netdev_event(struct notifier_block *this,
unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
if (event == NETDEV_CHANGE && netif_carrier_ok(dev)) {
__u64 bit = 0;
if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(0))
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 428da175d073..70e4f663ebd2 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -13,6 +13,7 @@ config MN10300
select MODULES_USE_ELF_RELA
select OLD_SIGSUSPEND3
select OLD_SIGACTION
+ select HAVE_DEBUG_STACKOVERFLOW
config AM33_2
def_bool n
diff --git a/arch/mn10300/Kconfig.debug b/arch/mn10300/Kconfig.debug
index bdbfd444a9ff..94efb3ed223f 100644
--- a/arch/mn10300/Kconfig.debug
+++ b/arch/mn10300/Kconfig.debug
@@ -2,10 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
-
config DEBUG_DECOMPRESS_KERNEL
bool "Using serial port during decompressing kernel"
depends on DEBUG_KERNEL
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index b4ce844c9391..db80fd3e398b 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -74,4 +74,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
index d48a84fd7fae..8a2e6ded9a44 100644
--- a/arch/mn10300/mm/fault.c
+++ b/arch/mn10300/mm/fault.c
@@ -345,9 +345,10 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
- if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
- do_exit(SIGKILL);
+ if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) {
+ pagefault_out_of_memory();
+ return;
+ }
goto no_context;
do_sigbus:
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
index 5a8ace63a6b4..97a1ec0beeec 100644
--- a/arch/mn10300/mm/init.c
+++ b/arch/mn10300/mm/init.c
@@ -99,43 +99,21 @@ void __init paging_init(void)
*/
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
- int tmp;
-
BUG_ON(!mem_map);
#define START_PFN (contig_page_data.bdata->node_min_pfn)
#define MAX_LOW_PFN (contig_page_data.bdata->node_low_pfn)
- max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN;
+ max_mapnr = MAX_LOW_PFN - START_PFN;
high_memory = (void *) __va(MAX_LOW_PFN * PAGE_SIZE);
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
/* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem();
-
- reservedpages = 0;
- for (tmp = 0; tmp < num_physpages; tmp++)
- if (PageReserved(&mem_map[tmp]))
- reservedpages++;
-
- codesize = (unsigned long) &_etext - (unsigned long) &_stext;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk(KERN_INFO
- "Memory: %luk/%luk available"
- " (%dk kernel code, %dk reserved, %dk data, %dk init,"
- " %ldk highmem)\n",
- nr_free_pages() << (PAGE_SHIFT - 10),
- max_mapnr << (PAGE_SHIFT - 10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT - 10),
- datasize >> 10,
- initsize >> 10,
- totalhigh_pages << (PAGE_SHIFT - 10));
+ free_all_bootmem();
+
+ mem_init_print_info(NULL);
}
/*
@@ -152,6 +130,7 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 1072bfd18c50..99dbab1c59ac 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -22,6 +22,7 @@ config OPENRISC
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA
+ select HAVE_DEBUG_STACKOVERFLOW
config MMU
def_bool y
@@ -128,16 +129,6 @@ config CMDLINE
menu "Debugging options"
-config DEBUG_STACKOVERFLOW
- bool "Check for kernel stack overflow"
- default y
- help
- Make extra checks for space available on stack in some
- critical functions. This will cause kernel to run a bit slower,
- but will catch most of kernel stack overruns and exit gracefully.
-
- Say Y if you are unsure.
-
config JUMP_UPON_UNHANDLED_EXCEPTION
bool "Try to die gracefully"
default y
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index f20d01d9aaf9..195653e851da 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -66,3 +66,4 @@ generic-y += types.h
generic-y += ucontext.h
generic-y += user.h
generic-y += word-at-a-time.h
+generic-y += xor.h
diff --git a/arch/openrisc/mm/fault.c b/arch/openrisc/mm/fault.c
index e2bfafce66c5..4a41f8493ab0 100644
--- a/arch/openrisc/mm/fault.c
+++ b/arch/openrisc/mm/fault.c
@@ -267,10 +267,10 @@ out_of_memory:
__asm__ __volatile__("l.nop 1");
up_read(&mm->mmap_sem);
- printk("VM: killing process %s\n", tsk->comm);
- if (user_mode(regs))
- do_exit(SIGKILL);
- goto no_context;
+ if (!user_mode(regs))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
do_sigbus:
up_read(&mm->mmap_sem);
diff --git a/arch/openrisc/mm/init.c b/arch/openrisc/mm/init.c
index b3cbc6703837..7f94652311d7 100644
--- a/arch/openrisc/mm/init.c
+++ b/arch/openrisc/mm/init.c
@@ -202,56 +202,20 @@ void __init paging_init(void)
/* References to section boundaries */
-static int __init free_pages_init(void)
-{
- int reservedpages, pfn;
-
- /* this will put all low memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
- reservedpages = 0;
- for (pfn = 0; pfn < max_low_pfn; pfn++) {
- /*
- * Only count reserved RAM pages
- */
- if (PageReserved(mem_map + pfn))
- reservedpages++;
- }
-
- return reservedpages;
-}
-
-static void __init set_max_mapnr_init(void)
-{
- max_mapnr = num_physpages = max_low_pfn;
-}
-
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
-
BUG_ON(!mem_map);
- set_max_mapnr_init();
-
+ max_mapnr = max_low_pfn;
high_memory = (void *)__va(max_low_pfn * PAGE_SIZE);
/* clear the zero-page */
memset((void *)empty_zero_page, 0, PAGE_SIZE);
- reservedpages = free_pages_init();
-
- codesize = (unsigned long)&_etext - (unsigned long)&_stext;
- datasize = (unsigned long)&_edata - (unsigned long)&_etext;
- initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
+ /* this will put all low memory onto the freelists */
+ free_all_bootmem();
- printk(KERN_INFO
- "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
- (unsigned long)nr_free_pages() << (PAGE_SHIFT - 10),
- max_mapnr << (PAGE_SHIFT - 10), codesize >> 10,
- reservedpages << (PAGE_SHIFT - 10), datasize >> 10,
- initsize >> 10, (unsigned long)(0 << (PAGE_SHIFT - 10))
- );
+ mem_init_print_info(NULL);
printk("mem_init_done ...........................................\n");
mem_init_done = 1;
@@ -261,11 +225,11 @@ void __init mem_init(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 2a2aea5aae5b..aa399a5259b6 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -27,6 +27,7 @@ config PARISC
select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS
select TTY # Needed for pdc_cons.c
+ select HAVE_DEBUG_STACKOVERFLOW
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug
index 08a332f6ee87..bc989e522a04 100644
--- a/arch/parisc/Kconfig.debug
+++ b/arch/parisc/Kconfig.debug
@@ -13,14 +13,3 @@ config DEBUG_RODATA
If in doubt, say "N".
endmenu
-
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- default y
- depends on DEBUG_KERNEL
- ---help---
- Say Y here if you want to check the overflows of kernel, IRQ
- and exception stacks. This option will cause messages of the
- stacks in detail when free stack space drops below a certain
- limit.
- If in doubt, say "N".
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
index 96ec3982be8d..e02f665f804a 100644
--- a/arch/parisc/Makefile
+++ b/arch/parisc/Makefile
@@ -17,6 +17,8 @@
# Mike Shaver, Helge Deller and Martin K. Petersen
#
+KBUILD_IMAGE := vmlinuz
+
KBUILD_DEFCONFIG := default_defconfig
NM = sh $(srctree)/arch/parisc/nm
@@ -92,7 +94,7 @@ PALOCONF := $(shell if [ -f $(src)/palo.conf ]; then echo $(src)/palo.conf; \
else echo $(obj)/palo.conf; \
fi)
-palo: vmlinux
+palo: vmlinuz
@if test ! -x "$(PALO)"; then \
echo 'ERROR: Please install palo first (apt-get install palo)';\
echo 'or build it from source and install it somewhere in your $$PATH';\
@@ -107,10 +109,14 @@ palo: vmlinux
fi
$(PALO) -f $(PALOCONF)
-# Shorthands for known targets not supported by parisc, use vmlinux as default
-Image zImage bzImage: vmlinux
+# Shorthands for known targets not supported by parisc, use vmlinux/vmlinuz as default
+Image: vmlinux
+zImage bzImage: vmlinuz
+
+vmlinuz: vmlinux
+ @gzip -cf -9 $< > $@
-install: vmlinux
+install: vmlinuz
sh $(src)/arch/parisc/install.sh \
$(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
@@ -119,6 +125,7 @@ MRPROPER_FILES += palo.conf
define archhelp
@echo '* vmlinux - Uncompressed kernel image (./vmlinux)'
+ @echo ' vmlinuz - Compressed kernel image (./vmlinuz)'
@echo ' palo - Bootable image (./lifimage)'
@echo ' install - Install kernel using'
@echo ' (your) ~/bin/$(INSTALLKERNEL) or'
diff --git a/arch/parisc/defpalo.conf b/arch/parisc/defpalo.conf
index 4e1ae25b08d1..208ff3b41487 100644
--- a/arch/parisc/defpalo.conf
+++ b/arch/parisc/defpalo.conf
@@ -4,7 +4,7 @@
# Most people using 'make palo' want a bootable file, usable for
# network or tape booting for example.
--init-tape=lifimage
---recoverykernel=vmlinux
+--recoverykernel=vmlinuz
########## Pick your ROOT here! ##########
# You need at least one 'root='!
@@ -12,10 +12,10 @@
# If you want a root ramdisk, use the next 2 lines
# (Edit the ramdisk image name!!!!)
--ramdisk=ram-disk-image-file
---commandline=0/vmlinux HOME=/ root=/dev/ram initrd=0/ramdisk
+--commandline=0/vmlinuz HOME=/ root=/dev/ram initrd=0/ramdisk panic_timeout=60 panic=-1
# If you want NFS root, use the following command line (Edit the HOSTNAME!!!)
-#--commandline=0/vmlinux HOME=/ root=/dev/nfs nfsroot=HOSTNAME ip=bootp
+#--commandline=0/vmlinuz HOME=/ root=/dev/nfs nfsroot=HOSTNAME ip=bootp
# If you have root on a disk partition, use this (Edit the partition name!!!)
-#--commandline=0/vmlinux HOME=/ root=/dev/sda1
+#--commandline=0/vmlinuz HOME=/ root=/dev/sda1
diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h
index d306b75bc77f..e1509308899f 100644
--- a/arch/parisc/include/asm/special_insns.h
+++ b/arch/parisc/include/asm/special_insns.h
@@ -32,9 +32,12 @@ static inline void set_eiem(unsigned long val)
cr; \
})
-#define mtsp(gr, cr) \
- __asm__ __volatile__("mtsp %0,%1" \
+#define mtsp(val, cr) \
+ { if (__builtin_constant_p(val) && ((val) == 0)) \
+ __asm__ __volatile__("mtsp %%r0,%0" : : "i" (cr) : "memory"); \
+ else \
+ __asm__ __volatile__("mtsp %0,%1" \
: /* no outputs */ \
- : "r" (gr), "i" (cr) : "memory")
+ : "r" (val), "i" (cr) : "memory"); }
#endif /* __PARISC_SPECIAL_INSNS_H */
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
index 5273da991e06..9d086a599fa0 100644
--- a/arch/parisc/include/asm/tlbflush.h
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -63,13 +63,14 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long addr)
{
- unsigned long flags;
+ unsigned long flags, sid;
/* For one page, it's not worth testing the split_tlb variable */
mb();
- mtsp(vma->vm_mm->context,1);
+ sid = vma->vm_mm->context;
purge_tlb_start(flags);
+ mtsp(sid, 1);
pdtlb(addr);
pitlb(addr);
purge_tlb_end(flags);
diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h
index 0304b92ccfea..cc61c475f277 100644
--- a/arch/parisc/include/uapi/asm/fcntl.h
+++ b/arch/parisc/include/uapi/asm/fcntl.h
@@ -20,6 +20,7 @@
#define O_INVISIBLE 004000000 /* invisible I/O, for DMAPI/XDSM */
#define O_PATH 020000000
+#define O_TMPFILE 040000000
#define F_GETLK64 8
#define F_SETLK64 9
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index 70c512a386f7..f866fff9a004 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -73,6 +73,8 @@
#define SO_SELECT_ERR_QUEUE 0x4026
+#define SO_LL 0x4027
+
/* O_NONBLOCK clashes with the bits used for socket types. Therefore we
* have to define SOCK_NONBLOCK to a different value here.
*/
diff --git a/arch/parisc/install.sh b/arch/parisc/install.sh
index e593fc8d58bc..4da682b466d0 100644
--- a/arch/parisc/install.sh
+++ b/arch/parisc/install.sh
@@ -26,13 +26,13 @@ if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
# Default install
-if [ -f $4/vmlinux ]; then
- mv $4/vmlinux $4/vmlinux.old
+if [ -f $4/vmlinuz ]; then
+ mv $4/vmlinuz $4/vmlinuz.old
fi
if [ -f $4/System.map ]; then
mv $4/System.map $4/System.old
fi
-cat $2 > $4/vmlinux
+cat $2 > $4/vmlinuz
cp $3 $4/System.map
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 65fb4cbc3a0f..2e65aa54bd10 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -440,8 +440,8 @@ void __flush_tlb_range(unsigned long sid, unsigned long start,
else {
unsigned long flags;
- mtsp(sid, 1);
purge_tlb_start(flags);
+ mtsp(sid, 1);
if (split_tlb) {
while (npages--) {
pdtlb(start);
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
index c8fb61ed32f4..8a96c8ab9fe6 100644
--- a/arch/parisc/kernel/processor.c
+++ b/arch/parisc/kernel/processor.c
@@ -371,10 +371,23 @@ show_cpuinfo (struct seq_file *m, void *v)
seq_printf(m, "capabilities\t:");
if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)
- seq_printf(m, " os32");
+ seq_puts(m, " os32");
if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS64)
- seq_printf(m, " os64");
- seq_printf(m, "\n");
+ seq_puts(m, " os64");
+ if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC)
+ seq_puts(m, " iopdir_fdc");
+ switch (boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) {
+ case PDC_MODEL_NVA_SUPPORTED:
+ seq_puts(m, " nva_supported");
+ break;
+ case PDC_MODEL_NVA_SLOW:
+ seq_puts(m, " nva_slow");
+ break;
+ case PDC_MODEL_NVA_UNSUPPORTED:
+ seq_puts(m, " needs_equivalent_aliasing");
+ break;
+ }
+ seq_printf(m, " (0x%02lx)\n", boot_cpu_data.pdc.capabilities);
seq_printf(m, "model\t\t: %s\n"
"model name\t: %s\n",
diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
index a49cc812df8a..ac4370b1ca40 100644
--- a/arch/parisc/lib/memcpy.c
+++ b/arch/parisc/lib/memcpy.c
@@ -2,6 +2,7 @@
* Optimized memory copy routines.
*
* Copyright (C) 2004 Randolph Chung <tausq@debian.org>
+ * Copyright (C) 2013 Helge Deller <deller@gmx.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
@@ -153,17 +154,21 @@ static inline void prefetch_dst(const void *addr)
#define prefetch_dst(addr) do { } while(0)
#endif
+#define PA_MEMCPY_OK 0
+#define PA_MEMCPY_LOAD_ERROR 1
+#define PA_MEMCPY_STORE_ERROR 2
+
/* Copy from a not-aligned src to an aligned dst, using shifts. Handles 4 words
* per loop. This code is derived from glibc.
*/
-static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src, unsigned long len, unsigned long o_dst, unsigned long o_src, unsigned long o_len)
+static inline unsigned long copy_dstaligned(unsigned long dst,
+ unsigned long src, unsigned long len)
{
/* gcc complains that a2 and a3 may be uninitialized, but actually
* they cannot be. Initialize a2/a3 to shut gcc up.
*/
register unsigned int a0, a1, a2 = 0, a3 = 0;
int sh_1, sh_2;
- struct exception_data *d;
/* prefetch_src((const void *)src); */
@@ -197,7 +202,7 @@ static inline unsigned long copy_dstaligned(unsigned long dst, unsigned long src
goto do2;
case 0:
if (len == 0)
- return 0;
+ return PA_MEMCPY_OK;
/* a3 = ((unsigned int *) src)[0];
a0 = ((unsigned int *) src)[1]; */
ldw(s_space, 0, src, a3, cda_ldw_exc);
@@ -256,42 +261,35 @@ do0:
preserve_branch(handle_load_error);
preserve_branch(handle_store_error);
- return 0;
+ return PA_MEMCPY_OK;
handle_load_error:
__asm__ __volatile__ ("cda_ldw_exc:\n");
- d = &__get_cpu_var(exception_data);
- DPRINTF("cda_ldw_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n",
- o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src);
- return o_len * 4 - d->fault_addr + o_src;
+ return PA_MEMCPY_LOAD_ERROR;
handle_store_error:
__asm__ __volatile__ ("cda_stw_exc:\n");
- d = &__get_cpu_var(exception_data);
- DPRINTF("cda_stw_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n",
- o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst);
- return o_len * 4 - d->fault_addr + o_dst;
+ return PA_MEMCPY_STORE_ERROR;
}
-/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
-static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
+/* Returns PA_MEMCPY_OK, PA_MEMCPY_LOAD_ERROR or PA_MEMCPY_STORE_ERROR.
+ * In case of an access fault the faulty address can be read from the per_cpu
+ * exception data struct. */
+static unsigned long pa_memcpy_internal(void *dstp, const void *srcp,
+ unsigned long len)
{
register unsigned long src, dst, t1, t2, t3;
register unsigned char *pcs, *pcd;
register unsigned int *pws, *pwd;
register double *pds, *pdd;
- unsigned long ret = 0;
- unsigned long o_dst, o_src, o_len;
- struct exception_data *d;
+ unsigned long ret;
src = (unsigned long)srcp;
dst = (unsigned long)dstp;
pcs = (unsigned char *)srcp;
pcd = (unsigned char *)dstp;
- o_dst = dst; o_src = src; o_len = len;
-
/* prefetch_src((const void *)srcp); */
if (len < THRESHOLD)
@@ -401,7 +399,7 @@ byte_copy:
len--;
}
- return 0;
+ return PA_MEMCPY_OK;
unaligned_copy:
/* possibly we are aligned on a word, but not on a double... */
@@ -438,8 +436,7 @@ unaligned_copy:
src = (unsigned long)pcs;
}
- ret = copy_dstaligned(dst, src, len / sizeof(unsigned int),
- o_dst, o_src, o_len);
+ ret = copy_dstaligned(dst, src, len / sizeof(unsigned int));
if (ret)
return ret;
@@ -454,17 +451,41 @@ unaligned_copy:
handle_load_error:
__asm__ __volatile__ ("pmc_load_exc:\n");
- d = &__get_cpu_var(exception_data);
- DPRINTF("pmc_load_exc: o_len=%lu fault_addr=%lu o_src=%lu ret=%lu\n",
- o_len, d->fault_addr, o_src, o_len - d->fault_addr + o_src);
- return o_len - d->fault_addr + o_src;
+ return PA_MEMCPY_LOAD_ERROR;
handle_store_error:
__asm__ __volatile__ ("pmc_store_exc:\n");
+ return PA_MEMCPY_STORE_ERROR;
+}
+
+
+/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
+static unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
+{
+ unsigned long ret, fault_addr, reference;
+ struct exception_data *d;
+
+ ret = pa_memcpy_internal(dstp, srcp, len);
+ if (likely(ret == PA_MEMCPY_OK))
+ return 0;
+
+ /* if a load or store fault occured we can get the faulty addr */
d = &__get_cpu_var(exception_data);
- DPRINTF("pmc_store_exc: o_len=%lu fault_addr=%lu o_dst=%lu ret=%lu\n",
- o_len, d->fault_addr, o_dst, o_len - d->fault_addr + o_dst);
- return o_len - d->fault_addr + o_dst;
+ fault_addr = d->fault_addr;
+
+ /* error in load or store? */
+ if (ret == PA_MEMCPY_LOAD_ERROR)
+ reference = (unsigned long) srcp;
+ else
+ reference = (unsigned long) dstp;
+
+ DPRINTF("pa_memcpy: fault type = %lu, len=%lu fault_addr=%lu ref=%lu\n",
+ ret, len, fault_addr, reference);
+
+ if (fault_addr >= reference)
+ return len - (fault_addr - reference);
+ else
+ return len;
}
#ifdef __KERNEL__
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 505b56c6b9b9..b0f96c0e6316 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -214,7 +214,6 @@ static void __init setup_bootmem(void)
mem_limit_func(); /* check for "mem=" argument */
mem_max = 0;
- num_physpages = 0;
for (i = 0; i < npmem_ranges; i++) {
unsigned long rsize;
@@ -229,10 +228,8 @@ static void __init setup_bootmem(void)
npmem_ranges = i + 1;
mem_max = mem_limit;
}
- num_physpages += pmem_ranges[i].pages;
break;
}
- num_physpages += pmem_ranges[i].pages;
mem_max += rsize;
}
@@ -532,7 +529,7 @@ void free_initmem(void)
* pages are no-longer executable */
flush_icache_range(init_begin, init_end);
- num_physpages += free_initmem_default(0);
+ free_initmem_default(-1);
/* set up a new led state on systems shipped LED State panel */
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
@@ -580,8 +577,6 @@ unsigned long pcxl_dma_start __read_mostly;
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
-
/* Do sanity checks on page table constants */
BUILD_BUG_ON(PTE_ENTRY_SIZE != sizeof(pte_t));
BUILD_BUG_ON(PMD_ENTRY_SIZE != sizeof(pmd_t));
@@ -590,45 +585,8 @@ void __init mem_init(void)
> BITS_PER_LONG);
high_memory = __va((max_pfn << PAGE_SHIFT));
-
-#ifndef CONFIG_DISCONTIGMEM
- max_mapnr = page_to_pfn(virt_to_page(high_memory - 1)) + 1;
- totalram_pages += free_all_bootmem();
-#else
- {
- int i;
-
- for (i = 0; i < npmem_ranges; i++)
- totalram_pages += free_all_bootmem_node(NODE_DATA(i));
- }
-#endif
-
- codesize = (unsigned long)_etext - (unsigned long)_text;
- datasize = (unsigned long)_edata - (unsigned long)_etext;
- initsize = (unsigned long)__init_end - (unsigned long)__init_begin;
-
- reservedpages = 0;
-{
- unsigned long pfn;
-#ifdef CONFIG_DISCONTIGMEM
- int i;
-
- for (i = 0; i < npmem_ranges; i++) {
- for (pfn = node_start_pfn(i); pfn < node_end_pfn(i); pfn++) {
- if (PageReserved(pfn_to_page(pfn)))
- reservedpages++;
- }
- }
-#else /* !CONFIG_DISCONTIGMEM */
- for (pfn = 0; pfn < max_pfn; pfn++) {
- /*
- * Only count reserved RAM pages
- */
- if (PageReserved(pfn_to_page(pfn)))
- reservedpages++;
- }
-#endif
-}
+ set_max_mapnr(page_to_pfn(virt_to_page(high_memory - 1)) + 1);
+ free_all_bootmem();
#ifdef CONFIG_PA11
if (hppa_dma_ops == &pcxl_dma_ops) {
@@ -643,15 +601,7 @@ void __init mem_init(void)
parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
#endif
- printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10
- );
-
+ mem_init_print_info(NULL);
#ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */
printk("virtual kernel memory layout:\n"
" vmalloc : 0x%p - 0x%p (%4ld MB)\n"
@@ -1101,6 +1051,6 @@ void flush_tlb_all(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- num_physpages += free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 508e3fe934d2..3bf72cd2c8fc 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -138,6 +138,7 @@ config PPC
select ARCH_USE_BUILTIN_BSWAP
select OLD_SIGSUSPEND
select OLD_SIGACTION if PPC32
+ select HAVE_DEBUG_STACKOVERFLOW
config EARLY_PRINTK
bool
@@ -298,7 +299,7 @@ config HUGETLB_PAGE_SIZE_VARIABLE
config MATH_EMULATION
bool "Math emulation"
- depends on 4xx || 8xx || E200 || PPC_MPC832x || E500
+ depends on 4xx || 8xx || PPC_MPC832x || BOOKE
---help---
Some PowerPC chips designed for embedded applications do not have
a floating-point unit and therefore do not implement the
@@ -307,6 +308,10 @@ config MATH_EMULATION
unit, which will allow programs that use floating-point
instructions to run.
+ This is also useful to emulate missing (optional) instructions
+ such as fsqrt on cores that do have an FPU but do not implement
+ them (such as Freescale BookE).
+
config PPC_TRANSACTIONAL_MEM
bool "Transactional Memory support for POWERPC"
depends on PPC_BOOK3S_64
@@ -315,17 +320,6 @@ config PPC_TRANSACTIONAL_MEM
---help---
Support user-mode Transactional Memory on POWERPC.
-config 8XX_MINIMAL_FPEMU
- bool "Minimal math emulation for 8xx"
- depends on 8xx && !MATH_EMULATION
- help
- Older arch/ppc kernels still emulated a few floating point
- instructions such as load and store, even when full math
- emulation is disabled. Say "Y" here if you want to preserve
- this behavior.
-
- It is recommended that you build a soft-float userspace instead.
-
config IOMMU_HELPER
def_bool PPC64
@@ -674,7 +668,6 @@ config SBUS
config FSL_SOC
bool
- select HAVE_CAN_FLEXCAN if NET && CAN
config FSL_PCI
bool
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 863d877e0b5f..21c9f304e96c 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -28,13 +28,6 @@ config PRINT_STACK_DEPTH
too small and stack traces cause important information to
scroll off the screen.
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config HCALL_STATS
bool "Hypervisor call instrumentation"
depends on PPC_PSERIES && DEBUG_FS && TRACEPOINTS
@@ -147,6 +140,13 @@ choice
enable debugging for the wrong type of machine your kernel
_will not boot_.
+config PPC_EARLY_DEBUG_BOOTX
+ bool "BootX or OpenFirmware"
+ depends on BOOTX_TEXT
+ help
+ Select this to enable early debugging for a machine using BootX
+ or OpenFirmware.
+
config PPC_EARLY_DEBUG_LPAR
bool "LPAR HV Console"
depends on PPC_PSERIES
diff --git a/arch/powerpc/boot/dts/currituck.dts b/arch/powerpc/boot/dts/currituck.dts
index b801dd06e573..d2c8a872308e 100644
--- a/arch/powerpc/boot/dts/currituck.dts
+++ b/arch/powerpc/boot/dts/currituck.dts
@@ -103,6 +103,11 @@
interrupts = <34 2>;
};
+ FPGA0: fpga@50000000 {
+ compatible = "ibm,currituck-fpga";
+ reg = <0x50000000 0x4>;
+ };
+
IIC0: i2c@00000000 {
compatible = "ibm,iic-currituck", "ibm,iic";
reg = <0x0 0x00000014>;
diff --git a/arch/powerpc/boot/dts/fsl/interlaken-lac-portals.dtsi b/arch/powerpc/boot/dts/fsl/interlaken-lac-portals.dtsi
new file mode 100644
index 000000000000..9cffccf4e07e
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/interlaken-lac-portals.dtsi
@@ -0,0 +1,156 @@
+/* T4240 Interlaken LAC Portal device tree stub with 24 portals.
+ *
+ * Copyright 2012 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.
+ */
+
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+compatible = "fsl,interlaken-lac-portals";
+
+lportal0: lac-portal@0 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x0 0x1000>;
+};
+
+lportal1: lac-portal@1000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x1000 0x1000>;
+};
+
+lportal2: lac-portal@2000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x2000 0x1000>;
+};
+
+lportal3: lac-portal@3000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x3000 0x1000>;
+};
+
+lportal4: lac-portal@4000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x4000 0x1000>;
+};
+
+lportal5: lac-portal@5000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x5000 0x1000>;
+};
+
+lportal6: lac-portal@6000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x6000 0x1000>;
+};
+
+lportal7: lac-portal@7000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x7000 0x1000>;
+};
+
+lportal8: lac-portal@8000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x8000 0x1000>;
+};
+
+lportal9: lac-portal@9000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x9000 0x1000>;
+};
+
+lportal10: lac-portal@A000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0xA000 0x1000>;
+};
+
+lportal11: lac-portal@B000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0xB000 0x1000>;
+};
+
+lportal12: lac-portal@C000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0xC000 0x1000>;
+};
+
+lportal13: lac-portal@D000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0xD000 0x1000>;
+};
+
+lportal14: lac-portal@E000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0xE000 0x1000>;
+};
+
+lportal15: lac-portal@F000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0xF000 0x1000>;
+};
+
+lportal16: lac-portal@10000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x10000 0x1000>;
+};
+
+lportal17: lac-portal@11000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x11000 0x1000>;
+};
+
+lportal18: lac-portal@1200 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x12000 0x1000>;
+};
+
+lportal19: lac-portal@13000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x13000 0x1000>;
+};
+
+lportal20: lac-portal@14000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x14000 0x1000>;
+};
+
+lportal21: lac-portal@15000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x15000 0x1000>;
+};
+
+lportal22: lac-portal@16000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x16000 0x1000>;
+};
+
+lportal23: lac-portal@17000 {
+ compatible = "fsl,interlaken-lac-portal-v1.0";
+ reg = <0x17000 0x1000>;
+};
diff --git a/arch/powerpc/boot/dts/fsl/interlaken-lac.dtsi b/arch/powerpc/boot/dts/fsl/interlaken-lac.dtsi
new file mode 100644
index 000000000000..e8208720ac0e
--- /dev/null
+++ b/arch/powerpc/boot/dts/fsl/interlaken-lac.dtsi
@@ -0,0 +1,45 @@
+/*
+ * T4 Interlaken Look-aside Controller (LAC) device tree stub
+ *
+ * Copyright 2012 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.
+ */
+
+lac: lac@229000 {
+ compatible = "fsl,interlaken-lac";
+ reg = <0x229000 0x1000>;
+ interrupts = <16 2 1 18>;
+};
+
+lac-hv@228000 {
+ compatible = "fsl,interlaken-lac-hv";
+ reg = <0x228000 0x1000>;
+ fsl,non-hv-node = <&lac>;
+};
diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig
index 2a84fd7f631c..671a8f960afa 100644
--- a/arch/powerpc/configs/c2k_defconfig
+++ b/arch/powerpc/configs/c2k_defconfig
@@ -423,6 +423,8 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_BOOTX_TEXT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_BOOTX=y
CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 07b7f2af2dca..1ea22fc24ea8 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -284,6 +284,8 @@ CONFIG_DEBUG_MUTEXES=y
CONFIG_LATENCYTOP=y
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_BOOTX_TEXT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_BOOTX=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_ECB=m
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index 02ac96b679b8..2a5afac29861 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -138,6 +138,8 @@ CONFIG_DEBUG_STACK_USAGE=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
CONFIG_BOOTX_TEXT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_BOOTX=y
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/mpc512x_defconfig b/arch/powerpc/configs/mpc512x_defconfig
index 0d0d981442fd..ee853a1b1b2c 100644
--- a/arch/powerpc/configs/mpc512x_defconfig
+++ b/arch/powerpc/configs/mpc512x_defconfig
@@ -1,7 +1,6 @@
-CONFIG_EXPERIMENTAL=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-CONFIG_SPARSE_IRQ=y
+CONFIG_NO_HZ=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_BLK_DEV_INITRD=y
# CONFIG_COMPAT_BRK is not set
@@ -9,6 +8,7 @@ CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
# CONFIG_IOSCHED_CFQ is not set
# CONFIG_PPC_CHRP is not set
CONFIG_PPC_MPC512x=y
@@ -16,9 +16,7 @@ CONFIG_MPC5121_ADS=y
CONFIG_MPC512x_GENERIC=y
CONFIG_PDM360NG=y
# CONFIG_PPC_PMAC is not set
-CONFIG_NO_HZ=y
CONFIG_HZ_1000=y
-# CONFIG_MIGRATION is not set
# CONFIG_SECCOMP is not set
# CONFIG_PCI is not set
CONFIG_NET=y
@@ -33,8 +31,6 @@ CONFIG_IP_PNP=y
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
CONFIG_CAN=y
-CONFIG_CAN_RAW=y
-CONFIG_CAN_BCM=y
CONFIG_CAN_VCAN=y
CONFIG_CAN_MSCAN=y
CONFIG_CAN_DEBUG_DEVICES=y
@@ -46,7 +42,6 @@ CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_FIRMWARE_IN_KERNEL is not set
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
@@ -60,7 +55,6 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_BLK_DEV_XIP=y
-CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_AT24=y
CONFIG_EEPROM_AT25=y
CONFIG_SCSI=y
@@ -68,6 +62,7 @@ CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
CONFIG_NETDEVICES=y
+CONFIG_FS_ENET=y
CONFIG_MARVELL_PHY=y
CONFIG_DAVICOM_PHY=y
CONFIG_QSEMI_PHY=y
@@ -83,10 +78,6 @@ CONFIG_STE10XP=y
CONFIG_LSI_ET1011C_PHY=y
CONFIG_FIXED_PHY=y
CONFIG_MDIO_BITBANG=y
-CONFIG_NET_ETHERNET=y
-CONFIG_FS_ENET=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_EVDEV=y
@@ -106,14 +97,18 @@ CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_MPC8XXX=y
# CONFIG_HWMON is not set
CONFIG_MEDIA_SUPPORT=y
-CONFIG_VIDEO_DEV=y
CONFIG_VIDEO_ADV_DEBUG=y
-# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
-CONFIG_VIDEO_SAA711X=y
CONFIG_FB=y
CONFIG_FB_FSL_DIU=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_FSL=y
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_FSL_USB2=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_M41T80=y
CONFIG_RTC_DRV_MPC5121=y
@@ -129,9 +124,7 @@ CONFIG_TMPFS=y
CONFIG_JFFS2_FS=y
CONFIG_UBIFS_FS=y
CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 165e6b32baef..152fa05b15e4 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -131,6 +131,7 @@ CONFIG_DUMMY=y
CONFIG_FS_ENET=y
CONFIG_UCC_GETH=y
CONFIG_GIANFAR=y
+CONFIG_E1000E=y
CONFIG_MARVELL_PHY=y
CONFIG_DAVICOM_PHY=y
CONFIG_CICADA_PHY=y
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
index 29767a8dfea5..a73626b09051 100644
--- a/arch/powerpc/configs/pmac32_defconfig
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -350,6 +350,8 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
CONFIG_BOOTX_TEXT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_BOOTX=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_MD4=m
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index aef3f71de5ad..c86fcb92358e 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -398,6 +398,8 @@ CONFIG_FTR_FIXUP_SELFTEST=y
CONFIG_MSI_BITMAP_SELFTEST=y
CONFIG_XMON=y
CONFIG_BOOTX_TEXT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_BOOTX=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index be1cb6ea3a36..20ebfaf7234b 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -1264,6 +1264,8 @@ CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_XMON=y
CONFIG_BOOTX_TEXT=y
+CONFIG_PPC_EARLY_DEBUG=y
+CONFIG_PPC_EARLY_DEBUG_BOOTX=y
CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index c4dfbaf8b192..bea8587c3af5 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -296,6 +296,7 @@ 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
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index a80e32b46c11..09a8743143f3 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/string.h>
+#include <linux/time.h>
struct pci_dev;
struct pci_bus;
@@ -52,6 +53,7 @@ struct device_node;
#define EEH_PE_ISOLATED (1 << 0) /* Isolated PE */
#define EEH_PE_RECOVERING (1 << 1) /* Recovering PE */
+#define EEH_PE_PHB_DEAD (1 << 2) /* Dead PHB */
struct eeh_pe {
int type; /* PE type: PHB/Bus/Device */
@@ -59,8 +61,10 @@ struct eeh_pe {
int config_addr; /* Traditional PCI address */
int addr; /* PE configuration address */
struct pci_controller *phb; /* Associated PHB */
+ struct pci_bus *bus; /* Top PCI bus for bus PE */
int check_count; /* Times of ignored error */
int freeze_count; /* Times of froze up */
+ struct timeval tstamp; /* Time on first-time freeze */
int false_positives; /* Times of reported #ff's */
struct eeh_pe *parent; /* Parent PE */
struct list_head child_list; /* Link PE to the child list */
@@ -95,12 +99,12 @@ struct eeh_dev {
static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev)
{
- return edev->dn;
+ return edev ? edev->dn : NULL;
}
static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
{
- return edev->pdev;
+ return edev ? edev->pdev : NULL;
}
/*
@@ -130,8 +134,9 @@ static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
struct eeh_ops {
char *name;
int (*init)(void);
+ int (*post_init)(void);
void* (*of_probe)(struct device_node *dn, void *flag);
- void* (*dev_probe)(struct pci_dev *dev, void *flag);
+ int (*dev_probe)(struct pci_dev *dev, void *flag);
int (*set_option)(struct eeh_pe *pe, int option);
int (*get_pe_addr)(struct eeh_pe *pe);
int (*get_state)(struct eeh_pe *pe, int *state);
@@ -141,11 +146,12 @@ struct eeh_ops {
int (*configure_bridge)(struct eeh_pe *pe);
int (*read_config)(struct device_node *dn, int where, int size, u32 *val);
int (*write_config)(struct device_node *dn, int where, int size, u32 val);
+ int (*next_error)(struct eeh_pe **pe);
};
extern struct eeh_ops *eeh_ops;
extern int eeh_subsystem_enabled;
-extern struct mutex eeh_mutex;
+extern raw_spinlock_t confirm_error_lock;
extern int eeh_probe_mode;
#define EEH_PROBE_MODE_DEV (1<<0) /* From PCI device */
@@ -166,14 +172,14 @@ static inline int eeh_probe_mode_dev(void)
return (eeh_probe_mode == EEH_PROBE_MODE_DEV);
}
-static inline void eeh_lock(void)
+static inline void eeh_serialize_lock(unsigned long *flags)
{
- mutex_lock(&eeh_mutex);
+ raw_spin_lock_irqsave(&confirm_error_lock, *flags);
}
-static inline void eeh_unlock(void)
+static inline void eeh_serialize_unlock(unsigned long flags)
{
- mutex_unlock(&eeh_mutex);
+ raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
}
/*
@@ -184,8 +190,11 @@ static inline void eeh_unlock(void)
typedef void *(*eeh_traverse_func)(void *data, void *flag);
int eeh_phb_pe_create(struct pci_controller *phb);
+struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb);
+struct eeh_pe *eeh_pe_get(struct eeh_dev *edev);
int eeh_add_to_parent_pe(struct eeh_dev *edev);
int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe);
+void eeh_pe_update_time_stamp(struct eeh_pe *pe);
void *eeh_pe_dev_traverse(struct eeh_pe *root,
eeh_traverse_func fn, void *flag);
void eeh_pe_restore_bars(struct eeh_pe *pe);
@@ -193,12 +202,13 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe);
void *eeh_dev_init(struct device_node *dn, void *data);
void eeh_dev_phb_init_dynamic(struct pci_controller *phb);
+int eeh_init(void);
int __init eeh_ops_register(struct eeh_ops *ops);
int __exit eeh_ops_unregister(const char *name);
unsigned long eeh_check_failure(const volatile void __iomem *token,
unsigned long val);
int eeh_dev_check_failure(struct eeh_dev *edev);
-void __init eeh_addr_cache_build(void);
+void eeh_addr_cache_build(void);
void eeh_add_device_tree_early(struct device_node *);
void eeh_add_device_tree_late(struct pci_bus *);
void eeh_add_sysfs_files(struct pci_bus *);
@@ -221,6 +231,11 @@ void eeh_remove_bus_device(struct pci_dev *, int);
#else /* !CONFIG_EEH */
+static inline int eeh_init(void)
+{
+ return 0;
+}
+
static inline void *eeh_dev_init(struct device_node *dn, void *data)
{
return NULL;
@@ -245,9 +260,6 @@ static inline void eeh_add_sysfs_files(struct pci_bus *bus) { }
static inline void eeh_remove_bus_device(struct pci_dev *dev, int purge_pe) { }
-static inline void eeh_lock(void) { }
-static inline void eeh_unlock(void) { }
-
#define EEH_POSSIBLE_ERROR(val, type) (0)
#define EEH_IO_ERROR_VALUE(size) (-1UL)
#endif /* CONFIG_EEH */
diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h
index de67d830151b..89d5670b2eeb 100644
--- a/arch/powerpc/include/asm/eeh_event.h
+++ b/arch/powerpc/include/asm/eeh_event.h
@@ -31,7 +31,9 @@ struct eeh_event {
struct eeh_pe *pe; /* EEH PE */
};
+int eeh_event_init(void);
int eeh_send_failure_event(struct eeh_pe *pe);
+void eeh_remove_event(struct eeh_pe *pe);
void eeh_handle_event(struct eeh_pe *pe);
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 46793b58a761..07ca627e52c0 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -358,12 +358,12 @@ label##_relon_pSeries: \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_STD, KVMTEST_PR, vec)
+ EXC_STD, NOTEST, vec)
#define STD_RELON_EXCEPTION_PSERIES_OOL(vec, label) \
.globl label##_relon_pSeries; \
label##_relon_pSeries: \
- EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST_PR, vec); \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \
EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_STD)
#define STD_RELON_EXCEPTION_HV(loc, vec, label) \
@@ -374,12 +374,12 @@ label##_relon_hv: \
/* No guest interrupts come through here */ \
SET_SCRATCH0(r13); /* save r13 */ \
EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
- EXC_HV, KVMTEST, vec)
+ EXC_HV, NOTEST, vec)
#define STD_RELON_EXCEPTION_HV_OOL(vec, label) \
.globl label##_relon_hv; \
label##_relon_hv: \
- EXCEPTION_PROLOG_1(PACA_EXGEN, KVMTEST, vec); \
+ EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, vec); \
EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, EXC_HV)
/* This associate vector numbers with bits in paca->irq_happened */
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h
index f2498c8e595d..d750336b171d 100644
--- a/arch/powerpc/include/asm/hugetlb.h
+++ b/arch/powerpc/include/asm/hugetlb.h
@@ -191,8 +191,14 @@ static inline void flush_hugetlb_page(struct vm_area_struct *vma,
unsigned long vmaddr)
{
}
-#endif /* CONFIG_HUGETLB_PAGE */
+#define hugepd_shift(x) 0
+static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr,
+ unsigned pdshift)
+{
+ return 0;
+}
+#endif /* CONFIG_HUGETLB_PAGE */
/*
* FSL Book3E platforms require special gpage handling - the gpages
diff --git a/arch/powerpc/include/asm/ibmebus.h b/arch/powerpc/include/asm/ibmebus.h
index 1a9d9aea21fa..088f95b2e14f 100644
--- a/arch/powerpc/include/asm/ibmebus.h
+++ b/arch/powerpc/include/asm/ibmebus.h
@@ -48,8 +48,8 @@
extern struct bus_type ibmebus_bus_type;
-int ibmebus_register_driver(struct of_platform_driver *drv);
-void ibmebus_unregister_driver(struct of_platform_driver *drv);
+int ibmebus_register_driver(struct platform_driver *drv);
+void ibmebus_unregister_driver(struct platform_driver *drv);
int ibmebus_request_irq(u32 ist, irq_handler_t handler,
unsigned long irq_flags, const char *devname,
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index cbfe678e3dbe..c34656a8925e 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -76,6 +76,9 @@ struct iommu_table {
struct iommu_pool large_pool;
struct iommu_pool pools[IOMMU_NR_POOLS];
unsigned long *it_map; /* A simple allocation bitmap for now */
+#ifdef CONFIG_IOMMU_API
+ struct iommu_group *it_group;
+#endif
};
struct scatterlist;
@@ -98,6 +101,8 @@ 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);
+extern void iommu_register_group(struct iommu_table *tbl,
+ int pci_domain_number, unsigned long pe_num);
extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
struct scatterlist *sglist, int nelems,
@@ -125,13 +130,6 @@ extern void iommu_init_early_pSeries(void);
extern void iommu_init_early_dart(void);
extern void iommu_init_early_pasemi(void);
-#ifdef CONFIG_PCI
-extern void pci_iommu_init(void);
-extern void pci_direct_iommu_init(void);
-#else
-static inline void pci_iommu_init(void) { }
-#endif
-
extern void alloc_dart_table(void);
#if defined(CONFIG_PPC64) && defined(CONFIG_PM)
static inline void iommu_save(void)
@@ -147,5 +145,26 @@ static inline void iommu_restore(void)
}
#endif
+/* The API to support IOMMU operations for VFIO */
+extern int iommu_tce_clear_param_check(struct iommu_table *tbl,
+ unsigned long ioba, unsigned long tce_value,
+ 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);
+
#endif /* __KERNEL__ */
#endif /* _ASM_IOMMU_H */
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index 349ed85c7d61..08891d07aeb6 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -107,8 +107,9 @@ struct kvmppc_vcpu_book3s {
#define CONTEXT_GUEST 1
#define CONTEXT_GUEST_END 2
-#define VSID_REAL 0x1fffffffffc00000ULL
-#define VSID_BAT 0x1fffffffffb00000ULL
+#define VSID_REAL 0x0fffffffffc00000ULL
+#define VSID_BAT 0x0fffffffffb00000ULL
+#define VSID_1T 0x1000000000000000ULL
#define VSID_REAL_DR 0x2000000000000000ULL
#define VSID_REAL_IR 0x4000000000000000ULL
#define VSID_PR 0x8000000000000000ULL
@@ -123,6 +124,7 @@ extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu);
extern void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu);
extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte);
extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr);
+extern void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong eaddr, ulong seg_size);
extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu);
extern int kvmppc_book3s_hv_page_fault(struct kvm_run *run,
struct kvm_vcpu *vcpu, unsigned long addr,
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index 9c1ff330c805..a1ecb14e4442 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -159,36 +159,46 @@ static inline int hpte_cache_flags_ok(unsigned long ptel, unsigned long io_type)
}
/*
- * Lock and read a linux PTE. If it's present and writable, atomically
- * set dirty and referenced bits and return the PTE, otherwise return 0.
+ * If it's present and writable, atomically set dirty and referenced bits and
+ * return the PTE, otherwise return 0. If we find a transparent hugepage
+ * and if it is marked splitting we return 0;
*/
-static inline pte_t kvmppc_read_update_linux_pte(pte_t *p, int writing)
+static inline pte_t kvmppc_read_update_linux_pte(pte_t *ptep, int writing,
+ unsigned int hugepage)
{
- pte_t pte, tmp;
-
- /* wait until _PAGE_BUSY is clear then set it atomically */
- __asm__ __volatile__ (
- "1: ldarx %0,0,%3\n"
- " andi. %1,%0,%4\n"
- " bne- 1b\n"
- " ori %1,%0,%4\n"
- " stdcx. %1,0,%3\n"
- " bne- 1b"
- : "=&r" (pte), "=&r" (tmp), "=m" (*p)
- : "r" (p), "i" (_PAGE_BUSY)
- : "cc");
-
- if (pte_present(pte)) {
- pte = pte_mkyoung(pte);
- if (writing && pte_write(pte))
- pte = pte_mkdirty(pte);
- }
+ pte_t old_pte, new_pte = __pte(0);
+
+ while (1) {
+ old_pte = pte_val(*ptep);
+ /*
+ * wait until _PAGE_BUSY is clear then set it atomically
+ */
+ if (unlikely(old_pte & _PAGE_BUSY)) {
+ cpu_relax();
+ continue;
+ }
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ /* If hugepage and is trans splitting return None */
+ if (unlikely(hugepage &&
+ pmd_trans_splitting(pte_pmd(old_pte))))
+ return __pte(0);
+#endif
+ /* If pte is not present return None */
+ if (unlikely(!(old_pte & _PAGE_PRESENT)))
+ return __pte(0);
- *p = pte; /* clears _PAGE_BUSY */
+ new_pte = pte_mkyoung(old_pte);
+ if (writing && pte_write(old_pte))
+ new_pte = pte_mkdirty(new_pte);
- return pte;
+ if (old_pte == __cmpxchg_u64((unsigned long *)ptep, old_pte,
+ new_pte))
+ break;
+ }
+ return new_pte;
}
+
/* Return HPTE cache control bits corresponding to Linux pte bits */
static inline unsigned long hpte_cache_bits(unsigned long pte_val)
{
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index b1e7f2af1016..9b12f88d4adb 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -66,7 +66,8 @@ struct lppaca {
u8 reserved6[48];
u8 cede_latency_hint;
- u8 reserved7[7];
+ u8 ebb_regs_in_use;
+ u8 reserved7[6];
u8 dtl_enable_mask; /* Dispatch Trace Log mask */
u8 donate_dedicated_cpu; /* Donate dedicated CPU cycles */
u8 fpregs_in_use;
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 92386fc4e82a..8b480901165a 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -36,13 +36,13 @@ struct machdep_calls {
#ifdef CONFIG_PPC64
void (*hpte_invalidate)(unsigned long slot,
unsigned long vpn,
- int psize, int ssize,
- int local);
+ int bpsize, int apsize,
+ int ssize, int local);
long (*hpte_updatepp)(unsigned long slot,
unsigned long newpp,
unsigned long vpn,
- int psize, int ssize,
- int local);
+ int bpsize, int apsize,
+ int ssize, int local);
void (*hpte_updateboltedpp)(unsigned long newpp,
unsigned long ea,
int psize, int ssize);
@@ -57,6 +57,9 @@ struct machdep_calls {
void (*hpte_removebolted)(unsigned long ea,
int psize, int ssize);
void (*flush_hash_range)(unsigned long number, int local);
+ void (*hugepage_invalidate)(struct mm_struct *mm,
+ unsigned char *hpte_slot_array,
+ unsigned long addr, int psize);
/* special for kexec, to be called in real mode, linear mapping is
* destroyed as well */
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index 2accc9611248..c4cf01197273 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -340,6 +340,20 @@ extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
pte_t *ptep, unsigned long trap, int local, int ssize,
unsigned int shift, unsigned int mmu_psize);
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern int __hash_page_thp(unsigned long ea, unsigned long access,
+ unsigned long vsid, pmd_t *pmdp, unsigned long trap,
+ int local, int ssize, unsigned int psize);
+#else
+static inline int __hash_page_thp(unsigned long ea, unsigned long access,
+ unsigned long vsid, pmd_t *pmdp,
+ unsigned long trap, int local,
+ int ssize, unsigned int psize)
+{
+ BUG();
+ return -1;
+}
+#endif
extern void hash_failure_debug(unsigned long ea, unsigned long access,
unsigned long vsid, unsigned long trap,
int ssize, int psize, int lpsize,
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index 885c040d6194..8ae133eaf9fa 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -68,6 +68,5 @@ struct mpc512x_lpc {
};
int mpc512x_cs_config(unsigned int cs, u32 val);
-int __init mpc5121_clk_init(void);
#endif /* __ASM_POWERPC_MPC5121_H__ */
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index c0f9ef90f0b8..4a1ac9fbf186 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -339,6 +339,8 @@ struct mpic
#endif
};
+extern struct bus_type mpic_subsys;
+
/*
* MPIC flags (passed to mpic_alloc)
*
@@ -393,6 +395,9 @@ struct mpic
#define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */
#define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */
+/* Get the version of primary MPIC */
+extern u32 fsl_mpic_primary_get_version(void);
+
/* Allocate the controller structure and setup the linux irq descs
* for the range if interrupts passed in. No HW initialization is
* actually performed.
diff --git a/arch/powerpc/include/asm/mpic_timer.h b/arch/powerpc/include/asm/mpic_timer.h
new file mode 100644
index 000000000000..0e23cd4ac8aa
--- /dev/null
+++ b/arch/powerpc/include/asm/mpic_timer.h
@@ -0,0 +1,46 @@
+/*
+ * arch/powerpc/include/asm/mpic_timer.h
+ *
+ * Header file for Mpic Global Timer
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Wang Dongsheng <Dongsheng.Wang@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MPIC_TIMER__
+#define __MPIC_TIMER__
+
+#include <linux/interrupt.h>
+#include <linux/time.h>
+
+struct mpic_timer {
+ void *dev;
+ struct cascade_priv *cascade_handle;
+ unsigned int num;
+ unsigned int irq;
+};
+
+#ifdef CONFIG_MPIC_TIMER
+struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
+ const struct timeval *time);
+void mpic_start_timer(struct mpic_timer *handle);
+void mpic_stop_timer(struct mpic_timer *handle);
+void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time);
+void mpic_free_timer(struct mpic_timer *handle);
+#else
+struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
+ const struct timeval *time) { return NULL; }
+void mpic_start_timer(struct mpic_timer *handle) { }
+void mpic_stop_timer(struct mpic_timer *handle) { }
+void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time) { }
+void mpic_free_timer(struct mpic_timer *handle) { }
+#endif
+
+#endif
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index cbb9305ab15a..029fe85722aa 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -117,7 +117,13 @@ extern int opal_enter_rtas(struct rtas_args *args,
#define OPAL_SET_SLOT_LED_STATUS 55
#define OPAL_GET_EPOW_STATUS 56
#define OPAL_SET_SYSTEM_ATTENTION_LED 57
+#define OPAL_RESERVED1 58
+#define OPAL_RESERVED2 59
+#define OPAL_PCI_NEXT_ERROR 60
+#define OPAL_PCI_EEH_FREEZE_STATUS2 61
+#define OPAL_PCI_POLL 62
#define OPAL_PCI_MSI_EOI 63
+#define OPAL_PCI_GET_PHB_DIAG_DATA2 64
#ifndef __ASSEMBLY__
@@ -125,6 +131,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
enum OpalVendorApiTokens {
OPAL_START_VENDOR_API_RANGE = 1000, OPAL_END_VENDOR_API_RANGE = 1999
};
+
enum OpalFreezeState {
OPAL_EEH_STOPPED_NOT_FROZEN = 0,
OPAL_EEH_STOPPED_MMIO_FREEZE = 1,
@@ -134,55 +141,69 @@ enum OpalFreezeState {
OPAL_EEH_STOPPED_TEMP_UNAVAIL = 5,
OPAL_EEH_STOPPED_PERM_UNAVAIL = 6
};
+
enum OpalEehFreezeActionToken {
OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO = 1,
OPAL_EEH_ACTION_CLEAR_FREEZE_DMA = 2,
OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3
};
+
enum OpalPciStatusToken {
- OPAL_EEH_PHB_NO_ERROR = 0,
- OPAL_EEH_PHB_FATAL = 1,
- OPAL_EEH_PHB_RECOVERABLE = 2,
- OPAL_EEH_PHB_BUS_ERROR = 3,
- OPAL_EEH_PCI_NO_DEVSEL = 4,
- OPAL_EEH_PCI_TA = 5,
- OPAL_EEH_PCIEX_UR = 6,
- OPAL_EEH_PCIEX_CA = 7,
- OPAL_EEH_PCI_MMIO_ERROR = 8,
- OPAL_EEH_PCI_DMA_ERROR = 9
+ OPAL_EEH_NO_ERROR = 0,
+ OPAL_EEH_IOC_ERROR = 1,
+ OPAL_EEH_PHB_ERROR = 2,
+ OPAL_EEH_PE_ERROR = 3,
+ OPAL_EEH_PE_MMIO_ERROR = 4,
+ OPAL_EEH_PE_DMA_ERROR = 5
};
+
+enum OpalPciErrorSeverity {
+ OPAL_EEH_SEV_NO_ERROR = 0,
+ OPAL_EEH_SEV_IOC_DEAD = 1,
+ OPAL_EEH_SEV_PHB_DEAD = 2,
+ OPAL_EEH_SEV_PHB_FENCED = 3,
+ OPAL_EEH_SEV_PE_ER = 4,
+ OPAL_EEH_SEV_INF = 5
+};
+
enum OpalShpcAction {
OPAL_SHPC_GET_LINK_STATE = 0,
OPAL_SHPC_GET_SLOT_STATE = 1
};
+
enum OpalShpcLinkState {
OPAL_SHPC_LINK_DOWN = 0,
OPAL_SHPC_LINK_UP = 1
};
+
enum OpalMmioWindowType {
OPAL_M32_WINDOW_TYPE = 1,
OPAL_M64_WINDOW_TYPE = 2,
OPAL_IO_WINDOW_TYPE = 3
};
+
enum OpalShpcSlotState {
OPAL_SHPC_DEV_NOT_PRESENT = 0,
OPAL_SHPC_DEV_PRESENT = 1
};
+
enum OpalExceptionHandler {
OPAL_MACHINE_CHECK_HANDLER = 1,
OPAL_HYPERVISOR_MAINTENANCE_HANDLER = 2,
OPAL_SOFTPATCH_HANDLER = 3
};
+
enum OpalPendingState {
- OPAL_EVENT_OPAL_INTERNAL = 0x1,
- OPAL_EVENT_NVRAM = 0x2,
- OPAL_EVENT_RTC = 0x4,
- OPAL_EVENT_CONSOLE_OUTPUT = 0x8,
- OPAL_EVENT_CONSOLE_INPUT = 0x10,
- OPAL_EVENT_ERROR_LOG_AVAIL = 0x20,
- OPAL_EVENT_ERROR_LOG = 0x40,
- OPAL_EVENT_EPOW = 0x80,
- OPAL_EVENT_LED_STATUS = 0x100
+ OPAL_EVENT_OPAL_INTERNAL = 0x1,
+ OPAL_EVENT_NVRAM = 0x2,
+ OPAL_EVENT_RTC = 0x4,
+ OPAL_EVENT_CONSOLE_OUTPUT = 0x8,
+ OPAL_EVENT_CONSOLE_INPUT = 0x10,
+ OPAL_EVENT_ERROR_LOG_AVAIL = 0x20,
+ OPAL_EVENT_ERROR_LOG = 0x40,
+ OPAL_EVENT_EPOW = 0x80,
+ OPAL_EVENT_LED_STATUS = 0x100,
+ OPAL_EVENT_PCI_ERROR = 0x200
};
/* Machine check related definitions */
@@ -364,15 +385,80 @@ struct opal_machine_check_event {
} u;
};
+enum {
+ OPAL_P7IOC_DIAG_TYPE_NONE = 0,
+ OPAL_P7IOC_DIAG_TYPE_RGC = 1,
+ OPAL_P7IOC_DIAG_TYPE_BI = 2,
+ OPAL_P7IOC_DIAG_TYPE_CI = 3,
+ OPAL_P7IOC_DIAG_TYPE_MISC = 4,
+ OPAL_P7IOC_DIAG_TYPE_I2C = 5,
+ OPAL_P7IOC_DIAG_TYPE_LAST = 6
+};
+
+struct OpalIoP7IOCErrorData {
+ uint16_t type;
+
+ /* GEM */
+ uint64_t gemXfir;
+ uint64_t gemRfir;
+ uint64_t gemRirqfir;
+ uint64_t gemMask;
+ uint64_t gemRwof;
+
+ /* LEM */
+ uint64_t lemFir;
+ uint64_t lemErrMask;
+ uint64_t lemAction0;
+ uint64_t lemAction1;
+ uint64_t lemWof;
+
+ union {
+ struct OpalIoP7IOCRgcErrorData {
+ uint64_t rgcStatus; /* 3E1C10 */
+ uint64_t rgcLdcp; /* 3E1C18 */
+ }rgc;
+ struct OpalIoP7IOCBiErrorData {
+ uint64_t biLdcp0; /* 3C0100, 3C0118 */
+ uint64_t biLdcp1; /* 3C0108, 3C0120 */
+ uint64_t biLdcp2; /* 3C0110, 3C0128 */
+ uint64_t biFenceStatus; /* 3C0130, 3C0130 */
+
+ uint8_t biDownbound; /* BI Downbound or Upbound */
+ }bi;
+ struct OpalIoP7IOCCiErrorData {
+ uint64_t ciPortStatus; /* 3Dn008 */
+ uint64_t ciPortLdcp; /* 3Dn010 */
+
+ uint8_t ciPort; /* Index of CI port: 0/1 */
+ }ci;
+ };
+};
+
/**
* This structure defines the overlay which will be used to store PHB error
* data upon request.
*/
enum {
+ OPAL_PHB_ERROR_DATA_VERSION_1 = 1,
+};
+
+enum {
+ OPAL_PHB_ERROR_DATA_TYPE_P7IOC = 1,
+};
+
+enum {
OPAL_P7IOC_NUM_PEST_REGS = 128,
};
+struct OpalIoPhbErrorCommon {
+ uint32_t version;
+ uint32_t ioType;
+ uint32_t len;
+};
+
struct OpalIoP7IOCPhbErrorData {
+ struct OpalIoPhbErrorCommon common;
+
uint32_t brdgCtl;
// P7IOC utl regs
@@ -530,14 +616,21 @@ int64_t opal_pci_map_pe_dma_window_real(uint64_t phb_id, uint16_t pe_number,
uint64_t pci_mem_size);
int64_t opal_pci_reset(uint64_t phb_id, uint8_t reset_scope, uint8_t assert_state);
-int64_t opal_pci_get_hub_diag_data(uint64_t hub_id, void *diag_buffer, uint64_t diag_buffer_len);
-int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer, uint64_t diag_buffer_len);
+int64_t opal_pci_get_hub_diag_data(uint64_t hub_id, void *diag_buffer,
+ uint64_t diag_buffer_len);
+int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer,
+ uint64_t diag_buffer_len);
+int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id, void *diag_buffer,
+ uint64_t diag_buffer_len);
int64_t opal_pci_fence_phb(uint64_t phb_id);
int64_t opal_pci_reinit(uint64_t phb_id, uint8_t reinit_scope);
int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action);
int64_t opal_set_slot_led_status(uint64_t phb_id, uint64_t slot_id, uint8_t led_type, uint8_t led_action);
int64_t opal_get_epow_status(uint64_t *status);
int64_t opal_set_system_attention_led(uint8_t led_action);
+int64_t opal_pci_next_error(uint64_t phb_id, uint64_t *first_frozen_pe,
+ uint16_t *pci_error_type, uint16_t *severity);
+int64_t opal_pci_poll(uint64_t phb_id);
/* Internal functions */
extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
@@ -551,6 +644,11 @@ extern void hvc_opal_init_early(void);
extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
int depth, void *data);
+extern int opal_notifier_register(struct notifier_block *nb);
+extern void opal_notifier_enable(void);
+extern void opal_notifier_disable(void);
+extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
+
extern int opal_get_chars(uint32_t vtermno, char *buf, int count);
extern int opal_put_chars(uint32_t vtermno, const char *buf, int total_len);
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index f265049dd7d6..2dd7bfc459be 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -60,6 +60,7 @@ struct power_pmu {
#define PPMU_HAS_SSLOT 0x00000020 /* Has sampled slot in MMCRA */
#define PPMU_HAS_SIER 0x00000040 /* Has SIER */
#define PPMU_BHRB 0x00000080 /* has BHRB feature enabled */
+#define PPMU_EBB 0x00000100 /* supports event based branch */
/*
* Values for flags to get_alternatives()
@@ -68,6 +69,11 @@ struct power_pmu {
#define PPMU_LIMITED_PMC_REQD 2 /* have to put this on a limited PMC */
#define PPMU_ONLY_COUNT_RUN 4 /* only counting in run state */
+/*
+ * We use the event config bit 63 as a flag to request EBB.
+ */
+#define EVENT_CONFIG_EBB_SHIFT 63
+
extern int register_power_pmu(struct power_pmu *);
struct pt_regs;
diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h
index b66ae722a8e9..f65e27b09bd3 100644
--- a/arch/powerpc/include/asm/pgalloc-64.h
+++ b/arch/powerpc/include/asm/pgalloc-64.h
@@ -221,17 +221,17 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t table,
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- return kmem_cache_alloc(PGT_CACHE(PMD_INDEX_SIZE),
+ return kmem_cache_alloc(PGT_CACHE(PMD_CACHE_INDEX),
GFP_KERNEL|__GFP_REPEAT);
}
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
{
- kmem_cache_free(PGT_CACHE(PMD_INDEX_SIZE), pmd);
+ kmem_cache_free(PGT_CACHE(PMD_CACHE_INDEX), pmd);
}
#define __pmd_free_tlb(tlb, pmd, addr) \
- pgtable_free_tlb(tlb, pmd, PMD_INDEX_SIZE)
+ pgtable_free_tlb(tlb, pmd, PMD_CACHE_INDEX)
#ifndef CONFIG_PPC_64K_PAGES
#define __pud_free_tlb(tlb, pud, addr) \
pgtable_free_tlb(tlb, pud, PUD_INDEX_SIZE)
diff --git a/arch/powerpc/include/asm/pgtable-ppc64-64k.h b/arch/powerpc/include/asm/pgtable-ppc64-64k.h
index 45142d640720..a56b82fb0609 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64-64k.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64-64k.h
@@ -33,7 +33,8 @@
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/* Bits to mask out from a PMD to get to the PTE page */
-#define PMD_MASKED_BITS 0x1ff
+/* PMDs point to PTE table fragments which are 4K aligned. */
+#define PMD_MASKED_BITS 0xfff
/* Bits to mask out from a PGD/PUD to get to the PMD page */
#define PUD_MASKED_BITS 0x1ff
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index e3d55f6f24fe..46db09414a10 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -10,6 +10,7 @@
#else
#include <asm/pgtable-ppc64-4k.h>
#endif
+#include <asm/barrier.h>
#define FIRST_USER_ADDRESS 0
@@ -20,7 +21,11 @@
PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
-
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+#define PMD_CACHE_INDEX (PMD_INDEX_SIZE + 1)
+#else
+#define PMD_CACHE_INDEX PMD_INDEX_SIZE
+#endif
/*
* Define the address range of the kernel non-linear virtual area
*/
@@ -150,7 +155,7 @@
#define pmd_present(pmd) (pmd_val(pmd) != 0)
#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
-#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd))
+extern struct page *pmd_page(pmd_t pmd);
#define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
#define pud_none(pud) (!pud_val(pud))
@@ -339,43 +344,217 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
void pgtable_cache_init(void);
+#endif /* __ASSEMBLY__ */
+
+/*
+ * THP pages can't be special. So use the _PAGE_SPECIAL
+ */
+#define _PAGE_SPLITTING _PAGE_SPECIAL
+
+/*
+ * We need to differentiate between explicit huge page and THP huge
+ * page, since THP huge page also need to track real subpage details
+ */
+#define _PAGE_THP_HUGE _PAGE_4K_PFN
/*
- * find_linux_pte returns the address of a linux pte for a given
- * effective address and directory. If not found, it returns zero.
+ * set of bits not changed in pmd_modify.
*/
-static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
+#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | \
+ _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPLITTING | \
+ _PAGE_THP_HUGE)
+
+#ifndef __ASSEMBLY__
+/*
+ * The linux hugepage PMD now include the pmd entries followed by the address
+ * to the stashed pgtable_t. The stashed pgtable_t contains the hpte bits.
+ * [ 1 bit secondary | 3 bit hidx | 1 bit valid | 000]. We use one byte per
+ * each HPTE entry. With 16MB hugepage and 64K HPTE we need 256 entries and
+ * with 4K HPTE we need 4096 entries. Both will fit in a 4K pgtable_t.
+ *
+ * The last three bits are intentionally left to zero. This memory location
+ * are also used as normal page PTE pointers. So if we have any pointers
+ * left around while we collapse a hugepage, we need to make sure
+ * _PAGE_PRESENT and _PAGE_FILE bits of that are zero when we look at them
+ */
+static inline unsigned int hpte_valid(unsigned char *hpte_slot_array, int index)
{
- pgd_t *pg;
- pud_t *pu;
- pmd_t *pm;
- pte_t *pt = NULL;
-
- pg = pgdir + pgd_index(ea);
- if (!pgd_none(*pg)) {
- pu = pud_offset(pg, ea);
- if (!pud_none(*pu)) {
- pm = pmd_offset(pu, ea);
- if (pmd_present(*pm))
- pt = pte_offset_kernel(pm, ea);
- }
- }
- return pt;
+ return (hpte_slot_array[index] >> 3) & 0x1;
}
-#ifdef CONFIG_HUGETLB_PAGE
-pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
- unsigned *shift);
-#else
-static inline pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
- unsigned *shift)
+static inline unsigned int hpte_hash_index(unsigned char *hpte_slot_array,
+ int index)
{
- if (shift)
- *shift = 0;
- return find_linux_pte(pgdir, ea);
+ return hpte_slot_array[index] >> 4;
}
-#endif /* !CONFIG_HUGETLB_PAGE */
-#endif /* __ASSEMBLY__ */
+static inline void mark_hpte_slot_valid(unsigned char *hpte_slot_array,
+ unsigned int index, unsigned int hidx)
+{
+ hpte_slot_array[index] = hidx << 4 | 0x1 << 3;
+}
+static inline char *get_hpte_slot_array(pmd_t *pmdp)
+{
+ /*
+ * The hpte hindex is stored in the pgtable whose address is in the
+ * second half of the PMD
+ *
+ * Order this load with the test for pmd_trans_huge in the caller
+ */
+ smp_rmb();
+ return *(char **)(pmdp + PTRS_PER_PMD);
+
+
+}
+
+extern void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp);
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+extern pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot);
+extern pmd_t mk_pmd(struct page *page, pgprot_t pgprot);
+extern pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot);
+extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, pmd_t pmd);
+extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd);
+
+static inline int pmd_trans_huge(pmd_t pmd)
+{
+ /*
+ * leaf pte for huge page, bottom two bits != 00
+ */
+ return (pmd_val(pmd) & 0x3) && (pmd_val(pmd) & _PAGE_THP_HUGE);
+}
+
+static inline int pmd_large(pmd_t pmd)
+{
+ /*
+ * leaf pte for huge page, bottom two bits != 00
+ */
+ if (pmd_trans_huge(pmd))
+ return pmd_val(pmd) & _PAGE_PRESENT;
+ return 0;
+}
+
+static inline int pmd_trans_splitting(pmd_t pmd)
+{
+ if (pmd_trans_huge(pmd))
+ return pmd_val(pmd) & _PAGE_SPLITTING;
+ return 0;
+}
+
+extern int has_transparent_hugepage(void);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+static inline pte_t pmd_pte(pmd_t pmd)
+{
+ return __pte(pmd_val(pmd));
+}
+
+static inline pmd_t pte_pmd(pte_t pte)
+{
+ return __pmd(pte_val(pte));
+}
+
+static inline pte_t *pmdp_ptep(pmd_t *pmd)
+{
+ return (pte_t *)pmd;
+}
+
+#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
+#define pmd_young(pmd) pte_young(pmd_pte(pmd))
+#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
+#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
+#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
+#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
+#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
+
+#define __HAVE_ARCH_PMD_WRITE
+#define pmd_write(pmd) pte_write(pmd_pte(pmd))
+
+static inline pmd_t pmd_mkhuge(pmd_t pmd)
+{
+ /* Do nothing, mk_pmd() does this part. */
+ return pmd;
+}
+
+static inline pmd_t pmd_mknotpresent(pmd_t pmd)
+{
+ pmd_val(pmd) &= ~_PAGE_PRESENT;
+ return pmd;
+}
+
+static inline pmd_t pmd_mksplitting(pmd_t pmd)
+{
+ pmd_val(pmd) |= _PAGE_SPLITTING;
+ return pmd;
+}
+
+#define __HAVE_ARCH_PMD_SAME
+static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
+{
+ return (((pmd_val(pmd_a) ^ pmd_val(pmd_b)) & ~_PAGE_HPTEFLAGS) == 0);
+}
+
+#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
+extern int pmdp_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp,
+ pmd_t entry, int dirty);
+
+extern unsigned long pmd_hugepage_update(struct mm_struct *mm,
+ unsigned long addr,
+ pmd_t *pmdp, unsigned long clr);
+
+static inline int __pmdp_test_and_clear_young(struct mm_struct *mm,
+ unsigned long addr, pmd_t *pmdp)
+{
+ unsigned long old;
+
+ if ((pmd_val(*pmdp) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+ return 0;
+ old = pmd_hugepage_update(mm, addr, pmdp, _PAGE_ACCESSED);
+ return ((old & _PAGE_ACCESSED) != 0);
+}
+
+#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG
+extern int pmdp_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp);
+#define __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH
+extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp);
+
+#define __HAVE_ARCH_PMDP_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_SET_WRPROTECT
+static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+
+ if ((pmd_val(*pmdp) & _PAGE_RW) == 0)
+ return;
+
+ pmd_hugepage_update(mm, addr, pmdp, _PAGE_RW);
+}
+
+#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
+extern void pmdp_splitting_flush(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp);
+
+#define __HAVE_ARCH_PGTABLE_DEPOSIT
+extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable);
+#define __HAVE_ARCH_PGTABLE_WITHDRAW
+extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
+
+#define __HAVE_ARCH_PMDP_INVALIDATE
+extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
+ pmd_t *pmdp);
+#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h
index b6293d26bd39..7d6eacf249cf 100644
--- a/arch/powerpc/include/asm/pgtable.h
+++ b/arch/powerpc/include/asm/pgtable.h
@@ -217,6 +217,12 @@ extern int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, unsigned long addr,
extern int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr);
+#ifndef CONFIG_TRANSPARENT_HUGEPAGE
+#define pmd_large(pmd) 0
+#define has_transparent_hugepage() 0
+#endif
+pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
+ unsigned *shift);
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/probes.h b/arch/powerpc/include/asm/probes.h
index 5f1e15b68704..3421637cfd7b 100644
--- a/arch/powerpc/include/asm/probes.h
+++ b/arch/powerpc/include/asm/probes.h
@@ -38,5 +38,30 @@ typedef u32 ppc_opcode_t;
#define is_trap(instr) (IS_TW(instr) || IS_TWI(instr))
#endif /* CONFIG_PPC64 */
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+#define MSR_SINGLESTEP (MSR_DE)
+#else
+#define MSR_SINGLESTEP (MSR_SE)
+#endif
+
+/* Enable single stepping for the current task */
+static inline void enable_single_step(struct pt_regs *regs)
+{
+ regs->msr |= MSR_SINGLESTEP;
+#ifdef CONFIG_PPC_ADV_DEBUG_REGS
+ /*
+ * We turn off Critical Input Exception(CE) to ensure that the single
+ * step will be for the instruction we have the probe on; if we don't,
+ * it is possible we'd get the single step reported for CE.
+ */
+ regs->msr &= ~MSR_CE;
+ mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
+#ifdef CONFIG_PPC_47x
+ isync();
+#endif
+#endif
+}
+
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PROBES_H */
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 14a658363698..47a35b08b963 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -168,10 +168,10 @@ struct thread_struct {
* The following help to manage the use of Debug Control Registers
* om the BookE platforms.
*/
- unsigned long dbcr0;
- unsigned long dbcr1;
+ uint32_t dbcr0;
+ uint32_t dbcr1;
#ifdef CONFIG_BOOKE
- unsigned long dbcr2;
+ uint32_t dbcr2;
#endif
/*
* The stored value of the DBSR register will be the value at the
@@ -179,7 +179,7 @@ struct thread_struct {
* user (will never be written to) and has value while helping to
* describe the reason for the last debug trap. Torez
*/
- unsigned long dbsr;
+ uint32_t dbsr;
/*
* The following will contain addresses used by debug applications
* to help trace and trap on particular address locations.
@@ -200,7 +200,7 @@ struct thread_struct {
#endif
#endif
/* FP and VSX 0-31 register set */
- double fpr[32][TS_FPRWIDTH];
+ double fpr[32][TS_FPRWIDTH] __attribute__((aligned(16)));
struct {
unsigned int pad;
@@ -287,9 +287,9 @@ struct thread_struct {
unsigned long siar;
unsigned long sdar;
unsigned long sier;
- unsigned long mmcr0;
unsigned long mmcr2;
- unsigned long mmcra;
+ unsigned mmcr0;
+ unsigned used_ebb;
#endif
};
@@ -404,9 +404,7 @@ static inline void prefetchw(const void *x)
#define spin_lock_prefetch(x) prefetchw(x)
-#ifdef CONFIG_PPC64
#define HAVE_ARCH_PICK_MMAP_LAYOUT
-#endif
#ifdef CONFIG_PPC64
static inline unsigned long get_clean_sp(unsigned long sp, int is_32)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 4a9e408644fe..5d7d9c2a5473 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -621,11 +621,15 @@
#define MMCR0_PMXE 0x04000000UL /* performance monitor exception enable */
#define MMCR0_FCECE 0x02000000UL /* freeze ctrs on enabled cond or event */
#define MMCR0_TBEE 0x00400000UL /* time base exception enable */
+#define MMCR0_EBE 0x00100000UL /* Event based branch enable */
+#define MMCR0_PMCC 0x000c0000UL /* PMC control */
+#define MMCR0_PMCC_U6 0x00080000UL /* PMC1-6 are R/W by user (PR) */
#define MMCR0_PMC1CE 0x00008000UL /* PMC1 count enable*/
#define MMCR0_PMCjCE 0x00004000UL /* PMCj count enable*/
#define MMCR0_TRIGGER 0x00002000UL /* TRIGGER enable */
#define MMCR0_PMAO 0x00000080UL /* performance monitor alert has occurred, set to 0 after handling exception */
#define MMCR0_SHRFC 0x00000040UL /* SHRre freeze conditions between threads */
+#define MMCR0_FC56 0x00000010UL /* freeze counters 5 and 6 */
#define MMCR0_FCTI 0x00000008UL /* freeze counters in tags inactive mode */
#define MMCR0_FCTA 0x00000004UL /* freeze counters in tags active mode */
#define MMCR0_FCWAIT 0x00000002UL /* freeze counter in WAIT state */
@@ -673,6 +677,11 @@
#define SIER_SIAR_VALID 0x0400000 /* SIAR contents valid */
#define SIER_SDAR_VALID 0x0200000 /* SDAR contents valid */
+/* When EBB is enabled, some of MMCR0/MMCR2/SIER are user accessible */
+#define MMCR0_USER_MASK (MMCR0_FC | MMCR0_PMXE | MMCR0_PMAO)
+#define MMCR2_USER_MASK 0x4020100804020000UL /* (FC1P|FC2P|FC3P|FC4P|FC5P|FC6P) */
+#define SIER_USER_MASK 0x7fffffUL
+
#define SPRN_PA6T_MMCR0 795
#define PA6T_MMCR0_EN0 0x0000000000000001UL
#define PA6T_MMCR0_EN1 0x0000000000000002UL
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 34fd70488d83..c7a8bfc9f6f5 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -350,8 +350,8 @@ static inline u32 rtas_config_addr(int busno, int devfn, int reg)
(devfn << 8) | (reg & 0xff);
}
-extern void __cpuinit rtas_give_timebase(void);
-extern void __cpuinit rtas_take_timebase(void);
+extern void rtas_give_timebase(void);
+extern void rtas_take_timebase(void);
#ifdef CONFIG_PPC_RTAS
static inline int page_is_rtas_user_buf(unsigned long pfn)
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index 200d763a0a67..49a13e0ef234 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -67,4 +67,18 @@ static inline void flush_spe_to_thread(struct task_struct *t)
}
#endif
+static inline void clear_task_ebb(struct task_struct *t)
+{
+#ifdef CONFIG_PPC_BOOK3S_64
+ /* EBB perf events are not inherited, so clear all EBB state. */
+ t->thread.bescr = 0;
+ t->thread.mmcr2 = 0;
+ t->thread.mmcr0 = 0;
+ t->thread.siar = 0;
+ t->thread.sdar = 0;
+ t->thread.sier = 0;
+ t->thread.used_ebb = 0;
+#endif
+}
+
#endif /* _ASM_POWERPC_SWITCH_TO_H */
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h
index 61a59271665b..2def01ed0cb2 100644
--- a/arch/powerpc/include/asm/tlbflush.h
+++ b/arch/powerpc/include/asm/tlbflush.h
@@ -165,7 +165,8 @@ static inline void flush_tlb_kernel_range(unsigned long start,
/* Private function for use by PCI IO mapping code */
extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
unsigned long end);
-
+extern void flush_tlb_pmd_range(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr);
#else
#error Unsupported MMU type
#endif
diff --git a/arch/powerpc/include/asm/vdso.h b/arch/powerpc/include/asm/vdso.h
index 50f261bc3e95..0d9cecddf8a4 100644
--- a/arch/powerpc/include/asm/vdso.h
+++ b/arch/powerpc/include/asm/vdso.h
@@ -22,7 +22,7 @@ extern unsigned long vdso64_rt_sigtramp;
extern unsigned long vdso32_sigtramp;
extern unsigned long vdso32_rt_sigtramp;
-int __cpuinit vdso_getcpu_init(void);
+int vdso_getcpu_init(void);
#else /* __ASSEMBLY__ */
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index a36daf3c6f9a..405fb09bda94 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -81,4 +81,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index f960a7944553..a8619bfe879e 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -58,6 +58,8 @@ obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
obj-$(CONFIG_IBMVIO) += vio.o
obj-$(CONFIG_IBMEBUS) += ibmebus.o
+obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \
+ eeh_driver.o eeh_event.o eeh_sysfs.o
obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_FA_DUMP) += fadump.o
@@ -100,7 +102,7 @@ obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_SWIOTLB) += dma-swiotlb.o
-pci64-$(CONFIG_PPC64) += pci_dn.o isa-bridge.o
+pci64-$(CONFIG_PPC64) += pci_dn.o pci-hotplug.o isa-bridge.o
obj-$(CONFIG_PCI) += pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
pci-common.o pci_of_scan.o
obj-$(CONFIG_PCI_MSI) += msi.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 6f16ffafa6f0..c7e8afc2ead0 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -105,9 +105,6 @@ int main(void)
DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
#else /* CONFIG_PPC64 */
DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
-#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
- DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
-#endif
#ifdef CONFIG_SPE
DEFINE(THREAD_EVR0, offsetof(struct thread_struct, evr[0]));
DEFINE(THREAD_ACC, offsetof(struct thread_struct, acc));
@@ -115,6 +112,9 @@ int main(void)
DEFINE(THREAD_USED_SPE, offsetof(struct thread_struct, used_spe));
#endif /* CONFIG_SPE */
#endif /* CONFIG_PPC64 */
+#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
+ DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
+#endif
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
DEFINE(THREAD_KVM_SVCPU, offsetof(struct thread_struct, kvm_shadow_vcpu));
#endif
@@ -132,7 +132,6 @@ int main(void)
DEFINE(THREAD_SIER, offsetof(struct thread_struct, sier));
DEFINE(THREAD_MMCR0, offsetof(struct thread_struct, mmcr0));
DEFINE(THREAD_MMCR2, offsetof(struct thread_struct, mmcr2));
- DEFINE(THREAD_MMCRA, offsetof(struct thread_struct, mmcra));
#endif
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
DEFINE(PACATMSCRATCH, offsetof(struct paca_struct, tm_scratch));
diff --git a/arch/powerpc/kernel/cacheinfo.c b/arch/powerpc/kernel/cacheinfo.c
index 92c6b008dd2b..9262cf2bec4b 100644
--- a/arch/powerpc/kernel/cacheinfo.c
+++ b/arch/powerpc/kernel/cacheinfo.c
@@ -131,7 +131,8 @@ static const char *cache_type_string(const struct cache *cache)
return cache_type_info[cache->type].name;
}
-static void __cpuinit cache_init(struct cache *cache, int type, int level, struct device_node *ofnode)
+static void cache_init(struct cache *cache, int type, int level,
+ struct device_node *ofnode)
{
cache->type = type;
cache->level = level;
@@ -140,7 +141,7 @@ static void __cpuinit cache_init(struct cache *cache, int type, int level, struc
list_add(&cache->list, &cache_list);
}
-static struct cache *__cpuinit new_cache(int type, int level, struct device_node *ofnode)
+static struct cache *new_cache(int type, int level, struct device_node *ofnode)
{
struct cache *cache;
@@ -324,7 +325,8 @@ static bool cache_node_is_unified(const struct device_node *np)
return of_get_property(np, "cache-unified", NULL);
}
-static struct cache *__cpuinit cache_do_one_devnode_unified(struct device_node *node, int level)
+static struct cache *cache_do_one_devnode_unified(struct device_node *node,
+ int level)
{
struct cache *cache;
@@ -335,7 +337,8 @@ static struct cache *__cpuinit cache_do_one_devnode_unified(struct device_node *
return cache;
}
-static struct cache *__cpuinit cache_do_one_devnode_split(struct device_node *node, int level)
+static struct cache *cache_do_one_devnode_split(struct device_node *node,
+ int level)
{
struct cache *dcache, *icache;
@@ -357,7 +360,7 @@ err:
return NULL;
}
-static struct cache *__cpuinit cache_do_one_devnode(struct device_node *node, int level)
+static struct cache *cache_do_one_devnode(struct device_node *node, int level)
{
struct cache *cache;
@@ -369,7 +372,8 @@ static struct cache *__cpuinit cache_do_one_devnode(struct device_node *node, in
return cache;
}
-static struct cache *__cpuinit cache_lookup_or_instantiate(struct device_node *node, int level)
+static struct cache *cache_lookup_or_instantiate(struct device_node *node,
+ int level)
{
struct cache *cache;
@@ -385,7 +389,7 @@ static struct cache *__cpuinit cache_lookup_or_instantiate(struct device_node *n
return cache;
}
-static void __cpuinit link_cache_lists(struct cache *smaller, struct cache *bigger)
+static void link_cache_lists(struct cache *smaller, struct cache *bigger)
{
while (smaller->next_local) {
if (smaller->next_local == bigger)
@@ -396,13 +400,13 @@ static void __cpuinit link_cache_lists(struct cache *smaller, struct cache *bigg
smaller->next_local = bigger;
}
-static void __cpuinit do_subsidiary_caches_debugcheck(struct cache *cache)
+static void do_subsidiary_caches_debugcheck(struct cache *cache)
{
WARN_ON_ONCE(cache->level != 1);
WARN_ON_ONCE(strcmp(cache->ofnode->type, "cpu"));
}
-static void __cpuinit do_subsidiary_caches(struct cache *cache)
+static void do_subsidiary_caches(struct cache *cache)
{
struct device_node *subcache_node;
int level = cache->level;
@@ -423,7 +427,7 @@ static void __cpuinit do_subsidiary_caches(struct cache *cache)
}
}
-static struct cache *__cpuinit cache_chain_instantiate(unsigned int cpu_id)
+static struct cache *cache_chain_instantiate(unsigned int cpu_id)
{
struct device_node *cpu_node;
struct cache *cpu_cache = NULL;
@@ -448,7 +452,7 @@ out:
return cpu_cache;
}
-static struct cache_dir *__cpuinit cacheinfo_create_cache_dir(unsigned int cpu_id)
+static struct cache_dir *cacheinfo_create_cache_dir(unsigned int cpu_id)
{
struct cache_dir *cache_dir;
struct device *dev;
@@ -653,7 +657,7 @@ static struct kobj_type cache_index_type = {
.default_attrs = cache_index_default_attrs,
};
-static void __cpuinit cacheinfo_create_index_opt_attrs(struct cache_index_dir *dir)
+static void cacheinfo_create_index_opt_attrs(struct cache_index_dir *dir)
{
const char *cache_name;
const char *cache_type;
@@ -696,7 +700,8 @@ static void __cpuinit cacheinfo_create_index_opt_attrs(struct cache_index_dir *d
kfree(buf);
}
-static void __cpuinit cacheinfo_create_index_dir(struct cache *cache, int index, struct cache_dir *cache_dir)
+static void cacheinfo_create_index_dir(struct cache *cache, int index,
+ struct cache_dir *cache_dir)
{
struct cache_index_dir *index_dir;
int rc;
@@ -722,7 +727,8 @@ err:
kfree(index_dir);
}
-static void __cpuinit cacheinfo_sysfs_populate(unsigned int cpu_id, struct cache *cache_list)
+static void cacheinfo_sysfs_populate(unsigned int cpu_id,
+ struct cache *cache_list)
{
struct cache_dir *cache_dir;
struct cache *cache;
@@ -740,7 +746,7 @@ static void __cpuinit cacheinfo_sysfs_populate(unsigned int cpu_id, struct cache
}
}
-void __cpuinit cacheinfo_cpu_online(unsigned int cpu_id)
+void cacheinfo_cpu_online(unsigned int cpu_id)
{
struct cache *cache;
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c
index 9ec3fe174cba..779a78c26435 100644
--- a/arch/powerpc/kernel/crash_dump.c
+++ b/arch/powerpc/kernel/crash_dump.c
@@ -69,16 +69,6 @@ void __init setup_kdump_trampoline(void)
}
#endif /* CONFIG_NONSTATIC_KERNEL */
-static int __init parse_savemaxmem(char *p)
-{
- if (p)
- saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1;
-
- return 1;
-}
-__setup("savemaxmem=", parse_savemaxmem);
-
-
static size_t copy_oldmem_vaddr(void *vaddr, char *buf, size_t csize,
unsigned long offset, int userbuf)
{
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/kernel/eeh.c
index 6b73d6c44f51..39954fe941b8 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -103,11 +103,8 @@ EXPORT_SYMBOL(eeh_subsystem_enabled);
*/
int eeh_probe_mode;
-/* Global EEH mutex */
-DEFINE_MUTEX(eeh_mutex);
-
/* Lock to avoid races due to multiple reports of an error */
-static DEFINE_RAW_SPINLOCK(confirm_error_lock);
+DEFINE_RAW_SPINLOCK(confirm_error_lock);
/* Buffer for reporting pci register dumps. Its here in BSS, and
* not dynamically alloced, so that it ends up in RMO where RTAS
@@ -235,16 +232,30 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
{
size_t loglen = 0;
struct eeh_dev *edev;
+ bool valid_cfg_log = true;
- eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
- eeh_ops->configure_bridge(pe);
- eeh_pe_restore_bars(pe);
-
- pci_regs_buf[0] = 0;
- eeh_pe_for_each_dev(pe, edev) {
- loglen += eeh_gather_pci_data(edev, pci_regs_buf,
- EEH_PCI_REGS_LOG_LEN);
- }
+ /*
+ * When the PHB is fenced or dead, it's pointless to collect
+ * the data from PCI config space because it should return
+ * 0xFF's. For ER, we still retrieve the data from the PCI
+ * config space.
+ */
+ if (eeh_probe_mode_dev() &&
+ (pe->type & EEH_PE_PHB) &&
+ (pe->state & (EEH_PE_ISOLATED | EEH_PE_PHB_DEAD)))
+ valid_cfg_log = false;
+
+ if (valid_cfg_log) {
+ eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
+ eeh_ops->configure_bridge(pe);
+ eeh_pe_restore_bars(pe);
+
+ pci_regs_buf[0] = 0;
+ eeh_pe_for_each_dev(pe, edev) {
+ loglen += eeh_gather_pci_data(edev, pci_regs_buf + loglen,
+ EEH_PCI_REGS_LOG_LEN - loglen);
+ }
+ }
eeh_ops->get_log(pe, severity, pci_regs_buf, loglen);
}
@@ -260,15 +271,74 @@ static inline unsigned long eeh_token_to_phys(unsigned long token)
{
pte_t *ptep;
unsigned long pa;
+ int hugepage_shift;
- ptep = find_linux_pte(init_mm.pgd, token);
+ /*
+ * We won't find hugepages here, iomem
+ */
+ ptep = find_linux_pte_or_hugepte(init_mm.pgd, token, &hugepage_shift);
if (!ptep)
return token;
+ WARN_ON(hugepage_shift);
pa = pte_pfn(*ptep) << PAGE_SHIFT;
return pa | (token & (PAGE_SIZE-1));
}
+/*
+ * On PowerNV platform, we might already have fenced PHB there.
+ * For that case, it's meaningless to recover frozen PE. Intead,
+ * We have to handle fenced PHB firstly.
+ */
+static int eeh_phb_check_failure(struct eeh_pe *pe)
+{
+ struct eeh_pe *phb_pe;
+ unsigned long flags;
+ int ret;
+
+ if (!eeh_probe_mode_dev())
+ return -EPERM;
+
+ /* Find the PHB PE */
+ phb_pe = eeh_phb_pe_get(pe->phb);
+ if (!phb_pe) {
+ pr_warning("%s Can't find PE for PHB#%d\n",
+ __func__, pe->phb->global_number);
+ return -EEXIST;
+ }
+
+ /* If the PHB has been in problematic state */
+ eeh_serialize_lock(&flags);
+ if (phb_pe->state & (EEH_PE_ISOLATED | EEH_PE_PHB_DEAD)) {
+ ret = 0;
+ goto out;
+ }
+
+ /* Check PHB state */
+ ret = eeh_ops->get_state(phb_pe, NULL);
+ if ((ret < 0) ||
+ (ret == EEH_STATE_NOT_SUPPORT) ||
+ (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) ==
+ (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) {
+ ret = 0;
+ goto out;
+ }
+
+ /* Isolate the PHB and send event */
+ eeh_pe_state_mark(phb_pe, EEH_PE_ISOLATED);
+ eeh_serialize_unlock(flags);
+ eeh_send_failure_event(phb_pe);
+
+ pr_err("EEH: PHB#%x failure detected\n",
+ phb_pe->phb->global_number);
+ dump_stack();
+
+ return 1;
+out:
+ eeh_serialize_unlock(flags);
+ return ret;
+}
+
/**
* eeh_dev_check_failure - Check if all 1's data is due to EEH slot freeze
* @edev: eeh device
@@ -319,13 +389,21 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
return 0;
}
+ /*
+ * On PowerNV platform, we might already have fenced PHB
+ * there and we need take care of that firstly.
+ */
+ ret = eeh_phb_check_failure(pe);
+ if (ret > 0)
+ return ret;
+
/* If we already have a pending isolation event for this
* slot, we know it's bad already, we don't need to check.
* Do this checking under a lock; as multiple PCI devices
* in one slot might report errors simultaneously, and we
* only want one error recovery routine running.
*/
- raw_spin_lock_irqsave(&confirm_error_lock, flags);
+ eeh_serialize_lock(&flags);
rc = 1;
if (pe->state & EEH_PE_ISOLATED) {
pe->check_count++;
@@ -368,13 +446,13 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
}
eeh_stats.slot_resets++;
-
+
/* Avoid repeated reports of this failure, including problems
* with other functions on this device, and functions under
* bridges.
*/
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
- raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
+ eeh_serialize_unlock(flags);
eeh_send_failure_event(pe);
@@ -382,11 +460,14 @@ int eeh_dev_check_failure(struct eeh_dev *edev)
* a stack trace will help the device-driver authors figure
* out what happened. So print that out.
*/
- WARN(1, "EEH: failure detected\n");
+ pr_err("EEH: Frozen PE#%x detected on PHB#%x\n",
+ pe->addr, pe->phb->global_number);
+ dump_stack();
+
return 1;
dn_unlock:
- raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
+ eeh_serialize_unlock(flags);
return rc;
}
@@ -525,7 +606,7 @@ static void eeh_reset_pe_once(struct eeh_pe *pe)
* or a fundamental reset (3).
* A fundamental reset required by any device under
* Partitionable Endpoint trumps hot-reset.
- */
+ */
eeh_pe_dev_traverse(pe, eeh_set_dev_freset, &freset);
if (freset)
@@ -538,8 +619,8 @@ static void eeh_reset_pe_once(struct eeh_pe *pe)
*/
#define PCI_BUS_RST_HOLD_TIME_MSEC 250
msleep(PCI_BUS_RST_HOLD_TIME_MSEC);
-
- /* We might get hit with another EEH freeze as soon as the
+
+ /* We might get hit with another EEH freeze as soon as the
* pci slot reset line is dropped. Make sure we don't miss
* these, and clear the flag now.
*/
@@ -565,6 +646,7 @@ static void eeh_reset_pe_once(struct eeh_pe *pe)
*/
int eeh_reset_pe(struct eeh_pe *pe)
{
+ int flags = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
int i, rc;
/* Take three shots at resetting the bus */
@@ -572,7 +654,7 @@ int eeh_reset_pe(struct eeh_pe *pe)
eeh_reset_pe_once(pe);
rc = eeh_ops->wait_state(pe, PCI_BUS_RESET_WAIT_MSEC);
- if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE))
+ if ((rc & flags) == flags)
return 0;
if (rc < 0) {
@@ -604,7 +686,7 @@ void eeh_save_bars(struct eeh_dev *edev)
if (!edev)
return;
dn = eeh_dev_to_of_node(edev);
-
+
for (i = 0; i < 16; i++)
eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]);
}
@@ -674,11 +756,21 @@ int __exit eeh_ops_unregister(const char *name)
* Even if force-off is set, the EEH hardware is still enabled, so that
* newer systems can boot.
*/
-static int __init eeh_init(void)
+int eeh_init(void)
{
struct pci_controller *hose, *tmp;
struct device_node *phb;
- int ret;
+ static int cnt = 0;
+ int ret = 0;
+
+ /*
+ * We have to delay the initialization on PowerNV after
+ * the PCI hierarchy tree has been built because the PEs
+ * are figured out based on PCI devices instead of device
+ * tree nodes
+ */
+ if (machine_is(powernv) && cnt++ <= 0)
+ return ret;
/* call platform initialization function */
if (!eeh_ops) {
@@ -691,7 +783,10 @@ static int __init eeh_init(void)
return ret;
}
- raw_spin_lock_init(&confirm_error_lock);
+ /* Initialize EEH event */
+ ret = eeh_event_init();
+ if (ret)
+ return ret;
/* Enable EEH for all adapters */
if (eeh_probe_mode_devtree()) {
@@ -700,6 +795,25 @@ static int __init eeh_init(void)
phb = hose->dn;
traverse_pci_devices(phb, eeh_ops->of_probe, NULL);
}
+ } else if (eeh_probe_mode_dev()) {
+ list_for_each_entry_safe(hose, tmp,
+ &hose_list, list_node)
+ pci_walk_bus(hose->bus, eeh_ops->dev_probe, NULL);
+ } else {
+ pr_warning("%s: Invalid probe mode %d\n",
+ __func__, eeh_probe_mode);
+ return -EINVAL;
+ }
+
+ /*
+ * Call platform post-initialization. Actually, It's good chance
+ * to inform platform that EEH is ready to supply service if the
+ * I/O cache stuff has been built up.
+ */
+ if (eeh_ops->post_init) {
+ ret = eeh_ops->post_init();
+ if (ret)
+ return ret;
}
if (eeh_subsystem_enabled)
@@ -728,6 +842,14 @@ static void eeh_add_device_early(struct device_node *dn)
{
struct pci_controller *phb;
+ /*
+ * If we're doing EEH probe based on PCI device, we
+ * would delay the probe until late stage because
+ * the PCI device isn't available this moment.
+ */
+ if (!eeh_probe_mode_devtree())
+ return;
+
if (!of_node_to_eeh_dev(dn))
return;
phb = of_node_to_eeh_dev(dn)->phb;
@@ -736,7 +858,6 @@ static void eeh_add_device_early(struct device_node *dn)
if (NULL == phb || 0 == phb->buid)
return;
- /* FIXME: hotplug support on POWERNV */
eeh_ops->of_probe(dn, NULL);
}
@@ -787,6 +908,13 @@ static void eeh_add_device_late(struct pci_dev *dev)
edev->pdev = dev;
dev->dev.archdata.edev = edev;
+ /*
+ * We have to do the EEH probe here because the PCI device
+ * hasn't been created yet in the early stage.
+ */
+ if (eeh_probe_mode_dev())
+ eeh_ops->dev_probe(dev, NULL);
+
eeh_addr_cache_insert_dev(dev);
}
@@ -803,12 +931,12 @@ void eeh_add_device_tree_late(struct pci_bus *bus)
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list) {
- eeh_add_device_late(dev);
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- struct pci_bus *subbus = dev->subordinate;
- if (subbus)
- eeh_add_device_tree_late(subbus);
- }
+ eeh_add_device_late(dev);
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ struct pci_bus *subbus = dev->subordinate;
+ if (subbus)
+ eeh_add_device_tree_late(subbus);
+ }
}
}
EXPORT_SYMBOL_GPL(eeh_add_device_tree_late);
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/kernel/eeh_cache.c
index 5ce3ba7ad137..f9ac1232a746 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/kernel/eeh_cache.c
@@ -194,7 +194,7 @@ static void __eeh_addr_cache_insert_dev(struct pci_dev *dev)
}
/* Skip any devices for which EEH is not enabled. */
- if (!edev->pe) {
+ if (!eeh_probe_mode_dev() && !edev->pe) {
#ifdef DEBUG
pr_info("PCI: skip building address cache for=%s - %s\n",
pci_name(dev), dn->full_name);
@@ -285,7 +285,7 @@ void eeh_addr_cache_rmv_dev(struct pci_dev *dev)
* Must be run late in boot process, after the pci controllers
* have been scanned for devices (after all device resources are known).
*/
-void __init eeh_addr_cache_build(void)
+void eeh_addr_cache_build(void)
{
struct device_node *dn;
struct eeh_dev *edev;
@@ -316,4 +316,3 @@ void __init eeh_addr_cache_build(void)
eeh_addr_cache_print(&pci_io_addr_cache_root);
#endif
}
-
diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/kernel/eeh_dev.c
index 1efa28f5fc54..1efa28f5fc54 100644
--- a/arch/powerpc/platforms/pseries/eeh_dev.c
+++ b/arch/powerpc/kernel/eeh_dev.c
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index a3fefb61097c..2b1ce17cae50 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -154,9 +154,9 @@ static void eeh_enable_irq(struct pci_dev *dev)
* eeh_report_error - Report pci error to each device driver
* @data: eeh device
* @userdata: return value
- *
- * Report an EEH error to each device driver, collect up and
- * merge the device driver responses. Cumulative response
+ *
+ * Report an EEH error to each device driver, collect up and
+ * merge the device driver responses. Cumulative response
* passed back in "userdata".
*/
static void *eeh_report_error(void *data, void *userdata)
@@ -349,10 +349,12 @@ static void *eeh_report_failure(void *data, void *userdata)
*/
static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
{
+ struct timeval tstamp;
int cnt, rc;
/* pcibios will clear the counter; save the value */
cnt = pe->freeze_count;
+ tstamp = pe->tstamp;
/*
* We don't remove the corresponding PE instances because
@@ -376,15 +378,17 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
eeh_pe_restore_bars(pe);
/* Give the system 5 seconds to finish running the user-space
- * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes,
- * this is a hack, but if we don't do this, and try to bring
- * the device up before the scripts have taken it down,
+ * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes,
+ * this is a hack, but if we don't do this, and try to bring
+ * the device up before the scripts have taken it down,
* potentially weird things happen.
*/
if (bus) {
ssleep(5);
pcibios_add_pci_devices(bus);
}
+
+ pe->tstamp = tstamp;
pe->freeze_count = cnt;
return 0;
@@ -395,24 +399,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
*/
#define MAX_WAIT_FOR_RECOVERY 150
-/**
- * eeh_handle_event - Reset a PCI device after hard lockup.
- * @pe: EEH PE
- *
- * While PHB detects address or data parity errors on particular PCI
- * slot, the associated PE will be frozen. Besides, DMA's occurring
- * to wild addresses (which usually happen due to bugs in device
- * drivers or in PCI adapter firmware) can cause EEH error. #SERR,
- * #PERR or other misc PCI-related errors also can trigger EEH errors.
- *
- * Recovery process consists of unplugging the device driver (which
- * generated hotplug events to userspace), then issuing a PCI #RST to
- * the device, then reconfiguring the PCI config space for all bridges
- * & devices under this slot, and then finally restarting the device
- * drivers (which cause a second set of hotplug events to go out to
- * userspace).
- */
-void eeh_handle_event(struct eeh_pe *pe)
+static void eeh_handle_normal_event(struct eeh_pe *pe)
{
struct pci_bus *frozen_bus;
int rc = 0;
@@ -425,6 +412,7 @@ void eeh_handle_event(struct eeh_pe *pe)
return;
}
+ eeh_pe_update_time_stamp(pe);
pe->freeze_count++;
if (pe->freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto excess_failures;
@@ -437,6 +425,7 @@ void eeh_handle_event(struct eeh_pe *pe)
* status ... if any child can't handle the reset, then the entire
* slot is dlpar removed and added.
*/
+ pr_info("EEH: Notify device drivers to shutdown\n");
eeh_pe_dev_traverse(pe, eeh_report_error, &result);
/* Get the current PCI slot state. This can take a long time,
@@ -444,7 +433,7 @@ void eeh_handle_event(struct eeh_pe *pe)
*/
rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000);
if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) {
- printk(KERN_WARNING "EEH: Permanent failure\n");
+ pr_warning("EEH: Permanent failure\n");
goto hard_fail;
}
@@ -452,6 +441,7 @@ void eeh_handle_event(struct eeh_pe *pe)
* don't post the error log until after all dev drivers
* have been informed.
*/
+ pr_info("EEH: Collect temporary log\n");
eeh_slot_error_detail(pe, EEH_LOG_TEMP);
/* If all device drivers were EEH-unaware, then shut
@@ -459,15 +449,18 @@ void eeh_handle_event(struct eeh_pe *pe)
* go down willingly, without panicing the system.
*/
if (result == PCI_ERS_RESULT_NONE) {
+ pr_info("EEH: Reset with hotplug activity\n");
rc = eeh_reset_device(pe, frozen_bus);
if (rc) {
- printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);
+ pr_warning("%s: Unable to reset, err=%d\n",
+ __func__, rc);
goto hard_fail;
}
}
/* If all devices reported they can proceed, then re-enable MMIO */
if (result == PCI_ERS_RESULT_CAN_RECOVER) {
+ pr_info("EEH: Enable I/O for affected devices\n");
rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
if (rc < 0)
@@ -475,6 +468,7 @@ void eeh_handle_event(struct eeh_pe *pe)
if (rc) {
result = PCI_ERS_RESULT_NEED_RESET;
} else {
+ pr_info("EEH: Notify device drivers to resume I/O\n");
result = PCI_ERS_RESULT_NONE;
eeh_pe_dev_traverse(pe, eeh_report_mmio_enabled, &result);
}
@@ -482,6 +476,7 @@ void eeh_handle_event(struct eeh_pe *pe)
/* If all devices reported they can proceed, then re-enable DMA */
if (result == PCI_ERS_RESULT_CAN_RECOVER) {
+ pr_info("EEH: Enabled DMA for affected devices\n");
rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA);
if (rc < 0)
@@ -494,17 +489,22 @@ void eeh_handle_event(struct eeh_pe *pe)
/* If any device has a hard failure, then shut off everything. */
if (result == PCI_ERS_RESULT_DISCONNECT) {
- printk(KERN_WARNING "EEH: Device driver gave up\n");
+ pr_warning("EEH: Device driver gave up\n");
goto hard_fail;
}
/* If any device called out for a reset, then reset the slot */
if (result == PCI_ERS_RESULT_NEED_RESET) {
+ pr_info("EEH: Reset without hotplug activity\n");
rc = eeh_reset_device(pe, NULL);
if (rc) {
- printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);
+ pr_warning("%s: Cannot reset, err=%d\n",
+ __func__, rc);
goto hard_fail;
}
+
+ pr_info("EEH: Notify device drivers "
+ "the completion of reset\n");
result = PCI_ERS_RESULT_NONE;
eeh_pe_dev_traverse(pe, eeh_report_reset, &result);
}
@@ -512,15 +512,16 @@ void eeh_handle_event(struct eeh_pe *pe)
/* All devices should claim they have recovered by now. */
if ((result != PCI_ERS_RESULT_RECOVERED) &&
(result != PCI_ERS_RESULT_NONE)) {
- printk(KERN_WARNING "EEH: Not recovered\n");
+ pr_warning("EEH: Not recovered\n");
goto hard_fail;
}
/* Tell all device drivers that they can resume operations */
+ pr_info("EEH: Notify device driver to resume\n");
eeh_pe_dev_traverse(pe, eeh_report_resume, NULL);
return;
-
+
excess_failures:
/*
* About 90% of all real-life EEH failures in the field
@@ -550,3 +551,111 @@ perm_error:
pcibios_remove_pci_devices(frozen_bus);
}
+static void eeh_handle_special_event(void)
+{
+ struct eeh_pe *pe, *phb_pe;
+ struct pci_bus *bus;
+ struct pci_controller *hose, *tmp;
+ unsigned long flags;
+ int rc = 0;
+
+ /*
+ * The return value from next_error() has been classified as follows.
+ * It might be good to enumerate them. However, next_error() is only
+ * supported by PowerNV platform for now. So it would be fine to use
+ * integer directly:
+ *
+ * 4 - Dead IOC 3 - Dead PHB
+ * 2 - Fenced PHB 1 - Frozen PE
+ * 0 - No error found
+ *
+ */
+ rc = eeh_ops->next_error(&pe);
+ if (rc <= 0)
+ return;
+
+ switch (rc) {
+ case 4:
+ /* Mark all PHBs in dead state */
+ eeh_serialize_lock(&flags);
+ list_for_each_entry_safe(hose, tmp,
+ &hose_list, list_node) {
+ phb_pe = eeh_phb_pe_get(hose);
+ if (!phb_pe) continue;
+
+ eeh_pe_state_mark(phb_pe,
+ EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+ }
+ eeh_serialize_unlock(flags);
+
+ /* Purge all events */
+ eeh_remove_event(NULL);
+ break;
+ case 3:
+ case 2:
+ case 1:
+ /* Mark the PE in fenced state */
+ eeh_serialize_lock(&flags);
+ if (rc == 3)
+ eeh_pe_state_mark(pe,
+ EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+ else
+ eeh_pe_state_mark(pe,
+ EEH_PE_ISOLATED | EEH_PE_RECOVERING);
+ eeh_serialize_unlock(flags);
+
+ /* Purge all events of the PHB */
+ eeh_remove_event(pe);
+ break;
+ default:
+ pr_err("%s: Invalid value %d from next_error()\n",
+ __func__, rc);
+ return;
+ }
+
+ /*
+ * For fenced PHB and frozen PE, it's handled as normal
+ * event. We have to remove the affected PHBs for dead
+ * PHB and IOC
+ */
+ if (rc == 2 || rc == 1)
+ eeh_handle_normal_event(pe);
+ else {
+ list_for_each_entry_safe(hose, tmp,
+ &hose_list, list_node) {
+ phb_pe = eeh_phb_pe_get(hose);
+ if (!phb_pe || !(phb_pe->state & EEH_PE_PHB_DEAD))
+ continue;
+
+ bus = eeh_pe_bus_get(phb_pe);
+ /* Notify all devices that they're about to go down. */
+ eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
+ pcibios_remove_pci_devices(bus);
+ }
+ }
+}
+
+/**
+ * eeh_handle_event - Reset a PCI device after hard lockup.
+ * @pe: EEH PE
+ *
+ * While PHB detects address or data parity errors on particular PCI
+ * slot, the associated PE will be frozen. Besides, DMA's occurring
+ * to wild addresses (which usually happen due to bugs in device
+ * drivers or in PCI adapter firmware) can cause EEH error. #SERR,
+ * #PERR or other misc PCI-related errors also can trigger EEH errors.
+ *
+ * Recovery process consists of unplugging the device driver (which
+ * generated hotplug events to userspace), then issuing a PCI #RST to
+ * the device, then reconfiguring the PCI config space for all bridges
+ * & devices under this slot, and then finally restarting the device
+ * drivers (which cause a second set of hotplug events to go out to
+ * userspace).
+ */
+void eeh_handle_event(struct eeh_pe *pe)
+{
+ if (pe)
+ eeh_handle_normal_event(pe);
+ else
+ eeh_handle_special_event();
+}
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/kernel/eeh_event.c
index 185bedd926df..d27c5afc90ae 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/kernel/eeh_event.c
@@ -18,11 +18,10 @@
#include <linux/delay.h>
#include <linux/list.h>
-#include <linux/mutex.h>
#include <linux/sched.h>
+#include <linux/semaphore.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/kthread.h>
#include <asm/eeh_event.h>
#include <asm/ppc-pci.h>
@@ -35,14 +34,9 @@
* work-queue, where a worker thread can drive recovery.
*/
-/* EEH event workqueue setup. */
static DEFINE_SPINLOCK(eeh_eventlist_lock);
+static struct semaphore eeh_eventlist_sem;
LIST_HEAD(eeh_eventlist);
-static void eeh_thread_launcher(struct work_struct *);
-DECLARE_WORK(eeh_event_wq, eeh_thread_launcher);
-
-/* Serialize reset sequences for a given pci device */
-DEFINE_MUTEX(eeh_event_mutex);
/**
* eeh_event_handler - Dispatch EEH events.
@@ -60,55 +54,63 @@ static int eeh_event_handler(void * dummy)
struct eeh_event *event;
struct eeh_pe *pe;
- spin_lock_irqsave(&eeh_eventlist_lock, flags);
- event = NULL;
-
- /* Unqueue the event, get ready to process. */
- if (!list_empty(&eeh_eventlist)) {
- event = list_entry(eeh_eventlist.next, struct eeh_event, list);
- list_del(&event->list);
- }
- spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
-
- if (event == NULL)
- return 0;
-
- /* Serialize processing of EEH events */
- mutex_lock(&eeh_event_mutex);
- pe = event->pe;
- eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
- pr_info("EEH: Detected PCI bus error on PHB#%d-PE#%x\n",
- pe->phb->global_number, pe->addr);
-
- set_current_state(TASK_INTERRUPTIBLE); /* Don't add to load average */
- eeh_handle_event(pe);
- eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
-
- kfree(event);
- mutex_unlock(&eeh_event_mutex);
-
- /* If there are no new errors after an hour, clear the counter. */
- if (pe && pe->freeze_count > 0) {
- msleep_interruptible(3600*1000);
- if (pe->freeze_count > 0)
- pe->freeze_count--;
-
+ while (!kthread_should_stop()) {
+ if (down_interruptible(&eeh_eventlist_sem))
+ break;
+
+ /* Fetch EEH event from the queue */
+ spin_lock_irqsave(&eeh_eventlist_lock, flags);
+ event = NULL;
+ if (!list_empty(&eeh_eventlist)) {
+ event = list_entry(eeh_eventlist.next,
+ struct eeh_event, list);
+ list_del(&event->list);
+ }
+ spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
+ if (!event)
+ continue;
+
+ /* We might have event without binding PE */
+ pe = event->pe;
+ if (pe) {
+ eeh_pe_state_mark(pe, EEH_PE_RECOVERING);
+ pr_info("EEH: Detected PCI bus error on PHB#%d-PE#%x\n",
+ pe->phb->global_number, pe->addr);
+ eeh_handle_event(pe);
+ eeh_pe_state_clear(pe, EEH_PE_RECOVERING);
+ } else {
+ eeh_handle_event(NULL);
+ }
+
+ kfree(event);
}
return 0;
}
/**
- * eeh_thread_launcher - Start kernel thread to handle EEH events
- * @dummy - unused
+ * eeh_event_init - Start kernel thread to handle EEH events
*
* This routine is called to start the kernel thread for processing
* EEH event.
*/
-static void eeh_thread_launcher(struct work_struct *dummy)
+int eeh_event_init(void)
{
- if (IS_ERR(kthread_run(eeh_event_handler, NULL, "eehd")))
- printk(KERN_ERR "Failed to start EEH daemon\n");
+ struct task_struct *t;
+ int ret = 0;
+
+ /* Initialize semaphore */
+ sema_init(&eeh_eventlist_sem, 0);
+
+ t = kthread_run(eeh_event_handler, NULL, "eehd");
+ if (IS_ERR(t)) {
+ ret = PTR_ERR(t);
+ pr_err("%s: Failed to start EEH daemon (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
}
/**
@@ -136,7 +138,45 @@ int eeh_send_failure_event(struct eeh_pe *pe)
list_add(&event->list, &eeh_eventlist);
spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
- schedule_work(&eeh_event_wq);
+ /* For EEH deamon to knick in */
+ up(&eeh_eventlist_sem);
return 0;
}
+
+/**
+ * eeh_remove_event - Remove EEH event from the queue
+ * @pe: Event binding to the PE
+ *
+ * On PowerNV platform, we might have subsequent coming events
+ * is part of the former one. For that case, those subsequent
+ * coming events are totally duplicated and unnecessary, thus
+ * they should be removed.
+ */
+void eeh_remove_event(struct eeh_pe *pe)
+{
+ unsigned long flags;
+ struct eeh_event *event, *tmp;
+
+ spin_lock_irqsave(&eeh_eventlist_lock, flags);
+ list_for_each_entry_safe(event, tmp, &eeh_eventlist, list) {
+ /*
+ * If we don't have valid PE passed in, that means
+ * we already have event corresponding to dead IOC
+ * and all events should be purged.
+ */
+ if (!pe) {
+ list_del(&event->list);
+ kfree(event);
+ } else if (pe->type & EEH_PE_PHB) {
+ if (event->pe && event->pe->phb == pe->phb) {
+ list_del(&event->list);
+ kfree(event);
+ }
+ } else if (event->pe == pe) {
+ list_del(&event->list);
+ kfree(event);
+ }
+ }
+ spin_unlock_irqrestore(&eeh_eventlist_lock, flags);
+}
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index 9d4a9e8562b2..016588a6f5ed 100644
--- a/arch/powerpc/platforms/pseries/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/delay.h>
#include <linux/export.h>
#include <linux/gfp.h>
#include <linux/init.h>
@@ -78,9 +79,7 @@ int eeh_phb_pe_create(struct pci_controller *phb)
}
/* Put it into the list */
- eeh_lock();
list_add_tail(&pe->child, &eeh_phb_pe);
- eeh_unlock();
pr_debug("EEH: Add PE for PHB#%d\n", phb->global_number);
@@ -95,7 +94,7 @@ int eeh_phb_pe_create(struct pci_controller *phb)
* hierarchy tree is composed of PHB PEs. The function is used
* to retrieve the corresponding PHB PE according to the given PHB.
*/
-static struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
+struct eeh_pe *eeh_phb_pe_get(struct pci_controller *phb)
{
struct eeh_pe *pe;
@@ -185,21 +184,15 @@ void *eeh_pe_dev_traverse(struct eeh_pe *root,
return NULL;
}
- eeh_lock();
-
/* Traverse root PE */
for (pe = root; pe; pe = eeh_pe_next(pe, root)) {
eeh_pe_for_each_dev(pe, edev) {
ret = fn(edev, flag);
- if (ret) {
- eeh_unlock();
+ if (ret)
return ret;
- }
}
}
- eeh_unlock();
-
return NULL;
}
@@ -228,7 +221,7 @@ static void *__eeh_pe_get(void *data, void *flag)
return pe;
/* Try BDF address */
- if (edev->pe_config_addr &&
+ if (edev->config_addr &&
(edev->config_addr == pe->config_addr))
return pe;
@@ -246,7 +239,7 @@ static void *__eeh_pe_get(void *data, void *flag)
* which is composed of PCI bus/device/function number, or unified
* PE address.
*/
-static struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
+struct eeh_pe *eeh_pe_get(struct eeh_dev *edev)
{
struct eeh_pe *root = eeh_phb_pe_get(edev->phb);
struct eeh_pe *pe;
@@ -305,8 +298,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
{
struct eeh_pe *pe, *parent;
- eeh_lock();
-
/*
* Search the PE has been existing or not according
* to the PE address. If that has been existing, the
@@ -316,7 +307,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
pe = eeh_pe_get(edev);
if (pe && !(pe->type & EEH_PE_INVALID)) {
if (!edev->pe_config_addr) {
- eeh_unlock();
pr_err("%s: PE with addr 0x%x already exists\n",
__func__, edev->config_addr);
return -EEXIST;
@@ -328,7 +318,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
/* Put the edev to PE */
list_add_tail(&edev->list, &pe->edevs);
- eeh_unlock();
pr_debug("EEH: Add %s to Bus PE#%x\n",
edev->dn->full_name, pe->addr);
@@ -347,7 +336,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
parent->type &= ~EEH_PE_INVALID;
parent = parent->parent;
}
- eeh_unlock();
pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
edev->dn->full_name, pe->addr, pe->parent->addr);
@@ -357,7 +345,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
/* Create a new EEH PE */
pe = eeh_pe_alloc(edev->phb, EEH_PE_DEVICE);
if (!pe) {
- eeh_unlock();
pr_err("%s: out of memory!\n", __func__);
return -ENOMEM;
}
@@ -365,6 +352,17 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
pe->config_addr = edev->config_addr;
/*
+ * While doing PE reset, we probably hot-reset the
+ * upstream bridge. However, the PCI devices including
+ * the associated EEH devices might be removed when EEH
+ * core is doing recovery. So that won't safe to retrieve
+ * the bridge through downstream EEH device. We have to
+ * trace the parent PCI bus, then the upstream bridge.
+ */
+ if (eeh_probe_mode_dev())
+ pe->bus = eeh_dev_to_pci_dev(edev)->bus;
+
+ /*
* Put the new EEH PE into hierarchy tree. If the parent
* can't be found, the newly created PE will be attached
* to PHB directly. Otherwise, we have to associate the
@@ -374,7 +372,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
if (!parent) {
parent = eeh_phb_pe_get(edev->phb);
if (!parent) {
- eeh_unlock();
pr_err("%s: No PHB PE is found (PHB Domain=%d)\n",
__func__, edev->phb->global_number);
edev->pe = NULL;
@@ -391,7 +388,6 @@ int eeh_add_to_parent_pe(struct eeh_dev *edev)
list_add_tail(&pe->child, &parent->child_list);
list_add_tail(&edev->list, &pe->edevs);
edev->pe = pe;
- eeh_unlock();
pr_debug("EEH: Add %s to Device PE#%x, Parent PE#%x\n",
edev->dn->full_name, pe->addr, pe->parent->addr);
@@ -419,8 +415,6 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
return -EEXIST;
}
- eeh_lock();
-
/* Remove the EEH device */
pe = edev->pe;
edev->pe = NULL;
@@ -465,12 +459,37 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
pe = parent;
}
- eeh_unlock();
-
return 0;
}
/**
+ * eeh_pe_update_time_stamp - Update PE's frozen time stamp
+ * @pe: EEH PE
+ *
+ * We have time stamp for each PE to trace its time of getting
+ * frozen in last hour. The function should be called to update
+ * the time stamp on first error of the specific PE. On the other
+ * handle, we needn't account for errors happened in last hour.
+ */
+void eeh_pe_update_time_stamp(struct eeh_pe *pe)
+{
+ struct timeval tstamp;
+
+ if (!pe) return;
+
+ if (pe->freeze_count <= 0) {
+ pe->freeze_count = 0;
+ do_gettimeofday(&pe->tstamp);
+ } else {
+ do_gettimeofday(&tstamp);
+ if (tstamp.tv_sec - pe->tstamp.tv_sec > 3600) {
+ pe->tstamp = tstamp;
+ pe->freeze_count = 0;
+ }
+ }
+}
+
+/**
* __eeh_pe_state_mark - Mark the state for the PE
* @data: EEH PE
* @flag: state
@@ -512,9 +531,7 @@ static void *__eeh_pe_state_mark(void *data, void *flag)
*/
void eeh_pe_state_mark(struct eeh_pe *pe, int state)
{
- eeh_lock();
eeh_pe_traverse(pe, __eeh_pe_state_mark, &state);
- eeh_unlock();
}
/**
@@ -548,35 +565,135 @@ static void *__eeh_pe_state_clear(void *data, void *flag)
*/
void eeh_pe_state_clear(struct eeh_pe *pe, int state)
{
- eeh_lock();
eeh_pe_traverse(pe, __eeh_pe_state_clear, &state);
- eeh_unlock();
}
-/**
- * eeh_restore_one_device_bars - Restore the Base Address Registers for one device
- * @data: EEH device
- * @flag: Unused
+/*
+ * Some PCI bridges (e.g. PLX bridges) have primary/secondary
+ * buses assigned explicitly by firmware, and we probably have
+ * lost that after reset. So we have to delay the check until
+ * the PCI-CFG registers have been restored for the parent
+ * bridge.
*
- * Loads the PCI configuration space base address registers,
- * the expansion ROM base address, the latency timer, and etc.
- * from the saved values in the device node.
+ * Don't use normal PCI-CFG accessors, which probably has been
+ * blocked on normal path during the stage. So we need utilize
+ * eeh operations, which is always permitted.
*/
-static void *eeh_restore_one_device_bars(void *data, void *flag)
+static void eeh_bridge_check_link(struct pci_dev *pdev,
+ struct device_node *dn)
+{
+ int cap;
+ uint32_t val;
+ int timeout = 0;
+
+ /*
+ * We only check root port and downstream ports of
+ * PCIe switches
+ */
+ if (!pci_is_pcie(pdev) ||
+ (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT &&
+ pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM))
+ return;
+
+ pr_debug("%s: Check PCIe link for %s ...\n",
+ __func__, pci_name(pdev));
+
+ /* Check slot status */
+ cap = pdev->pcie_cap;
+ eeh_ops->read_config(dn, cap + PCI_EXP_SLTSTA, 2, &val);
+ if (!(val & PCI_EXP_SLTSTA_PDS)) {
+ pr_debug(" No card in the slot (0x%04x) !\n", val);
+ return;
+ }
+
+ /* Check power status if we have the capability */
+ eeh_ops->read_config(dn, cap + PCI_EXP_SLTCAP, 2, &val);
+ if (val & PCI_EXP_SLTCAP_PCP) {
+ eeh_ops->read_config(dn, cap + PCI_EXP_SLTCTL, 2, &val);
+ if (val & PCI_EXP_SLTCTL_PCC) {
+ pr_debug(" In power-off state, power it on ...\n");
+ val &= ~(PCI_EXP_SLTCTL_PCC | PCI_EXP_SLTCTL_PIC);
+ val |= (0x0100 & PCI_EXP_SLTCTL_PIC);
+ eeh_ops->write_config(dn, cap + PCI_EXP_SLTCTL, 2, val);
+ msleep(2 * 1000);
+ }
+ }
+
+ /* Enable link */
+ eeh_ops->read_config(dn, cap + PCI_EXP_LNKCTL, 2, &val);
+ val &= ~PCI_EXP_LNKCTL_LD;
+ eeh_ops->write_config(dn, cap + PCI_EXP_LNKCTL, 2, val);
+
+ /* Check link */
+ eeh_ops->read_config(dn, cap + PCI_EXP_LNKCAP, 4, &val);
+ if (!(val & PCI_EXP_LNKCAP_DLLLARC)) {
+ pr_debug(" No link reporting capability (0x%08x) \n", val);
+ msleep(1000);
+ return;
+ }
+
+ /* Wait the link is up until timeout (5s) */
+ timeout = 0;
+ while (timeout < 5000) {
+ msleep(20);
+ timeout += 20;
+
+ eeh_ops->read_config(dn, cap + PCI_EXP_LNKSTA, 2, &val);
+ if (val & PCI_EXP_LNKSTA_DLLLA)
+ break;
+ }
+
+ if (val & PCI_EXP_LNKSTA_DLLLA)
+ pr_debug(" Link up (%s)\n",
+ (val & PCI_EXP_LNKSTA_CLS_2_5GB) ? "2.5GB" : "5GB");
+ else
+ pr_debug(" Link not ready (0x%04x)\n", val);
+}
+
+#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
+#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
+
+static void eeh_restore_bridge_bars(struct pci_dev *pdev,
+ struct eeh_dev *edev,
+ struct device_node *dn)
+{
+ int i;
+
+ /*
+ * Device BARs: 0x10 - 0x18
+ * Bus numbers and windows: 0x18 - 0x30
+ */
+ for (i = 4; i < 13; i++)
+ eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
+ /* Rom: 0x38 */
+ eeh_ops->write_config(dn, 14*4, 4, edev->config_space[14]);
+
+ /* Cache line & Latency timer: 0xC 0xD */
+ eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
+ SAVED_BYTE(PCI_CACHE_LINE_SIZE));
+ eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
+ SAVED_BYTE(PCI_LATENCY_TIMER));
+ /* Max latency, min grant, interrupt ping and line: 0x3C */
+ eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]);
+
+ /* PCI Command: 0x4 */
+ eeh_ops->write_config(dn, PCI_COMMAND, 4, edev->config_space[1]);
+
+ /* Check the PCIe link is ready */
+ eeh_bridge_check_link(pdev, dn);
+}
+
+static void eeh_restore_device_bars(struct eeh_dev *edev,
+ struct device_node *dn)
{
int i;
u32 cmd;
- struct eeh_dev *edev = (struct eeh_dev *)data;
- struct device_node *dn = eeh_dev_to_of_node(edev);
for (i = 4; i < 10; i++)
eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]);
/* 12 == Expansion ROM Address */
eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]);
-#define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF))
-#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)])
-
eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1,
SAVED_BYTE(PCI_CACHE_LINE_SIZE));
eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1,
@@ -599,6 +716,34 @@ static void *eeh_restore_one_device_bars(void *data, void *flag)
else
cmd &= ~PCI_COMMAND_SERR;
eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd);
+}
+
+/**
+ * eeh_restore_one_device_bars - Restore the Base Address Registers for one device
+ * @data: EEH device
+ * @flag: Unused
+ *
+ * Loads the PCI configuration space base address registers,
+ * the expansion ROM base address, the latency timer, and etc.
+ * from the saved values in the device node.
+ */
+static void *eeh_restore_one_device_bars(void *data, void *flag)
+{
+ struct pci_dev *pdev = NULL;
+ struct eeh_dev *edev = (struct eeh_dev *)data;
+ struct device_node *dn = eeh_dev_to_of_node(edev);
+
+ /* Trace the PCI bridge */
+ if (eeh_probe_mode_dev()) {
+ pdev = eeh_dev_to_pci_dev(edev);
+ if (pdev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
+ pdev = NULL;
+ }
+
+ if (pdev)
+ eeh_restore_bridge_bars(pdev, edev, dn);
+ else
+ eeh_restore_device_bars(edev, dn);
return NULL;
}
@@ -635,19 +780,21 @@ struct pci_bus *eeh_pe_bus_get(struct eeh_pe *pe)
struct eeh_dev *edev;
struct pci_dev *pdev;
- eeh_lock();
-
if (pe->type & EEH_PE_PHB) {
bus = pe->phb->bus;
} else if (pe->type & EEH_PE_BUS ||
pe->type & EEH_PE_DEVICE) {
+ if (pe->bus) {
+ bus = pe->bus;
+ goto out;
+ }
+
edev = list_first_entry(&pe->edevs, struct eeh_dev, list);
pdev = eeh_dev_to_pci_dev(edev);
if (pdev)
bus = pdev->bus;
}
- eeh_unlock();
-
+out:
return bus;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c
index d37708360f2e..e7ae3484918c 100644
--- a/arch/powerpc/platforms/pseries/eeh_sysfs.c
+++ b/arch/powerpc/kernel/eeh_sysfs.c
@@ -72,4 +72,3 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev)
device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr);
device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
}
-
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 8741c854e03d..ab15b8d057ad 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -629,21 +629,43 @@ _GLOBAL(ret_from_except_lite)
CURRENT_THREAD_INFO(r9, r1)
ld r3,_MSR(r1)
+#ifdef CONFIG_PPC_BOOK3E
+ ld r10,PACACURRENT(r13)
+#endif /* CONFIG_PPC_BOOK3E */
ld r4,TI_FLAGS(r9)
andi. r3,r3,MSR_PR
beq resume_kernel
+#ifdef CONFIG_PPC_BOOK3E
+ lwz r3,(THREAD+THREAD_DBCR0)(r10)
+#endif /* CONFIG_PPC_BOOK3E */
/* Check current_thread_info()->flags */
andi. r0,r4,_TIF_USER_WORK_MASK
+#ifdef CONFIG_PPC_BOOK3E
+ bne 1f
+ /*
+ * Check to see if the dbcr0 register is set up to debug.
+ * Use the internal debug mode bit to do this.
+ */
+ andis. r0,r3,DBCR0_IDM@h
beq restore
-
- andi. r0,r4,_TIF_NEED_RESCHED
- beq 1f
+ mfmsr r0
+ rlwinm r0,r0,0,~MSR_DE /* Clear MSR.DE */
+ mtmsr r0
+ mtspr SPRN_DBCR0,r3
+ li r10, -1
+ mtspr SPRN_DBSR,r10
+ b restore
+#else
+ beq restore
+#endif
+1: andi. r0,r4,_TIF_NEED_RESCHED
+ beq 2f
bl .restore_interrupts
SCHEDULE_USER
b .ret_from_except_lite
-1: bl .save_nvgprs
+2: bl .save_nvgprs
bl .restore_interrupts
addi r3,r1,STACK_FRAME_OVERHEAD
bl .do_notify_resume
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 40e4a17c8ba0..4e00d223b2e3 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -341,10 +341,17 @@ vsx_unavailable_pSeries_1:
EXCEPTION_PROLOG_0(PACA_EXGEN)
b vsx_unavailable_pSeries
+facility_unavailable_trampoline:
. = 0xf60
SET_SCRATCH0(r13)
EXCEPTION_PROLOG_0(PACA_EXGEN)
- b tm_unavailable_pSeries
+ b facility_unavailable_pSeries
+
+hv_facility_unavailable_trampoline:
+ . = 0xf80
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b facility_unavailable_hv
#ifdef CONFIG_CBE_RAS
STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
@@ -522,8 +529,10 @@ denorm_done:
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf20)
STD_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
- STD_EXCEPTION_PSERIES_OOL(0xf60, tm_unavailable)
+ STD_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf60)
+ STD_EXCEPTION_HV_OOL(0xf82, facility_unavailable)
+ KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xf82)
/*
* An interrupt came in while soft-disabled. We set paca->irq_happened, then:
@@ -793,14 +802,10 @@ system_call_relon_pSeries:
STD_RELON_EXCEPTION_PSERIES(0x4d00, 0xd00, single_step)
. = 0x4e00
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_data_storage_relon_hv
+ b . /* Can't happen, see v2.07 Book III-S section 6.5 */
. = 0x4e20
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b h_instr_storage_relon_hv
+ b . /* Can't happen, see v2.07 Book III-S section 6.5 */
. = 0x4e40
SET_SCRATCH0(r13)
@@ -808,9 +813,7 @@ system_call_relon_pSeries:
b emulation_assist_relon_hv
. = 0x4e60
- SET_SCRATCH0(r13)
- EXCEPTION_PROLOG_0(PACA_EXGEN)
- b hmi_exception_relon_hv
+ b . /* Can't happen, see v2.07 Book III-S section 6.5 */
. = 0x4e80
SET_SCRATCH0(r13)
@@ -835,11 +838,17 @@ vsx_unavailable_relon_pSeries_1:
EXCEPTION_PROLOG_0(PACA_EXGEN)
b vsx_unavailable_relon_pSeries
-tm_unavailable_relon_pSeries_1:
+facility_unavailable_relon_trampoline:
. = 0x4f60
SET_SCRATCH0(r13)
EXCEPTION_PROLOG_0(PACA_EXGEN)
- b tm_unavailable_relon_pSeries
+ b facility_unavailable_relon_pSeries
+
+hv_facility_unavailable_relon_trampoline:
+ . = 0x4f80
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_0(PACA_EXGEN)
+ b facility_unavailable_relon_hv
STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
#ifdef CONFIG_PPC_DENORMALISATION
@@ -1165,36 +1174,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
bl .vsx_unavailable_exception
b .ret_from_except
- .align 7
- .globl tm_unavailable_common
-tm_unavailable_common:
- EXCEPTION_PROLOG_COMMON(0xf60, PACA_EXGEN)
- bl .save_nvgprs
- DISABLE_INTS
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .tm_unavailable_exception
- b .ret_from_except
+ STD_EXCEPTION_COMMON(0xf60, facility_unavailable, .facility_unavailable_exception)
.align 7
.globl __end_handlers
__end_handlers:
/* Equivalents to the above handlers for relocation-on interrupt vectors */
- STD_RELON_EXCEPTION_HV_OOL(0xe00, h_data_storage)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe00)
- STD_RELON_EXCEPTION_HV_OOL(0xe20, h_instr_storage)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe20)
STD_RELON_EXCEPTION_HV_OOL(0xe40, emulation_assist)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe40)
- STD_RELON_EXCEPTION_HV_OOL(0xe60, hmi_exception)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe60)
MASKABLE_RELON_EXCEPTION_HV_OOL(0xe80, h_doorbell)
- KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe80)
STD_RELON_EXCEPTION_PSERIES_OOL(0xf00, performance_monitor)
STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
- STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, tm_unavailable)
+ STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
+ STD_RELON_EXCEPTION_HV_OOL(0xf80, facility_unavailable)
#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
/*
diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c
index a949bdfc9623..f0b47d1a6b0e 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -176,7 +176,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
length_max = 512 ; /* 64 doublewords */
/* DAWR region can't cross 512 boundary */
if ((bp->attr.bp_addr >> 10) !=
- ((bp->attr.bp_addr + bp->attr.bp_len) >> 10))
+ ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 10))
return -EINVAL;
}
if (info->len >
@@ -250,6 +250,7 @@ int __kprobes hw_breakpoint_handler(struct die_args *args)
* we still need to single-step the instruction, but we don't
* generate an event.
*/
+ info->type &= ~HW_BRK_TYPE_EXTRANEOUS_IRQ;
if (!((bp->attr.bp_addr <= dar) &&
(dar - bp->attr.bp_addr < bp->attr.bp_len)))
info->type |= HW_BRK_TYPE_EXTRANEOUS_IRQ;
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 8220baa46faf..16a7c2326d48 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -205,7 +205,7 @@ static int ibmebus_create_devices(const struct of_device_id *matches)
return ret;
}
-int ibmebus_register_driver(struct of_platform_driver *drv)
+int ibmebus_register_driver(struct platform_driver *drv)
{
/* If the driver uses devices that ibmebus doesn't know, add them */
ibmebus_create_devices(drv->driver.of_match_table);
@@ -215,7 +215,7 @@ int ibmebus_register_driver(struct of_platform_driver *drv)
}
EXPORT_SYMBOL(ibmebus_register_driver);
-void ibmebus_unregister_driver(struct of_platform_driver *drv)
+void ibmebus_unregister_driver(struct platform_driver *drv)
{
driver_unregister(&drv->driver);
}
@@ -338,11 +338,10 @@ static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv)
static int ibmebus_bus_device_probe(struct device *dev)
{
int error = -ENODEV;
- struct of_platform_driver *drv;
+ struct platform_driver *drv;
struct platform_device *of_dev;
- const struct of_device_id *match;
- drv = to_of_platform_driver(dev->driver);
+ drv = to_platform_driver(dev->driver);
of_dev = to_platform_device(dev);
if (!drv->probe)
@@ -350,9 +349,8 @@ static int ibmebus_bus_device_probe(struct device *dev)
of_dev_get(of_dev);
- match = of_match_device(drv->driver.of_match_table, dev);
- if (match)
- error = drv->probe(of_dev, match);
+ if (of_driver_match_device(dev, dev->driver))
+ error = drv->probe(of_dev);
if (error)
of_dev_put(of_dev);
@@ -362,7 +360,7 @@ static int ibmebus_bus_device_probe(struct device *dev)
static int ibmebus_bus_device_remove(struct device *dev)
{
struct platform_device *of_dev = to_platform_device(dev);
- struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ struct platform_driver *drv = to_platform_driver(dev->driver);
if (dev->driver && drv->remove)
drv->remove(of_dev);
@@ -372,7 +370,7 @@ static int ibmebus_bus_device_remove(struct device *dev)
static void ibmebus_bus_device_shutdown(struct device *dev)
{
struct platform_device *of_dev = to_platform_device(dev);
- struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ struct platform_driver *drv = to_platform_driver(dev->driver);
if (dev->driver && drv->shutdown)
drv->shutdown(of_dev);
@@ -419,7 +417,7 @@ struct device_attribute ibmebus_bus_device_attrs[] = {
static int ibmebus_bus_legacy_suspend(struct device *dev, pm_message_t mesg)
{
struct platform_device *of_dev = to_platform_device(dev);
- struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ struct platform_driver *drv = to_platform_driver(dev->driver);
int ret = 0;
if (dev->driver && drv->suspend)
@@ -430,7 +428,7 @@ static int ibmebus_bus_legacy_suspend(struct device *dev, pm_message_t mesg)
static int ibmebus_bus_legacy_resume(struct device *dev)
{
struct platform_device *of_dev = to_platform_device(dev);
- struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ struct platform_driver *drv = to_platform_driver(dev->driver);
int ret = 0;
if (dev->driver && drv->resume)
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 939ea7ef0dc8..d7216c9abda1 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -85,7 +85,7 @@ int powersave_nap;
/*
* Register the sysctl to set/clear powersave_nap.
*/
-static ctl_table powersave_nap_ctl_table[]={
+static struct ctl_table powersave_nap_ctl_table[] = {
{
.procname = "powersave-nap",
.data = &powersave_nap,
@@ -95,7 +95,7 @@ static ctl_table powersave_nap_ctl_table[]={
},
{}
};
-static ctl_table powersave_nap_sysctl_root[] = {
+static struct ctl_table powersave_nap_sysctl_root[] = {
{
.procname = "kernel",
.mode = 0555,
diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c
index 50e90b7e7139..fa0b54b2a362 100644
--- a/arch/powerpc/kernel/io-workarounds.c
+++ b/arch/powerpc/kernel/io-workarounds.c
@@ -55,6 +55,7 @@ static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
{
+ unsigned hugepage_shift;
struct iowa_bus *bus;
int token;
@@ -70,11 +71,17 @@ struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
return NULL;
- ptep = find_linux_pte(init_mm.pgd, vaddr);
+ ptep = find_linux_pte_or_hugepte(init_mm.pgd, vaddr,
+ &hugepage_shift);
if (ptep == NULL)
paddr = 0;
- else
+ else {
+ /*
+ * we don't have hugepages backing iomem
+ */
+ WARN_ON(hugepage_shift);
paddr = pte_pfn(*ptep) << PAGE_SHIFT;
+ }
bus = iowa_pci_find(vaddr, paddr);
if (bus == NULL)
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index c0d0dbddfba1..b20ff173a671 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -36,6 +36,8 @@
#include <linux/hash.h>
#include <linux/fault-inject.h>
#include <linux/pci.h>
+#include <linux/iommu.h>
+#include <linux/sched.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/iommu.h>
@@ -44,6 +46,7 @@
#include <asm/kdump.h>
#include <asm/fadump.h>
#include <asm/vio.h>
+#include <asm/tce.h>
#define DBG(...)
@@ -724,6 +727,13 @@ 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);
@@ -860,3 +870,316 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
free_pages((unsigned long)vaddr, get_order(size));
}
}
+
+#ifdef CONFIG_IOMMU_API
+/*
+ * SPAPR TCE API
+ */
+static void group_release(void *iommu_data)
+{
+ struct iommu_table *tbl = iommu_data;
+ tbl->it_group = NULL;
+}
+
+void iommu_register_group(struct iommu_table *tbl,
+ int pci_domain_number, unsigned long pe_num)
+{
+ struct iommu_group *grp;
+ char *name;
+
+ grp = iommu_group_alloc();
+ if (IS_ERR(grp)) {
+ pr_warn("powerpc iommu api: cannot create new group, err=%ld\n",
+ PTR_ERR(grp));
+ return;
+ }
+ tbl->it_group = grp;
+ iommu_group_set_iommudata(grp, tbl, group_release);
+ name = kasprintf(GFP_KERNEL, "domain%d-pe%lx",
+ pci_domain_number, pe_num);
+ if (!name)
+ return;
+ iommu_group_set_name(grp, name);
+ kfree(name);
+}
+
+enum dma_data_direction iommu_tce_direction(unsigned long tce)
+{
+ if ((tce & TCE_PCI_READ) && (tce & TCE_PCI_WRITE))
+ return DMA_BIDIRECTIONAL;
+ else if (tce & TCE_PCI_READ)
+ return DMA_TO_DEVICE;
+ else if (tce & TCE_PCI_WRITE)
+ return DMA_FROM_DEVICE;
+ else
+ return DMA_NONE;
+}
+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);
+
+ /* Make sure updates are seen by hardware */
+ mb();
+}
+EXPORT_SYMBOL_GPL(iommu_flush_tce);
+
+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 */
+ if (tce_value)
+ return -EINVAL;
+
+ if (ioba & ~IOMMU_PAGE_MASK)
+ return -EINVAL;
+
+ ioba >>= IOMMU_PAGE_SHIFT;
+ if (ioba < tbl->it_offset)
+ return -EINVAL;
+
+ if ((ioba + npages) > (tbl->it_offset + tbl->it_size))
+ return -EINVAL;
+
+ return 0;
+}
+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 | TCE_PCI_WRITE | TCE_PCI_READ))
+ return -EINVAL;
+
+ if (ioba & ~IOMMU_PAGE_MASK)
+ return -EINVAL;
+
+ ioba >>= IOMMU_PAGE_SHIFT;
+ if (ioba < tbl->it_offset)
+ return -EINVAL;
+
+ if ((ioba + 1) > (tbl->it_offset + tbl->it_size))
+ return -EINVAL;
+
+ return 0;
+}
+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)
+{
+ int ret = -EBUSY;
+ unsigned long oldtce;
+ struct iommu_pool *pool = get_pool(tbl, entry);
+
+ spin_lock(&(pool->lock));
+
+ 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);
+
+ spin_unlock(&(pool->lock));
+
+ /* if (unlikely(ret))
+ pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n",
+ __func__, hwaddr, entry << IOMMU_PAGE_SHIFT,
+ hwaddr, ret); */
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_tce_build);
+
+int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
+ unsigned long tce)
+{
+ int ret;
+ struct page *page = NULL;
+ unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK & ~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 << IOMMU_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 << IOMMU_PAGE_SHIFT, tce, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_put_tce_user_mode);
+
+int iommu_take_ownership(struct iommu_table *tbl)
+{
+ unsigned long sz = (tbl->it_size + 7) >> 3;
+
+ 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;
+ }
+
+ memset(tbl->it_map, 0xff, sz);
+ iommu_clear_tces_and_put_pages(tbl, tbl->it_offset, tbl->it_size);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iommu_take_ownership);
+
+void iommu_release_ownership(struct iommu_table *tbl)
+{
+ unsigned long sz = (tbl->it_size + 7) >> 3;
+
+ 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);
+}
+EXPORT_SYMBOL_GPL(iommu_release_ownership);
+
+static int iommu_add_device(struct device *dev)
+{
+ struct iommu_table *tbl;
+ int ret = 0;
+
+ if (WARN_ON(dev->iommu_group)) {
+ pr_warn("iommu_tce: device %s is already in iommu group %d, skipping\n",
+ dev_name(dev),
+ iommu_group_id(dev->iommu_group));
+ return -EBUSY;
+ }
+
+ tbl = get_iommu_table_base(dev);
+ if (!tbl || !tbl->it_group) {
+ pr_debug("iommu_tce: skipping device %s with no tbl\n",
+ dev_name(dev));
+ return 0;
+ }
+
+ pr_debug("iommu_tce: adding %s to iommu group %d\n",
+ dev_name(dev), iommu_group_id(tbl->it_group));
+
+ ret = iommu_group_add_device(tbl->it_group, dev);
+ if (ret < 0)
+ pr_err("iommu_tce: %s has not been added, ret=%d\n",
+ dev_name(dev), ret);
+
+ return ret;
+}
+
+static void iommu_del_device(struct device *dev)
+{
+ iommu_group_remove_device(dev);
+}
+
+static int iommu_bus_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ return iommu_add_device(dev);
+ case BUS_NOTIFY_DEL_DEVICE:
+ iommu_del_device(dev);
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+ .notifier_call = iommu_bus_notifier,
+};
+
+static int __init tce_iommu_init(void)
+{
+ struct pci_dev *pdev = NULL;
+
+ BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
+
+ for_each_pci_dev(pdev)
+ iommu_add_device(&pdev->dev);
+
+ bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+ return 0;
+}
+
+subsys_initcall_sync(tce_iommu_init);
+
+#else
+
+void iommu_register_group(struct iommu_table *tbl,
+ int pci_domain_number, unsigned long pe_num)
+{
+}
+
+#endif /* CONFIG_IOMMU_API */
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index ea185e0b3cae..2e51cde616d2 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -116,8 +116,6 @@ static inline notrace int decrementer_check_overflow(void)
u64 now = get_tb_or_rtc();
u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
- if (now >= *next_tb)
- set_dec(1);
return now >= *next_tb;
}
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 11f5b03a0b06..2156ea90eb54 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -36,12 +36,6 @@
#include <asm/sstep.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
-#define MSR_SINGLESTEP (MSR_DE)
-#else
-#define MSR_SINGLESTEP (MSR_SE)
-#endif
-
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -104,19 +98,7 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
- /* We turn off async exceptions to ensure that the single step will
- * be for the instruction we have the kprobe on, if we dont its
- * possible we'd get the single step reported for an exception handler
- * like Decrementer or External Interrupt */
- regs->msr &= ~MSR_EE;
- regs->msr |= MSR_SINGLESTEP;
-#ifdef CONFIG_PPC_ADV_DEBUG_REGS
- regs->msr &= ~MSR_CE;
- mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM);
-#ifdef CONFIG_PPC_47x
- isync();
-#endif
-#endif
+ enable_single_step(regs);
/*
* On powerpc we should single step on the original
diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c
index 6782221d49bd..db28032e320e 100644
--- a/arch/powerpc/kernel/kvm.c
+++ b/arch/powerpc/kernel/kvm.c
@@ -750,13 +750,8 @@ EXPORT_SYMBOL_GPL(kvm_hypercall);
static __init void kvm_free_tmp(void)
{
- unsigned long start, end;
-
- start = (ulong)&kvm_tmp[kvm_tmp_index + (PAGE_SIZE - 1)] & PAGE_MASK;
- end = (ulong)&kvm_tmp[ARRAY_SIZE(kvm_tmp)] & PAGE_MASK;
-
- /* Free the tmp space we don't need */
- free_reserved_area(start, end, 0, NULL);
+ free_reserved_area(&kvm_tmp[kvm_tmp_index],
+ &kvm_tmp[ARRAY_SIZE(kvm_tmp)], -1, NULL);
}
static int __init kvm_guest_init(void)
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 48fbc2b97e95..8213ee1eb05a 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -84,22 +84,30 @@ static ssize_t dev_nvram_read(struct file *file, char __user *buf,
char *tmp = NULL;
ssize_t size;
- ret = -ENODEV;
- if (!ppc_md.nvram_size)
+ if (!ppc_md.nvram_size) {
+ ret = -ENODEV;
goto out;
+ }
- ret = 0;
size = ppc_md.nvram_size();
- if (*ppos >= size || size < 0)
+ if (size < 0) {
+ ret = size;
+ goto out;
+ }
+
+ if (*ppos >= size) {
+ ret = 0;
goto out;
+ }
count = min_t(size_t, count, size - *ppos);
count = min(count, PAGE_SIZE);
- ret = -ENOMEM;
tmp = kmalloc(count, GFP_KERNEL);
- if (!tmp)
+ if (!tmp) {
+ ret = -ENOMEM;
goto out;
+ }
ret = ppc_md.nvram_read(tmp, count, ppos);
if (ret <= 0)
diff --git a/arch/powerpc/kernel/pci-hotplug.c b/arch/powerpc/kernel/pci-hotplug.c
new file mode 100644
index 000000000000..3f608800c06b
--- /dev/null
+++ b/arch/powerpc/kernel/pci-hotplug.c
@@ -0,0 +1,111 @@
+/*
+ * Derived from "arch/powerpc/platforms/pseries/pci_dlpar.c"
+ *
+ * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
+ * Copyright (C) 2005 International Business Machines
+ *
+ * Updates, 2005, John Rose <johnrose@austin.ibm.com>
+ * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
+ * Updates, 2013, Gavin Shan <shangw@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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/pci.h>
+#include <linux/export.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
+#include <asm/eeh.h>
+
+/**
+ * __pcibios_remove_pci_devices - remove all devices under this bus
+ * @bus: the indicated PCI bus
+ * @purge_pe: destroy the PE on removal of PCI devices
+ *
+ * Remove all of the PCI devices under this bus both from the
+ * linux pci device tree, and from the powerpc EEH address cache.
+ * By default, the corresponding PE will be destroied during the
+ * normal PCI hotplug path. For PCI hotplug during EEH recovery,
+ * the corresponding PE won't be destroied and deallocated.
+ */
+void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe)
+{
+ struct pci_dev *dev, *tmp;
+ struct pci_bus *child_bus;
+
+ /* First go down child busses */
+ list_for_each_entry(child_bus, &bus->children, node)
+ __pcibios_remove_pci_devices(child_bus, purge_pe);
+
+ pr_debug("PCI: Removing devices on bus %04x:%02x\n",
+ pci_domain_nr(bus), bus->number);
+ list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
+ pr_debug(" * Removing %s...\n", pci_name(dev));
+ eeh_remove_bus_device(dev, purge_pe);
+ pci_stop_and_remove_bus_device(dev);
+ }
+}
+
+/**
+ * pcibios_remove_pci_devices - remove all devices under this bus
+ * @bus: the indicated PCI bus
+ *
+ * Remove all of the PCI devices under this bus both from the
+ * linux pci device tree, and from the powerpc EEH address cache.
+ */
+void pcibios_remove_pci_devices(struct pci_bus *bus)
+{
+ __pcibios_remove_pci_devices(bus, 1);
+}
+EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
+
+/**
+ * pcibios_add_pci_devices - adds new pci devices to bus
+ * @bus: the indicated PCI bus
+ *
+ * This routine will find and fixup new pci devices under
+ * the indicated bus. This routine presumes that there
+ * might already be some devices under this bridge, so
+ * it carefully tries to add only new devices. (And that
+ * is how this routine differs from other, similar pcibios
+ * routines.)
+ */
+void pcibios_add_pci_devices(struct pci_bus * bus)
+{
+ int slotno, num, mode, pass, max;
+ struct pci_dev *dev;
+ struct device_node *dn = pci_bus_to_OF_node(bus);
+
+ eeh_add_device_tree_early(dn);
+
+ mode = PCI_PROBE_NORMAL;
+ if (ppc_md.pci_probe_mode)
+ mode = ppc_md.pci_probe_mode(bus);
+
+ if (mode == PCI_PROBE_DEVTREE) {
+ /* use ofdt-based probe */
+ of_rescan_bus(dn, bus);
+ } else if (mode == PCI_PROBE_NORMAL) {
+ /* use legacy probe */
+ slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
+ num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
+ if (!num)
+ return;
+ pcibios_setup_bus_devices(bus);
+ max = bus->busn_res.start;
+ for (pass = 0; pass < 2; pass++) {
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ max = pci_scan_bridge(bus, dev,
+ max, pass);
+ }
+ }
+ }
+ pcibios_finish_adding_to_bus(bus);
+}
+EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 2a67e9baa59f..6b0ba5854d99 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -128,7 +128,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
const char *type;
struct pci_slot *slot;
- dev = alloc_pci_dev();
+ dev = pci_alloc_dev(bus);
if (!dev)
return NULL;
type = of_get_property(node, "device_type", NULL);
@@ -137,7 +137,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
pr_debug(" create device, devfn: %x, type: %s\n", devfn, type);
- dev->bus = bus;
dev->dev.of_node = of_node_get(node);
dev->dev.parent = bus->bridge;
dev->dev.bus = &pci_bus_type;
@@ -165,7 +164,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
pr_debug(" class: 0x%x\n", dev->class);
pr_debug(" revision: 0x%x\n", dev->revision);
- dev->current_state = 4; /* unknown power state */
+ dev->current_state = PCI_UNKNOWN; /* unknown power state */
dev->error_state = pci_channel_io_normal;
dev->dma_mask = 0xffffffff;
diff --git a/arch/powerpc/kernel/proc_powerpc.c b/arch/powerpc/kernel/proc_powerpc.c
index feb8580fdc84..c30612aad68e 100644
--- a/arch/powerpc/kernel/proc_powerpc.c
+++ b/arch/powerpc/kernel/proc_powerpc.c
@@ -29,25 +29,9 @@
#ifdef CONFIG_PPC64
-static loff_t page_map_seek( struct file *file, loff_t off, int whence)
+static loff_t page_map_seek(struct file *file, loff_t off, int whence)
{
- loff_t new;
- switch(whence) {
- case 0:
- new = off;
- break;
- case 1:
- new = file->f_pos + off;
- break;
- case 2:
- new = PAGE_SIZE + off;
- break;
- default:
- return -EINVAL;
- }
- if ( new < 0 || new > PAGE_SIZE )
- return -EINVAL;
- return (file->f_pos = new);
+ return fixed_size_llseek(file, off, whence, PAGE_SIZE);
}
static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes,
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 076d1242507a..c517dbe705fd 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -916,7 +916,11 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
flush_altivec_to_thread(src);
flush_vsx_to_thread(src);
flush_spe_to_thread(src);
+
*dst = *src;
+
+ clear_task_ebb(dst);
+
return 0;
}
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 8b6f7a99cce2..eb23ac92abb9 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -559,6 +559,35 @@ void __init early_init_dt_setup_initrd_arch(unsigned long start,
}
#endif
+static void __init early_reserve_mem_dt(void)
+{
+ unsigned long i, len, dt_root;
+ const __be32 *prop;
+
+ dt_root = of_get_flat_dt_root();
+
+ prop = of_get_flat_dt_prop(dt_root, "reserved-ranges", &len);
+
+ if (!prop)
+ return;
+
+ DBG("Found new-style reserved-ranges\n");
+
+ /* Each reserved range is an (address,size) pair, 2 cells each,
+ * totalling 4 cells per range. */
+ for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
+ u64 base, size;
+
+ base = of_read_number(prop + (i * 4) + 0, 2);
+ size = of_read_number(prop + (i * 4) + 2, 2);
+
+ if (size) {
+ DBG("reserving: %llx -> %llx\n", base, size);
+ memblock_reserve(base, size);
+ }
+ }
+}
+
static void __init early_reserve_mem(void)
{
u64 base, size;
@@ -574,12 +603,16 @@ static void __init early_reserve_mem(void)
self_size = initial_boot_params->totalsize;
memblock_reserve(self_base, self_size);
+ /* Look for the new "reserved-regions" property in the DT */
+ early_reserve_mem_dt();
+
#ifdef CONFIG_BLK_DEV_INITRD
- /* then reserve the initrd, if any */
- if (initrd_start && (initrd_end > initrd_start))
+ /* Then reserve the initrd, if any */
+ if (initrd_start && (initrd_end > initrd_start)) {
memblock_reserve(_ALIGN_DOWN(__pa(initrd_start), PAGE_SIZE),
_ALIGN_UP(initrd_end, PAGE_SIZE) -
_ALIGN_DOWN(initrd_start, PAGE_SIZE));
+ }
#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_PPC32
@@ -591,6 +624,8 @@ static void __init early_reserve_mem(void)
u32 base_32, size_32;
u32 *reserve_map_32 = (u32 *)reserve_map;
+ DBG("Found old 32-bit reserve map\n");
+
while (1) {
base_32 = *(reserve_map_32++);
size_32 = *(reserve_map_32++);
@@ -605,6 +640,9 @@ static void __init early_reserve_mem(void)
return;
}
#endif
+ DBG("Processing reserve map\n");
+
+ /* Handle the reserve map in the fdt blob if it exists */
while (1) {
base = *(reserve_map++);
size = *(reserve_map++);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index 98c2fc198712..9a0d24c390a3 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -975,16 +975,12 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
hw_brk.type = (data & HW_BRK_TYPE_DABR) | HW_BRK_TYPE_PRIV_ALL;
hw_brk.len = 8;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
- if (ptrace_get_breakpoints(task) < 0)
- return -ESRCH;
-
bp = thread->ptrace_bps[0];
if ((!data) || !(hw_brk.type & HW_BRK_TYPE_RDWR)) {
if (bp) {
unregister_hw_breakpoint(bp);
thread->ptrace_bps[0] = NULL;
}
- ptrace_put_breakpoints(task);
return 0;
}
if (bp) {
@@ -997,11 +993,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
ret = modify_user_hw_breakpoint(bp, &attr);
if (ret) {
- ptrace_put_breakpoints(task);
return ret;
}
thread->ptrace_bps[0] = bp;
- ptrace_put_breakpoints(task);
thread->hw_brk = hw_brk;
return 0;
}
@@ -1016,12 +1010,9 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
ptrace_triggered, NULL, task);
if (IS_ERR(bp)) {
thread->ptrace_bps[0] = NULL;
- ptrace_put_breakpoints(task);
return PTR_ERR(bp);
}
- ptrace_put_breakpoints(task);
-
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
task->thread.hw_brk = hw_brk;
#else /* CONFIG_PPC_ADV_DEBUG_REGS */
@@ -1440,24 +1431,19 @@ static long ppc_set_hwdebug(struct task_struct *child,
if (bp_info->trigger_type & PPC_BREAKPOINT_TRIGGER_WRITE)
brk.type |= HW_BRK_TYPE_WRITE;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
- if (ptrace_get_breakpoints(child) < 0)
- return -ESRCH;
-
/*
* Check if the request is for 'range' breakpoints. We can
* support it if range < 8 bytes.
*/
- if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE) {
+ if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE)
len = bp_info->addr2 - bp_info->addr;
- } else if (bp_info->addr_mode != PPC_BREAKPOINT_MODE_EXACT) {
- ptrace_put_breakpoints(child);
+ else if (bp_info->addr_mode == PPC_BREAKPOINT_MODE_EXACT)
+ len = 1;
+ else
return -EINVAL;
- }
bp = thread->ptrace_bps[0];
- if (bp) {
- ptrace_put_breakpoints(child);
+ if (bp)
return -ENOSPC;
- }
/* Create a new breakpoint request if one doesn't exist already */
hw_breakpoint_init(&attr);
@@ -1469,11 +1455,9 @@ static long ppc_set_hwdebug(struct task_struct *child,
ptrace_triggered, NULL, child);
if (IS_ERR(bp)) {
thread->ptrace_bps[0] = NULL;
- ptrace_put_breakpoints(child);
return PTR_ERR(bp);
}
- ptrace_put_breakpoints(child);
return 1;
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
@@ -1517,16 +1501,12 @@ static long ppc_del_hwdebug(struct task_struct *child, long data)
return -EINVAL;
#ifdef CONFIG_HAVE_HW_BREAKPOINT
- if (ptrace_get_breakpoints(child) < 0)
- return -ESRCH;
-
bp = thread->ptrace_bps[0];
if (bp) {
unregister_hw_breakpoint(bp);
thread->ptrace_bps[0] = NULL;
} else
ret = -ENOENT;
- ptrace_put_breakpoints(child);
return ret;
#else /* CONFIG_HAVE_HW_BREAKPOINT */
if (child->thread.hw_brk.address == 0)
diff --git a/arch/powerpc/kernel/reloc_32.S b/arch/powerpc/kernel/reloc_32.S
index ef46ba6e094f..f366fedb0872 100644
--- a/arch/powerpc/kernel/reloc_32.S
+++ b/arch/powerpc/kernel/reloc_32.S
@@ -166,7 +166,7 @@ ha16:
/* R_PPC_ADDR16_LO */
lo16:
cmpwi r4, R_PPC_ADDR16_LO
- bne nxtrela
+ bne unknown_type
lwz r4, 0(r9) /* r_offset */
lwz r0, 8(r9) /* r_addend */
add r0, r0, r3
@@ -191,6 +191,7 @@ nxtrela:
dcbst r4,r7
sync /* Ensure the data is flushed before icbi */
icbi r4,r7
+unknown_type:
cmpwi r8, 0 /* relasz = 0 ? */
ble done
add r9, r9, r6 /* move to next entry in the .rela table */
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 52add6f3e201..80b5ef403f68 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -1172,7 +1172,7 @@ int __init early_init_dt_scan_rtas(unsigned long node,
static arch_spinlock_t timebase_lock;
static u64 timebase = 0;
-void __cpuinit rtas_give_timebase(void)
+void rtas_give_timebase(void)
{
unsigned long flags;
@@ -1189,7 +1189,7 @@ void __cpuinit rtas_give_timebase(void)
local_irq_restore(flags);
}
-void __cpuinit rtas_take_timebase(void)
+void rtas_take_timebase(void)
{
while (!timebase)
barrier();
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index e379d3fd1694..389fb8077cc9 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -76,7 +76,7 @@
#endif
int boot_cpuid = 0;
-int __initdata spinning_secondaries;
+int spinning_secondaries;
u64 ppc64_pft_size;
/* Pick defaults since we might want to patch instructions
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 201385c3a1ae..0f83122e6676 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -407,7 +407,8 @@ inline unsigned long copy_transact_fpr_from_user(struct task_struct *task,
* altivec/spe instructions at some point.
*/
static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
- int sigret, int ctx_has_vsx_region)
+ struct mcontext __user *tm_frame, int sigret,
+ int ctx_has_vsx_region)
{
unsigned long msr = regs->msr;
@@ -475,6 +476,12 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
if (__put_user(msr, &frame->mc_gregs[PT_MSR]))
return 1;
+ /* We need to write 0 the MSR top 32 bits in the tm frame so that we
+ * can check it on the restore to see if TM is active
+ */
+ if (tm_frame && __put_user(0, &tm_frame->mc_gregs[PT_MSR]))
+ return 1;
+
if (sigret) {
/* Set up the sigreturn trampoline: li r0,sigret; sc */
if (__put_user(0x38000000UL + sigret, &frame->tramp[0])
@@ -747,7 +754,7 @@ static long restore_tm_user_regs(struct pt_regs *regs,
struct mcontext __user *tm_sr)
{
long err;
- unsigned long msr;
+ unsigned long msr, msr_hi;
#ifdef CONFIG_VSX
int i;
#endif
@@ -852,8 +859,11 @@ static long restore_tm_user_regs(struct pt_regs *regs,
tm_enable();
/* This loads the checkpointed FP/VEC state, if used */
tm_recheckpoint(&current->thread, msr);
- /* The task has moved into TM state S, so ensure MSR reflects this */
- regs->msr = (regs->msr & ~MSR_TS_MASK) | MSR_TS_S;
+ /* Get the top half of the MSR */
+ if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
+ return 1;
+ /* Pull in MSR TM from user context */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
/* This loads the speculative FP/VEC state, if used */
if (msr & MSR_FP) {
@@ -952,6 +962,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
{
struct rt_sigframe __user *rt_sf;
struct mcontext __user *frame;
+ struct mcontext __user *tm_frame = NULL;
void __user *addr;
unsigned long newsp = 0;
int sigret;
@@ -985,23 +996,24 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ tm_frame = &rt_sf->uc_transact.uc_mcontext;
if (MSR_TM_ACTIVE(regs->msr)) {
- if (save_tm_user_regs(regs, &rt_sf->uc.uc_mcontext,
- &rt_sf->uc_transact.uc_mcontext, sigret))
+ if (save_tm_user_regs(regs, frame, tm_frame, sigret))
goto badframe;
}
else
#endif
- if (save_user_regs(regs, frame, sigret, 1))
+ {
+ if (save_user_regs(regs, frame, tm_frame, sigret, 1))
goto badframe;
+ }
regs->link = tramp;
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
if (MSR_TM_ACTIVE(regs->msr)) {
if (__put_user((unsigned long)&rt_sf->uc_transact,
&rt_sf->uc.uc_link)
- || __put_user(to_user_ptr(&rt_sf->uc_transact.uc_mcontext),
- &rt_sf->uc_transact.uc_regs))
+ || __put_user((unsigned long)tm_frame, &rt_sf->uc_transact.uc_regs))
goto badframe;
}
else
@@ -1170,7 +1182,7 @@ long sys_swapcontext(struct ucontext __user *old_ctx,
mctx = (struct mcontext __user *)
((unsigned long) &old_ctx->uc_mcontext & ~0xfUL);
if (!access_ok(VERIFY_WRITE, old_ctx, ctx_size)
- || save_user_regs(regs, mctx, 0, ctx_has_vsx_region)
+ || save_user_regs(regs, mctx, NULL, 0, ctx_has_vsx_region)
|| put_sigset_t(&old_ctx->uc_sigmask, &current->blocked)
|| __put_user(to_user_ptr(mctx), &old_ctx->uc_regs))
return -EFAULT;
@@ -1233,7 +1245,7 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
if (__get_user(msr_hi, &mcp->mc_gregs[PT_MSR]))
goto bad;
- if (MSR_TM_SUSPENDED(msr_hi<<32)) {
+ if (MSR_TM_ACTIVE(msr_hi<<32)) {
/* We only recheckpoint on return if we're
* transaction.
*/
@@ -1392,6 +1404,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
{
struct sigcontext __user *sc;
struct sigframe __user *frame;
+ struct mcontext __user *tm_mctx = NULL;
unsigned long newsp = 0;
int sigret;
unsigned long tramp;
@@ -1425,6 +1438,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ tm_mctx = &frame->mctx_transact;
if (MSR_TM_ACTIVE(regs->msr)) {
if (save_tm_user_regs(regs, &frame->mctx, &frame->mctx_transact,
sigret))
@@ -1432,8 +1446,10 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
}
else
#endif
- if (save_user_regs(regs, &frame->mctx, sigret, 1))
+ {
+ if (save_user_regs(regs, &frame->mctx, tm_mctx, sigret, 1))
goto badframe;
+ }
regs->link = tramp;
@@ -1481,16 +1497,22 @@ badframe:
long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
struct pt_regs *regs)
{
+ struct sigframe __user *sf;
struct sigcontext __user *sc;
struct sigcontext sigctx;
struct mcontext __user *sr;
void __user *addr;
sigset_t set;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ struct mcontext __user *mcp, *tm_mcp;
+ unsigned long msr_hi;
+#endif
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
- sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ sf = (struct sigframe __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+ sc = &sf->sctx;
addr = sc;
if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
goto badframe;
@@ -1507,11 +1529,25 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,
#endif
set_current_blocked(&set);
- sr = (struct mcontext __user *)from_user_ptr(sigctx.regs);
- addr = sr;
- if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
- || restore_user_regs(regs, sr, 1))
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+ mcp = (struct mcontext __user *)&sf->mctx;
+ tm_mcp = (struct mcontext __user *)&sf->mctx_transact;
+ if (__get_user(msr_hi, &tm_mcp->mc_gregs[PT_MSR]))
goto badframe;
+ if (MSR_TM_ACTIVE(msr_hi<<32)) {
+ if (!cpu_has_feature(CPU_FTR_TM))
+ goto badframe;
+ if (restore_tm_user_regs(regs, mcp, tm_mcp))
+ goto badframe;
+ } else
+#endif
+ {
+ sr = (struct mcontext __user *)from_user_ptr(sigctx.regs);
+ addr = sr;
+ if (!access_ok(VERIFY_READ, sr, sizeof(*sr))
+ || restore_user_regs(regs, sr, 1))
+ goto badframe;
+ }
set_thread_flag(TIF_RESTOREALL);
return 0;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 345947367ec0..887e99d85bc2 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -410,6 +410,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
/* get MSR separately, transfer the LE bit if doing signal return */
err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+ /* pull in MSR TM from user context */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
+
+ /* pull in MSR LE from user context */
regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE);
/* The following non-GPR non-FPR non-VR state is also checkpointed: */
@@ -505,8 +509,6 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
tm_enable();
/* This loads the checkpointed FP/VEC state, if used */
tm_recheckpoint(&current->thread, msr);
- /* The task has moved into TM state S, so ensure MSR reflects this: */
- regs->msr = (regs->msr & ~MSR_TS_MASK) | __MASK(33);
/* This loads the speculative FP/VEC state, if used */
if (msr & MSR_FP) {
@@ -654,7 +656,7 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
if (__get_user(msr, &uc->uc_mcontext.gp_regs[PT_MSR]))
goto badframe;
- if (MSR_TM_SUSPENDED(msr)) {
+ if (MSR_TM_ACTIVE(msr)) {
/* We recheckpoint on return. */
struct ucontext __user *uc_transact;
if (__get_user(uc_transact, &uc->uc_link))
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index ee7ac5e6e28a..38b0ba65a735 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -480,7 +480,7 @@ static void cpu_idle_thread_init(unsigned int cpu, struct task_struct *idle)
secondary_ti = current_set[cpu] = ti;
}
-int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
+int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
int rc, c;
@@ -610,7 +610,7 @@ static struct device_node *cpu_to_l2cache(int cpu)
}
/* Activate a secondary processor. */
-__cpuinit void start_secondary(void *unused)
+void start_secondary(void *unused)
{
unsigned int cpu = smp_processor_id();
struct device_node *l2_cache;
@@ -637,12 +637,10 @@ __cpuinit void start_secondary(void *unused)
vdso_getcpu_init();
#endif
- notify_cpu_starting(cpu);
- set_cpu_online(cpu, true);
/* Update sibling maps */
base = cpu_first_thread_sibling(cpu);
for (i = 0; i < threads_per_core; i++) {
- if (cpu_is_offline(base + i))
+ if (cpu_is_offline(base + i) && (cpu != base + i))
continue;
cpumask_set_cpu(cpu, cpu_sibling_mask(base + i));
cpumask_set_cpu(base + i, cpu_sibling_mask(cpu));
@@ -667,6 +665,10 @@ __cpuinit void start_secondary(void *unused)
}
of_node_put(l2_cache);
+ smp_wmb();
+ notify_cpu_starting(cpu);
+ set_cpu_online(cpu, true);
+
local_irq_enable();
cpu_startup_entry(CPUHP_ONLINE);
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index e68a84568b8b..27a90b99ef67 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -341,7 +341,7 @@ static struct device_attribute pa6t_attrs[] = {
#endif /* HAS_PPC_PMC_PA6T */
#endif /* HAS_PPC_PMC_CLASSIC */
-static void __cpuinit register_cpu_online(unsigned int cpu)
+static void register_cpu_online(unsigned int cpu)
{
struct cpu *c = &per_cpu(cpu_devices, cpu);
struct device *s = &c->dev;
@@ -502,7 +502,7 @@ ssize_t arch_cpu_release(const char *buf, size_t count)
#endif /* CONFIG_HOTPLUG_CPU */
-static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,
+static int sysfs_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned int)(long)hcpu;
@@ -522,7 +522,7 @@ static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata sysfs_cpu_nb = {
+static struct notifier_block sysfs_cpu_nb = {
.notifier_call = sysfs_cpu_notify,
};
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 5fc29ad7e26f..65ab9e909377 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -631,7 +631,6 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
return found;
}
-/* should become __cpuinit when secondary_cpu_time_init also is */
void start_cpu_decrementer(void)
{
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
index 2da67e7a16d5..51be8fb24803 100644
--- a/arch/powerpc/kernel/tm.S
+++ b/arch/powerpc/kernel/tm.S
@@ -112,9 +112,18 @@ _GLOBAL(tm_reclaim)
std r3, STACK_PARAM(0)(r1)
SAVE_NVGPRS(r1)
+ /* We need to setup MSR for VSX register save instructions. Here we
+ * also clear the MSR RI since when we do the treclaim, we won't have a
+ * valid kernel pointer for a while. We clear RI here as it avoids
+ * adding another mtmsr closer to the treclaim. This makes the region
+ * maked as non-recoverable wider than it needs to be but it saves on
+ * inserting another mtmsrd later.
+ */
mfmsr r14
mr r15, r14
ori r15, r15, MSR_FP
+ li r16, MSR_RI
+ andc r15, r15, r16
oris r15, r15, MSR_VEC@h
#ifdef CONFIG_VSX
BEGIN_FTR_SECTION
@@ -349,9 +358,10 @@ restore_gprs:
mtcr r5
mtxer r6
- /* MSR and flags: We don't change CRs, and we don't need to alter
- * MSR.
+ /* Clear the MSR RI since we are about to change R1. EE is already off
*/
+ li r4, 0
+ mtmsrd r4, 1
REST_4GPRS(0, r7) /* GPR0-3 */
REST_GPR(4, r7) /* GPR4-6 */
@@ -377,6 +387,10 @@ restore_gprs:
GET_PACA(r13)
GET_SCRATCH0(r1)
+ /* R1 is restored, so we are recoverable again. EE is still off */
+ li r4, MSR_RI
+ mtmsrd r4, 1
+
REST_NVGPRS(r1)
addi r1, r1, TM_FRAME_SIZE
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index c0e5caf8ccc7..bf33c22e38a4 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -866,6 +866,10 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword)
u8 val;
u32 shift = 8 * (3 - (pos & 0x3));
+ /* if process is 32-bit, clear upper 32 bits of EA */
+ if ((regs->msr & MSR_64BIT) == 0)
+ EA &= 0xFFFFFFFF;
+
switch ((instword & PPC_INST_STRING_MASK)) {
case PPC_INST_LSWX:
case PPC_INST_LSWI:
@@ -1125,7 +1129,17 @@ void __kprobes program_check_exception(struct pt_regs *regs)
* ESR_DST (!?) or 0. In the process of chasing this with the
* hardware people - not sure if it can happen on any illegal
* instruction or only on FP instructions, whether there is a
- * pattern to occurrences etc. -dgibson 31/Mar/2003 */
+ * pattern to occurrences etc. -dgibson 31/Mar/2003
+ */
+
+ /*
+ * If we support a HW FPU, we need to ensure the FP state
+ * if flushed into the thread_struct before attempting
+ * emulation
+ */
+#ifdef CONFIG_PPC_FPU
+ flush_fp_to_thread(current);
+#endif
switch (do_mathemu(regs)) {
case 0:
emulate_single_step(regs);
@@ -1282,25 +1296,50 @@ void vsx_unavailable_exception(struct pt_regs *regs)
die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT);
}
-void tm_unavailable_exception(struct pt_regs *regs)
+void facility_unavailable_exception(struct pt_regs *regs)
{
+ static char *facility_strings[] = {
+ "FPU",
+ "VMX/VSX",
+ "DSCR",
+ "PMU SPRs",
+ "BHRB",
+ "TM",
+ "AT",
+ "EBB",
+ "TAR",
+ };
+ char *facility, *prefix;
+ u64 value;
+
+ if (regs->trap == 0xf60) {
+ value = mfspr(SPRN_FSCR);
+ prefix = "";
+ } else {
+ value = mfspr(SPRN_HFSCR);
+ prefix = "Hypervisor ";
+ }
+
+ value = value >> 56;
+
/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
local_irq_enable();
- /* Currently we never expect a TMU exception. Catch
- * this and kill the process!
- */
- printk(KERN_EMERG "Unexpected TM unavailable exception at %lx "
- "(msr %lx)\n",
- regs->nip, regs->msr);
+ if (value < ARRAY_SIZE(facility_strings))
+ facility = facility_strings[value];
+ else
+ facility = "unknown";
+
+ pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
+ prefix, facility, regs->nip, regs->msr);
if (user_mode(regs)) {
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}
- die("Unexpected TM unavailable exception", regs, SIGABRT);
+ die("Unexpected facility unavailable exception", regs, SIGABRT);
}
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
@@ -1396,8 +1435,7 @@ void performance_monitor_exception(struct pt_regs *regs)
void SoftwareEmulation(struct pt_regs *regs)
{
extern int do_mathemu(struct pt_regs *);
- extern int Soft_emulate_8xx(struct pt_regs *);
-#if defined(CONFIG_MATH_EMULATION) || defined(CONFIG_8XX_MINIMAL_FPEMU)
+#if defined(CONFIG_MATH_EMULATION)
int errcode;
#endif
@@ -1430,23 +1468,6 @@ void SoftwareEmulation(struct pt_regs *regs)
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}
-
-#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
- errcode = Soft_emulate_8xx(regs);
- if (errcode >= 0)
- PPC_WARN_EMULATED(8xx, regs);
-
- switch (errcode) {
- case 0:
- emulate_single_step(regs);
- return;
- case 1:
- _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
- return;
- case -EFAULT:
- _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip);
- return;
- }
#else
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
#endif
@@ -1796,8 +1817,6 @@ struct ppc_emulated ppc_emulated = {
WARN_EMULATED_SETUP(unaligned),
#ifdef CONFIG_MATH_EMULATION
WARN_EMULATED_SETUP(math),
-#elif defined(CONFIG_8XX_MINIMAL_FPEMU)
- WARN_EMULATED_SETUP(8xx),
#endif
#ifdef CONFIG_VSX
WARN_EMULATED_SETUP(vsx),
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 9d3fdcd66290..a15837519dca 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -50,7 +50,7 @@ void __init udbg_early_init(void)
udbg_init_debug_beat();
#elif defined(CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE)
udbg_init_pas_realmode();
-#elif defined(CONFIG_BOOTX_TEXT)
+#elif defined(CONFIG_PPC_EARLY_DEBUG_BOOTX)
udbg_init_btext();
#elif defined(CONFIG_PPC_EARLY_DEBUG_44x)
/* PPC44x debug */
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index d4f463ac65b1..1d9c92621b36 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -711,7 +711,7 @@ static void __init vdso_setup_syscall_map(void)
}
#ifdef CONFIG_PPC64
-int __cpuinit vdso_getcpu_init(void)
+int vdso_getcpu_init(void)
{
unsigned long cpu, node, val;
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 422de3f4d46c..008cd856c5b5 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -5,9 +5,10 @@
subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
+KVM := ../../../virt/kvm
-common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o \
- eventfd.o)
+common-objs-y = $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \
+ $(KVM)/eventfd.o
CFLAGS_44x_tlb.o := -I.
CFLAGS_e500_mmu.o := -I.
@@ -53,7 +54,7 @@ kvm-e500mc-objs := \
kvm-objs-$(CONFIG_KVM_E500MC) := $(kvm-e500mc-objs)
kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_PR) := \
- ../../../virt/kvm/coalesced_mmio.o \
+ $(KVM)/coalesced_mmio.o \
fpu.o \
book3s_paired_singles.o \
book3s_pr.o \
@@ -86,8 +87,8 @@ kvm-book3s_64-objs-$(CONFIG_KVM_XICS) += \
book3s_xics.o
kvm-book3s_64-module-objs := \
- ../../../virt/kvm/kvm_main.o \
- ../../../virt/kvm/eventfd.o \
+ $(KVM)/kvm_main.o \
+ $(KVM)/eventfd.o \
powerpc.o \
emulate.o \
book3s.o \
@@ -111,7 +112,7 @@ kvm-book3s_32-objs := \
kvm-objs-$(CONFIG_KVM_BOOK3S_32) := $(kvm-book3s_32-objs)
kvm-objs-$(CONFIG_KVM_MPIC) += mpic.o
-kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(addprefix ../../../virt/kvm/, irqchip.o)
+kvm-objs-$(CONFIG_HAVE_KVM_IRQ_ROUTING) += $(KVM)/irqchip.o
kvm-objs := $(kvm-objs-m) $(kvm-objs-y)
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c
index b871721c0050..739bfbadb85e 100644
--- a/arch/powerpc/kvm/book3s_64_mmu.c
+++ b/arch/powerpc/kvm/book3s_64_mmu.c
@@ -26,6 +26,7 @@
#include <asm/tlbflush.h>
#include <asm/kvm_ppc.h>
#include <asm/kvm_book3s.h>
+#include <asm/mmu-hash64.h>
/* #define DEBUG_MMU */
@@ -76,6 +77,24 @@ static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe(
return NULL;
}
+static int kvmppc_slb_sid_shift(struct kvmppc_slb *slbe)
+{
+ return slbe->tb ? SID_SHIFT_1T : SID_SHIFT;
+}
+
+static u64 kvmppc_slb_offset_mask(struct kvmppc_slb *slbe)
+{
+ return (1ul << kvmppc_slb_sid_shift(slbe)) - 1;
+}
+
+static u64 kvmppc_slb_calc_vpn(struct kvmppc_slb *slb, gva_t eaddr)
+{
+ eaddr &= kvmppc_slb_offset_mask(slb);
+
+ return (eaddr >> VPN_SHIFT) |
+ ((slb->vsid) << (kvmppc_slb_sid_shift(slb) - VPN_SHIFT));
+}
+
static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
bool data)
{
@@ -85,11 +104,7 @@ static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr,
if (!slb)
return 0;
- if (slb->tb)
- return (((u64)eaddr >> 12) & 0xfffffff) |
- (((u64)slb->vsid) << 28);
-
- return (((u64)eaddr >> 12) & 0xffff) | (((u64)slb->vsid) << 16);
+ return kvmppc_slb_calc_vpn(slb, eaddr);
}
static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe)
@@ -100,7 +115,8 @@ static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe)
static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr)
{
int p = kvmppc_mmu_book3s_64_get_pagesize(slbe);
- return ((eaddr & 0xfffffff) >> p);
+
+ return ((eaddr & kvmppc_slb_offset_mask(slbe)) >> p);
}
static hva_t kvmppc_mmu_book3s_64_get_pteg(
@@ -109,13 +125,15 @@ static hva_t kvmppc_mmu_book3s_64_get_pteg(
bool second)
{
u64 hash, pteg, htabsize;
- u32 page;
+ u32 ssize;
hva_t r;
+ u64 vpn;
- page = kvmppc_mmu_book3s_64_get_page(slbe, eaddr);
htabsize = ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1);
- hash = slbe->vsid ^ page;
+ vpn = kvmppc_slb_calc_vpn(slbe, eaddr);
+ ssize = slbe->tb ? MMU_SEGSIZE_1T : MMU_SEGSIZE_256M;
+ hash = hpt_hash(vpn, kvmppc_mmu_book3s_64_get_pagesize(slbe), ssize);
if (second)
hash = ~hash;
hash &= ((1ULL << 39ULL) - 1ULL);
@@ -146,7 +164,7 @@ static u64 kvmppc_mmu_book3s_64_get_avpn(struct kvmppc_slb *slbe, gva_t eaddr)
u64 avpn;
avpn = kvmppc_mmu_book3s_64_get_page(slbe, eaddr);
- avpn |= slbe->vsid << (28 - p);
+ avpn |= slbe->vsid << (kvmppc_slb_sid_shift(slbe) - p);
if (p < 24)
avpn >>= ((80 - p) - 56) - 8;
@@ -167,7 +185,6 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
int i;
u8 key = 0;
bool found = false;
- bool perm_err = false;
int second = 0;
ulong mp_ea = vcpu->arch.magic_page_ea;
@@ -190,13 +207,15 @@ static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
if (!slbe)
goto no_seg_found;
+ avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr);
+ if (slbe->tb)
+ avpn |= SLB_VSID_B_1T;
+
do_second:
ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second);
if (kvm_is_error_hva(ptegp))
goto no_page_found;
- avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr);
-
if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) {
printk(KERN_ERR "KVM can't copy data from 0x%lx!\n", ptegp);
goto no_page_found;
@@ -219,7 +238,7 @@ do_second:
continue;
/* AVPN compare */
- if (HPTE_V_AVPN_VAL(avpn) == HPTE_V_AVPN_VAL(v)) {
+ if (HPTE_V_COMPARE(avpn, v)) {
u8 pp = (r & HPTE_R_PP) | key;
int eaddr_mask = 0xFFF;
@@ -248,11 +267,6 @@ do_second:
break;
}
- if (!gpte->may_read) {
- perm_err = true;
- continue;
- }
-
dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx "
"-> 0x%lx\n",
eaddr, avpn, gpte->vpage, gpte->raddr);
@@ -281,6 +295,8 @@ do_second:
if (pteg[i+1] != oldr)
copy_to_user((void __user *)ptegp, pteg, sizeof(pteg));
+ if (!gpte->may_read)
+ return -EPERM;
return 0;
} else {
dprintk("KVM MMU: No PTE found (ea=0x%lx sdr1=0x%llx "
@@ -296,13 +312,7 @@ do_second:
}
}
-
no_page_found:
-
-
- if (perm_err)
- return -EPERM;
-
return -ENOENT;
no_seg_found:
@@ -334,7 +344,7 @@ static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb)
slbe->large = (rs & SLB_VSID_L) ? 1 : 0;
slbe->tb = (rs & SLB_VSID_B_1T) ? 1 : 0;
slbe->esid = slbe->tb ? esid_1t : esid;
- slbe->vsid = rs >> 12;
+ slbe->vsid = (rs & ~SLB_VSID_B) >> (kvmppc_slb_sid_shift(slbe) - 16);
slbe->valid = (rb & SLB_ESID_V) ? 1 : 0;
slbe->Ks = (rs & SLB_VSID_KS) ? 1 : 0;
slbe->Kp = (rs & SLB_VSID_KP) ? 1 : 0;
@@ -375,6 +385,7 @@ static u64 kvmppc_mmu_book3s_64_slbmfev(struct kvm_vcpu *vcpu, u64 slb_nr)
static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea)
{
struct kvmppc_slb *slbe;
+ u64 seg_size;
dprintk("KVM MMU: slbie(0x%llx)\n", ea);
@@ -386,8 +397,11 @@ static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea)
dprintk("KVM MMU: slbie(0x%llx, 0x%llx)\n", ea, slbe->esid);
slbe->valid = false;
+ slbe->orige = 0;
+ slbe->origv = 0;
- kvmppc_mmu_map_segment(vcpu, ea);
+ seg_size = 1ull << kvmppc_slb_sid_shift(slbe);
+ kvmppc_mmu_flush_segment(vcpu, ea & ~(seg_size - 1), seg_size);
}
static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
@@ -396,8 +410,11 @@ static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu)
dprintk("KVM MMU: slbia()\n");
- for (i = 1; i < vcpu->arch.slb_nr; i++)
+ for (i = 1; i < vcpu->arch.slb_nr; i++) {
vcpu->arch.slb[i].valid = false;
+ vcpu->arch.slb[i].orige = 0;
+ vcpu->arch.slb[i].origv = 0;
+ }
if (vcpu->arch.shared->msr & MSR_IR) {
kvmppc_mmu_flush_segments(vcpu);
@@ -467,8 +484,14 @@ static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, ulong esid,
if (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
slb = kvmppc_mmu_book3s_64_find_slbe(vcpu, ea);
- if (slb)
+ if (slb) {
gvsid = slb->vsid;
+ if (slb->tb) {
+ gvsid <<= SID_SHIFT_1T - SID_SHIFT;
+ gvsid |= esid & ((1ul << (SID_SHIFT_1T - SID_SHIFT)) - 1);
+ gvsid |= VSID_1T;
+ }
+ }
}
switch (vcpu->arch.shared->msr & (MSR_DR|MSR_IR)) {
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index 3a9a1aceb14f..e5240524bf6c 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -34,7 +34,7 @@
void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
{
ppc_md.hpte_invalidate(pte->slot, pte->host_vpn,
- MMU_PAGE_4K, MMU_SEGSIZE_256M,
+ MMU_PAGE_4K, MMU_PAGE_4K, MMU_SEGSIZE_256M,
false);
}
@@ -301,6 +301,23 @@ out:
return r;
}
+void kvmppc_mmu_flush_segment(struct kvm_vcpu *vcpu, ulong ea, ulong seg_size)
+{
+ struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
+ ulong seg_mask = -seg_size;
+ int i;
+
+ for (i = 1; i < svcpu->slb_max; i++) {
+ if ((svcpu->slb[i].esid & SLB_ESID_V) &&
+ (svcpu->slb[i].esid & seg_mask) == ea) {
+ /* Invalidate this entry */
+ svcpu->slb[i].esid = 0;
+ }
+ }
+
+ svcpu_put(svcpu);
+}
+
void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
{
struct kvmppc_book3s_shadow_vcpu *svcpu = svcpu_get(vcpu);
@@ -325,9 +342,9 @@ int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
return -1;
vcpu3s->context_id[0] = err;
- vcpu3s->proto_vsid_max = ((vcpu3s->context_id[0] + 1)
+ vcpu3s->proto_vsid_max = ((u64)(vcpu3s->context_id[0] + 1)
<< ESID_BITS) - 1;
- vcpu3s->proto_vsid_first = vcpu3s->context_id[0] << ESID_BITS;
+ vcpu3s->proto_vsid_first = (u64)vcpu3s->context_id[0] << ESID_BITS;
vcpu3s->proto_vsid_next = vcpu3s->proto_vsid_first;
kvmppc_mmu_hpte_init(vcpu);
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 5880dfb31074..710d31317d81 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -675,6 +675,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
}
/* if the guest wants write access, see if that is OK */
if (!writing && hpte_is_writable(r)) {
+ unsigned int hugepage_shift;
pte_t *ptep, pte;
/*
@@ -683,9 +684,10 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
*/
rcu_read_lock_sched();
ptep = find_linux_pte_or_hugepte(current->mm->pgd,
- hva, NULL);
- if (ptep && pte_present(*ptep)) {
- pte = kvmppc_read_update_linux_pte(ptep, 1);
+ hva, &hugepage_shift);
+ if (ptep) {
+ pte = kvmppc_read_update_linux_pte(ptep, 1,
+ hugepage_shift);
if (pte_write(pte))
write_ok = 1;
}
diff --git a/arch/powerpc/kvm/book3s_64_slb.S b/arch/powerpc/kvm/book3s_64_slb.S
index 56b983e7b738..4f0caecc0f9d 100644
--- a/arch/powerpc/kvm/book3s_64_slb.S
+++ b/arch/powerpc/kvm/book3s_64_slb.S
@@ -66,10 +66,6 @@ slb_exit_skip_ ## num:
ld r12, PACA_SLBSHADOWPTR(r13)
- /* Save off the first entry so we can slbie it later */
- ld r10, SHADOW_SLB_ESID(0)(r12)
- ld r11, SHADOW_SLB_VSID(0)(r12)
-
/* Remove bolted entries */
UNBOLT_SLB_ENTRY(0)
UNBOLT_SLB_ENTRY(1)
@@ -81,15 +77,10 @@ slb_exit_skip_ ## num:
/* Flush SLB */
+ li r10, 0
+ slbmte r10, r10
slbia
- /* r0 = esid & ESID_MASK */
- rldicr r10, r10, 0, 35
- /* r0 |= CLASS_BIT(VSID) */
- rldic r12, r11, 56 - 36, 36
- or r10, r10, r12
- slbie r10
-
/* Fill SLB with our shadow */
lbz r12, SVCPU_SLB_MAX(r3)
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 6dcbb49105a4..fc25689a9f35 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -27,7 +27,7 @@ static void *real_vmalloc_addr(void *x)
unsigned long addr = (unsigned long) x;
pte_t *p;
- p = find_linux_pte(swapper_pg_dir, addr);
+ p = find_linux_pte_or_hugepte(swapper_pg_dir, addr, NULL);
if (!p || !pte_present(*p))
return NULL;
/* assume we don't have huge pages in vmalloc space... */
@@ -139,20 +139,18 @@ static pte_t lookup_linux_pte(pgd_t *pgdir, unsigned long hva,
{
pte_t *ptep;
unsigned long ps = *pte_sizep;
- unsigned int shift;
+ unsigned int hugepage_shift;
- ptep = find_linux_pte_or_hugepte(pgdir, hva, &shift);
+ ptep = find_linux_pte_or_hugepte(pgdir, hva, &hugepage_shift);
if (!ptep)
return __pte(0);
- if (shift)
- *pte_sizep = 1ul << shift;
+ if (hugepage_shift)
+ *pte_sizep = 1ul << hugepage_shift;
else
*pte_sizep = PAGE_SIZE;
if (ps > *pte_sizep)
return __pte(0);
- if (!pte_present(*ptep))
- return __pte(0);
- return kvmppc_read_update_linux_pte(ptep, writing);
+ return kvmppc_read_update_linux_pte(ptep, writing, hugepage_shift);
}
static inline void unlock_hpte(unsigned long *hpte, unsigned long hpte_v)
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index bdc40b8e77d9..19498a567a81 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -1239,8 +1239,7 @@ out:
#ifdef CONFIG_PPC64
int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm, struct kvm_ppc_smmu_info *info)
{
- /* No flags */
- info->flags = 0;
+ info->flags = KVM_PPC_1T_SEGMENTS;
/* SLB is always 64 entries */
info->slb_size = 64;
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 1a1b51189773..dcc94f016007 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -796,7 +796,7 @@ static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
kvmppc_fill_pt_regs(&regs);
timer_interrupt(&regs);
break;
-#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3E_64)
+#if defined(CONFIG_PPC_DOORBELL)
case BOOKE_INTERRUPT_DOORBELL:
kvmppc_fill_pt_regs(&regs);
doorbell_exception(&regs);
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index 631a2650e4e4..2c52ada30775 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -169,6 +169,9 @@ static int kvmppc_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
vcpu->arch.shared->sprg3 = spr_val;
break;
+ /* PIR can legally be written, but we ignore it */
+ case SPRN_PIR: break;
+
default:
emulated = kvmppc_core_emulate_mtspr(vcpu, sprn,
spr_val);
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index e15c521846ca..99c7fc16dc0d 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -580,7 +580,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
if (instr & 1)
regs->link = regs->nip;
if (branch_taken(instr, regs))
- regs->nip = imm;
+ regs->nip = truncate_if_32bit(regs->msr, imm);
return 1;
#ifdef CONFIG_PPC64
case 17: /* sc */
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
index 7d1dba0d57f9..8d035d2d42a6 100644
--- a/arch/powerpc/math-emu/Makefile
+++ b/arch/powerpc/math-emu/Makefile
@@ -4,7 +4,8 @@ obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
fmadd.o fmadds.o fmsub.o fmsubs.o \
fmul.o fmuls.o fnabs.o fneg.o \
fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \
- fres.o frsp.o frsqrte.o fsel.o lfs.o \
+ fres.o fre.o frsp.o fsel.o lfs.o \
+ frsqrte.o frsqrtes.o \
fsqrt.o fsqrts.o fsub.o fsubs.o \
mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
mtfsf.o mtfsfi.o stfiwx.o stfs.o \
diff --git a/arch/powerpc/math-emu/fre.c b/arch/powerpc/math-emu/fre.c
new file mode 100644
index 000000000000..49ccf2cc6a5a
--- /dev/null
+++ b/arch/powerpc/math-emu/fre.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+
+int fre(void *frD, void *frB)
+{
+#ifdef DEBUG
+ printk("%s: %p %p\n", __func__, frD, frB);
+#endif
+ return -ENOSYS;
+}
diff --git a/arch/powerpc/math-emu/frsqrtes.c b/arch/powerpc/math-emu/frsqrtes.c
new file mode 100644
index 000000000000..7e838e380314
--- /dev/null
+++ b/arch/powerpc/math-emu/frsqrtes.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/uaccess.h>
+
+int frsqrtes(void *frD, void *frB)
+{
+#ifdef DEBUG
+ printk("%s: %p %p\n", __func__, frD, frB);
+#endif
+ return 0;
+}
diff --git a/arch/powerpc/math-emu/math.c b/arch/powerpc/math-emu/math.c
index 164d55935bd8..0328e66e0799 100644
--- a/arch/powerpc/math-emu/math.c
+++ b/arch/powerpc/math-emu/math.c
@@ -58,8 +58,10 @@ FLOATFUNC(fnabs);
FLOATFUNC(fneg);
/* Optional */
+FLOATFUNC(fre);
FLOATFUNC(fres);
FLOATFUNC(frsqrte);
+FLOATFUNC(frsqrtes);
FLOATFUNC(fsel);
FLOATFUNC(fsqrt);
FLOATFUNC(fsqrts);
@@ -97,6 +99,7 @@ FLOATFUNC(fsqrts);
#define FSQRTS 0x016 /* 22 */
#define FRES 0x018 /* 24 */
#define FMULS 0x019 /* 25 */
+#define FRSQRTES 0x01a /* 26 */
#define FMSUBS 0x01c /* 28 */
#define FMADDS 0x01d /* 29 */
#define FNMSUBS 0x01e /* 30 */
@@ -109,6 +112,7 @@ FLOATFUNC(fsqrts);
#define FADD 0x015 /* 21 */
#define FSQRT 0x016 /* 22 */
#define FSEL 0x017 /* 23 */
+#define FRE 0x018 /* 24 */
#define FMUL 0x019 /* 25 */
#define FRSQRTE 0x01a /* 26 */
#define FMSUB 0x01c /* 28 */
@@ -299,9 +303,10 @@ do_mathemu(struct pt_regs *regs)
case FDIVS: func = fdivs; type = AB; break;
case FSUBS: func = fsubs; type = AB; break;
case FADDS: func = fadds; type = AB; break;
- case FSQRTS: func = fsqrts; type = AB; break;
- case FRES: func = fres; type = AB; break;
+ case FSQRTS: func = fsqrts; type = XB; break;
+ case FRES: func = fres; type = XB; break;
case FMULS: func = fmuls; type = AC; break;
+ case FRSQRTES: func = frsqrtes;type = XB; break;
case FMSUBS: func = fmsubs; type = ABC; break;
case FMADDS: func = fmadds; type = ABC; break;
case FNMSUBS: func = fnmsubs; type = ABC; break;
@@ -317,10 +322,11 @@ do_mathemu(struct pt_regs *regs)
case FDIV: func = fdiv; type = AB; break;
case FSUB: func = fsub; type = AB; break;
case FADD: func = fadd; type = AB; break;
- case FSQRT: func = fsqrt; type = AB; break;
+ case FSQRT: func = fsqrt; type = XB; break;
+ case FRE: func = fre; type = XB; break;
case FSEL: func = fsel; type = ABC; break;
case FMUL: func = fmul; type = AC; break;
- case FRSQRTE: func = frsqrte; type = AB; break;
+ case FRSQRTE: func = frsqrte; type = XB; break;
case FMSUB: func = fmsub; type = ABC; break;
case FMADD: func = fmadd; type = ABC; break;
case FNMSUB: func = fnmsub; type = ABC; break;
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index 2c9441ee6bb8..82b1ff759e26 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -41,7 +41,7 @@ int icache_44x_need_flush;
unsigned long tlb_47x_boltmap[1024/8];
-static void __cpuinit ppc44x_update_tlb_hwater(void)
+static void ppc44x_update_tlb_hwater(void)
{
extern unsigned int tlb_44x_patch_hwater_D[];
extern unsigned int tlb_44x_patch_hwater_I[];
@@ -134,7 +134,7 @@ static void __init ppc47x_update_boltmap(void)
/*
* "Pins" a 256MB TLB entry in AS0 for kernel lowmem for 47x type MMU
*/
-static void __cpuinit ppc47x_pin_tlb(unsigned int virt, unsigned int phys)
+static void ppc47x_pin_tlb(unsigned int virt, unsigned int phys)
{
unsigned int rA;
int bolted;
@@ -229,7 +229,7 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
}
#ifdef CONFIG_SMP
-void __cpuinit mmu_init_secondary(int cpu)
+void mmu_init_secondary(int cpu)
{
unsigned long addr;
unsigned long memstart = memstart_addr & ~(PPC_PIN_SIZE - 1);
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index cf16b5733eaa..51230ee6a407 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -6,17 +6,16 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
-obj-y := fault.o mem.o pgtable.o gup.o \
+obj-y := fault.o mem.o pgtable.o gup.o mmap.o \
init_$(CONFIG_WORD_SIZE).o \
pgtable_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_PPC_MMU_NOHASH) += mmu_context_nohash.o tlb_nohash.o \
tlb_nohash_low.o
obj-$(CONFIG_PPC_BOOK3E) += tlb_low_$(CONFIG_WORD_SIZE)e.o
-obj-$(CONFIG_PPC64) += mmap_64.o
hash64-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC_STD_MMU_64) += hash_utils_64.o \
slb_low.o slb.o stab.o \
- mmap_64.o $(hash64-y)
+ $(hash64-y)
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
tlb_hash$(CONFIG_WORD_SIZE).o \
@@ -28,11 +27,12 @@ obj-$(CONFIG_44x) += 44x_mmu.o
obj-$(CONFIG_PPC_FSL_BOOK3E) += fsl_booke_mmu.o
obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
obj-$(CONFIG_PPC_MM_SLICES) += slice.o
-ifeq ($(CONFIG_HUGETLB_PAGE),y)
obj-y += hugetlbpage.o
+ifeq ($(CONFIG_HUGETLB_PAGE),y)
obj-$(CONFIG_PPC_STD_MMU_64) += hugetlbpage-hash64.o
obj-$(CONFIG_PPC_BOOK3E_MMU) += hugetlbpage-book3e.o
endif
+obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += hugepage-hash64.o
obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o
obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
obj-$(CONFIG_HIGHMEM) += highmem.o
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index 4b921affa495..49822d90ea96 100644
--- a/arch/powerpc/mm/gup.c
+++ b/arch/powerpc/mm/gup.c
@@ -34,7 +34,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
ptep = pte_offset_kernel(&pmd, addr);
do {
- pte_t pte = *ptep;
+ pte_t pte = ACCESS_ONCE(*ptep);
struct page *page;
if ((pte_val(pte) & mask) != result)
@@ -63,12 +63,18 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
pmdp = pmd_offset(&pud, addr);
do {
- pmd_t pmd = *pmdp;
+ pmd_t pmd = ACCESS_ONCE(*pmdp);
next = pmd_addr_end(addr, end);
- if (pmd_none(pmd))
+ /*
+ * If we find a splitting transparent hugepage we
+ * return zero. That will result in taking the slow
+ * path which will call wait_split_huge_page()
+ * if the pmd is still in splitting state
+ */
+ if (pmd_none(pmd) || pmd_trans_splitting(pmd))
return 0;
- if (pmd_huge(pmd)) {
+ if (pmd_huge(pmd) || pmd_large(pmd)) {
if (!gup_hugepte((pte_t *)pmdp, PMD_SIZE, addr, next,
write, pages, nr))
return 0;
@@ -91,7 +97,7 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
pudp = pud_offset(&pgd, addr);
do {
- pud_t pud = *pudp;
+ pud_t pud = ACCESS_ONCE(*pudp);
next = pud_addr_end(addr, end);
if (pud_none(pud))
@@ -154,7 +160,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
pgdp = pgd_offset(mm, addr);
do {
- pgd_t pgd = *pgdp;
+ pgd_t pgd = ACCESS_ONCE(*pgdp);
pr_devel(" %016lx: normal pgd %p\n", addr,
(void *)pgd_val(pgd));
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index 0e980acae67c..d3cbda62857b 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -289,9 +289,10 @@ htab_modify_pte:
/* Call ppc_md.hpte_updatepp */
mr r5,r29 /* vpn */
- li r6,MMU_PAGE_4K /* page size */
- ld r7,STK_PARAM(R9)(r1) /* segment size */
- ld r8,STK_PARAM(R8)(r1) /* get "local" param */
+ li r6,MMU_PAGE_4K /* base page size */
+ li r7,MMU_PAGE_4K /* actual page size */
+ ld r8,STK_PARAM(R9)(r1) /* segment size */
+ ld r9,STK_PARAM(R8)(r1) /* get "local" param */
_GLOBAL(htab_call_hpte_updatepp)
bl . /* Patched by htab_finish_init() */
@@ -649,9 +650,10 @@ htab_modify_pte:
/* Call ppc_md.hpte_updatepp */
mr r5,r29 /* vpn */
- li r6,MMU_PAGE_4K /* page size */
- ld r7,STK_PARAM(R9)(r1) /* segment size */
- ld r8,STK_PARAM(R8)(r1) /* get "local" param */
+ li r6,MMU_PAGE_4K /* base page size */
+ li r7,MMU_PAGE_4K /* actual page size */
+ ld r8,STK_PARAM(R9)(r1) /* segment size */
+ ld r9,STK_PARAM(R8)(r1) /* get "local" param */
_GLOBAL(htab_call_hpte_updatepp)
bl . /* patched by htab_finish_init() */
@@ -937,9 +939,10 @@ ht64_modify_pte:
/* Call ppc_md.hpte_updatepp */
mr r5,r29 /* vpn */
- li r6,MMU_PAGE_64K
- ld r7,STK_PARAM(R9)(r1) /* segment size */
- ld r8,STK_PARAM(R8)(r1) /* get "local" param */
+ li r6,MMU_PAGE_64K /* base page size */
+ li r7,MMU_PAGE_64K /* actual page size */
+ ld r8,STK_PARAM(R9)(r1) /* segment size */
+ ld r9,STK_PARAM(R8)(r1) /* get "local" param */
_GLOBAL(ht64_call_hpte_updatepp)
bl . /* patched by htab_finish_init() */
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 4c122c3f1623..3f0c30ae4791 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -273,61 +273,15 @@ static long native_hpte_remove(unsigned long hpte_group)
return i;
}
-static inline int __hpte_actual_psize(unsigned int lp, int psize)
-{
- int i, shift;
- unsigned int mask;
-
- /* start from 1 ignoring MMU_PAGE_4K */
- for (i = 1; i < MMU_PAGE_COUNT; i++) {
-
- /* invalid penc */
- if (mmu_psize_defs[psize].penc[i] == -1)
- continue;
- /*
- * encoding bits per actual page size
- * PTE LP actual page size
- * rrrr rrrz >=8KB
- * rrrr rrzz >=16KB
- * rrrr rzzz >=32KB
- * rrrr zzzz >=64KB
- * .......
- */
- shift = mmu_psize_defs[i].shift - LP_SHIFT;
- if (shift > LP_BITS)
- shift = LP_BITS;
- mask = (1 << shift) - 1;
- if ((lp & mask) == mmu_psize_defs[psize].penc[i])
- return i;
- }
- return -1;
-}
-
-static inline int hpte_actual_psize(struct hash_pte *hptep, int psize)
-{
- /* Look at the 8 bit LP value */
- unsigned int lp = (hptep->r >> LP_SHIFT) & ((1 << LP_BITS) - 1);
-
- if (!(hptep->v & HPTE_V_VALID))
- return -1;
-
- /* First check if it is large page */
- if (!(hptep->v & HPTE_V_LARGE))
- return MMU_PAGE_4K;
-
- return __hpte_actual_psize(lp, psize);
-}
-
static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
- unsigned long vpn, int psize, int ssize,
- int local)
+ unsigned long vpn, int bpsize,
+ int apsize, int ssize, int local)
{
struct hash_pte *hptep = htab_address + slot;
unsigned long hpte_v, want_v;
int ret = 0;
- int actual_psize;
- want_v = hpte_encode_avpn(vpn, psize, ssize);
+ want_v = hpte_encode_avpn(vpn, bpsize, ssize);
DBG_LOW(" update(vpn=%016lx, avpnv=%016lx, group=%lx, newpp=%lx)",
vpn, want_v & HPTE_V_AVPN, slot, newpp);
@@ -335,7 +289,6 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
native_lock_hpte(hptep);
hpte_v = hptep->v;
- actual_psize = hpte_actual_psize(hptep, psize);
/*
* We need to invalidate the TLB always because hpte_remove doesn't do
* a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
@@ -343,12 +296,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
* (hpte_remove) because we assume the old translation is still
* technically "valid".
*/
- if (actual_psize < 0) {
- actual_psize = psize;
- ret = -1;
- goto err_out;
- }
- if (!HPTE_V_COMPARE(hpte_v, want_v)) {
+ if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
DBG_LOW(" -> miss\n");
ret = -1;
} else {
@@ -357,11 +305,10 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
(newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
}
-err_out:
native_unlock_hpte(hptep);
/* Ensure it is out of the tlb too. */
- tlbie(vpn, psize, actual_psize, ssize, local);
+ tlbie(vpn, bpsize, apsize, ssize, local);
return ret;
}
@@ -402,7 +349,6 @@ static long native_hpte_find(unsigned long vpn, int psize, int ssize)
static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
int psize, int ssize)
{
- int actual_psize;
unsigned long vpn;
unsigned long vsid;
long slot;
@@ -415,36 +361,33 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
if (slot == -1)
panic("could not find page to bolt\n");
hptep = htab_address + slot;
- actual_psize = hpte_actual_psize(hptep, psize);
- if (actual_psize < 0)
- actual_psize = psize;
/* Update the HPTE */
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
(newpp & (HPTE_R_PP | HPTE_R_N));
-
- /* Ensure it is out of the tlb too. */
- tlbie(vpn, psize, actual_psize, ssize, 0);
+ /*
+ * Ensure it is out of the tlb too. Bolted entries base and
+ * actual page size will be same.
+ */
+ tlbie(vpn, psize, psize, ssize, 0);
}
static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
- int psize, int ssize, int local)
+ int bpsize, int apsize, int ssize, int local)
{
struct hash_pte *hptep = htab_address + slot;
unsigned long hpte_v;
unsigned long want_v;
unsigned long flags;
- int actual_psize;
local_irq_save(flags);
DBG_LOW(" invalidate(vpn=%016lx, hash: %lx)\n", vpn, slot);
- want_v = hpte_encode_avpn(vpn, psize, ssize);
+ want_v = hpte_encode_avpn(vpn, bpsize, ssize);
native_lock_hpte(hptep);
hpte_v = hptep->v;
- actual_psize = hpte_actual_psize(hptep, psize);
/*
* We need to invalidate the TLB always because hpte_remove doesn't do
* a tlb invalidate. If a hash bucket gets full, we "evict" a more/less
@@ -452,23 +395,120 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long vpn,
* (hpte_remove) because we assume the old translation is still
* technically "valid".
*/
- if (actual_psize < 0) {
- actual_psize = psize;
- native_unlock_hpte(hptep);
- goto err_out;
- }
- if (!HPTE_V_COMPARE(hpte_v, want_v))
+ if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
native_unlock_hpte(hptep);
else
/* Invalidate the hpte. NOTE: this also unlocks it */
hptep->v = 0;
-err_out:
/* Invalidate the TLB */
- tlbie(vpn, psize, actual_psize, ssize, local);
+ tlbie(vpn, bpsize, apsize, ssize, local);
+
+ local_irq_restore(flags);
+}
+
+static void native_hugepage_invalidate(struct mm_struct *mm,
+ unsigned char *hpte_slot_array,
+ unsigned long addr, int psize)
+{
+ int ssize = 0, i;
+ int lock_tlbie;
+ struct hash_pte *hptep;
+ int actual_psize = MMU_PAGE_16M;
+ unsigned int max_hpte_count, valid;
+ unsigned long flags, s_addr = addr;
+ unsigned long hpte_v, want_v, shift;
+ unsigned long hidx, vpn = 0, vsid, hash, slot;
+
+ shift = mmu_psize_defs[psize].shift;
+ max_hpte_count = 1U << (PMD_SHIFT - shift);
+
+ local_irq_save(flags);
+ for (i = 0; i < max_hpte_count; i++) {
+ valid = hpte_valid(hpte_slot_array, i);
+ if (!valid)
+ continue;
+ hidx = hpte_hash_index(hpte_slot_array, i);
+
+ /* get the vpn */
+ addr = s_addr + (i * (1ul << shift));
+ if (!is_kernel_addr(addr)) {
+ ssize = user_segment_size(addr);
+ vsid = get_vsid(mm->context.id, addr, ssize);
+ WARN_ON(vsid == 0);
+ } else {
+ vsid = get_kernel_vsid(addr, mmu_kernel_ssize);
+ ssize = mmu_kernel_ssize;
+ }
+
+ vpn = hpt_vpn(addr, vsid, ssize);
+ hash = hpt_hash(vpn, shift, ssize);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+
+ hptep = htab_address + slot;
+ want_v = hpte_encode_avpn(vpn, psize, ssize);
+ native_lock_hpte(hptep);
+ hpte_v = hptep->v;
+
+ /* Even if we miss, we need to invalidate the TLB */
+ if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID))
+ native_unlock_hpte(hptep);
+ else
+ /* Invalidate the hpte. NOTE: this also unlocks it */
+ hptep->v = 0;
+ }
+ /*
+ * Since this is a hugepage, we just need a single tlbie.
+ * use the last vpn.
+ */
+ lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
+ if (lock_tlbie)
+ raw_spin_lock(&native_tlbie_lock);
+
+ asm volatile("ptesync":::"memory");
+ __tlbie(vpn, psize, actual_psize, ssize);
+ asm volatile("eieio; tlbsync; ptesync":::"memory");
+
+ if (lock_tlbie)
+ raw_spin_unlock(&native_tlbie_lock);
+
local_irq_restore(flags);
}
+static inline int __hpte_actual_psize(unsigned int lp, int psize)
+{
+ int i, shift;
+ unsigned int mask;
+
+ /* start from 1 ignoring MMU_PAGE_4K */
+ for (i = 1; i < MMU_PAGE_COUNT; i++) {
+
+ /* invalid penc */
+ if (mmu_psize_defs[psize].penc[i] == -1)
+ continue;
+ /*
+ * encoding bits per actual page size
+ * PTE LP actual page size
+ * rrrr rrrz >=8KB
+ * rrrr rrzz >=16KB
+ * rrrr rzzz >=32KB
+ * rrrr zzzz >=64KB
+ * .......
+ */
+ shift = mmu_psize_defs[i].shift - LP_SHIFT;
+ if (shift > LP_BITS)
+ shift = LP_BITS;
+ mask = (1 << shift) - 1;
+ if ((lp & mask) == mmu_psize_defs[psize].penc[i])
+ return i;
+ }
+ return -1;
+}
+
static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
int *psize, int *apsize, int *ssize, unsigned long *vpn)
{
@@ -672,4 +712,5 @@ void __init hpte_init_native(void)
ppc_md.hpte_remove = native_hpte_remove;
ppc_md.hpte_clear_all = native_hpte_clear;
ppc_md.flush_hash_range = native_flush_hash_range;
+ ppc_md.hugepage_invalidate = native_hugepage_invalidate;
}
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index e303a6d74e3a..6ecc38bd5b24 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -807,7 +807,7 @@ void __init early_init_mmu(void)
}
#ifdef CONFIG_SMP
-void __cpuinit early_init_mmu_secondary(void)
+void early_init_mmu_secondary(void)
{
/* Initialize hash table for that CPU */
if (!firmware_has_feature(FW_FEATURE_LPAR))
@@ -1050,13 +1050,26 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
goto bail;
}
-#ifdef CONFIG_HUGETLB_PAGE
if (hugeshift) {
- rc = __hash_page_huge(ea, access, vsid, ptep, trap, local,
- ssize, hugeshift, psize);
+ if (pmd_trans_huge(*(pmd_t *)ptep))
+ rc = __hash_page_thp(ea, access, vsid, (pmd_t *)ptep,
+ trap, local, ssize, psize);
+#ifdef CONFIG_HUGETLB_PAGE
+ else
+ rc = __hash_page_huge(ea, access, vsid, ptep, trap,
+ local, ssize, hugeshift, psize);
+#else
+ else {
+ /*
+ * if we have hugeshift, and is not transhuge with
+ * hugetlb disabled, something is really wrong.
+ */
+ rc = 1;
+ WARN_ON(1);
+ }
+#endif
goto bail;
}
-#endif /* CONFIG_HUGETLB_PAGE */
#ifndef CONFIG_PPC_64K_PAGES
DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep));
@@ -1145,6 +1158,7 @@ EXPORT_SYMBOL_GPL(hash_page);
void hash_preload(struct mm_struct *mm, unsigned long ea,
unsigned long access, unsigned long trap)
{
+ int hugepage_shift;
unsigned long vsid;
pgd_t *pgdir;
pte_t *ptep;
@@ -1166,10 +1180,27 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
pgdir = mm->pgd;
if (pgdir == NULL)
return;
- ptep = find_linux_pte(pgdir, ea);
- if (!ptep)
+
+ /* Get VSID */
+ ssize = user_segment_size(ea);
+ vsid = get_vsid(mm->context.id, ea, ssize);
+ if (!vsid)
return;
+ /*
+ * Hash doesn't like irqs. Walking linux page table with irq disabled
+ * saves us from holding multiple locks.
+ */
+ local_irq_save(flags);
+
+ /*
+ * THP pages use update_mmu_cache_pmd. We don't do
+ * hash preload there. Hence can ignore THP here
+ */
+ ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugepage_shift);
+ if (!ptep)
+ goto out_exit;
+ WARN_ON(hugepage_shift);
#ifdef CONFIG_PPC_64K_PAGES
/* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
* a 64K kernel), then we don't preload, hash_page() will take
@@ -1178,18 +1209,9 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
* page size demotion here
*/
if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE))
- return;
+ goto out_exit;
#endif /* CONFIG_PPC_64K_PAGES */
- /* Get VSID */
- ssize = user_segment_size(ea);
- vsid = get_vsid(mm->context.id, ea, ssize);
- if (!vsid)
- return;
-
- /* Hash doesn't like irqs */
- local_irq_save(flags);
-
/* Is that local to this CPU ? */
if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
local = 1;
@@ -1211,7 +1233,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
mm->context.user_psize,
mm->context.user_psize,
pte_val(*ptep));
-
+out_exit:
local_irq_restore(flags);
}
@@ -1232,7 +1254,11 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
slot += hidx & _PTEIDX_GROUP_IX;
DBG_LOW(" sub %ld: hash=%lx, hidx=%lx\n", index, slot, hidx);
- ppc_md.hpte_invalidate(slot, vpn, psize, ssize, local);
+ /*
+ * We use same base page size and actual psize, because we don't
+ * use these functions for hugepage
+ */
+ ppc_md.hpte_invalidate(slot, vpn, psize, psize, ssize, local);
} pte_iterate_hashed_end();
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
@@ -1365,7 +1391,8 @@ static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi)
hash = ~hash;
slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
slot += hidx & _PTEIDX_GROUP_IX;
- ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_kernel_ssize, 0);
+ ppc_md.hpte_invalidate(slot, vpn, mmu_linear_psize, mmu_linear_psize,
+ mmu_kernel_ssize, 0);
}
void kernel_map_pages(struct page *page, int numpages, int enable)
diff --git a/arch/powerpc/mm/hugepage-hash64.c b/arch/powerpc/mm/hugepage-hash64.c
new file mode 100644
index 000000000000..34de9e0cdc34
--- /dev/null
+++ b/arch/powerpc/mm/hugepage-hash64.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright IBM Corporation, 2013
+ * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/*
+ * PPC64 THP Support for hash based MMUs
+ */
+#include <linux/mm.h>
+#include <asm/machdep.h>
+
+int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
+ pmd_t *pmdp, unsigned long trap, int local, int ssize,
+ unsigned int psize)
+{
+ unsigned int index, valid;
+ unsigned char *hpte_slot_array;
+ unsigned long rflags, pa, hidx;
+ unsigned long old_pmd, new_pmd;
+ int ret, lpsize = MMU_PAGE_16M;
+ unsigned long vpn, hash, shift, slot;
+
+ /*
+ * atomically mark the linux large page PMD busy and dirty
+ */
+ do {
+ old_pmd = pmd_val(*pmdp);
+ /* If PMD busy, retry the access */
+ if (unlikely(old_pmd & _PAGE_BUSY))
+ return 0;
+ /* If PMD is trans splitting retry the access */
+ if (unlikely(old_pmd & _PAGE_SPLITTING))
+ return 0;
+ /* If PMD permissions don't match, take page fault */
+ if (unlikely(access & ~old_pmd))
+ return 1;
+ /*
+ * Try to lock the PTE, add ACCESSED and DIRTY if it was
+ * a write access
+ */
+ new_pmd = old_pmd | _PAGE_BUSY | _PAGE_ACCESSED;
+ if (access & _PAGE_RW)
+ new_pmd |= _PAGE_DIRTY;
+ } while (old_pmd != __cmpxchg_u64((unsigned long *)pmdp,
+ old_pmd, new_pmd));
+ /*
+ * PP bits. _PAGE_USER is already PP bit 0x2, so we only
+ * need to add in 0x1 if it's a read-only user page
+ */
+ rflags = new_pmd & _PAGE_USER;
+ if ((new_pmd & _PAGE_USER) && !((new_pmd & _PAGE_RW) &&
+ (new_pmd & _PAGE_DIRTY)))
+ rflags |= 0x1;
+ /*
+ * _PAGE_EXEC -> HW_NO_EXEC since it's inverted
+ */
+ rflags |= ((new_pmd & _PAGE_EXEC) ? 0 : HPTE_R_N);
+
+#if 0
+ if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) {
+
+ /*
+ * No CPU has hugepages but lacks no execute, so we
+ * don't need to worry about that case
+ */
+ rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap);
+ }
+#endif
+ /*
+ * Find the slot index details for this ea, using base page size.
+ */
+ shift = mmu_psize_defs[psize].shift;
+ index = (ea & ~HPAGE_PMD_MASK) >> shift;
+ BUG_ON(index >= 4096);
+
+ vpn = hpt_vpn(ea, vsid, ssize);
+ hash = hpt_hash(vpn, shift, ssize);
+ hpte_slot_array = get_hpte_slot_array(pmdp);
+
+ valid = hpte_valid(hpte_slot_array, index);
+ if (valid) {
+ /* update the hpte bits */
+ hidx = hpte_hash_index(hpte_slot_array, index);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+
+ ret = ppc_md.hpte_updatepp(slot, rflags, vpn,
+ psize, lpsize, ssize, local);
+ /*
+ * We failed to update, try to insert a new entry.
+ */
+ if (ret == -1) {
+ /*
+ * large pte is marked busy, so we can be sure
+ * nobody is looking at hpte_slot_array. hence we can
+ * safely update this here.
+ */
+ valid = 0;
+ new_pmd &= ~_PAGE_HPTEFLAGS;
+ hpte_slot_array[index] = 0;
+ } else
+ /* clear the busy bits and set the hash pte bits */
+ new_pmd = (new_pmd & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE;
+ }
+
+ if (!valid) {
+ unsigned long hpte_group;
+
+ /* insert new entry */
+ pa = pmd_pfn(__pmd(old_pmd)) << PAGE_SHIFT;
+repeat:
+ hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
+
+ /* clear the busy bits and set the hash pte bits */
+ new_pmd = (new_pmd & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE;
+
+ /* Add in WIMG bits */
+ rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
+ _PAGE_COHERENT | _PAGE_GUARDED));
+
+ /* Insert into the hash table, primary slot */
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
+ psize, lpsize, ssize);
+ /*
+ * Primary is full, try the secondary
+ */
+ if (unlikely(slot == -1)) {
+ hpte_group = ((~hash & htab_hash_mask) *
+ HPTES_PER_GROUP) & ~0x7UL;
+ slot = ppc_md.hpte_insert(hpte_group, vpn, pa,
+ rflags, HPTE_V_SECONDARY,
+ psize, lpsize, ssize);
+ if (slot == -1) {
+ if (mftb() & 0x1)
+ hpte_group = ((hash & htab_hash_mask) *
+ HPTES_PER_GROUP) & ~0x7UL;
+
+ ppc_md.hpte_remove(hpte_group);
+ goto repeat;
+ }
+ }
+ /*
+ * Hypervisor failure. Restore old pmd and return -1
+ * similar to __hash_page_*
+ */
+ if (unlikely(slot == -2)) {
+ *pmdp = __pmd(old_pmd);
+ hash_failure_debug(ea, access, vsid, trap, ssize,
+ psize, lpsize, old_pmd);
+ return -1;
+ }
+ /*
+ * large pte is marked busy, so we can be sure
+ * nobody is looking at hpte_slot_array. hence we can
+ * safely update this here.
+ */
+ mark_hpte_slot_valid(hpte_slot_array, index, slot);
+ }
+ /*
+ * No need to use ldarx/stdcx here
+ */
+ *pmdp = __pmd(new_pmd & ~_PAGE_BUSY);
+ return 0;
+}
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c
index 0f1d94a1fb82..0b7fb6761015 100644
--- a/arch/powerpc/mm/hugetlbpage-hash64.c
+++ b/arch/powerpc/mm/hugetlbpage-hash64.c
@@ -81,7 +81,7 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
slot += (old_pte & _PAGE_F_GIX) >> 12;
if (ppc_md.hpte_updatepp(slot, rflags, vpn, mmu_psize,
- ssize, local) == -1)
+ mmu_psize, ssize, local) == -1)
old_pte &= ~_PAGE_HPTEFLAGS;
}
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 77fdd2cef33b..834ca8eb38f2 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -21,6 +21,9 @@
#include <asm/pgalloc.h>
#include <asm/tlb.h>
#include <asm/setup.h>
+#include <asm/hugetlb.h>
+
+#ifdef CONFIG_HUGETLB_PAGE
#define PAGE_SHIFT_64K 16
#define PAGE_SHIFT_16M 24
@@ -100,68 +103,9 @@ int pgd_huge(pgd_t pgd)
}
#endif
-/*
- * We have 4 cases for pgds and pmds:
- * (1) invalid (all zeroes)
- * (2) pointer to next table, as normal; bottom 6 bits == 0
- * (3) leaf pte for huge page, bottom two bits != 00
- * (4) hugepd pointer, bottom two bits == 00, next 4 bits indicate size of table
- */
-pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift)
-{
- pgd_t *pg;
- pud_t *pu;
- pmd_t *pm;
- pte_t *ret_pte;
- hugepd_t *hpdp = NULL;
- unsigned pdshift = PGDIR_SHIFT;
-
- if (shift)
- *shift = 0;
-
- pg = pgdir + pgd_index(ea);
-
- if (pgd_huge(*pg)) {
- ret_pte = (pte_t *) pg;
- goto out;
- } else if (is_hugepd(pg))
- hpdp = (hugepd_t *)pg;
- else if (!pgd_none(*pg)) {
- pdshift = PUD_SHIFT;
- pu = pud_offset(pg, ea);
-
- if (pud_huge(*pu)) {
- ret_pte = (pte_t *) pu;
- goto out;
- } else if (is_hugepd(pu))
- hpdp = (hugepd_t *)pu;
- else if (!pud_none(*pu)) {
- pdshift = PMD_SHIFT;
- pm = pmd_offset(pu, ea);
-
- if (pmd_huge(*pm)) {
- ret_pte = (pte_t *) pm;
- goto out;
- } else if (is_hugepd(pm))
- hpdp = (hugepd_t *)pm;
- else if (!pmd_none(*pm))
- return pte_offset_kernel(pm, ea);
- }
- }
- if (!hpdp)
- return NULL;
-
- ret_pte = hugepte_offset(hpdp, ea, pdshift);
- pdshift = hugepd_shift(*hpdp);
-out:
- if (shift)
- *shift = pdshift;
- return ret_pte;
-}
-EXPORT_SYMBOL_GPL(find_linux_pte_or_hugepte);
-
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
+ /* Only called for hugetlbfs pages, hence can ignore THP */
return find_linux_pte_or_hugepte(mm->pgd, addr, NULL);
}
@@ -357,7 +301,7 @@ void add_gpage(u64 addr, u64 page_size, unsigned long number_of_pages)
int alloc_bootmem_huge_page(struct hstate *hstate)
{
struct huge_bootmem_page *m;
- int idx = shift_to_mmu_psize(hstate->order + PAGE_SHIFT);
+ int idx = shift_to_mmu_psize(huge_page_shift(hstate));
int nr_gpages = gpage_freearray[idx].nr_gpages;
if (nr_gpages == 0)
@@ -736,11 +680,14 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
struct page *page;
unsigned shift;
unsigned long mask;
-
+ /*
+ * Transparent hugepages are handled by generic code. We can skip them
+ * here.
+ */
ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
/* Verify it is a huge page else bail. */
- if (!ptep || !shift)
+ if (!ptep || !shift || pmd_trans_huge(*(pmd_t *)ptep))
return ERR_PTR(-EINVAL);
mask = (1UL << shift) - 1;
@@ -759,69 +706,6 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
return NULL;
}
-int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
- unsigned long end, int write, struct page **pages, int *nr)
-{
- unsigned long mask;
- unsigned long pte_end;
- struct page *head, *page, *tail;
- pte_t pte;
- int refs;
-
- pte_end = (addr + sz) & ~(sz-1);
- if (pte_end < end)
- end = pte_end;
-
- pte = *ptep;
- mask = _PAGE_PRESENT | _PAGE_USER;
- if (write)
- mask |= _PAGE_RW;
-
- if ((pte_val(pte) & mask) != mask)
- return 0;
-
- /* hugepages are never "special" */
- VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
-
- refs = 0;
- head = pte_page(pte);
-
- page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
- tail = page;
- do {
- VM_BUG_ON(compound_head(page) != head);
- pages[*nr] = page;
- (*nr)++;
- page++;
- refs++;
- } while (addr += PAGE_SIZE, addr != end);
-
- if (!page_cache_add_speculative(head, refs)) {
- *nr -= refs;
- return 0;
- }
-
- if (unlikely(pte_val(pte) != pte_val(*ptep))) {
- /* Could be optimized better */
- *nr -= refs;
- while (refs--)
- put_page(head);
- return 0;
- }
-
- /*
- * Any tail page need their mapcount reference taken before we
- * return.
- */
- while (refs--) {
- if (PageTail(tail))
- get_huge_page_tail(tail);
- tail++;
- }
-
- return 1;
-}
-
static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end,
unsigned long sz)
{
@@ -1038,3 +922,168 @@ void flush_dcache_icache_hugepage(struct page *page)
}
}
}
+
+#endif /* CONFIG_HUGETLB_PAGE */
+
+/*
+ * We have 4 cases for pgds and pmds:
+ * (1) invalid (all zeroes)
+ * (2) pointer to next table, as normal; bottom 6 bits == 0
+ * (3) leaf pte for huge page, bottom two bits != 00
+ * (4) hugepd pointer, bottom two bits == 00, next 4 bits indicate size of table
+ *
+ * So long as we atomically load page table pointers we are safe against teardown,
+ * we can follow the address down to the the page and take a ref on it.
+ */
+
+pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift)
+{
+ pgd_t pgd, *pgdp;
+ pud_t pud, *pudp;
+ pmd_t pmd, *pmdp;
+ pte_t *ret_pte;
+ hugepd_t *hpdp = NULL;
+ unsigned pdshift = PGDIR_SHIFT;
+
+ if (shift)
+ *shift = 0;
+
+ pgdp = pgdir + pgd_index(ea);
+ pgd = ACCESS_ONCE(*pgdp);
+ /*
+ * Always operate on the local stack value. This make sure the
+ * value don't get updated by a parallel THP split/collapse,
+ * page fault or a page unmap. The return pte_t * is still not
+ * stable. So should be checked there for above conditions.
+ */
+ if (pgd_none(pgd))
+ return NULL;
+ else if (pgd_huge(pgd)) {
+ ret_pte = (pte_t *) pgdp;
+ goto out;
+ } else if (is_hugepd(&pgd))
+ hpdp = (hugepd_t *)&pgd;
+ else {
+ /*
+ * Even if we end up with an unmap, the pgtable will not
+ * be freed, because we do an rcu free and here we are
+ * irq disabled
+ */
+ pdshift = PUD_SHIFT;
+ pudp = pud_offset(&pgd, ea);
+ pud = ACCESS_ONCE(*pudp);
+
+ if (pud_none(pud))
+ return NULL;
+ else if (pud_huge(pud)) {
+ ret_pte = (pte_t *) pudp;
+ goto out;
+ } else if (is_hugepd(&pud))
+ hpdp = (hugepd_t *)&pud;
+ else {
+ pdshift = PMD_SHIFT;
+ pmdp = pmd_offset(&pud, ea);
+ pmd = ACCESS_ONCE(*pmdp);
+ /*
+ * A hugepage collapse is captured by pmd_none, because
+ * it mark the pmd none and do a hpte invalidate.
+ *
+ * A hugepage split is captured by pmd_trans_splitting
+ * because we mark the pmd trans splitting and do a
+ * hpte invalidate
+ *
+ */
+ if (pmd_none(pmd) || pmd_trans_splitting(pmd))
+ return NULL;
+
+ if (pmd_huge(pmd) || pmd_large(pmd)) {
+ ret_pte = (pte_t *) pmdp;
+ goto out;
+ } else if (is_hugepd(&pmd))
+ hpdp = (hugepd_t *)&pmd;
+ else
+ return pte_offset_kernel(&pmd, ea);
+ }
+ }
+ if (!hpdp)
+ return NULL;
+
+ ret_pte = hugepte_offset(hpdp, ea, pdshift);
+ pdshift = hugepd_shift(*hpdp);
+out:
+ if (shift)
+ *shift = pdshift;
+ return ret_pte;
+}
+EXPORT_SYMBOL_GPL(find_linux_pte_or_hugepte);
+
+int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
+ unsigned long end, int write, struct page **pages, int *nr)
+{
+ unsigned long mask;
+ unsigned long pte_end;
+ struct page *head, *page, *tail;
+ pte_t pte;
+ int refs;
+
+ pte_end = (addr + sz) & ~(sz-1);
+ if (pte_end < end)
+ end = pte_end;
+
+ pte = ACCESS_ONCE(*ptep);
+ mask = _PAGE_PRESENT | _PAGE_USER;
+ if (write)
+ mask |= _PAGE_RW;
+
+ if ((pte_val(pte) & mask) != mask)
+ return 0;
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ /*
+ * check for splitting here
+ */
+ if (pmd_trans_splitting(pte_pmd(pte)))
+ return 0;
+#endif
+
+ /* hugepages are never "special" */
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+
+ refs = 0;
+ head = pte_page(pte);
+
+ page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
+ tail = page;
+ do {
+ VM_BUG_ON(compound_head(page) != head);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
+ }
+
+ if (unlikely(pte_val(pte) != pte_val(*ptep))) {
+ /* Could be optimized better */
+ *nr -= refs;
+ while (refs--)
+ put_page(head);
+ return 0;
+ }
+
+ /*
+ * Any tail page need their mapcount reference taken before we
+ * return.
+ */
+ while (refs--) {
+ if (PageTail(tail))
+ get_huge_page_tail(tail);
+ tail++;
+ }
+
+ return 1;
+}
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index a90b9c458990..d0cd9e4c6837 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -88,7 +88,11 @@ static void pgd_ctor(void *addr)
static void pmd_ctor(void *addr)
{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ memset(addr, 0, PMD_TABLE_SIZE * 2);
+#else
memset(addr, 0, PMD_TABLE_SIZE);
+#endif
}
struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE];
@@ -137,10 +141,9 @@ void pgtable_cache_add(unsigned shift, void (*ctor)(void *))
void pgtable_cache_init(void)
{
pgtable_cache_add(PGD_INDEX_SIZE, pgd_ctor);
- pgtable_cache_add(PMD_INDEX_SIZE, pmd_ctor);
- if (!PGT_CACHE(PGD_INDEX_SIZE) || !PGT_CACHE(PMD_INDEX_SIZE))
+ pgtable_cache_add(PMD_CACHE_INDEX, pmd_ctor);
+ if (!PGT_CACHE(PGD_INDEX_SIZE) || !PGT_CACHE(PMD_CACHE_INDEX))
panic("Couldn't allocate pgtable caches");
-
/* In all current configs, when the PUD index exists it's the
* same size as either the pgd or pmd index. Verify that the
* initialization above has also created a PUD cache. This
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 0988a26e0413..7f4bea162026 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -299,47 +299,13 @@ void __init paging_init(void)
void __init mem_init(void)
{
-#ifdef CONFIG_NEED_MULTIPLE_NODES
- int nid;
-#endif
- pg_data_t *pgdat;
- unsigned long i;
- struct page *page;
- unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
-
#ifdef CONFIG_SWIOTLB
swiotlb_init(0);
#endif
- num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-
-#ifdef CONFIG_NEED_MULTIPLE_NODES
- for_each_online_node(nid) {
- if (NODE_DATA(nid)->node_spanned_pages != 0) {
- printk("freeing bootmem node %d\n", nid);
- totalram_pages +=
- free_all_bootmem_node(NODE_DATA(nid));
- }
- }
-#else
- max_mapnr = max_pfn;
- totalram_pages += free_all_bootmem();
-#endif
- for_each_online_pgdat(pgdat) {
- for (i = 0; i < pgdat->node_spanned_pages; i++) {
- if (!pfn_valid(pgdat->node_start_pfn + i))
- continue;
- page = pgdat_page_nr(pgdat, i);
- if (PageReserved(page))
- reservedpages++;
- }
- }
-
- codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
- datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
- initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
- bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
+ set_max_mapnr(max_pfn);
+ free_all_bootmem();
#ifdef CONFIG_HIGHMEM
{
@@ -349,13 +315,9 @@ void __init mem_init(void)
for (pfn = highmem_mapnr; pfn < max_mapnr; ++pfn) {
phys_addr_t paddr = (phys_addr_t)pfn << PAGE_SHIFT;
struct page *page = pfn_to_page(pfn);
- if (memblock_is_reserved(paddr))
- continue;
- free_highmem_page(page);
- reservedpages--;
+ if (!memblock_is_reserved(paddr))
+ free_highmem_page(page);
}
- printk(KERN_DEBUG "High memory: %luk\n",
- totalhigh_pages << (PAGE_SHIFT-10));
}
#endif /* CONFIG_HIGHMEM */
@@ -368,16 +330,7 @@ void __init mem_init(void)
(mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) - 1;
#endif
- printk(KERN_INFO "Memory: %luk/%luk available (%luk kernel code, "
- "%luk reserved, %luk data, %luk bss, %luk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- bsssize >> 10,
- initsize >> 10);
-
+ mem_init_print_info(NULL);
#ifdef CONFIG_PPC32
pr_info("Kernel virtual memory layout:\n");
pr_info(" * 0x%08lx..0x%08lx : fixmap\n", FIXADDR_START, FIXADDR_TOP);
@@ -407,7 +360,7 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
@@ -508,6 +461,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
pte_t *ptep)
{
#ifdef CONFIG_PPC_STD_MMU
+ /*
+ * We don't need to worry about _PAGE_PRESENT here because we are
+ * called with either mm->page_table_lock held or ptl lock held
+ */
unsigned long access = 0, trap;
/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
diff --git a/arch/powerpc/mm/mmap_64.c b/arch/powerpc/mm/mmap.c
index 67a42ed0d2fc..cb8bdbe4972f 100644
--- a/arch/powerpc/mm/mmap_64.c
+++ b/arch/powerpc/mm/mmap.c
@@ -92,10 +92,8 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base();
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index e779642c25e5..af3d78e19302 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -112,8 +112,10 @@ static unsigned int steal_context_smp(unsigned int id)
*/
for_each_cpu(cpu, mm_cpumask(mm)) {
for (i = cpu_first_thread_sibling(cpu);
- i <= cpu_last_thread_sibling(cpu); i++)
- __set_bit(id, stale_map[i]);
+ i <= cpu_last_thread_sibling(cpu); i++) {
+ if (stale_map[i])
+ __set_bit(id, stale_map[i]);
+ }
cpu = i - 1;
}
return id;
@@ -272,7 +274,8 @@ void switch_mmu_context(struct mm_struct *prev, struct mm_struct *next)
/* XXX This clear should ultimately be part of local_flush_tlb_mm */
for (i = cpu_first_thread_sibling(cpu);
i <= cpu_last_thread_sibling(cpu); i++) {
- __clear_bit(id, stale_map[i]);
+ if (stale_map[i])
+ __clear_bit(id, stale_map[i]);
}
}
@@ -329,8 +332,8 @@ void destroy_context(struct mm_struct *mm)
#ifdef CONFIG_SMP
-static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
+static int mmu_context_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned int)(long)hcpu;
@@ -363,7 +366,7 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata mmu_context_cpu_nb = {
+static struct notifier_block mmu_context_cpu_nb = {
.notifier_call = mmu_context_cpu_notify,
};
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 88c0425dc0a8..08397217e8ac 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -516,7 +516,7 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
* Figure out to which domain a cpu belongs and stick it there.
* Return the id of the domain used.
*/
-static int __cpuinit numa_setup_cpu(unsigned long lcpu)
+static int numa_setup_cpu(unsigned long lcpu)
{
int nid = 0;
struct device_node *cpu = of_get_cpu_node(lcpu, NULL);
@@ -538,8 +538,7 @@ out:
return nid;
}
-static int __cpuinit cpu_numa_callback(struct notifier_block *nfb,
- unsigned long action,
+static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action,
void *hcpu)
{
unsigned long lcpu = (unsigned long)hcpu;
@@ -919,7 +918,7 @@ static void __init *careful_zallocation(int nid, unsigned long size,
return ret;
}
-static struct notifier_block __cpuinitdata ppc64_numa_nb = {
+static struct notifier_block ppc64_numa_nb = {
.notifier_call = cpu_numa_callback,
.priority = 1 /* Must run before sched domains notifier. */
};
@@ -1433,11 +1432,9 @@ static int update_cpu_topology(void *data)
if (cpu != update->cpu)
continue;
- unregister_cpu_under_node(update->cpu, update->old_nid);
unmap_cpu_from_node(update->cpu);
map_cpu_to_node(update->cpu, update->new_nid);
vdso_getcpu_init();
- register_cpu_under_node(update->cpu, update->new_nid);
}
return 0;
@@ -1485,6 +1482,9 @@ int arch_update_cpu_topology(void)
stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
for (ud = &updates[0]; ud; ud = ud->next) {
+ unregister_cpu_under_node(ud->cpu, ud->old_nid);
+ register_cpu_under_node(ud->cpu, ud->new_nid);
+
dev = get_cpu_device(ud->cpu);
if (dev)
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 214130a4edc6..edda589795c3 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -235,6 +235,14 @@ void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
pud = pud_offset(pgd, addr);
BUG_ON(pud_none(*pud));
pmd = pmd_offset(pud, addr);
+ /*
+ * khugepaged to collapse normal pages to hugepage, first set
+ * pmd to none to force page fault/gup to take mmap_sem. After
+ * pmd is set to none, we do a pte_clear which does this assertion
+ * so if we find pmd none, return.
+ */
+ if (pmd_none(*pmd))
+ return;
BUG_ON(!pmd_present(*pmd));
assert_spin_locked(pte_lockptr(mm, pmd));
}
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index a854096e1023..536eec72c0f7 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -338,6 +338,19 @@ EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(__iounmap);
EXPORT_SYMBOL(__iounmap_at);
+/*
+ * For hugepage we have pfn in the pmd, we use PTE_RPN_SHIFT bits for flags
+ * For PTE page, we have a PTE_FRAG_SIZE (4K) aligned virtual address.
+ */
+struct page *pmd_page(pmd_t pmd)
+{
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ if (pmd_trans_huge(pmd))
+ return pfn_to_page(pmd_pfn(pmd));
+#endif
+ return virt_to_page(pmd_page_vaddr(pmd));
+}
+
#ifdef CONFIG_PPC_64K_PAGES
static pte_t *get_from_cache(struct mm_struct *mm)
{
@@ -455,3 +468,404 @@ void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
}
#endif
#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+
+/*
+ * This is called when relaxing access to a hugepage. It's also called in the page
+ * fault path when we don't hit any of the major fault cases, ie, a minor
+ * update of _PAGE_ACCESSED, _PAGE_DIRTY, etc... The generic code will have
+ * handled those two for us, we additionally deal with missing execute
+ * permission here on some processors
+ */
+int pmdp_set_access_flags(struct vm_area_struct *vma, unsigned long address,
+ pmd_t *pmdp, pmd_t entry, int dirty)
+{
+ int changed;
+#ifdef CONFIG_DEBUG_VM
+ WARN_ON(!pmd_trans_huge(*pmdp));
+ assert_spin_locked(&vma->vm_mm->page_table_lock);
+#endif
+ changed = !pmd_same(*(pmdp), entry);
+ if (changed) {
+ __ptep_set_access_flags(pmdp_ptep(pmdp), pmd_pte(entry));
+ /*
+ * Since we are not supporting SW TLB systems, we don't
+ * have any thing similar to flush_tlb_page_nohash()
+ */
+ }
+ return changed;
+}
+
+unsigned long pmd_hugepage_update(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, unsigned long clr)
+{
+
+ unsigned long old, tmp;
+
+#ifdef CONFIG_DEBUG_VM
+ WARN_ON(!pmd_trans_huge(*pmdp));
+ assert_spin_locked(&mm->page_table_lock);
+#endif
+
+#ifdef PTE_ATOMIC_UPDATES
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%3\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ andc %1,%0,%4 \n\
+ stdcx. %1,0,%3 \n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
+ : "r" (pmdp), "r" (clr), "m" (*pmdp), "i" (_PAGE_BUSY)
+ : "cc" );
+#else
+ old = pmd_val(*pmdp);
+ *pmdp = __pmd(old & ~clr);
+#endif
+ if (old & _PAGE_HASHPTE)
+ hpte_do_hugepage_flush(mm, addr, pmdp);
+ return old;
+}
+
+pmd_t pmdp_clear_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);
+ }
+ return pmd;
+}
+
+int pmdp_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp)
+{
+ return __pmdp_test_and_clear_young(vma->vm_mm, address, pmdp);
+}
+
+/*
+ * We currently remove entries from the hashtable regardless of whether
+ * the entry was young or dirty. The generic routines only flush if the
+ * entry was young or dirty which is not good enough.
+ *
+ * We should be more intelligent about this but for the moment we override
+ * these functions and force a tlb flush unconditionally
+ */
+int pmdp_clear_flush_young(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp)
+{
+ return __pmdp_test_and_clear_young(vma->vm_mm, address, pmdp);
+}
+
+/*
+ * We mark the pmd splitting and invalidate all the hpte
+ * entries for this hugepage.
+ */
+void pmdp_splitting_flush(struct vm_area_struct *vma,
+ unsigned long address, pmd_t *pmdp)
+{
+ unsigned long old, tmp;
+
+ VM_BUG_ON(address & ~HPAGE_PMD_MASK);
+
+#ifdef CONFIG_DEBUG_VM
+ WARN_ON(!pmd_trans_huge(*pmdp));
+ assert_spin_locked(&vma->vm_mm->page_table_lock);
+#endif
+
+#ifdef PTE_ATOMIC_UPDATES
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%3\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ ori %1,%0,%4 \n\
+ stdcx. %1,0,%3 \n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
+ : "r" (pmdp), "i" (_PAGE_SPLITTING), "m" (*pmdp), "i" (_PAGE_BUSY)
+ : "cc" );
+#else
+ old = pmd_val(*pmdp);
+ *pmdp = __pmd(old | _PAGE_SPLITTING);
+#endif
+ /*
+ * If we didn't had the splitting flag set, go and flush the
+ * HPTE entries.
+ */
+ if (!(old & _PAGE_SPLITTING)) {
+ /* We need to flush the hpte */
+ if (old & _PAGE_HASHPTE)
+ hpte_do_hugepage_flush(vma->vm_mm, address, pmdp);
+ }
+}
+
+/*
+ * We want to put the pgtable in pmd and use pgtable for tracking
+ * the base page size hptes
+ */
+void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable)
+{
+ pgtable_t *pgtable_slot;
+ assert_spin_locked(&mm->page_table_lock);
+ /*
+ * we store the pgtable in the second half of PMD
+ */
+ pgtable_slot = (pgtable_t *)pmdp + PTRS_PER_PMD;
+ *pgtable_slot = pgtable;
+ /*
+ * expose the deposited pgtable to other cpus.
+ * before we set the hugepage PTE at pmd level
+ * hash fault code looks at the deposted pgtable
+ * to store hash index values.
+ */
+ smp_wmb();
+}
+
+pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
+{
+ pgtable_t pgtable;
+ pgtable_t *pgtable_slot;
+
+ assert_spin_locked(&mm->page_table_lock);
+ pgtable_slot = (pgtable_t *)pmdp + PTRS_PER_PMD;
+ pgtable = *pgtable_slot;
+ /*
+ * Once we withdraw, mark the entry NULL.
+ */
+ *pgtable_slot = NULL;
+ /*
+ * We store HPTE information in the deposited PTE fragment.
+ * zero out the content on withdraw.
+ */
+ memset(pgtable, 0, PTE_FRAG_SIZE);
+ return pgtable;
+}
+
+/*
+ * set a new huge pmd. We should not be called for updating
+ * an existing pmd entry. That should go via pmd_hugepage_update.
+ */
+void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp, pmd_t pmd)
+{
+#ifdef CONFIG_DEBUG_VM
+ WARN_ON(!pmd_none(*pmdp));
+ assert_spin_locked(&mm->page_table_lock);
+ WARN_ON(!pmd_trans_huge(pmd));
+#endif
+ return set_pte_at(mm, addr, pmdp_ptep(pmdp), pmd_pte(pmd));
+}
+
+void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
+ pmd_t *pmdp)
+{
+ pmd_hugepage_update(vma->vm_mm, address, pmdp, _PAGE_PRESENT);
+}
+
+/*
+ * A linux hugepage PMD was changed and the corresponding hash table entries
+ * neesd to be flushed.
+ */
+void hpte_do_hugepage_flush(struct mm_struct *mm, unsigned long addr,
+ pmd_t *pmdp)
+{
+ int ssize, i;
+ unsigned long s_addr;
+ int max_hpte_count;
+ unsigned int psize, valid;
+ unsigned char *hpte_slot_array;
+ unsigned long hidx, vpn, vsid, hash, shift, slot;
+
+ /*
+ * Flush all the hptes mapping this hugepage
+ */
+ s_addr = addr & HPAGE_PMD_MASK;
+ hpte_slot_array = get_hpte_slot_array(pmdp);
+ /*
+ * IF we try to do a HUGE PTE update after a withdraw is done.
+ * we will find the below NULL. This happens when we do
+ * split_huge_page_pmd
+ */
+ if (!hpte_slot_array)
+ return;
+
+ /* get the base page size */
+ psize = get_slice_psize(mm, s_addr);
+
+ if (ppc_md.hugepage_invalidate)
+ return ppc_md.hugepage_invalidate(mm, hpte_slot_array,
+ s_addr, psize);
+ /*
+ * No bluk hpte removal support, invalidate each entry
+ */
+ shift = mmu_psize_defs[psize].shift;
+ max_hpte_count = HPAGE_PMD_SIZE >> shift;
+ for (i = 0; i < max_hpte_count; i++) {
+ /*
+ * 8 bits per each hpte entries
+ * 000| [ secondary group (one bit) | hidx (3 bits) | valid bit]
+ */
+ valid = hpte_valid(hpte_slot_array, i);
+ if (!valid)
+ continue;
+ hidx = hpte_hash_index(hpte_slot_array, i);
+
+ /* get the vpn */
+ addr = s_addr + (i * (1ul << shift));
+ if (!is_kernel_addr(addr)) {
+ ssize = user_segment_size(addr);
+ vsid = get_vsid(mm->context.id, addr, ssize);
+ WARN_ON(vsid == 0);
+ } else {
+ vsid = get_kernel_vsid(addr, mmu_kernel_ssize);
+ ssize = mmu_kernel_ssize;
+ }
+
+ vpn = hpt_vpn(addr, vsid, ssize);
+ hash = hpt_hash(vpn, shift, ssize);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+ ppc_md.hpte_invalidate(slot, vpn, psize,
+ MMU_PAGE_16M, ssize, 0);
+ }
+}
+
+static pmd_t pmd_set_protbits(pmd_t pmd, pgprot_t pgprot)
+{
+ pmd_val(pmd) |= pgprot_val(pgprot);
+ return pmd;
+}
+
+pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot)
+{
+ pmd_t pmd;
+ /*
+ * For a valid pte, we would have _PAGE_PRESENT or _PAGE_FILE always
+ * set. We use this to check THP page at pmd level.
+ * leaf pte for huge page, bottom two bits != 00
+ */
+ pmd_val(pmd) = pfn << PTE_RPN_SHIFT;
+ pmd_val(pmd) |= _PAGE_THP_HUGE;
+ pmd = pmd_set_protbits(pmd, pgprot);
+ return pmd;
+}
+
+pmd_t mk_pmd(struct page *page, pgprot_t pgprot)
+{
+ return pfn_pmd(page_to_pfn(page), pgprot);
+}
+
+pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
+{
+
+ pmd_val(pmd) &= _HPAGE_CHG_MASK;
+ pmd = pmd_set_protbits(pmd, newprot);
+ return pmd;
+}
+
+/*
+ * This is called at the end of handling a user page fault, when the
+ * fault has been handled by updating a HUGE PMD entry in the linux page tables.
+ * We use it to preload an HPTE into the hash table corresponding to
+ * the updated linux HUGE PMD entry.
+ */
+void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
+ pmd_t *pmd)
+{
+ return;
+}
+
+pmd_t pmdp_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pmd_t *pmdp)
+{
+ pmd_t old_pmd;
+ pgtable_t pgtable;
+ unsigned long old;
+ pgtable_t *pgtable_slot;
+
+ old = pmd_hugepage_update(mm, addr, pmdp, ~0UL);
+ old_pmd = __pmd(old);
+ /*
+ * We have pmd == none and we are holding page_table_lock.
+ * So we can safely go and clear the pgtable hash
+ * index info.
+ */
+ pgtable_slot = (pgtable_t *)pmdp + PTRS_PER_PMD;
+ pgtable = *pgtable_slot;
+ /*
+ * Let's zero out old valid and hash index details
+ * hash fault look at them.
+ */
+ memset(pgtable, 0, PTE_FRAG_SIZE);
+ return old_pmd;
+}
+
+int has_transparent_hugepage(void)
+{
+ if (!mmu_has_feature(MMU_FTR_16M_PAGE))
+ return 0;
+ /*
+ * We support THP only if PMD_SIZE is 16MB.
+ */
+ if (mmu_psize_defs[MMU_PAGE_16M].shift != PMD_SHIFT)
+ return 0;
+ /*
+ * We need to make sure that we support 16MB hugepage in a segement
+ * with base page size 64K or 4K. We only enable THP with a PAGE_SIZE
+ * of 64K.
+ */
+ /*
+ * If we have 64K HPTE, we will be using that by default
+ */
+ if (mmu_psize_defs[MMU_PAGE_64K].shift &&
+ (mmu_psize_defs[MMU_PAGE_64K].penc[MMU_PAGE_16M] == -1))
+ return 0;
+ /*
+ * Ok we only have 4K HPTE
+ */
+ if (mmu_psize_defs[MMU_PAGE_4K].penc[MMU_PAGE_16M] == -1)
+ return 0;
+
+ return 1;
+}
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
index 7c415ddde948..aa74acb0fdfc 100644
--- a/arch/powerpc/mm/subpage-prot.c
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -130,6 +130,53 @@ static void subpage_prot_clear(unsigned long addr, unsigned long len)
up_write(&mm->mmap_sem);
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static int subpage_walk_pmd_entry(pmd_t *pmd, unsigned long addr,
+ unsigned long end, struct mm_walk *walk)
+{
+ struct vm_area_struct *vma = walk->private;
+ split_huge_page_pmd(vma, addr, pmd);
+ return 0;
+}
+
+static void subpage_mark_vma_nohuge(struct mm_struct *mm, unsigned long addr,
+ unsigned long len)
+{
+ struct vm_area_struct *vma;
+ struct mm_walk subpage_proto_walk = {
+ .mm = mm,
+ .pmd_entry = subpage_walk_pmd_entry,
+ };
+
+ /*
+ * We don't try too hard, we just mark all the vma in that range
+ * VM_NOHUGEPAGE and split them.
+ */
+ vma = find_vma(mm, addr);
+ /*
+ * If the range is in unmapped range, just return
+ */
+ if (vma && ((addr + len) <= vma->vm_start))
+ return;
+
+ while (vma) {
+ if (vma->vm_start >= (addr + len))
+ break;
+ vma->vm_flags |= VM_NOHUGEPAGE;
+ subpage_proto_walk.private = vma;
+ walk_page_range(vma->vm_start, vma->vm_end,
+ &subpage_proto_walk);
+ vma = vma->vm_next;
+ }
+}
+#else
+static void subpage_mark_vma_nohuge(struct mm_struct *mm, unsigned long addr,
+ unsigned long len)
+{
+ return;
+}
+#endif
+
/*
* Copy in a subpage protection map for an address range.
* The map has 2 bits per 4k subpage, so 32 bits per 64k page.
@@ -168,6 +215,7 @@ long sys_subpage_prot(unsigned long addr, unsigned long len, u32 __user *map)
return -EFAULT;
down_write(&mm->mmap_sem);
+ subpage_mark_vma_nohuge(mm, addr, len);
for (limit = addr + len; addr < limit; addr = next) {
next = pmd_addr_end(addr, limit);
err = -ENOMEM;
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c
index 7df1c5edda87..36e44b4260eb 100644
--- a/arch/powerpc/mm/tlb_hash64.c
+++ b/arch/powerpc/mm/tlb_hash64.c
@@ -189,6 +189,7 @@ void tlb_flush(struct mmu_gather *tlb)
void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
+ int hugepage_shift;
unsigned long flags;
start = _ALIGN_DOWN(start, PAGE_SIZE);
@@ -206,7 +207,8 @@ void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
local_irq_save(flags);
arch_enter_lazy_mmu_mode();
for (; start < end; start += PAGE_SIZE) {
- pte_t *ptep = find_linux_pte(mm->pgd, start);
+ pte_t *ptep = find_linux_pte_or_hugepte(mm->pgd, start,
+ &hugepage_shift);
unsigned long pte;
if (ptep == NULL)
@@ -214,7 +216,37 @@ void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
pte = pte_val(*ptep);
if (!(pte & _PAGE_HASHPTE))
continue;
- hpte_need_flush(mm, start, ptep, pte, 0);
+ if (unlikely(hugepage_shift && pmd_trans_huge(*(pmd_t *)pte)))
+ hpte_do_hugepage_flush(mm, start, (pmd_t *)pte);
+ else
+ hpte_need_flush(mm, start, ptep, pte, 0);
+ }
+ arch_leave_lazy_mmu_mode();
+ local_irq_restore(flags);
+}
+
+void flush_tlb_pmd_range(struct mm_struct *mm, pmd_t *pmd, unsigned long addr)
+{
+ pte_t *pte;
+ pte_t *start_pte;
+ unsigned long flags;
+
+ addr = _ALIGN_DOWN(addr, PMD_SIZE);
+ /* Note: Normally, we should only ever use a batch within a
+ * PTE locked section. This violates the rule, but will work
+ * since we don't actually modify the PTEs, we just flush the
+ * hash while leaving the PTEs intact (including their reference
+ * to being hashed). This is not the most performance oriented
+ * way to do things but is fine for our needs here.
+ */
+ local_irq_save(flags);
+ arch_enter_lazy_mmu_mode();
+ start_pte = pte_offset_map(pmd, addr);
+ for (pte = start_pte; pte < start_pte + PTRS_PER_PTE; pte++) {
+ unsigned long pteval = pte_val(*pte);
+ if (pteval & _PAGE_HASHPTE)
+ hpte_need_flush(mm, addr, pte, pteval, 0);
+ addr += PAGE_SIZE;
}
arch_leave_lazy_mmu_mode();
local_irq_restore(flags);
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index 6888cad5103d..41cd68dee681 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -648,7 +648,7 @@ void __init early_init_mmu(void)
__early_init_mmu(1);
}
-void __cpuinit early_init_mmu_secondary(void)
+void early_init_mmu_secondary(void)
{
__early_init_mmu(0);
}
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index c427ae36374a..bf56e33f8257 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -650,8 +650,7 @@ void bpf_jit_compile(struct sk_filter *fp)
proglen = cgctx.idx * 4;
alloclen = proglen + FUNCTION_DESCR_SIZE;
- image = module_alloc(max_t(unsigned int, alloclen,
- sizeof(struct work_struct)));
+ image = module_alloc(alloclen);
if (!image)
goto out;
@@ -688,20 +687,8 @@ out:
return;
}
-static void jit_free_defer(struct work_struct *arg)
-{
- module_free(NULL, arg);
-}
-
-/* run from softirq, we must use a work_struct to call
- * module_free() from process context
- */
void bpf_jit_free(struct sk_filter *fp)
{
- if (fp->bpf_func != sk_run_filter) {
- struct work_struct *work = (struct work_struct *)fp->bpf_func;
-
- INIT_WORK(work, jit_free_defer);
- schedule_work(work);
- }
+ if (fp->bpf_func != sk_run_filter)
+ module_free(NULL, fp->bpf_func);
}
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 29c6482890c8..a3985aee77fe 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -75,6 +75,11 @@ static unsigned int freeze_events_kernel = MMCR0_FCS;
#define MMCR0_FCHV 0
#define MMCR0_PMCjCE MMCR0_PMCnCE
+#define MMCR0_FC56 0
+#define MMCR0_PMAO 0
+#define MMCR0_EBE 0
+#define MMCR0_PMCC 0
+#define MMCR0_PMCC_U6 0
#define SPRN_MMCRA SPRN_MMCR2
#define MMCRA_SAMPLE_ENABLE 0
@@ -102,6 +107,15 @@ static inline int siar_valid(struct pt_regs *regs)
return 1;
}
+static bool is_ebb_event(struct perf_event *event) { return false; }
+static int ebb_event_check(struct perf_event *event) { return 0; }
+static void ebb_event_add(struct perf_event *event) { }
+static void ebb_switch_out(unsigned long mmcr0) { }
+static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
+{
+ return mmcr0;
+}
+
static inline void power_pmu_bhrb_enable(struct perf_event *event) {}
static inline void power_pmu_bhrb_disable(struct perf_event *event) {}
void power_pmu_flush_branch_stack(void) {}
@@ -462,6 +476,89 @@ void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
return;
}
+static bool is_ebb_event(struct perf_event *event)
+{
+ /*
+ * This could be a per-PMU callback, but we'd rather avoid the cost. We
+ * check that the PMU supports EBB, meaning those that don't can still
+ * use bit 63 of the event code for something else if they wish.
+ */
+ return (ppmu->flags & PPMU_EBB) &&
+ ((event->attr.config >> EVENT_CONFIG_EBB_SHIFT) & 1);
+}
+
+static int ebb_event_check(struct perf_event *event)
+{
+ struct perf_event *leader = event->group_leader;
+
+ /* Event and group leader must agree on EBB */
+ if (is_ebb_event(leader) != is_ebb_event(event))
+ return -EINVAL;
+
+ if (is_ebb_event(event)) {
+ if (!(event->attach_state & PERF_ATTACH_TASK))
+ return -EINVAL;
+
+ if (!leader->attr.pinned || !leader->attr.exclusive)
+ return -EINVAL;
+
+ if (event->attr.inherit || event->attr.sample_period ||
+ event->attr.enable_on_exec || event->attr.freq)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void ebb_event_add(struct perf_event *event)
+{
+ if (!is_ebb_event(event) || current->thread.used_ebb)
+ return;
+
+ /*
+ * IFF this is the first time we've added an EBB event, set
+ * PMXE in the user MMCR0 so we can detect when it's cleared by
+ * userspace. We need this so that we can context switch while
+ * userspace is in the EBB handler (where PMXE is 0).
+ */
+ current->thread.used_ebb = 1;
+ current->thread.mmcr0 |= MMCR0_PMXE;
+}
+
+static void ebb_switch_out(unsigned long mmcr0)
+{
+ if (!(mmcr0 & MMCR0_EBE))
+ return;
+
+ current->thread.siar = mfspr(SPRN_SIAR);
+ current->thread.sier = mfspr(SPRN_SIER);
+ current->thread.sdar = mfspr(SPRN_SDAR);
+ current->thread.mmcr0 = mmcr0 & MMCR0_USER_MASK;
+ current->thread.mmcr2 = mfspr(SPRN_MMCR2) & MMCR2_USER_MASK;
+}
+
+static unsigned long ebb_switch_in(bool ebb, unsigned long mmcr0)
+{
+ if (!ebb)
+ goto out;
+
+ /* Enable EBB and read/write to all 6 PMCs for userspace */
+ mmcr0 |= MMCR0_EBE | MMCR0_PMCC_U6;
+
+ /* Add any bits from the user reg, FC or PMAO */
+ mmcr0 |= current->thread.mmcr0;
+
+ /* Be careful not to set PMXE if userspace had it cleared */
+ if (!(current->thread.mmcr0 & MMCR0_PMXE))
+ mmcr0 &= ~MMCR0_PMXE;
+
+ mtspr(SPRN_SIAR, current->thread.siar);
+ mtspr(SPRN_SIER, current->thread.sier);
+ mtspr(SPRN_SDAR, current->thread.sdar);
+ mtspr(SPRN_MMCR2, current->thread.mmcr2);
+out:
+ return mmcr0;
+}
#endif /* CONFIG_PPC64 */
static void perf_event_interrupt(struct pt_regs *regs);
@@ -732,6 +829,13 @@ static void power_pmu_read(struct perf_event *event)
if (!event->hw.idx)
return;
+
+ if (is_ebb_event(event)) {
+ val = read_pmc(event->hw.idx);
+ local64_set(&event->hw.prev_count, val);
+ return;
+ }
+
/*
* Performance monitor interrupts come even when interrupts
* are soft-disabled, as long as interrupts are hard-enabled.
@@ -852,7 +956,7 @@ static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
static void power_pmu_disable(struct pmu *pmu)
{
struct cpu_hw_events *cpuhw;
- unsigned long flags;
+ unsigned long flags, mmcr0, val;
if (!ppmu)
return;
@@ -860,9 +964,6 @@ static void power_pmu_disable(struct pmu *pmu)
cpuhw = &__get_cpu_var(cpu_hw_events);
if (!cpuhw->disabled) {
- cpuhw->disabled = 1;
- cpuhw->n_added = 0;
-
/*
* Check if we ever enabled the PMU on this cpu.
*/
@@ -872,6 +973,21 @@ static void power_pmu_disable(struct pmu *pmu)
}
/*
+ * Set the 'freeze counters' bit, clear EBE/PMCC/PMAO/FC56.
+ */
+ val = mmcr0 = mfspr(SPRN_MMCR0);
+ val |= MMCR0_FC;
+ val &= ~(MMCR0_EBE | MMCR0_PMCC | MMCR0_PMAO | MMCR0_FC56);
+
+ /*
+ * The barrier is to make sure the mtspr has been
+ * executed and the PMU has frozen the events etc.
+ * before we return.
+ */
+ write_mmcr0(cpuhw, val);
+ mb();
+
+ /*
* Disable instruction sampling if it was enabled
*/
if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
@@ -880,15 +996,12 @@ static void power_pmu_disable(struct pmu *pmu)
mb();
}
- /*
- * Set the 'freeze counters' bit.
- * The barrier is to make sure the mtspr has been
- * executed and the PMU has frozen the events
- * before we return.
- */
- write_mmcr0(cpuhw, mfspr(SPRN_MMCR0) | MMCR0_FC);
- mb();
+ cpuhw->disabled = 1;
+ cpuhw->n_added = 0;
+
+ ebb_switch_out(mmcr0);
}
+
local_irq_restore(flags);
}
@@ -903,23 +1016,36 @@ static void power_pmu_enable(struct pmu *pmu)
struct cpu_hw_events *cpuhw;
unsigned long flags;
long i;
- unsigned long val;
+ unsigned long val, mmcr0;
s64 left;
unsigned int hwc_index[MAX_HWEVENTS];
int n_lim;
int idx;
+ bool ebb;
if (!ppmu)
return;
local_irq_save(flags);
+
cpuhw = &__get_cpu_var(cpu_hw_events);
- if (!cpuhw->disabled) {
- local_irq_restore(flags);
- return;
+ if (!cpuhw->disabled)
+ goto out;
+
+ if (cpuhw->n_events == 0) {
+ ppc_set_pmu_inuse(0);
+ goto out;
}
+
cpuhw->disabled = 0;
/*
+ * EBB requires an exclusive group and all events must have the EBB
+ * flag set, or not set, so we can just check a single event. Also we
+ * know we have at least one event.
+ */
+ ebb = is_ebb_event(cpuhw->event[0]);
+
+ /*
* If we didn't change anything, or only removed events,
* no need to recalculate MMCR* settings and reset the PMCs.
* Just reenable the PMU with the current MMCR* settings
@@ -928,8 +1054,6 @@ static void power_pmu_enable(struct pmu *pmu)
if (!cpuhw->n_added) {
mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
- if (cpuhw->n_events == 0)
- ppc_set_pmu_inuse(0);
goto out_enable;
}
@@ -996,25 +1120,34 @@ static void power_pmu_enable(struct pmu *pmu)
++n_lim;
continue;
}
- val = 0;
- if (event->hw.sample_period) {
- left = local64_read(&event->hw.period_left);
- if (left < 0x80000000L)
- val = 0x80000000L - left;
+
+ if (ebb)
+ val = local64_read(&event->hw.prev_count);
+ else {
+ val = 0;
+ if (event->hw.sample_period) {
+ left = local64_read(&event->hw.period_left);
+ if (left < 0x80000000L)
+ val = 0x80000000L - left;
+ }
+ local64_set(&event->hw.prev_count, val);
}
- local64_set(&event->hw.prev_count, val);
+
event->hw.idx = idx;
if (event->hw.state & PERF_HES_STOPPED)
val = 0;
write_pmc(idx, val);
+
perf_event_update_userpage(event);
}
cpuhw->n_limited = n_lim;
cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
out_enable:
+ mmcr0 = ebb_switch_in(ebb, cpuhw->mmcr[0]);
+
mb();
- write_mmcr0(cpuhw, cpuhw->mmcr[0]);
+ write_mmcr0(cpuhw, mmcr0);
/*
* Enable instruction sampling if necessary
@@ -1112,6 +1245,8 @@ static int power_pmu_add(struct perf_event *event, int ef_flags)
event->hw.config = cpuhw->events[n0];
nocheck:
+ ebb_event_add(event);
+
++cpuhw->n_events;
++cpuhw->n_added;
@@ -1472,6 +1607,11 @@ static int power_pmu_event_init(struct perf_event *event)
}
}
+ /* Extra checks for EBB */
+ err = ebb_event_check(event);
+ if (err)
+ return err;
+
/*
* If this is in a group, check if it can go on with all the
* other hardware events in the group. We assume the event
@@ -1511,6 +1651,13 @@ static int power_pmu_event_init(struct perf_event *event)
local64_set(&event->hw.period_left, event->hw.last_period);
/*
+ * For EBB events we just context switch the PMC value, we don't do any
+ * of the sample_period logic. We use hw.prev_count for this.
+ */
+ if (is_ebb_event(event))
+ local64_set(&event->hw.prev_count, 0);
+
+ /*
* See if we need to reserve the PMU.
* If no events are currently in use, then we have to take a
* mutex to ensure that we don't race with another task doing
@@ -1786,7 +1933,7 @@ static void power_pmu_setup(int cpu)
cpuhw->mmcr[0] = MMCR0_FC;
}
-static int __cpuinit
+static int
power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
@@ -1803,7 +1950,7 @@ power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu
return NOTIFY_OK;
}
-int __cpuinit register_power_pmu(struct power_pmu *pmu)
+int register_power_pmu(struct power_pmu *pmu)
{
if (ppmu)
return -EBUSY; /* something's already registered */
diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c
index f7d1c4fff303..96a64d6a8bdf 100644
--- a/arch/powerpc/perf/power8-pmu.c
+++ b/arch/powerpc/perf/power8-pmu.c
@@ -31,9 +31,9 @@
*
* 60 56 52 48 44 40 36 32
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- * [ thresh_cmp ] [ thresh_ctl ]
- * |
- * thresh start/stop OR FAB match -*
+ * | [ thresh_cmp ] [ thresh_ctl ]
+ * | |
+ * *- EBB (Linux) thresh start/stop OR FAB match -*
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
@@ -85,6 +85,7 @@
*
*/
+#define EVENT_EBB_MASK 1ull
#define EVENT_THR_CMP_SHIFT 40 /* Threshold CMP value */
#define EVENT_THR_CMP_MASK 0x3ff
#define EVENT_THR_CTL_SHIFT 32 /* Threshold control value (start/stop) */
@@ -109,6 +110,17 @@
#define EVENT_IS_MARKED (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT)
#define EVENT_PSEL_MASK 0xff /* PMCxSEL value */
+#define EVENT_VALID_MASK \
+ ((EVENT_THRESH_MASK << EVENT_THRESH_SHIFT) | \
+ (EVENT_SAMPLE_MASK << EVENT_SAMPLE_SHIFT) | \
+ (EVENT_CACHE_SEL_MASK << EVENT_CACHE_SEL_SHIFT) | \
+ (EVENT_PMC_MASK << EVENT_PMC_SHIFT) | \
+ (EVENT_UNIT_MASK << EVENT_UNIT_SHIFT) | \
+ (EVENT_COMBINE_MASK << EVENT_COMBINE_SHIFT) | \
+ (EVENT_MARKED_MASK << EVENT_MARKED_SHIFT) | \
+ (EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT) | \
+ EVENT_PSEL_MASK)
+
/* MMCRA IFM bits - POWER8 */
#define POWER8_MMCRA_IFM1 0x0000000040000000UL
#define POWER8_MMCRA_IFM2 0x0000000080000000UL
@@ -130,10 +142,10 @@
*
* 28 24 20 16 12 8 4 0
* | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
- * [ ] [ sample ] [ ] [6] [5] [4] [3] [2] [1]
- * | |
- * L1 I/D qualifier -* | Count of events for each PMC.
- * | p1, p2, p3, p4, p5, p6.
+ * | [ ] [ sample ] [ ] [6] [5] [4] [3] [2] [1]
+ * EBB -* | |
+ * | | Count of events for each PMC.
+ * L1 I/D qualifier -* | p1, p2, p3, p4, p5, p6.
* nc - number of counters -*
*
* The PMC fields P1..P6, and NC, are adder fields. As we accumulate constraints
@@ -149,6 +161,9 @@
#define CNST_THRESH_VAL(v) (((v) & EVENT_THRESH_MASK) << 32)
#define CNST_THRESH_MASK CNST_THRESH_VAL(EVENT_THRESH_MASK)
+#define CNST_EBB_VAL(v) (((v) & EVENT_EBB_MASK) << 24)
+#define CNST_EBB_MASK CNST_EBB_VAL(EVENT_EBB_MASK)
+
#define CNST_L1_QUAL_VAL(v) (((v) & 3) << 22)
#define CNST_L1_QUAL_MASK CNST_L1_QUAL_VAL(3)
@@ -207,14 +222,21 @@ static inline bool event_is_fab_match(u64 event)
static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long *valp)
{
- unsigned int unit, pmc, cache;
+ unsigned int unit, pmc, cache, ebb;
unsigned long mask, value;
mask = value = 0;
- pmc = (event >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
- unit = (event >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK;
- cache = (event >> EVENT_CACHE_SEL_SHIFT) & EVENT_CACHE_SEL_MASK;
+ if (event & ~EVENT_VALID_MASK)
+ return -1;
+
+ pmc = (event >> EVENT_PMC_SHIFT) & EVENT_PMC_MASK;
+ unit = (event >> EVENT_UNIT_SHIFT) & EVENT_UNIT_MASK;
+ cache = (event >> EVENT_CACHE_SEL_SHIFT) & EVENT_CACHE_SEL_MASK;
+ ebb = (event >> EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
+
+ /* Clear the EBB bit in the event, so event checks work below */
+ event &= ~(EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT);
if (pmc) {
if (pmc > 6)
@@ -284,6 +306,18 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
value |= CNST_THRESH_VAL(event >> EVENT_THRESH_SHIFT);
}
+ if (!pmc && ebb)
+ /* EBB events must specify the PMC */
+ return -1;
+
+ /*
+ * All events must agree on EBB, either all request it or none.
+ * EBB events are pinned & exclusive, so this should never actually
+ * hit, but we leave it as a fallback in case.
+ */
+ mask |= CNST_EBB_VAL(ebb);
+ value |= CNST_EBB_MASK;
+
*maskp = mask;
*valp = value;
@@ -378,6 +412,10 @@ static int power8_compute_mmcr(u64 event[], int n_ev,
if (pmc_inuse & 0x7c)
mmcr[0] |= MMCR0_PMCjCE;
+ /* If we're not using PMC 5 or 6, freeze them */
+ if (!(pmc_inuse & 0x60))
+ mmcr[0] |= MMCR0_FC56;
+
mmcr[1] = mmcr1;
mmcr[2] = mmcra;
@@ -574,7 +612,7 @@ static struct power_pmu power8_pmu = {
.get_constraint = power8_get_constraint,
.get_alternatives = power8_get_alternatives,
.disable_pmc = power8_disable_pmc,
- .flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB,
+ .flags = PPMU_HAS_SSLOT | PPMU_HAS_SIER | PPMU_BHRB | PPMU_EBB,
.n_generic = ARRAY_SIZE(power8_generic_events),
.generic_events = power8_generic_events,
.attr_groups = power8_pmu_attr_groups,
diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c
index ecd3890c40d7..7f1b71a01c6a 100644
--- a/arch/powerpc/platforms/44x/currituck.c
+++ b/arch/powerpc/platforms/44x/currituck.c
@@ -91,12 +91,12 @@ static void __init ppc47x_init_irq(void)
}
#ifdef CONFIG_SMP
-static void __cpuinit smp_ppc47x_setup_cpu(int cpu)
+static void smp_ppc47x_setup_cpu(int cpu)
{
mpic_setup_this_cpu();
}
-static int __cpuinit smp_ppc47x_kick_cpu(int cpu)
+static int smp_ppc47x_kick_cpu(int cpu)
{
struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
const u64 *spin_table_addr_prop;
@@ -176,13 +176,48 @@ static int __init ppc47x_probe(void)
return 1;
}
+static int board_rev = -1;
+static int __init ppc47x_get_board_rev(void)
+{
+ u8 fpga_reg0;
+ void *fpga;
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
+ if (!np)
+ goto fail;
+
+ fpga = of_iomap(np, 0);
+ of_node_put(np);
+ if (!fpga)
+ goto fail;
+
+ fpga_reg0 = ioread8(fpga);
+ board_rev = fpga_reg0 & 0x03;
+ pr_info("%s: Found board revision %d\n", __func__, board_rev);
+ iounmap(fpga);
+ return 0;
+
+fail:
+ pr_info("%s: Unable to find board revision\n", __func__);
+ return 0;
+}
+machine_arch_initcall(ppc47x, ppc47x_get_board_rev);
+
/* Use USB controller should have been hardware swizzled but it wasn't :( */
static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
{
if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
dev->device == 0x00e0)) {
- dev->irq = irq_create_mapping(NULL, 47);
- pr_info("%s: Mapping irq 47 %d\n", __func__, dev->irq);
+ if (board_rev == 0) {
+ dev->irq = irq_create_mapping(NULL, 47);
+ pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
+ } else if (board_rev == 2) {
+ dev->irq = irq_create_mapping(NULL, 49);
+ pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
+ } else {
+ pr_alert("%s: Unknown board revision\n", __func__);
+ }
}
}
diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c
index a28a8629727e..4241bc825800 100644
--- a/arch/powerpc/platforms/44x/iss4xx.c
+++ b/arch/powerpc/platforms/44x/iss4xx.c
@@ -81,12 +81,12 @@ static void __init iss4xx_init_irq(void)
}
#ifdef CONFIG_SMP
-static void __cpuinit smp_iss4xx_setup_cpu(int cpu)
+static void smp_iss4xx_setup_cpu(int cpu)
{
mpic_setup_this_cpu();
}
-static int __cpuinit smp_iss4xx_kick_cpu(int cpu)
+static int smp_iss4xx_kick_cpu(int cpu)
{
struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
const u64 *spin_table_addr_prop;
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index 0a134e0469ef..3e90ece10ae9 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -43,9 +43,7 @@ static void __init mpc5121_ads_setup_arch(void)
mpc83xx_add_bridge(np);
#endif
-#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
- mpc512x_setup_diu();
-#endif
+ mpc512x_setup_arch();
}
static void __init mpc5121_ads_init_IRQ(void)
@@ -69,7 +67,7 @@ define_machine(mpc5121_ads) {
.probe = mpc5121_ads_probe,
.setup_arch = mpc5121_ads_setup_arch,
.init = mpc512x_init,
- .init_early = mpc512x_init_diu,
+ .init_early = mpc512x_init_early,
.init_IRQ = mpc5121_ads_init_IRQ,
.get_irq = ipic_get_irq,
.calibrate_decr = generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index 0a8e60023944..cc97f022d028 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -12,18 +12,12 @@
#ifndef __MPC512X_H__
#define __MPC512X_H__
extern void __init mpc512x_init_IRQ(void);
+extern void __init mpc512x_init_early(void);
extern void __init mpc512x_init(void);
+extern void __init mpc512x_setup_arch(void);
extern int __init mpc5121_clk_init(void);
-void __init mpc512x_declare_of_platform_devices(void);
extern const char *mpc512x_select_psc_compat(void);
+extern const char *mpc512x_select_reset_compat(void);
extern void mpc512x_restart(char *cmd);
-#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-void mpc512x_init_diu(void);
-void mpc512x_setup_diu(void);
-#else
-#define mpc512x_init_diu NULL
-#define mpc512x_setup_diu NULL
-#endif
-
#endif /* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_generic.c b/arch/powerpc/platforms/512x/mpc512x_generic.c
index 5fb919b30924..ce71408781a0 100644
--- a/arch/powerpc/platforms/512x/mpc512x_generic.c
+++ b/arch/powerpc/platforms/512x/mpc512x_generic.c
@@ -45,8 +45,8 @@ define_machine(mpc512x_generic) {
.name = "MPC512x generic",
.probe = mpc512x_generic_probe,
.init = mpc512x_init,
- .init_early = mpc512x_init_diu,
- .setup_arch = mpc512x_setup_diu,
+ .init_early = mpc512x_init_early,
+ .setup_arch = mpc512x_setup_arch,
.init_IRQ = mpc512x_init_IRQ,
.get_irq = ipic_get_irq,
.calibrate_decr = generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 6eb94ab99d39..a82a41b4fd91 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -35,8 +35,10 @@ static struct mpc512x_reset_module __iomem *reset_module_base;
static void __init mpc512x_restart_init(void)
{
struct device_node *np;
+ const char *reset_compat;
- np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+ reset_compat = mpc512x_select_reset_compat();
+ np = of_find_compatible_node(NULL, NULL, reset_compat);
if (!np)
return;
@@ -58,7 +60,7 @@ void mpc512x_restart(char *cmd)
;
}
-#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+#if IS_ENABLED(CONFIG_FB_FSL_DIU)
struct fsl_diu_shared_fb {
u8 gamma[0x300]; /* 32-bit aligned! */
@@ -355,6 +357,17 @@ const char *mpc512x_select_psc_compat(void)
return NULL;
}
+const char *mpc512x_select_reset_compat(void)
+{
+ if (of_machine_is_compatible("fsl,mpc5121"))
+ return "fsl,mpc5121-reset";
+
+ if (of_machine_is_compatible("fsl,mpc5125"))
+ return "fsl,mpc5125-reset";
+
+ return NULL;
+}
+
static unsigned int __init get_fifo_size(struct device_node *np,
char *prop_name)
{
@@ -436,14 +449,26 @@ void __init mpc512x_psc_fifo_init(void)
}
}
+void __init mpc512x_init_early(void)
+{
+ mpc512x_restart_init();
+ if (IS_ENABLED(CONFIG_FB_FSL_DIU))
+ mpc512x_init_diu();
+}
+
void __init mpc512x_init(void)
{
mpc5121_clk_init();
mpc512x_declare_of_platform_devices();
- mpc512x_restart_init();
mpc512x_psc_fifo_init();
}
+void __init mpc512x_setup_arch(void)
+{
+ if (IS_ENABLED(CONFIG_FB_FSL_DIU))
+ mpc512x_setup_diu();
+}
+
/**
* mpc512x_cs_config - Setup chip select configuration
* @cs: chip select number
diff --git a/arch/powerpc/platforms/512x/pdm360ng.c b/arch/powerpc/platforms/512x/pdm360ng.c
index 0575e858291c..24b314d7bd5f 100644
--- a/arch/powerpc/platforms/512x/pdm360ng.c
+++ b/arch/powerpc/platforms/512x/pdm360ng.c
@@ -119,9 +119,9 @@ static int __init pdm360ng_probe(void)
define_machine(pdm360ng) {
.name = "PDM360NG",
.probe = pdm360ng_probe,
- .setup_arch = mpc512x_setup_diu,
+ .setup_arch = mpc512x_setup_arch,
.init = pdm360ng_init,
- .init_early = mpc512x_init_diu,
+ .init_early = mpc512x_init_early,
.init_IRQ = mpc512x_init_IRQ,
.get_irq = ipic_get_irq,
.calibrate_decr = generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
index 624cb51d19c9..7bc315822935 100644
--- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
+++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
@@ -231,17 +231,7 @@ static struct i2c_driver mcu_driver = {
.id_table = mcu_ids,
};
-static int __init mcu_init(void)
-{
- return i2c_add_driver(&mcu_driver);
-}
-module_init(mcu_init);
-
-static void __exit mcu_exit(void)
-{
- i2c_del_driver(&mcu_driver);
-}
-module_exit(mcu_exit);
+module_i2c_driver(mcu_driver);
MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
"MPC8349E-mITX-compatible MCU");
diff --git a/arch/powerpc/platforms/85xx/p5020_ds.c b/arch/powerpc/platforms/85xx/p5020_ds.c
index 753a42c29d4d..39cfa4044e6c 100644
--- a/arch/powerpc/platforms/85xx/p5020_ds.c
+++ b/arch/powerpc/platforms/85xx/p5020_ds.c
@@ -75,12 +75,7 @@ define_machine(p5020_ds) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
-/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
-#ifdef CONFIG_PPC64
- .get_irq = mpic_get_irq,
-#else
.get_irq = mpic_get_coreint_irq,
-#endif
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
diff --git a/arch/powerpc/platforms/85xx/p5040_ds.c b/arch/powerpc/platforms/85xx/p5040_ds.c
index 11381851828e..f70e74cddf97 100644
--- a/arch/powerpc/platforms/85xx/p5040_ds.c
+++ b/arch/powerpc/platforms/85xx/p5040_ds.c
@@ -66,12 +66,7 @@ define_machine(p5040_ds) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
-/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
-#ifdef CONFIG_PPC64
- .get_irq = mpic_get_irq,
-#else
.get_irq = mpic_get_coreint_irq,
-#endif
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 6a1759939c6b..5ced4f5bb2b2 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -99,7 +99,7 @@ static void mpc85xx_take_timebase(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void __cpuinit smp_85xx_mach_cpu_die(void)
+static void smp_85xx_mach_cpu_die(void)
{
unsigned int cpu = smp_processor_id();
u32 tmp;
@@ -141,7 +141,7 @@ static inline u32 read_spin_table_addr_l(void *spin_table)
return in_be32(&((struct epapr_spin_table *)spin_table)->addr_l);
}
-static int __cpuinit smp_85xx_kick_cpu(int nr)
+static int smp_85xx_kick_cpu(int nr)
{
unsigned long flags;
const u64 *cpu_rel_addr;
@@ -362,7 +362,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
}
#endif /* CONFIG_KEXEC */
-static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
+static void smp_85xx_setup_cpu(int cpu_nr)
{
if (smp_85xx_ops.probe == smp_mpic_probe)
mpic_setup_this_cpu();
diff --git a/arch/powerpc/platforms/85xx/t4240_qds.c b/arch/powerpc/platforms/85xx/t4240_qds.c
index 5998e9f33304..91ead6b1b8af 100644
--- a/arch/powerpc/platforms/85xx/t4240_qds.c
+++ b/arch/powerpc/platforms/85xx/t4240_qds.c
@@ -75,12 +75,7 @@ define_machine(t4240_qds) {
#ifdef CONFIG_PCI
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
-/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
-#ifdef CONFIG_PPC64
- .get_irq = mpic_get_irq,
-#else
.get_irq = mpic_get_coreint_irq,
-#endif
.restart = fsl_rstcr_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 1e121088826f..587a2828b06c 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -43,6 +43,7 @@ static irqreturn_t timebase_interrupt(int irq, void *dev)
static struct irqaction tbint_irqaction = {
.handler = timebase_interrupt,
+ .flags = IRQF_NO_THREAD,
.name = "tbint",
};
@@ -218,19 +219,12 @@ void mpc8xx_restart(char *cmd)
static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
{
- struct irq_chip *chip;
- int cascade_irq;
-
- if ((cascade_irq = cpm_get_irq()) >= 0) {
- struct irq_desc *cdesc = irq_to_desc(cascade_irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ int cascade_irq = cpm_get_irq();
+ if (cascade_irq >= 0)
generic_handle_irq(cascade_irq);
- chip = irq_desc_get_chip(cdesc);
- chip->irq_eoi(&cdesc->irq_data);
- }
-
- chip = irq_desc_get_chip(desc);
chip->irq_eoi(&desc->irq_data);
}
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index b62aab3e22ec..d703775bda30 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -86,6 +86,27 @@ config MPIC
bool
default n
+config MPIC_TIMER
+ bool "MPIC Global Timer"
+ depends on MPIC && FSL_SOC
+ default n
+ help
+ The MPIC global timer is a hardware timer inside the
+ Freescale PIC complying with OpenPIC standard. When the
+ specified interval times out, the hardware timer generates
+ an interrupt. The driver currently is only tested on fsl
+ chip, but it can potentially support other global timers
+ complying with the OpenPIC standard.
+
+config FSL_MPIC_TIMER_WAKEUP
+ tristate "Freescale MPIC global timer wakeup driver"
+ depends on FSL_SOC && MPIC_TIMER && PM
+ default n
+ help
+ The driver provides a way to wake up the system by MPIC
+ timer.
+ e.g. "echo 5 > /sys/devices/system/mpic/timer_wakeup"
+
config PPC_EPAPR_HV_PIC
bool
default n
@@ -164,6 +185,11 @@ config IBMEBUS
help
Bus device driver for GX bus based adapters.
+config EEH
+ bool
+ depends on (PPC_POWERNV || PPC_PSERIES) && PCI
+ default y
+
config PPC_MPC106
bool
default n
@@ -193,37 +219,6 @@ config PPC_IO_WORKAROUNDS
source "drivers/cpufreq/Kconfig"
-menu "CPU Frequency drivers"
- depends on CPU_FREQ
-
-config CPU_FREQ_PMAC
- bool "Support for Apple PowerBooks"
- depends on ADB_PMU && PPC32
- select CPU_FREQ_TABLE
- help
- This adds support for frequency switching on Apple PowerBooks,
- this currently includes some models of iBook & Titanium
- PowerBook.
-
-config CPU_FREQ_PMAC64
- bool "Support for some Apple G5s"
- depends on PPC_PMAC && PPC64
- select CPU_FREQ_TABLE
- help
- This adds support for frequency switching on Apple iMac G5,
- and some of the more recent desktop G5 machines as well.
-
-config PPC_PASEMI_CPUFREQ
- bool "Support for PA Semi PWRficient"
- depends on PPC_PASEMI
- default y
- select CPU_FREQ_TABLE
- help
- This adds the support for frequency switching on PA Semi
- PWRficient processors.
-
-endmenu
-
menu "CPUIdle driver"
source "drivers/cpuidle/Kconfig"
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 54f3936001aa..47d9a03dd415 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -71,6 +71,7 @@ config PPC_BOOK3S_64
select PPC_FPU
select PPC_HAVE_PMU_SUPPORT
select SYS_SUPPORTS_HUGETLBFS
+ select HAVE_ARCH_TRANSPARENT_HUGEPAGE if PPC_64K_PAGES
config PPC_BOOK3E_64
bool "Embedded processors"
@@ -158,6 +159,7 @@ config E500
config PPC_E500MC
bool "e500mc Support"
select PPC_FPU
+ select COMMON_CLK
depends on E500
help
This must be enabled for running on e500mc (and derivatives
diff --git a/arch/powerpc/platforms/cell/beat_htab.c b/arch/powerpc/platforms/cell/beat_htab.c
index 246e1d8b3af3..c34ee4e60873 100644
--- a/arch/powerpc/platforms/cell/beat_htab.c
+++ b/arch/powerpc/platforms/cell/beat_htab.c
@@ -185,7 +185,8 @@ static void beat_lpar_hptab_clear(void)
static long beat_lpar_hpte_updatepp(unsigned long slot,
unsigned long newpp,
unsigned long vpn,
- int psize, int ssize, int local)
+ int psize, int apsize,
+ int ssize, int local)
{
unsigned long lpar_rc;
u64 dummy0, dummy1;
@@ -274,7 +275,8 @@ static void beat_lpar_hpte_updateboltedpp(unsigned long newpp,
}
static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
- int psize, int ssize, int local)
+ int psize, int apsize,
+ int ssize, int local)
{
unsigned long want_v;
unsigned long lpar_rc;
@@ -364,9 +366,10 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,
* already zero. For now I am paranoid.
*/
static long beat_lpar_hpte_updatepp_v3(unsigned long slot,
- unsigned long newpp,
- unsigned long vpn,
- int psize, int ssize, int local)
+ unsigned long newpp,
+ unsigned long vpn,
+ int psize, int apsize,
+ int ssize, int local)
{
unsigned long lpar_rc;
unsigned long want_v;
@@ -394,7 +397,8 @@ static long beat_lpar_hpte_updatepp_v3(unsigned long slot,
}
static void beat_lpar_hpte_invalidate_v3(unsigned long slot, unsigned long vpn,
- int psize, int ssize, int local)
+ int psize, int apsize,
+ int ssize, int local)
{
unsigned long want_v;
unsigned long lpar_rc;
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 8c6dc42ecf65..9e5dfbcc00af 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -239,7 +239,7 @@ void __init beatic_init_IRQ(void)
ppc_md.get_irq = beatic_get_irq;
/* Allocate an irq host */
- beatic_host = irq_domain_add_nomap(NULL, 0, &beatic_pic_host_ops, NULL);
+ beatic_host = irq_domain_add_nomap(NULL, ~0, &beatic_pic_host_ops, NULL);
BUG_ON(beatic_host == NULL);
irq_set_default_host(beatic_host);
}
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index d35dbbc8ec79..f75f6fcac729 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -142,7 +142,7 @@ static int smp_cell_cpu_bootable(unsigned int nr)
* during boot if the user requests it. Odd-numbered
* cpus are assumed to be secondary threads.
*/
- if (system_state < SYSTEM_RUNNING &&
+ if (system_state == SYSTEM_BOOTING &&
cpu_has_feature(CPU_FTR_SMT) &&
!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index ce6d789e0741..8e8d4cae5ebe 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1,3 +1,2 @@
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_PPC_PASEMI_CPUFREQ) += cpufreq.o
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile
index ea47df66fee5..52c6ce1cc985 100644
--- a/arch/powerpc/platforms/powermac/Makefile
+++ b/arch/powerpc/platforms/powermac/Makefile
@@ -9,8 +9,6 @@ obj-y += pic.o setup.o time.o feature.o pci.o \
sleep.o low_i2c.o cache.o pfunc_core.o \
pfunc_base.o udbg_scc.o udbg_adb.o
obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o
-obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o
-obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o
# CONFIG_NVRAM is an arch. independent tristate symbol, for pmac32 we really
# need this to be a bool. Cheat here and pretend CONFIG_NVRAM=m is really
# CONFIG_NVRAM=y
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index bdb738a69e41..5cbd4d67d5c4 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -192,7 +192,7 @@ static int psurge_secondary_ipi_init(void)
{
int rc = -ENOMEM;
- psurge_host = irq_domain_add_nomap(NULL, 0, &psurge_host_ops, NULL);
+ psurge_host = irq_domain_add_nomap(NULL, ~0, &psurge_host_ops, NULL);
if (psurge_host)
psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
@@ -885,7 +885,7 @@ static int smp_core99_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata smp_core99_cpu_nb = {
+static struct notifier_block smp_core99_cpu_nb = {
.notifier_call = smp_core99_cpu_notify,
};
#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index bcc3cb48a44e..7fe595152478 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -3,3 +3,4 @@ obj-y += opal-rtc.o opal-nvram.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
+obj-$(CONFIG_EEH) += eeh-ioda.o eeh-powernv.o
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
new file mode 100644
index 000000000000..0cd1c4a71755
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -0,0 +1,916 @@
+/*
+ * The file intends to implement the functions needed by EEH, which is
+ * built on IODA compliant chip. Actually, lots of functions related
+ * to EEH would be built based on the OPAL APIs.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013.
+ *
+ * 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/bootmem.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/notifier.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include <asm/eeh.h>
+#include <asm/eeh_event.h>
+#include <asm/io.h>
+#include <asm/iommu.h>
+#include <asm/msi_bitmap.h>
+#include <asm/opal.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc-pci.h>
+#include <asm/tce.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+/* Debugging option */
+#ifdef IODA_EEH_DBG_ON
+#define IODA_EEH_DBG(args...) pr_info(args)
+#else
+#define IODA_EEH_DBG(args...)
+#endif
+
+static char *hub_diag = NULL;
+static int ioda_eeh_nb_init = 0;
+
+static int ioda_eeh_event(struct notifier_block *nb,
+ unsigned long events, void *change)
+{
+ uint64_t changed_evts = (uint64_t)change;
+
+ /* We simply send special EEH event */
+ if ((changed_evts & OPAL_EVENT_PCI_ERROR) &&
+ (events & OPAL_EVENT_PCI_ERROR))
+ eeh_send_failure_event(NULL);
+
+ return 0;
+}
+
+static struct notifier_block ioda_eeh_nb = {
+ .notifier_call = ioda_eeh_event,
+ .next = NULL,
+ .priority = 0
+};
+
+#ifdef CONFIG_DEBUG_FS
+static int ioda_eeh_dbgfs_set(void *data, u64 val)
+{
+ struct pci_controller *hose = data;
+ struct pnv_phb *phb = hose->private_data;
+
+ out_be64(phb->regs + 0xD10, val);
+ return 0;
+}
+
+static int ioda_eeh_dbgfs_get(void *data, u64 *val)
+{
+ struct pci_controller *hose = data;
+ struct pnv_phb *phb = hose->private_data;
+
+ *val = in_be64(phb->regs + 0xD10);
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(ioda_eeh_dbgfs_ops, ioda_eeh_dbgfs_get,
+ ioda_eeh_dbgfs_set, "0x%llx\n");
+#endif /* CONFIG_DEBUG_FS */
+
+/**
+ * ioda_eeh_post_init - Chip dependent post initialization
+ * @hose: PCI controller
+ *
+ * The function will be called after eeh PEs and devices
+ * have been built. That means the EEH is ready to supply
+ * service with I/O cache.
+ */
+static int ioda_eeh_post_init(struct pci_controller *hose)
+{
+ struct pnv_phb *phb = hose->private_data;
+ int ret;
+
+ /* Register OPAL event notifier */
+ if (!ioda_eeh_nb_init) {
+ ret = opal_notifier_register(&ioda_eeh_nb);
+ if (ret) {
+ pr_err("%s: Can't register OPAL event notifier (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ioda_eeh_nb_init = 1;
+ }
+
+ /* FIXME: Enable it for PHB3 later */
+ if (phb->type == PNV_PHB_IODA1) {
+ if (!hub_diag) {
+ hub_diag = (char *)__get_free_page(GFP_KERNEL |
+ __GFP_ZERO);
+ if (!hub_diag) {
+ pr_err("%s: Out of memory !\n",
+ __func__);
+ return -ENOMEM;
+ }
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ if (phb->dbgfs)
+ debugfs_create_file("err_injct", 0600,
+ phb->dbgfs, hose,
+ &ioda_eeh_dbgfs_ops);
+#endif
+
+ phb->eeh_state |= PNV_EEH_STATE_ENABLED;
+ }
+
+ return 0;
+}
+
+/**
+ * ioda_eeh_set_option - Set EEH operation or I/O setting
+ * @pe: EEH PE
+ * @option: options
+ *
+ * Enable or disable EEH option for the indicated PE. The
+ * function also can be used to enable I/O or DMA for the
+ * PE.
+ */
+static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
+{
+ s64 ret;
+ u32 pe_no;
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+
+ /* Check on PE number */
+ if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) {
+ pr_err("%s: PE address %x out of range [0, %x] "
+ "on PHB#%x\n",
+ __func__, pe->addr, phb->ioda.total_pe,
+ hose->global_number);
+ return -EINVAL;
+ }
+
+ pe_no = pe->addr;
+ switch (option) {
+ case EEH_OPT_DISABLE:
+ ret = -EEXIST;
+ break;
+ case EEH_OPT_ENABLE:
+ ret = 0;
+ break;
+ case EEH_OPT_THAW_MMIO:
+ ret = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
+ OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO);
+ if (ret) {
+ pr_warning("%s: Failed to enable MMIO for "
+ "PHB#%x-PE#%x, err=%lld\n",
+ __func__, hose->global_number, pe_no, ret);
+ return -EIO;
+ }
+
+ break;
+ case EEH_OPT_THAW_DMA:
+ ret = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
+ OPAL_EEH_ACTION_CLEAR_FREEZE_DMA);
+ if (ret) {
+ pr_warning("%s: Failed to enable DMA for "
+ "PHB#%x-PE#%x, err=%lld\n",
+ __func__, hose->global_number, pe_no, ret);
+ return -EIO;
+ }
+
+ break;
+ default:
+ pr_warning("%s: Invalid option %d\n", __func__, option);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * ioda_eeh_get_state - Retrieve the state of PE
+ * @pe: EEH PE
+ *
+ * The PE's state should be retrieved from the PEEV, PEST
+ * IODA tables. Since the OPAL has exported the function
+ * to do it, it'd better to use that.
+ */
+static int ioda_eeh_get_state(struct eeh_pe *pe)
+{
+ s64 ret = 0;
+ u8 fstate;
+ u16 pcierr;
+ u32 pe_no;
+ int result;
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+
+ /*
+ * Sanity check on PE address. The PHB PE address should
+ * be zero.
+ */
+ if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) {
+ pr_err("%s: PE address %x out of range [0, %x] "
+ "on PHB#%x\n",
+ __func__, pe->addr, phb->ioda.total_pe,
+ hose->global_number);
+ return EEH_STATE_NOT_SUPPORT;
+ }
+
+ /* Retrieve PE status through OPAL */
+ pe_no = pe->addr;
+ ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
+ &fstate, &pcierr, NULL);
+ if (ret) {
+ pr_err("%s: Failed to get EEH status on "
+ "PHB#%x-PE#%x\n, err=%lld\n",
+ __func__, hose->global_number, pe_no, ret);
+ return EEH_STATE_NOT_SUPPORT;
+ }
+
+ /* Check PHB status */
+ if (pe->type & EEH_PE_PHB) {
+ result = 0;
+ result &= ~EEH_STATE_RESET_ACTIVE;
+
+ if (pcierr != OPAL_EEH_PHB_ERROR) {
+ result |= EEH_STATE_MMIO_ACTIVE;
+ result |= EEH_STATE_DMA_ACTIVE;
+ result |= EEH_STATE_MMIO_ENABLED;
+ result |= EEH_STATE_DMA_ENABLED;
+ }
+
+ return result;
+ }
+
+ /* Parse result out */
+ result = 0;
+ switch (fstate) {
+ case OPAL_EEH_STOPPED_NOT_FROZEN:
+ result &= ~EEH_STATE_RESET_ACTIVE;
+ result |= EEH_STATE_MMIO_ACTIVE;
+ result |= EEH_STATE_DMA_ACTIVE;
+ result |= EEH_STATE_MMIO_ENABLED;
+ result |= EEH_STATE_DMA_ENABLED;
+ break;
+ case OPAL_EEH_STOPPED_MMIO_FREEZE:
+ result &= ~EEH_STATE_RESET_ACTIVE;
+ result |= EEH_STATE_DMA_ACTIVE;
+ result |= EEH_STATE_DMA_ENABLED;
+ break;
+ case OPAL_EEH_STOPPED_DMA_FREEZE:
+ result &= ~EEH_STATE_RESET_ACTIVE;
+ result |= EEH_STATE_MMIO_ACTIVE;
+ result |= EEH_STATE_MMIO_ENABLED;
+ break;
+ case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE:
+ result &= ~EEH_STATE_RESET_ACTIVE;
+ break;
+ case OPAL_EEH_STOPPED_RESET:
+ result |= EEH_STATE_RESET_ACTIVE;
+ break;
+ case OPAL_EEH_STOPPED_TEMP_UNAVAIL:
+ result |= EEH_STATE_UNAVAILABLE;
+ break;
+ case OPAL_EEH_STOPPED_PERM_UNAVAIL:
+ result |= EEH_STATE_NOT_SUPPORT;
+ break;
+ default:
+ pr_warning("%s: Unexpected EEH status 0x%x "
+ "on PHB#%x-PE#%x\n",
+ __func__, fstate, hose->global_number, pe_no);
+ }
+
+ return result;
+}
+
+static int ioda_eeh_pe_clear(struct eeh_pe *pe)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ u32 pe_no;
+ u8 fstate;
+ u16 pcierr;
+ s64 ret;
+
+ pe_no = pe->addr;
+ hose = pe->phb;
+ phb = pe->phb->private_data;
+
+ /* Clear the EEH error on the PE */
+ ret = opal_pci_eeh_freeze_clear(phb->opal_id,
+ pe_no, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+ if (ret) {
+ pr_err("%s: Failed to clear EEH error for "
+ "PHB#%x-PE#%x, err=%lld\n",
+ __func__, hose->global_number, pe_no, ret);
+ return -EIO;
+ }
+
+ /*
+ * Read the PE state back and verify that the frozen
+ * state has been removed.
+ */
+ ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
+ &fstate, &pcierr, NULL);
+ if (ret) {
+ pr_err("%s: Failed to get EEH status on "
+ "PHB#%x-PE#%x\n, err=%lld\n",
+ __func__, hose->global_number, pe_no, ret);
+ return -EIO;
+ }
+
+ if (fstate != OPAL_EEH_STOPPED_NOT_FROZEN) {
+ pr_err("%s: Frozen state not cleared on "
+ "PHB#%x-PE#%x, sts=%x\n",
+ __func__, hose->global_number, pe_no, fstate);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static s64 ioda_eeh_phb_poll(struct pnv_phb *phb)
+{
+ s64 rc = OPAL_HARDWARE;
+
+ while (1) {
+ rc = opal_pci_poll(phb->opal_id);
+ if (rc <= 0)
+ break;
+
+ msleep(rc);
+ }
+
+ return rc;
+}
+
+static int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
+{
+ struct pnv_phb *phb = hose->private_data;
+ s64 rc = OPAL_HARDWARE;
+
+ pr_debug("%s: Reset PHB#%x, option=%d\n",
+ __func__, hose->global_number, option);
+
+ /* Issue PHB complete reset request */
+ if (option == EEH_RESET_FUNDAMENTAL ||
+ option == EEH_RESET_HOT)
+ rc = opal_pci_reset(phb->opal_id,
+ OPAL_PHB_COMPLETE,
+ OPAL_ASSERT_RESET);
+ else if (option == EEH_RESET_DEACTIVATE)
+ rc = opal_pci_reset(phb->opal_id,
+ OPAL_PHB_COMPLETE,
+ OPAL_DEASSERT_RESET);
+ if (rc < 0)
+ goto out;
+
+ /*
+ * Poll state of the PHB until the request is done
+ * successfully.
+ */
+ rc = ioda_eeh_phb_poll(phb);
+out:
+ if (rc != OPAL_SUCCESS)
+ return -EIO;
+
+ return 0;
+}
+
+static int ioda_eeh_root_reset(struct pci_controller *hose, int option)
+{
+ struct pnv_phb *phb = hose->private_data;
+ s64 rc = OPAL_SUCCESS;
+
+ pr_debug("%s: Reset PHB#%x, option=%d\n",
+ __func__, hose->global_number, option);
+
+ /*
+ * During the reset deassert time, we needn't care
+ * the reset scope because the firmware does nothing
+ * for fundamental or hot reset during deassert phase.
+ */
+ if (option == EEH_RESET_FUNDAMENTAL)
+ rc = opal_pci_reset(phb->opal_id,
+ OPAL_PCI_FUNDAMENTAL_RESET,
+ OPAL_ASSERT_RESET);
+ else if (option == EEH_RESET_HOT)
+ rc = opal_pci_reset(phb->opal_id,
+ OPAL_PCI_HOT_RESET,
+ OPAL_ASSERT_RESET);
+ else if (option == EEH_RESET_DEACTIVATE)
+ rc = opal_pci_reset(phb->opal_id,
+ OPAL_PCI_HOT_RESET,
+ OPAL_DEASSERT_RESET);
+ if (rc < 0)
+ goto out;
+
+ /* Poll state of the PHB until the request is done */
+ rc = ioda_eeh_phb_poll(phb);
+out:
+ if (rc != OPAL_SUCCESS)
+ return -EIO;
+
+ return 0;
+}
+
+static int ioda_eeh_bridge_reset(struct pci_controller *hose,
+ struct pci_dev *dev, int option)
+{
+ u16 ctrl;
+
+ pr_debug("%s: Reset device %04x:%02x:%02x.%01x with option %d\n",
+ __func__, hose->global_number, dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), option);
+
+ switch (option) {
+ case EEH_RESET_FUNDAMENTAL:
+ case EEH_RESET_HOT:
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+ ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+ break;
+ case EEH_RESET_DEACTIVATE:
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &ctrl);
+ ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, ctrl);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * ioda_eeh_reset - Reset the indicated PE
+ * @pe: EEH PE
+ * @option: reset option
+ *
+ * Do reset on the indicated PE. For PCI bus sensitive PE,
+ * we need to reset the parent p2p bridge. The PHB has to
+ * be reinitialized if the p2p bridge is root bridge. For
+ * PCI device sensitive PE, we will try to reset the device
+ * through FLR. For now, we don't have OPAL APIs to do HARD
+ * reset yet, so all reset would be SOFT (HOT) reset.
+ */
+static int ioda_eeh_reset(struct eeh_pe *pe, int option)
+{
+ struct pci_controller *hose = pe->phb;
+ struct eeh_dev *edev;
+ struct pci_dev *dev;
+ int ret;
+
+ /*
+ * Anyway, we have to clear the problematic state for the
+ * corresponding PE. However, we needn't do it if the PE
+ * is PHB associated. That means the PHB is having fatal
+ * errors and it needs reset. Further more, the AIB interface
+ * isn't reliable any more.
+ */
+ if (!(pe->type & EEH_PE_PHB) &&
+ (option == EEH_RESET_HOT ||
+ option == EEH_RESET_FUNDAMENTAL)) {
+ ret = ioda_eeh_pe_clear(pe);
+ if (ret)
+ return -EIO;
+ }
+
+ /*
+ * The rules applied to reset, either fundamental or hot reset:
+ *
+ * We always reset the direct upstream bridge of the PE. If the
+ * direct upstream bridge isn't root bridge, we always take hot
+ * reset no matter what option (fundamental or hot) is. Otherwise,
+ * we should do the reset according to the required option.
+ */
+ if (pe->type & EEH_PE_PHB) {
+ ret = ioda_eeh_phb_reset(hose, option);
+ } else {
+ if (pe->type & EEH_PE_DEVICE) {
+ /*
+ * If it's device PE, we didn't refer to the parent
+ * PCI bus yet. So we have to figure it out indirectly.
+ */
+ edev = list_first_entry(&pe->edevs,
+ struct eeh_dev, list);
+ dev = eeh_dev_to_pci_dev(edev);
+ dev = dev->bus->self;
+ } else {
+ /*
+ * If it's bus PE, the parent PCI bus is already there
+ * and just pick it up.
+ */
+ dev = pe->bus->self;
+ }
+
+ /*
+ * Do reset based on the fact that the direct upstream bridge
+ * is root bridge (port) or not.
+ */
+ if (dev->bus->number == 0)
+ ret = ioda_eeh_root_reset(hose, option);
+ else
+ ret = ioda_eeh_bridge_reset(hose, dev, option);
+ }
+
+ return ret;
+}
+
+/**
+ * ioda_eeh_get_log - Retrieve error log
+ * @pe: EEH PE
+ * @severity: Severity level of the log
+ * @drv_log: buffer to store the log
+ * @len: space of the log buffer
+ *
+ * The function is used to retrieve error log from P7IOC.
+ */
+static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
+ char *drv_log, unsigned long len)
+{
+ s64 ret;
+ unsigned long flags;
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+
+ spin_lock_irqsave(&phb->lock, flags);
+
+ ret = opal_pci_get_phb_diag_data2(phb->opal_id,
+ phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
+ if (ret) {
+ spin_unlock_irqrestore(&phb->lock, flags);
+ pr_warning("%s: Failed to get log for PHB#%x-PE#%x\n",
+ __func__, hose->global_number, pe->addr);
+ return -EIO;
+ }
+
+ /*
+ * FIXME: We probably need log the error in somewhere.
+ * Lets make it up in future.
+ */
+ /* pr_info("%s", phb->diag.blob); */
+
+ spin_unlock_irqrestore(&phb->lock, flags);
+
+ return 0;
+}
+
+/**
+ * ioda_eeh_configure_bridge - Configure the PCI bridges for the indicated PE
+ * @pe: EEH PE
+ *
+ * For particular PE, it might have included PCI bridges. In order
+ * to make the PE work properly, those PCI bridges should be configured
+ * correctly. However, we need do nothing on P7IOC since the reset
+ * function will do everything that should be covered by the function.
+ */
+static int ioda_eeh_configure_bridge(struct eeh_pe *pe)
+{
+ return 0;
+}
+
+static void ioda_eeh_hub_diag_common(struct OpalIoP7IOCErrorData *data)
+{
+ /* GEM */
+ pr_info(" GEM XFIR: %016llx\n", data->gemXfir);
+ pr_info(" GEM RFIR: %016llx\n", data->gemRfir);
+ pr_info(" GEM RIRQFIR: %016llx\n", data->gemRirqfir);
+ pr_info(" GEM Mask: %016llx\n", data->gemMask);
+ pr_info(" GEM RWOF: %016llx\n", data->gemRwof);
+
+ /* LEM */
+ pr_info(" LEM FIR: %016llx\n", data->lemFir);
+ pr_info(" LEM Error Mask: %016llx\n", data->lemErrMask);
+ pr_info(" LEM Action 0: %016llx\n", data->lemAction0);
+ pr_info(" LEM Action 1: %016llx\n", data->lemAction1);
+ pr_info(" LEM WOF: %016llx\n", data->lemWof);
+}
+
+static void ioda_eeh_hub_diag(struct pci_controller *hose)
+{
+ struct pnv_phb *phb = hose->private_data;
+ struct OpalIoP7IOCErrorData *data;
+ long rc;
+
+ data = (struct OpalIoP7IOCErrorData *)ioda_eeh_hub_diag;
+ rc = opal_pci_get_hub_diag_data(phb->hub_id, data, PAGE_SIZE);
+ if (rc != OPAL_SUCCESS) {
+ pr_warning("%s: Failed to get HUB#%llx diag-data (%ld)\n",
+ __func__, phb->hub_id, rc);
+ return;
+ }
+
+ switch (data->type) {
+ case OPAL_P7IOC_DIAG_TYPE_RGC:
+ pr_info("P7IOC diag-data for RGC\n\n");
+ ioda_eeh_hub_diag_common(data);
+ pr_info(" RGC Status: %016llx\n", data->rgc.rgcStatus);
+ pr_info(" RGC LDCP: %016llx\n", data->rgc.rgcLdcp);
+ break;
+ case OPAL_P7IOC_DIAG_TYPE_BI:
+ pr_info("P7IOC diag-data for BI %s\n\n",
+ data->bi.biDownbound ? "Downbound" : "Upbound");
+ ioda_eeh_hub_diag_common(data);
+ pr_info(" BI LDCP 0: %016llx\n", data->bi.biLdcp0);
+ pr_info(" BI LDCP 1: %016llx\n", data->bi.biLdcp1);
+ pr_info(" BI LDCP 2: %016llx\n", data->bi.biLdcp2);
+ pr_info(" BI Fence Status: %016llx\n", data->bi.biFenceStatus);
+ break;
+ case OPAL_P7IOC_DIAG_TYPE_CI:
+ pr_info("P7IOC diag-data for CI Port %d\\nn",
+ data->ci.ciPort);
+ ioda_eeh_hub_diag_common(data);
+ pr_info(" CI Port Status: %016llx\n", data->ci.ciPortStatus);
+ pr_info(" CI Port LDCP: %016llx\n", data->ci.ciPortLdcp);
+ break;
+ case OPAL_P7IOC_DIAG_TYPE_MISC:
+ pr_info("P7IOC diag-data for MISC\n\n");
+ ioda_eeh_hub_diag_common(data);
+ break;
+ case OPAL_P7IOC_DIAG_TYPE_I2C:
+ pr_info("P7IOC diag-data for I2C\n\n");
+ ioda_eeh_hub_diag_common(data);
+ break;
+ default:
+ pr_warning("%s: Invalid type of HUB#%llx diag-data (%d)\n",
+ __func__, phb->hub_id, data->type);
+ }
+}
+
+static void ioda_eeh_p7ioc_phb_diag(struct pci_controller *hose,
+ struct OpalIoPhbErrorCommon *common)
+{
+ struct OpalIoP7IOCPhbErrorData *data;
+ int i;
+
+ data = (struct OpalIoP7IOCPhbErrorData *)common;
+
+ pr_info("P7IOC PHB#%x Diag-data (Version: %d)\n\n",
+ hose->global_number, common->version);
+
+ pr_info(" brdgCtl: %08x\n", data->brdgCtl);
+
+ pr_info(" portStatusReg: %08x\n", data->portStatusReg);
+ pr_info(" rootCmplxStatus: %08x\n", data->rootCmplxStatus);
+ pr_info(" busAgentStatus: %08x\n", data->busAgentStatus);
+
+ pr_info(" deviceStatus: %08x\n", data->deviceStatus);
+ pr_info(" slotStatus: %08x\n", data->slotStatus);
+ pr_info(" linkStatus: %08x\n", data->linkStatus);
+ pr_info(" devCmdStatus: %08x\n", data->devCmdStatus);
+ pr_info(" devSecStatus: %08x\n", data->devSecStatus);
+
+ pr_info(" rootErrorStatus: %08x\n", data->rootErrorStatus);
+ pr_info(" uncorrErrorStatus: %08x\n", data->uncorrErrorStatus);
+ pr_info(" corrErrorStatus: %08x\n", data->corrErrorStatus);
+ pr_info(" tlpHdr1: %08x\n", data->tlpHdr1);
+ pr_info(" tlpHdr2: %08x\n", data->tlpHdr2);
+ pr_info(" tlpHdr3: %08x\n", data->tlpHdr3);
+ pr_info(" tlpHdr4: %08x\n", data->tlpHdr4);
+ pr_info(" sourceId: %08x\n", data->sourceId);
+
+ pr_info(" errorClass: %016llx\n", data->errorClass);
+ pr_info(" correlator: %016llx\n", data->correlator);
+ pr_info(" p7iocPlssr: %016llx\n", data->p7iocPlssr);
+ pr_info(" p7iocCsr: %016llx\n", data->p7iocCsr);
+ pr_info(" lemFir: %016llx\n", data->lemFir);
+ pr_info(" lemErrorMask: %016llx\n", data->lemErrorMask);
+ pr_info(" lemWOF: %016llx\n", data->lemWOF);
+ pr_info(" phbErrorStatus: %016llx\n", data->phbErrorStatus);
+ pr_info(" phbFirstErrorStatus: %016llx\n", data->phbFirstErrorStatus);
+ pr_info(" phbErrorLog0: %016llx\n", data->phbErrorLog0);
+ pr_info(" phbErrorLog1: %016llx\n", data->phbErrorLog1);
+ pr_info(" mmioErrorStatus: %016llx\n", data->mmioErrorStatus);
+ pr_info(" mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
+ pr_info(" mmioErrorLog0: %016llx\n", data->mmioErrorLog0);
+ pr_info(" mmioErrorLog1: %016llx\n", data->mmioErrorLog1);
+ pr_info(" dma0ErrorStatus: %016llx\n", data->dma0ErrorStatus);
+ pr_info(" dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
+ pr_info(" dma0ErrorLog0: %016llx\n", data->dma0ErrorLog0);
+ pr_info(" dma0ErrorLog1: %016llx\n", data->dma0ErrorLog1);
+ pr_info(" dma1ErrorStatus: %016llx\n", data->dma1ErrorStatus);
+ pr_info(" dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
+ pr_info(" dma1ErrorLog0: %016llx\n", data->dma1ErrorLog0);
+ pr_info(" dma1ErrorLog1: %016llx\n", data->dma1ErrorLog1);
+
+ for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
+ if ((data->pestA[i] >> 63) == 0 &&
+ (data->pestB[i] >> 63) == 0)
+ continue;
+
+ pr_info(" PE[%3d] PESTA: %016llx\n", i, data->pestA[i]);
+ pr_info(" PESTB: %016llx\n", data->pestB[i]);
+ }
+}
+
+static void ioda_eeh_phb_diag(struct pci_controller *hose)
+{
+ struct pnv_phb *phb = hose->private_data;
+ struct OpalIoPhbErrorCommon *common;
+ long rc;
+
+ common = (struct OpalIoPhbErrorCommon *)phb->diag.blob;
+ rc = opal_pci_get_phb_diag_data2(phb->opal_id, common, PAGE_SIZE);
+ if (rc != OPAL_SUCCESS) {
+ pr_warning("%s: Failed to get diag-data for PHB#%x (%ld)\n",
+ __func__, hose->global_number, rc);
+ return;
+ }
+
+ switch (common->ioType) {
+ case OPAL_PHB_ERROR_DATA_TYPE_P7IOC:
+ ioda_eeh_p7ioc_phb_diag(hose, common);
+ break;
+ default:
+ pr_warning("%s: Unrecognized I/O chip %d\n",
+ __func__, common->ioType);
+ }
+}
+
+static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
+ struct eeh_pe **pe)
+{
+ struct eeh_pe *phb_pe;
+
+ phb_pe = eeh_phb_pe_get(hose);
+ if (!phb_pe) {
+ pr_warning("%s Can't find PE for PHB#%d\n",
+ __func__, hose->global_number);
+ return -EEXIST;
+ }
+
+ *pe = phb_pe;
+ return 0;
+}
+
+static int ioda_eeh_get_pe(struct pci_controller *hose,
+ u16 pe_no, struct eeh_pe **pe)
+{
+ struct eeh_pe *phb_pe, *dev_pe;
+ struct eeh_dev dev;
+
+ /* Find the PHB PE */
+ if (ioda_eeh_get_phb_pe(hose, &phb_pe))
+ return -EEXIST;
+
+ /* Find the PE according to PE# */
+ memset(&dev, 0, sizeof(struct eeh_dev));
+ dev.phb = hose;
+ dev.pe_config_addr = pe_no;
+ dev_pe = eeh_pe_get(&dev);
+ if (!dev_pe) {
+ pr_warning("%s: Can't find PE for PHB#%x - PE#%x\n",
+ __func__, hose->global_number, pe_no);
+ return -EEXIST;
+ }
+
+ *pe = dev_pe;
+ return 0;
+}
+
+/**
+ * ioda_eeh_next_error - Retrieve next error for EEH core to handle
+ * @pe: The affected PE
+ *
+ * The function is expected to be called by EEH core while it gets
+ * special EEH event (without binding PE). The function calls to
+ * OPAL APIs for next error to handle. The informational error is
+ * handled internally by platform. However, the dead IOC, dead PHB,
+ * fenced PHB and frozen PE should be handled by EEH core eventually.
+ */
+static int ioda_eeh_next_error(struct eeh_pe **pe)
+{
+ struct pci_controller *hose, *tmp;
+ struct pnv_phb *phb;
+ u64 frozen_pe_no;
+ u16 err_type, severity;
+ long rc;
+ int ret = 1;
+
+ /*
+ * 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.
+ */
+ eeh_remove_event(NULL);
+ opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+ /*
+ * If the subordinate PCI buses of the PHB has been
+ * removed, we needn't take care of it any more.
+ */
+ phb = hose->private_data;
+ if (phb->eeh_state & PNV_EEH_STATE_REMOVED)
+ continue;
+
+ rc = opal_pci_next_error(phb->opal_id,
+ &frozen_pe_no, &err_type, &severity);
+
+ /* If OPAL API returns error, we needn't proceed */
+ if (rc != OPAL_SUCCESS) {
+ IODA_EEH_DBG("%s: Invalid return value on "
+ "PHB#%x (0x%lx) from opal_pci_next_error",
+ __func__, hose->global_number, rc);
+ continue;
+ }
+
+ /* If the PHB doesn't have error, stop processing */
+ if (err_type == OPAL_EEH_NO_ERROR ||
+ severity == OPAL_EEH_SEV_NO_ERROR) {
+ IODA_EEH_DBG("%s: No error found on PHB#%x\n",
+ __func__, hose->global_number);
+ continue;
+ }
+
+ /*
+ * Processing the error. We're expecting the error with
+ * highest priority reported upon multiple errors on the
+ * specific PHB.
+ */
+ IODA_EEH_DBG("%s: Error (%d, %d, %d) on PHB#%x\n",
+ err_type, severity, pe_no, hose->global_number);
+ switch (err_type) {
+ case OPAL_EEH_IOC_ERROR:
+ if (severity == OPAL_EEH_SEV_IOC_DEAD) {
+ list_for_each_entry_safe(hose, tmp,
+ &hose_list, list_node) {
+ phb = hose->private_data;
+ phb->eeh_state |= PNV_EEH_STATE_REMOVED;
+ }
+
+ pr_err("EEH: dead IOC detected\n");
+ ret = 4;
+ goto out;
+ } else if (severity == OPAL_EEH_SEV_INF) {
+ pr_info("EEH: IOC informative error "
+ "detected\n");
+ ioda_eeh_hub_diag(hose);
+ }
+
+ break;
+ case OPAL_EEH_PHB_ERROR:
+ if (severity == OPAL_EEH_SEV_PHB_DEAD) {
+ if (ioda_eeh_get_phb_pe(hose, pe))
+ break;
+
+ pr_err("EEH: dead PHB#%x detected\n",
+ hose->global_number);
+ phb->eeh_state |= PNV_EEH_STATE_REMOVED;
+ ret = 3;
+ goto out;
+ } else if (severity == OPAL_EEH_SEV_PHB_FENCED) {
+ if (ioda_eeh_get_phb_pe(hose, pe))
+ break;
+
+ pr_err("EEH: fenced PHB#%x detected\n",
+ hose->global_number);
+ ret = 2;
+ goto out;
+ } else if (severity == OPAL_EEH_SEV_INF) {
+ pr_info("EEH: PHB#%x informative error "
+ "detected\n",
+ hose->global_number);
+ ioda_eeh_phb_diag(hose);
+ }
+
+ break;
+ case OPAL_EEH_PE_ERROR:
+ if (ioda_eeh_get_pe(hose, frozen_pe_no, pe))
+ break;
+
+ pr_err("EEH: Frozen PE#%x on PHB#%x detected\n",
+ (*pe)->addr, (*pe)->phb->global_number);
+ ret = 1;
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+struct pnv_eeh_ops ioda_eeh_ops = {
+ .post_init = ioda_eeh_post_init,
+ .set_option = ioda_eeh_set_option,
+ .get_state = ioda_eeh_get_state,
+ .reset = ioda_eeh_reset,
+ .get_log = ioda_eeh_get_log,
+ .configure_bridge = ioda_eeh_configure_bridge,
+ .next_error = ioda_eeh_next_error
+};
diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c
new file mode 100644
index 000000000000..969cce73055a
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -0,0 +1,379 @@
+/*
+ * The file intends to implement the platform dependent EEH operations on
+ * powernv platform. Actually, the powernv was created in order to fully
+ * hypervisor support.
+ *
+ * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013.
+ *
+ * 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/atomic.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/rbtree.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+
+#include <asm/eeh.h>
+#include <asm/eeh_event.h>
+#include <asm/firmware.h>
+#include <asm/io.h>
+#include <asm/iommu.h>
+#include <asm/machdep.h>
+#include <asm/msi_bitmap.h>
+#include <asm/opal.h>
+#include <asm/ppc-pci.h>
+
+#include "powernv.h"
+#include "pci.h"
+
+/**
+ * powernv_eeh_init - EEH platform dependent initialization
+ *
+ * EEH platform dependent initialization on powernv
+ */
+static int powernv_eeh_init(void)
+{
+ /* We require OPALv3 */
+ if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
+ pr_warning("%s: OPALv3 is required !\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Set EEH probe mode */
+ eeh_probe_mode_set(EEH_PROBE_MODE_DEV);
+
+ return 0;
+}
+
+/**
+ * powernv_eeh_post_init - EEH platform dependent post initialization
+ *
+ * EEH platform dependent post initialization on powernv. When
+ * the function is called, the EEH PEs and devices should have
+ * been built. If the I/O cache staff has been built, EEH is
+ * ready to supply service.
+ */
+static int powernv_eeh_post_init(void)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb;
+ int ret = 0;
+
+ list_for_each_entry(hose, &hose_list, list_node) {
+ phb = hose->private_data;
+
+ if (phb->eeh_ops && phb->eeh_ops->post_init) {
+ ret = phb->eeh_ops->post_init(hose);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * powernv_eeh_dev_probe - Do probe on PCI device
+ * @dev: PCI device
+ * @flag: unused
+ *
+ * When EEH module is installed during system boot, all PCI devices
+ * are checked one by one to see if it supports EEH. The function
+ * is introduced for the purpose. By default, EEH has been enabled
+ * on all PCI devices. That's to say, we only need do necessary
+ * initialization on the corresponding eeh device and create PE
+ * accordingly.
+ *
+ * It's notable that's unsafe to retrieve the EEH device through
+ * the corresponding PCI device. During the PCI device hotplug, which
+ * was possiblly triggered by EEH core, the binding between EEH device
+ * and the PCI device isn't built yet.
+ */
+static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag)
+{
+ struct pci_controller *hose = pci_bus_to_host(dev->bus);
+ struct pnv_phb *phb = hose->private_data;
+ struct device_node *dn = pci_device_to_OF_node(dev);
+ struct eeh_dev *edev = of_node_to_eeh_dev(dn);
+
+ /*
+ * When probing the root bridge, which doesn't have any
+ * subordinate PCI devices. We don't have OF node for
+ * the root bridge. So it's not reasonable to continue
+ * the probing.
+ */
+ if (!dn || !edev)
+ return 0;
+
+ /* Skip for PCI-ISA bridge */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
+ return 0;
+
+ /* Initialize eeh device */
+ edev->class_code = dev->class;
+ edev->mode = 0;
+ edev->config_addr = ((dev->bus->number << 8) | dev->devfn);
+ edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff);
+
+ /* Create PE */
+ eeh_add_to_parent_pe(edev);
+
+ /*
+ * Enable EEH explicitly so that we will do EEH check
+ * while accessing I/O stuff
+ *
+ * FIXME: Enable that for PHB3 later
+ */
+ if (phb->type == PNV_PHB_IODA1)
+ eeh_subsystem_enabled = 1;
+
+ /* Save memory bars */
+ eeh_save_bars(edev);
+
+ return 0;
+}
+
+/**
+ * powernv_eeh_set_option - Initialize EEH or MMIO/DMA reenable
+ * @pe: EEH PE
+ * @option: operation to be issued
+ *
+ * The function is used to control the EEH functionality globally.
+ * Currently, following options are support according to PAPR:
+ * Enable EEH, Disable EEH, Enable MMIO and Enable DMA
+ */
+static int powernv_eeh_set_option(struct eeh_pe *pe, int option)
+{
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+ int ret = -EEXIST;
+
+ /*
+ * What we need do is pass it down for hardware
+ * implementation to handle it.
+ */
+ if (phb->eeh_ops && phb->eeh_ops->set_option)
+ ret = phb->eeh_ops->set_option(pe, option);
+
+ return ret;
+}
+
+/**
+ * powernv_eeh_get_pe_addr - Retrieve PE address
+ * @pe: EEH PE
+ *
+ * Retrieve the PE address according to the given tranditional
+ * PCI BDF (Bus/Device/Function) address.
+ */
+static int powernv_eeh_get_pe_addr(struct eeh_pe *pe)
+{
+ return pe->addr;
+}
+
+/**
+ * powernv_eeh_get_state - Retrieve PE state
+ * @pe: EEH PE
+ * @delay: delay while PE state is temporarily unavailable
+ *
+ * Retrieve the state of the specified PE. For IODA-compitable
+ * platform, it should be retrieved from IODA table. Therefore,
+ * we prefer passing down to hardware implementation to handle
+ * it.
+ */
+static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay)
+{
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+ int ret = EEH_STATE_NOT_SUPPORT;
+
+ if (phb->eeh_ops && phb->eeh_ops->get_state) {
+ ret = phb->eeh_ops->get_state(pe);
+
+ /*
+ * If the PE state is temporarily unavailable,
+ * to inform the EEH core delay for default
+ * period (1 second)
+ */
+ if (delay) {
+ *delay = 0;
+ if (ret & EEH_STATE_UNAVAILABLE)
+ *delay = 1000;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * powernv_eeh_reset - Reset the specified PE
+ * @pe: EEH PE
+ * @option: reset option
+ *
+ * Reset the specified PE
+ */
+static int powernv_eeh_reset(struct eeh_pe *pe, int option)
+{
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+ int ret = -EEXIST;
+
+ if (phb->eeh_ops && phb->eeh_ops->reset)
+ ret = phb->eeh_ops->reset(pe, option);
+
+ return ret;
+}
+
+/**
+ * powernv_eeh_wait_state - Wait for PE state
+ * @pe: EEH PE
+ * @max_wait: maximal period in microsecond
+ *
+ * Wait for the state of associated PE. It might take some time
+ * to retrieve the PE's state.
+ */
+static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait)
+{
+ int ret;
+ int mwait;
+
+ while (1) {
+ ret = powernv_eeh_get_state(pe, &mwait);
+
+ /*
+ * If the PE's state is temporarily unavailable,
+ * we have to wait for the specified time. Otherwise,
+ * the PE's state will be returned immediately.
+ */
+ if (ret != EEH_STATE_UNAVAILABLE)
+ return ret;
+
+ max_wait -= mwait;
+ if (max_wait <= 0) {
+ pr_warning("%s: Timeout getting PE#%x's state (%d)\n",
+ __func__, pe->addr, max_wait);
+ return EEH_STATE_NOT_SUPPORT;
+ }
+
+ msleep(mwait);
+ }
+
+ return EEH_STATE_NOT_SUPPORT;
+}
+
+/**
+ * powernv_eeh_get_log - Retrieve error log
+ * @pe: EEH PE
+ * @severity: temporary or permanent error log
+ * @drv_log: driver log to be combined with retrieved error log
+ * @len: length of driver log
+ *
+ * Retrieve the temporary or permanent error from the PE.
+ */
+static int powernv_eeh_get_log(struct eeh_pe *pe, int severity,
+ char *drv_log, unsigned long len)
+{
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+ int ret = -EEXIST;
+
+ if (phb->eeh_ops && phb->eeh_ops->get_log)
+ ret = phb->eeh_ops->get_log(pe, severity, drv_log, len);
+
+ return ret;
+}
+
+/**
+ * powernv_eeh_configure_bridge - Configure PCI bridges in the indicated PE
+ * @pe: EEH PE
+ *
+ * The function will be called to reconfigure the bridges included
+ * in the specified PE so that the mulfunctional PE would be recovered
+ * again.
+ */
+static int powernv_eeh_configure_bridge(struct eeh_pe *pe)
+{
+ struct pci_controller *hose = pe->phb;
+ struct pnv_phb *phb = hose->private_data;
+ int ret = 0;
+
+ if (phb->eeh_ops && phb->eeh_ops->configure_bridge)
+ ret = phb->eeh_ops->configure_bridge(pe);
+
+ return ret;
+}
+
+/**
+ * powernv_eeh_next_error - Retrieve next EEH error to handle
+ * @pe: Affected PE
+ *
+ * Using OPAL API, to retrieve next EEH error for EEH core to handle
+ */
+static int powernv_eeh_next_error(struct eeh_pe **pe)
+{
+ struct pci_controller *hose;
+ struct pnv_phb *phb = NULL;
+
+ list_for_each_entry(hose, &hose_list, list_node) {
+ phb = hose->private_data;
+ break;
+ }
+
+ if (phb && phb->eeh_ops->next_error)
+ return phb->eeh_ops->next_error(pe);
+
+ return -EEXIST;
+}
+
+static struct eeh_ops powernv_eeh_ops = {
+ .name = "powernv",
+ .init = powernv_eeh_init,
+ .post_init = powernv_eeh_post_init,
+ .of_probe = NULL,
+ .dev_probe = powernv_eeh_dev_probe,
+ .set_option = powernv_eeh_set_option,
+ .get_pe_addr = powernv_eeh_get_pe_addr,
+ .get_state = powernv_eeh_get_state,
+ .reset = powernv_eeh_reset,
+ .wait_state = powernv_eeh_wait_state,
+ .get_log = powernv_eeh_get_log,
+ .configure_bridge = powernv_eeh_configure_bridge,
+ .read_config = pnv_pci_cfg_read,
+ .write_config = pnv_pci_cfg_write,
+ .next_error = powernv_eeh_next_error
+};
+
+/**
+ * eeh_powernv_init - Register platform dependent EEH operations
+ *
+ * EEH initialization on powernv platform. This function should be
+ * called before any EEH related functions.
+ */
+static int __init eeh_powernv_init(void)
+{
+ int ret = -EINVAL;
+
+ if (!machine_is(powernv))
+ return ret;
+
+ ret = eeh_ops_register(&powernv_eeh_ops);
+ if (!ret)
+ pr_info("EEH: PowerNV platform initialized\n");
+ else
+ pr_info("EEH: Failed to initialize PowerNV platform (%d)\n", ret);
+
+ return ret;
+}
+
+early_initcall(eeh_powernv_init);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 6fabe92eafb6..e88863ffb135 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -107,4 +107,7 @@ OPAL_CALL(opal_pci_mask_pe_error, OPAL_PCI_MASK_PE_ERROR);
OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS);
OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS);
OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED);
+OPAL_CALL(opal_pci_next_error, OPAL_PCI_NEXT_ERROR);
+OPAL_CALL(opal_pci_poll, OPAL_PCI_POLL);
OPAL_CALL(opal_pci_msi_eoi, OPAL_PCI_MSI_EOI);
+OPAL_CALL(opal_pci_get_phb_diag_data2, OPAL_PCI_GET_PHB_DIAG_DATA2);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 628c564ceadb..106301fd2fa5 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/interrupt.h>
+#include <linux/notifier.h>
#include <linux/slab.h>
#include <asm/opal.h>
#include <asm/firmware.h>
@@ -31,6 +32,10 @@ static DEFINE_SPINLOCK(opal_write_lock);
extern u64 opal_mc_secondary_handler[];
static unsigned int *opal_irqs;
static unsigned int opal_irq_count;
+static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
+static DEFINE_SPINLOCK(opal_notifier_lock);
+static uint64_t last_notified_mask = 0x0ul;
+static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
int __init early_init_dt_scan_opal(unsigned long node,
const char *uname, int depth, void *data)
@@ -95,6 +100,68 @@ static int __init opal_register_exception_handlers(void)
early_initcall(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;
+}
+
+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;
+ uint64_t evt = 0;
+
+ atomic_set(&opal_notifier_hold, 0);
+
+ /* Process pending events */
+ rc = opal_poll_events(&evt);
+ if (rc == OPAL_SUCCESS && evt)
+ opal_do_notifier(evt);
+}
+
+void opal_notifier_disable(void)
+{
+ atomic_set(&opal_notifier_hold, 1);
+}
+
int opal_get_chars(uint32_t vtermno, char *buf, int count)
{
s64 len, rc;
@@ -297,7 +364,7 @@ static irqreturn_t opal_interrupt(int irq, void *data)
opal_handle_interrupt(virq_to_hw(irq), &events);
- /* XXX TODO: Do something with the events */
+ opal_do_notifier(events);
return IRQ_HANDLED;
}
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 9c9d15e4cdf2..49b57b9f835d 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -32,6 +33,7 @@
#include <asm/iommu.h>
#include <asm/tce.h>
#include <asm/xics.h>
+#include <asm/debug.h>
#include "powernv.h"
#include "pci.h"
@@ -441,6 +443,17 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
set_iommu_table_base(&pdev->dev, &pe->tce32_table);
}
+static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ set_iommu_table_base(&dev->dev, &pe->tce32_table);
+ if (dev->subordinate)
+ pnv_ioda_setup_bus_dma(pe, dev->subordinate);
+ }
+}
+
static void pnv_pci_ioda1_tce_invalidate(struct iommu_table *tbl,
u64 *startp, u64 *endp)
{
@@ -595,6 +608,12 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
TCE_PCI_SWINV_PAIR;
}
iommu_init_table(tbl, phb->hose->node);
+ iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
+
+ if (pe->pdev)
+ set_iommu_table_base(&pe->pdev->dev, tbl);
+ else
+ pnv_ioda_setup_bus_dma(pe, pe->pbus);
return;
fail:
@@ -667,6 +686,11 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
}
iommu_init_table(tbl, phb->hose->node);
+ if (pe->pdev)
+ set_iommu_table_base(&pe->pdev->dev, tbl);
+ else
+ pnv_ioda_setup_bus_dma(pe, pe->pbus);
+
return;
fail:
if (pe->tce32_seg >= 0)
@@ -968,11 +992,38 @@ static void pnv_pci_ioda_setup_DMA(void)
}
}
+static void pnv_pci_ioda_create_dbgfs(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ struct pci_controller *hose, *tmp;
+ struct pnv_phb *phb;
+ char name[16];
+
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+ phb = hose->private_data;
+
+ sprintf(name, "PCI%04x", hose->global_number);
+ phb->dbgfs = debugfs_create_dir(name, powerpc_debugfs_root);
+ if (!phb->dbgfs)
+ pr_warning("%s: Error on creating debugfs on PHB#%x\n",
+ __func__, hose->global_number);
+ }
+#endif /* CONFIG_DEBUG_FS */
+}
+
static void pnv_pci_ioda_fixup(void)
{
pnv_pci_ioda_setup_PEs();
pnv_pci_ioda_setup_seg();
pnv_pci_ioda_setup_DMA();
+
+ pnv_pci_ioda_create_dbgfs();
+
+#ifdef CONFIG_EEH
+ eeh_probe_mode_set(EEH_PROBE_MODE_DEV);
+ eeh_addr_cache_build();
+ eeh_init();
+#endif
}
/*
@@ -1049,7 +1100,8 @@ static void pnv_pci_ioda_shutdown(struct pnv_phb *phb)
OPAL_ASSERT_RESET);
}
-void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type)
+void __init pnv_pci_init_ioda_phb(struct device_node *np,
+ u64 hub_id, int ioda_type)
{
struct pci_controller *hose;
static int primary = 1;
@@ -1087,6 +1139,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type)
hose->first_busno = 0;
hose->last_busno = 0xff;
hose->private_data = phb;
+ phb->hub_id = hub_id;
phb->opal_id = phb_id;
phb->type = ioda_type;
@@ -1172,6 +1225,9 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type)
phb->ioda.io_size, phb->ioda.io_segsize);
phb->hose->ops = &pnv_pci_ops;
+#ifdef CONFIG_EEH
+ phb->eeh_ops = &ioda_eeh_ops;
+#endif
/* Setup RID -> PE mapping function */
phb->bdfn_to_pe = pnv_ioda_bdfn_to_pe;
@@ -1212,7 +1268,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type)
void pnv_pci_init_ioda2_phb(struct device_node *np)
{
- pnv_pci_init_ioda_phb(np, PNV_PHB_IODA2);
+ pnv_pci_init_ioda_phb(np, 0, PNV_PHB_IODA2);
}
void __init pnv_pci_init_ioda_hub(struct device_node *np)
@@ -1235,6 +1291,6 @@ void __init pnv_pci_init_ioda_hub(struct device_node *np)
for_each_child_of_node(np, phbn) {
/* Look for IODA1 PHBs */
if (of_device_is_compatible(phbn, "ibm,ioda-phb"))
- pnv_pci_init_ioda_phb(phbn, PNV_PHB_IODA1);
+ pnv_pci_init_ioda_phb(phbn, hub_id, PNV_PHB_IODA1);
}
}
diff --git a/arch/powerpc/platforms/powernv/pci-p5ioc2.c b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
index 92b37a0186c9..b68db6325c1b 100644
--- a/arch/powerpc/platforms/powernv/pci-p5ioc2.c
+++ b/arch/powerpc/platforms/powernv/pci-p5ioc2.c
@@ -86,13 +86,16 @@ static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { }
static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb,
struct pci_dev *pdev)
{
- if (phb->p5ioc2.iommu_table.it_map == NULL)
+ 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,
+ pci_domain_nr(phb->hose->bus), phb->opal_id);
+ }
set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table);
}
-static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np,
+static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
void *tce_mem, u64 tce_size)
{
struct pnv_phb *phb;
@@ -133,6 +136,7 @@ static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np,
phb->hose->first_busno = 0;
phb->hose->last_busno = 0xff;
phb->hose->private_data = phb;
+ phb->hub_id = hub_id;
phb->opal_id = phb_id;
phb->type = PNV_PHB_P5IOC2;
phb->model = PNV_PHB_MODEL_P5IOC2;
@@ -226,7 +230,8 @@ void __init pnv_pci_init_p5ioc2_hub(struct device_node *np)
for_each_child_of_node(np, phbn) {
if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") ||
of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) {
- pnv_pci_init_p5ioc2_phb(phbn, tce_mem, tce_per_phb);
+ pnv_pci_init_p5ioc2_phb(phbn, hub_id,
+ tce_mem, tce_per_phb);
tce_mem += tce_per_phb;
}
}
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 277343cc6a3d..a28d3b5e6393 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -20,6 +20,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/msi.h>
+#include <linux/iommu.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -32,6 +33,8 @@
#include <asm/iommu.h>
#include <asm/tce.h>
#include <asm/firmware.h>
+#include <asm/eeh_event.h>
+#include <asm/eeh.h>
#include "powernv.h"
#include "pci.h"
@@ -202,7 +205,8 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
spin_lock_irqsave(&phb->lock, flags);
- rc = opal_pci_get_phb_diag_data(phb->opal_id, phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE);
+ rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
+ PNV_PCI_DIAG_BUF_SIZE);
has_diag = (rc == OPAL_SUCCESS);
rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
@@ -227,43 +231,50 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
spin_unlock_irqrestore(&phb->lock, flags);
}
-static void pnv_pci_config_check_eeh(struct pnv_phb *phb, struct pci_bus *bus,
- u32 bdfn)
+static void pnv_pci_config_check_eeh(struct pnv_phb *phb,
+ struct device_node *dn)
{
s64 rc;
u8 fstate;
u16 pcierr;
u32 pe_no;
- /* Get PE# if we support IODA */
- pe_no = phb->bdfn_to_pe ? phb->bdfn_to_pe(phb, bus, bdfn & 0xff) : 0;
+ /*
+ * Get the PE#. During the PCI probe stage, we might not
+ * setup that yet. So all ER errors should be mapped to
+ * PE#0
+ */
+ pe_no = PCI_DN(dn)->pe_number;
+ if (pe_no == IODA_INVALID_PE)
+ pe_no = 0;
/* Read freeze status */
rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr,
NULL);
if (rc) {
- pr_warning("PCI %d: Failed to read EEH status for PE#%d,"
- " err %lld\n", phb->hose->global_number, pe_no, rc);
+ pr_warning("%s: Can't read EEH status (PE#%d) for "
+ "%s, err %lld\n",
+ __func__, pe_no, dn->full_name, rc);
return;
}
- cfg_dbg(" -> EEH check, bdfn=%04x PE%d fstate=%x\n",
- bdfn, pe_no, fstate);
+ cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n",
+ (PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn),
+ pe_no, fstate);
if (fstate != 0)
pnv_pci_handle_eeh_config(phb, pe_no);
}
-static int pnv_pci_read_config(struct pci_bus *bus,
- unsigned int devfn,
- int where, int size, u32 *val)
+int pnv_pci_cfg_read(struct device_node *dn,
+ int where, int size, u32 *val)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct pnv_phb *phb = hose->private_data;
- u32 bdfn = (((uint64_t)bus->number) << 8) | devfn;
+ struct pci_dn *pdn = PCI_DN(dn);
+ struct pnv_phb *phb = pdn->phb->private_data;
+ u32 bdfn = (pdn->busno << 8) | pdn->devfn;
+#ifdef CONFIG_EEH
+ struct eeh_pe *phb_pe = NULL;
+#endif
s64 rc;
- if (hose == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
switch (size) {
case 1: {
u8 v8;
@@ -287,28 +298,43 @@ static int pnv_pci_read_config(struct pci_bus *bus,
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
- cfg_dbg("pnv_pci_read_config bus: %x devfn: %x +%x/%x -> %08x\n",
- bus->number, devfn, where, size, *val);
-
- /* Check if the PHB got frozen due to an error (no response) */
- pnv_pci_config_check_eeh(phb, bus, bdfn);
+ cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
+ __func__, pdn->busno, pdn->devfn, where, size, *val);
+
+ /*
+ * Check if the specified PE has been put into frozen
+ * state. On the other hand, we needn't do that while
+ * the PHB has been put into frozen state because of
+ * PHB-fatal errors.
+ */
+#ifdef CONFIG_EEH
+ phb_pe = eeh_phb_pe_get(pdn->phb);
+ if (phb_pe && (phb_pe->state & EEH_PE_ISOLATED))
+ return PCIBIOS_SUCCESSFUL;
+
+ if (phb->eeh_state & PNV_EEH_STATE_ENABLED) {
+ if (*val == EEH_IO_ERROR_VALUE(size) &&
+ eeh_dev_check_failure(of_node_to_eeh_dev(dn)))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else {
+ pnv_pci_config_check_eeh(phb, dn);
+ }
+#else
+ pnv_pci_config_check_eeh(phb, dn);
+#endif
return PCIBIOS_SUCCESSFUL;
}
-static int pnv_pci_write_config(struct pci_bus *bus,
- unsigned int devfn,
- int where, int size, u32 val)
+int pnv_pci_cfg_write(struct device_node *dn,
+ int where, int size, u32 val)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct pnv_phb *phb = hose->private_data;
- u32 bdfn = (((uint64_t)bus->number) << 8) | devfn;
-
- if (hose == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
+ struct pci_dn *pdn = PCI_DN(dn);
+ struct pnv_phb *phb = pdn->phb->private_data;
+ u32 bdfn = (pdn->busno << 8) | pdn->devfn;
- cfg_dbg("pnv_pci_write_config bus: %x devfn: %x +%x/%x -> %08x\n",
- bus->number, devfn, where, size, val);
+ cfg_dbg("%s: bus: %x devfn: %x +%x/%x -> %08x\n",
+ pdn->busno, pdn->devfn, where, size, val);
switch (size) {
case 1:
opal_pci_config_write_byte(phb->opal_id, bdfn, where, val);
@@ -322,14 +348,54 @@ static int pnv_pci_write_config(struct pci_bus *bus,
default:
return PCIBIOS_FUNC_NOT_SUPPORTED;
}
+
/* Check if the PHB got frozen due to an error (no response) */
- pnv_pci_config_check_eeh(phb, bus, bdfn);
+#ifdef CONFIG_EEH
+ if (!(phb->eeh_state & PNV_EEH_STATE_ENABLED))
+ pnv_pci_config_check_eeh(phb, dn);
+#else
+ pnv_pci_config_check_eeh(phb, dn);
+#endif
return PCIBIOS_SUCCESSFUL;
}
+static int pnv_pci_read_config(struct pci_bus *bus,
+ unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
+ struct pci_dn *pdn;
+
+ for (dn = busdn->child; dn; dn = dn->sibling) {
+ pdn = PCI_DN(dn);
+ if (pdn && pdn->devfn == devfn)
+ return pnv_pci_cfg_read(dn, where, size, val);
+ }
+
+ *val = 0xFFFFFFFF;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+}
+
+static int pnv_pci_write_config(struct pci_bus *bus,
+ unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct device_node *dn, *busdn = pci_bus_to_OF_node(bus);
+ struct pci_dn *pdn;
+
+ for (dn = busdn->child; dn; dn = dn->sibling) {
+ pdn = PCI_DN(dn);
+ if (pdn && pdn->devfn == devfn)
+ return pnv_pci_cfg_write(dn, where, size, val);
+ }
+
+ return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
struct pci_ops pnv_pci_ops = {
- .read = pnv_pci_read_config,
+ .read = pnv_pci_read_config,
.write = pnv_pci_write_config,
};
@@ -412,6 +478,7 @@ static struct iommu_table *pnv_pci_setup_bml_iommu(struct pci_controller *hose)
pnv_pci_setup_iommu_table(tbl, __va(be64_to_cpup(basep)),
be32_to_cpup(sizep), 0);
iommu_init_table(tbl, hose->node);
+ iommu_register_group(tbl, pci_domain_nr(hose->bus), 0);
/* Deal with SW invalidated TCEs when needed (BML way) */
swinvp = of_get_property(hose->dn, "linux,tce-sw-invalidate-info",
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 25d76c4df50b..d633c64e05a1 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -66,15 +66,43 @@ struct pnv_ioda_pe {
struct list_head list;
};
+/* IOC dependent EEH operations */
+#ifdef CONFIG_EEH
+struct pnv_eeh_ops {
+ int (*post_init)(struct pci_controller *hose);
+ int (*set_option)(struct eeh_pe *pe, int option);
+ int (*get_state)(struct eeh_pe *pe);
+ int (*reset)(struct eeh_pe *pe, int option);
+ int (*get_log)(struct eeh_pe *pe, int severity,
+ char *drv_log, unsigned long len);
+ int (*configure_bridge)(struct eeh_pe *pe);
+ int (*next_error)(struct eeh_pe **pe);
+};
+
+#define PNV_EEH_STATE_ENABLED (1 << 0) /* EEH enabled */
+#define PNV_EEH_STATE_REMOVED (1 << 1) /* PHB removed */
+
+#endif /* CONFIG_EEH */
+
struct pnv_phb {
struct pci_controller *hose;
enum pnv_phb_type type;
enum pnv_phb_model model;
+ u64 hub_id;
u64 opal_id;
void __iomem *regs;
int initialized;
spinlock_t lock;
+#ifdef CONFIG_EEH
+ struct pnv_eeh_ops *eeh_ops;
+ int eeh_state;
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dbgfs;
+#endif
+
#ifdef CONFIG_PCI_MSI
unsigned int msi_base;
unsigned int msi32_support;
@@ -150,7 +178,14 @@ struct pnv_phb {
};
extern struct pci_ops pnv_pci_ops;
+#ifdef CONFIG_EEH
+extern struct pnv_eeh_ops ioda_eeh_ops;
+#endif
+int pnv_pci_cfg_read(struct device_node *dn,
+ int where, int size, u32 *val);
+int pnv_pci_cfg_write(struct device_node *dn,
+ int where, int size, u32 val);
extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
void *tce_mem, u64 tce_size,
u64 dma_offset);
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index d4459bfc92f7..84438af96c05 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -93,6 +93,8 @@ static void __noreturn pnv_restart(char *cmd)
{
long rc = OPAL_BUSY;
+ opal_notifier_disable();
+
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
rc = opal_cec_reboot();
if (rc == OPAL_BUSY_EVENT)
@@ -108,6 +110,8 @@ static void __noreturn pnv_power_off(void)
{
long rc = OPAL_BUSY;
+ opal_notifier_disable();
+
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
rc = opal_cec_power_down(0);
if (rc == OPAL_BUSY_EVENT)
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index 88c9459c3e07..89e3857af4e0 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -40,7 +40,7 @@
#define DBG(fmt...)
#endif
-static void __cpuinit pnv_smp_setup_cpu(int cpu)
+static void pnv_smp_setup_cpu(int cpu)
{
if (cpu != boot_cpuid)
xics_setup_cpu();
@@ -51,7 +51,7 @@ static int pnv_smp_cpu_bootable(unsigned int nr)
/* Special case - we inhibit secondary thread startup
* during boot if the user requests it.
*/
- if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) {
+ if (system_state == SYSTEM_BOOTING && cpu_has_feature(CPU_FTR_SMT)) {
if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
if (smt_enabled_at_boot
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 177a2f70700c..3e270e3412ae 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -109,7 +109,8 @@ static long ps3_hpte_remove(unsigned long hpte_group)
}
static long ps3_hpte_updatepp(unsigned long slot, unsigned long newpp,
- unsigned long vpn, int psize, int ssize, int local)
+ unsigned long vpn, int psize, int apsize,
+ int ssize, int local)
{
int result;
u64 hpte_v, want_v, hpte_rs;
@@ -162,7 +163,7 @@ static void ps3_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
}
static void ps3_hpte_invalidate(unsigned long slot, unsigned long vpn,
- int psize, int ssize, int local)
+ int psize, int apsize, int ssize, int local)
{
unsigned long flags;
int result;
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 4459eff7a75a..1bd3399146ed 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -33,11 +33,6 @@ config PPC_SPLPAR
processors, that is, which share physical processors between
two or more partitions.
-config EEH
- bool
- depends on PPC_PSERIES && PCI
- default y
-
config PSERIES_MSI
bool
depends on PCI_MSI && EEH
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 53866e537a92..8ae010381316 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -6,9 +6,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
firmware.o power.o dlpar.o mobility.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SCANLOG) += scanlog.o
-obj-$(CONFIG_EEH) += eeh.o eeh_pe.o eeh_dev.o eeh_cache.o \
- eeh_driver.o eeh_event.o eeh_sysfs.o \
- eeh_pseries.o
+obj-$(CONFIG_EEH) += eeh_pseries.o
obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
obj-$(CONFIG_PSERIES_MSI) += msi.o
diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c
index ef9d9d84c7d5..5ea88d1541f7 100644
--- a/arch/powerpc/platforms/pseries/io_event_irq.c
+++ b/arch/powerpc/platforms/pseries/io_event_irq.c
@@ -115,7 +115,7 @@ static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
* by scope or event type alone. For example, Torrent ISR route change
* event is reported with scope 0x00 (Not Applicatable) rather than
* 0x3B (Torrent-hub). It is better to let the clients to identify
- * who owns the the event.
+ * who owns the event.
*/
static irqreturn_t ioei_interrupt(int irq, void *dev_id)
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 86ae364900d6..23fc1dcf4434 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -614,6 +614,7 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
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);
/* Divide the rest (1.75GB) among the children */
pci->phb->dma_window_size = 0x80000000ul;
@@ -658,6 +659,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
ppci->phb->node);
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);
}
}
@@ -684,6 +686,7 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
phb->node);
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(&dev->dev, PCI_DN(dn)->iommu_table);
return;
}
@@ -1184,6 +1187,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
pci->phb->node);
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);
} else {
pr_debug(" found DMA window, table: %p\n", pci->iommu_table);
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 6d62072a7d5a..02d6e21619bb 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -45,6 +45,13 @@
#include "plpar_wrappers.h"
#include "pseries.h"
+/* Flag bits for H_BULK_REMOVE */
+#define HBR_REQUEST 0x4000000000000000UL
+#define HBR_RESPONSE 0x8000000000000000UL
+#define HBR_END 0xc000000000000000UL
+#define HBR_AVPN 0x0200000000000000UL
+#define HBR_ANDCOND 0x0100000000000000UL
+
/* in hvCall.S */
EXPORT_SYMBOL(plpar_hcall);
@@ -64,6 +71,9 @@ void vpa_init(int cpu)
if (cpu_has_feature(CPU_FTR_ALTIVEC))
lppaca_of(cpu).vmxregs_in_use = 1;
+ if (cpu_has_feature(CPU_FTR_ARCH_207S))
+ lppaca_of(cpu).ebb_regs_in_use = 1;
+
addr = __pa(&lppaca_of(cpu));
ret = register_vpa(hwcpu, addr);
@@ -240,7 +250,8 @@ static void pSeries_lpar_hptab_clear(void)
static long pSeries_lpar_hpte_updatepp(unsigned long slot,
unsigned long newpp,
unsigned long vpn,
- int psize, int ssize, int local)
+ int psize, int apsize,
+ int ssize, int local)
{
unsigned long lpar_rc;
unsigned long flags = (newpp & 7) | H_AVPN;
@@ -328,7 +339,8 @@ static void pSeries_lpar_hpte_updateboltedpp(unsigned long newpp,
}
static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
- int psize, int ssize, int local)
+ int psize, int apsize,
+ int ssize, int local)
{
unsigned long want_v;
unsigned long lpar_rc;
@@ -345,6 +357,113 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long vpn,
BUG_ON(lpar_rc != H_SUCCESS);
}
+/*
+ * Limit iterations holding pSeries_lpar_tlbie_lock to 3. We also need
+ * to make sure that we avoid bouncing the hypervisor tlbie lock.
+ */
+#define PPC64_HUGE_HPTE_BATCH 12
+
+static void __pSeries_lpar_hugepage_invalidate(unsigned long *slot,
+ unsigned long *vpn, int count,
+ int psize, int ssize)
+{
+ unsigned long param[8];
+ int i = 0, pix = 0, rc;
+ unsigned long flags = 0;
+ int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
+
+ if (lock_tlbie)
+ spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
+
+ for (i = 0; i < count; i++) {
+
+ if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
+ pSeries_lpar_hpte_invalidate(slot[i], vpn[i], psize, 0,
+ ssize, 0);
+ } else {
+ param[pix] = HBR_REQUEST | HBR_AVPN | slot[i];
+ param[pix+1] = hpte_encode_avpn(vpn[i], psize, ssize);
+ pix += 2;
+ if (pix == 8) {
+ rc = plpar_hcall9(H_BULK_REMOVE, param,
+ param[0], param[1], param[2],
+ param[3], param[4], param[5],
+ param[6], param[7]);
+ BUG_ON(rc != H_SUCCESS);
+ pix = 0;
+ }
+ }
+ }
+ if (pix) {
+ param[pix] = HBR_END;
+ rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1],
+ param[2], param[3], param[4], param[5],
+ param[6], param[7]);
+ BUG_ON(rc != H_SUCCESS);
+ }
+
+ if (lock_tlbie)
+ spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
+}
+
+static void pSeries_lpar_hugepage_invalidate(struct mm_struct *mm,
+ unsigned char *hpte_slot_array,
+ unsigned long addr, int psize)
+{
+ int ssize = 0, i, index = 0;
+ unsigned long s_addr = addr;
+ unsigned int max_hpte_count, valid;
+ unsigned long vpn_array[PPC64_HUGE_HPTE_BATCH];
+ unsigned long slot_array[PPC64_HUGE_HPTE_BATCH];
+ unsigned long shift, hidx, vpn = 0, vsid, hash, slot;
+
+ shift = mmu_psize_defs[psize].shift;
+ max_hpte_count = 1U << (PMD_SHIFT - shift);
+
+ for (i = 0; i < max_hpte_count; i++) {
+ valid = hpte_valid(hpte_slot_array, i);
+ if (!valid)
+ continue;
+ hidx = hpte_hash_index(hpte_slot_array, i);
+
+ /* get the vpn */
+ addr = s_addr + (i * (1ul << shift));
+ if (!is_kernel_addr(addr)) {
+ ssize = user_segment_size(addr);
+ vsid = get_vsid(mm->context.id, addr, ssize);
+ WARN_ON(vsid == 0);
+ } else {
+ vsid = get_kernel_vsid(addr, mmu_kernel_ssize);
+ ssize = mmu_kernel_ssize;
+ }
+
+ vpn = hpt_vpn(addr, vsid, ssize);
+ hash = hpt_hash(vpn, shift, ssize);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+
+ slot_array[index] = slot;
+ vpn_array[index] = vpn;
+ if (index == PPC64_HUGE_HPTE_BATCH - 1) {
+ /*
+ * Now do a bluk invalidate
+ */
+ __pSeries_lpar_hugepage_invalidate(slot_array,
+ vpn_array,
+ PPC64_HUGE_HPTE_BATCH,
+ psize, ssize);
+ index = 0;
+ } else
+ index++;
+ }
+ if (index)
+ __pSeries_lpar_hugepage_invalidate(slot_array, vpn_array,
+ index, psize, ssize);
+}
+
static void pSeries_lpar_hpte_removebolted(unsigned long ea,
int psize, int ssize)
{
@@ -356,17 +475,12 @@ static void pSeries_lpar_hpte_removebolted(unsigned long ea,
slot = pSeries_lpar_hpte_find(vpn, psize, ssize);
BUG_ON(slot == -1);
-
- pSeries_lpar_hpte_invalidate(slot, vpn, psize, ssize, 0);
+ /*
+ * lpar doesn't use the passed actual page size
+ */
+ pSeries_lpar_hpte_invalidate(slot, vpn, psize, 0, ssize, 0);
}
-/* Flag bits for H_BULK_REMOVE */
-#define HBR_REQUEST 0x4000000000000000UL
-#define HBR_RESPONSE 0x8000000000000000UL
-#define HBR_END 0xc000000000000000UL
-#define HBR_AVPN 0x0200000000000000UL
-#define HBR_ANDCOND 0x0100000000000000UL
-
/*
* Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
* lock.
@@ -400,8 +514,11 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
slot += hidx & _PTEIDX_GROUP_IX;
if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
+ /*
+ * lpar doesn't use the passed actual page size
+ */
pSeries_lpar_hpte_invalidate(slot, vpn, psize,
- ssize, local);
+ 0, ssize, local);
} else {
param[pix] = HBR_REQUEST | HBR_AVPN | slot;
param[pix+1] = hpte_encode_avpn(vpn, psize,
@@ -452,6 +569,7 @@ void __init hpte_init_lpar(void)
ppc_md.hpte_removebolted = pSeries_lpar_hpte_removebolted;
ppc_md.flush_hash_range = pSeries_lpar_flush_hash_range;
ppc_md.hpte_clear_all = pSeries_lpar_hptab_clear;
+ ppc_md.hugepage_invalidate = pSeries_lpar_hugepage_invalidate;
}
#ifdef CONFIG_PPC_SMLPAR
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 8733a86ad52e..9f8671a44551 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -18,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/kmsg_dump.h>
+#include <linux/pstore.h>
#include <linux/ctype.h>
#include <linux/zlib.h>
#include <asm/uaccess.h>
@@ -29,6 +30,13 @@
/* Max bytes to read/write in one go */
#define NVRW_CNT 0x20
+/*
+ * Set oops header version to distingush between old and new format header.
+ * lnx,oops-log partition max size is 4000, header version > 4000 will
+ * help in identifying new header.
+ */
+#define OOPS_HDR_VERSION 5000
+
static unsigned int nvram_size;
static int nvram_fetch, nvram_store;
static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
@@ -45,20 +53,23 @@ struct nvram_os_partition {
int min_size; /* minimum acceptable size (0 means req_size) */
long size; /* size of data portion (excluding err_log_info) */
long index; /* offset of data portion of partition */
+ bool os_partition; /* partition initialized by OS, not FW */
};
static struct nvram_os_partition rtas_log_partition = {
.name = "ibm,rtas-log",
.req_size = 2079,
.min_size = 1055,
- .index = -1
+ .index = -1,
+ .os_partition = true
};
static struct nvram_os_partition oops_log_partition = {
.name = "lnx,oops-log",
.req_size = 4000,
.min_size = 2000,
- .index = -1
+ .index = -1,
+ .os_partition = true
};
static const char *pseries_nvram_os_partitions[] = {
@@ -67,6 +78,12 @@ static const char *pseries_nvram_os_partitions[] = {
NULL
};
+struct oops_log_info {
+ u16 version;
+ u16 report_length;
+ u64 timestamp;
+} __attribute__((packed));
+
static void oops_to_nvram(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason);
@@ -83,28 +100,28 @@ static unsigned long last_unread_rtas_event; /* timestamp */
* big_oops_buf[] holds the uncompressed text we're capturing.
*
- * oops_buf[] holds the compressed text, preceded by a prefix.
- * The prefix is just a u16 holding the length of the compressed* text.
- * (*Or uncompressed, if compression fails.) oops_buf[] gets written
- * to NVRAM.
+ * oops_buf[] holds the compressed text, preceded by a oops header.
+ * oops header has u16 holding the version of oops header (to differentiate
+ * between old and new format header) followed by u16 holding the length of
+ * the compressed* text (*Or uncompressed, if compression fails.) and u64
+ * holding the timestamp. oops_buf[] gets written to NVRAM.
*
- * oops_len points to the prefix. oops_data points to the compressed text.
+ * oops_log_info points to the header. oops_data points to the compressed text.
*
* +- oops_buf
- * | +- oops_data
- * v v
- * +------------+-----------------------------------------------+
- * | length | text |
- * | (2 bytes) | (oops_data_sz bytes) |
- * +------------+-----------------------------------------------+
+ * | +- oops_data
+ * v v
+ * +-----------+-----------+-----------+------------------------+
+ * | version | length | timestamp | text |
+ * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) |
+ * +-----------+-----------+-----------+------------------------+
* ^
- * +- oops_len
+ * +- oops_log_info
*
* We preallocate these buffers during init to avoid kmalloc during oops/panic.
*/
static size_t big_oops_buf_sz;
static char *big_oops_buf, *oops_buf;
-static u16 *oops_len;
static char *oops_data;
static size_t oops_data_sz;
@@ -114,6 +131,30 @@ static size_t oops_data_sz;
#define MEM_LEVEL 4
static struct z_stream_s stream;
+#ifdef CONFIG_PSTORE
+static struct nvram_os_partition of_config_partition = {
+ .name = "of-config",
+ .index = -1,
+ .os_partition = false
+};
+
+static struct nvram_os_partition common_partition = {
+ .name = "common",
+ .index = -1,
+ .os_partition = false
+};
+
+static enum pstore_type_id nvram_type_ids[] = {
+ PSTORE_TYPE_DMESG,
+ PSTORE_TYPE_PPC_RTAS,
+ PSTORE_TYPE_PPC_OF,
+ PSTORE_TYPE_PPC_COMMON,
+ -1
+};
+static int read_type;
+static unsigned long last_rtas_event;
+#endif
+
static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
{
unsigned int i;
@@ -275,48 +316,72 @@ int nvram_write_error_log(char * buff, int length,
{
int rc = nvram_write_os_partition(&rtas_log_partition, buff, length,
err_type, error_log_cnt);
- if (!rc)
+ if (!rc) {
last_unread_rtas_event = get_seconds();
+#ifdef CONFIG_PSTORE
+ last_rtas_event = get_seconds();
+#endif
+ }
+
return rc;
}
-/* nvram_read_error_log
+/* nvram_read_partition
*
- * Reads nvram for error log for at most 'length'
+ * Reads nvram partition for at most 'length'
*/
-int nvram_read_error_log(char * buff, int length,
- unsigned int * err_type, unsigned int * error_log_cnt)
+int nvram_read_partition(struct nvram_os_partition *part, char *buff,
+ int length, unsigned int *err_type,
+ unsigned int *error_log_cnt)
{
int rc;
loff_t tmp_index;
struct err_log_info info;
- if (rtas_log_partition.index == -1)
+ if (part->index == -1)
return -1;
- if (length > rtas_log_partition.size)
- length = rtas_log_partition.size;
+ if (length > part->size)
+ length = part->size;
- tmp_index = rtas_log_partition.index;
+ tmp_index = part->index;
- rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
- if (rc <= 0) {
- printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
- return rc;
+ if (part->os_partition) {
+ rc = ppc_md.nvram_read((char *)&info,
+ sizeof(struct err_log_info),
+ &tmp_index);
+ if (rc <= 0) {
+ pr_err("%s: Failed nvram_read (%d)\n", __FUNCTION__,
+ rc);
+ return rc;
+ }
}
rc = ppc_md.nvram_read(buff, length, &tmp_index);
if (rc <= 0) {
- printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
+ pr_err("%s: Failed nvram_read (%d)\n", __FUNCTION__, rc);
return rc;
}
- *error_log_cnt = info.seq_num;
- *err_type = info.error_type;
+ if (part->os_partition) {
+ *error_log_cnt = info.seq_num;
+ *err_type = info.error_type;
+ }
return 0;
}
+/* nvram_read_error_log
+ *
+ * Reads nvram for error log for at most 'length'
+ */
+int nvram_read_error_log(char *buff, int length,
+ unsigned int *err_type, unsigned int *error_log_cnt)
+{
+ return nvram_read_partition(&rtas_log_partition, buff, length,
+ err_type, error_log_cnt);
+}
+
/* This doesn't actually zero anything, but it sets the event_logged
* word to tell that this event is safely in syslog.
*/
@@ -405,6 +470,349 @@ static int __init pseries_nvram_init_os_partition(struct nvram_os_partition
return 0;
}
+/*
+ * Are we using the ibm,rtas-log for oops/panic reports? And if so,
+ * would logging this oops/panic overwrite an RTAS event that rtas_errd
+ * hasn't had a chance to read and process? Return 1 if so, else 0.
+ *
+ * We assume that if rtas_errd hasn't read the RTAS event in
+ * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
+ */
+static int clobbering_unread_rtas_event(void)
+{
+ return (oops_log_partition.index == rtas_log_partition.index
+ && last_unread_rtas_event
+ && get_seconds() - last_unread_rtas_event <=
+ NVRAM_RTAS_READ_TIMEOUT);
+}
+
+/* Derived from logfs_compress() */
+static int nvram_compress(const void *in, void *out, size_t inlen,
+ size_t outlen)
+{
+ int err, ret;
+
+ ret = -EIO;
+ err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
+ MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ if (err != Z_OK)
+ goto error;
+
+ stream.next_in = in;
+ stream.avail_in = inlen;
+ stream.total_in = 0;
+ stream.next_out = out;
+ stream.avail_out = outlen;
+ stream.total_out = 0;
+
+ err = zlib_deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto error;
+
+ err = zlib_deflateEnd(&stream);
+ if (err != Z_OK)
+ goto error;
+
+ if (stream.total_out >= stream.total_in)
+ goto error;
+
+ ret = stream.total_out;
+error:
+ return ret;
+}
+
+/* Compress the text from big_oops_buf into oops_buf. */
+static int zip_oops(size_t text_len)
+{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
+ int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len,
+ oops_data_sz);
+ if (zipped_len < 0) {
+ pr_err("nvram: compression failed; returned %d\n", zipped_len);
+ pr_err("nvram: logging uncompressed oops/panic report\n");
+ return -1;
+ }
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) zipped_len;
+ oops_hdr->timestamp = get_seconds();
+ return 0;
+}
+
+#ifdef CONFIG_PSTORE
+/* Derived from logfs_uncompress */
+int nvram_decompress(void *in, void *out, size_t inlen, size_t outlen)
+{
+ int err, ret;
+
+ ret = -EIO;
+ err = zlib_inflateInit(&stream);
+ if (err != Z_OK)
+ goto error;
+
+ stream.next_in = in;
+ stream.avail_in = inlen;
+ stream.total_in = 0;
+ stream.next_out = out;
+ stream.avail_out = outlen;
+ stream.total_out = 0;
+
+ err = zlib_inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto error;
+
+ err = zlib_inflateEnd(&stream);
+ if (err != Z_OK)
+ goto error;
+
+ ret = stream.total_out;
+error:
+ return ret;
+}
+
+static int unzip_oops(char *oops_buf, char *big_buf)
+{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
+ u64 timestamp = oops_hdr->timestamp;
+ char *big_oops_data = NULL;
+ char *oops_data_buf = NULL;
+ size_t big_oops_data_sz;
+ int unzipped_len;
+
+ big_oops_data = big_buf + sizeof(struct oops_log_info);
+ big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info);
+ oops_data_buf = oops_buf + sizeof(struct oops_log_info);
+
+ unzipped_len = nvram_decompress(oops_data_buf, big_oops_data,
+ oops_hdr->report_length,
+ big_oops_data_sz);
+
+ if (unzipped_len < 0) {
+ pr_err("nvram: decompression failed; returned %d\n",
+ unzipped_len);
+ return -1;
+ }
+ oops_hdr = (struct oops_log_info *)big_buf;
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) unzipped_len;
+ oops_hdr->timestamp = timestamp;
+ return 0;
+}
+
+static int nvram_pstore_open(struct pstore_info *psi)
+{
+ /* Reset the iterator to start reading partitions again */
+ read_type = -1;
+ return 0;
+}
+
+/**
+ * nvram_pstore_write - pstore write callback for nvram
+ * @type: Type of message logged
+ * @reason: reason behind dump (oops/panic)
+ * @id: identifier to indicate the write performed
+ * @part: pstore writes data to registered buffer in parts,
+ * part number will indicate the same.
+ * @count: Indicates oops count
+ * @hsize: Size of header added by pstore
+ * @size: number of bytes written to the registered buffer
+ * @psi: registered pstore_info structure
+ *
+ * Called by pstore_dump() when an oops or panic report is logged in the
+ * printk buffer.
+ * Returns 0 on successful write.
+ */
+static int nvram_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason,
+ u64 *id, unsigned int part, int count,
+ size_t hsize, size_t size,
+ struct pstore_info *psi)
+{
+ int rc;
+ unsigned int err_type = ERR_TYPE_KERNEL_PANIC;
+ struct oops_log_info *oops_hdr = (struct oops_log_info *) oops_buf;
+
+ /* part 1 has the recent messages from printk buffer */
+ if (part > 1 || type != PSTORE_TYPE_DMESG ||
+ clobbering_unread_rtas_event())
+ return -1;
+
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) size;
+ oops_hdr->timestamp = get_seconds();
+
+ if (big_oops_buf) {
+ rc = zip_oops(size);
+ /*
+ * If compression fails copy recent log messages from
+ * big_oops_buf to oops_data.
+ */
+ if (rc != 0) {
+ size_t diff = size - oops_data_sz + hsize;
+
+ if (size > oops_data_sz) {
+ memcpy(oops_data, big_oops_buf, hsize);
+ memcpy(oops_data + hsize, big_oops_buf + diff,
+ oops_data_sz - hsize);
+
+ oops_hdr->report_length = (u16) oops_data_sz;
+ } else
+ memcpy(oops_data, big_oops_buf, size);
+ } else
+ err_type = ERR_TYPE_KERNEL_PANIC_GZ;
+ }
+
+ rc = nvram_write_os_partition(&oops_log_partition, oops_buf,
+ (int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
+ count);
+
+ if (rc != 0)
+ return rc;
+
+ *id = part;
+ return 0;
+}
+
+/*
+ * Reads the oops/panic report, rtas, of-config and common partition.
+ * Returns the length of the data we read from each partition.
+ * Returns 0 if we've been called before.
+ */
+static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
+ int *count, struct timespec *time, char **buf,
+ struct pstore_info *psi)
+{
+ struct oops_log_info *oops_hdr;
+ unsigned int err_type, id_no, size = 0;
+ struct nvram_os_partition *part = NULL;
+ char *buff = NULL, *big_buff = NULL;
+ int rc, sig = 0;
+ loff_t p;
+
+read_partition:
+ read_type++;
+
+ switch (nvram_type_ids[read_type]) {
+ case PSTORE_TYPE_DMESG:
+ part = &oops_log_partition;
+ *type = PSTORE_TYPE_DMESG;
+ break;
+ case PSTORE_TYPE_PPC_RTAS:
+ part = &rtas_log_partition;
+ *type = PSTORE_TYPE_PPC_RTAS;
+ time->tv_sec = last_rtas_event;
+ time->tv_nsec = 0;
+ break;
+ case PSTORE_TYPE_PPC_OF:
+ sig = NVRAM_SIG_OF;
+ part = &of_config_partition;
+ *type = PSTORE_TYPE_PPC_OF;
+ *id = PSTORE_TYPE_PPC_OF;
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ break;
+ case PSTORE_TYPE_PPC_COMMON:
+ sig = NVRAM_SIG_SYS;
+ part = &common_partition;
+ *type = PSTORE_TYPE_PPC_COMMON;
+ *id = PSTORE_TYPE_PPC_COMMON;
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+ break;
+ default:
+ return 0;
+ }
+
+ if (!part->os_partition) {
+ p = nvram_find_partition(part->name, sig, &size);
+ if (p <= 0) {
+ pr_err("nvram: Failed to find partition %s, "
+ "err %d\n", part->name, (int)p);
+ return 0;
+ }
+ part->index = p;
+ part->size = size;
+ }
+
+ buff = kmalloc(part->size, GFP_KERNEL);
+
+ if (!buff)
+ return -ENOMEM;
+
+ if (nvram_read_partition(part, buff, part->size, &err_type, &id_no)) {
+ kfree(buff);
+ return 0;
+ }
+
+ *count = 0;
+
+ if (part->os_partition)
+ *id = id_no;
+
+ if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
+ oops_hdr = (struct oops_log_info *)buff;
+ *buf = buff + sizeof(*oops_hdr);
+
+ if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
+ big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
+ if (!big_buff)
+ return -ENOMEM;
+
+ rc = unzip_oops(buff, big_buff);
+
+ if (rc != 0) {
+ kfree(buff);
+ kfree(big_buff);
+ goto read_partition;
+ }
+
+ oops_hdr = (struct oops_log_info *)big_buff;
+ *buf = big_buff + sizeof(*oops_hdr);
+ kfree(buff);
+ }
+
+ time->tv_sec = oops_hdr->timestamp;
+ time->tv_nsec = 0;
+ return oops_hdr->report_length;
+ }
+
+ *buf = buff;
+ return part->size;
+}
+
+static struct pstore_info nvram_pstore_info = {
+ .owner = THIS_MODULE,
+ .name = "nvram",
+ .open = nvram_pstore_open,
+ .read = nvram_pstore_read,
+ .write = nvram_pstore_write,
+};
+
+static int nvram_pstore_init(void)
+{
+ int rc = 0;
+
+ if (big_oops_buf) {
+ nvram_pstore_info.buf = big_oops_buf;
+ nvram_pstore_info.bufsize = big_oops_buf_sz;
+ } else {
+ nvram_pstore_info.buf = oops_data;
+ nvram_pstore_info.bufsize = oops_data_sz;
+ }
+
+ rc = pstore_register(&nvram_pstore_info);
+ if (rc != 0)
+ pr_err("nvram: pstore_register() failed, defaults to "
+ "kmsg_dump; returned %d\n", rc);
+
+ return rc;
+}
+#else
+static int nvram_pstore_init(void)
+{
+ return -1;
+}
+#endif
+
static void __init nvram_init_oops_partition(int rtas_partition_exists)
{
int rc;
@@ -425,9 +833,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
oops_log_partition.name);
return;
}
- oops_len = (u16*) oops_buf;
- oops_data = oops_buf + sizeof(u16);
- oops_data_sz = oops_log_partition.size - sizeof(u16);
+ oops_data = oops_buf + sizeof(struct oops_log_info);
+ oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info);
/*
* Figure compression (preceded by elimination of each line's <n>
@@ -452,6 +859,11 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
stream.workspace = NULL;
}
+ rc = nvram_pstore_init();
+
+ if (!rc)
+ return;
+
rc = kmsg_dump_register(&nvram_kmsg_dumper);
if (rc != 0) {
pr_err("nvram: kmsg_dump_register() failed; returned %d\n", rc);
@@ -501,70 +913,6 @@ int __init pSeries_nvram_init(void)
return 0;
}
-/*
- * Are we using the ibm,rtas-log for oops/panic reports? And if so,
- * would logging this oops/panic overwrite an RTAS event that rtas_errd
- * hasn't had a chance to read and process? Return 1 if so, else 0.
- *
- * We assume that if rtas_errd hasn't read the RTAS event in
- * NVRAM_RTAS_READ_TIMEOUT seconds, it's probably not going to.
- */
-static int clobbering_unread_rtas_event(void)
-{
- return (oops_log_partition.index == rtas_log_partition.index
- && last_unread_rtas_event
- && get_seconds() - last_unread_rtas_event <=
- NVRAM_RTAS_READ_TIMEOUT);
-}
-
-/* Derived from logfs_compress() */
-static int nvram_compress(const void *in, void *out, size_t inlen,
- size_t outlen)
-{
- int err, ret;
-
- ret = -EIO;
- err = zlib_deflateInit2(&stream, COMPR_LEVEL, Z_DEFLATED, WINDOW_BITS,
- MEM_LEVEL, Z_DEFAULT_STRATEGY);
- if (err != Z_OK)
- goto error;
-
- stream.next_in = in;
- stream.avail_in = inlen;
- stream.total_in = 0;
- stream.next_out = out;
- stream.avail_out = outlen;
- stream.total_out = 0;
-
- err = zlib_deflate(&stream, Z_FINISH);
- if (err != Z_STREAM_END)
- goto error;
-
- err = zlib_deflateEnd(&stream);
- if (err != Z_OK)
- goto error;
-
- if (stream.total_out >= stream.total_in)
- goto error;
-
- ret = stream.total_out;
-error:
- return ret;
-}
-
-/* Compress the text from big_oops_buf into oops_buf. */
-static int zip_oops(size_t text_len)
-{
- int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len,
- oops_data_sz);
- if (zipped_len < 0) {
- pr_err("nvram: compression failed; returned %d\n", zipped_len);
- pr_err("nvram: logging uncompressed oops/panic report\n");
- return -1;
- }
- *oops_len = (u16) zipped_len;
- return 0;
-}
/*
* This is our kmsg_dump callback, called after an oops or panic report
@@ -576,6 +924,7 @@ static int zip_oops(size_t text_len)
static void oops_to_nvram(struct kmsg_dumper *dumper,
enum kmsg_dump_reason reason)
{
+ struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
static unsigned int oops_count = 0;
static bool panicking = false;
static DEFINE_SPINLOCK(lock);
@@ -619,14 +968,17 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
}
if (rc != 0) {
kmsg_dump_rewind(dumper);
- kmsg_dump_get_buffer(dumper, true,
+ kmsg_dump_get_buffer(dumper, false,
oops_data, oops_data_sz, &text_len);
err_type = ERR_TYPE_KERNEL_PANIC;
- *oops_len = (u16) text_len;
+ oops_hdr->version = OOPS_HDR_VERSION;
+ oops_hdr->report_length = (u16) text_len;
+ oops_hdr->timestamp = get_seconds();
}
(void) nvram_write_os_partition(&oops_log_partition, oops_buf,
- (int) (sizeof(*oops_len) + *oops_len), err_type, ++oops_count);
+ (int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type,
+ ++oops_count);
spin_unlock_irqrestore(&lock, flags);
}
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index c91b22be9288..efe61374f6ea 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -64,91 +64,6 @@ pcibios_find_pci_bus(struct device_node *dn)
}
EXPORT_SYMBOL_GPL(pcibios_find_pci_bus);
-/**
- * __pcibios_remove_pci_devices - remove all devices under this bus
- * @bus: the indicated PCI bus
- * @purge_pe: destroy the PE on removal of PCI devices
- *
- * Remove all of the PCI devices under this bus both from the
- * linux pci device tree, and from the powerpc EEH address cache.
- * By default, the corresponding PE will be destroied during the
- * normal PCI hotplug path. For PCI hotplug during EEH recovery,
- * the corresponding PE won't be destroied and deallocated.
- */
-void __pcibios_remove_pci_devices(struct pci_bus *bus, int purge_pe)
-{
- struct pci_dev *dev, *tmp;
- struct pci_bus *child_bus;
-
- /* First go down child busses */
- list_for_each_entry(child_bus, &bus->children, node)
- __pcibios_remove_pci_devices(child_bus, purge_pe);
-
- pr_debug("PCI: Removing devices on bus %04x:%02x\n",
- pci_domain_nr(bus), bus->number);
- list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
- pr_debug(" * Removing %s...\n", pci_name(dev));
- eeh_remove_bus_device(dev, purge_pe);
- pci_stop_and_remove_bus_device(dev);
- }
-}
-
-/**
- * pcibios_remove_pci_devices - remove all devices under this bus
- *
- * Remove all of the PCI devices under this bus both from the
- * linux pci device tree, and from the powerpc EEH address cache.
- */
-void pcibios_remove_pci_devices(struct pci_bus *bus)
-{
- __pcibios_remove_pci_devices(bus, 1);
-}
-EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
-
-/**
- * pcibios_add_pci_devices - adds new pci devices to bus
- *
- * This routine will find and fixup new pci devices under
- * the indicated bus. This routine presumes that there
- * might already be some devices under this bridge, so
- * it carefully tries to add only new devices. (And that
- * is how this routine differs from other, similar pcibios
- * routines.)
- */
-void pcibios_add_pci_devices(struct pci_bus * bus)
-{
- int slotno, num, mode, pass, max;
- struct pci_dev *dev;
- struct device_node *dn = pci_bus_to_OF_node(bus);
-
- eeh_add_device_tree_early(dn);
-
- mode = PCI_PROBE_NORMAL;
- if (ppc_md.pci_probe_mode)
- mode = ppc_md.pci_probe_mode(bus);
-
- if (mode == PCI_PROBE_DEVTREE) {
- /* use ofdt-based probe */
- of_rescan_bus(dn, bus);
- } else if (mode == PCI_PROBE_NORMAL) {
- /* use legacy probe */
- slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
- num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
- if (!num)
- return;
- pcibios_setup_bus_devices(bus);
- max = bus->busn_res.start;
- for (pass=0; pass < 2; pass++)
- list_for_each_entry(dev, &bus->devices, bus_list) {
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
- dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
- max = pci_scan_bridge(bus, dev, max, pass);
- }
- }
- pcibios_finish_adding_to_bus(bus);
-}
-EXPORT_SYMBOL_GPL(pcibios_add_pci_devices);
-
struct pci_controller *init_phb_dynamic(struct device_node *dn)
{
struct pci_controller *phb;
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index c4dfccd3a3d9..7b3cbde8c783 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -83,7 +83,7 @@ static void handle_system_shutdown(char event_modifier)
switch (event_modifier) {
case EPOW_SHUTDOWN_NORMAL:
pr_emerg("Firmware initiated power off");
- orderly_poweroff(1);
+ orderly_poweroff(true);
break;
case EPOW_SHUTDOWN_ON_UPS:
@@ -95,13 +95,13 @@ static void handle_system_shutdown(char event_modifier)
pr_emerg("Loss of system critical functions reported by "
"firmware");
pr_emerg("Check RTAS error log for details");
- orderly_poweroff(1);
+ orderly_poweroff(true);
break;
case EPOW_SHUTDOWN_AMBIENT_TEMPERATURE_TOO_HIGH:
pr_emerg("Ambient temperature too high reported by firmware");
pr_emerg("Check RTAS error log for details");
- orderly_poweroff(1);
+ orderly_poweroff(true);
break;
default:
@@ -162,7 +162,7 @@ void rtas_parse_epow_errlog(struct rtas_error_log *log)
case EPOW_SYSTEM_HALT:
pr_emerg("Firmware initiated power off");
- orderly_poweroff(1);
+ orderly_poweroff(true);
break;
case EPOW_MAIN_ENCLOSURE:
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 12bc8c3663ad..306643cc9dbc 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -192,7 +192,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr)
/* Special case - we inhibit secondary thread startup
* during boot if the user requests it.
*/
- if (system_state < SYSTEM_RUNNING && cpu_has_feature(CPU_FTR_SMT)) {
+ if (system_state == SYSTEM_BOOTING && cpu_has_feature(CPU_FTR_SMT)) {
if (!smt_enabled_at_boot && cpu_thread_in_core(nr) != 0)
return 0;
if (smt_enabled_at_boot
diff --git a/arch/powerpc/relocs_check.pl b/arch/powerpc/relocs_check.pl
index 7f5b83808862..3f46e8b9c56d 100755
--- a/arch/powerpc/relocs_check.pl
+++ b/arch/powerpc/relocs_check.pl
@@ -7,7 +7,7 @@
# as published by the Free Software Foundation; either version
# 2 of the License, or (at your option) any later version.
-# This script checks the relcoations of a vmlinux for "suspicious"
+# This script checks the relocations of a vmlinux for "suspicious"
# relocations.
use strict;
@@ -28,7 +28,7 @@ open(FD, "$objdump -R $vmlinux|") or die;
while (<FD>) {
study $_;
- # Only look at relcoation lines.
+ # Only look at relocation lines.
next if (!/\s+R_/);
# These relocations are okay
@@ -45,7 +45,7 @@ while (<FD>) {
/\bR_PPC_ADDR16_HA\b/ or /\bR_PPC_RELATIVE\b/ or
/\bR_PPC_NONE\b/);
- # If we see this type of relcoation it's an idication that
+ # If we see this type of relocation it's an idication that
# we /may/ be using an old version of binutils.
if (/R_PPC64_UADDR64/) {
$old_binutils++;
@@ -61,6 +61,6 @@ if ($bad_relocs_count) {
}
if ($old_binutils) {
- print "WARNING: You need at binutils >= 2.19 to build a ".
- "CONFIG_RELCOATABLE kernel\n";
+ print "WARNING: You need at least binutils >= 2.19 to build a ".
+ "CONFIG_RELOCATABLE kernel\n";
}
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 99464a7bdb3b..f67ac900d870 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -4,6 +4,8 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.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
mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y)
obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index d4fa03f2b6ac..5e6ff38ea69f 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -120,6 +120,7 @@ static irqreturn_t cpm_error_interrupt(int irq, void *dev)
static struct irqaction cpm_error_irqaction = {
.handler = cpm_error_interrupt,
+ .flags = IRQF_NO_THREAD,
.name = "error",
};
diff --git a/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
new file mode 100644
index 000000000000..1707bf04dec6
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_mpic_timer_wakeup.c
@@ -0,0 +1,161 @@
+/*
+ * MPIC timer wakeup driver
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+#include <asm/mpic_timer.h>
+#include <asm/mpic.h>
+
+struct fsl_mpic_timer_wakeup {
+ struct mpic_timer *timer;
+ struct work_struct free_work;
+};
+
+static struct fsl_mpic_timer_wakeup *fsl_wakeup;
+static DEFINE_MUTEX(sysfs_lock);
+
+static void fsl_free_resource(struct work_struct *ws)
+{
+ struct fsl_mpic_timer_wakeup *wakeup =
+ container_of(ws, struct fsl_mpic_timer_wakeup, free_work);
+
+ mutex_lock(&sysfs_lock);
+
+ if (wakeup->timer) {
+ disable_irq_wake(wakeup->timer->irq);
+ mpic_free_timer(wakeup->timer);
+ }
+
+ wakeup->timer = NULL;
+ mutex_unlock(&sysfs_lock);
+}
+
+static irqreturn_t fsl_mpic_timer_irq(int irq, void *dev_id)
+{
+ struct fsl_mpic_timer_wakeup *wakeup = dev_id;
+
+ schedule_work(&wakeup->free_work);
+
+ return wakeup->timer ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static ssize_t fsl_timer_wakeup_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct timeval interval;
+ int val = 0;
+
+ mutex_lock(&sysfs_lock);
+ if (fsl_wakeup->timer) {
+ mpic_get_remain_time(fsl_wakeup->timer, &interval);
+ val = interval.tv_sec + 1;
+ }
+ mutex_unlock(&sysfs_lock);
+
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t fsl_timer_wakeup_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct timeval interval;
+ int ret;
+
+ interval.tv_usec = 0;
+ if (kstrtol(buf, 0, &interval.tv_sec))
+ return -EINVAL;
+
+ mutex_lock(&sysfs_lock);
+
+ if (fsl_wakeup->timer) {
+ disable_irq_wake(fsl_wakeup->timer->irq);
+ mpic_free_timer(fsl_wakeup->timer);
+ fsl_wakeup->timer = NULL;
+ }
+
+ if (!interval.tv_sec) {
+ mutex_unlock(&sysfs_lock);
+ return count;
+ }
+
+ fsl_wakeup->timer = mpic_request_timer(fsl_mpic_timer_irq,
+ fsl_wakeup, &interval);
+ if (!fsl_wakeup->timer) {
+ mutex_unlock(&sysfs_lock);
+ return -EINVAL;
+ }
+
+ ret = enable_irq_wake(fsl_wakeup->timer->irq);
+ if (ret) {
+ mpic_free_timer(fsl_wakeup->timer);
+ fsl_wakeup->timer = NULL;
+ mutex_unlock(&sysfs_lock);
+
+ return ret;
+ }
+
+ mpic_start_timer(fsl_wakeup->timer);
+
+ mutex_unlock(&sysfs_lock);
+
+ return count;
+}
+
+static struct device_attribute mpic_attributes = __ATTR(timer_wakeup, 0644,
+ fsl_timer_wakeup_show, fsl_timer_wakeup_store);
+
+static int __init fsl_wakeup_sys_init(void)
+{
+ int ret;
+
+ fsl_wakeup = kzalloc(sizeof(struct fsl_mpic_timer_wakeup), GFP_KERNEL);
+ if (!fsl_wakeup)
+ return -ENOMEM;
+
+ INIT_WORK(&fsl_wakeup->free_work, fsl_free_resource);
+
+ ret = device_create_file(mpic_subsys.dev_root, &mpic_attributes);
+ if (ret)
+ kfree(fsl_wakeup);
+
+ return ret;
+}
+
+static void __exit fsl_wakeup_sys_exit(void)
+{
+ device_remove_file(mpic_subsys.dev_root, &mpic_attributes);
+
+ mutex_lock(&sysfs_lock);
+
+ if (fsl_wakeup->timer) {
+ disable_irq_wake(fsl_wakeup->timer->irq);
+ mpic_free_timer(fsl_wakeup->timer);
+ }
+
+ kfree(fsl_wakeup);
+
+ mutex_unlock(&sysfs_lock);
+}
+
+module_init(fsl_wakeup_sys_init);
+module_exit(fsl_wakeup_sys_exit);
+
+MODULE_DESCRIPTION("Freescale MPIC global timer wakeup driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wang Dongsheng <dongsheng.wang@freescale.com>");
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 3cc2f9159ab1..1be54faf60dd 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -48,6 +48,12 @@
#define DBG(fmt...)
#endif
+struct bus_type mpic_subsys = {
+ .name = "mpic",
+ .dev_name = "mpic",
+};
+EXPORT_SYMBOL_GPL(mpic_subsys);
+
static struct mpic *mpics;
static struct mpic *mpic_primary;
static DEFINE_RAW_SPINLOCK(mpic_lock);
@@ -920,6 +926,22 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
return IRQ_SET_MASK_OK_NOCOPY;
}
+static int mpic_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ struct irq_desc *desc = container_of(d, struct irq_desc, irq_data);
+ struct mpic *mpic = mpic_from_irq_data(d);
+
+ if (!(mpic->flags & MPIC_FSL))
+ return -ENXIO;
+
+ if (on)
+ desc->action->flags |= IRQF_NO_SUSPEND;
+ else
+ desc->action->flags &= ~IRQF_NO_SUSPEND;
+
+ return 0;
+}
+
void mpic_set_vector(unsigned int virq, unsigned int vector)
{
struct mpic *mpic = mpic_from_irq(virq);
@@ -957,6 +979,7 @@ static struct irq_chip mpic_irq_chip = {
.irq_unmask = mpic_unmask_irq,
.irq_eoi = mpic_end_irq,
.irq_set_type = mpic_set_irq_type,
+ .irq_set_wake = mpic_irq_set_wake,
};
#ifdef CONFIG_SMP
@@ -971,6 +994,7 @@ static struct irq_chip mpic_tm_chip = {
.irq_mask = mpic_mask_tm,
.irq_unmask = mpic_unmask_tm,
.irq_eoi = mpic_end_irq,
+ .irq_set_wake = mpic_irq_set_wake,
};
#ifdef CONFIG_MPIC_U3_HT_IRQS
@@ -1173,10 +1197,33 @@ static struct irq_domain_ops mpic_host_ops = {
.xlate = mpic_host_xlate,
};
+static u32 fsl_mpic_get_version(struct mpic *mpic)
+{
+ u32 brr1;
+
+ if (!(mpic->flags & MPIC_FSL))
+ return 0;
+
+ brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+ MPIC_FSL_BRR1);
+
+ return brr1 & MPIC_FSL_BRR1_VER;
+}
+
/*
* Exported functions
*/
+u32 fsl_mpic_primary_get_version(void)
+{
+ struct mpic *mpic = mpic_primary;
+
+ if (mpic)
+ return fsl_mpic_get_version(mpic);
+
+ return 0;
+}
+
struct mpic * __init mpic_alloc(struct device_node *node,
phys_addr_t phys_addr,
unsigned int flags,
@@ -1323,7 +1370,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
if (mpic->flags & MPIC_FSL) {
- u32 brr1;
int ret;
/*
@@ -1334,9 +1380,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
MPIC_CPU_THISBASE, 0x1000);
- brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- fsl_version = brr1 & MPIC_FSL_BRR1_VER;
+ fsl_version = fsl_mpic_get_version(mpic);
/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
@@ -1526,9 +1570,7 @@ void __init mpic_init(struct mpic *mpic)
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
if (mpic->flags & MPIC_FSL) {
- u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- u32 version = brr1 & MPIC_FSL_BRR1_VER;
+ u32 version = fsl_mpic_get_version(mpic);
/*
* Timer group B is present at the latest in MPIC 3.1 (e.g.
@@ -1999,6 +2041,8 @@ static struct syscore_ops mpic_syscore_ops = {
static int mpic_init_sys(void)
{
register_syscore_ops(&mpic_syscore_ops);
+ subsys_system_register(&mpic_subsys, NULL);
+
return 0;
}
diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c
new file mode 100644
index 000000000000..c06db92a4fb1
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_timer.c
@@ -0,0 +1,593 @@
+/*
+ * MPIC timer driver
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
+ * Li Yang <leoli@freescale.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/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/syscore_ops.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/io.h>
+
+#include <asm/mpic_timer.h>
+
+#define FSL_GLOBAL_TIMER 0x1
+
+/* Clock Ratio
+ * Divide by 64 0x00000300
+ * Divide by 32 0x00000200
+ * Divide by 16 0x00000100
+ * Divide by 8 0x00000000 (Hardware default div)
+ */
+#define MPIC_TIMER_TCR_CLKDIV 0x00000300
+
+#define MPIC_TIMER_TCR_ROVR_OFFSET 24
+
+#define TIMER_STOP 0x80000000
+#define TIMERS_PER_GROUP 4
+#define MAX_TICKS (~0U >> 1)
+#define MAX_TICKS_CASCADE (~0U)
+#define TIMER_OFFSET(num) (1 << (TIMERS_PER_GROUP - 1 - num))
+
+/* tv_usec should be less than ONE_SECOND, otherwise use tv_sec */
+#define ONE_SECOND 1000000
+
+struct timer_regs {
+ u32 gtccr;
+ u32 res0[3];
+ u32 gtbcr;
+ u32 res1[3];
+ u32 gtvpr;
+ u32 res2[3];
+ u32 gtdr;
+ u32 res3[3];
+};
+
+struct cascade_priv {
+ u32 tcr_value; /* TCR register: CASC & ROVR value */
+ unsigned int cascade_map; /* cascade map */
+ unsigned int timer_num; /* cascade control timer */
+};
+
+struct timer_group_priv {
+ struct timer_regs __iomem *regs;
+ struct mpic_timer timer[TIMERS_PER_GROUP];
+ struct list_head node;
+ unsigned int timerfreq;
+ unsigned int idle;
+ unsigned int flags;
+ spinlock_t lock;
+ void __iomem *group_tcr;
+};
+
+static struct cascade_priv cascade_timer[] = {
+ /* cascade timer 0 and 1 */
+ {0x1, 0xc, 0x1},
+ /* cascade timer 1 and 2 */
+ {0x2, 0x6, 0x2},
+ /* cascade timer 2 and 3 */
+ {0x4, 0x3, 0x3}
+};
+
+static LIST_HEAD(timer_group_list);
+
+static void convert_ticks_to_time(struct timer_group_priv *priv,
+ const u64 ticks, struct timeval *time)
+{
+ u64 tmp_sec;
+
+ time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq);
+ tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
+
+ time->tv_usec = (__kernel_suseconds_t)
+ div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
+
+ return;
+}
+
+/* the time set by the user is converted to "ticks" */
+static int convert_time_to_ticks(struct timer_group_priv *priv,
+ const struct timeval *time, u64 *ticks)
+{
+ u64 max_value; /* prevent u64 overflow */
+ u64 tmp = 0;
+
+ u64 tmp_sec;
+ u64 tmp_ms;
+ u64 tmp_us;
+
+ max_value = div_u64(ULLONG_MAX, priv->timerfreq);
+
+ if (time->tv_sec > max_value ||
+ (time->tv_sec == max_value && time->tv_usec > 0))
+ return -EINVAL;
+
+ tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
+ tmp += tmp_sec;
+
+ tmp_ms = time->tv_usec / 1000;
+ tmp_ms = div_u64((u64)tmp_ms * (u64)priv->timerfreq, 1000);
+ tmp += tmp_ms;
+
+ tmp_us = time->tv_usec % 1000;
+ tmp_us = div_u64((u64)tmp_us * (u64)priv->timerfreq, 1000000);
+ tmp += tmp_us;
+
+ *ticks = tmp;
+
+ return 0;
+}
+
+/* detect whether there is a cascade timer available */
+static struct mpic_timer *detect_idle_cascade_timer(
+ struct timer_group_priv *priv)
+{
+ struct cascade_priv *casc_priv;
+ unsigned int map;
+ unsigned int array_size = ARRAY_SIZE(cascade_timer);
+ unsigned int num;
+ unsigned int i;
+ unsigned long flags;
+
+ casc_priv = cascade_timer;
+ for (i = 0; i < array_size; i++) {
+ spin_lock_irqsave(&priv->lock, flags);
+ map = casc_priv->cascade_map & priv->idle;
+ if (map == casc_priv->cascade_map) {
+ num = casc_priv->timer_num;
+ priv->timer[num].cascade_handle = casc_priv;
+
+ /* set timer busy */
+ priv->idle &= ~casc_priv->cascade_map;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return &priv->timer[num];
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ casc_priv++;
+ }
+
+ return NULL;
+}
+
+static int set_cascade_timer(struct timer_group_priv *priv, u64 ticks,
+ unsigned int num)
+{
+ struct cascade_priv *casc_priv;
+ u32 tcr;
+ u32 tmp_ticks;
+ u32 rem_ticks;
+
+ /* set group tcr reg for cascade */
+ casc_priv = priv->timer[num].cascade_handle;
+ if (!casc_priv)
+ return -EINVAL;
+
+ tcr = casc_priv->tcr_value |
+ (casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
+ setbits32(priv->group_tcr, tcr);
+
+ tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
+
+ out_be32(&priv->regs[num].gtccr, 0);
+ out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
+
+ out_be32(&priv->regs[num - 1].gtccr, 0);
+ out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
+
+ return 0;
+}
+
+static struct mpic_timer *get_cascade_timer(struct timer_group_priv *priv,
+ u64 ticks)
+{
+ struct mpic_timer *allocated_timer;
+
+ /* Two cascade timers: Support the maximum time */
+ const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
+ int ret;
+
+ if (ticks > max_ticks)
+ return NULL;
+
+ /* detect idle timer */
+ allocated_timer = detect_idle_cascade_timer(priv);
+ if (!allocated_timer)
+ return NULL;
+
+ /* set ticks to timer */
+ ret = set_cascade_timer(priv, ticks, allocated_timer->num);
+ if (ret < 0)
+ return NULL;
+
+ return allocated_timer;
+}
+
+static struct mpic_timer *get_timer(const struct timeval *time)
+{
+ struct timer_group_priv *priv;
+ struct mpic_timer *timer;
+
+ u64 ticks;
+ unsigned int num;
+ unsigned int i;
+ unsigned long flags;
+ int ret;
+
+ list_for_each_entry(priv, &timer_group_list, node) {
+ ret = convert_time_to_ticks(priv, time, &ticks);
+ if (ret < 0)
+ return NULL;
+
+ if (ticks > MAX_TICKS) {
+ if (!(priv->flags & FSL_GLOBAL_TIMER))
+ return NULL;
+
+ timer = get_cascade_timer(priv, ticks);
+ if (!timer)
+ continue;
+
+ return timer;
+ }
+
+ for (i = 0; i < TIMERS_PER_GROUP; i++) {
+ /* one timer: Reverse allocation */
+ num = TIMERS_PER_GROUP - 1 - i;
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->idle & (1 << i)) {
+ /* set timer busy */
+ priv->idle &= ~(1 << i);
+ /* set ticks & stop timer */
+ out_be32(&priv->regs[num].gtbcr,
+ ticks | TIMER_STOP);
+ out_be32(&priv->regs[num].gtccr, 0);
+ priv->timer[num].cascade_handle = NULL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return &priv->timer[num];
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * mpic_start_timer - start hardware timer
+ * @handle: the timer to be started.
+ *
+ * It will do ->fn(->dev) callback from the hardware interrupt at
+ * the ->timeval point in the future.
+ */
+void mpic_start_timer(struct mpic_timer *handle)
+{
+ struct timer_group_priv *priv = container_of(handle,
+ struct timer_group_priv, timer[handle->num]);
+
+ clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
+}
+EXPORT_SYMBOL(mpic_start_timer);
+
+/**
+ * mpic_stop_timer - stop hardware timer
+ * @handle: the timer to be stoped
+ *
+ * The timer periodically generates an interrupt. Unless user stops the timer.
+ */
+void mpic_stop_timer(struct mpic_timer *handle)
+{
+ struct timer_group_priv *priv = container_of(handle,
+ struct timer_group_priv, timer[handle->num]);
+ struct cascade_priv *casc_priv;
+
+ setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
+
+ casc_priv = priv->timer[handle->num].cascade_handle;
+ if (casc_priv) {
+ out_be32(&priv->regs[handle->num].gtccr, 0);
+ out_be32(&priv->regs[handle->num - 1].gtccr, 0);
+ } else {
+ out_be32(&priv->regs[handle->num].gtccr, 0);
+ }
+}
+EXPORT_SYMBOL(mpic_stop_timer);
+
+/**
+ * mpic_get_remain_time - get timer time
+ * @handle: the timer to be selected.
+ * @time: time for timer
+ *
+ * Query timer remaining time.
+ */
+void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time)
+{
+ struct timer_group_priv *priv = container_of(handle,
+ struct timer_group_priv, timer[handle->num]);
+ struct cascade_priv *casc_priv;
+
+ u64 ticks;
+ u32 tmp_ticks;
+
+ casc_priv = priv->timer[handle->num].cascade_handle;
+ if (casc_priv) {
+ tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
+ ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
+ tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
+ ticks += tmp_ticks;
+ } else {
+ ticks = in_be32(&priv->regs[handle->num].gtccr);
+ }
+
+ convert_ticks_to_time(priv, ticks, time);
+}
+EXPORT_SYMBOL(mpic_get_remain_time);
+
+/**
+ * mpic_free_timer - free hardware timer
+ * @handle: the timer to be removed.
+ *
+ * Free the timer.
+ *
+ * Note: can not be used in interrupt context.
+ */
+void mpic_free_timer(struct mpic_timer *handle)
+{
+ struct timer_group_priv *priv = container_of(handle,
+ struct timer_group_priv, timer[handle->num]);
+
+ struct cascade_priv *casc_priv;
+ unsigned long flags;
+
+ mpic_stop_timer(handle);
+
+ casc_priv = priv->timer[handle->num].cascade_handle;
+
+ free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (casc_priv) {
+ u32 tcr;
+ tcr = casc_priv->tcr_value | (casc_priv->tcr_value <<
+ MPIC_TIMER_TCR_ROVR_OFFSET);
+ clrbits32(priv->group_tcr, tcr);
+ priv->idle |= casc_priv->cascade_map;
+ priv->timer[handle->num].cascade_handle = NULL;
+ } else {
+ priv->idle |= TIMER_OFFSET(handle->num);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+EXPORT_SYMBOL(mpic_free_timer);
+
+/**
+ * mpic_request_timer - get a hardware timer
+ * @fn: interrupt handler function
+ * @dev: callback function of the data
+ * @time: time for timer
+ *
+ * This executes the "request_irq", returning NULL
+ * else "handle" on success.
+ */
+struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
+ const struct timeval *time)
+{
+ struct mpic_timer *allocated_timer;
+ int ret;
+
+ if (list_empty(&timer_group_list))
+ return NULL;
+
+ if (!(time->tv_sec + time->tv_usec) ||
+ time->tv_sec < 0 || time->tv_usec < 0)
+ return NULL;
+
+ if (time->tv_usec > ONE_SECOND)
+ return NULL;
+
+ allocated_timer = get_timer(time);
+ if (!allocated_timer)
+ return NULL;
+
+ ret = request_irq(allocated_timer->irq, fn,
+ IRQF_TRIGGER_LOW, "global-timer", dev);
+ if (ret) {
+ mpic_free_timer(allocated_timer);
+ return NULL;
+ }
+
+ allocated_timer->dev = dev;
+
+ return allocated_timer;
+}
+EXPORT_SYMBOL(mpic_request_timer);
+
+static int timer_group_get_freq(struct device_node *np,
+ struct timer_group_priv *priv)
+{
+ u32 div;
+
+ if (priv->flags & FSL_GLOBAL_TIMER) {
+ struct device_node *dn;
+
+ dn = of_find_compatible_node(NULL, NULL, "fsl,mpic");
+ if (dn) {
+ of_property_read_u32(dn, "clock-frequency",
+ &priv->timerfreq);
+ of_node_put(dn);
+ }
+ }
+
+ if (priv->timerfreq <= 0)
+ return -EINVAL;
+
+ if (priv->flags & FSL_GLOBAL_TIMER) {
+ div = (1 << (MPIC_TIMER_TCR_CLKDIV >> 8)) * 8;
+ priv->timerfreq /= div;
+ }
+
+ return 0;
+}
+
+static int timer_group_get_irq(struct device_node *np,
+ struct timer_group_priv *priv)
+{
+ const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
+ const u32 *p;
+ u32 offset;
+ u32 count;
+
+ unsigned int i;
+ unsigned int j;
+ unsigned int irq_index = 0;
+ unsigned int irq;
+ int len;
+
+ p = of_get_property(np, "fsl,available-ranges", &len);
+ if (p && len % (2 * sizeof(u32)) != 0) {
+ pr_err("%s: malformed available-ranges property.\n",
+ np->full_name);
+ return -EINVAL;
+ }
+
+ if (!p) {
+ p = all_timer;
+ len = sizeof(all_timer);
+ }
+
+ len /= 2 * sizeof(u32);
+
+ for (i = 0; i < len; i++) {
+ offset = p[i * 2];
+ count = p[i * 2 + 1];
+ for (j = 0; j < count; j++) {
+ irq = irq_of_parse_and_map(np, irq_index);
+ if (!irq) {
+ pr_err("%s: irq parse and map failed.\n",
+ np->full_name);
+ return -EINVAL;
+ }
+
+ /* Set timer idle */
+ priv->idle |= TIMER_OFFSET((offset + j));
+ priv->timer[offset + j].irq = irq;
+ priv->timer[offset + j].num = offset + j;
+ irq_index++;
+ }
+ }
+
+ return 0;
+}
+
+static void timer_group_init(struct device_node *np)
+{
+ struct timer_group_priv *priv;
+ unsigned int i = 0;
+ int ret;
+
+ priv = kzalloc(sizeof(struct timer_group_priv), GFP_KERNEL);
+ if (!priv) {
+ pr_err("%s: cannot allocate memory for group.\n",
+ np->full_name);
+ return;
+ }
+
+ if (of_device_is_compatible(np, "fsl,mpic-global-timer"))
+ priv->flags |= FSL_GLOBAL_TIMER;
+
+ priv->regs = of_iomap(np, i++);
+ if (!priv->regs) {
+ pr_err("%s: cannot ioremap timer register address.\n",
+ np->full_name);
+ goto out;
+ }
+
+ if (priv->flags & FSL_GLOBAL_TIMER) {
+ priv->group_tcr = of_iomap(np, i++);
+ if (!priv->group_tcr) {
+ pr_err("%s: cannot ioremap tcr address.\n",
+ np->full_name);
+ goto out;
+ }
+ }
+
+ ret = timer_group_get_freq(np, priv);
+ if (ret < 0) {
+ pr_err("%s: cannot get timer frequency.\n", np->full_name);
+ goto out;
+ }
+
+ ret = timer_group_get_irq(np, priv);
+ if (ret < 0) {
+ pr_err("%s: cannot get timer irqs.\n", np->full_name);
+ goto out;
+ }
+
+ spin_lock_init(&priv->lock);
+
+ /* Init FSL timer hardware */
+ if (priv->flags & FSL_GLOBAL_TIMER)
+ setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
+
+ list_add_tail(&priv->node, &timer_group_list);
+
+ return;
+
+out:
+ if (priv->regs)
+ iounmap(priv->regs);
+
+ if (priv->group_tcr)
+ iounmap(priv->group_tcr);
+
+ kfree(priv);
+}
+
+static void mpic_timer_resume(void)
+{
+ struct timer_group_priv *priv;
+
+ list_for_each_entry(priv, &timer_group_list, node) {
+ /* Init FSL timer hardware */
+ if (priv->flags & FSL_GLOBAL_TIMER)
+ setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
+ }
+}
+
+static const struct of_device_id mpic_timer_ids[] = {
+ { .compatible = "fsl,mpic-global-timer", },
+ {},
+};
+
+static struct syscore_ops mpic_timer_syscore_ops = {
+ .resume = mpic_timer_resume,
+};
+
+static int __init mpic_timer_init(void)
+{
+ struct device_node *np = NULL;
+
+ for_each_matching_node(np, mpic_timer_ids)
+ timer_group_init(np);
+
+ register_syscore_ops(&mpic_timer_syscore_ops);
+
+ if (list_empty(&timer_group_list))
+ return -ENODEV;
+
+ return 0;
+}
+subsys_initcall(mpic_timer_init);
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
index 7ef60b52d6e0..42be53743133 100644
--- a/arch/s390/appldata/appldata_mem.c
+++ b/arch/s390/appldata/appldata_mem.c
@@ -32,7 +32,7 @@
* book:
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
*/
-static struct appldata_mem_data {
+struct appldata_mem_data {
u64 timestamp;
u32 sync_count_1; /* after VM collected the record data, */
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
@@ -63,7 +63,7 @@ static struct appldata_mem_data {
u64 pgmajfault; /* page faults (major only) */
// <-- New in 2.6
-} __attribute__((packed)) appldata_mem_data;
+} __packed;
/*
@@ -118,7 +118,6 @@ static struct appldata_ops ops = {
.record_nr = APPLDATA_RECORD_MEM_ID,
.size = sizeof(struct appldata_mem_data),
.callback = &appldata_get_mem_data,
- .data = &appldata_mem_data,
.owner = THIS_MODULE,
.mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */
};
@@ -131,7 +130,17 @@ static struct appldata_ops ops = {
*/
static int __init appldata_mem_init(void)
{
- return appldata_register_ops(&ops);
+ int ret;
+
+ ops.data = kzalloc(sizeof(struct appldata_mem_data), GFP_KERNEL);
+ if (!ops.data)
+ return -ENOMEM;
+
+ ret = appldata_register_ops(&ops);
+ if (ret)
+ kfree(ops.data);
+
+ return ret;
}
/*
@@ -142,6 +151,7 @@ static int __init appldata_mem_init(void)
static void __exit appldata_mem_exit(void)
{
appldata_unregister_ops(&ops);
+ kfree(ops.data);
}
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 2d224b945355..66037d2622b4 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -29,7 +29,7 @@
* book:
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
*/
-static struct appldata_net_sum_data {
+struct appldata_net_sum_data {
u64 timestamp;
u32 sync_count_1; /* after VM collected the record data, */
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
@@ -51,7 +51,7 @@ static struct appldata_net_sum_data {
u64 rx_dropped; /* no space in linux buffers */
u64 tx_dropped; /* no space available in linux */
u64 collisions; /* collisions while transmitting */
-} __attribute__((packed)) appldata_net_sum_data;
+} __packed;
/*
@@ -121,7 +121,6 @@ static struct appldata_ops ops = {
.record_nr = APPLDATA_RECORD_NET_SUM_ID,
.size = sizeof(struct appldata_net_sum_data),
.callback = &appldata_get_net_sum_data,
- .data = &appldata_net_sum_data,
.owner = THIS_MODULE,
.mod_lvl = {0xF0, 0xF0}, /* EBCDIC "00" */
};
@@ -134,7 +133,17 @@ static struct appldata_ops ops = {
*/
static int __init appldata_net_init(void)
{
- return appldata_register_ops(&ops);
+ int ret;
+
+ ops.data = kzalloc(sizeof(struct appldata_net_sum_data), GFP_KERNEL);
+ if (!ops.data)
+ return -ENOMEM;
+
+ ret = appldata_register_ops(&ops);
+ if (ret)
+ kfree(ops.data);
+
+ return ret;
}
/*
@@ -145,6 +154,7 @@ static int __init appldata_net_init(void)
static void __exit appldata_net_exit(void)
{
appldata_unregister_ops(&ops);
+ kfree(ops.data);
}
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 7fd3690b6760..138893e5f736 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -651,9 +651,7 @@ static int hypfs_create_cpu_files(struct super_block *sb,
}
diag224_idx2name(cpu_info__ctidx(diag204_info_type, cpu_info), buffer);
rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
- if (IS_ERR(rc))
- return PTR_ERR(rc);
- return 0;
+ return PTR_RET(rc);
}
static void *hypfs_create_lpar_files(struct super_block *sb,
@@ -702,9 +700,7 @@ static int hypfs_create_phys_cpu_files(struct super_block *sb,
return PTR_ERR(rc);
diag224_idx2name(phys_cpu__ctidx(diag204_info_type, cpu_info), buffer);
rc = hypfs_create_str(sb, cpu_dir, "type", buffer);
- if (IS_ERR(rc))
- return PTR_ERR(rc);
- return 0;
+ return PTR_RET(rc);
}
static void *hypfs_create_phys_files(struct super_block *sb,
diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h
index 9819891ed7a2..4066cee0c2d2 100644
--- a/arch/s390/include/asm/airq.h
+++ b/arch/s390/include/asm/airq.h
@@ -9,9 +9,18 @@
#ifndef _ASM_S390_AIRQ_H
#define _ASM_S390_AIRQ_H
-typedef void (*adapter_int_handler_t)(void *, void *);
+struct airq_struct {
+ struct hlist_node list; /* Handler queueing. */
+ void (*handler)(struct airq_struct *); /* Thin-interrupt handler */
+ u8 *lsi_ptr; /* Local-Summary-Indicator pointer */
+ u8 lsi_mask; /* Local-Summary-Indicator mask */
+ u8 isc; /* Interrupt-subclass */
+ u8 flags;
+};
-void *s390_register_adapter_interrupt(adapter_int_handler_t, void *, u8);
-void s390_unregister_adapter_interrupt(void *, u8);
+#define AIRQ_PTR_ALLOCATED 0x01
+
+int register_adapter_interrupt(struct airq_struct *airq);
+void unregister_adapter_interrupt(struct airq_struct *airq);
#endif /* _ASM_S390_AIRQ_H */
diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h
index 2f8c1abeb086..3fbc67d9e197 100644
--- a/arch/s390/include/asm/dma-mapping.h
+++ b/arch/s390/include/asm/dma-mapping.h
@@ -53,7 +53,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
debug_dma_mapping_error(dev, dma_addr);
if (dma_ops->mapping_error)
return dma_ops->mapping_error(dev, dma_addr);
- return (dma_addr == DMA_ERROR_CODE);
+ return dma_addr == DMA_ERROR_CODE;
}
static inline void *dma_alloc_coherent(struct device *dev, size_t size,
diff --git a/arch/s390/include/asm/facility.h b/arch/s390/include/asm/facility.h
index 2ee66a65f2d4..0aa6a7ed95a3 100644
--- a/arch/s390/include/asm/facility.h
+++ b/arch/s390/include/asm/facility.h
@@ -13,6 +13,16 @@
#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
+static inline int __test_facility(unsigned long nr, void *facilities)
+{
+ unsigned char *ptr;
+
+ if (nr >= MAX_FACILITY_BIT)
+ return 0;
+ ptr = (unsigned char *) facilities + (nr >> 3);
+ return (*ptr & (0x80 >> (nr & 7))) != 0;
+}
+
/*
* The test_facility function uses the bit odering where the MSB is bit 0.
* That makes it easier to query facility bits with the bit number as
@@ -20,12 +30,7 @@
*/
static inline int test_facility(unsigned long nr)
{
- unsigned char *ptr;
-
- if (nr >= MAX_FACILITY_BIT)
- return 0;
- ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
- return (*ptr & (0x80 >> (nr & 7))) != 0;
+ return __test_facility(nr, &S390_lowcore.stfle_fac_list);
}
/**
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h
index fd9be010f9b2..cd6b9ee7b69c 100644
--- a/arch/s390/include/asm/io.h
+++ b/arch/s390/include/asm/io.h
@@ -13,28 +13,6 @@
#include <asm/page.h>
#include <asm/pci_io.h>
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are pretty trivial
- */
-static inline unsigned long virt_to_phys(volatile void * address)
-{
- unsigned long real_address;
- asm volatile(
- " lra %0,0(%1)\n"
- " jz 0f\n"
- " la %0,0\n"
- "0:"
- : "=a" (real_address) : "a" (address) : "cc");
- return real_address;
-}
-#define virt_to_phys virt_to_phys
-
-static inline void * phys_to_virt(unsigned long address)
-{
- return (void *) address;
-}
-
void *xlate_dev_mem_ptr(unsigned long phys);
#define xlate_dev_mem_ptr xlate_dev_mem_ptr
void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 16bd5d169cdb..3238d4004e84 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -62,13 +62,20 @@ struct sca_block {
#define CPUSTAT_MCDS 0x00000100
#define CPUSTAT_SM 0x00000080
#define CPUSTAT_G 0x00000008
+#define CPUSTAT_GED 0x00000004
#define CPUSTAT_J 0x00000002
#define CPUSTAT_P 0x00000001
struct kvm_s390_sie_block {
atomic_t cpuflags; /* 0x0000 */
__u32 prefix; /* 0x0004 */
- __u8 reserved8[32]; /* 0x0008 */
+ __u8 reserved08[4]; /* 0x0008 */
+#define PROG_IN_SIE (1<<0)
+ __u32 prog0c; /* 0x000c */
+ __u8 reserved10[16]; /* 0x0010 */
+#define PROG_BLOCK_SIE 0x00000001
+ atomic_t prog20; /* 0x0020 */
+ __u8 reserved24[4]; /* 0x0024 */
__u64 cputm; /* 0x0028 */
__u64 ckc; /* 0x0030 */
__u64 epoch; /* 0x0038 */
@@ -90,7 +97,8 @@ struct kvm_s390_sie_block {
__u32 scaoh; /* 0x005c */
__u8 reserved60; /* 0x0060 */
__u8 ecb; /* 0x0061 */
- __u8 reserved62[2]; /* 0x0062 */
+ __u8 ecb2; /* 0x0062 */
+ __u8 reserved63[1]; /* 0x0063 */
__u32 scaol; /* 0x0064 */
__u8 reserved68[4]; /* 0x0068 */
__u32 todpr; /* 0x006c */
@@ -130,6 +138,7 @@ struct kvm_vcpu_stat {
u32 deliver_program_int;
u32 deliver_io_int;
u32 exit_wait_state;
+ u32 instruction_pfmf;
u32 instruction_stidp;
u32 instruction_spx;
u32 instruction_stpx;
@@ -166,7 +175,7 @@ struct kvm_s390_ext_info {
};
#define PGM_OPERATION 0x01
-#define PGM_PRIVILEGED_OPERATION 0x02
+#define PGM_PRIVILEGED_OP 0x02
#define PGM_EXECUTE 0x03
#define PGM_PROTECTION 0x04
#define PGM_ADDRESSING 0x05
@@ -219,7 +228,7 @@ struct kvm_s390_local_interrupt {
atomic_t active;
struct kvm_s390_float_interrupt *float_int;
int timer_due; /* event indicator for waitqueue below */
- wait_queue_head_t wq;
+ wait_queue_head_t *wq;
atomic_t *cpuflags;
unsigned int action_bits;
};
@@ -266,4 +275,5 @@ struct kvm_arch{
};
extern int sie64a(struct kvm_s390_sie_block *, u64 *);
+extern char sie_exit;
#endif
diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
index 6c1801235db9..6e577ba0e5da 100644
--- a/arch/s390/include/asm/pci.h
+++ b/arch/s390/include/asm/pci.h
@@ -120,7 +120,6 @@ struct zpci_dev {
struct dentry *debugfs_dev;
struct dentry *debugfs_perf;
- struct dentry *debugfs_debug;
};
struct pci_hp_callback_ops {
@@ -143,7 +142,6 @@ int zpci_enable_device(struct zpci_dev *);
int zpci_disable_device(struct zpci_dev *);
void zpci_stop_device(struct zpci_dev *);
void zpci_free_device(struct zpci_dev *);
-int zpci_scan_device(struct zpci_dev *);
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
int zpci_unregister_ioat(struct zpci_dev *, u8);
diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h
index 5f0173a31693..1141fb3e7b21 100644
--- a/arch/s390/include/asm/perf_event.h
+++ b/arch/s390/include/asm/perf_event.h
@@ -14,3 +14,13 @@
/* Per-CPU flags for PMU states */
#define PMU_F_RESERVED 0x1000
#define PMU_F_ENABLED 0x2000
+
+#ifdef CONFIG_64BIT
+
+/* Perf callbacks */
+struct pt_regs;
+extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
+extern unsigned long perf_misc_flags(struct pt_regs *regs);
+#define perf_misc_flags(regs) perf_misc_flags(regs)
+
+#endif /* CONFIG_64BIT */
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index 590c3219c634..e1408ddb94f8 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -22,6 +22,9 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long);
void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mmu_gather *, unsigned long *);
+int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+ unsigned long key, bool nq);
+
static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
{
typedef struct { char _[n]; } addrtype;
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 9aefa3c64eb2..75fb726de91f 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -296,18 +296,16 @@ extern unsigned long MODULES_END;
#define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV)
/* Page status table bits for virtualization */
-#define RCP_ACC_BITS 0xf0000000UL
-#define RCP_FP_BIT 0x08000000UL
-#define RCP_PCL_BIT 0x00800000UL
-#define RCP_HR_BIT 0x00400000UL
-#define RCP_HC_BIT 0x00200000UL
-#define RCP_GR_BIT 0x00040000UL
-#define RCP_GC_BIT 0x00020000UL
-#define RCP_IN_BIT 0x00002000UL /* IPTE notify bit */
-
-/* User dirty / referenced bit for KVM's migration feature */
-#define KVM_UR_BIT 0x00008000UL
-#define KVM_UC_BIT 0x00004000UL
+#define PGSTE_ACC_BITS 0xf0000000UL
+#define PGSTE_FP_BIT 0x08000000UL
+#define PGSTE_PCL_BIT 0x00800000UL
+#define PGSTE_HR_BIT 0x00400000UL
+#define PGSTE_HC_BIT 0x00200000UL
+#define PGSTE_GR_BIT 0x00040000UL
+#define PGSTE_GC_BIT 0x00020000UL
+#define PGSTE_UR_BIT 0x00008000UL
+#define PGSTE_UC_BIT 0x00004000UL /* user dirty (migration) */
+#define PGSTE_IN_BIT 0x00002000UL /* IPTE notify bit */
#else /* CONFIG_64BIT */
@@ -364,18 +362,16 @@ extern unsigned long MODULES_END;
| _SEGMENT_ENTRY_SPLIT | _SEGMENT_ENTRY_CO)
/* Page status table bits for virtualization */
-#define RCP_ACC_BITS 0xf000000000000000UL
-#define RCP_FP_BIT 0x0800000000000000UL
-#define RCP_PCL_BIT 0x0080000000000000UL
-#define RCP_HR_BIT 0x0040000000000000UL
-#define RCP_HC_BIT 0x0020000000000000UL
-#define RCP_GR_BIT 0x0004000000000000UL
-#define RCP_GC_BIT 0x0002000000000000UL
-#define RCP_IN_BIT 0x0000200000000000UL /* IPTE notify bit */
-
-/* User dirty / referenced bit for KVM's migration feature */
-#define KVM_UR_BIT 0x0000800000000000UL
-#define KVM_UC_BIT 0x0000400000000000UL
+#define PGSTE_ACC_BITS 0xf000000000000000UL
+#define PGSTE_FP_BIT 0x0800000000000000UL
+#define PGSTE_PCL_BIT 0x0080000000000000UL
+#define PGSTE_HR_BIT 0x0040000000000000UL
+#define PGSTE_HC_BIT 0x0020000000000000UL
+#define PGSTE_GR_BIT 0x0004000000000000UL
+#define PGSTE_GC_BIT 0x0002000000000000UL
+#define PGSTE_UR_BIT 0x0000800000000000UL
+#define PGSTE_UC_BIT 0x0000400000000000UL /* user dirty (migration) */
+#define PGSTE_IN_BIT 0x0000200000000000UL /* IPTE notify bit */
#endif /* CONFIG_64BIT */
@@ -615,8 +611,8 @@ static inline pgste_t pgste_get_lock(pte_t *ptep)
asm(
" lg %0,%2\n"
"0: lgr %1,%0\n"
- " nihh %0,0xff7f\n" /* clear RCP_PCL_BIT in old */
- " oihh %1,0x0080\n" /* set RCP_PCL_BIT in new */
+ " nihh %0,0xff7f\n" /* clear PCL bit in old */
+ " oihh %1,0x0080\n" /* set PCL bit in new */
" csg %0,%1,%2\n"
" jl 0b\n"
: "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE])
@@ -629,7 +625,7 @@ static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
{
#ifdef CONFIG_PGSTE
asm(
- " nihh %1,0xff7f\n" /* clear RCP_PCL_BIT */
+ " nihh %1,0xff7f\n" /* clear PCL bit */
" stg %1,%0\n"
: "=Q" (ptep[PTRS_PER_PTE])
: "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE])
@@ -662,14 +658,14 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
else if (bits)
page_reset_referenced(address);
/* Transfer page changed & referenced bit to guest bits in pgste */
- pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */
+ pgste_val(pgste) |= bits << 48; /* GR bit & GC bit */
/* Get host changed & referenced bits from pgste */
- bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52;
+ bits |= (pgste_val(pgste) & (PGSTE_HR_BIT | PGSTE_HC_BIT)) >> 52;
/* Transfer page changed & referenced bit to kvm user bits */
- pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */
+ pgste_val(pgste) |= bits << 45; /* PGSTE_UR_BIT & PGSTE_UC_BIT */
/* Clear relevant host bits in pgste. */
- pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT);
- pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT);
+ pgste_val(pgste) &= ~(PGSTE_HR_BIT | PGSTE_HC_BIT);
+ pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT);
/* Copy page access key and fetch protection bit to pgste */
pgste_val(pgste) |=
(unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
@@ -690,15 +686,15 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
/* Get referenced bit from storage key */
young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
if (young)
- pgste_val(pgste) |= RCP_GR_BIT;
+ pgste_val(pgste) |= PGSTE_GR_BIT;
/* Get host referenced bit from pgste */
- if (pgste_val(pgste) & RCP_HR_BIT) {
- pgste_val(pgste) &= ~RCP_HR_BIT;
+ if (pgste_val(pgste) & PGSTE_HR_BIT) {
+ pgste_val(pgste) &= ~PGSTE_HR_BIT;
young = 1;
}
/* Transfer referenced bit to kvm user bits and pte */
if (young) {
- pgste_val(pgste) |= KVM_UR_BIT;
+ pgste_val(pgste) |= PGSTE_UR_BIT;
pte_val(*ptep) |= _PAGE_SWR;
}
#endif
@@ -720,7 +716,7 @@ static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
* The guest C/R information is still in the PGSTE, set real
* key C/R to 0.
*/
- nkey = (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
+ nkey = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56;
page_set_storage_key(address, nkey, 0);
#endif
}
@@ -750,6 +746,7 @@ struct gmap {
struct mm_struct *mm;
unsigned long *table;
unsigned long asce;
+ void *private;
struct list_head crst_list;
};
@@ -808,8 +805,8 @@ static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
pte_t *ptep, pgste_t pgste)
{
#ifdef CONFIG_PGSTE
- if (pgste_val(pgste) & RCP_IN_BIT) {
- pgste_val(pgste) &= ~RCP_IN_BIT;
+ if (pgste_val(pgste) & PGSTE_IN_BIT) {
+ pgste_val(pgste) &= ~PGSTE_IN_BIT;
gmap_do_ipte_notify(mm, addr, ptep);
}
#endif
@@ -977,8 +974,8 @@ static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
pgste = pgste_update_all(ptep, pgste);
- dirty = !!(pgste_val(pgste) & KVM_UC_BIT);
- pgste_val(pgste) &= ~KVM_UC_BIT;
+ dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT);
+ pgste_val(pgste) &= ~PGSTE_UC_BIT;
pgste_set_unlock(ptep, pgste);
return dirty;
}
@@ -997,8 +994,8 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
pgste = pgste_update_young(ptep, pgste);
- young = !!(pgste_val(pgste) & KVM_UR_BIT);
- pgste_val(pgste) &= ~KVM_UR_BIT;
+ young = !!(pgste_val(pgste) & PGSTE_UR_BIT);
+ pgste_val(pgste) &= ~PGSTE_UR_BIT;
pgste_set_unlock(ptep, pgste);
}
return young;
@@ -1367,10 +1364,11 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
#define __HAVE_ARCH_PGTABLE_DEPOSIT
-extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable);
+extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable);
#define __HAVE_ARCH_PGTABLE_WITHDRAW
-extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm);
+extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
static inline int pmd_trans_splitting(pmd_t pmd)
{
diff --git a/arch/s390/include/asm/ptrace.h b/arch/s390/include/asm/ptrace.h
index 559512a455da..52b56533c57c 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -24,6 +24,7 @@ struct pt_regs
unsigned long gprs[NUM_GPRS];
unsigned long orig_gpr2;
unsigned int int_code;
+ unsigned int int_parm;
unsigned long int_parm_long;
};
diff --git a/arch/s390/include/uapi/asm/Kbuild b/arch/s390/include/uapi/asm/Kbuild
index 9ccd1905bdad..6a9a9eb645f5 100644
--- a/arch/s390/include/uapi/asm/Kbuild
+++ b/arch/s390/include/uapi/asm/Kbuild
@@ -35,6 +35,7 @@ header-y += siginfo.h
header-y += signal.h
header-y += socket.h
header-y += sockios.h
+header-y += sclp_ctl.h
header-y += stat.h
header-y += statfs.h
header-y += swab.h
diff --git a/arch/s390/include/uapi/asm/chsc.h b/arch/s390/include/uapi/asm/chsc.h
index 1c6a7f85a581..65dc694725a8 100644
--- a/arch/s390/include/uapi/asm/chsc.h
+++ b/arch/s390/include/uapi/asm/chsc.h
@@ -29,6 +29,16 @@ struct chsc_async_area {
__u8 data[CHSC_SIZE - sizeof(struct chsc_async_header)];
} __attribute__ ((packed));
+struct chsc_header {
+ __u16 length;
+ __u16 code;
+} __attribute__ ((packed));
+
+struct chsc_sync_area {
+ struct chsc_header header;
+ __u8 data[CHSC_SIZE - sizeof(struct chsc_header)];
+} __attribute__ ((packed));
+
struct chsc_response_struct {
__u16 length;
__u16 code;
@@ -126,5 +136,8 @@ struct chsc_cpd_info {
#define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list)
#define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info)
#define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal)
+#define CHSC_START_SYNC _IOWR(CHSC_IOCTL_MAGIC, 0x89, struct chsc_sync_area)
+#define CHSC_ON_CLOSE_SET _IOWR(CHSC_IOCTL_MAGIC, 0x8a, struct chsc_async_area)
+#define CHSC_ON_CLOSE_REMOVE _IO(CHSC_IOCTL_MAGIC, 0x8b)
#endif
diff --git a/arch/s390/include/uapi/asm/dasd.h b/arch/s390/include/uapi/asm/dasd.h
index 38eca3ba40e2..5812a3b2df9e 100644
--- a/arch/s390/include/uapi/asm/dasd.h
+++ b/arch/s390/include/uapi/asm/dasd.h
@@ -261,6 +261,10 @@ struct dasd_snid_ioctl_data {
#define BIODASDQUIESCE _IO(DASD_IOCTL_LETTER,6)
/* Resume IO on device */
#define BIODASDRESUME _IO(DASD_IOCTL_LETTER,7)
+/* Abort all I/O on a device */
+#define BIODASDABORTIO _IO(DASD_IOCTL_LETTER, 240)
+/* Allow I/O on a device */
+#define BIODASDALLOWIO _IO(DASD_IOCTL_LETTER, 241)
/* retrieve API version number */
diff --git a/arch/s390/include/uapi/asm/sclp_ctl.h b/arch/s390/include/uapi/asm/sclp_ctl.h
new file mode 100644
index 000000000000..f2818613ee41
--- /dev/null
+++ b/arch/s390/include/uapi/asm/sclp_ctl.h
@@ -0,0 +1,24 @@
+/*
+ * IOCTL interface for SCLP
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#ifndef _ASM_SCLP_CTL_H
+#define _ASM_SCLP_CTL_H
+
+#include <linux/types.h>
+
+struct sclp_ctl_sccb {
+ __u32 cmdw;
+ __u64 sccb;
+} __attribute__((packed));
+
+#define SCLP_CTL_IOCTL_MAGIC 0x10
+
+#define SCLP_CTL_SCCB \
+ _IOWR(SCLP_CTL_IOCTL_MAGIC, 0x10, struct sclp_ctl_sccb)
+
+#endif
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 2dacb306835c..0c5105fbaaf3 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -80,4 +80,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 7a82f9f70100..2416138ebd3e 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -7,6 +7,7 @@
#define ASM_OFFSETS_C
#include <linux/kbuild.h>
+#include <linux/kvm_host.h>
#include <linux/sched.h>
#include <asm/cputime.h>
#include <asm/vdso.h>
@@ -47,6 +48,7 @@ int main(void)
DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
DEFINE(__PT_INT_CODE, offsetof(struct pt_regs, int_code));
+ DEFINE(__PT_INT_PARM, offsetof(struct pt_regs, int_parm));
DEFINE(__PT_INT_PARM_LONG, offsetof(struct pt_regs, int_parm_long));
DEFINE(__PT_SIZE, sizeof(struct pt_regs));
BLANK();
@@ -161,6 +163,8 @@ int main(void)
DEFINE(__LC_PGM_TDB, offsetof(struct _lowcore, pgm_tdb));
DEFINE(__THREAD_trap_tdb, offsetof(struct task_struct, thread.trap_tdb));
DEFINE(__GMAP_ASCE, offsetof(struct gmap, asce));
+ DEFINE(__SIE_PROG0C, offsetof(struct kvm_s390_sie_block, prog0c));
+ DEFINE(__SIE_PROG20, offsetof(struct kvm_s390_sie_block, prog20));
#endif /* CONFIG_32BIT */
return 0;
}
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 4d5e6f8a7978..be7a408be7a1 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -429,11 +429,19 @@ io_skip:
stm %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
stm %r8,%r9,__PT_PSW(%r11)
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+io_loop:
l %r1,BASED(.Ldo_IRQ)
lr %r2,%r11 # pass pointer to pt_regs
basr %r14,%r1 # call do_IRQ
+ tm __LC_MACHINE_FLAGS+2,0x10 # MACHINE_FLAG_LPAR
+ jz io_return
+ tpi 0
+ jz io_return
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+ j io_loop
io_return:
LOCKDEP_SYS_EXIT
TRACE_IRQS_ON
@@ -573,10 +581,10 @@ ext_skip:
stm %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(32,%r11),__LC_SAVE_AREA_ASYNC
stm %r8,%r9,__PT_PSW(%r11)
+ mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
+ mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
TRACE_IRQS_OFF
lr %r2,%r11 # pass pointer to pt_regs
- l %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
- l %r4,__LC_EXT_PARAMS # get external parameters
l %r1,BASED(.Ldo_extint)
basr %r14,%r1 # call do_extint
j io_return
diff --git a/arch/s390/kernel/entry.h b/arch/s390/kernel/entry.h
index aa0ab02e9595..3ddbc26d246e 100644
--- a/arch/s390/kernel/entry.h
+++ b/arch/s390/kernel/entry.h
@@ -54,7 +54,7 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka,
void do_notify_resume(struct pt_regs *regs);
struct ext_code;
-void do_extint(struct pt_regs *regs, struct ext_code, unsigned int, unsigned long);
+void do_extint(struct pt_regs *regs);
void do_restart(void);
void __init startup_init(void);
void die(struct pt_regs *regs, const char *str);
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 4c17eece707e..1c039d0c24c7 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -47,7 +47,6 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
_TIF_TRACE = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
_TIF_SYSCALL_TRACEPOINT)
-_TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#define BASED(name) name-system_call(%r13)
@@ -81,23 +80,27 @@ _TIF_EXIT_SIE = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#endif
.endm
- .macro HANDLE_SIE_INTERCEPT scratch,pgmcheck
+ .macro HANDLE_SIE_INTERCEPT scratch,reason
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
tmhh %r8,0x0001 # interrupting from user ?
- jnz .+42
+ jnz .+62
lgr \scratch,%r9
- slg \scratch,BASED(.Lsie_loop)
- clg \scratch,BASED(.Lsie_length)
- .if \pgmcheck
+ slg \scratch,BASED(.Lsie_critical)
+ clg \scratch,BASED(.Lsie_critical_length)
+ .if \reason==1
# Some program interrupts are suppressing (e.g. protection).
# We must also check the instruction after SIE in that case.
# do_protection_exception will rewind to rewind_pad
- jh .+22
+ jh .+42
.else
- jhe .+22
+ jhe .+42
.endif
- lg %r9,BASED(.Lsie_loop)
- LPP BASED(.Lhost_id) # set host id
+ lg %r14,__SF_EMPTY(%r15) # get control block pointer
+ LPP __SF_EMPTY+16(%r15) # set host id
+ ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
+ lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
+ larl %r9,sie_exit # skip forward to sie_exit
+ mvi __SF_EMPTY+31(%r15),\reason # set exit reason
#endif
.endm
@@ -450,7 +453,7 @@ ENTRY(io_int_handler)
lg %r12,__LC_THREAD_INFO
larl %r13,system_call
lmg %r8,%r9,__LC_IO_OLD_PSW
- HANDLE_SIE_INTERCEPT %r14,0
+ HANDLE_SIE_INTERCEPT %r14,2
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
tmhh %r8,0x0001 # interrupting from user?
jz io_skip
@@ -460,10 +463,18 @@ io_skip:
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
stmg %r8,%r9,__PT_PSW(%r11)
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
+io_loop:
lgr %r2,%r11 # pass pointer to pt_regs
brasl %r14,do_IRQ
+ tm __LC_MACHINE_FLAGS+6,0x10 # MACHINE_FLAG_LPAR
+ jz io_return
+ tpi 0
+ jz io_return
+ mvc __PT_INT_CODE(12,%r11),__LC_SUBCHANNEL_ID
+ j io_loop
io_return:
LOCKDEP_SYS_EXIT
TRACE_IRQS_ON
@@ -595,7 +606,7 @@ ENTRY(ext_int_handler)
lg %r12,__LC_THREAD_INFO
larl %r13,system_call
lmg %r8,%r9,__LC_EXT_OLD_PSW
- HANDLE_SIE_INTERCEPT %r14,0
+ HANDLE_SIE_INTERCEPT %r14,3
SWITCH_ASYNC __LC_SAVE_AREA_ASYNC,__LC_ASYNC_STACK,STACK_SHIFT
tmhh %r8,0x0001 # interrupting from user ?
jz ext_skip
@@ -605,13 +616,13 @@ ext_skip:
stmg %r0,%r7,__PT_R0(%r11)
mvc __PT_R8(64,%r11),__LC_SAVE_AREA_ASYNC
stmg %r8,%r9,__PT_PSW(%r11)
+ lghi %r1,__LC_EXT_PARAMS2
+ mvc __PT_INT_CODE(4,%r11),__LC_EXT_CPU_ADDR
+ mvc __PT_INT_PARM(4,%r11),__LC_EXT_PARAMS
+ mvc __PT_INT_PARM_LONG(8,%r11),0(%r1)
TRACE_IRQS_OFF
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
- lghi %r1,4096
lgr %r2,%r11 # pass pointer to pt_regs
- llgf %r3,__LC_EXT_CPU_ADDR # get cpu address + interruption code
- llgf %r4,__LC_EXT_PARAMS # get external parameter
- lg %r5,__LC_EXT_PARAMS2-4096(%r1) # get 64 bit external parameter
brasl %r14,do_extint
j io_return
@@ -643,7 +654,7 @@ ENTRY(mcck_int_handler)
lg %r12,__LC_THREAD_INFO
larl %r13,system_call
lmg %r8,%r9,__LC_MCK_OLD_PSW
- HANDLE_SIE_INTERCEPT %r14,0
+ HANDLE_SIE_INTERCEPT %r14,4
tm __LC_MCCK_CODE,0x80 # system damage?
jo mcck_panic # yes -> rest of mcck code invalid
lghi %r14,__LC_CPU_TIMER_SAVE_AREA
@@ -937,56 +948,50 @@ ENTRY(sie64a)
stmg %r6,%r14,__SF_GPRS(%r15) # save kernel registers
stg %r2,__SF_EMPTY(%r15) # save control block pointer
stg %r3,__SF_EMPTY+8(%r15) # save guest register save area
- xc __SF_EMPTY+16(8,%r15),__SF_EMPTY+16(%r15) # host id == 0
+ xc __SF_EMPTY+16(16,%r15),__SF_EMPTY+16(%r15) # host id & reason
lmg %r0,%r13,0(%r3) # load guest gprs 0-13
-# some program checks are suppressing. C code (e.g. do_protection_exception)
-# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
-# instructions in the sie_loop should not cause program interrupts. So
-# lets use a nop (47 00 00 00) as a landing pad.
-# See also HANDLE_SIE_INTERCEPT
-rewind_pad:
- nop 0
-sie_loop:
- lg %r14,__LC_THREAD_INFO # pointer thread_info struct
- tm __TI_flags+7(%r14),_TIF_EXIT_SIE
- jnz sie_exit
lg %r14,__LC_GMAP # get gmap pointer
ltgr %r14,%r14
jz sie_gmap
lctlg %c1,%c1,__GMAP_ASCE(%r14) # load primary asce
sie_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...
+ jnz sie_done
LPP __SF_EMPTY(%r15) # set guest id
sie 0(%r14)
sie_done:
LPP __SF_EMPTY+16(%r15) # set host id
- lg %r14,__LC_THREAD_INFO # pointer thread_info struct
-sie_exit:
+ ni __SIE_PROG0C+3(%r14),0xfe # no longer in SIE
lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
+# some program checks are suppressing. C code (e.g. do_protection_exception)
+# will rewind the PSW by the ILC, which is 4 bytes in case of SIE. Other
+# instructions beween sie64a and sie_done should not cause program
+# interrupts. So lets use a nop (47 00 00 00) as a landing pad.
+# See also HANDLE_SIE_INTERCEPT
+rewind_pad:
+ nop 0
+ .globl sie_exit
+sie_exit:
lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
stmg %r0,%r13,0(%r14) # save guest gprs 0-13
lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
- lghi %r2,0
+ lg %r2,__SF_EMPTY+24(%r15) # return exit reason code
br %r14
sie_fault:
- lctlg %c1,%c1,__LC_USER_ASCE # load primary asce
- lg %r14,__LC_THREAD_INFO # pointer thread_info struct
- lg %r14,__SF_EMPTY+8(%r15) # load guest register save area
- stmg %r0,%r13,0(%r14) # save guest gprs 0-13
- lmg %r6,%r14,__SF_GPRS(%r15) # restore kernel registers
- lghi %r2,-EFAULT
- br %r14
+ lghi %r14,-EFAULT
+ stg %r14,__SF_EMPTY+24(%r15) # set exit reason code
+ j sie_exit
.align 8
-.Lsie_loop:
- .quad sie_loop
-.Lsie_length:
- .quad sie_done - sie_loop
-.Lhost_id:
- .quad 0
+.Lsie_critical:
+ .quad sie_gmap
+.Lsie_critical_length:
+ .quad sie_done - sie_gmap
EX_TABLE(rewind_pad,sie_fault)
- EX_TABLE(sie_loop,sie_fault)
+ EX_TABLE(sie_exit,sie_fault)
#endif
.section .rodata, "a"
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index dd3c1994b8bd..54b0995514e8 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -234,9 +234,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
}
EXPORT_SYMBOL(unregister_external_interrupt);
-void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
- unsigned int param32, unsigned long param64)
+void __irq_entry do_extint(struct pt_regs *regs)
{
+ struct ext_code ext_code;
struct pt_regs *old_regs;
struct ext_int_info *p;
int index;
@@ -248,6 +248,7 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
clock_comparator_work();
}
kstat_incr_irqs_this_cpu(EXTERNAL_INTERRUPT, NULL);
+ ext_code = *(struct ext_code *) &regs->int_code;
if (ext_code.code != 0x1004)
__get_cpu_var(s390_idle).nohz_delay = 1;
@@ -255,7 +256,8 @@ void __irq_entry do_extint(struct pt_regs *regs, struct ext_code ext_code,
rcu_read_lock();
list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
if (likely(p->code == ext_code.code))
- p->handler(ext_code, param32, param64);
+ p->handler(ext_code, regs->int_parm,
+ regs->int_parm_long);
rcu_read_unlock();
irq_exit();
set_irq_regs(old_regs);
diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c
index f58f37f66824..a6fc037671b1 100644
--- a/arch/s390/kernel/perf_event.c
+++ b/arch/s390/kernel/perf_event.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/perf_event.h>
+#include <linux/kvm_host.h>
#include <linux/percpu.h>
#include <linux/export.h>
#include <asm/irq.h>
@@ -39,6 +40,57 @@ int perf_num_counters(void)
}
EXPORT_SYMBOL(perf_num_counters);
+static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
+{
+ struct stack_frame *stack = (struct stack_frame *) regs->gprs[15];
+
+ if (!stack)
+ return NULL;
+
+ return (struct kvm_s390_sie_block *) stack->empty1[0];
+}
+
+static bool is_in_guest(struct pt_regs *regs)
+{
+ unsigned long ip = instruction_pointer(regs);
+
+ if (user_mode(regs))
+ return false;
+
+ return ip == (unsigned long) &sie_exit;
+}
+
+static unsigned long guest_is_user_mode(struct pt_regs *regs)
+{
+ return sie_block(regs)->gpsw.mask & PSW_MASK_PSTATE;
+}
+
+static unsigned long instruction_pointer_guest(struct pt_regs *regs)
+{
+ return sie_block(regs)->gpsw.addr & PSW_ADDR_INSN;
+}
+
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+ return is_in_guest(regs) ? instruction_pointer_guest(regs)
+ : instruction_pointer(regs);
+}
+
+static unsigned long perf_misc_guest_flags(struct pt_regs *regs)
+{
+ return guest_is_user_mode(regs) ? PERF_RECORD_MISC_GUEST_USER
+ : PERF_RECORD_MISC_GUEST_KERNEL;
+}
+
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+ if (is_in_guest(regs))
+ return perf_misc_guest_flags(regs);
+
+ return user_mode(regs) ? PERF_RECORD_MISC_USER
+ : PERF_RECORD_MISC_KERNEL;
+}
+
void perf_event_print_debug(void)
{
struct cpumf_ctr_info cf_info;
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 9bdbcef1da9e..3bac589844a7 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -7,6 +7,7 @@ EXPORT_SYMBOL(_mcount);
#endif
#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
EXPORT_SYMBOL(sie64a);
+EXPORT_SYMBOL(sie_exit);
#endif
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 0a49095104c9..497451ec5e26 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -719,10 +719,6 @@ static void reserve_oldmem(void)
}
create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE);
create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE);
- if (OLDMEM_BASE + OLDMEM_SIZE == real_size)
- saved_max_pfn = PFN_DOWN(OLDMEM_BASE) - 1;
- else
- saved_max_pfn = PFN_DOWN(real_size) - 1;
#endif
}
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 4f977d0d25c2..15a016c10563 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -49,7 +49,6 @@
enum {
ec_schedule = 0,
- ec_call_function,
ec_call_function_single,
ec_stop_cpu,
};
@@ -438,8 +437,6 @@ static void smp_handle_ext_call(void)
smp_stop_cpu();
if (test_bit(ec_schedule, &bits))
scheduler_ipi();
- if (test_bit(ec_call_function, &bits))
- generic_smp_call_function_interrupt();
if (test_bit(ec_call_function_single, &bits))
generic_smp_call_function_single_interrupt();
}
@@ -456,7 +453,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
int cpu;
for_each_cpu(cpu, mask)
- pcpu_ec_call(pcpu_devices + cpu, ec_call_function);
+ pcpu_ec_call(pcpu_devices + cpu, ec_call_function_single);
}
void arch_send_call_function_single_ipi(int cpu)
diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile
index 8fe9d65a4585..40b4c6470f88 100644
--- a/arch/s390/kvm/Makefile
+++ b/arch/s390/kvm/Makefile
@@ -6,7 +6,8 @@
# it under the terms of the GNU General Public License (version 2 only)
# as published by the Free Software Foundation.
-common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o eventfd.o)
+KVM := ../../../virt/kvm
+common-objs = $(KVM)/kvm_main.o $(KVM)/eventfd.o
ccflags-y := -Ivirt/kvm -Iarch/s390/kvm
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 1c01a9912989..3074475c8ae0 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -132,6 +132,9 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
{
int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
trace_kvm_s390_handle_diag(vcpu, code);
switch (code) {
case 0x10:
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index b7d1b2edeeb3..5ee56e5acc23 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -22,87 +22,6 @@
#include "trace.h"
#include "trace-s390.h"
-static int handle_lctlg(struct kvm_vcpu *vcpu)
-{
- int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
- int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
- u64 useraddr;
- int reg, rc;
-
- vcpu->stat.instruction_lctlg++;
-
- useraddr = kvm_s390_get_base_disp_rsy(vcpu);
-
- if (useraddr & 7)
- return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
-
- reg = reg1;
-
- VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3,
- useraddr);
- trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
-
- do {
- rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg],
- (u64 __user *) useraddr);
- if (rc)
- return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
- useraddr += 8;
- if (reg == reg3)
- break;
- reg = (reg + 1) % 16;
- } while (1);
- return 0;
-}
-
-static int handle_lctl(struct kvm_vcpu *vcpu)
-{
- int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
- int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
- u64 useraddr;
- u32 val = 0;
- int reg, rc;
-
- vcpu->stat.instruction_lctl++;
-
- useraddr = kvm_s390_get_base_disp_rs(vcpu);
-
- if (useraddr & 3)
- return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
-
- VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3,
- useraddr);
- trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
-
- reg = reg1;
- do {
- rc = get_guest(vcpu, val, (u32 __user *) useraddr);
- if (rc)
- return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
- vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul;
- vcpu->arch.sie_block->gcr[reg] |= val;
- useraddr += 4;
- if (reg == reg3)
- break;
- reg = (reg + 1) % 16;
- } while (1);
- return 0;
-}
-
-static const intercept_handler_t eb_handlers[256] = {
- [0x2f] = handle_lctlg,
- [0x8a] = kvm_s390_handle_priv_eb,
-};
-
-static int handle_eb(struct kvm_vcpu *vcpu)
-{
- intercept_handler_t handler;
-
- handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
- if (handler)
- return handler(vcpu);
- return -EOPNOTSUPP;
-}
static const intercept_handler_t instruction_handlers[256] = {
[0x01] = kvm_s390_handle_01,
@@ -110,10 +29,10 @@ static const intercept_handler_t instruction_handlers[256] = {
[0x83] = kvm_s390_handle_diag,
[0xae] = kvm_s390_handle_sigp,
[0xb2] = kvm_s390_handle_b2,
- [0xb7] = handle_lctl,
+ [0xb7] = kvm_s390_handle_lctl,
[0xb9] = kvm_s390_handle_b9,
[0xe5] = kvm_s390_handle_e5,
- [0xeb] = handle_eb,
+ [0xeb] = kvm_s390_handle_eb,
};
static int handle_noop(struct kvm_vcpu *vcpu)
@@ -174,47 +93,12 @@ static int handle_stop(struct kvm_vcpu *vcpu)
static int handle_validity(struct kvm_vcpu *vcpu)
{
- unsigned long vmaddr;
int viwhy = vcpu->arch.sie_block->ipb >> 16;
- int rc;
vcpu->stat.exit_validity++;
trace_kvm_s390_intercept_validity(vcpu, viwhy);
- if (viwhy == 0x37) {
- vmaddr = gmap_fault(vcpu->arch.sie_block->prefix,
- vcpu->arch.gmap);
- if (IS_ERR_VALUE(vmaddr)) {
- rc = -EOPNOTSUPP;
- goto out;
- }
- rc = fault_in_pages_writeable((char __user *) vmaddr,
- PAGE_SIZE);
- if (rc) {
- /* user will receive sigsegv, exit to user */
- rc = -EOPNOTSUPP;
- goto out;
- }
- vmaddr = gmap_fault(vcpu->arch.sie_block->prefix + PAGE_SIZE,
- vcpu->arch.gmap);
- if (IS_ERR_VALUE(vmaddr)) {
- rc = -EOPNOTSUPP;
- goto out;
- }
- rc = fault_in_pages_writeable((char __user *) vmaddr,
- PAGE_SIZE);
- if (rc) {
- /* user will receive sigsegv, exit to user */
- rc = -EOPNOTSUPP;
- goto out;
- }
- } else
- rc = -EOPNOTSUPP;
-
-out:
- if (rc)
- VCPU_EVENT(vcpu, 2, "unhandled validity intercept code %d",
- viwhy);
- return rc;
+ WARN_ONCE(true, "kvm: unhandled validity intercept 0x%x\n", viwhy);
+ return -EOPNOTSUPP;
}
static int handle_instruction(struct kvm_vcpu *vcpu)
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 5c948177529e..7f35cb33e510 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -438,7 +438,7 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
no_timer:
spin_lock(&vcpu->arch.local_int.float_int->lock);
spin_lock_bh(&vcpu->arch.local_int.lock);
- add_wait_queue(&vcpu->arch.local_int.wq, &wait);
+ add_wait_queue(&vcpu->wq, &wait);
while (list_empty(&vcpu->arch.local_int.list) &&
list_empty(&vcpu->arch.local_int.float_int->list) &&
(!vcpu->arch.local_int.timer_due) &&
@@ -452,7 +452,7 @@ no_timer:
}
__unset_cpu_idle(vcpu);
__set_current_state(TASK_RUNNING);
- remove_wait_queue(&vcpu->arch.local_int.wq, &wait);
+ remove_wait_queue(&vcpu->wq, &wait);
spin_unlock_bh(&vcpu->arch.local_int.lock);
spin_unlock(&vcpu->arch.local_int.float_int->lock);
hrtimer_try_to_cancel(&vcpu->arch.ckc_timer);
@@ -465,8 +465,8 @@ void kvm_s390_tasklet(unsigned long parm)
spin_lock(&vcpu->arch.local_int.lock);
vcpu->arch.local_int.timer_due = 1;
- if (waitqueue_active(&vcpu->arch.local_int.wq))
- wake_up_interruptible(&vcpu->arch.local_int.wq);
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
spin_unlock(&vcpu->arch.local_int.lock);
}
@@ -613,7 +613,7 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
spin_lock_bh(&li->lock);
list_add(&inti->list, &li->list);
atomic_set(&li->active, 1);
- BUG_ON(waitqueue_active(&li->wq));
+ BUG_ON(waitqueue_active(li->wq));
spin_unlock_bh(&li->lock);
return 0;
}
@@ -746,8 +746,8 @@ int kvm_s390_inject_vm(struct kvm *kvm,
li = fi->local_int[sigcpu];
spin_lock_bh(&li->lock);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- if (waitqueue_active(&li->wq))
- wake_up_interruptible(&li->wq);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
spin_unlock(&fi->lock);
mutex_unlock(&kvm->lock);
@@ -832,8 +832,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
if (inti->type == KVM_S390_SIGP_STOP)
li->action_bits |= ACTION_STOP_ON_STOP;
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- if (waitqueue_active(&li->wq))
- wake_up_interruptible(&vcpu->arch.local_int.wq);
+ if (waitqueue_active(&vcpu->wq))
+ wake_up_interruptible(&vcpu->wq);
spin_unlock_bh(&li->lock);
mutex_unlock(&vcpu->kvm->lock);
return 0;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index c1c7c683fa26..ba694d2ba51e 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -59,6 +59,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
{ "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
{ "exit_wait_state", VCPU_STAT(exit_wait_state) },
+ { "instruction_pfmf", VCPU_STAT(instruction_pfmf) },
{ "instruction_stidp", VCPU_STAT(instruction_stidp) },
{ "instruction_spx", VCPU_STAT(instruction_spx) },
{ "instruction_stpx", VCPU_STAT(instruction_stpx) },
@@ -84,6 +85,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
};
static unsigned long long *facilities;
+static struct gmap_notifier gmap_notifier;
/* Section: not file related */
int kvm_arch_hardware_enable(void *garbage)
@@ -96,13 +98,18 @@ void kvm_arch_hardware_disable(void *garbage)
{
}
+static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address);
+
int kvm_arch_hardware_setup(void)
{
+ gmap_notifier.notifier_call = kvm_gmap_notifier;
+ gmap_register_ipte_notifier(&gmap_notifier);
return 0;
}
void kvm_arch_hardware_unsetup(void)
{
+ gmap_unregister_ipte_notifier(&gmap_notifier);
}
void kvm_arch_check_processor_compat(void *rtn)
@@ -239,6 +246,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.gmap = gmap_alloc(current->mm);
if (!kvm->arch.gmap)
goto out_nogmap;
+ kvm->arch.gmap->private = kvm;
}
kvm->arch.css_support = 0;
@@ -270,7 +278,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
free_page((unsigned long)(vcpu->arch.sie_block));
kvm_vcpu_uninit(vcpu);
- kfree(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
}
static void kvm_free_vcpus(struct kvm *kvm)
@@ -309,6 +317,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
vcpu->arch.gmap = gmap_alloc(current->mm);
if (!vcpu->arch.gmap)
return -ENOMEM;
+ vcpu->arch.gmap->private = vcpu->kvm;
return 0;
}
@@ -373,8 +382,10 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
{
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
CPUSTAT_SM |
- CPUSTAT_STOPPED);
+ CPUSTAT_STOPPED |
+ CPUSTAT_GED);
vcpu->arch.sie_block->ecb = 6;
+ vcpu->arch.sie_block->ecb2 = 8;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) facilities;
hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
@@ -397,7 +408,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
rc = -ENOMEM;
- vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+ vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
if (!vcpu)
goto out;
@@ -427,7 +438,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
spin_lock(&kvm->arch.float_int.lock);
kvm->arch.float_int.local_int[id] = &vcpu->arch.local_int;
- init_waitqueue_head(&vcpu->arch.local_int.wq);
+ vcpu->arch.local_int.wq = &vcpu->wq;
vcpu->arch.local_int.cpuflags = &vcpu->arch.sie_block->cpuflags;
spin_unlock(&kvm->arch.float_int.lock);
@@ -442,7 +453,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
out_free_sie_block:
free_page((unsigned long)(vcpu->arch.sie_block));
out_free_cpu:
- kfree(vcpu);
+ kmem_cache_free(kvm_vcpu_cache, vcpu);
out:
return ERR_PTR(rc);
}
@@ -454,6 +465,50 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
return 0;
}
+void s390_vcpu_block(struct kvm_vcpu *vcpu)
+{
+ atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20);
+}
+
+void s390_vcpu_unblock(struct kvm_vcpu *vcpu)
+{
+ atomic_clear_mask(PROG_BLOCK_SIE, &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
+ * return immediately. */
+void exit_sie(struct kvm_vcpu *vcpu)
+{
+ atomic_set_mask(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags);
+ while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE)
+ cpu_relax();
+}
+
+/* Kick a guest cpu out of SIE and prevent SIE-reentry */
+void exit_sie_sync(struct kvm_vcpu *vcpu)
+{
+ s390_vcpu_block(vcpu);
+ exit_sie(vcpu);
+}
+
+static void kvm_gmap_notifier(struct gmap *gmap, unsigned long address)
+{
+ int i;
+ struct kvm *kvm = gmap->private;
+ struct kvm_vcpu *vcpu;
+
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ /* match against both prefix pages */
+ if (vcpu->arch.sie_block->prefix == (address & ~0x1000UL)) {
+ VCPU_EVENT(vcpu, 2, "gmap notifier for %lx", address);
+ kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
+ exit_sie_sync(vcpu);
+ }
+ }
+}
+
int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
{
/* kvm common code refers to this, but never calls it */
@@ -606,6 +661,27 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return -EINVAL; /* not implemented yet */
}
+static int kvm_s390_handle_requests(struct kvm_vcpu *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.
+ * This ensures that the ipte instruction for this request has
+ * already finished. We might race against a second unmapper that
+ * wants to set the blocking bit. Lets just retry the request loop.
+ */
+ while (kvm_check_request(KVM_REQ_MMU_RELOAD, vcpu)) {
+ int rc;
+ rc = gmap_ipte_notify(vcpu->arch.gmap,
+ vcpu->arch.sie_block->prefix,
+ PAGE_SIZE * 2);
+ if (rc)
+ return rc;
+ s390_vcpu_unblock(vcpu);
+ }
+ return 0;
+}
+
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
int rc;
@@ -621,6 +697,10 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
if (!kvm_is_ucontrol(vcpu->kvm))
kvm_s390_deliver_pending_interrupts(vcpu);
+ rc = kvm_s390_handle_requests(vcpu);
+ if (rc)
+ return rc;
+
vcpu->arch.sie_block->icptcode = 0;
preempt_disable();
kvm_guest_enter();
@@ -630,7 +710,9 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
trace_kvm_s390_sie_enter(vcpu,
atomic_read(&vcpu->arch.sie_block->cpuflags));
rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
- if (rc) {
+ if (rc > 0)
+ rc = 0;
+ if (rc < 0) {
if (kvm_is_ucontrol(vcpu->kvm)) {
rc = SIE_INTERCEPT_UCONTROL;
} else {
@@ -1046,7 +1128,7 @@ static int __init kvm_s390_init(void)
return -ENOMEM;
}
memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
- facilities[0] &= 0xff00fff3f47c0000ULL;
+ facilities[0] &= 0xff82fff3f47c0000ULL;
facilities[1] &= 0x001c000000000000ULL;
return 0;
}
@@ -1059,3 +1141,12 @@ static void __exit kvm_s390_exit(void)
module_init(kvm_s390_init);
module_exit(kvm_s390_exit);
+
+/*
+ * Enable autoloading of the kvm module.
+ * Note that we add the module alias here instead of virt/kvm/kvm_main.c
+ * since x86 takes a different approach.
+ */
+#include <linux/miscdevice.h>
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index efc14f687265..028ca9fd2158 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -63,6 +63,7 @@ static inline void kvm_s390_set_prefix(struct kvm_vcpu *vcpu, u32 prefix)
{
vcpu->arch.sie_block->prefix = prefix & 0x7fffe000u;
vcpu->arch.sie_block->ihcpu = 0xffff;
+ kvm_make_request(KVM_REQ_MMU_RELOAD, vcpu);
}
static inline u64 kvm_s390_get_base_disp_s(struct kvm_vcpu *vcpu)
@@ -85,6 +86,12 @@ static inline void kvm_s390_get_base_disp_sse(struct kvm_vcpu *vcpu,
*address2 = (base2 ? vcpu->run->s.regs.gprs[base2] : 0) + disp2;
}
+static inline void kvm_s390_get_regs_rre(struct kvm_vcpu *vcpu, int *r1, int *r2)
+{
+ *r1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 20;
+ *r2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16;
+}
+
static inline u64 kvm_s390_get_base_disp_rsy(struct kvm_vcpu *vcpu)
{
u32 base2 = vcpu->arch.sie_block->ipb >> 28;
@@ -125,7 +132,8 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu);
int kvm_s390_handle_01(struct kvm_vcpu *vcpu);
int kvm_s390_handle_b9(struct kvm_vcpu *vcpu);
int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu);
-int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu);
+int kvm_s390_handle_eb(struct kvm_vcpu *vcpu);
/* implemented in sigp.c */
int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
@@ -133,6 +141,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
/* implemented in kvm-s390.c */
int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu,
unsigned long addr);
+void s390_vcpu_block(struct kvm_vcpu *vcpu);
+void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
+void exit_sie(struct kvm_vcpu *vcpu);
+void exit_sie_sync(struct kvm_vcpu *vcpu);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 6bbd7b5a0bbe..0da3e6eb6be6 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -1,7 +1,7 @@
/*
* handling privileged instructions
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2013
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
@@ -20,6 +20,9 @@
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <asm/sysinfo.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
#include <asm/ptrace.h>
#include <asm/compat.h>
#include "gaccess.h"
@@ -34,6 +37,9 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_spx++;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
operand2 = kvm_s390_get_base_disp_s(vcpu);
/* must be word boundary */
@@ -65,6 +71,9 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_stpx++;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
operand2 = kvm_s390_get_base_disp_s(vcpu);
/* must be word boundary */
@@ -89,6 +98,9 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_stap++;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
useraddr = kvm_s390_get_base_disp_s(vcpu);
if (useraddr & 1)
@@ -105,7 +117,12 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
static int handle_skey(struct kvm_vcpu *vcpu)
{
vcpu->stat.instruction_storage_key++;
- vcpu->arch.sie_block->gpsw.addr -= 4;
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ vcpu->arch.sie_block->gpsw.addr =
+ __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
VCPU_EVENT(vcpu, 4, "%s", "retrying storage key operation");
return 0;
}
@@ -129,9 +146,10 @@ static int handle_tpi(struct kvm_vcpu *vcpu)
* Store the two-word I/O interruption code into the
* provided area.
*/
- put_guest(vcpu, inti->io.subchannel_id, (u16 __user *) addr);
- put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *) (addr + 2));
- put_guest(vcpu, inti->io.io_int_parm, (u32 __user *) (addr + 4));
+ if (put_guest(vcpu, inti->io.subchannel_id, (u16 __user *)addr)
+ || put_guest(vcpu, inti->io.subchannel_nr, (u16 __user *)(addr + 2))
+ || put_guest(vcpu, inti->io.io_int_parm, (u32 __user *)(addr + 4)))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
} else {
/*
* Store the three-word I/O interruption code into
@@ -182,6 +200,9 @@ static int handle_io_inst(struct kvm_vcpu *vcpu)
{
VCPU_EVENT(vcpu, 4, "%s", "I/O instruction");
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
if (vcpu->kvm->arch.css_support) {
/*
* Most I/O instructions will be handled by userspace.
@@ -210,8 +231,12 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
int rc;
vcpu->stat.instruction_stfl++;
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
/* only pass the facility bits, which we can handle */
- facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
+ facility_list = S390_lowcore.stfl_fac_list & 0xff82fff3;
rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
&facility_list, sizeof(facility_list));
@@ -255,8 +280,8 @@ int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu)
u64 addr;
if (gpsw->mask & PSW_MASK_PSTATE)
- return kvm_s390_inject_program_int(vcpu,
- PGM_PRIVILEGED_OPERATION);
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
addr = kvm_s390_get_base_disp_s(vcpu);
if (addr & 7)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -278,6 +303,9 @@ static int handle_lpswe(struct kvm_vcpu *vcpu)
psw_t new_psw;
u64 addr;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
addr = kvm_s390_get_base_disp_s(vcpu);
if (addr & 7)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
@@ -296,6 +324,9 @@ static int handle_stidp(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_stidp++;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
operand2 = kvm_s390_get_base_disp_s(vcpu);
if (operand2 & 7)
@@ -351,16 +382,30 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_stsi++;
VCPU_EVENT(vcpu, 4, "stsi: fc: %x sel1: %x sel2: %x", fc, sel1, sel2);
- operand2 = kvm_s390_get_base_disp_s(vcpu);
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ if (fc > 3) {
+ vcpu->arch.sie_block->gpsw.mask |= 3ul << 44; /* cc 3 */
+ return 0;
+ }
- if (operand2 & 0xfff && fc > 0)
+ if (vcpu->run->s.regs.gprs[0] & 0x0fffff00
+ || vcpu->run->s.regs.gprs[1] & 0xffff0000)
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
- switch (fc) {
- case 0:
+ if (fc == 0) {
vcpu->run->s.regs.gprs[0] = 3 << 28;
- vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
+ vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44); /* cc 0 */
return 0;
+ }
+
+ operand2 = kvm_s390_get_base_disp_s(vcpu);
+
+ if (operand2 & 0xfff)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ switch (fc) {
case 1: /* same handling for 1 and 2 */
case 2:
mem = get_zeroed_page(GFP_KERNEL);
@@ -377,8 +422,6 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
goto out_no_data;
handle_stsi_3_2_2(vcpu, (void *) mem);
break;
- default:
- goto out_no_data;
}
if (copy_to_guest_absolute(vcpu, operand2, (void *) mem, PAGE_SIZE)) {
@@ -432,20 +475,14 @@ int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
intercept_handler_t handler;
/*
- * a lot of B2 instructions are priviledged. We first check for
- * the privileged ones, that we can handle in the kernel. If the
- * kernel can handle this instruction, we check for the problem
- * state bit and (a) handle the instruction or (b) send a code 2
- * program check.
- * Anything else goes to userspace.*/
+ * A lot of B2 instructions are priviledged. Here we check for
+ * the privileged ones, that we can handle in the kernel.
+ * Anything else goes to userspace.
+ */
handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
- if (handler) {
- if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
- return kvm_s390_inject_program_int(vcpu,
- PGM_PRIVILEGED_OPERATION);
- else
- return handler(vcpu);
- }
+ if (handler)
+ return handler(vcpu);
+
return -EOPNOTSUPP;
}
@@ -453,8 +490,7 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
{
int reg1, reg2;
- reg1 = (vcpu->arch.sie_block->ipb & 0x00f00000) >> 24;
- reg2 = (vcpu->arch.sie_block->ipb & 0x000f0000) >> 16;
+ kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
/* This basically extracts the mask half of the psw. */
vcpu->run->s.regs.gprs[reg1] &= 0xffffffff00000000;
@@ -467,9 +503,88 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
return 0;
}
+#define PFMF_RESERVED 0xfffc0101UL
+#define PFMF_SK 0x00020000UL
+#define PFMF_CF 0x00010000UL
+#define PFMF_UI 0x00008000UL
+#define PFMF_FSC 0x00007000UL
+#define PFMF_NQ 0x00000800UL
+#define PFMF_MR 0x00000400UL
+#define PFMF_MC 0x00000200UL
+#define PFMF_KEY 0x000000feUL
+
+static int handle_pfmf(struct kvm_vcpu *vcpu)
+{
+ int reg1, reg2;
+ unsigned long start, end;
+
+ vcpu->stat.instruction_pfmf++;
+
+ kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
+
+ if (!MACHINE_HAS_PFMF)
+ return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ if (vcpu->run->s.regs.gprs[reg1] & PFMF_RESERVED)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /* Only provide non-quiescing support if the host supports it */
+ if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ &&
+ S390_lowcore.stfl_fac_list & 0x00020000)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /* No support for conditional-SSKE */
+ if (vcpu->run->s.regs.gprs[reg1] & (PFMF_MR | PFMF_MC))
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ start = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
+ switch (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
+ case 0x00000000:
+ end = (start + (1UL << 12)) & ~((1UL << 12) - 1);
+ break;
+ case 0x00001000:
+ end = (start + (1UL << 20)) & ~((1UL << 20) - 1);
+ break;
+ /* We dont support EDAT2
+ case 0x00002000:
+ end = (start + (1UL << 31)) & ~((1UL << 31) - 1);
+ break;*/
+ default:
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ }
+ while (start < end) {
+ unsigned long useraddr;
+
+ useraddr = gmap_translate(start, vcpu->arch.gmap);
+ if (IS_ERR((void *)useraddr))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+
+ if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
+ if (clear_user((void __user *)useraddr, PAGE_SIZE))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ }
+
+ if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) {
+ if (set_guest_storage_key(current->mm, useraddr,
+ vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
+ vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ }
+
+ start += PAGE_SIZE;
+ }
+ if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC)
+ vcpu->run->s.regs.gprs[reg2] = end;
+ return 0;
+}
+
static const intercept_handler_t b9_handlers[256] = {
[0x8d] = handle_epsw,
[0x9c] = handle_io_inst,
+ [0xaf] = handle_pfmf,
};
int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
@@ -478,29 +593,96 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
/* This is handled just as for the B2 instructions. */
handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
- if (handler) {
- if ((handler != handle_epsw) &&
- (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE))
- return kvm_s390_inject_program_int(vcpu,
- PGM_PRIVILEGED_OPERATION);
- else
- return handler(vcpu);
- }
+ if (handler)
+ return handler(vcpu);
+
return -EOPNOTSUPP;
}
+int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu)
+{
+ int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+ int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
+ u64 useraddr;
+ u32 val = 0;
+ int reg, rc;
+
+ vcpu->stat.instruction_lctl++;
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ useraddr = kvm_s390_get_base_disp_rs(vcpu);
+
+ if (useraddr & 3)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3,
+ useraddr);
+ trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
+
+ reg = reg1;
+ do {
+ rc = get_guest(vcpu, val, (u32 __user *) useraddr);
+ if (rc)
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul;
+ vcpu->arch.sie_block->gcr[reg] |= val;
+ useraddr += 4;
+ if (reg == reg3)
+ break;
+ reg = (reg + 1) % 16;
+ } while (1);
+
+ return 0;
+}
+
+static int handle_lctlg(struct kvm_vcpu *vcpu)
+{
+ int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4;
+ int reg3 = vcpu->arch.sie_block->ipa & 0x000f;
+ u64 useraddr;
+ int reg, rc;
+
+ vcpu->stat.instruction_lctlg++;
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ useraddr = kvm_s390_get_base_disp_rsy(vcpu);
+
+ if (useraddr & 7)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ reg = reg1;
+
+ VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3,
+ useraddr);
+ trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
+
+ do {
+ rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg],
+ (u64 __user *) useraddr);
+ if (rc)
+ return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
+ useraddr += 8;
+ if (reg == reg3)
+ break;
+ reg = (reg + 1) % 16;
+ } while (1);
+
+ return 0;
+}
+
static const intercept_handler_t eb_handlers[256] = {
+ [0x2f] = handle_lctlg,
[0x8a] = handle_io_inst,
};
-int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu)
+int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
{
intercept_handler_t handler;
- /* All eb instructions that end up here are privileged. */
- if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
- return kvm_s390_inject_program_int(vcpu,
- PGM_PRIVILEGED_OPERATION);
handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
if (handler)
return handler(vcpu);
@@ -515,6 +697,9 @@ static int handle_tprot(struct kvm_vcpu *vcpu)
vcpu->stat.instruction_tprot++;
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
kvm_s390_get_base_disp_sse(vcpu, &address1, &address2);
/* we only handle the Linux memory detection case:
@@ -560,8 +745,7 @@ static int handle_sckpf(struct kvm_vcpu *vcpu)
u32 value;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
- return kvm_s390_inject_program_int(vcpu,
- PGM_PRIVILEGED_OPERATION);
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
if (vcpu->run->s.regs.gprs[0] & 0x00000000ffff0000)
return kvm_s390_inject_program_int(vcpu,
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index 1c48ab2845e0..bec398c57acf 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -79,8 +79,8 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr)
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- if (waitqueue_active(&li->wq))
- wake_up_interruptible(&li->wq);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr);
@@ -117,8 +117,8 @@ static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr)
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags);
- if (waitqueue_active(&li->wq))
- wake_up_interruptible(&li->wq);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
spin_unlock_bh(&li->lock);
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr);
@@ -145,8 +145,8 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
atomic_set(&li->active, 1);
atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags);
li->action_bits |= action;
- if (waitqueue_active(&li->wq))
- wake_up_interruptible(&li->wq);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
out:
spin_unlock_bh(&li->lock);
@@ -250,8 +250,8 @@ static int __sigp_set_prefix(struct kvm_vcpu *vcpu, u16 cpu_addr, u32 address,
list_add_tail(&inti->list, &li->list);
atomic_set(&li->active, 1);
- if (waitqueue_active(&li->wq))
- wake_up_interruptible(&li->wq);
+ if (waitqueue_active(li->wq))
+ wake_up_interruptible(li->wq);
rc = SIGP_CC_ORDER_CODE_ACCEPTED;
VCPU_EVENT(vcpu, 4, "set prefix of cpu %02x to %x", cpu_addr, address);
@@ -333,8 +333,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
/* sigp in userspace can exit */
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
- return kvm_s390_inject_program_int(vcpu,
- PGM_PRIVILEGED_OPERATION);
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
order_code = kvm_s390_get_base_disp_rs(vcpu);
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 89ebae4008f2..ce36ea80e4f9 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -135,30 +135,17 @@ void __init paging_init(void)
void __init mem_init(void)
{
- unsigned long codesize, reservedpages, datasize, initsize;
-
- max_mapnr = num_physpages = max_low_pfn;
+ max_mapnr = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
/* Setup guest page hinting */
cmma_init();
/* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem();
+ free_all_bootmem();
setup_zero_pages(); /* Setup zeroed pages. */
- reservedpages = 0;
-
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
- printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, %ldk data, %ldk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >>10,
- initsize >> 10);
+ mem_init_print_info(NULL);
printk("Write protected kernel read-only data: %#lx - %#lx\n",
(unsigned long)&_stext,
PFN_ALIGN((unsigned long)&_eshared) - 1);
@@ -166,13 +153,14 @@ void __init mem_init(void)
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index 06bafec00278..40023290ee5b 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -91,11 +91,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base();
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
@@ -176,11 +174,9 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = TASK_UNMAPPED_BASE;
mm->get_unmapped_area = s390_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base();
mm->get_unmapped_area = s390_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index a938b548f07e..a8154a1a2c94 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -689,7 +689,7 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long start, unsigned long len)
entry = *ptep;
if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_RO)) == 0) {
pgste = pgste_get_lock(ptep);
- pgste_val(pgste) |= RCP_IN_BIT;
+ pgste_val(pgste) |= PGSTE_IN_BIT;
pgste_set_unlock(ptep, pgste);
start += PAGE_SIZE;
len -= PAGE_SIZE;
@@ -771,6 +771,54 @@ static inline void page_table_free_pgste(unsigned long *table)
__free_page(page);
}
+int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
+ unsigned long key, bool nq)
+{
+ spinlock_t *ptl;
+ pgste_t old, new;
+ pte_t *ptep;
+
+ down_read(&mm->mmap_sem);
+ ptep = get_locked_pte(current->mm, addr, &ptl);
+ if (unlikely(!ptep)) {
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
+ }
+
+ new = old = pgste_get_lock(ptep);
+ pgste_val(new) &= ~(PGSTE_GR_BIT | PGSTE_GC_BIT |
+ PGSTE_ACC_BITS | PGSTE_FP_BIT);
+ pgste_val(new) |= (key & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48;
+ pgste_val(new) |= (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
+ if (!(pte_val(*ptep) & _PAGE_INVALID)) {
+ unsigned long address, bits;
+ unsigned char skey;
+
+ address = pte_val(*ptep) & PAGE_MASK;
+ skey = page_get_storage_key(address);
+ bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
+ /* Set storage key ACC and FP */
+ page_set_storage_key(address,
+ (key & (_PAGE_ACC_BITS | _PAGE_FP_BIT)),
+ !nq);
+
+ /* Merge host changed & referenced into pgste */
+ pgste_val(new) |= bits << 52;
+ /* Transfer skey changed & referenced bit to kvm user bits */
+ pgste_val(new) |= bits << 45; /* PGSTE_UR_BIT & PGSTE_UC_BIT */
+ }
+ /* changing the guest storage key is considered a change of the page */
+ if ((pgste_val(new) ^ pgste_val(old)) &
+ (PGSTE_ACC_BITS | PGSTE_FP_BIT | PGSTE_GR_BIT | PGSTE_GC_BIT))
+ pgste_val(new) |= PGSTE_UC_BIT;
+
+ pgste_set_unlock(ptep, new);
+ pte_unmap_unlock(*ptep, ptl);
+ up_read(&mm->mmap_sem);
+ return 0;
+}
+EXPORT_SYMBOL(set_guest_storage_key);
+
#else /* CONFIG_PGSTE */
static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
@@ -1117,7 +1165,8 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
}
}
-void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable)
+void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable)
{
struct list_head *lh = (struct list_head *) pgtable;
@@ -1131,7 +1180,7 @@ void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable)
mm->pmd_huge_pte = pgtable;
}
-pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm)
+pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
{
struct list_head *lh;
pgtable_t pgtable;
diff --git a/arch/s390/oprofile/hwsampler.h b/arch/s390/oprofile/hwsampler.h
index 1912f3bb190c..0022e1ebfbde 100644
--- a/arch/s390/oprofile/hwsampler.h
+++ b/arch/s390/oprofile/hwsampler.h
@@ -81,8 +81,8 @@ struct hws_data_entry {
unsigned int:16;
unsigned int prim_asn:16; /* primary ASN */
unsigned long long ia; /* Instruction Address */
- unsigned long long lpp; /* Logical-Partition Program Param. */
- unsigned long long vpp; /* Virtual-Machine Program Param. */
+ unsigned long long gpp; /* Guest Program Parameter */
+ unsigned long long hpp; /* Host Program Parameter */
};
struct hws_trailer_entry {
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index f1e5be85d592..e2956ad39a4f 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -82,10 +82,13 @@ struct intr_bucket {
static struct intr_bucket *bucket;
-/* Adapter local summary indicator */
-static u8 *zpci_irq_si;
+/* Adapter interrupt definitions */
+static void zpci_irq_handler(struct airq_struct *airq);
-static atomic_t irq_retries = ATOMIC_INIT(0);
+static struct airq_struct zpci_airq = {
+ .handler = zpci_irq_handler,
+ .isc = PCI_ISC,
+};
/* I/O Map */
static DEFINE_SPINLOCK(zpci_iomap_lock);
@@ -404,7 +407,7 @@ static struct pci_ops pci_root_ops = {
/* store the last handled bit to implement fair scheduling of devices */
static DEFINE_PER_CPU(unsigned long, next_sbit);
-static void zpci_irq_handler(void *dont, void *need)
+static void zpci_irq_handler(struct airq_struct *airq)
{
unsigned long sbit, mbit, last = 0, start = __get_cpu_var(next_sbit);
int rescan = 0, max = aisb_max;
@@ -452,7 +455,6 @@ scan:
max = aisb_max;
sbit = find_first_bit_left(bucket->aisb, max);
if (sbit != max) {
- atomic_inc(&irq_retries);
rescan++;
goto scan;
}
@@ -565,7 +567,21 @@ static void zpci_map_resources(struct zpci_dev *zdev)
pr_debug("BAR%i: -> start: %Lx end: %Lx\n",
i, pdev->resource[i].start, pdev->resource[i].end);
}
-};
+}
+
+static void zpci_unmap_resources(struct zpci_dev *zdev)
+{
+ struct pci_dev *pdev = zdev->pdev;
+ resource_size_t len;
+ int i;
+
+ for (i = 0; i < PCI_BAR_COUNT; i++) {
+ len = pci_resource_len(pdev, i);
+ if (!len)
+ continue;
+ pci_iounmap(pdev, (void *) pdev->resource[i].start);
+ }
+}
struct zpci_dev *zpci_alloc_device(void)
{
@@ -701,25 +717,20 @@ static int __init zpci_irq_init(void)
goto out_alloc;
}
- isc_register(PCI_ISC);
- zpci_irq_si = s390_register_adapter_interrupt(&zpci_irq_handler, NULL, PCI_ISC);
- if (IS_ERR(zpci_irq_si)) {
- rc = PTR_ERR(zpci_irq_si);
- zpci_irq_si = NULL;
+ rc = register_adapter_interrupt(&zpci_airq);
+ if (rc)
goto out_ai;
- }
+ /* Set summary to 1 to be called every time for the ISC. */
+ *zpci_airq.lsi_ptr = 1;
for_each_online_cpu(cpu)
per_cpu(next_sbit, cpu) = 0;
spin_lock_init(&bucket->lock);
- /* set summary to 1 to be called every time for the ISC */
- *zpci_irq_si = 1;
set_irq_ctrl(SIC_IRQ_MODE_SINGLE, NULL, PCI_ISC);
return 0;
out_ai:
- isc_unregister(PCI_ISC);
free_page((unsigned long) bucket->alloc);
out_alloc:
free_page((unsigned long) bucket->aisb);
@@ -732,21 +743,10 @@ static void zpci_irq_exit(void)
{
free_page((unsigned long) bucket->alloc);
free_page((unsigned long) bucket->aisb);
- s390_unregister_adapter_interrupt(zpci_irq_si, PCI_ISC);
- isc_unregister(PCI_ISC);
+ unregister_adapter_interrupt(&zpci_airq);
kfree(bucket);
}
-void zpci_debug_info(struct zpci_dev *zdev, struct seq_file *m)
-{
- if (!zdev)
- return;
-
- seq_printf(m, "global irq retries: %u\n", atomic_read(&irq_retries));
- seq_printf(m, "aibv[0]:%016lx aibv[1]:%016lx aisb:%016lx\n",
- get_imap(0)->aibv, get_imap(1)->aibv, *bucket->aisb);
-}
-
static struct resource *zpci_alloc_bus_resource(unsigned long start, unsigned long size,
unsigned long flags, int domain)
{
@@ -810,6 +810,16 @@ int pcibios_add_device(struct pci_dev *pdev)
return 0;
}
+void pcibios_release_device(struct pci_dev *pdev)
+{
+ struct zpci_dev *zdev = get_zdev(pdev);
+
+ zpci_unmap_resources(zdev);
+ zpci_fmb_disable_device(zdev);
+ zpci_debug_exit_device(zdev);
+ zdev->pdev = NULL;
+}
+
static int zpci_scan_bus(struct zpci_dev *zdev)
{
struct resource *res;
@@ -950,25 +960,6 @@ void zpci_stop_device(struct zpci_dev *zdev)
}
EXPORT_SYMBOL_GPL(zpci_stop_device);
-int zpci_scan_device(struct zpci_dev *zdev)
-{
- zdev->pdev = pci_scan_single_device(zdev->bus, ZPCI_DEVFN);
- if (!zdev->pdev) {
- pr_err("pci_scan_single_device failed for fid: 0x%x\n",
- zdev->fid);
- goto out;
- }
-
- pci_bus_add_devices(zdev->bus);
-
- return 0;
-out:
- zpci_dma_exit_device(zdev);
- clp_disable_fh(zdev);
- return -EIO;
-}
-EXPORT_SYMBOL_GPL(zpci_scan_device);
-
static inline int barsize(u8 size)
{
return (size) ? (1 << size) >> 10 : 0;
diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c
index bd34359d1546..2e9539625d93 100644
--- a/arch/s390/pci/pci_clp.c
+++ b/arch/s390/pci/pci_clp.c
@@ -236,7 +236,6 @@ int clp_disable_fh(struct zpci_dev *zdev)
if (!zdev_enabled(zdev))
return 0;
- dev_info(&zdev->pdev->dev, "disabling fn handle: 0x%x\n", fh);
rc = clp_set_pci_fn(&fh, 0, CLP_SET_DISABLE_PCI_FN);
if (!rc)
/* Success -> store disabled handle in zdev */
diff --git a/arch/s390/pci/pci_debug.c b/arch/s390/pci/pci_debug.c
index 771b82359af4..75c69b402e05 100644
--- a/arch/s390/pci/pci_debug.c
+++ b/arch/s390/pci/pci_debug.c
@@ -115,27 +115,6 @@ static const struct file_operations debugfs_pci_perf_fops = {
.release = single_release,
};
-static int pci_debug_show(struct seq_file *m, void *v)
-{
- struct zpci_dev *zdev = m->private;
-
- zpci_debug_info(zdev, m);
- return 0;
-}
-
-static int pci_debug_seq_open(struct inode *inode, struct file *filp)
-{
- return single_open(filp, pci_debug_show,
- file_inode(filp)->i_private);
-}
-
-static const struct file_operations debugfs_pci_debug_fops = {
- .open = pci_debug_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
void zpci_debug_init_device(struct zpci_dev *zdev)
{
zdev->debugfs_dev = debugfs_create_dir(dev_name(&zdev->pdev->dev),
@@ -149,19 +128,11 @@ void zpci_debug_init_device(struct zpci_dev *zdev)
&debugfs_pci_perf_fops);
if (IS_ERR(zdev->debugfs_perf))
zdev->debugfs_perf = NULL;
-
- zdev->debugfs_debug = debugfs_create_file("debug",
- S_IFREG | S_IRUGO | S_IWUSR,
- zdev->debugfs_dev, zdev,
- &debugfs_pci_debug_fops);
- if (IS_ERR(zdev->debugfs_debug))
- zdev->debugfs_debug = NULL;
}
void zpci_debug_exit_device(struct zpci_dev *zdev)
{
debugfs_remove(zdev->debugfs_perf);
- debugfs_remove(zdev->debugfs_debug);
debugfs_remove(zdev->debugfs_dev);
}
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index f8e69d5bc0a9..a2343c1f6e04 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -263,7 +263,7 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
enum dma_data_direction direction,
struct dma_attrs *attrs)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
unsigned long nr_pages, iommu_page_index;
unsigned long pa = page_to_phys(page) + offset;
int flags = ZPCI_PTE_VALID;
@@ -304,7 +304,7 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction direction,
struct dma_attrs *attrs)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
unsigned long iommu_page_index;
int npages;
@@ -323,7 +323,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag,
struct dma_attrs *attrs)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
struct page *page;
unsigned long pa;
dma_addr_t map;
diff --git a/arch/s390/pci/pci_sysfs.c b/arch/s390/pci/pci_sysfs.c
index a42cce69d0a0..e99a2557f186 100644
--- a/arch/s390/pci/pci_sysfs.c
+++ b/arch/s390/pci/pci_sysfs.c
@@ -15,40 +15,36 @@
static ssize_t show_fid(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
- sprintf(buf, "0x%08x\n", zdev->fid);
- return strlen(buf);
+ return sprintf(buf, "0x%08x\n", zdev->fid);
}
static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL);
static ssize_t show_fh(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
- sprintf(buf, "0x%08x\n", zdev->fh);
- return strlen(buf);
+ return sprintf(buf, "0x%08x\n", zdev->fh);
}
static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL);
static ssize_t show_pchid(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
- sprintf(buf, "0x%04x\n", zdev->pchid);
- return strlen(buf);
+ return sprintf(buf, "0x%04x\n", zdev->pchid);
}
static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL);
static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct zpci_dev *zdev = get_zdev(container_of(dev, struct pci_dev, dev));
+ struct zpci_dev *zdev = get_zdev(to_pci_dev(dev));
- sprintf(buf, "0x%02x\n", zdev->pfgid);
- return strlen(buf);
+ return sprintf(buf, "0x%02x\n", zdev->pfgid);
}
static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL);
diff --git a/arch/score/include/asm/Kbuild b/arch/score/include/asm/Kbuild
index cebaff8069a1..e1c7bb999b06 100644
--- a/arch/score/include/asm/Kbuild
+++ b/arch/score/include/asm/Kbuild
@@ -3,3 +3,4 @@ header-y +=
generic-y += clkdev.h
generic-y += trace_clock.h
+generic-y += xor.h
diff --git a/arch/score/include/asm/dma-mapping.h b/arch/score/include/asm/dma-mapping.h
deleted file mode 100644
index f9c0193c7a53..000000000000
--- a/arch/score/include/asm/dma-mapping.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SCORE_DMA_MAPPING_H
-#define _ASM_SCORE_DMA_MAPPING_H
-
-#include <asm-generic/dma-mapping-broken.h>
-
-#endif /* _ASM_SCORE_DMA_MAPPING_H */
diff --git a/arch/score/kernel/vmlinux.lds.S b/arch/score/kernel/vmlinux.lds.S
index eebcbaa4e978..7274b5c4287e 100644
--- a/arch/score/kernel/vmlinux.lds.S
+++ b/arch/score/kernel/vmlinux.lds.S
@@ -49,6 +49,7 @@ SECTIONS
}
. = ALIGN(16);
+ _sdata = .; /* Start of data section */
RODATA
EXCEPTION_TABLE(16)
diff --git a/arch/score/mm/fault.c b/arch/score/mm/fault.c
index 47b600e4b2c5..6b18fb0189ae 100644
--- a/arch/score/mm/fault.c
+++ b/arch/score/mm/fault.c
@@ -172,10 +172,10 @@ out_of_memory:
down_read(&mm->mmap_sem);
goto survive;
}
- printk("VM: killing process %s\n", tsk->comm);
- if (user_mode(regs))
- do_group_exit(SIGKILL);
- goto no_context;
+ if (!user_mode(regs))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
do_sigbus:
up_read(&mm->mmap_sem);
diff --git a/arch/score/mm/init.c b/arch/score/mm/init.c
index 0940682ab38b..9fbce49ad3bd 100644
--- a/arch/score/mm/init.c
+++ b/arch/score/mm/init.c
@@ -75,40 +75,19 @@ void __init paging_init(void)
void __init mem_init(void)
{
- unsigned long codesize, reservedpages, datasize, initsize;
- unsigned long tmp, ram = 0;
-
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
- totalram_pages += free_all_bootmem();
+ free_all_bootmem();
setup_zero_page(); /* Setup zeroed pages. */
- reservedpages = 0;
-
- for (tmp = 0; tmp < max_low_pfn; tmp++)
- if (page_is_ram(tmp)) {
- ram++;
- if (PageReserved(pfn_to_page(tmp)))
- reservedpages++;
- }
-
- num_physpages = ram;
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
- "%ldk reserved, %ldk data, %ldk init, %ldk highmem)\n",
- (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- ram << (PAGE_SHIFT-10), codesize >> 10,
- reservedpages << (PAGE_SHIFT-10), datasize >> 10,
- initsize >> 10,
- totalhigh_pages << (PAGE_SHIFT-10));
+
+ mem_init_print_info(NULL);
}
#endif /* !CONFIG_NEED_MULTIPLE_NODES */
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, POISON_FREE_INITMEM, "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/sh/boards/board-espt.c b/arch/sh/boards/board-espt.c
index d71a0bcf8145..4d94dff9015c 100644
--- a/arch/sh/boards/board-espt.c
+++ b/arch/sh/boards/board-espt.c
@@ -85,7 +85,7 @@ static struct sh_eth_plat_data sh7763_eth_pdata = {
};
static struct platform_device espt_eth_device = {
- .name = "sh-eth",
+ .name = "sh7763-gether",
.resource = sh_eth_resources,
.num_resources = ARRAY_SIZE(sh_eth_resources),
.dev = {
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
index 41f86702eb9f..4f114d1cd019 100644
--- a/arch/sh/boards/board-sh7757lcr.c
+++ b/arch/sh/boards/board-sh7757lcr.c
@@ -82,7 +82,7 @@ static struct sh_eth_plat_data sh7757_eth0_pdata = {
};
static struct platform_device sh7757_eth0_device = {
- .name = "sh-eth",
+ .name = "sh7757-ether",
.resource = sh_eth0_resources,
.id = 0,
.num_resources = ARRAY_SIZE(sh_eth0_resources),
@@ -111,7 +111,7 @@ static struct sh_eth_plat_data sh7757_eth1_pdata = {
};
static struct platform_device sh7757_eth1_device = {
- .name = "sh-eth",
+ .name = "sh7757-ether",
.resource = sh_eth1_resources,
.id = 1,
.num_resources = ARRAY_SIZE(sh_eth1_resources),
@@ -157,7 +157,7 @@ static struct sh_eth_plat_data sh7757_eth_giga0_pdata = {
};
static struct platform_device sh7757_eth_giga0_device = {
- .name = "sh-eth",
+ .name = "sh7757-gether",
.resource = sh_eth_giga0_resources,
.id = 2,
.num_resources = ARRAY_SIZE(sh_eth_giga0_resources),
@@ -192,7 +192,7 @@ static struct sh_eth_plat_data sh7757_eth_giga1_pdata = {
};
static struct platform_device sh7757_eth_giga1_device = {
- .name = "sh-eth",
+ .name = "sh7757-gether",
.resource = sh_eth_giga1_resources,
.id = 3,
.num_resources = ARRAY_SIZE(sh_eth_giga1_resources),
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 764530c85aa9..61fade0ffa96 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -165,8 +165,8 @@ static struct sh_eth_plat_data sh_eth_plat = {
};
static struct platform_device sh_eth_device = {
- .name = "sh-eth",
- .id = 0,
+ .name = "sh7724-ether",
+ .id = 0,
.dev = {
.platform_data = &sh_eth_plat,
},
diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c
index 9759d6ba7ffb..658326f44df8 100644
--- a/arch/sh/boards/mach-se/770x/setup.c
+++ b/arch/sh/boards/mach-se/770x/setup.c
@@ -128,8 +128,8 @@ static struct resource sh_eth0_resources[] = {
};
static struct platform_device sh_eth0_device = {
- .name = "sh-eth",
- .id = 0,
+ .name = "sh771x-ether",
+ .id = 0,
.dev = {
.platform_data = PHY_ID,
},
@@ -151,8 +151,8 @@ static struct resource sh_eth1_resources[] = {
};
static struct platform_device sh_eth1_device = {
- .name = "sh-eth",
- .id = 1,
+ .name = "sh771x-ether",
+ .id = 1,
.dev = {
.platform_data = PHY_ID,
},
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 4010e63e82d8..b70180ef3e29 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -380,8 +380,8 @@ static struct sh_eth_plat_data sh_eth_plat = {
};
static struct platform_device sh_eth_device = {
- .name = "sh-eth",
- .id = 0,
+ .name = "sh7724-ether",
+ .id = 0,
.dev = {
.platform_data = &sh_eth_plat,
},
diff --git a/arch/sh/boards/mach-sh7763rdp/setup.c b/arch/sh/boards/mach-sh7763rdp/setup.c
index b7c75298dfb5..50ba481fa240 100644
--- a/arch/sh/boards/mach-sh7763rdp/setup.c
+++ b/arch/sh/boards/mach-sh7763rdp/setup.c
@@ -93,7 +93,7 @@ static struct sh_eth_plat_data sh7763_eth_pdata = {
};
static struct platform_device sh7763rdp_eth_device = {
- .name = "sh-eth",
+ .name = "sh7763-gether",
.resource = sh_eth_resources,
.num_resources = ARRAY_SIZE(sh_eth_resources),
.dev = {
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index e0b740c831c7..bb11e1925178 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -124,8 +124,8 @@ static struct resource eth_resources[] = {
};
static struct platform_device eth_device = {
- .name = "sh-eth",
- .id = -1,
+ .name = "sh7619-ether",
+ .id = -1,
.dev = {
.platform_data = (void *)1,
},
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
index 5f30f805d2f2..0128af3399b7 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c
@@ -329,7 +329,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[HWBLK_IIC0]),
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[HWBLK_IIC1]),
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[HWBLK_MMC]),
- CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[HWBLK_ETHER]),
+ CLKDEV_DEV_ID("sh7724-ether.0", &mstp_clks[HWBLK_ETHER]),
CLKDEV_CON_ID("atapi0", &mstp_clks[HWBLK_ATAPI]),
CLKDEV_CON_ID("tpu0", &mstp_clks[HWBLK_TPU]),
CLKDEV_CON_ID("irda0", &mstp_clks[HWBLK_IRDA]),
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
index deb683abacf0..ed9501519ab3 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
@@ -238,7 +238,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("adc0", &mstp_clks[MSTP313]),
CLKDEV_CON_ID("mtu0", &mstp_clks[MSTP312]),
CLKDEV_CON_ID("iebus0", &mstp_clks[MSTP304]),
- CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[MSTP114]),
+ CLKDEV_DEV_ID("sh7734-gether.0", &mstp_clks[MSTP114]),
CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP303]),
CLKDEV_CON_ID("hif0", &mstp_clks[MSTP302]),
CLKDEV_CON_ID("stif0", &mstp_clks[MSTP301]),
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 81f999a672f6..668c81631c08 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -117,11 +117,7 @@ void user_enable_single_step(struct task_struct *child)
set_tsk_thread_flag(child, TIF_SINGLESTEP);
- if (ptrace_get_breakpoints(child) < 0)
- return;
-
set_single_step(child, pc);
- ptrace_put_breakpoints(child);
}
void user_disable_single_step(struct task_struct *child)
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 20f9ead650d3..33890fd267cb 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -407,30 +407,16 @@ unsigned int mem_init_done = 0;
void __init mem_init(void)
{
- int codesize, datasize, initsize;
- int nid;
+ pg_data_t *pgdat;
iommu_init();
- num_physpages = 0;
high_memory = NULL;
+ for_each_online_pgdat(pgdat)
+ high_memory = max_t(void *, high_memory,
+ __va(pgdat_end_pfn(pgdat) << PAGE_SHIFT));
- for_each_online_node(nid) {
- pg_data_t *pgdat = NODE_DATA(nid);
- void *node_high_memory;
-
- num_physpages += pgdat->node_present_pages;
-
- if (pgdat->node_spanned_pages)
- totalram_pages += free_all_bootmem_node(pgdat);
-
-
- node_high_memory = (void *)__va((pgdat->node_start_pfn +
- pgdat->node_spanned_pages) <<
- PAGE_SHIFT);
- if (node_high_memory > high_memory)
- high_memory = node_high_memory;
- }
+ free_all_bootmem();
/* Set this up early, so we can take care of the zero page */
cpu_cache_init();
@@ -441,19 +427,8 @@ void __init mem_init(void)
vsyscall_init();
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
- "%dk data, %dk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- datasize >> 10,
- initsize >> 10);
-
- printk(KERN_INFO "virtual kernel memory layout:\n"
+ mem_init_print_info(NULL);
+ pr_info("virtual kernel memory layout:\n"
" fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
#ifdef CONFIG_HIGHMEM
" pkmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
@@ -499,13 +474,13 @@ void __init mem_init(void)
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index b836e9297f2a..c2f6ff6d7a35 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -108,7 +108,7 @@ static inline int sparc_leon3_snooping_enabled(void)
{
u32 cctrl;
__asm__ __volatile__("lda [%%g0] 2, %0\n\t" : "=r"(cctrl));
- return (cctrl >> 23) & 1;
+ return ((cctrl >> 23) & 1) && ((cctrl >> 17) & 1);
};
static inline void sparc_leon3_disable_cache(void)
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 79c214efa3fe..36760317814f 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -853,10 +853,11 @@ extern void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
pmd_t *pmd);
#define __HAVE_ARCH_PGTABLE_DEPOSIT
-extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable);
+extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable);
#define __HAVE_ARCH_PGTABLE_WITHDRAW
-extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm);
+extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
#endif
/* Encode and de-code a swap entry */
diff --git a/arch/sparc/include/uapi/asm/fcntl.h b/arch/sparc/include/uapi/asm/fcntl.h
index d0b83f66f356..d73e5e008b0d 100644
--- a/arch/sparc/include/uapi/asm/fcntl.h
+++ b/arch/sparc/include/uapi/asm/fcntl.h
@@ -35,6 +35,7 @@
#define O_SYNC (__O_SYNC|O_DSYNC)
#define O_PATH 0x1000000
+#define O_TMPFILE 0x2000000
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index 89f49b68a21c..b46c3fa0b265 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -70,6 +70,8 @@
#define SO_SELECT_ERR_QUEUE 0x0029
+#define SO_LL 0x0030
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
index 961b87f99e69..f76389a32342 100644
--- a/arch/sparc/kernel/asm-offsets.c
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -49,6 +49,8 @@ int foo(void)
DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
BLANK();
DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context));
+ BLANK();
+ DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm));
/* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */
return 0;
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
index 5ef48dab5636..11d460f6f9cc 100644
--- a/arch/sparc/kernel/ds.c
+++ b/arch/sparc/kernel/ds.c
@@ -783,6 +783,16 @@ void ldom_set_var(const char *var, const char *value)
char *base, *p;
int msg_len, loops;
+ if (strlen(var) + strlen(value) + 2 >
+ sizeof(pkt) - sizeof(pkt.header)) {
+ printk(KERN_ERR PFX
+ "contents length: %zu, which more than max: %lu,"
+ "so could not set (%s) variable to (%s).\n",
+ strlen(var) + strlen(value) + 2,
+ sizeof(pkt) - sizeof(pkt.header), var, value);
+ return;
+ }
+
memset(&pkt, 0, sizeof(pkt));
pkt.header.data.tag.type = DS_DATA;
pkt.header.data.handle = cp->handle;
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
index 6cfc1b09ec25..d7aa524b7283 100644
--- a/arch/sparc/kernel/leon_smp.c
+++ b/arch/sparc/kernel/leon_smp.c
@@ -254,15 +254,12 @@ void __init leon_smp_done(void)
/* Free unneeded trap tables */
if (!cpu_present(1)) {
free_reserved_page(virt_to_page(&trapbase_cpu1));
- num_physpages++;
}
if (!cpu_present(2)) {
free_reserved_page(virt_to_page(&trapbase_cpu2));
- num_physpages++;
}
if (!cpu_present(3)) {
free_reserved_page(virt_to_page(&trapbase_cpu3));
- num_physpages++;
}
/* Ok, they are spinning and ready to go. */
smp_processors_ready = 1;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 2031c65fd4ea..bc4d3f5d2e5d 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -254,7 +254,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
const char *type;
u32 class;
- dev = alloc_pci_dev();
+ dev = pci_alloc_dev(bus);
if (!dev)
return NULL;
@@ -281,7 +281,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
printk(" create device, devfn: %x, type: %s\n",
devfn, type);
- dev->bus = bus;
dev->sysdata = node;
dev->dev.parent = bus->bridge;
dev->dev.bus = &pci_bus_type;
@@ -327,7 +326,7 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
pci_set_master(dev);
- dev->current_state = 4; /* unknown power state */
+ dev->current_state = PCI_UNKNOWN; /* unknown power state */
dev->error_state = pci_channel_io_normal;
dev->dma_mask = 0xffffffff;
diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c
index 2daaaa6eda23..51561b8b15ba 100644
--- a/arch/sparc/kernel/sys_sparc_64.c
+++ b/arch/sparc/kernel/sys_sparc_64.c
@@ -290,7 +290,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
sysctl_legacy_va_layout) {
mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
/* We know it's 32-bit */
unsigned long task_size = STACK_TOP32;
@@ -302,7 +301,6 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor);
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/sparc/mm/hypersparc.S b/arch/sparc/mm/hypersparc.S
index 44aad32eeb4e..969f96450f69 100644
--- a/arch/sparc/mm/hypersparc.S
+++ b/arch/sparc/mm/hypersparc.S
@@ -74,7 +74,7 @@ hypersparc_flush_cache_mm_out:
/* The things we do for performance... */
hypersparc_flush_cache_range:
- ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
#ifndef CONFIG_SMP
ld [%o0 + AOFF_mm_context], %g1
cmp %g1, -1
@@ -163,7 +163,7 @@ hypersparc_flush_cache_range_out:
*/
/* Verified, my ass... */
hypersparc_flush_cache_page:
- ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
ld [%o0 + AOFF_mm_context], %g2
#ifndef CONFIG_SMP
cmp %g2, -1
@@ -284,7 +284,7 @@ hypersparc_flush_tlb_mm_out:
sta %g5, [%g1] ASI_M_MMUREGS
hypersparc_flush_tlb_range:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
lda [%g1] ASI_M_MMUREGS, %g5
@@ -307,7 +307,7 @@ hypersparc_flush_tlb_range_out:
sta %g5, [%g1] ASI_M_MMUREGS
hypersparc_flush_tlb_page:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index af472cf7c69a..db6987082805 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -288,10 +288,6 @@ static void map_high_region(unsigned long start_pfn, unsigned long end_pfn)
void __init mem_init(void)
{
- int codepages = 0;
- int datapages = 0;
- int initpages = 0;
- int reservedpages = 0;
int i;
if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
@@ -323,15 +319,12 @@ void __init mem_init(void)
max_mapnr = last_valid_pfn - pfn_base;
high_memory = __va(max_low_pfn << PAGE_SHIFT);
-
- totalram_pages = free_all_bootmem();
+ free_all_bootmem();
for (i = 0; sp_banks[i].num_bytes != 0; i++) {
unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
- num_physpages += sp_banks[i].num_bytes >> PAGE_SHIFT;
-
if (end_pfn <= highstart_pfn)
continue;
@@ -341,39 +334,19 @@ void __init mem_init(void)
map_high_region(start_pfn, end_pfn);
}
- codepages = (((unsigned long) &_etext) - ((unsigned long)&_start));
- codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
- datapages = (((unsigned long) &_edata) - ((unsigned long)&_etext));
- datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
- initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
- initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
-
- /* Ignore memory holes for the purpose of counting reserved pages */
- for (i=0; i < max_low_pfn; i++)
- if (test_bit(i >> (20 - PAGE_SHIFT), sparc_valid_addr_bitmap)
- && PageReserved(pfn_to_page(i)))
- reservedpages++;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT - 10),
- codepages << (PAGE_SHIFT-10),
- reservedpages << (PAGE_SHIFT - 10),
- datapages << (PAGE_SHIFT-10),
- initpages << (PAGE_SHIFT-10),
- totalhigh_pages << (PAGE_SHIFT-10));
+ mem_init_print_info(NULL);
}
void free_initmem (void)
{
- num_physpages += free_initmem_default(POISON_FREE_INITMEM);
+ free_initmem_default(POISON_FREE_INITMEM);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- num_physpages += free_reserved_area(start, end, POISON_FREE_INITMEM,
- "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 04fd55a6e461..a9c42a7ffb6a 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -2045,7 +2045,6 @@ static void __init register_page_bootmem_info(void)
}
void __init mem_init(void)
{
- unsigned long codepages, datapages, initpages;
unsigned long addr, last;
addr = PAGE_OFFSET + kern_base;
@@ -2061,12 +2060,7 @@ void __init mem_init(void)
high_memory = __va(last_valid_pfn << PAGE_SHIFT);
register_page_bootmem_info();
- totalram_pages = free_all_bootmem();
-
- /* We subtract one to account for the mem_map_zero page
- * allocated below.
- */
- num_physpages = totalram_pages - 1;
+ free_all_bootmem();
/*
* Set up the zero page, mark it reserved, so that page count
@@ -2079,19 +2073,7 @@ void __init mem_init(void)
}
mark_page_reserved(mem_map_zero);
- codepages = (((unsigned long) _etext) - ((unsigned long) _start));
- codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
- datapages = (((unsigned long) _edata) - ((unsigned long) _etext));
- datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
- initpages = (((unsigned long) __init_end) - ((unsigned long) __init_begin));
- initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
-
- printk("Memory: %luk available (%ldk kernel code, %ldk data, %ldk init) [%016lx,%016lx]\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10),
- initpages << (PAGE_SHIFT-10),
- PAGE_OFFSET, (last_valid_pfn << PAGE_SHIFT));
+ mem_init_print_info(NULL);
if (tlb_type == cheetah || tlb_type == cheetah_plus)
cheetah_ecache_flush_init();
@@ -2131,8 +2113,8 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- num_physpages += free_reserved_area(start, end, POISON_FREE_INITMEM,
- "initrd");
+ free_reserved_area((void *)start, (void *)end, POISON_FREE_INITMEM,
+ "initrd");
}
#endif
diff --git a/arch/sparc/mm/swift.S b/arch/sparc/mm/swift.S
index c801c3953a00..5d2b88d39424 100644
--- a/arch/sparc/mm/swift.S
+++ b/arch/sparc/mm/swift.S
@@ -105,7 +105,7 @@ swift_flush_cache_mm_out:
.globl swift_flush_cache_range
swift_flush_cache_range:
- ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
sub %o2, %o1, %o2
sethi %hi(4096), %o3
cmp %o2, %o3
@@ -116,7 +116,7 @@ swift_flush_cache_range:
.globl swift_flush_cache_page
swift_flush_cache_page:
- ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
70:
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
@@ -219,7 +219,7 @@ swift_flush_sig_insns:
.globl swift_flush_tlb_range
.globl swift_flush_tlb_all
swift_flush_tlb_range:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
swift_flush_tlb_mm:
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
@@ -233,7 +233,7 @@ swift_flush_tlb_all_out:
.globl swift_flush_tlb_page
swift_flush_tlb_page:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index 37e7bc4c95b3..7a91f288c708 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -188,7 +188,8 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
}
}
-void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable)
+void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
+ pgtable_t pgtable)
{
struct list_head *lh = (struct list_head *) pgtable;
@@ -202,7 +203,7 @@ void pgtable_trans_huge_deposit(struct mm_struct *mm, pgtable_t pgtable)
mm->pmd_huge_pte = pgtable;
}
-pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm)
+pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp)
{
struct list_head *lh;
pgtable_t pgtable;
diff --git a/arch/sparc/mm/tsunami.S b/arch/sparc/mm/tsunami.S
index 4e55e8f76648..bf10a345fa8b 100644
--- a/arch/sparc/mm/tsunami.S
+++ b/arch/sparc/mm/tsunami.S
@@ -24,7 +24,7 @@
/* Sliiick... */
tsunami_flush_cache_page:
tsunami_flush_cache_range:
- ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
tsunami_flush_cache_mm:
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
@@ -46,7 +46,7 @@ tsunami_flush_sig_insns:
/* More slick stuff... */
tsunami_flush_tlb_range:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
tsunami_flush_tlb_mm:
ld [%o0 + AOFF_mm_context], %g2
cmp %g2, -1
@@ -65,7 +65,7 @@ tsunami_flush_tlb_out:
/* This one can be done in a fine grained manner... */
tsunami_flush_tlb_page:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
andn %o1, (PAGE_SIZE - 1), %o1
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S
index bf8ee0613ae7..852257fcc82b 100644
--- a/arch/sparc/mm/viking.S
+++ b/arch/sparc/mm/viking.S
@@ -108,7 +108,7 @@ viking_mxcc_flush_page:
viking_flush_cache_page:
viking_flush_cache_range:
#ifndef CONFIG_SMP
- ld [%o0 + 0x0], %o0 /* XXX vma->vm_mm, GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
#endif
viking_flush_cache_mm:
#ifndef CONFIG_SMP
@@ -148,7 +148,7 @@ viking_flush_tlb_mm:
#endif
viking_flush_tlb_range:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
lda [%g1] ASI_M_MMUREGS, %g5
@@ -173,7 +173,7 @@ viking_flush_tlb_range:
#endif
viking_flush_tlb_page:
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
mov SRMMU_CTX_REG, %g1
ld [%o0 + AOFF_mm_context], %o3
lda [%g1] ASI_M_MMUREGS, %g5
@@ -239,7 +239,7 @@ sun4dsmp_flush_tlb_range:
tst %g5
bne 3f
mov SRMMU_CTX_REG, %g1
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
ld [%o0 + AOFF_mm_context], %o3
lda [%g1] ASI_M_MMUREGS, %g5
sethi %hi(~((1 << SRMMU_PGDIR_SHIFT) - 1)), %o4
@@ -265,7 +265,7 @@ sun4dsmp_flush_tlb_page:
tst %g5
bne 2f
mov SRMMU_CTX_REG, %g1
- ld [%o0 + 0x00], %o0 /* XXX vma->vm_mm GROSS XXX */
+ ld [%o0 + VMA_VM_MM], %o0
ld [%o0 + AOFF_mm_context], %o3
lda [%g1] ASI_M_MMUREGS, %g5
and %o1, PAGE_MASK, %o1
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index d36a85ebb5e0..9c7be59e6f5a 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -785,9 +785,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf];
break;
}
if (proglen == oldproglen) {
- image = module_alloc(max_t(unsigned int,
- proglen,
- sizeof(struct work_struct)));
+ image = module_alloc(proglen);
if (!image)
goto out;
}
@@ -806,20 +804,8 @@ out:
return;
}
-static void jit_free_defer(struct work_struct *arg)
-{
- module_free(NULL, arg);
-}
-
-/* run from softirq, we must use a work_struct to call
- * module_free() from process context
- */
void bpf_jit_free(struct sk_filter *fp)
{
- if (fp->bpf_func != sk_run_filter) {
- struct work_struct *work = (struct work_struct *)fp->bpf_func;
-
- INIT_WORK(work, jit_free_defer);
- schedule_work(work);
- }
+ if (fp->bpf_func != sk_run_filter)
+ module_free(NULL, fp->bpf_func);
}
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 3aa37669ff8c..24565a7ffe6d 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -25,6 +25,7 @@ config TILE
select HAVE_ARCH_TRACEHOOK
select HAVE_SYSCALL_TRACEPOINTS
select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+ select HAVE_DEBUG_STACKOVERFLOW
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug
index ddbfc3322d7f..9165ea979e85 100644
--- a/arch/tile/Kconfig.debug
+++ b/arch/tile/Kconfig.debug
@@ -14,13 +14,6 @@ config EARLY_PRINTK
with klogd/syslogd. You should normally N here,
unless you want to debug such a crash.
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- help
- This option will cause messages to be printed if free stack space
- drops below a certain limit.
-
config DEBUG_EXTRA_FLAGS
string "Additional compiler arguments when building with '-g'"
depends on DEBUG_INFO
diff --git a/arch/tile/include/asm/sections.h b/arch/tile/include/asm/sections.h
index d062d463fca9..7d8a935a9238 100644
--- a/arch/tile/include/asm/sections.h
+++ b/arch/tile/include/asm/sections.h
@@ -34,7 +34,7 @@ extern char __sys_cmpxchg_grab_lock[];
extern char __start_atomic_asm_code[], __end_atomic_asm_code[];
#endif
-/* Handle the discontiguity between _sdata and _stext. */
+/* Handle the discontiguity between _sdata and _text. */
static inline int arch_is_kernel_data(unsigned long addr)
{
return addr >= (unsigned long)_sdata &&
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 7a5aa1a7864e..68b542677f6a 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -307,8 +307,8 @@ static void __cpuinit store_permanent_mappings(void)
hv_store_mapping(addr, pages << PAGE_SHIFT, pa);
}
- hv_store_mapping((HV_VirtAddr)_stext,
- (uint32_t)(_einittext - _stext), 0);
+ hv_store_mapping((HV_VirtAddr)_text,
+ (uint32_t)(_einittext - _text), 0);
}
/*
@@ -329,6 +329,7 @@ static void __init setup_memory(void)
#if defined(CONFIG_HIGHMEM) || defined(__tilegx__)
long lowmem_pages;
#endif
+ unsigned long physpages = 0;
/* We are using a char to hold the cpu_2_node[] mapping */
BUILD_BUG_ON(MAX_NUMNODES > 127);
@@ -388,8 +389,8 @@ static void __init setup_memory(void)
continue;
}
}
- if (num_physpages + PFN_DOWN(range.size) > maxmem_pfn) {
- int max_size = maxmem_pfn - num_physpages;
+ if (physpages + PFN_DOWN(range.size) > maxmem_pfn) {
+ int max_size = maxmem_pfn - physpages;
if (max_size > 0) {
pr_err("Maxmem reduced node %d to %d pages\n",
i, max_size);
@@ -446,7 +447,7 @@ static void __init setup_memory(void)
node_start_pfn[i] = start;
node_end_pfn[i] = end;
node_controller[i] = range.controller;
- num_physpages += size;
+ physpages += size;
max_pfn = end;
/* Mark node as online */
@@ -465,7 +466,7 @@ static void __init setup_memory(void)
* we're willing to use at 8 million pages (32GB of 4KB pages).
*/
cap = 8 * 1024 * 1024; /* 8 million pages */
- if (num_physpages > cap) {
+ if (physpages > cap) {
int num_nodes = num_online_nodes();
int cap_each = cap / num_nodes;
unsigned long dropped_pages = 0;
@@ -476,10 +477,10 @@ static void __init setup_memory(void)
node_end_pfn[i] = node_start_pfn[i] + cap_each;
}
}
- num_physpages -= dropped_pages;
+ physpages -= dropped_pages;
pr_warning("Only using %ldMB memory;"
" ignoring %ldMB.\n",
- num_physpages >> (20 - PAGE_SHIFT),
+ physpages >> (20 - PAGE_SHIFT),
dropped_pages >> (20 - PAGE_SHIFT));
pr_warning("Consider using a larger page size.\n");
}
@@ -497,7 +498,7 @@ static void __init setup_memory(void)
lowmem_pages = (mappable_physpages > MAXMEM_PFN) ?
MAXMEM_PFN : mappable_physpages;
- highmem_pages = (long) (num_physpages - lowmem_pages);
+ highmem_pages = (long) (physpages - lowmem_pages);
pr_notice("%ldMB HIGHMEM available.\n",
pages_to_mb(highmem_pages > 0 ? highmem_pages : 0));
@@ -514,7 +515,6 @@ static void __init setup_memory(void)
pr_warning("Use a HIGHMEM enabled kernel.\n");
max_low_pfn = MAXMEM_PFN;
max_pfn = MAXMEM_PFN;
- num_physpages = MAXMEM_PFN;
node_end_pfn[0] = MAXMEM_PFN;
} else {
pr_notice("%ldMB memory available.\n",
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S
index 631f10de12fe..a13ed902afbb 100644
--- a/arch/tile/kernel/vmlinux.lds.S
+++ b/arch/tile/kernel/vmlinux.lds.S
@@ -27,7 +27,6 @@ SECTIONS
.intrpt1 (LOAD_OFFSET) : AT ( 0 ) /* put at the start of physical memory */
{
_text = .;
- _stext = .;
*(.intrpt1)
} :intrpt1 =0
@@ -36,6 +35,7 @@ SECTIONS
/* Now the real code */
. = ALIGN(0x20000);
+ _stext = .;
.text : AT (ADDR(.text) - LOAD_OFFSET) {
HEAD_TEXT
SCHED_TEXT
@@ -58,11 +58,13 @@ SECTIONS
#define LOAD_OFFSET PAGE_OFFSET
. = ALIGN(PAGE_SIZE);
+ __init_begin = .;
VMLINUX_SYMBOL(_sinitdata) = .;
INIT_DATA_SECTION(16) :data =0
PERCPU_SECTION(L2_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
VMLINUX_SYMBOL(_einitdata) = .;
+ __init_end = .;
_sdata = .; /* Start of data section */
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 3d2b81c163a6..f7f99f90cbe0 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -573,10 +573,10 @@ out_of_memory:
down_read(&mm->mmap_sem);
goto survive;
}
- pr_alert("VM: killing process %s\n", tsk->comm);
- if (!is_kernel_mode)
- do_group_exit(SIGKILL);
- goto no_context;
+ if (is_kernel_mode)
+ goto no_context;
+ pagefault_out_of_memory();
+ return 0;
do_sigbus:
up_read(&mm->mmap_sem);
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index 2749515a0547..e182958c707d 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -562,7 +562,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
prot = ktext_set_nocache(prot);
}
- BUG_ON(address != (unsigned long)_stext);
+ BUG_ON(address != (unsigned long)_text);
pte = NULL;
for (; address < (unsigned long)_einittext;
pfn++, address += PAGE_SIZE) {
@@ -720,7 +720,7 @@ static void __init init_free_pfn_range(unsigned long start, unsigned long end)
}
init_page_count(page);
__free_pages(page, order);
- totalram_pages += count;
+ adjust_managed_page_count(page, count);
page += count;
pfn += count;
@@ -821,7 +821,6 @@ static void __init set_max_mapnr_init(void)
void __init mem_init(void)
{
- int codesize, datasize, initsize;
int i;
#ifndef __tilegx__
void *last;
@@ -846,26 +845,14 @@ void __init mem_init(void)
set_max_mapnr_init();
/* this will put all bootmem onto the freelists */
- totalram_pages += free_all_bootmem();
+ free_all_bootmem();
#ifndef CONFIG_64BIT
/* count all remaining LOWMEM and give all HIGHMEM to page allocator */
set_non_bootmem_pages_init();
#endif
- codesize = (unsigned long)&_etext - (unsigned long)&_text;
- datasize = (unsigned long)&_end - (unsigned long)&_sdata;
- initsize = (unsigned long)&_einittext - (unsigned long)&_sinittext;
- initsize += (unsigned long)&_einitdata - (unsigned long)&_sinitdata;
-
- pr_info("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n",
- (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- datasize >> 10,
- initsize >> 10,
- (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
- );
+ mem_init_print_info(NULL);
/*
* In debug mode, dump some interesting memory mappings.
@@ -1024,16 +1011,13 @@ static void free_init_pages(char *what, unsigned long begin, unsigned long end)
pte_clear(&init_mm, addr, ptep);
continue;
}
- __ClearPageReserved(page);
- init_page_count(page);
if (pte_huge(*ptep))
BUG_ON(!kdata_huge);
else
set_pte_at(&init_mm, addr, ptep,
pfn_pte(pfn, PAGE_KERNEL));
memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- free_page(addr);
- totalram_pages++;
+ free_reserved_page(page);
}
pr_info("Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
}
diff --git a/arch/tile/mm/mmap.c b/arch/tile/mm/mmap.c
index f96f4cec602a..d67d91ebf63e 100644
--- a/arch/tile/mm/mmap.c
+++ b/arch/tile/mm/mmap.c
@@ -66,10 +66,8 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (!is_32bit || rlimit(RLIMIT_STACK) == RLIM_INFINITY) {
mm->mmap_base = TASK_UNMAPPED_BASE;
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base(mm);
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S
index 4938de5512d2..1dd5bd8a8c59 100644
--- a/arch/um/include/asm/common.lds.S
+++ b/arch/um/include/asm/common.lds.S
@@ -57,7 +57,6 @@
*(.uml.initcall.init)
__uml_initcall_end = .;
}
- __init_end = .;
SECURITY_INIT
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index fb8fd6fb6563..adde088aeeff 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -14,8 +14,6 @@ SECTIONS
__binary_start = .;
. = ALIGN(4096); /* Init code and data */
_text = .;
- _stext = .;
- __init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
@@ -67,6 +65,7 @@ SECTIONS
} =0x90909090
.plt : { *(.plt) }
.text : {
+ _stext = .;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
@@ -91,7 +90,9 @@ SECTIONS
#include <asm/common.lds.S>
+ __init_begin = .;
init.data : { INIT_DATA }
+ __init_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
@@ -155,6 +156,7 @@ SECTIONS
. = ALIGN(32 / 8);
. = ALIGN(32 / 8);
}
+ __bss_stop = .;
_end = .;
PROVIDE (end = .);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 9df292b270a8..7ddb64baf327 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -65,15 +65,13 @@ void __init mem_init(void)
uml_reserved = brk_end;
/* this will put all low memory onto the freelists */
- totalram_pages = free_all_bootmem();
+ free_all_bootmem();
max_low_pfn = totalram_pages;
#ifdef CONFIG_HIGHMEM
setup_highmem(end_iomem, highmem);
#endif
- num_physpages = totalram_pages;
max_pfn = totalram_pages;
- printk(KERN_INFO "Memory: %luk available\n",
- nr_free_pages() << (PAGE_SHIFT-10));
+ mem_init_print_info(NULL);
kmalloc_ok = 1;
}
@@ -244,7 +242,7 @@ void free_initmem(void)
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index ff65fb4f1a95..6899195602b7 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -20,13 +20,12 @@ SECTIONS
. = START + SIZEOF_HEADERS;
_text = .;
- _stext = .;
- __init_begin = .;
INIT_TEXT_SECTION(0)
. = ALIGN(PAGE_SIZE);
.text :
{
+ _stext = .;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
@@ -62,7 +61,10 @@ SECTIONS
#include <asm/common.lds.S>
+ __init_begin = .;
init.data : { INIT_DATA }
+ __init_end = .;
+
.data :
{
INIT_TASK_DATA(KERNEL_STACK_SIZE)
@@ -97,6 +99,7 @@ SECTIONS
PROVIDE(_bss_start = .);
SBSS(0)
BSS(0)
+ __bss_stop = .;
_end = .;
PROVIDE (end = .);
diff --git a/arch/unicore32/boot/compressed/Makefile b/arch/unicore32/boot/compressed/Makefile
index 950a9afa38f8..96494fb646f7 100644
--- a/arch/unicore32/boot/compressed/Makefile
+++ b/arch/unicore32/boot/compressed/Makefile
@@ -17,7 +17,7 @@ OBJS := misc.o
# font.c and font.o
CFLAGS_font.o := -Dstatic=
-$(obj)/font.c: $(srctree)/drivers/video/console/font_8x8.c
+$(obj)/font.c: $(srctree)/lib/fonts/font_8x8.c
$(call cmd,shipped)
# piggy.S and piggy.o
diff --git a/arch/unicore32/include/asm/memory.h b/arch/unicore32/include/asm/memory.h
index 5eddb997defe..debafc40200a 100644
--- a/arch/unicore32/include/asm/memory.h
+++ b/arch/unicore32/include/asm/memory.h
@@ -98,12 +98,6 @@
/*
* Conversion between a struct page and a physical address.
*
- * Note: when converting an unknown physical address to a
- * struct page, the resulting pointer must be validated
- * using VALID_PAGE(). It must return an invalid struct page
- * for any physical address not corresponding to a system
- * RAM address.
- *
* page_to_pfn(page) convert a struct page * to a PFN number
* pfn_to_page(pfn) convert a _valid_ PFN number to struct page *
*
diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index ef69c0c82825..374a055a8e6b 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -277,11 +277,6 @@ static int __init pci_common_init(void)
pci_bus_assign_resources(puv3_bus);
}
- /*
- * Tell drivers about devices found.
- */
- pci_bus_add_devices(puv3_bus);
-
return 0;
}
subsys_initcall(pci_common_init);
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index c9447691bdac..778ebba80827 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -51,16 +51,6 @@ void arch_cpu_idle(void)
local_irq_enable();
}
-static char reboot_mode = 'h';
-
-int __init reboot_setup(char *str)
-{
- reboot_mode = str[0];
- return 1;
-}
-
-__setup("reboot=", reboot_setup);
-
void machine_halt(void)
{
gpio_set_value(GPO_SOFT_OFF, 0);
@@ -88,7 +78,7 @@ void machine_restart(char *cmd)
* we may need it to insert some 1:1 mappings so that
* soft boot works.
*/
- setup_mm_for_reboot(reboot_mode);
+ setup_mm_for_reboot();
/* Clean and invalidate caches */
flush_cache_all();
@@ -102,7 +92,7 @@ void machine_restart(char *cmd)
/*
* Now handle reboot code.
*/
- if (reboot_mode == 's') {
+ if (reboot_mode == REBOOT_SOFT) {
/* Jump into ROM at address 0xffff0000 */
cpu_reset(VECTORS_BASE);
} else {
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
index 30f749da8f73..f5c51b85ad24 100644
--- a/arch/unicore32/kernel/setup.h
+++ b/arch/unicore32/kernel/setup.h
@@ -22,7 +22,7 @@ extern void puv3_ps2_init(void);
extern void pci_puv3_preinit(void);
extern void __init puv3_init_gpio(void);
-extern void setup_mm_for_reboot(char mode);
+extern void setup_mm_for_reboot(void);
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c
index 63df12d71ce3..ae6bc036db92 100644
--- a/arch/unicore32/mm/init.c
+++ b/arch/unicore32/mm/init.c
@@ -383,59 +383,14 @@ static void __init free_unused_memmap(struct meminfo *mi)
*/
void __init mem_init(void)
{
- unsigned long reserved_pages, free_pages;
- struct memblock_region *reg;
- int i;
-
max_mapnr = pfn_to_page(max_pfn + PHYS_PFN_OFFSET) - mem_map;
free_unused_memmap(&meminfo);
/* this will put all unused low memory onto the freelists */
- totalram_pages += free_all_bootmem();
-
- reserved_pages = free_pages = 0;
-
- for_each_bank(i, &meminfo) {
- struct membank *bank = &meminfo.bank[i];
- unsigned int pfn1, pfn2;
- struct page *page, *end;
-
- pfn1 = bank_pfn_start(bank);
- pfn2 = bank_pfn_end(bank);
-
- page = pfn_to_page(pfn1);
- end = pfn_to_page(pfn2 - 1) + 1;
-
- do {
- if (PageReserved(page))
- reserved_pages++;
- else if (!page_count(page))
- free_pages++;
- page++;
- } while (page < end);
- }
-
- /*
- * Since our memory may not be contiguous, calculate the
- * real number of pages we have in this system
- */
- printk(KERN_INFO "Memory:");
- num_physpages = 0;
- for_each_memblock(memory, reg) {
- unsigned long pages = memblock_region_memory_end_pfn(reg) -
- memblock_region_memory_base_pfn(reg);
- num_physpages += pages;
- printk(" %ldMB", pages >> (20 - PAGE_SHIFT));
- }
- printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT));
-
- printk(KERN_NOTICE "Memory: %luk/%luk available, %luk reserved, %luK highmem\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- free_pages << (PAGE_SHIFT-10),
- reserved_pages << (PAGE_SHIFT-10),
- totalhigh_pages << (PAGE_SHIFT-10));
+ free_all_bootmem();
+ mem_init_print_info(NULL);
printk(KERN_NOTICE "Virtual kernel memory layout:\n"
" vector : 0x%08lx - 0x%08lx (%4ld kB)\n"
" vmalloc : 0x%08lx - 0x%08lx (%4ld MB)\n"
@@ -464,7 +419,7 @@ void __init mem_init(void)
BUILD_BUG_ON(TASK_SIZE > MODULES_VADDR);
BUG_ON(TASK_SIZE > MODULES_VADDR);
- if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
+ if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) {
/*
* On a machine this small we won't get
* anywhere without overcommit, so turn
@@ -476,7 +431,7 @@ void __init mem_init(void)
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -486,7 +441,7 @@ static int keep_initrd;
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (!keep_initrd)
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
static int __init keepinitrd_setup(char *__unused)
diff --git a/arch/unicore32/mm/mmu.c b/arch/unicore32/mm/mmu.c
index 43c20b40e444..4f5a532bee13 100644
--- a/arch/unicore32/mm/mmu.c
+++ b/arch/unicore32/mm/mmu.c
@@ -445,7 +445,7 @@ void __init paging_init(void)
* the user-mode pages. This will then ensure that we have predictable
* results when turning the mmu off
*/
-void setup_mm_for_reboot(char mode)
+void setup_mm_for_reboot(void)
{
unsigned long base_pmdval;
pgd_t *pgd;
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index d98b665e6536..b32ebf92b0ce 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -65,6 +65,7 @@ config X86
select HAVE_KERNEL_LZMA
select HAVE_KERNEL_XZ
select HAVE_KERNEL_LZO
+ select HAVE_KERNEL_LZ4
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
select PERF_EVENTS
@@ -102,6 +103,7 @@ config X86
select HAVE_ARCH_SECCOMP_FILTER
select BUILDTIME_EXTABLE_SORT
select GENERIC_CMOS_UPDATE
+ select HAVE_ARCH_SOFT_DIRTY
select CLOCKSOURCE_WATCHDOG
select GENERIC_CLOCKEVENTS
select ARCH_CLOCKSOURCE_DATA if X86_64
@@ -121,6 +123,7 @@ config X86
select OLD_SIGACTION if X86_32
select COMPAT_OLD_SIGACTION if IA32_EMULATION
select RTC_LIB
+ select HAVE_DEBUG_STACKOVERFLOW
config INSTRUCTION_DECODER
def_bool y
@@ -207,6 +210,12 @@ config ARCH_HIBERNATION_POSSIBLE
config ARCH_SUSPEND_POSSIBLE
def_bool y
+config ARCH_WANT_HUGE_PMD_SHARE
+ def_bool y
+
+config ARCH_WANT_GENERAL_HUGETLB
+ def_bool y
+
config ZONE_DMA32
bool
default X86_64
@@ -2252,11 +2261,11 @@ source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
config RAPIDIO
- bool "RapidIO support"
+ tristate "RapidIO support"
depends on PCI
default n
help
- If you say Y here, the kernel will include drivers and
+ If enabled this option will include drivers and the core
infrastructure code to support RapidIO interconnect devices.
source "drivers/rapidio/Kconfig"
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index c963881de0d0..78d91afb8e50 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -59,16 +59,6 @@ config EARLY_PRINTK_DBGP
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash. You need usb debug device.
-config DEBUG_STACKOVERFLOW
- bool "Check for stack overflows"
- depends on DEBUG_KERNEL
- ---help---
- Say Y here if you want to check the overflows of kernel, IRQ
- and exception stacks. This option will cause messages of the
- stacks in detail when free stack space drops below a certain
- limit.
- If in doubt, say "N".
-
config X86_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 5ef205c5f37b..dcd90df10ab4 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -4,7 +4,8 @@
# create a compressed vmlinux image from the original vmlinux
#
-targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo
+targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
+ vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
@@ -63,12 +64,15 @@ $(obj)/vmlinux.bin.xz: $(vmlinux.bin.all-y) FORCE
$(call if_changed,xzkern)
$(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y) FORCE
$(call if_changed,lzo)
+$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y) FORCE
+ $(call if_changed,lz4)
suffix-$(CONFIG_KERNEL_GZIP) := gz
suffix-$(CONFIG_KERNEL_BZIP2) := bz2
suffix-$(CONFIG_KERNEL_LZMA) := lzma
suffix-$(CONFIG_KERNEL_XZ) := xz
suffix-$(CONFIG_KERNEL_LZO) := lzo
+suffix-$(CONFIG_KERNEL_LZ4) := lz4
quiet_cmd_mkpiggy = MKPIGGY $@
cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 7cb56c6ca351..0319c88290a5 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -145,6 +145,10 @@ static int lines, cols;
#include "../../../../lib/decompress_unlzo.c"
#endif
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
static void scroll(void)
{
int i;
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index a3a0ed80f17c..7d6ba9db1be9 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -3,8 +3,6 @@
#
avx_supported := $(call as-instr,vpxor %xmm0$(comma)%xmm0$(comma)%xmm0,yes,no)
-avx2_supported := $(call as-instr,vpgatherdd %ymm0$(comma)(%eax$(comma)%ymm1\
- $(comma)4)$(comma)%ymm2,yes,no)
obj-$(CONFIG_CRYPTO_ABLK_HELPER_X86) += ablk_helper.o
obj-$(CONFIG_CRYPTO_GLUE_HELPER_X86) += glue_helper.o
@@ -29,6 +27,7 @@ obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
+obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o
# These modules require assembler to support AVX.
ifeq ($(avx_supported),yes)
@@ -42,10 +41,8 @@ endif
# These modules require assembler to support AVX2.
ifeq ($(avx2_supported),yes)
- obj-$(CONFIG_CRYPTO_BLOWFISH_AVX2_X86_64) += blowfish-avx2.o
obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o
obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o
- obj-$(CONFIG_CRYPTO_TWOFISH_AVX2_X86_64) += twofish-avx2.o
endif
aes-i586-y := aes-i586-asm_32.o aes_glue.o
@@ -73,10 +70,8 @@ ifeq ($(avx_supported),yes)
endif
ifeq ($(avx2_supported),yes)
- blowfish-avx2-y := blowfish-avx2-asm_64.o blowfish_avx2_glue.o
camellia-aesni-avx2-y := camellia-aesni-avx2-asm_64.o camellia_aesni_avx2_glue.o
serpent-avx2-y := serpent-avx2-asm_64.o serpent_avx2_glue.o
- twofish-avx2-y := twofish-avx2-asm_64.o twofish_avx2_glue.o
endif
aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o
@@ -87,3 +82,4 @@ crc32c-intel-$(CONFIG_64BIT) += crc32c-pcl-intel-asm_64.o
crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o
sha256-ssse3-y := sha256-ssse3-asm.o sha256-avx-asm.o sha256-avx2-asm.o sha256_ssse3_glue.o
sha512-ssse3-y := sha512-ssse3-asm.o sha512-avx-asm.o sha512-avx2-asm.o sha512_ssse3_glue.o
+crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o
diff --git a/arch/x86/crypto/blowfish-avx2-asm_64.S b/arch/x86/crypto/blowfish-avx2-asm_64.S
deleted file mode 100644
index 784452e0d05d..000000000000
--- a/arch/x86/crypto/blowfish-avx2-asm_64.S
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * x86_64/AVX2 assembler optimized version of Blowfish
- *
- * Copyright © 2012-2013 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>
-
-.file "blowfish-avx2-asm_64.S"
-
-.data
-.align 32
-
-.Lprefetch_mask:
-.long 0*64
-.long 1*64
-.long 2*64
-.long 3*64
-.long 4*64
-.long 5*64
-.long 6*64
-.long 7*64
-
-.Lbswap32_mask:
-.long 0x00010203
-.long 0x04050607
-.long 0x08090a0b
-.long 0x0c0d0e0f
-
-.Lbswap128_mask:
- .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
-.Lbswap_iv_mask:
- .byte 7, 6, 5, 4, 3, 2, 1, 0, 7, 6, 5, 4, 3, 2, 1, 0
-
-.text
-/* structure of crypto context */
-#define p 0
-#define s0 ((16 + 2) * 4)
-#define s1 ((16 + 2 + (1 * 256)) * 4)
-#define s2 ((16 + 2 + (2 * 256)) * 4)
-#define s3 ((16 + 2 + (3 * 256)) * 4)
-
-/* register macros */
-#define CTX %rdi
-#define RIO %rdx
-
-#define RS0 %rax
-#define RS1 %r8
-#define RS2 %r9
-#define RS3 %r10
-
-#define RLOOP %r11
-#define RLOOPd %r11d
-
-#define RXr0 %ymm8
-#define RXr1 %ymm9
-#define RXr2 %ymm10
-#define RXr3 %ymm11
-#define RXl0 %ymm12
-#define RXl1 %ymm13
-#define RXl2 %ymm14
-#define RXl3 %ymm15
-
-/* temp regs */
-#define RT0 %ymm0
-#define RT0x %xmm0
-#define RT1 %ymm1
-#define RT1x %xmm1
-#define RIDX0 %ymm2
-#define RIDX1 %ymm3
-#define RIDX1x %xmm3
-#define RIDX2 %ymm4
-#define RIDX3 %ymm5
-
-/* vpgatherdd mask and '-1' */
-#define RNOT %ymm6
-
-/* byte mask, (-1 >> 24) */
-#define RBYTE %ymm7
-
-/***********************************************************************
- * 32-way AVX2 blowfish
- ***********************************************************************/
-#define F(xl, xr) \
- vpsrld $24, xl, RIDX0; \
- vpsrld $16, xl, RIDX1; \
- vpsrld $8, xl, RIDX2; \
- vpand RBYTE, RIDX1, RIDX1; \
- vpand RBYTE, RIDX2, RIDX2; \
- vpand RBYTE, xl, RIDX3; \
- \
- vpgatherdd RNOT, (RS0, RIDX0, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpcmpeqd RIDX0, RIDX0, RIDX0; \
- \
- vpgatherdd RNOT, (RS1, RIDX1, 4), RT1; \
- vpcmpeqd RIDX1, RIDX1, RIDX1; \
- vpaddd RT0, RT1, RT0; \
- \
- vpgatherdd RIDX0, (RS2, RIDX2, 4), RT1; \
- vpxor RT0, RT1, RT0; \
- \
- vpgatherdd RIDX1, (RS3, RIDX3, 4), RT1; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpaddd RT0, RT1, RT0; \
- \
- vpxor RT0, xr, xr;
-
-#define add_roundkey(xl, nmem) \
- vpbroadcastd nmem, RT0; \
- vpxor RT0, xl ## 0, xl ## 0; \
- vpxor RT0, xl ## 1, xl ## 1; \
- vpxor RT0, xl ## 2, xl ## 2; \
- vpxor RT0, xl ## 3, xl ## 3;
-
-#define round_enc() \
- add_roundkey(RXr, p(CTX,RLOOP,4)); \
- F(RXl0, RXr0); \
- F(RXl1, RXr1); \
- F(RXl2, RXr2); \
- F(RXl3, RXr3); \
- \
- add_roundkey(RXl, p+4(CTX,RLOOP,4)); \
- F(RXr0, RXl0); \
- F(RXr1, RXl1); \
- F(RXr2, RXl2); \
- F(RXr3, RXl3);
-
-#define round_dec() \
- add_roundkey(RXr, p+4*2(CTX,RLOOP,4)); \
- F(RXl0, RXr0); \
- F(RXl1, RXr1); \
- F(RXl2, RXr2); \
- F(RXl3, RXr3); \
- \
- add_roundkey(RXl, p+4(CTX,RLOOP,4)); \
- F(RXr0, RXl0); \
- F(RXr1, RXl1); \
- F(RXr2, RXl2); \
- F(RXr3, RXl3);
-
-#define init_round_constants() \
- vpcmpeqd RNOT, RNOT, RNOT; \
- leaq s0(CTX), RS0; \
- leaq s1(CTX), RS1; \
- leaq s2(CTX), RS2; \
- leaq s3(CTX), RS3; \
- vpsrld $24, RNOT, RBYTE;
-
-#define transpose_2x2(x0, x1, t0) \
- vpunpckldq x0, x1, t0; \
- vpunpckhdq x0, x1, x1; \
- \
- vpunpcklqdq t0, x1, x0; \
- vpunpckhqdq t0, x1, x1;
-
-#define read_block(xl, xr) \
- vbroadcasti128 .Lbswap32_mask, RT1; \
- \
- vpshufb RT1, xl ## 0, xl ## 0; \
- vpshufb RT1, xr ## 0, xr ## 0; \
- vpshufb RT1, xl ## 1, xl ## 1; \
- vpshufb RT1, xr ## 1, xr ## 1; \
- vpshufb RT1, xl ## 2, xl ## 2; \
- vpshufb RT1, xr ## 2, xr ## 2; \
- vpshufb RT1, xl ## 3, xl ## 3; \
- vpshufb RT1, xr ## 3, xr ## 3; \
- \
- transpose_2x2(xl ## 0, xr ## 0, RT0); \
- transpose_2x2(xl ## 1, xr ## 1, RT0); \
- transpose_2x2(xl ## 2, xr ## 2, RT0); \
- transpose_2x2(xl ## 3, xr ## 3, RT0);
-
-#define write_block(xl, xr) \
- vbroadcasti128 .Lbswap32_mask, RT1; \
- \
- transpose_2x2(xl ## 0, xr ## 0, RT0); \
- transpose_2x2(xl ## 1, xr ## 1, RT0); \
- transpose_2x2(xl ## 2, xr ## 2, RT0); \
- transpose_2x2(xl ## 3, xr ## 3, RT0); \
- \
- vpshufb RT1, xl ## 0, xl ## 0; \
- vpshufb RT1, xr ## 0, xr ## 0; \
- vpshufb RT1, xl ## 1, xl ## 1; \
- vpshufb RT1, xr ## 1, xr ## 1; \
- vpshufb RT1, xl ## 2, xl ## 2; \
- vpshufb RT1, xr ## 2, xr ## 2; \
- vpshufb RT1, xl ## 3, xl ## 3; \
- vpshufb RT1, xr ## 3, xr ## 3;
-
-.align 8
-__blowfish_enc_blk32:
- /* input:
- * %rdi: ctx, CTX
- * RXl0..4, RXr0..4: plaintext
- * output:
- * RXl0..4, RXr0..4: ciphertext (RXl <=> RXr swapped)
- */
- init_round_constants();
-
- read_block(RXl, RXr);
-
- movl $1, RLOOPd;
- add_roundkey(RXl, p+4*(0)(CTX));
-
-.align 4
-.L__enc_loop:
- round_enc();
-
- leal 2(RLOOPd), RLOOPd;
- cmpl $17, RLOOPd;
- jne .L__enc_loop;
-
- add_roundkey(RXr, p+4*(17)(CTX));
-
- write_block(RXl, RXr);
-
- ret;
-ENDPROC(__blowfish_enc_blk32)
-
-.align 8
-__blowfish_dec_blk32:
- /* input:
- * %rdi: ctx, CTX
- * RXl0..4, RXr0..4: ciphertext
- * output:
- * RXl0..4, RXr0..4: plaintext (RXl <=> RXr swapped)
- */
- init_round_constants();
-
- read_block(RXl, RXr);
-
- movl $14, RLOOPd;
- add_roundkey(RXl, p+4*(17)(CTX));
-
-.align 4
-.L__dec_loop:
- round_dec();
-
- addl $-2, RLOOPd;
- jns .L__dec_loop;
-
- add_roundkey(RXr, p+4*(0)(CTX));
-
- write_block(RXl, RXr);
-
- ret;
-ENDPROC(__blowfish_dec_blk32)
-
-ENTRY(blowfish_ecb_enc_32way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- */
-
- vzeroupper;
-
- vmovdqu 0*32(%rdx), RXl0;
- vmovdqu 1*32(%rdx), RXr0;
- vmovdqu 2*32(%rdx), RXl1;
- vmovdqu 3*32(%rdx), RXr1;
- vmovdqu 4*32(%rdx), RXl2;
- vmovdqu 5*32(%rdx), RXr2;
- vmovdqu 6*32(%rdx), RXl3;
- vmovdqu 7*32(%rdx), RXr3;
-
- call __blowfish_enc_blk32;
-
- vmovdqu RXr0, 0*32(%rsi);
- vmovdqu RXl0, 1*32(%rsi);
- vmovdqu RXr1, 2*32(%rsi);
- vmovdqu RXl1, 3*32(%rsi);
- vmovdqu RXr2, 4*32(%rsi);
- vmovdqu RXl2, 5*32(%rsi);
- vmovdqu RXr3, 6*32(%rsi);
- vmovdqu RXl3, 7*32(%rsi);
-
- vzeroupper;
-
- ret;
-ENDPROC(blowfish_ecb_enc_32way)
-
-ENTRY(blowfish_ecb_dec_32way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- */
-
- vzeroupper;
-
- vmovdqu 0*32(%rdx), RXl0;
- vmovdqu 1*32(%rdx), RXr0;
- vmovdqu 2*32(%rdx), RXl1;
- vmovdqu 3*32(%rdx), RXr1;
- vmovdqu 4*32(%rdx), RXl2;
- vmovdqu 5*32(%rdx), RXr2;
- vmovdqu 6*32(%rdx), RXl3;
- vmovdqu 7*32(%rdx), RXr3;
-
- call __blowfish_dec_blk32;
-
- vmovdqu RXr0, 0*32(%rsi);
- vmovdqu RXl0, 1*32(%rsi);
- vmovdqu RXr1, 2*32(%rsi);
- vmovdqu RXl1, 3*32(%rsi);
- vmovdqu RXr2, 4*32(%rsi);
- vmovdqu RXl2, 5*32(%rsi);
- vmovdqu RXr3, 6*32(%rsi);
- vmovdqu RXl3, 7*32(%rsi);
-
- vzeroupper;
-
- ret;
-ENDPROC(blowfish_ecb_dec_32way)
-
-ENTRY(blowfish_cbc_dec_32way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- */
-
- vzeroupper;
-
- vmovdqu 0*32(%rdx), RXl0;
- vmovdqu 1*32(%rdx), RXr0;
- vmovdqu 2*32(%rdx), RXl1;
- vmovdqu 3*32(%rdx), RXr1;
- vmovdqu 4*32(%rdx), RXl2;
- vmovdqu 5*32(%rdx), RXr2;
- vmovdqu 6*32(%rdx), RXl3;
- vmovdqu 7*32(%rdx), RXr3;
-
- call __blowfish_dec_blk32;
-
- /* xor with src */
- vmovq (%rdx), RT0x;
- vpshufd $0x4f, RT0x, RT0x;
- vinserti128 $1, 8(%rdx), RT0, RT0;
- vpxor RT0, RXr0, RXr0;
- vpxor 0*32+24(%rdx), RXl0, RXl0;
- vpxor 1*32+24(%rdx), RXr1, RXr1;
- vpxor 2*32+24(%rdx), RXl1, RXl1;
- vpxor 3*32+24(%rdx), RXr2, RXr2;
- vpxor 4*32+24(%rdx), RXl2, RXl2;
- vpxor 5*32+24(%rdx), RXr3, RXr3;
- vpxor 6*32+24(%rdx), RXl3, RXl3;
-
- vmovdqu RXr0, (0*32)(%rsi);
- vmovdqu RXl0, (1*32)(%rsi);
- vmovdqu RXr1, (2*32)(%rsi);
- vmovdqu RXl1, (3*32)(%rsi);
- vmovdqu RXr2, (4*32)(%rsi);
- vmovdqu RXl2, (5*32)(%rsi);
- vmovdqu RXr3, (6*32)(%rsi);
- vmovdqu RXl3, (7*32)(%rsi);
-
- vzeroupper;
-
- ret;
-ENDPROC(blowfish_cbc_dec_32way)
-
-ENTRY(blowfish_ctr_32way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- * %rcx: iv (big endian, 64bit)
- */
-
- vzeroupper;
-
- vpcmpeqd RT0, RT0, RT0;
- vpsrldq $8, RT0, RT0; /* a: -1, b: 0, c: -1, d: 0 */
-
- vpcmpeqd RT1x, RT1x, RT1x;
- vpaddq RT1x, RT1x, RT1x; /* a: -2, b: -2 */
- vpxor RIDX0, RIDX0, RIDX0;
- vinserti128 $1, RT1x, RIDX0, RIDX0; /* a: 0, b: 0, c: -2, d: -2 */
-
- vpaddq RIDX0, RT0, RT0; /* a: -1, b: 0, c: -3, d: -2 */
-
- vpcmpeqd RT1, RT1, RT1;
- vpaddq RT1, RT1, RT1; /* a: -2, b: -2, c: -2, d: -2 */
- vpaddq RT1, RT1, RIDX2; /* a: -4, b: -4, c: -4, d: -4 */
-
- vbroadcasti128 .Lbswap_iv_mask, RIDX0;
- vbroadcasti128 .Lbswap128_mask, RIDX1;
-
- /* load IV and byteswap */
- vmovq (%rcx), RT1x;
- vinserti128 $1, RT1x, RT1, RT1; /* a: BE, b: 0, c: BE, d: 0 */
- vpshufb RIDX0, RT1, RT1; /* a: LE, b: LE, c: LE, d: LE */
-
- /* construct IVs */
- vpsubq RT0, RT1, RT1; /* a: le1, b: le0, c: le3, d: le2 */
- vpshufb RIDX1, RT1, RXl0; /* a: be0, b: be1, c: be2, d: be3 */
- vpsubq RIDX2, RT1, RT1; /* le5, le4, le7, le6 */
- vpshufb RIDX1, RT1, RXr0; /* be4, be5, be6, be7 */
- vpsubq RIDX2, RT1, RT1;
- vpshufb RIDX1, RT1, RXl1;
- vpsubq RIDX2, RT1, RT1;
- vpshufb RIDX1, RT1, RXr1;
- vpsubq RIDX2, RT1, RT1;
- vpshufb RIDX1, RT1, RXl2;
- vpsubq RIDX2, RT1, RT1;
- vpshufb RIDX1, RT1, RXr2;
- vpsubq RIDX2, RT1, RT1;
- vpshufb RIDX1, RT1, RXl3;
- vpsubq RIDX2, RT1, RT1;
- vpshufb RIDX1, RT1, RXr3;
-
- /* store last IV */
- vpsubq RIDX2, RT1, RT1; /* a: le33, b: le32, ... */
- vpshufb RIDX1x, RT1x, RT1x; /* a: be32, ... */
- vmovq RT1x, (%rcx);
-
- call __blowfish_enc_blk32;
-
- /* dst = src ^ iv */
- vpxor 0*32(%rdx), RXr0, RXr0;
- vpxor 1*32(%rdx), RXl0, RXl0;
- vpxor 2*32(%rdx), RXr1, RXr1;
- vpxor 3*32(%rdx), RXl1, RXl1;
- vpxor 4*32(%rdx), RXr2, RXr2;
- vpxor 5*32(%rdx), RXl2, RXl2;
- vpxor 6*32(%rdx), RXr3, RXr3;
- vpxor 7*32(%rdx), RXl3, RXl3;
- vmovdqu RXr0, (0*32)(%rsi);
- vmovdqu RXl0, (1*32)(%rsi);
- vmovdqu RXr1, (2*32)(%rsi);
- vmovdqu RXl1, (3*32)(%rsi);
- vmovdqu RXr2, (4*32)(%rsi);
- vmovdqu RXl2, (5*32)(%rsi);
- vmovdqu RXr3, (6*32)(%rsi);
- vmovdqu RXl3, (7*32)(%rsi);
-
- vzeroupper;
-
- ret;
-ENDPROC(blowfish_ctr_32way)
diff --git a/arch/x86/crypto/blowfish_avx2_glue.c b/arch/x86/crypto/blowfish_avx2_glue.c
deleted file mode 100644
index 4417e9aea78d..000000000000
--- a/arch/x86/crypto/blowfish_avx2_glue.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * Glue Code for x86_64/AVX2 assembler optimized version of Blowfish
- *
- * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
- *
- * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
- * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
- * CTR part based on code (crypto/ctr.c) by:
- * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@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
- * 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/types.h>
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <crypto/algapi.h>
-#include <crypto/blowfish.h>
-#include <crypto/cryptd.h>
-#include <crypto/ctr.h>
-#include <asm/i387.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
-#include <asm/crypto/blowfish.h>
-#include <asm/crypto/ablk_helper.h>
-#include <crypto/scatterwalk.h>
-
-#define BF_AVX2_PARALLEL_BLOCKS 32
-
-/* 32-way AVX2 parallel cipher functions */
-asmlinkage void blowfish_ecb_enc_32way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void blowfish_ecb_dec_32way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void blowfish_cbc_dec_32way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void blowfish_ctr_32way(struct bf_ctx *ctx, u8 *dst, const u8 *src,
- __be64 *iv);
-
-static inline bool bf_fpu_begin(bool fpu_enabled, unsigned int nbytes)
-{
- if (fpu_enabled)
- return true;
-
- /* FPU is only used when chunk to be processed is large enough, so
- * do not enable FPU until it is necessary.
- */
- if (nbytes < BF_BLOCK_SIZE * BF_AVX2_PARALLEL_BLOCKS)
- return false;
-
- kernel_fpu_begin();
- return true;
-}
-
-static inline void bf_fpu_end(bool fpu_enabled)
-{
- if (fpu_enabled)
- kernel_fpu_end();
-}
-
-static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
- bool enc)
-{
- bool fpu_enabled = false;
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- const unsigned int bsize = BF_BLOCK_SIZE;
- unsigned int nbytes;
- int err;
-
- err = blkcipher_walk_virt(desc, walk);
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-
- while ((nbytes = walk->nbytes)) {
- u8 *wsrc = walk->src.virt.addr;
- u8 *wdst = walk->dst.virt.addr;
-
- fpu_enabled = bf_fpu_begin(fpu_enabled, nbytes);
-
- /* Process multi-block AVX2 batch */
- if (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS) {
- do {
- if (enc)
- blowfish_ecb_enc_32way(ctx, wdst, wsrc);
- else
- blowfish_ecb_dec_32way(ctx, wdst, wsrc);
-
- wsrc += bsize * BF_AVX2_PARALLEL_BLOCKS;
- wdst += bsize * BF_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * BF_AVX2_PARALLEL_BLOCKS;
- } while (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS);
-
- if (nbytes < bsize)
- goto done;
- }
-
- /* Process multi-block batch */
- if (nbytes >= bsize * BF_PARALLEL_BLOCKS) {
- do {
- if (enc)
- blowfish_enc_blk_4way(ctx, wdst, wsrc);
- else
- blowfish_dec_blk_4way(ctx, wdst, wsrc);
-
- wsrc += bsize * BF_PARALLEL_BLOCKS;
- wdst += bsize * BF_PARALLEL_BLOCKS;
- nbytes -= bsize * BF_PARALLEL_BLOCKS;
- } while (nbytes >= bsize * BF_PARALLEL_BLOCKS);
-
- if (nbytes < bsize)
- goto done;
- }
-
- /* Handle leftovers */
- do {
- if (enc)
- blowfish_enc_blk(ctx, wdst, wsrc);
- else
- blowfish_dec_blk(ctx, wdst, wsrc);
-
- wsrc += bsize;
- wdst += bsize;
- nbytes -= bsize;
- } while (nbytes >= bsize);
-
-done:
- err = blkcipher_walk_done(desc, walk, nbytes);
- }
-
- bf_fpu_end(fpu_enabled);
- return err;
-}
-
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, true);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_crypt(desc, &walk, false);
-}
-
-static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- unsigned int bsize = BF_BLOCK_SIZE;
- unsigned int nbytes = walk->nbytes;
- u64 *src = (u64 *)walk->src.virt.addr;
- u64 *dst = (u64 *)walk->dst.virt.addr;
- u64 *iv = (u64 *)walk->iv;
-
- do {
- *dst = *src ^ *iv;
- blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
- iv = dst;
-
- src += 1;
- dst += 1;
- nbytes -= bsize;
- } while (nbytes >= bsize);
-
- *(u64 *)walk->iv = *iv;
- return nbytes;
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct blkcipher_walk walk;
- int err;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
-
- while ((nbytes = walk.nbytes)) {
- nbytes = __cbc_encrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
- }
-
- return err;
-}
-
-static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- const unsigned int bsize = BF_BLOCK_SIZE;
- unsigned int nbytes = walk->nbytes;
- u64 *src = (u64 *)walk->src.virt.addr;
- u64 *dst = (u64 *)walk->dst.virt.addr;
- u64 last_iv;
- int i;
-
- /* Start of the last block. */
- src += nbytes / bsize - 1;
- dst += nbytes / bsize - 1;
-
- last_iv = *src;
-
- /* Process multi-block AVX2 batch */
- if (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS) {
- do {
- nbytes -= bsize * (BF_AVX2_PARALLEL_BLOCKS - 1);
- src -= BF_AVX2_PARALLEL_BLOCKS - 1;
- dst -= BF_AVX2_PARALLEL_BLOCKS - 1;
-
- blowfish_cbc_dec_32way(ctx, (u8 *)dst, (u8 *)src);
-
- nbytes -= bsize;
- if (nbytes < bsize)
- goto done;
-
- *dst ^= *(src - 1);
- src -= 1;
- dst -= 1;
- } while (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS);
-
- if (nbytes < bsize)
- goto done;
- }
-
- /* Process multi-block batch */
- if (nbytes >= bsize * BF_PARALLEL_BLOCKS) {
- u64 ivs[BF_PARALLEL_BLOCKS - 1];
-
- do {
- nbytes -= bsize * (BF_PARALLEL_BLOCKS - 1);
- src -= BF_PARALLEL_BLOCKS - 1;
- dst -= BF_PARALLEL_BLOCKS - 1;
-
- for (i = 0; i < BF_PARALLEL_BLOCKS - 1; i++)
- ivs[i] = src[i];
-
- blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src);
-
- for (i = 0; i < BF_PARALLEL_BLOCKS - 1; i++)
- dst[i + 1] ^= ivs[i];
-
- nbytes -= bsize;
- if (nbytes < bsize)
- goto done;
-
- *dst ^= *(src - 1);
- src -= 1;
- dst -= 1;
- } while (nbytes >= bsize * BF_PARALLEL_BLOCKS);
-
- if (nbytes < bsize)
- goto done;
- }
-
- /* Handle leftovers */
- for (;;) {
- blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src);
-
- nbytes -= bsize;
- if (nbytes < bsize)
- break;
-
- *dst ^= *(src - 1);
- src -= 1;
- dst -= 1;
- }
-
-done:
- *dst ^= *(u64 *)walk->iv;
- *(u64 *)walk->iv = last_iv;
-
- return nbytes;
-}
-
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- bool fpu_enabled = false;
- struct blkcipher_walk walk;
- int err;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt(desc, &walk);
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-
- while ((nbytes = walk.nbytes)) {
- fpu_enabled = bf_fpu_begin(fpu_enabled, nbytes);
- nbytes = __cbc_decrypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
- }
-
- bf_fpu_end(fpu_enabled);
- return err;
-}
-
-static void ctr_crypt_final(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- u8 *ctrblk = walk->iv;
- u8 keystream[BF_BLOCK_SIZE];
- u8 *src = walk->src.virt.addr;
- u8 *dst = walk->dst.virt.addr;
- unsigned int nbytes = walk->nbytes;
-
- blowfish_enc_blk(ctx, keystream, ctrblk);
- crypto_xor(keystream, src, nbytes);
- memcpy(dst, keystream, nbytes);
-
- crypto_inc(ctrblk, BF_BLOCK_SIZE);
-}
-
-static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
- struct blkcipher_walk *walk)
-{
- struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- unsigned int bsize = BF_BLOCK_SIZE;
- unsigned int nbytes = walk->nbytes;
- u64 *src = (u64 *)walk->src.virt.addr;
- u64 *dst = (u64 *)walk->dst.virt.addr;
- int i;
-
- /* Process multi-block AVX2 batch */
- if (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS) {
- do {
- blowfish_ctr_32way(ctx, (u8 *)dst, (u8 *)src,
- (__be64 *)walk->iv);
-
- src += BF_AVX2_PARALLEL_BLOCKS;
- dst += BF_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * BF_AVX2_PARALLEL_BLOCKS;
- } while (nbytes >= bsize * BF_AVX2_PARALLEL_BLOCKS);
-
- if (nbytes < bsize)
- goto done;
- }
-
- /* Process four block batch */
- if (nbytes >= bsize * BF_PARALLEL_BLOCKS) {
- __be64 ctrblocks[BF_PARALLEL_BLOCKS];
- u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
-
- do {
- /* create ctrblks for parallel encrypt */
- for (i = 0; i < BF_PARALLEL_BLOCKS; i++) {
- if (dst != src)
- dst[i] = src[i];
-
- ctrblocks[i] = cpu_to_be64(ctrblk++);
- }
-
- blowfish_enc_blk_xor_4way(ctx, (u8 *)dst,
- (u8 *)ctrblocks);
-
- src += BF_PARALLEL_BLOCKS;
- dst += BF_PARALLEL_BLOCKS;
- nbytes -= bsize * BF_PARALLEL_BLOCKS;
- } while (nbytes >= bsize * BF_PARALLEL_BLOCKS);
-
- *(__be64 *)walk->iv = cpu_to_be64(ctrblk);
-
- if (nbytes < bsize)
- goto done;
- }
-
- /* Handle leftovers */
- do {
- u64 ctrblk;
-
- if (dst != src)
- *dst = *src;
-
- ctrblk = *(u64 *)walk->iv;
- be64_add_cpu((__be64 *)walk->iv, 1);
-
- blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)&ctrblk);
-
- src += 1;
- dst += 1;
- } while ((nbytes -= bsize) >= bsize);
-
-done:
- return nbytes;
-}
-
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- bool fpu_enabled = false;
- struct blkcipher_walk walk;
- int err;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- err = blkcipher_walk_virt_block(desc, &walk, BF_BLOCK_SIZE);
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
-
- while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) {
- fpu_enabled = bf_fpu_begin(fpu_enabled, nbytes);
- nbytes = __ctr_crypt(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, nbytes);
- }
-
- bf_fpu_end(fpu_enabled);
-
- if (walk.nbytes) {
- ctr_crypt_final(desc, &walk);
- err = blkcipher_walk_done(desc, &walk, 0);
- }
-
- return err;
-}
-
-static struct crypto_alg bf_algs[6] = { {
- .cra_name = "__ecb-blowfish-avx2",
- .cra_driver_name = "__driver-ecb-blowfish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = BF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct bf_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .setkey = blowfish_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-blowfish-avx2",
- .cra_driver_name = "__driver-cbc-blowfish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = BF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct bf_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .setkey = blowfish_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-blowfish-avx2",
- .cra_driver_name = "__driver-ctr-blowfish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct bf_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .ivsize = BF_BLOCK_SIZE,
- .setkey = blowfish_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "ecb(blowfish)",
- .cra_driver_name = "ecb-blowfish-avx2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = BF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(blowfish)",
- .cra_driver_name = "cbc-blowfish-avx2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = BF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .ivsize = BF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(blowfish)",
- .cra_driver_name = "ctr-blowfish-avx2",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = BF_MIN_KEY_SIZE,
- .max_keysize = BF_MAX_KEY_SIZE,
- .ivsize = BF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-} };
-
-
-static int __init init(void)
-{
- u64 xcr0;
-
- 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");
- return -ENODEV;
- }
-
- return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs));
-}
-
-static void __exit fini(void)
-{
- crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs));
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Blowfish Cipher Algorithm, AVX2 optimized");
-MODULE_ALIAS("blowfish");
-MODULE_ALIAS("blowfish-asm");
diff --git a/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c
index 3548d76dbaa9..50ec333b70e6 100644
--- a/arch/x86/crypto/blowfish_glue.c
+++ b/arch/x86/crypto/blowfish_glue.c
@@ -1,7 +1,7 @@
/*
* Glue Code for assembler optimized version of Blowfish
*
- * Copyright © 2011-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
+ * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
*
* CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
* Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
@@ -32,24 +32,40 @@
#include <linux/module.h>
#include <linux/types.h>
#include <crypto/algapi.h>
-#include <asm/crypto/blowfish.h>
/* regular block cipher functions */
asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src,
bool xor);
-EXPORT_SYMBOL_GPL(__blowfish_enc_blk);
-
asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src);
-EXPORT_SYMBOL_GPL(blowfish_dec_blk);
/* 4-way parallel cipher functions */
asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
const u8 *src, bool xor);
-EXPORT_SYMBOL_GPL(__blowfish_enc_blk_4way);
-
asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst,
const u8 *src);
-EXPORT_SYMBOL_GPL(blowfish_dec_blk_4way);
+
+static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src)
+{
+ __blowfish_enc_blk(ctx, dst, src, false);
+}
+
+static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst,
+ const u8 *src)
+{
+ __blowfish_enc_blk(ctx, dst, src, true);
+}
+
+static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
+ const u8 *src)
+{
+ __blowfish_enc_blk_4way(ctx, dst, src, false);
+}
+
+static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst,
+ const u8 *src)
+{
+ __blowfish_enc_blk_4way(ctx, dst, src, true);
+}
static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
diff --git a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S
index 91a1878fcc3e..0e0b8863a34b 100644
--- a/arch/x86/crypto/camellia-aesni-avx2-asm_64.S
+++ b/arch/x86/crypto/camellia-aesni-avx2-asm_64.S
@@ -51,16 +51,6 @@
#define ymm14_x xmm14
#define ymm15_x xmm15
-/*
- * AES-NI instructions do not support ymmX registers, so we need splitting and
- * merging.
- */
-#define vaesenclast256(zero, yreg, tmp) \
- vextracti128 $1, yreg, tmp##_x; \
- vaesenclast zero##_x, yreg##_x, yreg##_x; \
- vaesenclast zero##_x, tmp##_x, tmp##_x; \
- vinserti128 $1, tmp##_x, yreg, yreg;
-
/**********************************************************************
32-way camellia
**********************************************************************/
@@ -79,46 +69,70 @@
* S-function with AES subbytes \
*/ \
vbroadcasti128 .Linv_shift_row, t4; \
- vpbroadcastb .L0f0f0f0f, t7; \
- vbroadcasti128 .Lpre_tf_lo_s1, t0; \
- vbroadcasti128 .Lpre_tf_hi_s1, t1; \
+ vpbroadcastd .L0f0f0f0f, t7; \
+ vbroadcasti128 .Lpre_tf_lo_s1, t5; \
+ vbroadcasti128 .Lpre_tf_hi_s1, t6; \
+ vbroadcasti128 .Lpre_tf_lo_s4, t2; \
+ vbroadcasti128 .Lpre_tf_hi_s4, t3; \
\
/* AES inverse shift rows */ \
vpshufb t4, x0, x0; \
vpshufb t4, x7, x7; \
- vpshufb t4, x1, x1; \
- vpshufb t4, x4, x4; \
- vpshufb t4, x2, x2; \
- vpshufb t4, x5, x5; \
vpshufb t4, x3, x3; \
vpshufb t4, x6, x6; \
+ vpshufb t4, x2, x2; \
+ vpshufb t4, x5, x5; \
+ vpshufb t4, x1, x1; \
+ vpshufb t4, x4, x4; \
\
/* prefilter sboxes 1, 2 and 3 */ \
- vbroadcasti128 .Lpre_tf_lo_s4, t2; \
- vbroadcasti128 .Lpre_tf_hi_s4, t3; \
- filter_8bit(x0, t0, t1, t7, t6); \
- filter_8bit(x7, t0, t1, t7, t6); \
- filter_8bit(x1, t0, t1, t7, t6); \
- filter_8bit(x4, t0, t1, t7, t6); \
- filter_8bit(x2, t0, t1, t7, t6); \
- filter_8bit(x5, t0, t1, t7, t6); \
- \
/* prefilter sbox 4 */ \
+ filter_8bit(x0, t5, t6, t7, t4); \
+ filter_8bit(x7, t5, t6, t7, t4); \
+ vextracti128 $1, x0, t0##_x; \
+ vextracti128 $1, x7, t1##_x; \
+ filter_8bit(x3, t2, t3, t7, t4); \
+ filter_8bit(x6, t2, t3, t7, t4); \
+ vextracti128 $1, x3, t3##_x; \
+ vextracti128 $1, x6, t2##_x; \
+ filter_8bit(x2, t5, t6, t7, t4); \
+ filter_8bit(x5, t5, t6, t7, t4); \
+ filter_8bit(x1, t5, t6, t7, t4); \
+ filter_8bit(x4, t5, t6, t7, t4); \
+ \
vpxor t4##_x, t4##_x, t4##_x; \
- filter_8bit(x3, t2, t3, t7, t6); \
- filter_8bit(x6, t2, t3, t7, t6); \
\
/* AES subbytes + AES shift rows */ \
+ vextracti128 $1, x2, t6##_x; \
+ vextracti128 $1, x5, t5##_x; \
+ vaesenclast t4##_x, x0##_x, x0##_x; \
+ vaesenclast t4##_x, t0##_x, t0##_x; \
+ vinserti128 $1, t0##_x, x0, x0; \
+ vaesenclast t4##_x, x7##_x, x7##_x; \
+ vaesenclast t4##_x, t1##_x, t1##_x; \
+ vinserti128 $1, t1##_x, x7, x7; \
+ vaesenclast t4##_x, x3##_x, x3##_x; \
+ vaesenclast t4##_x, t3##_x, t3##_x; \
+ vinserti128 $1, t3##_x, x3, x3; \
+ vaesenclast t4##_x, x6##_x, x6##_x; \
+ vaesenclast t4##_x, t2##_x, t2##_x; \
+ vinserti128 $1, t2##_x, x6, x6; \
+ vextracti128 $1, x1, t3##_x; \
+ vextracti128 $1, x4, t2##_x; \
vbroadcasti128 .Lpost_tf_lo_s1, t0; \
vbroadcasti128 .Lpost_tf_hi_s1, t1; \
- vaesenclast256(t4, x0, t5); \
- vaesenclast256(t4, x7, t5); \
- vaesenclast256(t4, x1, t5); \
- vaesenclast256(t4, x4, t5); \
- vaesenclast256(t4, x2, t5); \
- vaesenclast256(t4, x5, t5); \
- vaesenclast256(t4, x3, t5); \
- vaesenclast256(t4, x6, t5); \
+ vaesenclast t4##_x, x2##_x, x2##_x; \
+ vaesenclast t4##_x, t6##_x, t6##_x; \
+ vinserti128 $1, t6##_x, x2, x2; \
+ vaesenclast t4##_x, x5##_x, x5##_x; \
+ vaesenclast t4##_x, t5##_x, t5##_x; \
+ vinserti128 $1, t5##_x, x5, x5; \
+ vaesenclast t4##_x, x1##_x, x1##_x; \
+ vaesenclast t4##_x, t3##_x, t3##_x; \
+ vinserti128 $1, t3##_x, x1, x1; \
+ vaesenclast t4##_x, x4##_x, x4##_x; \
+ vaesenclast t4##_x, t2##_x, t2##_x; \
+ vinserti128 $1, t2##_x, x4, x4; \
\
/* postfilter sboxes 1 and 4 */ \
vbroadcasti128 .Lpost_tf_lo_s3, t2; \
@@ -139,22 +153,12 @@
/* postfilter sbox 2 */ \
filter_8bit(x1, t4, t5, t7, t2); \
filter_8bit(x4, t4, t5, t7, t2); \
+ vpxor t7, t7, t7; \
\
vpsrldq $1, t0, t1; \
vpsrldq $2, t0, t2; \
+ vpshufb t7, t1, t1; \
vpsrldq $3, t0, t3; \
- vpsrldq $4, t0, t4; \
- vpsrldq $5, t0, t5; \
- vpsrldq $6, t0, t6; \
- vpsrldq $7, t0, t7; \
- vpbroadcastb t0##_x, t0; \
- vpbroadcastb t1##_x, t1; \
- vpbroadcastb t2##_x, t2; \
- vpbroadcastb t3##_x, t3; \
- vpbroadcastb t4##_x, t4; \
- vpbroadcastb t6##_x, t6; \
- vpbroadcastb t5##_x, t5; \
- vpbroadcastb t7##_x, t7; \
\
/* P-function */ \
vpxor x5, x0, x0; \
@@ -162,11 +166,21 @@
vpxor x7, x2, x2; \
vpxor x4, x3, x3; \
\
+ vpshufb t7, t2, t2; \
+ vpsrldq $4, t0, t4; \
+ vpshufb t7, t3, t3; \
+ vpsrldq $5, t0, t5; \
+ vpshufb t7, t4, t4; \
+ \
vpxor x2, x4, x4; \
vpxor x3, x5, x5; \
vpxor x0, x6, x6; \
vpxor x1, x7, x7; \
\
+ vpsrldq $6, t0, t6; \
+ vpshufb t7, t5, t5; \
+ vpshufb t7, t6, t6; \
+ \
vpxor x7, x0, x0; \
vpxor x4, x1, x1; \
vpxor x5, x2, x2; \
@@ -179,12 +193,16 @@
\
/* Add key material and result to CD (x becomes new CD) */ \
\
- vpxor t7, x0, x0; \
- vpxor 4 * 32(mem_cd), x0, x0; \
- \
vpxor t6, x1, x1; \
vpxor 5 * 32(mem_cd), x1, x1; \
\
+ vpsrldq $7, t0, t6; \
+ vpshufb t7, t0, t0; \
+ vpshufb t7, t6, t7; \
+ \
+ vpxor t7, x0, x0; \
+ vpxor 4 * 32(mem_cd), x0, x0; \
+ \
vpxor t5, x2, x2; \
vpxor 6 * 32(mem_cd), x2, x2; \
\
@@ -204,7 +222,7 @@
vpxor 3 * 32(mem_cd), x7, x7;
/*
- * Size optimization... with inlined roundsm16 binary would be over 5 times
+ * Size optimization... with inlined roundsm32 binary would be over 5 times
* larger and would only marginally faster.
*/
.align 8
@@ -324,13 +342,13 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
*/ \
vpbroadcastd kll, t0; /* only lowest 32-bit used */ \
vpxor tt0, tt0, tt0; \
- vpbroadcastb t0##_x, t3; \
+ vpshufb tt0, t0, t3; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t2; \
+ vpshufb tt0, t0, t2; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t1; \
+ vpshufb tt0, t0, t1; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t0; \
+ vpshufb tt0, t0, t0; \
\
vpand l0, t0, t0; \
vpand l1, t1, t1; \
@@ -340,6 +358,7 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
rol32_1_32(t3, t2, t1, t0, tt1, tt2, tt3, tt0); \
\
vpxor l4, t0, l4; \
+ vpbroadcastd krr, t0; /* only lowest 32-bit used */ \
vmovdqu l4, 4 * 32(l); \
vpxor l5, t1, l5; \
vmovdqu l5, 5 * 32(l); \
@@ -354,14 +373,13 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
* rl ^= t2; \
*/ \
\
- vpbroadcastd krr, t0; /* only lowest 32-bit used */ \
- vpbroadcastb t0##_x, t3; \
+ vpshufb tt0, t0, t3; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t2; \
+ vpshufb tt0, t0, t2; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t1; \
+ vpshufb tt0, t0, t1; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t0; \
+ vpshufb tt0, t0, t0; \
\
vpor 4 * 32(r), t0, t0; \
vpor 5 * 32(r), t1, t1; \
@@ -373,6 +391,7 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
vpxor 2 * 32(r), t2, t2; \
vpxor 3 * 32(r), t3, t3; \
vmovdqu t0, 0 * 32(r); \
+ vpbroadcastd krl, t0; /* only lowest 32-bit used */ \
vmovdqu t1, 1 * 32(r); \
vmovdqu t2, 2 * 32(r); \
vmovdqu t3, 3 * 32(r); \
@@ -382,14 +401,13 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
* t2 &= rl; \
* rr ^= rol32(t2, 1); \
*/ \
- vpbroadcastd krl, t0; /* only lowest 32-bit used */ \
- vpbroadcastb t0##_x, t3; \
+ vpshufb tt0, t0, t3; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t2; \
+ vpshufb tt0, t0, t2; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t1; \
+ vpshufb tt0, t0, t1; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t0; \
+ vpshufb tt0, t0, t0; \
\
vpand 0 * 32(r), t0, t0; \
vpand 1 * 32(r), t1, t1; \
@@ -403,6 +421,7 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
vpxor 6 * 32(r), t2, t2; \
vpxor 7 * 32(r), t3, t3; \
vmovdqu t0, 4 * 32(r); \
+ vpbroadcastd klr, t0; /* only lowest 32-bit used */ \
vmovdqu t1, 5 * 32(r); \
vmovdqu t2, 6 * 32(r); \
vmovdqu t3, 7 * 32(r); \
@@ -413,14 +432,13 @@ ENDPROC(roundsm32_x4_x5_x6_x7_x0_x1_x2_x3_y4_y5_y6_y7_y0_y1_y2_y3_ab)
* ll ^= t0; \
*/ \
\
- vpbroadcastd klr, t0; /* only lowest 32-bit used */ \
- vpbroadcastb t0##_x, t3; \
+ vpshufb tt0, t0, t3; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t2; \
+ vpshufb tt0, t0, t2; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t1; \
+ vpshufb tt0, t0, t1; \
vpsrldq $1, t0, t0; \
- vpbroadcastb t0##_x, t0; \
+ vpshufb tt0, t0, t0; \
\
vpor l4, t0, t0; \
vpor l5, t1, t1; \
diff --git a/arch/x86/crypto/crct10dif-pcl-asm_64.S b/arch/x86/crypto/crct10dif-pcl-asm_64.S
new file mode 100644
index 000000000000..35e97569d05f
--- /dev/null
+++ b/arch/x86/crypto/crct10dif-pcl-asm_64.S
@@ -0,0 +1,643 @@
+########################################################################
+# Implement fast CRC-T10DIF computation with SSE and PCLMULQDQ instructions
+#
+# Copyright (c) 2013, Intel Corporation
+#
+# Authors:
+# Erdinc Ozturk <erdinc.ozturk@intel.com>
+# Vinodh Gopal <vinodh.gopal@intel.com>
+# James Guilford <james.guilford@intel.com>
+# Tim Chen <tim.c.chen@linux.intel.com>
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# 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 the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+#
+# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""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 INTEL CORPORATION OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+########################################################################
+# Function API:
+# UINT16 crc_t10dif_pcl(
+# UINT16 init_crc, //initial CRC value, 16 bits
+# const unsigned char *buf, //buffer pointer to calculate CRC on
+# UINT64 len //buffer length in bytes (64-bit data)
+# );
+#
+# Reference paper titled "Fast CRC Computation for Generic
+# Polynomials Using PCLMULQDQ Instruction"
+# URL: http://www.intel.com/content/dam/www/public/us/en/documents
+# /white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
+#
+#
+
+#include <linux/linkage.h>
+
+.text
+
+#define arg1 %rdi
+#define arg2 %rsi
+#define arg3 %rdx
+
+#define arg1_low32 %edi
+
+ENTRY(crc_t10dif_pcl)
+.align 16
+
+ # adjust the 16-bit initial_crc value, scale it to 32 bits
+ shl $16, arg1_low32
+
+ # Allocate Stack Space
+ mov %rsp, %rcx
+ sub $16*2, %rsp
+ # align stack to 16 byte boundary
+ and $~(0x10 - 1), %rsp
+
+ # check if smaller than 256
+ cmp $256, arg3
+
+ # for sizes less than 128, we can't fold 64B at a time...
+ jl _less_than_128
+
+
+ # load the initial crc value
+ movd arg1_low32, %xmm10 # initial crc
+
+ # crc value does not need to be byte-reflected, but it needs
+ # to be moved to the high part of the register.
+ # because data will be byte-reflected and will align with
+ # initial crc at correct place.
+ pslldq $12, %xmm10
+
+ movdqa SHUF_MASK(%rip), %xmm11
+ # receive the initial 64B data, xor the initial crc value
+ movdqu 16*0(arg2), %xmm0
+ movdqu 16*1(arg2), %xmm1
+ movdqu 16*2(arg2), %xmm2
+ movdqu 16*3(arg2), %xmm3
+ movdqu 16*4(arg2), %xmm4
+ movdqu 16*5(arg2), %xmm5
+ movdqu 16*6(arg2), %xmm6
+ movdqu 16*7(arg2), %xmm7
+
+ pshufb %xmm11, %xmm0
+ # XOR the initial_crc value
+ pxor %xmm10, %xmm0
+ pshufb %xmm11, %xmm1
+ pshufb %xmm11, %xmm2
+ pshufb %xmm11, %xmm3
+ pshufb %xmm11, %xmm4
+ pshufb %xmm11, %xmm5
+ pshufb %xmm11, %xmm6
+ pshufb %xmm11, %xmm7
+
+ movdqa rk3(%rip), %xmm10 #xmm10 has rk3 and rk4
+ #imm value of pclmulqdq instruction
+ #will determine which constant to use
+
+ #################################################################
+ # we subtract 256 instead of 128 to save one instruction from the loop
+ sub $256, arg3
+
+ # at this section of the code, there is 64*x+y (0<=y<64) bytes of
+ # buffer. The _fold_64_B_loop will fold 64B at a time
+ # until we have 64+y Bytes of buffer
+
+
+ # fold 64B at a time. This section of the code folds 4 xmm
+ # registers in parallel
+_fold_64_B_loop:
+
+ # update the buffer pointer
+ add $128, arg2 # buf += 64#
+
+ movdqu 16*0(arg2), %xmm9
+ movdqu 16*1(arg2), %xmm12
+ pshufb %xmm11, %xmm9
+ pshufb %xmm11, %xmm12
+ movdqa %xmm0, %xmm8
+ movdqa %xmm1, %xmm13
+ pclmulqdq $0x0 , %xmm10, %xmm0
+ pclmulqdq $0x11, %xmm10, %xmm8
+ pclmulqdq $0x0 , %xmm10, %xmm1
+ pclmulqdq $0x11, %xmm10, %xmm13
+ pxor %xmm9 , %xmm0
+ xorps %xmm8 , %xmm0
+ pxor %xmm12, %xmm1
+ xorps %xmm13, %xmm1
+
+ movdqu 16*2(arg2), %xmm9
+ movdqu 16*3(arg2), %xmm12
+ pshufb %xmm11, %xmm9
+ pshufb %xmm11, %xmm12
+ movdqa %xmm2, %xmm8
+ movdqa %xmm3, %xmm13
+ pclmulqdq $0x0, %xmm10, %xmm2
+ pclmulqdq $0x11, %xmm10, %xmm8
+ pclmulqdq $0x0, %xmm10, %xmm3
+ pclmulqdq $0x11, %xmm10, %xmm13
+ pxor %xmm9 , %xmm2
+ xorps %xmm8 , %xmm2
+ pxor %xmm12, %xmm3
+ xorps %xmm13, %xmm3
+
+ movdqu 16*4(arg2), %xmm9
+ movdqu 16*5(arg2), %xmm12
+ pshufb %xmm11, %xmm9
+ pshufb %xmm11, %xmm12
+ movdqa %xmm4, %xmm8
+ movdqa %xmm5, %xmm13
+ pclmulqdq $0x0, %xmm10, %xmm4
+ pclmulqdq $0x11, %xmm10, %xmm8
+ pclmulqdq $0x0, %xmm10, %xmm5
+ pclmulqdq $0x11, %xmm10, %xmm13
+ pxor %xmm9 , %xmm4
+ xorps %xmm8 , %xmm4
+ pxor %xmm12, %xmm5
+ xorps %xmm13, %xmm5
+
+ movdqu 16*6(arg2), %xmm9
+ movdqu 16*7(arg2), %xmm12
+ pshufb %xmm11, %xmm9
+ pshufb %xmm11, %xmm12
+ movdqa %xmm6 , %xmm8
+ movdqa %xmm7 , %xmm13
+ pclmulqdq $0x0 , %xmm10, %xmm6
+ pclmulqdq $0x11, %xmm10, %xmm8
+ pclmulqdq $0x0 , %xmm10, %xmm7
+ pclmulqdq $0x11, %xmm10, %xmm13
+ pxor %xmm9 , %xmm6
+ xorps %xmm8 , %xmm6
+ pxor %xmm12, %xmm7
+ xorps %xmm13, %xmm7
+
+ sub $128, arg3
+
+ # check if there is another 64B in the buffer to be able to fold
+ jge _fold_64_B_loop
+ ##################################################################
+
+
+ add $128, arg2
+ # at this point, the buffer pointer is pointing at the last y Bytes
+ # of the buffer the 64B of folded data is in 4 of the xmm
+ # registers: xmm0, xmm1, xmm2, xmm3
+
+
+ # fold the 8 xmm registers to 1 xmm register with different constants
+
+ movdqa rk9(%rip), %xmm10
+ movdqa %xmm0, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm0
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ xorps %xmm0, %xmm7
+
+ movdqa rk11(%rip), %xmm10
+ movdqa %xmm1, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm1
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ xorps %xmm1, %xmm7
+
+ movdqa rk13(%rip), %xmm10
+ movdqa %xmm2, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm2
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ pxor %xmm2, %xmm7
+
+ movdqa rk15(%rip), %xmm10
+ movdqa %xmm3, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm3
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ xorps %xmm3, %xmm7
+
+ movdqa rk17(%rip), %xmm10
+ movdqa %xmm4, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm4
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ pxor %xmm4, %xmm7
+
+ movdqa rk19(%rip), %xmm10
+ movdqa %xmm5, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm5
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ xorps %xmm5, %xmm7
+
+ movdqa rk1(%rip), %xmm10 #xmm10 has rk1 and rk2
+ #imm value of pclmulqdq instruction
+ #will determine which constant to use
+ movdqa %xmm6, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm6
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ pxor %xmm6, %xmm7
+
+
+ # instead of 64, we add 48 to the loop counter to save 1 instruction
+ # from the loop instead of a cmp instruction, we use the negative
+ # flag with the jl instruction
+ add $128-16, arg3
+ jl _final_reduction_for_128
+
+ # now we have 16+y bytes left to reduce. 16 Bytes is in register xmm7
+ # and the rest is in memory. We can fold 16 bytes at a time if y>=16
+ # continue folding 16B at a time
+
+_16B_reduction_loop:
+ movdqa %xmm7, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm7
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ movdqu (arg2), %xmm0
+ pshufb %xmm11, %xmm0
+ pxor %xmm0 , %xmm7
+ add $16, arg2
+ sub $16, arg3
+ # instead of a cmp instruction, we utilize the flags with the
+ # jge instruction equivalent of: cmp arg3, 16-16
+ # check if there is any more 16B in the buffer to be able to fold
+ jge _16B_reduction_loop
+
+ #now we have 16+z bytes left to reduce, where 0<= z < 16.
+ #first, we reduce the data in the xmm7 register
+
+
+_final_reduction_for_128:
+ # check if any more data to fold. If not, compute the CRC of
+ # the final 128 bits
+ add $16, arg3
+ je _128_done
+
+ # here we are getting data that is less than 16 bytes.
+ # since we know that there was data before the pointer, we can
+ # offset the input pointer before the actual point, to receive
+ # exactly 16 bytes. after that the registers need to be adjusted.
+_get_last_two_xmms:
+ movdqa %xmm7, %xmm2
+
+ movdqu -16(arg2, arg3), %xmm1
+ pshufb %xmm11, %xmm1
+
+ # get rid of the extra data that was loaded before
+ # load the shift constant
+ lea pshufb_shf_table+16(%rip), %rax
+ sub arg3, %rax
+ movdqu (%rax), %xmm0
+
+ # shift xmm2 to the left by arg3 bytes
+ pshufb %xmm0, %xmm2
+
+ # shift xmm7 to the right by 16-arg3 bytes
+ pxor mask1(%rip), %xmm0
+ pshufb %xmm0, %xmm7
+ pblendvb %xmm2, %xmm1 #xmm0 is implicit
+
+ # fold 16 Bytes
+ movdqa %xmm1, %xmm2
+ movdqa %xmm7, %xmm8
+ pclmulqdq $0x11, %xmm10, %xmm7
+ pclmulqdq $0x0 , %xmm10, %xmm8
+ pxor %xmm8, %xmm7
+ pxor %xmm2, %xmm7
+
+_128_done:
+ # compute crc of a 128-bit value
+ movdqa rk5(%rip), %xmm10 # rk5 and rk6 in xmm10
+ movdqa %xmm7, %xmm0
+
+ #64b fold
+ pclmulqdq $0x1, %xmm10, %xmm7
+ pslldq $8 , %xmm0
+ pxor %xmm0, %xmm7
+
+ #32b fold
+ movdqa %xmm7, %xmm0
+
+ pand mask2(%rip), %xmm0
+
+ psrldq $12, %xmm7
+ pclmulqdq $0x10, %xmm10, %xmm7
+ pxor %xmm0, %xmm7
+
+ #barrett reduction
+_barrett:
+ movdqa rk7(%rip), %xmm10 # rk7 and rk8 in xmm10
+ movdqa %xmm7, %xmm0
+ pclmulqdq $0x01, %xmm10, %xmm7
+ pslldq $4, %xmm7
+ pclmulqdq $0x11, %xmm10, %xmm7
+
+ pslldq $4, %xmm7
+ pxor %xmm0, %xmm7
+ pextrd $1, %xmm7, %eax
+
+_cleanup:
+ # scale the result back to 16 bits
+ shr $16, %eax
+ mov %rcx, %rsp
+ ret
+
+########################################################################
+
+.align 16
+_less_than_128:
+
+ # check if there is enough buffer to be able to fold 16B at a time
+ cmp $32, arg3
+ jl _less_than_32
+ movdqa SHUF_MASK(%rip), %xmm11
+
+ # now if there is, load the constants
+ movdqa rk1(%rip), %xmm10 # rk1 and rk2 in xmm10
+
+ movd arg1_low32, %xmm0 # get the initial crc value
+ pslldq $12, %xmm0 # align it to its correct place
+ movdqu (arg2), %xmm7 # load the plaintext
+ pshufb %xmm11, %xmm7 # byte-reflect the plaintext
+ pxor %xmm0, %xmm7
+
+
+ # update the buffer pointer
+ add $16, arg2
+
+ # update the counter. subtract 32 instead of 16 to save one
+ # instruction from the loop
+ sub $32, arg3
+
+ jmp _16B_reduction_loop
+
+
+.align 16
+_less_than_32:
+ # mov initial crc to the return value. this is necessary for
+ # zero-length buffers.
+ mov arg1_low32, %eax
+ test arg3, arg3
+ je _cleanup
+
+ movdqa SHUF_MASK(%rip), %xmm11
+
+ movd arg1_low32, %xmm0 # get the initial crc value
+ pslldq $12, %xmm0 # align it to its correct place
+
+ cmp $16, arg3
+ je _exact_16_left
+ jl _less_than_16_left
+
+ movdqu (arg2), %xmm7 # load the plaintext
+ pshufb %xmm11, %xmm7 # byte-reflect the plaintext
+ pxor %xmm0 , %xmm7 # xor the initial crc value
+ add $16, arg2
+ sub $16, arg3
+ movdqa rk1(%rip), %xmm10 # rk1 and rk2 in xmm10
+ jmp _get_last_two_xmms
+
+
+.align 16
+_less_than_16_left:
+ # use stack space to load data less than 16 bytes, zero-out
+ # the 16B in memory first.
+
+ pxor %xmm1, %xmm1
+ mov %rsp, %r11
+ movdqa %xmm1, (%r11)
+
+ cmp $4, arg3
+ jl _only_less_than_4
+
+ # backup the counter value
+ mov arg3, %r9
+ cmp $8, arg3
+ jl _less_than_8_left
+
+ # load 8 Bytes
+ mov (arg2), %rax
+ mov %rax, (%r11)
+ add $8, %r11
+ sub $8, arg3
+ add $8, arg2
+_less_than_8_left:
+
+ cmp $4, arg3
+ jl _less_than_4_left
+
+ # load 4 Bytes
+ mov (arg2), %eax
+ mov %eax, (%r11)
+ add $4, %r11
+ sub $4, arg3
+ add $4, arg2
+_less_than_4_left:
+
+ cmp $2, arg3
+ jl _less_than_2_left
+
+ # load 2 Bytes
+ mov (arg2), %ax
+ mov %ax, (%r11)
+ add $2, %r11
+ sub $2, arg3
+ add $2, arg2
+_less_than_2_left:
+ cmp $1, arg3
+ jl _zero_left
+
+ # load 1 Byte
+ mov (arg2), %al
+ mov %al, (%r11)
+_zero_left:
+ movdqa (%rsp), %xmm7
+ pshufb %xmm11, %xmm7
+ pxor %xmm0 , %xmm7 # xor the initial crc value
+
+ # shl r9, 4
+ lea pshufb_shf_table+16(%rip), %rax
+ sub %r9, %rax
+ movdqu (%rax), %xmm0
+ pxor mask1(%rip), %xmm0
+
+ pshufb %xmm0, %xmm7
+ jmp _128_done
+
+.align 16
+_exact_16_left:
+ movdqu (arg2), %xmm7
+ pshufb %xmm11, %xmm7
+ pxor %xmm0 , %xmm7 # xor the initial crc value
+
+ jmp _128_done
+
+_only_less_than_4:
+ cmp $3, arg3
+ jl _only_less_than_3
+
+ # load 3 Bytes
+ mov (arg2), %al
+ mov %al, (%r11)
+
+ mov 1(arg2), %al
+ mov %al, 1(%r11)
+
+ mov 2(arg2), %al
+ mov %al, 2(%r11)
+
+ movdqa (%rsp), %xmm7
+ pshufb %xmm11, %xmm7
+ pxor %xmm0 , %xmm7 # xor the initial crc value
+
+ psrldq $5, %xmm7
+
+ jmp _barrett
+_only_less_than_3:
+ cmp $2, arg3
+ jl _only_less_than_2
+
+ # load 2 Bytes
+ mov (arg2), %al
+ mov %al, (%r11)
+
+ mov 1(arg2), %al
+ mov %al, 1(%r11)
+
+ movdqa (%rsp), %xmm7
+ pshufb %xmm11, %xmm7
+ pxor %xmm0 , %xmm7 # xor the initial crc value
+
+ psrldq $6, %xmm7
+
+ jmp _barrett
+_only_less_than_2:
+
+ # load 1 Byte
+ mov (arg2), %al
+ mov %al, (%r11)
+
+ movdqa (%rsp), %xmm7
+ pshufb %xmm11, %xmm7
+ pxor %xmm0 , %xmm7 # xor the initial crc value
+
+ psrldq $7, %xmm7
+
+ jmp _barrett
+
+ENDPROC(crc_t10dif_pcl)
+
+.data
+
+# precomputed constants
+# these constants are precomputed from the poly:
+# 0x8bb70000 (0x8bb7 scaled to 32 bits)
+.align 16
+# Q = 0x18BB70000
+# rk1 = 2^(32*3) mod Q << 32
+# rk2 = 2^(32*5) mod Q << 32
+# rk3 = 2^(32*15) mod Q << 32
+# rk4 = 2^(32*17) mod Q << 32
+# rk5 = 2^(32*3) mod Q << 32
+# rk6 = 2^(32*2) mod Q << 32
+# rk7 = floor(2^64/Q)
+# rk8 = Q
+rk1:
+.quad 0x2d56000000000000
+rk2:
+.quad 0x06df000000000000
+rk3:
+.quad 0x9d9d000000000000
+rk4:
+.quad 0x7cf5000000000000
+rk5:
+.quad 0x2d56000000000000
+rk6:
+.quad 0x1368000000000000
+rk7:
+.quad 0x00000001f65a57f8
+rk8:
+.quad 0x000000018bb70000
+
+rk9:
+.quad 0xceae000000000000
+rk10:
+.quad 0xbfd6000000000000
+rk11:
+.quad 0x1e16000000000000
+rk12:
+.quad 0x713c000000000000
+rk13:
+.quad 0xf7f9000000000000
+rk14:
+.quad 0x80a6000000000000
+rk15:
+.quad 0x044c000000000000
+rk16:
+.quad 0xe658000000000000
+rk17:
+.quad 0xad18000000000000
+rk18:
+.quad 0xa497000000000000
+rk19:
+.quad 0x6ee3000000000000
+rk20:
+.quad 0xe7b5000000000000
+
+
+
+mask1:
+.octa 0x80808080808080808080808080808080
+mask2:
+.octa 0x00000000FFFFFFFFFFFFFFFFFFFFFFFF
+
+SHUF_MASK:
+.octa 0x000102030405060708090A0B0C0D0E0F
+
+pshufb_shf_table:
+# use these values for shift constants for the pshufb instruction
+# different alignments result in values as shown:
+# DDQ 0x008f8e8d8c8b8a898887868584838281 # shl 15 (16-1) / shr1
+# DDQ 0x01008f8e8d8c8b8a8988878685848382 # shl 14 (16-3) / shr2
+# DDQ 0x0201008f8e8d8c8b8a89888786858483 # shl 13 (16-4) / shr3
+# DDQ 0x030201008f8e8d8c8b8a898887868584 # shl 12 (16-4) / shr4
+# DDQ 0x04030201008f8e8d8c8b8a8988878685 # shl 11 (16-5) / shr5
+# DDQ 0x0504030201008f8e8d8c8b8a89888786 # shl 10 (16-6) / shr6
+# DDQ 0x060504030201008f8e8d8c8b8a898887 # shl 9 (16-7) / shr7
+# DDQ 0x07060504030201008f8e8d8c8b8a8988 # shl 8 (16-8) / shr8
+# DDQ 0x0807060504030201008f8e8d8c8b8a89 # shl 7 (16-9) / shr9
+# DDQ 0x090807060504030201008f8e8d8c8b8a # shl 6 (16-10) / shr10
+# DDQ 0x0a090807060504030201008f8e8d8c8b # shl 5 (16-11) / shr11
+# DDQ 0x0b0a090807060504030201008f8e8d8c # shl 4 (16-12) / shr12
+# DDQ 0x0c0b0a090807060504030201008f8e8d # shl 3 (16-13) / shr13
+# DDQ 0x0d0c0b0a090807060504030201008f8e # shl 2 (16-14) / shr14
+# DDQ 0x0e0d0c0b0a090807060504030201008f # shl 1 (16-15) / shr15
+.octa 0x8f8e8d8c8b8a89888786858483828100
+.octa 0x000e0d0c0b0a09080706050403020100
diff --git a/arch/x86/crypto/crct10dif-pclmul_glue.c b/arch/x86/crypto/crct10dif-pclmul_glue.c
new file mode 100644
index 000000000000..7845d7fd54c0
--- /dev/null
+++ b/arch/x86/crypto/crct10dif-pclmul_glue.c
@@ -0,0 +1,151 @@
+/*
+ * Cryptographic API.
+ *
+ * T10 Data Integrity Field CRC16 Crypto Transform using PCLMULQDQ Instructions
+ *
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/crc-t10dif.h>
+#include <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/i387.h>
+#include <asm/cpufeature.h>
+#include <asm/cpu_device_id.h>
+
+asmlinkage __u16 crc_t10dif_pcl(__u16 crc, const unsigned char *buf,
+ size_t len);
+
+struct chksum_desc_ctx {
+ __u16 crc;
+};
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static int chksum_init(struct shash_desc *desc)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ ctx->crc = 0;
+
+ return 0;
+}
+
+static int chksum_update(struct shash_desc *desc, const u8 *data,
+ unsigned int length)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ if (irq_fpu_usable()) {
+ kernel_fpu_begin();
+ ctx->crc = crc_t10dif_pcl(ctx->crc, data, length);
+ kernel_fpu_end();
+ } else
+ ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
+ return 0;
+}
+
+static int chksum_final(struct shash_desc *desc, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ *(__u16 *)out = ctx->crc;
+ return 0;
+}
+
+static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
+ u8 *out)
+{
+ if (irq_fpu_usable()) {
+ kernel_fpu_begin();
+ *(__u16 *)out = crc_t10dif_pcl(*crcp, data, len);
+ kernel_fpu_end();
+ } else
+ *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
+ return 0;
+}
+
+static int chksum_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ return __chksum_finup(&ctx->crc, data, len, out);
+}
+
+static int chksum_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int length, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ return __chksum_finup(&ctx->crc, data, length, out);
+}
+
+static struct shash_alg alg = {
+ .digestsize = CRC_T10DIF_DIGEST_SIZE,
+ .init = chksum_init,
+ .update = chksum_update,
+ .final = chksum_final,
+ .finup = chksum_finup,
+ .digest = chksum_digest,
+ .descsize = sizeof(struct chksum_desc_ctx),
+ .base = {
+ .cra_name = "crct10dif",
+ .cra_driver_name = "crct10dif-pclmul",
+ .cra_priority = 200,
+ .cra_blocksize = CRC_T10DIF_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static const struct x86_cpu_id crct10dif_cpu_id[] = {
+ X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ),
+ {}
+};
+MODULE_DEVICE_TABLE(x86cpu, crct10dif_cpu_id);
+
+static int __init crct10dif_intel_mod_init(void)
+{
+ if (!x86_match_cpu(crct10dif_cpu_id))
+ return -ENODEV;
+
+ return crypto_register_shash(&alg);
+}
+
+static void __exit crct10dif_intel_mod_fini(void)
+{
+ crypto_unregister_shash(&alg);
+}
+
+module_init(crct10dif_intel_mod_init);
+module_exit(crct10dif_intel_mod_fini);
+
+MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
+MODULE_DESCRIPTION("T10 DIF CRC calculation accelerated with PCLMULQDQ.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("crct10dif");
+MODULE_ALIAS("crct10dif-pclmul");
diff --git a/arch/x86/crypto/sha256_ssse3_glue.c b/arch/x86/crypto/sha256_ssse3_glue.c
index 597d4da69656..50226c4b86ed 100644
--- a/arch/x86/crypto/sha256_ssse3_glue.c
+++ b/arch/x86/crypto/sha256_ssse3_glue.c
@@ -187,7 +187,36 @@ static int sha256_ssse3_import(struct shash_desc *desc, const void *in)
return 0;
}
-static struct shash_alg alg = {
+static int sha224_ssse3_init(struct shash_desc *desc)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+
+ sctx->state[0] = SHA224_H0;
+ sctx->state[1] = SHA224_H1;
+ sctx->state[2] = SHA224_H2;
+ sctx->state[3] = SHA224_H3;
+ sctx->state[4] = SHA224_H4;
+ sctx->state[5] = SHA224_H5;
+ sctx->state[6] = SHA224_H6;
+ sctx->state[7] = SHA224_H7;
+ sctx->count = 0;
+
+ return 0;
+}
+
+static int sha224_ssse3_final(struct shash_desc *desc, u8 *hash)
+{
+ u8 D[SHA256_DIGEST_SIZE];
+
+ sha256_ssse3_final(desc, D);
+
+ memcpy(hash, D, SHA224_DIGEST_SIZE);
+ memset(D, 0, SHA256_DIGEST_SIZE);
+
+ return 0;
+}
+
+static struct shash_alg algs[] = { {
.digestsize = SHA256_DIGEST_SIZE,
.init = sha256_ssse3_init,
.update = sha256_ssse3_update,
@@ -204,7 +233,24 @@ static struct shash_alg alg = {
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
-};
+}, {
+ .digestsize = SHA224_DIGEST_SIZE,
+ .init = sha224_ssse3_init,
+ .update = sha256_ssse3_update,
+ .final = sha224_ssse3_final,
+ .export = sha256_ssse3_export,
+ .import = sha256_ssse3_import,
+ .descsize = sizeof(struct sha256_state),
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha224",
+ .cra_driver_name = "sha224-ssse3",
+ .cra_priority = 150,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA224_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+} };
#ifdef CONFIG_AS_AVX
static bool __init avx_usable(void)
@@ -227,7 +273,7 @@ static bool __init avx_usable(void)
static int __init sha256_ssse3_mod_init(void)
{
- /* test for SSE3 first */
+ /* test for SSSE3 first */
if (cpu_has_ssse3)
sha256_transform_asm = sha256_transform_ssse3;
@@ -254,7 +300,7 @@ static int __init sha256_ssse3_mod_init(void)
else
#endif
pr_info("Using SSSE3 optimized SHA-256 implementation\n");
- return crypto_register_shash(&alg);
+ return crypto_register_shashes(algs, ARRAY_SIZE(algs));
}
pr_info("Neither AVX nor SSSE3 is available/usable.\n");
@@ -263,7 +309,7 @@ static int __init sha256_ssse3_mod_init(void)
static void __exit sha256_ssse3_mod_fini(void)
{
- crypto_unregister_shash(&alg);
+ crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
}
module_init(sha256_ssse3_mod_init);
@@ -273,3 +319,4 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm, Supplemental SSE3 accelerated");
MODULE_ALIAS("sha256");
+MODULE_ALIAS("sha384");
diff --git a/arch/x86/crypto/sha512_ssse3_glue.c b/arch/x86/crypto/sha512_ssse3_glue.c
index 6cbd8df348d2..f30cd10293f0 100644
--- a/arch/x86/crypto/sha512_ssse3_glue.c
+++ b/arch/x86/crypto/sha512_ssse3_glue.c
@@ -194,7 +194,37 @@ static int sha512_ssse3_import(struct shash_desc *desc, const void *in)
return 0;
}
-static struct shash_alg alg = {
+static int sha384_ssse3_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_ssse3_final(struct shash_desc *desc, u8 *hash)
+{
+ u8 D[SHA512_DIGEST_SIZE];
+
+ sha512_ssse3_final(desc, D);
+
+ memcpy(hash, D, SHA384_DIGEST_SIZE);
+ memset(D, 0, SHA512_DIGEST_SIZE);
+
+ return 0;
+}
+
+static struct shash_alg algs[] = { {
.digestsize = SHA512_DIGEST_SIZE,
.init = sha512_ssse3_init,
.update = sha512_ssse3_update,
@@ -211,7 +241,24 @@ static struct shash_alg alg = {
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_module = THIS_MODULE,
}
-};
+}, {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .init = sha384_ssse3_init,
+ .update = sha512_ssse3_update,
+ .final = sha384_ssse3_final,
+ .export = sha512_ssse3_export,
+ .import = sha512_ssse3_import,
+ .descsize = sizeof(struct sha512_state),
+ .statesize = sizeof(struct sha512_state),
+ .base = {
+ .cra_name = "sha384",
+ .cra_driver_name = "sha384-ssse3",
+ .cra_priority = 150,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA384_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+} };
#ifdef CONFIG_AS_AVX
static bool __init avx_usable(void)
@@ -234,7 +281,7 @@ static bool __init avx_usable(void)
static int __init sha512_ssse3_mod_init(void)
{
- /* test for SSE3 first */
+ /* test for SSSE3 first */
if (cpu_has_ssse3)
sha512_transform_asm = sha512_transform_ssse3;
@@ -261,7 +308,7 @@ static int __init sha512_ssse3_mod_init(void)
else
#endif
pr_info("Using SSSE3 optimized SHA-512 implementation\n");
- return crypto_register_shash(&alg);
+ return crypto_register_shashes(algs, ARRAY_SIZE(algs));
}
pr_info("Neither AVX nor SSSE3 is available/usable.\n");
@@ -270,7 +317,7 @@ static int __init sha512_ssse3_mod_init(void)
static void __exit sha512_ssse3_mod_fini(void)
{
- crypto_unregister_shash(&alg);
+ crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
}
module_init(sha512_ssse3_mod_init);
@@ -280,3 +327,4 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SHA512 Secure Hash Algorithm, Supplemental SSE3 accelerated");
MODULE_ALIAS("sha512");
+MODULE_ALIAS("sha384");
diff --git a/arch/x86/crypto/twofish-avx2-asm_64.S b/arch/x86/crypto/twofish-avx2-asm_64.S
deleted file mode 100644
index e1a83b9cd389..000000000000
--- a/arch/x86/crypto/twofish-avx2-asm_64.S
+++ /dev/null
@@ -1,600 +0,0 @@
-/*
- * x86_64/AVX2 assembler optimized version of Twofish
- *
- * Copyright © 2012-2013 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>
-#include "glue_helper-asm-avx2.S"
-
-.file "twofish-avx2-asm_64.S"
-
-.data
-.align 16
-
-.Lvpshufb_mask0:
-.long 0x80808000
-.long 0x80808004
-.long 0x80808008
-.long 0x8080800c
-
-.Lbswap128_mask:
- .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
-.Lxts_gf128mul_and_shl1_mask_0:
- .byte 0x87, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
-.Lxts_gf128mul_and_shl1_mask_1:
- .byte 0x0e, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0
-
-.text
-
-/* structure of crypto context */
-#define s0 0
-#define s1 1024
-#define s2 2048
-#define s3 3072
-#define w 4096
-#define k 4128
-
-/* register macros */
-#define CTX %rdi
-
-#define RS0 CTX
-#define RS1 %r8
-#define RS2 %r9
-#define RS3 %r10
-#define RK %r11
-#define RW %rax
-#define RROUND %r12
-#define RROUNDd %r12d
-
-#define RA0 %ymm8
-#define RB0 %ymm9
-#define RC0 %ymm10
-#define RD0 %ymm11
-#define RA1 %ymm12
-#define RB1 %ymm13
-#define RC1 %ymm14
-#define RD1 %ymm15
-
-/* temp regs */
-#define RX0 %ymm0
-#define RY0 %ymm1
-#define RX1 %ymm2
-#define RY1 %ymm3
-#define RT0 %ymm4
-#define RIDX %ymm5
-
-#define RX0x %xmm0
-#define RY0x %xmm1
-#define RX1x %xmm2
-#define RY1x %xmm3
-#define RT0x %xmm4
-
-/* vpgatherdd mask and '-1' */
-#define RNOT %ymm6
-
-/* byte mask, (-1 >> 24) */
-#define RBYTE %ymm7
-
-/**********************************************************************
- 16-way AVX2 twofish
- **********************************************************************/
-#define init_round_constants() \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpsrld $24, RNOT, RBYTE; \
- leaq k(CTX), RK; \
- leaq w(CTX), RW; \
- leaq s1(CTX), RS1; \
- leaq s2(CTX), RS2; \
- leaq s3(CTX), RS3; \
-
-#define g16(ab, rs0, rs1, rs2, rs3, xy) \
- vpand RBYTE, ab ## 0, RIDX; \
- vpgatherdd RNOT, (rs0, RIDX, 4), xy ## 0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- \
- vpand RBYTE, ab ## 1, RIDX; \
- vpgatherdd RNOT, (rs0, RIDX, 4), xy ## 1; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- \
- vpsrld $8, ab ## 0, RIDX; \
- vpand RBYTE, RIDX, RIDX; \
- vpgatherdd RNOT, (rs1, RIDX, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpxor RT0, xy ## 0, xy ## 0; \
- \
- vpsrld $8, ab ## 1, RIDX; \
- vpand RBYTE, RIDX, RIDX; \
- vpgatherdd RNOT, (rs1, RIDX, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpxor RT0, xy ## 1, xy ## 1; \
- \
- vpsrld $16, ab ## 0, RIDX; \
- vpand RBYTE, RIDX, RIDX; \
- vpgatherdd RNOT, (rs2, RIDX, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpxor RT0, xy ## 0, xy ## 0; \
- \
- vpsrld $16, ab ## 1, RIDX; \
- vpand RBYTE, RIDX, RIDX; \
- vpgatherdd RNOT, (rs2, RIDX, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpxor RT0, xy ## 1, xy ## 1; \
- \
- vpsrld $24, ab ## 0, RIDX; \
- vpgatherdd RNOT, (rs3, RIDX, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpxor RT0, xy ## 0, xy ## 0; \
- \
- vpsrld $24, ab ## 1, RIDX; \
- vpgatherdd RNOT, (rs3, RIDX, 4), RT0; \
- vpcmpeqd RNOT, RNOT, RNOT; \
- vpxor RT0, xy ## 1, xy ## 1;
-
-#define g1_16(a, x) \
- g16(a, RS0, RS1, RS2, RS3, x);
-
-#define g2_16(b, y) \
- g16(b, RS1, RS2, RS3, RS0, y);
-
-#define encrypt_round_end16(a, b, c, d, nk) \
- vpaddd RY0, RX0, RX0; \
- vpaddd RX0, RY0, RY0; \
- vpbroadcastd nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RX0, RX0; \
- vpbroadcastd 4+nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RY0, RY0; \
- \
- vpxor RY0, d ## 0, d ## 0; \
- \
- vpxor RX0, c ## 0, c ## 0; \
- vpsrld $1, c ## 0, RT0; \
- vpslld $31, c ## 0, c ## 0; \
- vpor RT0, c ## 0, c ## 0; \
- \
- vpaddd RY1, RX1, RX1; \
- vpaddd RX1, RY1, RY1; \
- vpbroadcastd nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RX1, RX1; \
- vpbroadcastd 4+nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RY1, RY1; \
- \
- vpxor RY1, d ## 1, d ## 1; \
- \
- vpxor RX1, c ## 1, c ## 1; \
- vpsrld $1, c ## 1, RT0; \
- vpslld $31, c ## 1, c ## 1; \
- vpor RT0, c ## 1, c ## 1; \
-
-#define encrypt_round16(a, b, c, d, nk) \
- g2_16(b, RY); \
- \
- vpslld $1, b ## 0, RT0; \
- vpsrld $31, b ## 0, b ## 0; \
- vpor RT0, b ## 0, b ## 0; \
- \
- vpslld $1, b ## 1, RT0; \
- vpsrld $31, b ## 1, b ## 1; \
- vpor RT0, b ## 1, b ## 1; \
- \
- g1_16(a, RX); \
- \
- encrypt_round_end16(a, b, c, d, nk);
-
-#define encrypt_round_first16(a, b, c, d, nk) \
- vpslld $1, d ## 0, RT0; \
- vpsrld $31, d ## 0, d ## 0; \
- vpor RT0, d ## 0, d ## 0; \
- \
- vpslld $1, d ## 1, RT0; \
- vpsrld $31, d ## 1, d ## 1; \
- vpor RT0, d ## 1, d ## 1; \
- \
- encrypt_round16(a, b, c, d, nk);
-
-#define encrypt_round_last16(a, b, c, d, nk) \
- g2_16(b, RY); \
- \
- g1_16(a, RX); \
- \
- encrypt_round_end16(a, b, c, d, nk);
-
-#define decrypt_round_end16(a, b, c, d, nk) \
- vpaddd RY0, RX0, RX0; \
- vpaddd RX0, RY0, RY0; \
- vpbroadcastd nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RX0, RX0; \
- vpbroadcastd 4+nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RY0, RY0; \
- \
- vpxor RX0, c ## 0, c ## 0; \
- \
- vpxor RY0, d ## 0, d ## 0; \
- vpsrld $1, d ## 0, RT0; \
- vpslld $31, d ## 0, d ## 0; \
- vpor RT0, d ## 0, d ## 0; \
- \
- vpaddd RY1, RX1, RX1; \
- vpaddd RX1, RY1, RY1; \
- vpbroadcastd nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RX1, RX1; \
- vpbroadcastd 4+nk(RK,RROUND,8), RT0; \
- vpaddd RT0, RY1, RY1; \
- \
- vpxor RX1, c ## 1, c ## 1; \
- \
- vpxor RY1, d ## 1, d ## 1; \
- vpsrld $1, d ## 1, RT0; \
- vpslld $31, d ## 1, d ## 1; \
- vpor RT0, d ## 1, d ## 1;
-
-#define decrypt_round16(a, b, c, d, nk) \
- g1_16(a, RX); \
- \
- vpslld $1, a ## 0, RT0; \
- vpsrld $31, a ## 0, a ## 0; \
- vpor RT0, a ## 0, a ## 0; \
- \
- vpslld $1, a ## 1, RT0; \
- vpsrld $31, a ## 1, a ## 1; \
- vpor RT0, a ## 1, a ## 1; \
- \
- g2_16(b, RY); \
- \
- decrypt_round_end16(a, b, c, d, nk);
-
-#define decrypt_round_first16(a, b, c, d, nk) \
- vpslld $1, c ## 0, RT0; \
- vpsrld $31, c ## 0, c ## 0; \
- vpor RT0, c ## 0, c ## 0; \
- \
- vpslld $1, c ## 1, RT0; \
- vpsrld $31, c ## 1, c ## 1; \
- vpor RT0, c ## 1, c ## 1; \
- \
- decrypt_round16(a, b, c, d, nk)
-
-#define decrypt_round_last16(a, b, c, d, nk) \
- g1_16(a, RX); \
- \
- g2_16(b, RY); \
- \
- decrypt_round_end16(a, b, c, d, nk);
-
-#define encrypt_cycle16() \
- encrypt_round16(RA, RB, RC, RD, 0); \
- encrypt_round16(RC, RD, RA, RB, 8);
-
-#define encrypt_cycle_first16() \
- encrypt_round_first16(RA, RB, RC, RD, 0); \
- encrypt_round16(RC, RD, RA, RB, 8);
-
-#define encrypt_cycle_last16() \
- encrypt_round16(RA, RB, RC, RD, 0); \
- encrypt_round_last16(RC, RD, RA, RB, 8);
-
-#define decrypt_cycle16(n) \
- decrypt_round16(RC, RD, RA, RB, 8); \
- decrypt_round16(RA, RB, RC, RD, 0);
-
-#define decrypt_cycle_first16(n) \
- decrypt_round_first16(RC, RD, RA, RB, 8); \
- decrypt_round16(RA, RB, RC, RD, 0);
-
-#define decrypt_cycle_last16(n) \
- decrypt_round16(RC, RD, RA, RB, 8); \
- decrypt_round_last16(RA, RB, RC, RD, 0);
-
-#define transpose_4x4(x0,x1,x2,x3,t1,t2) \
- vpunpckhdq x1, x0, t2; \
- vpunpckldq x1, x0, x0; \
- \
- vpunpckldq x3, x2, t1; \
- vpunpckhdq x3, x2, x2; \
- \
- vpunpckhqdq t1, x0, x1; \
- vpunpcklqdq t1, x0, x0; \
- \
- vpunpckhqdq x2, t2, x3; \
- vpunpcklqdq x2, t2, x2;
-
-#define read_blocks8(offs,a,b,c,d) \
- transpose_4x4(a, b, c, d, RX0, RY0);
-
-#define write_blocks8(offs,a,b,c,d) \
- transpose_4x4(a, b, c, d, RX0, RY0);
-
-#define inpack_enc8(a,b,c,d) \
- vpbroadcastd 4*0(RW), RT0; \
- vpxor RT0, a, a; \
- \
- vpbroadcastd 4*1(RW), RT0; \
- vpxor RT0, b, b; \
- \
- vpbroadcastd 4*2(RW), RT0; \
- vpxor RT0, c, c; \
- \
- vpbroadcastd 4*3(RW), RT0; \
- vpxor RT0, d, d;
-
-#define outunpack_enc8(a,b,c,d) \
- vpbroadcastd 4*4(RW), RX0; \
- vpbroadcastd 4*5(RW), RY0; \
- vpxor RX0, c, RX0; \
- vpxor RY0, d, RY0; \
- \
- vpbroadcastd 4*6(RW), RT0; \
- vpxor RT0, a, c; \
- vpbroadcastd 4*7(RW), RT0; \
- vpxor RT0, b, d; \
- \
- vmovdqa RX0, a; \
- vmovdqa RY0, b;
-
-#define inpack_dec8(a,b,c,d) \
- vpbroadcastd 4*4(RW), RX0; \
- vpbroadcastd 4*5(RW), RY0; \
- vpxor RX0, a, RX0; \
- vpxor RY0, b, RY0; \
- \
- vpbroadcastd 4*6(RW), RT0; \
- vpxor RT0, c, a; \
- vpbroadcastd 4*7(RW), RT0; \
- vpxor RT0, d, b; \
- \
- vmovdqa RX0, c; \
- vmovdqa RY0, d;
-
-#define outunpack_dec8(a,b,c,d) \
- vpbroadcastd 4*0(RW), RT0; \
- vpxor RT0, a, a; \
- \
- vpbroadcastd 4*1(RW), RT0; \
- vpxor RT0, b, b; \
- \
- vpbroadcastd 4*2(RW), RT0; \
- vpxor RT0, c, c; \
- \
- vpbroadcastd 4*3(RW), RT0; \
- vpxor RT0, d, d;
-
-#define read_blocks16(a,b,c,d) \
- read_blocks8(0, a ## 0, b ## 0, c ## 0, d ## 0); \
- read_blocks8(8, a ## 1, b ## 1, c ## 1, d ## 1);
-
-#define write_blocks16(a,b,c,d) \
- write_blocks8(0, a ## 0, b ## 0, c ## 0, d ## 0); \
- write_blocks8(8, a ## 1, b ## 1, c ## 1, d ## 1);
-
-#define xor_blocks16(a,b,c,d) \
- xor_blocks8(0, a ## 0, b ## 0, c ## 0, d ## 0); \
- xor_blocks8(8, a ## 1, b ## 1, c ## 1, d ## 1);
-
-#define inpack_enc16(a,b,c,d) \
- inpack_enc8(a ## 0, b ## 0, c ## 0, d ## 0); \
- inpack_enc8(a ## 1, b ## 1, c ## 1, d ## 1);
-
-#define outunpack_enc16(a,b,c,d) \
- outunpack_enc8(a ## 0, b ## 0, c ## 0, d ## 0); \
- outunpack_enc8(a ## 1, b ## 1, c ## 1, d ## 1);
-
-#define inpack_dec16(a,b,c,d) \
- inpack_dec8(a ## 0, b ## 0, c ## 0, d ## 0); \
- inpack_dec8(a ## 1, b ## 1, c ## 1, d ## 1);
-
-#define outunpack_dec16(a,b,c,d) \
- outunpack_dec8(a ## 0, b ## 0, c ## 0, d ## 0); \
- outunpack_dec8(a ## 1, b ## 1, c ## 1, d ## 1);
-
-.align 8
-__twofish_enc_blk16:
- /* input:
- * %rdi: ctx, CTX
- * RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1: plaintext
- * output:
- * RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1: ciphertext
- */
- init_round_constants();
-
- read_blocks16(RA, RB, RC, RD);
- inpack_enc16(RA, RB, RC, RD);
-
- xorl RROUNDd, RROUNDd;
- encrypt_cycle_first16();
- movl $2, RROUNDd;
-
-.align 4
-.L__enc_loop:
- encrypt_cycle16();
-
- addl $2, RROUNDd;
- cmpl $14, RROUNDd;
- jne .L__enc_loop;
-
- encrypt_cycle_last16();
-
- outunpack_enc16(RA, RB, RC, RD);
- write_blocks16(RA, RB, RC, RD);
-
- ret;
-ENDPROC(__twofish_enc_blk16)
-
-.align 8
-__twofish_dec_blk16:
- /* input:
- * %rdi: ctx, CTX
- * RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1: ciphertext
- * output:
- * RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1: plaintext
- */
- init_round_constants();
-
- read_blocks16(RA, RB, RC, RD);
- inpack_dec16(RA, RB, RC, RD);
-
- movl $14, RROUNDd;
- decrypt_cycle_first16();
- movl $12, RROUNDd;
-
-.align 4
-.L__dec_loop:
- decrypt_cycle16();
-
- addl $-2, RROUNDd;
- jnz .L__dec_loop;
-
- decrypt_cycle_last16();
-
- outunpack_dec16(RA, RB, RC, RD);
- write_blocks16(RA, RB, RC, RD);
-
- ret;
-ENDPROC(__twofish_dec_blk16)
-
-ENTRY(twofish_ecb_enc_16way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- */
-
- vzeroupper;
- pushq %r12;
-
- load_16way(%rdx, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- call __twofish_enc_blk16;
-
- store_16way(%rsi, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- popq %r12;
- vzeroupper;
-
- ret;
-ENDPROC(twofish_ecb_enc_16way)
-
-ENTRY(twofish_ecb_dec_16way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- */
-
- vzeroupper;
- pushq %r12;
-
- load_16way(%rdx, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- call __twofish_dec_blk16;
-
- store_16way(%rsi, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- popq %r12;
- vzeroupper;
-
- ret;
-ENDPROC(twofish_ecb_dec_16way)
-
-ENTRY(twofish_cbc_dec_16way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst
- * %rdx: src
- */
-
- vzeroupper;
- pushq %r12;
-
- load_16way(%rdx, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- call __twofish_dec_blk16;
-
- store_cbc_16way(%rdx, %rsi, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1,
- RX0);
-
- popq %r12;
- vzeroupper;
-
- ret;
-ENDPROC(twofish_cbc_dec_16way)
-
-ENTRY(twofish_ctr_16way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst (16 blocks)
- * %rdx: src (16 blocks)
- * %rcx: iv (little endian, 128bit)
- */
-
- vzeroupper;
- pushq %r12;
-
- load_ctr_16way(%rcx, .Lbswap128_mask, RA0, RB0, RC0, RD0, RA1, RB1, RC1,
- RD1, RX0, RX0x, RX1, RX1x, RY0, RY0x, RY1, RY1x, RNOT,
- RBYTE);
-
- call __twofish_enc_blk16;
-
- store_ctr_16way(%rdx, %rsi, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- popq %r12;
- vzeroupper;
-
- ret;
-ENDPROC(twofish_ctr_16way)
-
-.align 8
-twofish_xts_crypt_16way:
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst (16 blocks)
- * %rdx: src (16 blocks)
- * %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
- * %r8: pointer to __twofish_enc_blk16 or __twofish_dec_blk16
- */
-
- vzeroupper;
- pushq %r12;
-
- load_xts_16way(%rcx, %rdx, %rsi, RA0, RB0, RC0, RD0, RA1, RB1, RC1,
- RD1, RX0, RX0x, RX1, RX1x, RY0, RY0x, RY1, RY1x, RNOT,
- .Lxts_gf128mul_and_shl1_mask_0,
- .Lxts_gf128mul_and_shl1_mask_1);
-
- call *%r8;
-
- store_xts_16way(%rsi, RA0, RB0, RC0, RD0, RA1, RB1, RC1, RD1);
-
- popq %r12;
- vzeroupper;
-
- ret;
-ENDPROC(twofish_xts_crypt_16way)
-
-ENTRY(twofish_xts_enc_16way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst (16 blocks)
- * %rdx: src (16 blocks)
- * %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
- */
- leaq __twofish_enc_blk16, %r8;
- jmp twofish_xts_crypt_16way;
-ENDPROC(twofish_xts_enc_16way)
-
-ENTRY(twofish_xts_dec_16way)
- /* input:
- * %rdi: ctx, CTX
- * %rsi: dst (16 blocks)
- * %rdx: src (16 blocks)
- * %rcx: iv (t ⊕ αⁿ ∈ GF(2¹²⁸))
- */
- leaq __twofish_dec_blk16, %r8;
- jmp twofish_xts_crypt_16way;
-ENDPROC(twofish_xts_dec_16way)
diff --git a/arch/x86/crypto/twofish_avx2_glue.c b/arch/x86/crypto/twofish_avx2_glue.c
deleted file mode 100644
index ce33b5be64ee..000000000000
--- a/arch/x86/crypto/twofish_avx2_glue.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/*
- * Glue Code for x86_64/AVX2 assembler optimized version of Twofish
- *
- * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.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/module.h>
-#include <linux/types.h>
-#include <linux/crypto.h>
-#include <linux/err.h>
-#include <crypto/algapi.h>
-#include <crypto/ctr.h>
-#include <crypto/twofish.h>
-#include <crypto/lrw.h>
-#include <crypto/xts.h>
-#include <asm/xcr.h>
-#include <asm/xsave.h>
-#include <asm/crypto/twofish.h>
-#include <asm/crypto/ablk_helper.h>
-#include <asm/crypto/glue_helper.h>
-#include <crypto/scatterwalk.h>
-
-#define TF_AVX2_PARALLEL_BLOCKS 16
-
-/* 16-way AVX2 parallel cipher functions */
-asmlinkage void twofish_ecb_enc_16way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void twofish_ecb_dec_16way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void twofish_cbc_dec_16way(void *ctx, u128 *dst, const u128 *src);
-
-asmlinkage void twofish_ctr_16way(void *ctx, u128 *dst, const u128 *src,
- le128 *iv);
-
-asmlinkage void twofish_xts_enc_16way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src, le128 *iv);
-asmlinkage void twofish_xts_dec_16way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src, le128 *iv);
-
-static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src)
-{
- __twofish_enc_blk_3way(ctx, dst, src, false);
-}
-
-static const struct common_glue_ctx twofish_enc = {
- .num_funcs = 4,
- .fpu_blocks_limit = 8,
-
- .funcs = { {
- .num_blocks = 16,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_ecb_enc_16way) }
- }, {
- .num_blocks = 8,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_ecb_enc_8way) }
- }, {
- .num_blocks = 3,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk_3way) }
- }, {
- .num_blocks = 1,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_enc_blk) }
- } }
-};
-
-static const struct common_glue_ctx twofish_ctr = {
- .num_funcs = 4,
- .fpu_blocks_limit = 8,
-
- .funcs = { {
- .num_blocks = 16,
- .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_ctr_16way) }
- }, {
- .num_blocks = 8,
- .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_ctr_8way) }
- }, {
- .num_blocks = 3,
- .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_enc_blk_ctr_3way) }
- }, {
- .num_blocks = 1,
- .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(twofish_enc_blk_ctr) }
- } }
-};
-
-static const struct common_glue_ctx twofish_enc_xts = {
- .num_funcs = 3,
- .fpu_blocks_limit = 8,
-
- .funcs = { {
- .num_blocks = 16,
- .fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_enc_16way) }
- }, {
- .num_blocks = 8,
- .fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_enc_8way) }
- }, {
- .num_blocks = 1,
- .fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_enc) }
- } }
-};
-
-static const struct common_glue_ctx twofish_dec = {
- .num_funcs = 4,
- .fpu_blocks_limit = 8,
-
- .funcs = { {
- .num_blocks = 16,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_ecb_dec_16way) }
- }, {
- .num_blocks = 8,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_ecb_dec_8way) }
- }, {
- .num_blocks = 3,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_dec_blk_3way) }
- }, {
- .num_blocks = 1,
- .fn_u = { .ecb = GLUE_FUNC_CAST(twofish_dec_blk) }
- } }
-};
-
-static const struct common_glue_ctx twofish_dec_cbc = {
- .num_funcs = 4,
- .fpu_blocks_limit = 8,
-
- .funcs = { {
- .num_blocks = 16,
- .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_cbc_dec_16way) }
- }, {
- .num_blocks = 8,
- .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_cbc_dec_8way) }
- }, {
- .num_blocks = 3,
- .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_dec_blk_cbc_3way) }
- }, {
- .num_blocks = 1,
- .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(twofish_dec_blk) }
- } }
-};
-
-static const struct common_glue_ctx twofish_dec_xts = {
- .num_funcs = 3,
- .fpu_blocks_limit = 8,
-
- .funcs = { {
- .num_blocks = 16,
- .fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_dec_16way) }
- }, {
- .num_blocks = 8,
- .fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_dec_8way) }
- }, {
- .num_blocks = 1,
- .fn_u = { .xts = GLUE_XTS_FUNC_CAST(twofish_xts_dec) }
- } }
-};
-
-static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&twofish_enc, desc, dst, src, nbytes);
-}
-
-static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ecb_crypt_128bit(&twofish_dec, desc, dst, src, nbytes);
-}
-
-static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(twofish_enc_blk), desc,
- dst, src, nbytes);
-}
-
-static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_cbc_decrypt_128bit(&twofish_dec_cbc, desc, dst, src,
- nbytes);
-}
-
-static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- return glue_ctr_crypt_128bit(&twofish_ctr, desc, dst, src, nbytes);
-}
-
-static inline bool twofish_fpu_begin(bool fpu_enabled, unsigned int nbytes)
-{
- /* since reusing AVX functions, starts using FPU at 8 parallel blocks */
- return glue_fpu_begin(TF_BLOCK_SIZE, 8, NULL, fpu_enabled, nbytes);
-}
-
-static inline void twofish_fpu_end(bool fpu_enabled)
-{
- glue_fpu_end(fpu_enabled);
-}
-
-struct crypt_priv {
- struct twofish_ctx *ctx;
- bool fpu_enabled;
-};
-
-static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = TF_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = twofish_fpu_begin(ctx->fpu_enabled, nbytes);
-
- while (nbytes >= TF_AVX2_PARALLEL_BLOCKS * bsize) {
- twofish_ecb_enc_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * TF_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * TF_AVX2_PARALLEL_BLOCKS;
- }
-
- while (nbytes >= 8 * bsize) {
- twofish_ecb_enc_8way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * 8;
- nbytes -= bsize * 8;
- }
-
- while (nbytes >= 3 * bsize) {
- twofish_enc_blk_3way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * 3;
- nbytes -= bsize * 3;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- twofish_enc_blk(ctx->ctx, srcdst, srcdst);
-}
-
-static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
-{
- const unsigned int bsize = TF_BLOCK_SIZE;
- struct crypt_priv *ctx = priv;
- int i;
-
- ctx->fpu_enabled = twofish_fpu_begin(ctx->fpu_enabled, nbytes);
-
- while (nbytes >= TF_AVX2_PARALLEL_BLOCKS * bsize) {
- twofish_ecb_dec_16way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * TF_AVX2_PARALLEL_BLOCKS;
- nbytes -= bsize * TF_AVX2_PARALLEL_BLOCKS;
- }
-
- while (nbytes >= 8 * bsize) {
- twofish_ecb_dec_8way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * 8;
- nbytes -= bsize * 8;
- }
-
- while (nbytes >= 3 * bsize) {
- twofish_dec_blk_3way(ctx->ctx, srcdst, srcdst);
- srcdst += bsize * 3;
- nbytes -= bsize * 3;
- }
-
- for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
- twofish_dec_blk(ctx->ctx, srcdst, srcdst);
-}
-
-static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[TF_AVX2_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->twofish_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = encrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- twofish_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
- be128 buf[TF_AVX2_PARALLEL_BLOCKS];
- struct crypt_priv crypt_ctx = {
- .ctx = &ctx->twofish_ctx,
- .fpu_enabled = false,
- };
- struct lrw_crypt_req req = {
- .tbuf = buf,
- .tbuflen = sizeof(buf),
-
- .table_ctx = &ctx->lrw_table,
- .crypt_ctx = &crypt_ctx,
- .crypt_fn = decrypt_callback,
- };
- int ret;
-
- desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- ret = lrw_crypt(desc, dst, src, nbytes, &req);
- twofish_fpu_end(crypt_ctx.fpu_enabled);
-
- return ret;
-}
-
-static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&twofish_enc_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(twofish_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
-
- return glue_xts_crypt_128bit(&twofish_dec_xts, desc, dst, src, nbytes,
- XTS_TWEAK_CAST(twofish_enc_blk),
- &ctx->tweak_ctx, &ctx->crypt_ctx);
-}
-
-static struct crypto_alg tf_algs[10] = { {
- .cra_name = "__ecb-twofish-avx2",
- .cra_driver_name = "__driver-ecb-twofish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = twofish_setkey,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-}, {
- .cra_name = "__cbc-twofish-avx2",
- .cra_driver_name = "__driver-cbc-twofish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = twofish_setkey,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-}, {
- .cra_name = "__ctr-twofish-avx2",
- .cra_driver_name = "__driver-ctr-twofish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct twofish_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = twofish_setkey,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-}, {
- .cra_name = "__lrw-twofish-avx2",
- .cra_driver_name = "__driver-lrw-twofish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_lrw_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_exit = lrw_twofish_exit_tfm,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE +
- TF_BLOCK_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE +
- TF_BLOCK_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = lrw_twofish_setkey,
- .encrypt = lrw_encrypt,
- .decrypt = lrw_decrypt,
- },
- },
-}, {
- .cra_name = "__xts-twofish-avx2",
- .cra_driver_name = "__driver-xts-twofish-avx2",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct twofish_xts_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_u = {
- .blkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE * 2,
- .max_keysize = TF_MAX_KEY_SIZE * 2,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = xts_twofish_setkey,
- .encrypt = xts_encrypt,
- .decrypt = xts_decrypt,
- },
- },
-}, {
- .cra_name = "ecb(twofish)",
- .cra_driver_name = "ecb-twofish-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "cbc(twofish)",
- .cra_driver_name = "cbc-twofish-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = __ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "ctr(twofish)",
- .cra_driver_name = "ctr-twofish-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-}, {
- .cra_name = "lrw(twofish)",
- .cra_driver_name = "lrw-twofish-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE +
- TF_BLOCK_SIZE,
- .max_keysize = TF_MAX_KEY_SIZE +
- TF_BLOCK_SIZE,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-}, {
- .cra_name = "xts(twofish)",
- .cra_driver_name = "xts-twofish-avx2",
- .cra_priority = 500,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
- .cra_blocksize = TF_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_helper_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_init = ablk_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = TF_MIN_KEY_SIZE * 2,
- .max_keysize = TF_MAX_KEY_SIZE * 2,
- .ivsize = TF_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-} };
-
-static int __init init(void)
-{
- u64 xcr0;
-
- 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("AVX2 detected but unusable.\n");
- return -ENODEV;
- }
-
- return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs));
-}
-
-static void __exit fini(void)
-{
- crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs));
-}
-
-module_init(init);
-module_exit(fini);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Twofish Cipher Algorithm, AVX2 optimized");
-MODULE_ALIAS("twofish");
-MODULE_ALIAS("twofish-asm");
diff --git a/arch/x86/crypto/twofish_avx_glue.c b/arch/x86/crypto/twofish_avx_glue.c
index 2047a562f6b3..a62ba541884e 100644
--- a/arch/x86/crypto/twofish_avx_glue.c
+++ b/arch/x86/crypto/twofish_avx_glue.c
@@ -50,26 +50,18 @@
/* 8-way parallel cipher functions */
asmlinkage void twofish_ecb_enc_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src);
-EXPORT_SYMBOL_GPL(twofish_ecb_enc_8way);
-
asmlinkage void twofish_ecb_dec_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src);
-EXPORT_SYMBOL_GPL(twofish_ecb_dec_8way);
asmlinkage void twofish_cbc_dec_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src);
-EXPORT_SYMBOL_GPL(twofish_cbc_dec_8way);
-
asmlinkage void twofish_ctr_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src, le128 *iv);
-EXPORT_SYMBOL_GPL(twofish_ctr_8way);
asmlinkage void twofish_xts_enc_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src, le128 *iv);
-EXPORT_SYMBOL_GPL(twofish_xts_enc_8way);
asmlinkage void twofish_xts_dec_8way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src, le128 *iv);
-EXPORT_SYMBOL_GPL(twofish_xts_dec_8way);
static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src)
@@ -77,19 +69,17 @@ static inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
__twofish_enc_blk_3way(ctx, dst, src, false);
}
-void twofish_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void twofish_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv)
{
glue_xts_crypt_128bit_one(ctx, dst, src, iv,
GLUE_FUNC_CAST(twofish_enc_blk));
}
-EXPORT_SYMBOL_GPL(twofish_xts_enc);
-void twofish_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
+static void twofish_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv)
{
glue_xts_crypt_128bit_one(ctx, dst, src, iv,
GLUE_FUNC_CAST(twofish_dec_blk));
}
-EXPORT_SYMBOL_GPL(twofish_xts_dec);
static const struct common_glue_ctx twofish_enc = {
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index 52ff81cce008..bae3aba95b15 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -308,8 +308,6 @@ static int load_aout_binary(struct linux_binprm *bprm)
(current->mm->start_data = N_DATADDR(ex));
current->mm->brk = ex.a_bss +
(current->mm->start_brk = N_BSSADDR(ex));
- current->mm->free_area_cache = TASK_UNMAPPED_BASE;
- current->mm->cached_hole_size = 0;
retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
if (retval < 0) {
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index b31bf97775fc..2dfac58f3b11 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -111,7 +111,7 @@ static inline void acpi_disable_pci(void)
}
/* Low-level suspend routine. */
-extern int acpi_suspend_lowlevel(void);
+extern int (*acpi_suspend_lowlevel)(void);
/* Physical address to resume after wakeup */
#define acpi_wakeup_address ((unsigned long)(real_mode_header->wakeup_start))
diff --git a/arch/x86/include/asm/crypto/blowfish.h b/arch/x86/include/asm/crypto/blowfish.h
deleted file mode 100644
index f097b2face10..000000000000
--- a/arch/x86/include/asm/crypto/blowfish.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef ASM_X86_BLOWFISH_H
-#define ASM_X86_BLOWFISH_H
-
-#include <linux/crypto.h>
-#include <crypto/blowfish.h>
-
-#define BF_PARALLEL_BLOCKS 4
-
-/* regular block cipher functions */
-asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src,
- bool xor);
-asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src);
-
-/* 4-way parallel cipher functions */
-asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src, bool xor);
-asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src);
-
-static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src)
-{
- __blowfish_enc_blk(ctx, dst, src, false);
-}
-
-static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst,
- const u8 *src)
-{
- __blowfish_enc_blk(ctx, dst, src, true);
-}
-
-static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src)
-{
- __blowfish_enc_blk_4way(ctx, dst, src, false);
-}
-
-static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst,
- const u8 *src)
-{
- __blowfish_enc_blk_4way(ctx, dst, src, true);
-}
-
-#endif
diff --git a/arch/x86/include/asm/crypto/twofish.h b/arch/x86/include/asm/crypto/twofish.h
index e655c6029b45..878c51ceebb5 100644
--- a/arch/x86/include/asm/crypto/twofish.h
+++ b/arch/x86/include/asm/crypto/twofish.h
@@ -28,20 +28,6 @@ asmlinkage void __twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
asmlinkage void twofish_dec_blk_3way(struct twofish_ctx *ctx, u8 *dst,
const u8 *src);
-/* 8-way parallel cipher functions */
-asmlinkage void twofish_ecb_enc_8way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void twofish_ecb_dec_8way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void twofish_cbc_dec_8way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src);
-asmlinkage void twofish_ctr_8way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src, le128 *iv);
-asmlinkage void twofish_xts_enc_8way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src, le128 *iv);
-asmlinkage void twofish_xts_dec_8way(struct twofish_ctx *ctx, u8 *dst,
- const u8 *src, le128 *iv);
-
/* helpers from twofish_x86_64-3way module */
extern void twofish_dec_blk_cbc_3way(void *ctx, u128 *dst, const u128 *src);
extern void twofish_enc_blk_ctr(void *ctx, u128 *dst, const u128 *src,
@@ -57,8 +43,4 @@ extern void lrw_twofish_exit_tfm(struct crypto_tfm *tfm);
extern int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen);
-/* helpers from twofish-avx module */
-extern void twofish_xts_enc(void *ctx, u128 *dst, const u128 *src, le128 *iv);
-extern void twofish_xts_dec(void *ctx, u128 *dst, const u128 *src, le128 *iv);
-
#endif /* ASM_X86_TWOFISH_H */
diff --git a/arch/x86/include/asm/emergency-restart.h b/arch/x86/include/asm/emergency-restart.h
index 75ce3f47d204..77a99ac06d00 100644
--- a/arch/x86/include/asm/emergency-restart.h
+++ b/arch/x86/include/asm/emergency-restart.h
@@ -1,18 +1,6 @@
#ifndef _ASM_X86_EMERGENCY_RESTART_H
#define _ASM_X86_EMERGENCY_RESTART_H
-enum reboot_type {
- BOOT_TRIPLE = 't',
- BOOT_KBD = 'k',
- BOOT_BIOS = 'b',
- BOOT_ACPI = 'a',
- BOOT_EFI = 'e',
- BOOT_CF9 = 'p',
- BOOT_CF9_COND = 'q',
-};
-
-extern enum reboot_type reboot_type;
-
extern void machine_emergency_restart(void);
#endif /* _ASM_X86_EMERGENCY_RESTART_H */
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index d8e8eefbe24c..34f69cb9350a 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -345,4 +345,11 @@ 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_add(unsigned long base,
+ unsigned long size);
+extern void arch_phys_wc_del(int handle);
+#define arch_phys_wc_add arch_phys_wc_add
+#endif
+
#endif /* _ASM_X86_IO_H */
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index af9c5525434d..f87f7fcefa0a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -222,14 +222,22 @@ struct kvm_mmu_page {
int root_count; /* Currently serving as active root */
unsigned int unsync_children;
unsigned long parent_ptes; /* Reverse mapping for parent_pte */
+
+ /* The page is obsolete if mmu_valid_gen != kvm->arch.mmu_valid_gen. */
+ unsigned long mmu_valid_gen;
+
DECLARE_BITMAP(unsync_child_bitmap, 512);
#ifdef CONFIG_X86_32
+ /*
+ * Used out of the mmu-lock to avoid reading spte values while an
+ * update is in progress; see the comments in __get_spte_lockless().
+ */
int clear_spte_count;
#endif
+ /* Number of writes since the last time traversal visited this page. */
int write_flooding_count;
- bool mmio_cached;
};
struct kvm_pio_request {
@@ -529,11 +537,14 @@ struct kvm_arch {
unsigned int n_requested_mmu_pages;
unsigned int n_max_mmu_pages;
unsigned int indirect_shadow_pages;
+ unsigned long mmu_valid_gen;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
/*
* Hash table of struct kvm_mmu_page.
*/
struct list_head active_mmu_pages;
+ struct list_head zapped_obsolete_pages;
+
struct list_head assigned_dev_head;
struct iommu_domain *iommu_domain;
int iommu_flags;
@@ -769,7 +780,7 @@ void kvm_mmu_write_protect_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_zap_mmio_sptes(struct kvm *kvm);
+void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm);
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);
diff --git a/arch/x86/include/asm/mc146818rtc.h b/arch/x86/include/asm/mc146818rtc.h
index d354fb781c57..a55c7efcc4ed 100644
--- a/arch/x86/include/asm/mc146818rtc.h
+++ b/arch/x86/include/asm/mc146818rtc.h
@@ -95,8 +95,8 @@ static inline unsigned char current_lock_cmos_reg(void)
unsigned char rtc_cmos_read(unsigned char addr);
void rtc_cmos_write(unsigned char val, unsigned char addr);
-extern int mach_set_rtc_mmss(unsigned long nowtime);
-extern unsigned long mach_get_cmos_time(void);
+extern int mach_set_rtc_mmss(const struct timespec *now);
+extern void mach_get_cmos_time(struct timespec *now);
#define RTC_IRQ 8
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 6b52980c29c1..29e3093bbd21 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -214,6 +214,13 @@ void mce_log_therm_throt_event(__u64 status);
/* Interrupt Handler for core thermal thresholds */
extern int (*platform_thermal_notify)(__u64 msr_val);
+/* Interrupt Handler for package thermal thresholds */
+extern int (*platform_thermal_package_notify)(__u64 msr_val);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+extern bool (*platform_thermal_package_rate_control)(void);
+
#ifdef CONFIG_X86_THERMAL_VECTOR
extern void mcheck_intel_therm_init(void);
#else
diff --git a/arch/x86/include/asm/mrst-vrtc.h b/arch/x86/include/asm/mrst-vrtc.h
index 73668abdbedf..1e69a75412a4 100644
--- a/arch/x86/include/asm/mrst-vrtc.h
+++ b/arch/x86/include/asm/mrst-vrtc.h
@@ -3,7 +3,7 @@
extern unsigned char vrtc_cmos_read(unsigned char reg);
extern void vrtc_cmos_write(unsigned char val, unsigned char reg);
-extern unsigned long vrtc_get_time(void);
-extern int vrtc_set_mmss(unsigned long nowtime);
+extern void vrtc_get_time(struct timespec *now);
+extern int vrtc_set_mmss(const struct timespec *now);
#endif
diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h
index e235582f9930..f768f6298419 100644
--- a/arch/x86/include/asm/mtrr.h
+++ b/arch/x86/include/asm/mtrr.h
@@ -26,7 +26,10 @@
#include <uapi/asm/mtrr.h>
-/* The following functions are for use by other drivers */
+/*
+ * The following functions are for use by other drivers that cannot use
+ * arch_phys_wc_add and arch_phys_wc_del.
+ */
# ifdef CONFIG_MTRR
extern u8 mtrr_type_lookup(u64 addr, u64 end);
extern void mtrr_save_fixed_ranges(void *);
@@ -45,6 +48,7 @@ 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)
{
@@ -80,6 +84,10 @@ 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)
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 5b0818bc8963..7dc305a46058 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -207,7 +207,7 @@ static inline pte_t pte_mkexec(pte_t pte)
static inline pte_t pte_mkdirty(pte_t pte)
{
- return pte_set_flags(pte, _PAGE_DIRTY);
+ return pte_set_flags(pte, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
}
static inline pte_t pte_mkyoung(pte_t pte)
@@ -271,7 +271,7 @@ static inline pmd_t pmd_wrprotect(pmd_t pmd)
static inline pmd_t pmd_mkdirty(pmd_t pmd)
{
- return pmd_set_flags(pmd, _PAGE_DIRTY);
+ return pmd_set_flags(pmd, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
}
static inline pmd_t pmd_mkhuge(pmd_t pmd)
@@ -294,6 +294,26 @@ static inline pmd_t pmd_mknotpresent(pmd_t pmd)
return pmd_clear_flags(pmd, _PAGE_PRESENT);
}
+static inline int pte_soft_dirty(pte_t pte)
+{
+ return pte_flags(pte) & _PAGE_SOFT_DIRTY;
+}
+
+static inline int pmd_soft_dirty(pmd_t pmd)
+{
+ return pmd_flags(pmd) & _PAGE_SOFT_DIRTY;
+}
+
+static inline pte_t pte_mksoft_dirty(pte_t pte)
+{
+ return pte_set_flags(pte, _PAGE_SOFT_DIRTY);
+}
+
+static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
+{
+ return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY);
+}
+
/*
* Mask out unsupported bits in a present pgprot. Non-present pgprots
* can use those bits for other purposes, so leave them be.
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index e6423002c10b..c98ac63aae48 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -55,6 +55,18 @@
#define _PAGE_HIDDEN (_AT(pteval_t, 0))
#endif
+/*
+ * The same hidden bit is used by kmemcheck, but since kmemcheck
+ * works on kernel pages while soft-dirty engine on user space,
+ * they do not conflict with each other.
+ */
+
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define _PAGE_SOFT_DIRTY (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)
+#else
+#define _PAGE_SOFT_DIRTY (_AT(pteval_t, 0))
+#endif
+
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX)
#else
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index a1df6e84691f..27811190cbd7 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -89,7 +89,6 @@ struct thread_info {
#define TIF_FORK 18 /* ret_from_fork */
#define TIF_NOHZ 19 /* in adaptive nohz mode */
#define TIF_MEMDIE 20 /* is terminating due to OOM killer */
-#define TIF_DEBUG 21 /* uses debug registers */
#define TIF_IO_BITMAP 22 /* uses I/O bitmap */
#define TIF_FORCED_TF 24 /* true if TF in eflags artificially */
#define TIF_BLOCKSTEP 25 /* set when we want DEBUGCTLMSR_BTF */
@@ -113,7 +112,6 @@ struct thread_info {
#define _TIF_IA32 (1 << TIF_IA32)
#define _TIF_FORK (1 << TIF_FORK)
#define _TIF_NOHZ (1 << TIF_NOHZ)
-#define _TIF_DEBUG (1 << TIF_DEBUG)
#define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP)
#define _TIF_FORCED_TF (1 << TIF_FORCED_TF)
#define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP)
@@ -154,7 +152,7 @@ struct thread_info {
(_TIF_IO_BITMAP|_TIF_NOTSC|_TIF_BLOCKSTEP)
#define _TIF_WORK_CTXSW_PREV (_TIF_WORK_CTXSW|_TIF_USER_RETURN_NOTIFY)
-#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW|_TIF_DEBUG)
+#define _TIF_WORK_CTXSW_NEXT (_TIF_WORK_CTXSW)
#define PREEMPT_ACTIVE 0x10000000
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index d8d99222b36a..828a1565ba57 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -142,6 +142,8 @@ struct x86_cpuinit_ops {
void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node);
};
+struct timespec;
+
/**
* struct x86_platform_ops - platform specific runtime functions
* @calibrate_tsc: calibrate TSC
@@ -156,8 +158,8 @@ struct x86_cpuinit_ops {
*/
struct x86_platform_ops {
unsigned long (*calibrate_tsc)(void);
- unsigned long (*get_wallclock)(void);
- int (*set_wallclock)(unsigned long nowtime);
+ void (*get_wallclock)(struct timespec *ts);
+ int (*set_wallclock)(const struct timespec *ts);
void (*iommu_shutdown)(void);
bool (*is_untracked_pat_range)(u64 start, u64 end);
void (*nmi_init)(void);
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 230c8ea878e5..d81a972dd506 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -44,6 +44,7 @@
#include <asm/mpspec.h>
#include <asm/smp.h>
+#include "sleep.h" /* To include x86_acpi_suspend_lowlevel */
static int __initdata acpi_force = 0;
u32 acpi_rsdt_forced;
int acpi_disabled;
@@ -559,6 +560,12 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
int trigger, int polarity) = acpi_register_gsi_pic;
+#ifdef CONFIG_ACPI_SLEEP
+int (*acpi_suspend_lowlevel)(void) = x86_acpi_suspend_lowlevel;
+#else
+int (*acpi_suspend_lowlevel)(void);
+#endif
+
/*
* success: return IRQ number (>=0)
* failure: return < 0
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index b44577bc9744..2a34aaf3c8f1 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -26,12 +26,12 @@ static char temp_stack[4096];
#endif
/**
- * acpi_suspend_lowlevel - save kernel state
+ * x86_acpi_suspend_lowlevel - save kernel state
*
* Create an identity mapped page table and copy the wakeup routine to
* low memory.
*/
-int acpi_suspend_lowlevel(void)
+int x86_acpi_suspend_lowlevel(void)
{
struct wakeup_header *header =
(struct wakeup_header *) __va(real_mode_header->wakeup_header);
diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h
index 67f59f8c6956..c9c2c982d5e4 100644
--- a/arch/x86/kernel/acpi/sleep.h
+++ b/arch/x86/kernel/acpi/sleep.h
@@ -15,3 +15,5 @@ extern unsigned long acpi_copy_wakeup_routine(unsigned long);
extern void wakeup_long64(void);
extern void do_suspend_lowlevel(void);
+
+extern int x86_acpi_suspend_lowlevel(void);
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 39cc7f7acab3..63092afb142e 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -25,6 +25,7 @@
#include <linux/kdebug.h>
#include <linux/delay.h>
#include <linux/crash_dump.h>
+#include <linux/reboot.h>
#include <asm/uv/uv_mmrs.h>
#include <asm/uv/uv_hub.h>
@@ -36,7 +37,6 @@
#include <asm/ipi.h>
#include <asm/smp.h>
#include <asm/x86_init.h>
-#include <asm/emergency-restart.h>
#include <asm/nmi.h>
/* BMC sets a bit this MMR non-zero before sending an NMI */
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 5013a48d1aff..c587a8757227 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -90,7 +90,7 @@ static void __cpuinit init_amd_k5(struct cpuinfo_x86 *c)
static void __cpuinit init_amd_k6(struct cpuinfo_x86 *c)
{
u32 l, h;
- int mbytes = num_physpages >> (20-PAGE_SHIFT);
+ int mbytes = get_num_physpages() >> (20-PAGE_SHIFT);
if (c->x86_model < 6) {
/* Based on AMD doc 20734R - June 2000 */
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index 2f3a7995e56a..41e8e00a6637 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -55,12 +55,24 @@ struct thermal_state {
struct _thermal_state package_power_limit;
struct _thermal_state core_thresh0;
struct _thermal_state core_thresh1;
+ struct _thermal_state pkg_thresh0;
+ struct _thermal_state pkg_thresh1;
};
/* Callback to handle core threshold interrupts */
int (*platform_thermal_notify)(__u64 msr_val);
EXPORT_SYMBOL(platform_thermal_notify);
+/* Callback to handle core package threshold_interrupts */
+int (*platform_thermal_package_notify)(__u64 msr_val);
+EXPORT_SYMBOL_GPL(platform_thermal_package_notify);
+
+/* Callback support of rate control, return true, if
+ * callback has rate control */
+bool (*platform_thermal_package_rate_control)(void);
+EXPORT_SYMBOL_GPL(platform_thermal_package_rate_control);
+
+
static DEFINE_PER_CPU(struct thermal_state, thermal_state);
static atomic_t therm_throt_en = ATOMIC_INIT(0);
@@ -182,11 +194,6 @@ static int therm_throt_process(bool new_event, int event, int level)
this_cpu,
level == CORE_LEVEL ? "Core" : "Package",
state->count);
- else
- printk(KERN_CRIT "CPU%d: %s power limit notification (total events = %lu)\n",
- this_cpu,
- level == CORE_LEVEL ? "Core" : "Package",
- state->count);
return 1;
}
if (old_event) {
@@ -194,31 +201,42 @@ static int therm_throt_process(bool new_event, int event, int level)
printk(KERN_INFO "CPU%d: %s temperature/speed normal\n",
this_cpu,
level == CORE_LEVEL ? "Core" : "Package");
- else
- printk(KERN_INFO "CPU%d: %s power limit normal\n",
- this_cpu,
- level == CORE_LEVEL ? "Core" : "Package");
return 1;
}
return 0;
}
-static int thresh_event_valid(int event)
+static int thresh_event_valid(int level, int event)
{
struct _thermal_state *state;
unsigned int this_cpu = smp_processor_id();
struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);
u64 now = get_jiffies_64();
- state = (event == 0) ? &pstate->core_thresh0 : &pstate->core_thresh1;
+ if (level == PACKAGE_LEVEL)
+ state = (event == 0) ? &pstate->pkg_thresh0 :
+ &pstate->pkg_thresh1;
+ else
+ state = (event == 0) ? &pstate->core_thresh0 :
+ &pstate->core_thresh1;
if (time_before64(now, state->next_check))
return 0;
state->next_check = now + CHECK_INTERVAL;
+
+ return 1;
+}
+
+static bool int_pln_enable;
+static int __init int_pln_enable_setup(char *s)
+{
+ int_pln_enable = true;
+
return 1;
}
+__setup("int_pln_enable", int_pln_enable_setup);
#ifdef CONFIG_SYSFS
/* Add/Remove thermal_throttle interface for CPU device: */
@@ -232,7 +250,7 @@ static __cpuinit int thermal_throttle_add_dev(struct device *dev,
if (err)
return err;
- if (cpu_has(c, X86_FEATURE_PLN))
+ if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
err = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_core_power_limit_count.attr,
thermal_attr_group.name);
@@ -240,7 +258,7 @@ static __cpuinit int thermal_throttle_add_dev(struct device *dev,
err = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_package_throttle_count.attr,
thermal_attr_group.name);
- if (cpu_has(c, X86_FEATURE_PLN))
+ if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
err = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_package_power_limit_count.attr,
thermal_attr_group.name);
@@ -322,6 +340,39 @@ device_initcall(thermal_throttle_init_device);
#endif /* CONFIG_SYSFS */
+static void notify_package_thresholds(__u64 msr_val)
+{
+ bool notify_thres_0 = false;
+ bool notify_thres_1 = false;
+
+ if (!platform_thermal_package_notify)
+ return;
+
+ /* lower threshold check */
+ if (msr_val & THERM_LOG_THRESHOLD0)
+ notify_thres_0 = true;
+ /* higher threshold check */
+ if (msr_val & THERM_LOG_THRESHOLD1)
+ notify_thres_1 = true;
+
+ if (!notify_thres_0 && !notify_thres_1)
+ return;
+
+ if (platform_thermal_package_rate_control &&
+ platform_thermal_package_rate_control()) {
+ /* Rate control is implemented in callback */
+ platform_thermal_package_notify(msr_val);
+ return;
+ }
+
+ /* lower threshold reached */
+ if (notify_thres_0 && thresh_event_valid(PACKAGE_LEVEL, 0))
+ platform_thermal_package_notify(msr_val);
+ /* higher threshold reached */
+ if (notify_thres_1 && thresh_event_valid(PACKAGE_LEVEL, 1))
+ platform_thermal_package_notify(msr_val);
+}
+
static void notify_thresholds(__u64 msr_val)
{
/* check whether the interrupt handler is defined;
@@ -331,10 +382,12 @@ static void notify_thresholds(__u64 msr_val)
return;
/* lower threshold reached */
- if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0))
+ if ((msr_val & THERM_LOG_THRESHOLD0) &&
+ thresh_event_valid(CORE_LEVEL, 0))
platform_thermal_notify(msr_val);
/* higher threshold reached */
- if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1))
+ if ((msr_val & THERM_LOG_THRESHOLD1) &&
+ thresh_event_valid(CORE_LEVEL, 1))
platform_thermal_notify(msr_val);
}
@@ -353,17 +406,19 @@ static void intel_thermal_interrupt(void)
CORE_LEVEL) != 0)
mce_log_therm_throt_event(msr_val);
- if (this_cpu_has(X86_FEATURE_PLN))
+ if (this_cpu_has(X86_FEATURE_PLN) && int_pln_enable)
therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
POWER_LIMIT_EVENT,
CORE_LEVEL);
if (this_cpu_has(X86_FEATURE_PTS)) {
rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
+ /* check violations of package thermal thresholds */
+ notify_package_thresholds(msr_val);
therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
THERMAL_THROTTLING_EVENT,
PACKAGE_LEVEL);
- if (this_cpu_has(X86_FEATURE_PLN))
+ if (this_cpu_has(X86_FEATURE_PLN) && int_pln_enable)
therm_throt_process(msr_val &
PACKAGE_THERM_STATUS_POWER_LIMIT,
POWER_LIMIT_EVENT,
@@ -482,9 +537,13 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
apic_write(APIC_LVTTHMR, h);
rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
- if (cpu_has(c, X86_FEATURE_PLN))
+ if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)
+ wrmsr(MSR_IA32_THERM_INTERRUPT,
+ (l | (THERM_INT_LOW_ENABLE
+ | THERM_INT_HIGH_ENABLE)) & ~THERM_INT_PLN_ENABLE, h);
+ else if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
wrmsr(MSR_IA32_THERM_INTERRUPT,
- l | (THERM_INT_LOW_ENABLE
+ l | (THERM_INT_LOW_ENABLE
| THERM_INT_HIGH_ENABLE | THERM_INT_PLN_ENABLE), h);
else
wrmsr(MSR_IA32_THERM_INTERRUPT,
@@ -492,9 +551,14 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
if (cpu_has(c, X86_FEATURE_PTS)) {
rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
- if (cpu_has(c, X86_FEATURE_PLN))
+ if (cpu_has(c, X86_FEATURE_PLN) && !int_pln_enable)
wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
- l | (PACKAGE_THERM_INT_LOW_ENABLE
+ (l | (PACKAGE_THERM_INT_LOW_ENABLE
+ | PACKAGE_THERM_INT_HIGH_ENABLE))
+ & ~PACKAGE_THERM_INT_PLN_ENABLE, h);
+ else if (cpu_has(c, X86_FEATURE_PLN) && int_pln_enable)
+ wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
+ l | (PACKAGE_THERM_INT_LOW_ENABLE
| PACKAGE_THERM_INT_HIGH_ENABLE
| PACKAGE_THERM_INT_PLN_ENABLE), h);
else
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index ca22b73aaa25..f961de9964c7 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -51,9 +51,13 @@
#include <asm/e820.h>
#include <asm/mtrr.h>
#include <asm/msr.h>
+#include <asm/pat.h>
#include "mtrr.h"
+/* arch_phys_wc_add returns an MTRR register index plus this offset. */
+#define MTRR_TO_PHYS_WC_OFFSET 1000
+
u32 num_var_ranges;
unsigned int mtrr_usage_table[MTRR_MAX_VAR_RANGES];
@@ -525,6 +529,73 @@ int mtrr_del(int reg, unsigned long base, unsigned long size)
}
EXPORT_SYMBOL(mtrr_del);
+/**
+ * arch_phys_wc_add - add a WC MTRR and handle errors if PAT is unavailable
+ * @base: Physical base address
+ * @size: Size of region
+ *
+ * If PAT is available, this does nothing. If PAT is unavailable, it
+ * attempts to add a WC MTRR covering size bytes starting at base and
+ * logs an error if this fails.
+ *
+ * Drivers must store the return value to pass to mtrr_del_wc_if_needed,
+ * but drivers should not try to interpret that return value.
+ */
+int arch_phys_wc_add(unsigned long base, unsigned long size)
+{
+ int ret;
+
+ if (pat_enabled)
+ return 0; /* Success! (We don't need to do anything.) */
+
+ ret = mtrr_add(base, size, MTRR_TYPE_WRCOMB, true);
+ if (ret < 0) {
+ pr_warn("Failed to add WC MTRR for [%p-%p]; performance may suffer.",
+ (void *)base, (void *)(base + size - 1));
+ return ret;
+ }
+ return ret + MTRR_TO_PHYS_WC_OFFSET;
+}
+EXPORT_SYMBOL(arch_phys_wc_add);
+
+/*
+ * arch_phys_wc_del - undoes arch_phys_wc_add
+ * @handle: Return value from arch_phys_wc_add
+ *
+ * This cleans up after mtrr_add_wc_if_needed.
+ *
+ * The API guarantees that mtrr_del_wc_if_needed(error code) and
+ * mtrr_del_wc_if_needed(0) do nothing.
+ */
+void arch_phys_wc_del(int handle)
+{
+ if (handle >= 1) {
+ WARN_ON(handle < MTRR_TO_PHYS_WC_OFFSET);
+ mtrr_del(handle - MTRR_TO_PHYS_WC_OFFSET, 0, 0);
+ }
+}
+EXPORT_SYMBOL(arch_phys_wc_del);
+
+/*
+ * phys_wc_to_mtrr_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
+ * index suitable for debugging.
+ *
+ * Note: There is no legitimate use for this function, except possibly
+ * in printk line. Alas there is an illegitimate use in some ancient
+ * drm ioctls.
+ */
+int phys_wc_to_mtrr_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);
+
/*
* HACK ALERT!
* These should be called implicitly, but we can't yet until all the initcall
diff --git a/arch/x86/kernel/cpu/perf_event_amd_iommu.c b/arch/x86/kernel/cpu/perf_event_amd_iommu.c
index 0db655ef3918..639d1289b1ba 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_iommu.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_iommu.c
@@ -491,10 +491,8 @@ static struct perf_amd_iommu __perf_iommu = {
static __init int amd_iommu_pc_init(void)
{
/* Make sure the IOMMU PC resource is available */
- if (!amd_iommu_pc_supported()) {
- pr_err("perf: amd_iommu PMU not installed. No support!\n");
+ if (!amd_iommu_pc_supported())
return -ENODEV;
- }
_init_perf_amd_iommu(&__perf_iommu, "amd_iommu");
diff --git a/arch/x86/kernel/cpu/powerflags.c b/arch/x86/kernel/cpu/powerflags.c
index 7b3fe56b1c21..31f0f335ed22 100644
--- a/arch/x86/kernel/cpu/powerflags.c
+++ b/arch/x86/kernel/cpu/powerflags.c
@@ -11,10 +11,10 @@ const char *const x86_power_flags[32] = {
"fid", /* frequency id control */
"vid", /* voltage id control */
"ttp", /* thermal trip */
- "tm",
- "stc",
- "100mhzsteps",
- "hwpstate",
+ "tm", /* hardware thermal control */
+ "stc", /* software thermal control */
+ "100mhzsteps", /* 100 MHz multiplier control */
+ "hwpstate", /* hardware P-state control */
"", /* tsc invariant mapped to constant_tsc */
"cpb", /* core performance boost */
"eff_freq_ro", /* Readonly aperf/mperf */
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index b1581527a236..4934890e4db2 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -364,9 +364,7 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num,
* and assigned so we can keep the 1:1 mapping which the ioapic
* is having.
*/
- ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
- if (ret)
- pr_err("Error mapping legacy IRQs: %d\n", ret);
+ irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
if (num > NR_IRQS_LEGACY) {
ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index 02f07634d265..f66ff162dce8 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -393,6 +393,9 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
unregister_hw_breakpoint(t->ptrace_bps[i]);
t->ptrace_bps[i] = NULL;
}
+
+ t->debugreg6 = 0;
+ t->ptrace_dr7 = 0;
}
void hw_breakpoint_restore(void)
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 3dd37ebd591b..1f354f4b602b 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -48,10 +48,9 @@ static struct pvclock_wall_clock wall_clock;
* have elapsed since the hypervisor wrote the data. So we try to account for
* that with system time
*/
-static unsigned long kvm_get_wallclock(void)
+static void kvm_get_wallclock(struct timespec *now)
{
struct pvclock_vcpu_time_info *vcpu_time;
- struct timespec ts;
int low, high;
int cpu;
@@ -64,14 +63,12 @@ static unsigned long kvm_get_wallclock(void)
cpu = smp_processor_id();
vcpu_time = &hv_clock[cpu].pvti;
- pvclock_read_wallclock(&wall_clock, vcpu_time, &ts);
+ pvclock_read_wallclock(&wall_clock, vcpu_time, now);
preempt_enable();
-
- return ts.tv_sec;
}
-static int kvm_set_wallclock(unsigned long now)
+static int kvm_set_wallclock(const struct timespec *now)
{
return -1;
}
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 29a8120e6fe8..7461f50d5bb1 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -601,30 +601,48 @@ static unsigned long ptrace_get_dr7(struct perf_event *bp[])
return dr7;
}
-static int
-ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
- struct task_struct *tsk, int disabled)
+static int ptrace_fill_bp_fields(struct perf_event_attr *attr,
+ int len, int type, bool disabled)
+{
+ int err, bp_len, bp_type;
+
+ err = arch_bp_generic_fields(len, type, &bp_len, &bp_type);
+ if (!err) {
+ attr->bp_len = bp_len;
+ attr->bp_type = bp_type;
+ attr->disabled = disabled;
+ }
+
+ return err;
+}
+
+static struct perf_event *
+ptrace_register_breakpoint(struct task_struct *tsk, int len, int type,
+ unsigned long addr, bool disabled)
{
- int err;
- int gen_len, gen_type;
struct perf_event_attr attr;
+ int err;
- /*
- * We should have at least an inactive breakpoint at this
- * slot. It means the user is writing dr7 without having
- * written the address register first
- */
- if (!bp)
- return -EINVAL;
+ ptrace_breakpoint_init(&attr);
+ attr.bp_addr = addr;
- err = arch_bp_generic_fields(len, type, &gen_len, &gen_type);
+ err = ptrace_fill_bp_fields(&attr, len, type, disabled);
if (err)
- return err;
+ return ERR_PTR(err);
+
+ return register_user_hw_breakpoint(&attr, ptrace_triggered,
+ NULL, tsk);
+}
- attr = bp->attr;
- attr.bp_len = gen_len;
- attr.bp_type = gen_type;
- attr.disabled = disabled;
+static int ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
+ int disabled)
+{
+ struct perf_event_attr attr = bp->attr;
+ int err;
+
+ err = ptrace_fill_bp_fields(&attr, len, type, disabled);
+ if (err)
+ return err;
return modify_user_hw_breakpoint(bp, &attr);
}
@@ -634,67 +652,50 @@ ptrace_modify_breakpoint(struct perf_event *bp, int len, int type,
*/
static int ptrace_write_dr7(struct task_struct *tsk, unsigned long data)
{
- struct thread_struct *thread = &(tsk->thread);
+ struct thread_struct *thread = &tsk->thread;
unsigned long old_dr7;
- int i, orig_ret = 0, rc = 0;
- int enabled, second_pass = 0;
- unsigned len, type;
- struct perf_event *bp;
-
- if (ptrace_get_breakpoints(tsk) < 0)
- return -ESRCH;
+ bool second_pass = false;
+ int i, rc, ret = 0;
data &= ~DR_CONTROL_RESERVED;
old_dr7 = ptrace_get_dr7(thread->ptrace_bps);
+
restore:
- /*
- * Loop through all the hardware breakpoints, making the
- * appropriate changes to each.
- */
+ rc = 0;
for (i = 0; i < HBP_NUM; i++) {
- enabled = decode_dr7(data, i, &len, &type);
- bp = thread->ptrace_bps[i];
-
- if (!enabled) {
- if (bp) {
- /*
- * Don't unregister the breakpoints right-away,
- * unless all register_user_hw_breakpoint()
- * requests have succeeded. This prevents
- * any window of opportunity for debug
- * register grabbing by other users.
- */
- if (!second_pass)
- continue;
-
- rc = ptrace_modify_breakpoint(bp, len, type,
- tsk, 1);
- if (rc)
- break;
+ unsigned len, type;
+ bool disabled = !decode_dr7(data, i, &len, &type);
+ struct perf_event *bp = thread->ptrace_bps[i];
+
+ if (!bp) {
+ if (disabled)
+ continue;
+
+ bp = ptrace_register_breakpoint(tsk,
+ len, type, 0, disabled);
+ if (IS_ERR(bp)) {
+ rc = PTR_ERR(bp);
+ break;
}
+
+ thread->ptrace_bps[i] = bp;
continue;
}
- rc = ptrace_modify_breakpoint(bp, len, type, tsk, 0);
+ rc = ptrace_modify_breakpoint(bp, len, type, disabled);
if (rc)
break;
}
- /*
- * Make a second pass to free the remaining unused breakpoints
- * or to restore the original breakpoints if an error occurred.
- */
- if (!second_pass) {
- second_pass = 1;
- if (rc < 0) {
- orig_ret = rc;
- data = old_dr7;
- }
+
+ /* Restore if the first pass failed, second_pass shouldn't fail. */
+ if (rc && !WARN_ON(second_pass)) {
+ ret = rc;
+ data = old_dr7;
+ second_pass = true;
goto restore;
}
- ptrace_put_breakpoints(tsk);
-
- return ((orig_ret < 0) ? orig_ret : rc);
+ return ret;
}
/*
@@ -702,25 +703,17 @@ restore:
*/
static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
{
- struct thread_struct *thread = &(tsk->thread);
+ struct thread_struct *thread = &tsk->thread;
unsigned long val = 0;
if (n < HBP_NUM) {
- struct perf_event *bp;
+ struct perf_event *bp = thread->ptrace_bps[n];
- if (ptrace_get_breakpoints(tsk) < 0)
- return -ESRCH;
-
- bp = thread->ptrace_bps[n];
- if (!bp)
- val = 0;
- else
+ if (bp)
val = bp->hw.info.address;
-
- ptrace_put_breakpoints(tsk);
} else if (n == 6) {
val = thread->debugreg6;
- } else if (n == 7) {
+ } else if (n == 7) {
val = thread->ptrace_dr7;
}
return val;
@@ -729,29 +722,14 @@ static unsigned long ptrace_get_debugreg(struct task_struct *tsk, int n)
static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
unsigned long addr)
{
- struct perf_event *bp;
struct thread_struct *t = &tsk->thread;
- struct perf_event_attr attr;
+ struct perf_event *bp = t->ptrace_bps[nr];
int err = 0;
- if (ptrace_get_breakpoints(tsk) < 0)
- return -ESRCH;
-
- if (!t->ptrace_bps[nr]) {
- ptrace_breakpoint_init(&attr);
- /*
- * Put stub len and type to register (reserve) an inactive but
- * correct bp
- */
- attr.bp_addr = addr;
- attr.bp_len = HW_BREAKPOINT_LEN_1;
- attr.bp_type = HW_BREAKPOINT_W;
- attr.disabled = 1;
-
- bp = register_user_hw_breakpoint(&attr, ptrace_triggered,
- NULL, tsk);
-
+ if (!bp) {
/*
+ * Put stub len and type to create an inactive but correct bp.
+ *
* CHECKME: the previous code returned -EIO if the addr wasn't
* a valid task virtual addr. The new one will return -EINVAL in
* this case.
@@ -760,22 +738,20 @@ static int ptrace_set_breakpoint_addr(struct task_struct *tsk, int nr,
* writing for the user. And anyway this is the previous
* behaviour.
*/
- if (IS_ERR(bp)) {
+ bp = ptrace_register_breakpoint(tsk,
+ X86_BREAKPOINT_LEN_1, X86_BREAKPOINT_WRITE,
+ addr, true);
+ if (IS_ERR(bp))
err = PTR_ERR(bp);
- goto put;
- }
-
- t->ptrace_bps[nr] = bp;
+ else
+ t->ptrace_bps[nr] = bp;
} else {
- bp = t->ptrace_bps[nr];
+ struct perf_event_attr attr = bp->attr;
- attr = bp->attr;
attr.bp_addr = addr;
err = modify_user_hw_breakpoint(bp, &attr);
}
-put:
- ptrace_put_breakpoints(tsk);
return err;
}
@@ -785,30 +761,20 @@ put:
static int ptrace_set_debugreg(struct task_struct *tsk, int n,
unsigned long val)
{
- struct thread_struct *thread = &(tsk->thread);
- int rc = 0;
-
+ struct thread_struct *thread = &tsk->thread;
/* There are no DR4 or DR5 registers */
- if (n == 4 || n == 5)
- return -EIO;
+ int rc = -EIO;
- if (n == 6) {
- thread->debugreg6 = val;
- goto ret_path;
- }
if (n < HBP_NUM) {
rc = ptrace_set_breakpoint_addr(tsk, n, val);
- if (rc)
- return rc;
- }
- /* All that's left is DR7 */
- if (n == 7) {
+ } else if (n == 6) {
+ thread->debugreg6 = val;
+ rc = 0;
+ } else if (n == 7) {
rc = ptrace_write_dr7(tsk, val);
if (!rc)
thread->ptrace_dr7 = val;
}
-
-ret_path:
return rc;
}
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 76fa1e9a2b39..563ed91e6faa 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -36,22 +36,6 @@ void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
static const struct desc_ptr no_idt = {};
-static int reboot_mode;
-enum reboot_type reboot_type = BOOT_ACPI;
-int reboot_force;
-
-/*
- * This variable is used privately to keep track of whether or not
- * reboot_type is still set to its default value (i.e., reboot= hasn't
- * been set on the command line). This is needed so that we can
- * suppress DMI scanning for reboot quirks. Without it, it's
- * impossible to override a faulty reboot quirk without recompiling.
- */
-static int reboot_default = 1;
-
-#ifdef CONFIG_SMP
-static int reboot_cpu = -1;
-#endif
/*
* This is set if we need to go through the 'emergency' path.
@@ -64,79 +48,6 @@ static int reboot_emergency;
bool port_cf9_safe = false;
/*
- * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
- * warm Don't set the cold reboot flag
- * cold Set the cold reboot flag
- * bios Reboot by jumping through the BIOS
- * smp Reboot by executing reset on BSP or other CPU
- * triple Force a triple fault (init)
- * kbd Use the keyboard controller. cold reset (default)
- * acpi Use the RESET_REG in the FADT
- * efi Use efi reset_system runtime service
- * pci Use the so-called "PCI reset register", CF9
- * force Avoid anything that could hang.
- */
-static int __init reboot_setup(char *str)
-{
- for (;;) {
- /*
- * Having anything passed on the command line via
- * reboot= will cause us to disable DMI checking
- * below.
- */
- reboot_default = 0;
-
- switch (*str) {
- case 'w':
- reboot_mode = 0x1234;
- break;
-
- case 'c':
- reboot_mode = 0;
- break;
-
-#ifdef CONFIG_SMP
- case 's':
- if (isdigit(*(str+1))) {
- reboot_cpu = (int) (*(str+1) - '0');
- if (isdigit(*(str+2)))
- reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
- }
- /*
- * We will leave sorting out the final value
- * when we are ready to reboot, since we might not
- * have detected BSP APIC ID or smp_num_cpu
- */
- break;
-#endif /* CONFIG_SMP */
-
- case 'b':
- case 'a':
- case 'k':
- case 't':
- case 'e':
- case 'p':
- reboot_type = *str;
- break;
-
- case 'f':
- reboot_force = 1;
- break;
- }
-
- str = strchr(str, ',');
- if (str)
- str++;
- else
- break;
- }
- return 1;
-}
-
-__setup("reboot=", reboot_setup);
-
-
-/*
* Reboot options and system auto-detection code provided by
* Dell Inc. so their systems "just work". :-)
*/
@@ -536,6 +447,7 @@ static void native_machine_emergency_restart(void)
int i;
int attempt = 0;
int orig_reboot_type = reboot_type;
+ unsigned short mode;
if (reboot_emergency)
emergency_vmx_disable_all();
@@ -543,7 +455,8 @@ static void native_machine_emergency_restart(void)
tboot_shutdown(TB_SHUTDOWN_REBOOT);
/* Tell the BIOS if we want cold or warm reboot */
- *((unsigned short *)__va(0x472)) = reboot_mode;
+ mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0;
+ *((unsigned short *)__va(0x472)) = mode;
for (;;) {
/* Could also try the reset bit in the Hammer NB */
@@ -585,7 +498,7 @@ static void native_machine_emergency_restart(void)
case BOOT_EFI:
if (efi_enabled(EFI_RUNTIME_SERVICES))
- efi.reset_system(reboot_mode ?
+ efi.reset_system(reboot_mode == REBOOT_WARM ?
EFI_RESET_WARM :
EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL);
@@ -614,26 +527,10 @@ void native_machine_shutdown(void)
{
/* Stop the cpus and apics */
#ifdef CONFIG_SMP
-
- /* The boot cpu is always logical cpu 0 */
- int reboot_cpu_id = 0;
-
- /* See if there has been given a command line override */
- if ((reboot_cpu != -1) && (reboot_cpu < nr_cpu_ids) &&
- cpu_online(reboot_cpu))
- reboot_cpu_id = reboot_cpu;
-
- /* Make certain the cpu I'm about to reboot on is online */
- if (!cpu_online(reboot_cpu_id))
- reboot_cpu_id = smp_processor_id();
-
- /* Make certain I only run on the appropriate processor */
- set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
-
/*
- * O.K Now that I'm on the appropriate processor, stop all of the
- * others. Also disable the local irq to not receive the per-cpu
- * timer interrupt which may trigger scheduler's load balance.
+ * Stop all of the others. Also disable the local irq to
+ * not receive the per-cpu timer interrupt which may trigger
+ * scheduler's load balance.
*/
local_irq_disable();
stop_other_cpus();
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 198eb201ed3b..0aa29394ed6f 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -38,8 +38,9 @@ EXPORT_SYMBOL(rtc_lock);
* jump to the next second precisely 500 ms later. Check the Motorola
* MC146818A or Dallas DS12887 data sheet for details.
*/
-int mach_set_rtc_mmss(unsigned long nowtime)
+int mach_set_rtc_mmss(const struct timespec *now)
{
+ unsigned long nowtime = now->tv_sec;
struct rtc_time tm;
int retval = 0;
@@ -58,7 +59,7 @@ int mach_set_rtc_mmss(unsigned long nowtime)
return retval;
}
-unsigned long mach_get_cmos_time(void)
+void mach_get_cmos_time(struct timespec *now)
{
unsigned int status, year, mon, day, hour, min, sec, century = 0;
unsigned long flags;
@@ -107,7 +108,8 @@ unsigned long mach_get_cmos_time(void)
} else
year += CMOS_YEARS_OFFS;
- return mktime(year, mon, day, hour, min, sec);
+ now->tv_sec = mktime(year, mon, day, hour, min, sec);
+ now->tv_nsec = 0;
}
/* Routines for accessing the CMOS RAM/RTC. */
@@ -135,18 +137,13 @@ EXPORT_SYMBOL(rtc_cmos_write);
int update_persistent_clock(struct timespec now)
{
- return x86_platform.set_wallclock(now.tv_sec);
+ return x86_platform.set_wallclock(&now);
}
/* not static: needed by APM */
void read_persistent_clock(struct timespec *ts)
{
- unsigned long retval;
-
- retval = x86_platform.get_wallclock();
-
- ts->tv_sec = retval;
- ts->tv_nsec = 0;
+ x86_platform.get_wallclock(ts);
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 56f7fcfe7fa2..e68709da8251 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1040,8 +1040,6 @@ void __init setup_arch(char **cmdline_p)
/* max_low_pfn get updated here */
find_low_pfn_range();
#else
- num_physpages = max_pfn;
-
check_x2apic();
/* How many end-of-memory variables you have, grandma! */
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index f4fe0b8879e0..cdaa347dfcad 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -265,23 +265,30 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
*/
}
-void smp_trace_reschedule_interrupt(struct pt_regs *regs)
+static inline void smp_entering_irq(void)
{
ack_APIC_irq();
+ irq_enter();
+}
+
+void smp_trace_reschedule_interrupt(struct pt_regs *regs)
+{
+ /*
+ * Need to call irq_enter() before calling the trace point.
+ * __smp_reschedule_interrupt() calls irq_enter/exit() too (in
+ * scheduler_ipi(). This is OK, since those functions are allowed
+ * to nest.
+ */
+ smp_entering_irq();
trace_reschedule_entry(RESCHEDULE_VECTOR);
__smp_reschedule_interrupt();
trace_reschedule_exit(RESCHEDULE_VECTOR);
+ exiting_irq();
/*
* KVM uses this interrupt to force a cpu out of guest mode
*/
}
-static inline void call_function_entering_irq(void)
-{
- ack_APIC_irq();
- irq_enter();
-}
-
static inline void __smp_call_function_interrupt(void)
{
generic_smp_call_function_interrupt();
@@ -290,14 +297,14 @@ static inline void __smp_call_function_interrupt(void)
void smp_call_function_interrupt(struct pt_regs *regs)
{
- call_function_entering_irq();
+ smp_entering_irq();
__smp_call_function_interrupt();
exiting_irq();
}
void smp_trace_call_function_interrupt(struct pt_regs *regs)
{
- call_function_entering_irq();
+ smp_entering_irq();
trace_call_function_entry(CALL_FUNCTION_VECTOR);
__smp_call_function_interrupt();
trace_call_function_exit(CALL_FUNCTION_VECTOR);
@@ -312,14 +319,14 @@ static inline void __smp_call_function_single_interrupt(void)
void smp_call_function_single_interrupt(struct pt_regs *regs)
{
- call_function_entering_irq();
+ smp_entering_irq();
__smp_call_function_single_interrupt();
exiting_irq();
}
void smp_trace_call_function_single_interrupt(struct pt_regs *regs)
{
- call_function_entering_irq();
+ smp_entering_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/kvm/Makefile b/arch/x86/kvm/Makefile
index d609e1d84048..bf4fb04d0112 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -5,12 +5,13 @@ CFLAGS_x86.o := -I.
CFLAGS_svm.o := -I.
CFLAGS_vmx.o := -I.
-kvm-y += $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o \
- coalesced_mmio.o irq_comm.o eventfd.o \
- irqchip.o)
-kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += $(addprefix ../../../virt/kvm/, \
- assigned-dev.o iommu.o)
-kvm-$(CONFIG_KVM_ASYNC_PF) += $(addprefix ../../../virt/kvm/, async_pf.o)
+KVM := ../../../virt/kvm
+
+kvm-y += $(KVM)/kvm_main.o $(KVM)/ioapic.o \
+ $(KVM)/coalesced_mmio.o $(KVM)/irq_comm.o \
+ $(KVM)/eventfd.o $(KVM)/irqchip.o
+kvm-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += $(KVM)/assigned-dev.o $(KVM)/iommu.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 cpuid.o pmu.o
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5953dcea752d..2bc1e81045b0 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -61,6 +61,8 @@
#define OpMem8 26ull /* 8-bit zero extended memory operand */
#define OpImm64 27ull /* Sign extended 16/32/64-bit immediate */
#define OpXLat 28ull /* memory at BX/EBX/RBX + zero-extended AL */
+#define OpAccLo 29ull /* Low part of extended acc (AX/AX/EAX/RAX) */
+#define OpAccHi 30ull /* High part of extended acc (-/DX/EDX/RDX) */
#define OpBits 5 /* Width of operand field */
#define OpMask ((1ull << OpBits) - 1)
@@ -86,6 +88,7 @@
#define DstMem64 (OpMem64 << DstShift)
#define DstImmUByte (OpImmUByte << DstShift)
#define DstDX (OpDX << DstShift)
+#define DstAccLo (OpAccLo << DstShift)
#define DstMask (OpMask << DstShift)
/* Source operand type. */
#define SrcShift 6
@@ -108,6 +111,7 @@
#define SrcImm64 (OpImm64 << SrcShift)
#define SrcDX (OpDX << SrcShift)
#define SrcMem8 (OpMem8 << SrcShift)
+#define SrcAccHi (OpAccHi << SrcShift)
#define SrcMask (OpMask << SrcShift)
#define BitOp (1<<11)
#define MemAbs (1<<12) /* Memory operand is absolute displacement */
@@ -138,6 +142,7 @@
/* Source 2 operand type */
#define Src2Shift (31)
#define Src2None (OpNone << Src2Shift)
+#define Src2Mem (OpMem << Src2Shift)
#define Src2CL (OpCL << Src2Shift)
#define Src2ImmByte (OpImmByte << Src2Shift)
#define Src2One (OpOne << Src2Shift)
@@ -155,6 +160,9 @@
#define Avx ((u64)1 << 43) /* Advanced Vector Extensions */
#define Fastop ((u64)1 << 44) /* Use opcode::u.fastop */
#define NoWrite ((u64)1 << 45) /* No writeback */
+#define SrcWrite ((u64)1 << 46) /* Write back src operand */
+
+#define DstXacc (DstAccLo | SrcAccHi | SrcWrite)
#define X2(x...) x, x
#define X3(x...) X2(x), x
@@ -171,10 +179,11 @@
/*
* fastop functions have a special calling convention:
*
- * dst: [rdx]:rax (in/out)
- * src: rbx (in/out)
+ * dst: rax (in/out)
+ * src: rdx (in/out)
* src2: rcx (in)
* flags: rflags (in/out)
+ * ex: rsi (in:fastop pointer, out:zero if exception)
*
* Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
* different operand sizes can be reached by calculation, rather than a jump
@@ -276,174 +285,17 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
}
/*
- * Instruction emulation:
- * Most instructions are emulated directly via a fragment of inline assembly
- * code. This allows us to save/restore EFLAGS and thus very easily pick up
- * any modified flags.
- */
-
-#if defined(CONFIG_X86_64)
-#define _LO32 "k" /* force 32-bit operand */
-#define _STK "%%rsp" /* stack pointer */
-#elif defined(__i386__)
-#define _LO32 "" /* force 32-bit operand */
-#define _STK "%%esp" /* stack pointer */
-#endif
-
-/*
* These EFLAGS bits are restored from saved value during emulation, and
* any changes are written back to the saved value after emulation.
*/
#define EFLAGS_MASK (EFLG_OF|EFLG_SF|EFLG_ZF|EFLG_AF|EFLG_PF|EFLG_CF)
-/* Before executing instruction: restore necessary bits in EFLAGS. */
-#define _PRE_EFLAGS(_sav, _msk, _tmp) \
- /* EFLAGS = (_sav & _msk) | (EFLAGS & ~_msk); _sav &= ~_msk; */ \
- "movl %"_sav",%"_LO32 _tmp"; " \
- "push %"_tmp"; " \
- "push %"_tmp"; " \
- "movl %"_msk",%"_LO32 _tmp"; " \
- "andl %"_LO32 _tmp",("_STK"); " \
- "pushf; " \
- "notl %"_LO32 _tmp"; " \
- "andl %"_LO32 _tmp",("_STK"); " \
- "andl %"_LO32 _tmp","__stringify(BITS_PER_LONG/4)"("_STK"); " \
- "pop %"_tmp"; " \
- "orl %"_LO32 _tmp",("_STK"); " \
- "popf; " \
- "pop %"_sav"; "
-
-/* After executing instruction: write-back necessary bits in EFLAGS. */
-#define _POST_EFLAGS(_sav, _msk, _tmp) \
- /* _sav |= EFLAGS & _msk; */ \
- "pushf; " \
- "pop %"_tmp"; " \
- "andl %"_msk",%"_LO32 _tmp"; " \
- "orl %"_LO32 _tmp",%"_sav"; "
-
#ifdef CONFIG_X86_64
#define ON64(x) x
#else
#define ON64(x)
#endif
-#define ____emulate_2op(ctxt, _op, _x, _y, _suffix, _dsttype) \
- do { \
- __asm__ __volatile__ ( \
- _PRE_EFLAGS("0", "4", "2") \
- _op _suffix " %"_x"3,%1; " \
- _POST_EFLAGS("0", "4", "2") \
- : "=m" ((ctxt)->eflags), \
- "+q" (*(_dsttype*)&(ctxt)->dst.val), \
- "=&r" (_tmp) \
- : _y ((ctxt)->src.val), "i" (EFLAGS_MASK)); \
- } while (0)
-
-
-/* Raw emulation: instruction has two explicit operands. */
-#define __emulate_2op_nobyte(ctxt,_op,_wx,_wy,_lx,_ly,_qx,_qy) \
- do { \
- unsigned long _tmp; \
- \
- switch ((ctxt)->dst.bytes) { \
- case 2: \
- ____emulate_2op(ctxt,_op,_wx,_wy,"w",u16); \
- break; \
- case 4: \
- ____emulate_2op(ctxt,_op,_lx,_ly,"l",u32); \
- break; \
- case 8: \
- ON64(____emulate_2op(ctxt,_op,_qx,_qy,"q",u64)); \
- break; \
- } \
- } while (0)
-
-#define __emulate_2op(ctxt,_op,_bx,_by,_wx,_wy,_lx,_ly,_qx,_qy) \
- do { \
- unsigned long _tmp; \
- switch ((ctxt)->dst.bytes) { \
- case 1: \
- ____emulate_2op(ctxt,_op,_bx,_by,"b",u8); \
- break; \
- default: \
- __emulate_2op_nobyte(ctxt, _op, \
- _wx, _wy, _lx, _ly, _qx, _qy); \
- break; \
- } \
- } while (0)
-
-/* Source operand is byte-sized and may be restricted to just %cl. */
-#define emulate_2op_SrcB(ctxt, _op) \
- __emulate_2op(ctxt, _op, "b", "c", "b", "c", "b", "c", "b", "c")
-
-/* Source operand is byte, word, long or quad sized. */
-#define emulate_2op_SrcV(ctxt, _op) \
- __emulate_2op(ctxt, _op, "b", "q", "w", "r", _LO32, "r", "", "r")
-
-/* Source operand is word, long or quad sized. */
-#define emulate_2op_SrcV_nobyte(ctxt, _op) \
- __emulate_2op_nobyte(ctxt, _op, "w", "r", _LO32, "r", "", "r")
-
-/* Instruction has three operands and one operand is stored in ECX register */
-#define __emulate_2op_cl(ctxt, _op, _suffix, _type) \
- do { \
- unsigned long _tmp; \
- _type _clv = (ctxt)->src2.val; \
- _type _srcv = (ctxt)->src.val; \
- _type _dstv = (ctxt)->dst.val; \
- \
- __asm__ __volatile__ ( \
- _PRE_EFLAGS("0", "5", "2") \
- _op _suffix " %4,%1 \n" \
- _POST_EFLAGS("0", "5", "2") \
- : "=m" ((ctxt)->eflags), "+r" (_dstv), "=&r" (_tmp) \
- : "c" (_clv) , "r" (_srcv), "i" (EFLAGS_MASK) \
- ); \
- \
- (ctxt)->src2.val = (unsigned long) _clv; \
- (ctxt)->src2.val = (unsigned long) _srcv; \
- (ctxt)->dst.val = (unsigned long) _dstv; \
- } while (0)
-
-#define emulate_2op_cl(ctxt, _op) \
- do { \
- switch ((ctxt)->dst.bytes) { \
- case 2: \
- __emulate_2op_cl(ctxt, _op, "w", u16); \
- break; \
- case 4: \
- __emulate_2op_cl(ctxt, _op, "l", u32); \
- break; \
- case 8: \
- ON64(__emulate_2op_cl(ctxt, _op, "q", ulong)); \
- break; \
- } \
- } while (0)
-
-#define __emulate_1op(ctxt, _op, _suffix) \
- do { \
- unsigned long _tmp; \
- \
- __asm__ __volatile__ ( \
- _PRE_EFLAGS("0", "3", "2") \
- _op _suffix " %1; " \
- _POST_EFLAGS("0", "3", "2") \
- : "=m" ((ctxt)->eflags), "+m" ((ctxt)->dst.val), \
- "=&r" (_tmp) \
- : "i" (EFLAGS_MASK)); \
- } while (0)
-
-/* Instruction has only one explicit operand (no source operand). */
-#define emulate_1op(ctxt, _op) \
- do { \
- switch ((ctxt)->dst.bytes) { \
- case 1: __emulate_1op(ctxt, _op, "b"); break; \
- case 2: __emulate_1op(ctxt, _op, "w"); break; \
- case 4: __emulate_1op(ctxt, _op, "l"); break; \
- case 8: ON64(__emulate_1op(ctxt, _op, "q")); break; \
- } \
- } while (0)
-
static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
#define FOP_ALIGN ".align " __stringify(FASTOP_SIZE) " \n\t"
@@ -462,7 +314,10 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
#define FOPNOP() FOP_ALIGN FOP_RET
#define FOP1E(op, dst) \
- FOP_ALIGN #op " %" #dst " \n\t" FOP_RET
+ FOP_ALIGN "10: " #op " %" #dst " \n\t" FOP_RET
+
+#define FOP1EEX(op, dst) \
+ FOP1E(op, dst) _ASM_EXTABLE(10b, kvm_fastop_exception)
#define FASTOP1(op) \
FOP_START(op) \
@@ -472,24 +327,42 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
ON64(FOP1E(op##q, rax)) \
FOP_END
+/* 1-operand, using src2 (for MUL/DIV r/m) */
+#define FASTOP1SRC2(op, name) \
+ FOP_START(name) \
+ FOP1E(op, cl) \
+ FOP1E(op, cx) \
+ FOP1E(op, ecx) \
+ ON64(FOP1E(op, rcx)) \
+ FOP_END
+
+/* 1-operand, using src2 (for MUL/DIV r/m), with exceptions */
+#define FASTOP1SRC2EX(op, name) \
+ FOP_START(name) \
+ FOP1EEX(op, cl) \
+ FOP1EEX(op, cx) \
+ FOP1EEX(op, ecx) \
+ ON64(FOP1EEX(op, rcx)) \
+ FOP_END
+
#define FOP2E(op, dst, src) \
FOP_ALIGN #op " %" #src ", %" #dst " \n\t" FOP_RET
#define FASTOP2(op) \
FOP_START(op) \
- FOP2E(op##b, al, bl) \
- FOP2E(op##w, ax, bx) \
- FOP2E(op##l, eax, ebx) \
- ON64(FOP2E(op##q, rax, rbx)) \
+ FOP2E(op##b, al, dl) \
+ FOP2E(op##w, ax, dx) \
+ FOP2E(op##l, eax, edx) \
+ ON64(FOP2E(op##q, rax, rdx)) \
FOP_END
/* 2 operand, word only */
#define FASTOP2W(op) \
FOP_START(op) \
FOPNOP() \
- FOP2E(op##w, ax, bx) \
- FOP2E(op##l, eax, ebx) \
- ON64(FOP2E(op##q, rax, rbx)) \
+ FOP2E(op##w, ax, dx) \
+ FOP2E(op##l, eax, edx) \
+ ON64(FOP2E(op##q, rax, rdx)) \
FOP_END
/* 2 operand, src is CL */
@@ -508,14 +381,17 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *));
#define FASTOP3WCL(op) \
FOP_START(op) \
FOPNOP() \
- FOP3E(op##w, ax, bx, cl) \
- FOP3E(op##l, eax, ebx, cl) \
- ON64(FOP3E(op##q, rax, rbx, cl)) \
+ FOP3E(op##w, ax, dx, cl) \
+ FOP3E(op##l, eax, edx, cl) \
+ ON64(FOP3E(op##q, rax, rdx, cl)) \
FOP_END
/* Special case for SETcc - 1 instruction per cc */
#define FOP_SETCC(op) ".align 4; " #op " %al; ret \n\t"
+asm(".global kvm_fastop_exception \n"
+ "kvm_fastop_exception: xor %esi, %esi; ret");
+
FOP_START(setcc)
FOP_SETCC(seto)
FOP_SETCC(setno)
@@ -538,47 +414,6 @@ FOP_END;
FOP_START(salc) "pushf; sbb %al, %al; popf \n\t" FOP_RET
FOP_END;
-#define __emulate_1op_rax_rdx(ctxt, _op, _suffix, _ex) \
- do { \
- unsigned long _tmp; \
- ulong *rax = reg_rmw((ctxt), VCPU_REGS_RAX); \
- ulong *rdx = reg_rmw((ctxt), VCPU_REGS_RDX); \
- \
- __asm__ __volatile__ ( \
- _PRE_EFLAGS("0", "5", "1") \
- "1: \n\t" \
- _op _suffix " %6; " \
- "2: \n\t" \
- _POST_EFLAGS("0", "5", "1") \
- ".pushsection .fixup,\"ax\" \n\t" \
- "3: movb $1, %4 \n\t" \
- "jmp 2b \n\t" \
- ".popsection \n\t" \
- _ASM_EXTABLE(1b, 3b) \
- : "=m" ((ctxt)->eflags), "=&r" (_tmp), \
- "+a" (*rax), "+d" (*rdx), "+qm"(_ex) \
- : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val)); \
- } while (0)
-
-/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
-#define emulate_1op_rax_rdx(ctxt, _op, _ex) \
- do { \
- switch((ctxt)->src.bytes) { \
- case 1: \
- __emulate_1op_rax_rdx(ctxt, _op, "b", _ex); \
- break; \
- case 2: \
- __emulate_1op_rax_rdx(ctxt, _op, "w", _ex); \
- break; \
- case 4: \
- __emulate_1op_rax_rdx(ctxt, _op, "l", _ex); \
- break; \
- case 8: ON64( \
- __emulate_1op_rax_rdx(ctxt, _op, "q", _ex)); \
- break; \
- } \
- } while (0)
-
static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
enum x86_intercept intercept,
enum x86_intercept_stage stage)
@@ -988,6 +823,11 @@ FASTOP2(xor);
FASTOP2(cmp);
FASTOP2(test);
+FASTOP1SRC2(mul, mul_ex);
+FASTOP1SRC2(imul, imul_ex);
+FASTOP1SRC2EX(div, div_ex);
+FASTOP1SRC2EX(idiv, idiv_ex);
+
FASTOP3WCL(shld);
FASTOP3WCL(shrd);
@@ -1013,6 +853,8 @@ FASTOP2W(bts);
FASTOP2W(btr);
FASTOP2W(btc);
+FASTOP2(xadd);
+
static u8 test_cc(unsigned int condition, unsigned long flags)
{
u8 rc;
@@ -1726,45 +1568,42 @@ static void write_register_operand(struct operand *op)
}
}
-static int writeback(struct x86_emulate_ctxt *ctxt)
+static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op)
{
int rc;
- if (ctxt->d & NoWrite)
- return X86EMUL_CONTINUE;
-
- switch (ctxt->dst.type) {
+ switch (op->type) {
case OP_REG:
- write_register_operand(&ctxt->dst);
+ write_register_operand(op);
break;
case OP_MEM:
if (ctxt->lock_prefix)
rc = segmented_cmpxchg(ctxt,
- ctxt->dst.addr.mem,
- &ctxt->dst.orig_val,
- &ctxt->dst.val,
- ctxt->dst.bytes);
+ op->addr.mem,
+ &op->orig_val,
+ &op->val,
+ op->bytes);
else
rc = segmented_write(ctxt,
- ctxt->dst.addr.mem,
- &ctxt->dst.val,
- ctxt->dst.bytes);
+ op->addr.mem,
+ &op->val,
+ op->bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
break;
case OP_MEM_STR:
rc = segmented_write(ctxt,
- ctxt->dst.addr.mem,
- ctxt->dst.data,
- ctxt->dst.bytes * ctxt->dst.count);
+ op->addr.mem,
+ op->data,
+ op->bytes * op->count);
if (rc != X86EMUL_CONTINUE)
return rc;
break;
case OP_XMM:
- write_sse_reg(ctxt, &ctxt->dst.vec_val, ctxt->dst.addr.xmm);
+ write_sse_reg(ctxt, &op->vec_val, op->addr.xmm);
break;
case OP_MM:
- write_mmx_reg(ctxt, &ctxt->dst.mm_val, ctxt->dst.addr.mm);
+ write_mmx_reg(ctxt, &op->mm_val, op->addr.mm);
break;
case OP_NONE:
/* no writeback */
@@ -2117,42 +1956,6 @@ static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
-static int em_mul_ex(struct x86_emulate_ctxt *ctxt)
-{
- u8 ex = 0;
-
- emulate_1op_rax_rdx(ctxt, "mul", ex);
- return X86EMUL_CONTINUE;
-}
-
-static int em_imul_ex(struct x86_emulate_ctxt *ctxt)
-{
- u8 ex = 0;
-
- emulate_1op_rax_rdx(ctxt, "imul", ex);
- return X86EMUL_CONTINUE;
-}
-
-static int em_div_ex(struct x86_emulate_ctxt *ctxt)
-{
- u8 de = 0;
-
- emulate_1op_rax_rdx(ctxt, "div", de);
- if (de)
- return emulate_de(ctxt);
- return X86EMUL_CONTINUE;
-}
-
-static int em_idiv_ex(struct x86_emulate_ctxt *ctxt)
-{
- u8 de = 0;
-
- emulate_1op_rax_rdx(ctxt, "idiv", de);
- if (de)
- return emulate_de(ctxt);
- return X86EMUL_CONTINUE;
-}
-
static int em_grp45(struct x86_emulate_ctxt *ctxt)
{
int rc = X86EMUL_CONTINUE;
@@ -3734,10 +3537,10 @@ static const struct opcode group3[] = {
F(DstMem | SrcImm | NoWrite, em_test),
F(DstMem | SrcNone | Lock, em_not),
F(DstMem | SrcNone | Lock, em_neg),
- I(SrcMem, em_mul_ex),
- I(SrcMem, em_imul_ex),
- I(SrcMem, em_div_ex),
- I(SrcMem, em_idiv_ex),
+ F(DstXacc | Src2Mem, em_mul_ex),
+ F(DstXacc | Src2Mem, em_imul_ex),
+ F(DstXacc | Src2Mem, em_div_ex),
+ F(DstXacc | Src2Mem, em_idiv_ex),
};
static const struct opcode group4[] = {
@@ -4064,7 +3867,7 @@ static const struct opcode twobyte_table[256] = {
F(DstReg | SrcMem | ModRM, em_bsf), F(DstReg | SrcMem | ModRM, em_bsr),
D(DstReg | SrcMem8 | ModRM | Mov), D(DstReg | SrcMem16 | ModRM | Mov),
/* 0xC0 - 0xC7 */
- D2bv(DstMem | SrcReg | ModRM | Lock),
+ F2bv(DstMem | SrcReg | ModRM | SrcWrite | Lock, em_xadd),
N, D(DstMem | SrcReg | ModRM | Mov),
N, N, N, GD(0, &group9),
/* 0xC8 - 0xCF */
@@ -4172,6 +3975,24 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
fetch_register_operand(op);
op->orig_val = op->val;
break;
+ case OpAccLo:
+ op->type = OP_REG;
+ op->bytes = (ctxt->d & ByteOp) ? 2 : ctxt->op_bytes;
+ op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RAX);
+ fetch_register_operand(op);
+ op->orig_val = op->val;
+ break;
+ case OpAccHi:
+ if (ctxt->d & ByteOp) {
+ op->type = OP_NONE;
+ break;
+ }
+ op->type = OP_REG;
+ op->bytes = ctxt->op_bytes;
+ op->addr.reg = reg_rmw(ctxt, VCPU_REGS_RDX);
+ fetch_register_operand(op);
+ op->orig_val = op->val;
+ break;
case OpDI:
op->type = OP_MEM;
op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
@@ -4553,11 +4374,15 @@ static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt,
static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
{
ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
- fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
+ if (!(ctxt->d & ByteOp))
+ fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
- : "+a"(ctxt->dst.val), "+b"(ctxt->src.val), [flags]"+D"(flags)
- : "c"(ctxt->src2.val), [fastop]"S"(fop));
+ : "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
+ [fastop]"+S"(fop)
+ : "c"(ctxt->src2.val));
ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);
+ if (!fop) /* exception is returned in fop variable */
+ return emulate_de(ctxt);
return X86EMUL_CONTINUE;
}
@@ -4773,9 +4598,17 @@ special_insn:
goto done;
writeback:
- rc = writeback(ctxt);
- if (rc != X86EMUL_CONTINUE)
- goto done;
+ if (!(ctxt->d & NoWrite)) {
+ rc = writeback(ctxt, &ctxt->dst);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+ if (ctxt->d & SrcWrite) {
+ BUG_ON(ctxt->src.type == OP_MEM || ctxt->src.type == OP_MEM_STR);
+ rc = writeback(ctxt, &ctxt->src);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
/*
* restore dst type in case the decoding will be reused
@@ -4872,12 +4705,6 @@ twobyte_insn:
ctxt->dst.val = (ctxt->src.bytes == 1) ? (s8) ctxt->src.val :
(s16) ctxt->src.val;
break;
- case 0xc0 ... 0xc1: /* xadd */
- fastop(ctxt, em_add);
- /* Write back the register source. */
- ctxt->src.val = ctxt->dst.orig_val;
- write_register_operand(&ctxt->src);
- break;
case 0xc3: /* movnti */
ctxt->dst.bytes = ctxt->op_bytes;
ctxt->dst.val = (ctxt->op_bytes == 4) ? (u32) ctxt->src.val :
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 0eee2c8b64d1..afc11245827c 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1608,8 +1608,8 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
return;
if (atomic_read(&apic->lapic_timer.pending) > 0) {
- if (kvm_apic_local_deliver(apic, APIC_LVTT))
- atomic_dec(&apic->lapic_timer.pending);
+ kvm_apic_local_deliver(apic, APIC_LVTT);
+ atomic_set(&apic->lapic_timer.pending, 0);
}
}
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 004cc87b781c..0d094da49541 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -197,15 +197,63 @@ void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask)
}
EXPORT_SYMBOL_GPL(kvm_mmu_set_mmio_spte_mask);
-static void mark_mmio_spte(u64 *sptep, u64 gfn, unsigned access)
+/*
+ * spte bits of bit 3 ~ bit 11 are used as low 9 bits of generation number,
+ * the bits of bits 52 ~ bit 61 are used as high 10 bits of generation
+ * number.
+ */
+#define MMIO_SPTE_GEN_LOW_SHIFT 3
+#define MMIO_SPTE_GEN_HIGH_SHIFT 52
+
+#define MMIO_GEN_SHIFT 19
+#define MMIO_GEN_LOW_SHIFT 9
+#define MMIO_GEN_LOW_MASK ((1 << MMIO_GEN_LOW_SHIFT) - 1)
+#define MMIO_GEN_MASK ((1 << MMIO_GEN_SHIFT) - 1)
+#define MMIO_MAX_GEN ((1 << MMIO_GEN_SHIFT) - 1)
+
+static u64 generation_mmio_spte_mask(unsigned int gen)
{
- struct kvm_mmu_page *sp = page_header(__pa(sptep));
+ u64 mask;
+
+ WARN_ON(gen > MMIO_MAX_GEN);
+
+ mask = (gen & MMIO_GEN_LOW_MASK) << MMIO_SPTE_GEN_LOW_SHIFT;
+ mask |= ((u64)gen >> MMIO_GEN_LOW_SHIFT) << MMIO_SPTE_GEN_HIGH_SHIFT;
+ return mask;
+}
+
+static unsigned int get_mmio_spte_generation(u64 spte)
+{
+ unsigned int gen;
+
+ spte &= ~shadow_mmio_mask;
+
+ gen = (spte >> MMIO_SPTE_GEN_LOW_SHIFT) & MMIO_GEN_LOW_MASK;
+ gen |= (spte >> MMIO_SPTE_GEN_HIGH_SHIFT) << MMIO_GEN_LOW_SHIFT;
+ return gen;
+}
+
+static unsigned int kvm_current_mmio_generation(struct kvm *kvm)
+{
+ /*
+ * Init kvm generation close to MMIO_MAX_GEN to easily test the
+ * code of handling generation number wrap-around.
+ */
+ return (kvm_memslots(kvm)->generation +
+ MMIO_MAX_GEN - 150) & MMIO_GEN_MASK;
+}
+
+static void mark_mmio_spte(struct kvm *kvm, u64 *sptep, u64 gfn,
+ unsigned access)
+{
+ unsigned int gen = kvm_current_mmio_generation(kvm);
+ u64 mask = generation_mmio_spte_mask(gen);
access &= ACC_WRITE_MASK | ACC_USER_MASK;
+ mask |= shadow_mmio_mask | access | gfn << PAGE_SHIFT;
- sp->mmio_cached = true;
- trace_mark_mmio_spte(sptep, gfn, access);
- mmu_spte_set(sptep, shadow_mmio_mask | access | gfn << PAGE_SHIFT);
+ trace_mark_mmio_spte(sptep, gfn, access, gen);
+ mmu_spte_set(sptep, mask);
}
static bool is_mmio_spte(u64 spte)
@@ -215,24 +263,38 @@ static bool is_mmio_spte(u64 spte)
static gfn_t get_mmio_spte_gfn(u64 spte)
{
- return (spte & ~shadow_mmio_mask) >> PAGE_SHIFT;
+ u64 mask = generation_mmio_spte_mask(MMIO_MAX_GEN) | shadow_mmio_mask;
+ return (spte & ~mask) >> PAGE_SHIFT;
}
static unsigned get_mmio_spte_access(u64 spte)
{
- return (spte & ~shadow_mmio_mask) & ~PAGE_MASK;
+ u64 mask = generation_mmio_spte_mask(MMIO_MAX_GEN) | shadow_mmio_mask;
+ return (spte & ~mask) & ~PAGE_MASK;
}
-static bool set_mmio_spte(u64 *sptep, gfn_t gfn, pfn_t pfn, unsigned access)
+static bool set_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
+ pfn_t pfn, unsigned access)
{
if (unlikely(is_noslot_pfn(pfn))) {
- mark_mmio_spte(sptep, gfn, access);
+ mark_mmio_spte(kvm, sptep, gfn, access);
return true;
}
return false;
}
+static bool check_mmio_spte(struct kvm *kvm, u64 spte)
+{
+ unsigned int kvm_gen, spte_gen;
+
+ kvm_gen = kvm_current_mmio_generation(kvm);
+ spte_gen = get_mmio_spte_generation(spte);
+
+ trace_check_mmio_spte(spte, kvm_gen, spte_gen);
+ return likely(kvm_gen == spte_gen);
+}
+
static inline u64 rsvd_bits(int s, int e)
{
return ((1ULL << (e - s + 1)) - 1) << s;
@@ -404,9 +466,20 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte)
/*
* The idea using the light way get the spte on x86_32 guest is from
* gup_get_pte(arch/x86/mm/gup.c).
- * The difference is we can not catch the spte tlb flush if we leave
- * guest mode, so we emulate it by increase clear_spte_count when spte
- * is cleared.
+ *
+ * An spte tlb flush may be pending, because kvm_set_pte_rmapp
+ * coalesces them and we are running out of the MMU lock. Therefore
+ * we need to protect against in-progress updates of the spte.
+ *
+ * Reading the spte while an update is in progress may get the old value
+ * for the high part of the spte. The race is fine for a present->non-present
+ * change (because the high part of the spte is ignored for non-present spte),
+ * but for a present->present change we must reread the spte.
+ *
+ * All such changes are done in two steps (present->non-present and
+ * non-present->present), hence it is enough to count the number of
+ * present->non-present updates: if it changed while reading the spte,
+ * we might have hit the race. This is done using clear_spte_count.
*/
static u64 __get_spte_lockless(u64 *sptep)
{
@@ -1511,6 +1584,12 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
if (!direct)
sp->gfns = mmu_memory_cache_alloc(&vcpu->arch.mmu_page_cache);
set_page_private(virt_to_page(sp->spt), (unsigned long)sp);
+
+ /*
+ * The active_mmu_pages list is the FIFO list, do not move the
+ * page until it is zapped. kvm_zap_obsolete_pages depends on
+ * this feature. See the comments in kvm_zap_obsolete_pages().
+ */
list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
sp->parent_ptes = 0;
mmu_page_add_parent_pte(vcpu, sp, parent_pte);
@@ -1648,6 +1727,16 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
static void kvm_mmu_commit_zap_page(struct kvm *kvm,
struct list_head *invalid_list);
+/*
+ * NOTE: we should pay more attention on the zapped-obsolete page
+ * (is_obsolete_sp(sp) && sp->role.invalid) when you do hash list walk
+ * since it has been deleted from active_mmu_pages but still can be found
+ * at hast list.
+ *
+ * for_each_gfn_indirect_valid_sp has skipped that kind of page and
+ * kvm_mmu_get_page(), the only user of for_each_gfn_sp(), has skipped
+ * all the obsolete pages.
+ */
#define for_each_gfn_sp(_kvm, _sp, _gfn) \
hlist_for_each_entry(_sp, \
&(_kvm)->arch.mmu_page_hash[kvm_page_table_hashfn(_gfn)], hash_link) \
@@ -1838,6 +1927,11 @@ static void clear_sp_write_flooding_count(u64 *spte)
__clear_sp_write_flooding_count(sp);
}
+static bool is_obsolete_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
+{
+ return unlikely(sp->mmu_valid_gen != kvm->arch.mmu_valid_gen);
+}
+
static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
gfn_t gfn,
gva_t gaddr,
@@ -1864,6 +1958,9 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
role.quadrant = quadrant;
}
for_each_gfn_sp(vcpu->kvm, sp, gfn) {
+ if (is_obsolete_sp(vcpu->kvm, sp))
+ continue;
+
if (!need_sync && sp->unsync)
need_sync = true;
@@ -1900,6 +1997,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
account_shadowed(vcpu->kvm, gfn);
}
+ sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
init_shadow_page_table(sp);
trace_kvm_mmu_get_page(sp, true);
return sp;
@@ -2070,8 +2168,10 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
ret = mmu_zap_unsync_children(kvm, sp, invalid_list);
kvm_mmu_page_unlink_children(kvm, sp);
kvm_mmu_unlink_parents(kvm, sp);
+
if (!sp->role.invalid && !sp->role.direct)
unaccount_shadowed(kvm, sp->gfn);
+
if (sp->unsync)
kvm_unlink_unsync_page(kvm, sp);
if (!sp->root_count) {
@@ -2081,7 +2181,13 @@ static int kvm_mmu_prepare_zap_page(struct kvm *kvm, struct kvm_mmu_page *sp,
kvm_mod_used_mmu_pages(kvm, -1);
} else {
list_move(&sp->link, &kvm->arch.active_mmu_pages);
- kvm_reload_remote_mmus(kvm);
+
+ /*
+ * The obsolete pages can not be used on any vcpus.
+ * See the comments in kvm_mmu_invalidate_zap_all_pages().
+ */
+ if (!sp->role.invalid && !is_obsolete_sp(kvm, sp))
+ kvm_reload_remote_mmus(kvm);
}
sp->role.invalid = 1;
@@ -2331,7 +2437,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
u64 spte;
int ret = 0;
- if (set_mmio_spte(sptep, gfn, pfn, pte_access))
+ if (set_mmio_spte(vcpu->kvm, sptep, gfn, pfn, pte_access))
return 0;
spte = PT_PRESENT_MASK;
@@ -2869,22 +2975,25 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
if (!VALID_PAGE(vcpu->arch.mmu.root_hpa))
return;
- spin_lock(&vcpu->kvm->mmu_lock);
+
if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL &&
(vcpu->arch.mmu.root_level == PT64_ROOT_LEVEL ||
vcpu->arch.mmu.direct_map)) {
hpa_t root = vcpu->arch.mmu.root_hpa;
+ spin_lock(&vcpu->kvm->mmu_lock);
sp = page_header(root);
--sp->root_count;
if (!sp->root_count && sp->role.invalid) {
kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list);
kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list);
}
- vcpu->arch.mmu.root_hpa = INVALID_PAGE;
spin_unlock(&vcpu->kvm->mmu_lock);
+ vcpu->arch.mmu.root_hpa = INVALID_PAGE;
return;
}
+
+ spin_lock(&vcpu->kvm->mmu_lock);
for (i = 0; i < 4; ++i) {
hpa_t root = vcpu->arch.mmu.pae_root[i];
@@ -3148,17 +3257,12 @@ static u64 walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr)
return spte;
}
-/*
- * If it is a real mmio page fault, return 1 and emulat the instruction
- * directly, return 0 to let CPU fault again on the address, -1 is
- * returned if bug is detected.
- */
int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
{
u64 spte;
if (quickly_check_mmio_pf(vcpu, addr, direct))
- return 1;
+ return RET_MMIO_PF_EMULATE;
spte = walk_shadow_page_get_mmio_spte(vcpu, addr);
@@ -3166,12 +3270,15 @@ 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))
+ return RET_MMIO_PF_INVALID;
+
if (direct)
addr = 0;
trace_handle_mmio_page_fault(addr, gfn, access);
vcpu_cache_mmio_info(vcpu, addr, gfn, access);
- return 1;
+ return RET_MMIO_PF_EMULATE;
}
/*
@@ -3179,13 +3286,13 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
* it's a BUG if the gfn is not a mmio page.
*/
if (direct && !check_direct_spte_mmio_pf(spte))
- return -1;
+ return RET_MMIO_PF_BUG;
/*
* If the page table is zapped by other cpus, let CPU fault again on
* the address.
*/
- return 0;
+ return RET_MMIO_PF_RETRY;
}
EXPORT_SYMBOL_GPL(handle_mmio_page_fault_common);
@@ -3195,7 +3302,7 @@ static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr,
int ret;
ret = handle_mmio_page_fault_common(vcpu, addr, direct);
- WARN_ON(ret < 0);
+ WARN_ON(ret == RET_MMIO_PF_BUG);
return ret;
}
@@ -3207,8 +3314,12 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code);
- if (unlikely(error_code & PFERR_RSVD_MASK))
- return handle_mmio_page_fault(vcpu, gva, error_code, true);
+ if (unlikely(error_code & PFERR_RSVD_MASK)) {
+ r = handle_mmio_page_fault(vcpu, gva, error_code, true);
+
+ if (likely(r != RET_MMIO_PF_INVALID))
+ return r;
+ }
r = mmu_topup_memory_caches(vcpu);
if (r)
@@ -3284,8 +3395,12 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
ASSERT(vcpu);
ASSERT(VALID_PAGE(vcpu->arch.mmu.root_hpa));
- if (unlikely(error_code & PFERR_RSVD_MASK))
- return handle_mmio_page_fault(vcpu, gpa, error_code, true);
+ if (unlikely(error_code & PFERR_RSVD_MASK)) {
+ r = handle_mmio_page_fault(vcpu, gpa, error_code, true);
+
+ if (likely(r != RET_MMIO_PF_INVALID))
+ return r;
+ }
r = mmu_topup_memory_caches(vcpu);
if (r)
@@ -3391,8 +3506,8 @@ static inline void protect_clean_gpte(unsigned *access, unsigned gpte)
*access &= mask;
}
-static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access,
- int *nr_present)
+static bool sync_mmio_spte(struct kvm *kvm, u64 *sptep, gfn_t gfn,
+ unsigned access, int *nr_present)
{
if (unlikely(is_mmio_spte(*sptep))) {
if (gfn != get_mmio_spte_gfn(*sptep)) {
@@ -3401,7 +3516,7 @@ static bool sync_mmio_spte(u64 *sptep, gfn_t gfn, unsigned access,
}
(*nr_present)++;
- mark_mmio_spte(sptep, gfn, access);
+ mark_mmio_spte(kvm, sptep, gfn, access);
return true;
}
@@ -3764,9 +3879,7 @@ int kvm_mmu_load(struct kvm_vcpu *vcpu)
if (r)
goto out;
r = mmu_alloc_roots(vcpu);
- spin_lock(&vcpu->kvm->mmu_lock);
- mmu_sync_roots(vcpu);
- spin_unlock(&vcpu->kvm->mmu_lock);
+ kvm_mmu_sync_roots(vcpu);
if (r)
goto out;
/* set_cr3() should ensure TLB has been flushed */
@@ -4179,39 +4292,107 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
spin_unlock(&kvm->mmu_lock);
}
-void kvm_mmu_zap_all(struct kvm *kvm)
+#define BATCH_ZAP_PAGES 10
+static void kvm_zap_obsolete_pages(struct kvm *kvm)
{
struct kvm_mmu_page *sp, *node;
- LIST_HEAD(invalid_list);
+ int batch = 0;
- spin_lock(&kvm->mmu_lock);
restart:
- list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link)
- if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list))
+ list_for_each_entry_safe_reverse(sp, node,
+ &kvm->arch.active_mmu_pages, link) {
+ int ret;
+
+ /*
+ * No obsolete page exists before new created page since
+ * active_mmu_pages is the FIFO list.
+ */
+ if (!is_obsolete_sp(kvm, sp))
+ break;
+
+ /*
+ * Since we are reversely walking the list and the invalid
+ * list will be moved to the head, skip the invalid page
+ * can help us to avoid the infinity list walking.
+ */
+ if (sp->role.invalid)
+ continue;
+
+ /*
+ * Need not flush tlb since we only zap the sp with invalid
+ * generation number.
+ */
+ if (batch >= BATCH_ZAP_PAGES &&
+ cond_resched_lock(&kvm->mmu_lock)) {
+ batch = 0;
+ goto restart;
+ }
+
+ ret = kvm_mmu_prepare_zap_page(kvm, sp,
+ &kvm->arch.zapped_obsolete_pages);
+ batch += ret;
+
+ if (ret)
goto restart;
+ }
- kvm_mmu_commit_zap_page(kvm, &invalid_list);
- spin_unlock(&kvm->mmu_lock);
+ /*
+ * Should flush tlb before free page tables since lockless-walking
+ * may use the pages.
+ */
+ kvm_mmu_commit_zap_page(kvm, &kvm->arch.zapped_obsolete_pages);
}
-void kvm_mmu_zap_mmio_sptes(struct kvm *kvm)
+/*
+ * Fast invalidate all shadow pages and use lock-break technique
+ * to zap obsolete pages.
+ *
+ * It's required when memslot is being deleted or VM is being
+ * destroyed, in these cases, we should ensure that KVM MMU does
+ * not use any resource of the being-deleted slot or all slots
+ * after calling the function.
+ */
+void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm)
{
- struct kvm_mmu_page *sp, *node;
- LIST_HEAD(invalid_list);
-
spin_lock(&kvm->mmu_lock);
-restart:
- list_for_each_entry_safe(sp, node, &kvm->arch.active_mmu_pages, link) {
- if (!sp->mmio_cached)
- continue;
- if (kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list))
- goto restart;
- }
+ trace_kvm_mmu_invalidate_zap_all_pages(kvm);
+ kvm->arch.mmu_valid_gen++;
- kvm_mmu_commit_zap_page(kvm, &invalid_list);
+ /*
+ * Notify all vcpus to reload its shadow page table
+ * and flush TLB. Then all vcpus will switch to new
+ * shadow page table with the new mmu_valid_gen.
+ *
+ * Note: we should do this under the protection of
+ * mmu-lock, otherwise, vcpu would purge shadow page
+ * but miss tlb flush.
+ */
+ kvm_reload_remote_mmus(kvm);
+
+ kvm_zap_obsolete_pages(kvm);
spin_unlock(&kvm->mmu_lock);
}
+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)
+{
+ /*
+ * The very rare case: if the generation-number is round,
+ * zap all shadow pages.
+ *
+ * The max value is MMIO_MAX_GEN - 1 since it is not called
+ * when mark memslot invalid.
+ */
+ if (unlikely(kvm_current_mmio_generation(kvm) >= (MMIO_MAX_GEN - 1))) {
+ printk_ratelimited(KERN_INFO "kvm: zapping shadow pages for mmio generation wraparound\n");
+ kvm_mmu_invalidate_zap_all_pages(kvm);
+ }
+}
+
static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
{
struct kvm *kvm;
@@ -4240,15 +4421,23 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
* want to shrink a VM that only started to populate its MMU
* anyway.
*/
- if (!kvm->arch.n_used_mmu_pages)
+ if (!kvm->arch.n_used_mmu_pages &&
+ !kvm_has_zapped_obsolete_pages(kvm))
continue;
idx = srcu_read_lock(&kvm->srcu);
spin_lock(&kvm->mmu_lock);
+ if (kvm_has_zapped_obsolete_pages(kvm)) {
+ kvm_mmu_commit_zap_page(kvm,
+ &kvm->arch.zapped_obsolete_pages);
+ goto unlock;
+ }
+
prepare_zap_oldest_mmu_page(kvm, &invalid_list);
kvm_mmu_commit_zap_page(kvm, &invalid_list);
+unlock:
spin_unlock(&kvm->mmu_lock);
srcu_read_unlock(&kvm->srcu, idx);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 2adcbc2cac6d..5b59c573aba7 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -52,6 +52,23 @@
int kvm_mmu_get_spte_hierarchy(struct kvm_vcpu *vcpu, u64 addr, u64 sptes[4]);
void kvm_mmu_set_mmio_spte_mask(u64 mmio_mask);
+
+/*
+ * Return values of handle_mmio_page_fault_common:
+ * RET_MMIO_PF_EMULATE: it is a real mmio page fault, emulate the instruction
+ * directly.
+ * RET_MMIO_PF_INVALID: invalid spte is detected then let the real page
+ * fault path update the mmio spte.
+ * RET_MMIO_PF_RETRY: let CPU fault again on the address.
+ * RET_MMIO_PF_BUG: bug is detected.
+ */
+enum {
+ RET_MMIO_PF_EMULATE = 1,
+ RET_MMIO_PF_INVALID = 2,
+ RET_MMIO_PF_RETRY = 0,
+ RET_MMIO_PF_BUG = -1
+};
+
int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
int kvm_init_shadow_mmu(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
@@ -97,4 +114,5 @@ static inline bool permission_fault(struct kvm_mmu *mmu, unsigned pte_access,
return (mmu->permissions[pfec >> 1] >> pte_access) & 1;
}
+void kvm_mmu_invalidate_zap_all_pages(struct kvm *kvm);
#endif
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index b8f6172f4174..9d2e0ffcb190 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -7,16 +7,18 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM kvmmmu
-#define KVM_MMU_PAGE_FIELDS \
- __field(__u64, gfn) \
- __field(__u32, role) \
- __field(__u32, root_count) \
+#define KVM_MMU_PAGE_FIELDS \
+ __field(unsigned long, mmu_valid_gen) \
+ __field(__u64, gfn) \
+ __field(__u32, role) \
+ __field(__u32, root_count) \
__field(bool, unsync)
-#define KVM_MMU_PAGE_ASSIGN(sp) \
- __entry->gfn = sp->gfn; \
- __entry->role = sp->role.word; \
- __entry->root_count = sp->root_count; \
+#define KVM_MMU_PAGE_ASSIGN(sp) \
+ __entry->mmu_valid_gen = sp->mmu_valid_gen; \
+ __entry->gfn = sp->gfn; \
+ __entry->role = sp->role.word; \
+ __entry->root_count = sp->root_count; \
__entry->unsync = sp->unsync;
#define KVM_MMU_PAGE_PRINTK() ({ \
@@ -28,8 +30,8 @@
\
role.word = __entry->role; \
\
- trace_seq_printf(p, "sp gfn %llx %u%s q%u%s %s%s" \
- " %snxe root %u %s%c", \
+ trace_seq_printf(p, "sp gen %lx gfn %llx %u%s q%u%s %s%s" \
+ " %snxe root %u %s%c", __entry->mmu_valid_gen, \
__entry->gfn, role.level, \
role.cr4_pae ? " pae" : "", \
role.quadrant, \
@@ -197,23 +199,25 @@ DEFINE_EVENT(kvm_mmu_page_class, kvm_mmu_prepare_zap_page,
TRACE_EVENT(
mark_mmio_spte,
- TP_PROTO(u64 *sptep, gfn_t gfn, unsigned access),
- TP_ARGS(sptep, gfn, access),
+ TP_PROTO(u64 *sptep, gfn_t gfn, unsigned access, unsigned int gen),
+ TP_ARGS(sptep, gfn, access, gen),
TP_STRUCT__entry(
__field(void *, sptep)
__field(gfn_t, gfn)
__field(unsigned, access)
+ __field(unsigned int, gen)
),
TP_fast_assign(
__entry->sptep = sptep;
__entry->gfn = gfn;
__entry->access = access;
+ __entry->gen = gen;
),
- TP_printk("sptep:%p gfn %llx access %x", __entry->sptep, __entry->gfn,
- __entry->access)
+ TP_printk("sptep:%p gfn %llx access %x gen %x", __entry->sptep,
+ __entry->gfn, __entry->access, __entry->gen)
);
TRACE_EVENT(
@@ -274,6 +278,50 @@ TRACE_EVENT(
__spte_satisfied(old_spte), __spte_satisfied(new_spte)
)
);
+
+TRACE_EVENT(
+ kvm_mmu_invalidate_zap_all_pages,
+ TP_PROTO(struct kvm *kvm),
+ TP_ARGS(kvm),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, mmu_valid_gen)
+ __field(unsigned int, mmu_used_pages)
+ ),
+
+ TP_fast_assign(
+ __entry->mmu_valid_gen = kvm->arch.mmu_valid_gen;
+ __entry->mmu_used_pages = kvm->arch.n_used_mmu_pages;
+ ),
+
+ TP_printk("kvm-mmu-valid-gen %lx used_pages %x",
+ __entry->mmu_valid_gen, __entry->mmu_used_pages
+ )
+);
+
+
+TRACE_EVENT(
+ check_mmio_spte,
+ TP_PROTO(u64 spte, unsigned int kvm_gen, unsigned int spte_gen),
+ TP_ARGS(spte, kvm_gen, spte_gen),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, kvm_gen)
+ __field(unsigned int, spte_gen)
+ __field(u64, spte)
+ ),
+
+ TP_fast_assign(
+ __entry->kvm_gen = kvm_gen;
+ __entry->spte_gen = spte_gen;
+ __entry->spte = spte;
+ ),
+
+ TP_printk("spte %llx kvm_gen %x spte-gen %x valid %d", __entry->spte,
+ __entry->kvm_gen, __entry->spte_gen,
+ __entry->kvm_gen == __entry->spte_gen
+ )
+);
#endif /* _TRACE_KVMMMU_H */
#undef TRACE_INCLUDE_PATH
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index da20860b457a..7769699d48a8 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -552,9 +552,12 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
- if (unlikely(error_code & PFERR_RSVD_MASK))
- return handle_mmio_page_fault(vcpu, addr, error_code,
+ if (unlikely(error_code & PFERR_RSVD_MASK)) {
+ r = handle_mmio_page_fault(vcpu, addr, error_code,
mmu_is_nested(vcpu));
+ if (likely(r != RET_MMIO_PF_INVALID))
+ return r;
+ };
r = mmu_topup_memory_caches(vcpu);
if (r)
@@ -792,7 +795,8 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
pte_access &= gpte_access(vcpu, gpte);
protect_clean_gpte(&pte_access, gpte);
- if (sync_mmio_spte(&sp->spt[i], gfn, pte_access, &nr_present))
+ if (sync_mmio_spte(vcpu->kvm, &sp->spt[i], gfn, pte_access,
+ &nr_present))
continue;
if (gfn != sp->gfns[i]) {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index a14a6eaf871d..c0bc80391e40 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1026,7 +1026,10 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
g_tsc_offset = svm->vmcb->control.tsc_offset -
svm->nested.hsave->control.tsc_offset;
svm->nested.hsave->control.tsc_offset = offset;
- }
+ } else
+ trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+ svm->vmcb->control.tsc_offset,
+ offset);
svm->vmcb->control.tsc_offset = offset + g_tsc_offset;
@@ -1044,6 +1047,11 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
svm->vmcb->control.tsc_offset += adjustment;
if (is_guest_mode(vcpu))
svm->nested.hsave->control.tsc_offset += adjustment;
+ else
+ trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+ svm->vmcb->control.tsc_offset - adjustment,
+ svm->vmcb->control.tsc_offset);
+
mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
}
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index fe5e00ed7036..545245d7cc63 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -756,6 +756,27 @@ TRACE_EVENT(
__entry->gpa_match ? "GPA" : "GVA")
);
+TRACE_EVENT(kvm_write_tsc_offset,
+ TP_PROTO(unsigned int vcpu_id, __u64 previous_tsc_offset,
+ __u64 next_tsc_offset),
+ TP_ARGS(vcpu_id, previous_tsc_offset, next_tsc_offset),
+
+ TP_STRUCT__entry(
+ __field( unsigned int, vcpu_id )
+ __field( __u64, previous_tsc_offset )
+ __field( __u64, next_tsc_offset )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->previous_tsc_offset = previous_tsc_offset;
+ __entry->next_tsc_offset = next_tsc_offset;
+ ),
+
+ TP_printk("vcpu=%u prev=%llu next=%llu", __entry->vcpu_id,
+ __entry->previous_tsc_offset, __entry->next_tsc_offset)
+);
+
#ifdef CONFIG_X86_64
#define host_clocks \
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b30f5a54a2ab..064d0be67ecc 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2096,6 +2096,8 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
(nested_cpu_has(vmcs12, CPU_BASED_USE_TSC_OFFSETING) ?
vmcs12->tsc_offset : 0));
} else {
+ trace_kvm_write_tsc_offset(vcpu->vcpu_id,
+ vmcs_read64(TSC_OFFSET), offset);
vmcs_write64(TSC_OFFSET, offset);
}
}
@@ -2103,11 +2105,14 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
{
u64 offset = vmcs_read64(TSC_OFFSET);
+
vmcs_write64(TSC_OFFSET, offset + adjustment);
if (is_guest_mode(vcpu)) {
/* Even when running L2, the adjustment needs to apply to L1 */
to_vmx(vcpu)->nested.vmcs01_tsc_offset += adjustment;
- }
+ } else
+ trace_kvm_write_tsc_offset(vcpu->vcpu_id, offset,
+ offset + adjustment);
}
static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
@@ -3399,15 +3404,22 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
var->limit = vmx_read_guest_seg_limit(vmx, seg);
var->selector = vmx_read_guest_seg_selector(vmx, seg);
ar = vmx_read_guest_seg_ar(vmx, seg);
+ var->unusable = (ar >> 16) & 1;
var->type = ar & 15;
var->s = (ar >> 4) & 1;
var->dpl = (ar >> 5) & 3;
- var->present = (ar >> 7) & 1;
+ /*
+ * Some userspaces do not preserve unusable property. Since usable
+ * segment has to be present according to VMX spec we can use present
+ * property to amend userspace bug by making unusable segment always
+ * nonpresent. vmx_segment_access_rights() already marks nonpresent
+ * segment as unusable.
+ */
+ var->present = !var->unusable;
var->avl = (ar >> 12) & 1;
var->l = (ar >> 13) & 1;
var->db = (ar >> 14) & 1;
var->g = (ar >> 15) & 1;
- var->unusable = (ar >> 16) & 1;
}
static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
@@ -4176,10 +4188,10 @@ static void ept_set_mmio_spte_mask(void)
/*
* EPT Misconfigurations can be generated if the value of bits 2:0
* of an EPT paging-structure entry is 110b (write/execute).
- * Also, magic bits (0xffull << 49) is set to quickly identify mmio
+ * Also, magic bits (0x3ull << 62) is set to quickly identify mmio
* spte.
*/
- kvm_mmu_set_mmio_spte_mask(0xffull << 49 | 0x6ull);
+ kvm_mmu_set_mmio_spte_mask((0x3ull << 62) | 0x6ull);
}
/*
@@ -5366,10 +5378,14 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
ret = handle_mmio_page_fault_common(vcpu, gpa, true);
- if (likely(ret == 1))
+ if (likely(ret == RET_MMIO_PF_EMULATE))
return x86_emulate_instruction(vcpu, gpa, 0, NULL, 0) ==
EMULATE_DONE;
- if (unlikely(!ret))
+
+ if (unlikely(ret == RET_MMIO_PF_INVALID))
+ return kvm_mmu_page_fault(vcpu, gpa, 0, NULL, 0);
+
+ if (unlikely(ret == RET_MMIO_PF_RETRY))
return 1;
/* It is the real ept misconfig */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 292e6ca89f42..d21bce505315 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1193,20 +1193,37 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
elapsed = ns - kvm->arch.last_tsc_nsec;
if (vcpu->arch.virtual_tsc_khz) {
+ int faulted = 0;
+
/* n.b - signed multiplication and division required */
usdiff = data - kvm->arch.last_tsc_write;
#ifdef CONFIG_X86_64
usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz;
#else
/* do_div() only does unsigned */
- asm("idivl %2; xor %%edx, %%edx"
- : "=A"(usdiff)
- : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz));
+ asm("1: idivl %[divisor]\n"
+ "2: xor %%edx, %%edx\n"
+ " movl $0, %[faulted]\n"
+ "3:\n"
+ ".section .fixup,\"ax\"\n"
+ "4: movl $1, %[faulted]\n"
+ " jmp 3b\n"
+ ".previous\n"
+
+ _ASM_EXTABLE(1b, 4b)
+
+ : "=A"(usdiff), [faulted] "=r" (faulted)
+ : "A"(usdiff * 1000), [divisor] "rm"(vcpu->arch.virtual_tsc_khz));
+
#endif
do_div(elapsed, 1000);
usdiff -= elapsed;
if (usdiff < 0)
usdiff = -usdiff;
+
+ /* idivl overflow => difference is larger than USEC_PER_SEC */
+ if (faulted)
+ usdiff = USEC_PER_SEC;
} else
usdiff = USEC_PER_SEC; /* disable TSC match window below */
@@ -1587,6 +1604,30 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
return 0;
}
+/*
+ * kvmclock updates which are isolated to a given vcpu, such as
+ * vcpu->cpu migration, should not allow system_timestamp from
+ * the rest of the vcpus to remain static. Otherwise ntp frequency
+ * correction applies to one vcpu's system_timestamp but not
+ * the others.
+ *
+ * So in those cases, request a kvmclock update for all vcpus.
+ * The worst case for a remote vcpu to update its kvmclock
+ * is then bounded by maximum nohz sleep latency.
+ */
+
+static void kvm_gen_kvmclock_update(struct kvm_vcpu *v)
+{
+ int i;
+ struct kvm *kvm = v->kvm;
+ struct kvm_vcpu *vcpu;
+
+ kvm_for_each_vcpu(i, vcpu, kvm) {
+ set_bit(KVM_REQ_CLOCK_UPDATE, &vcpu->requests);
+ kvm_vcpu_kick(vcpu);
+ }
+}
+
static bool msr_mtrr_valid(unsigned msr)
{
switch (msr) {
@@ -1984,7 +2025,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
kvmclock_reset(vcpu);
vcpu->arch.time = data;
- kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+ kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
/* we verify if the enable bit is set... */
if (!(data & 1))
@@ -2701,7 +2742,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
* kvmclock on vcpu->cpu migration
*/
if (!vcpu->kvm->arch.use_master_clock || vcpu->cpu == -1)
- kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
+ kvm_make_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu);
if (vcpu->cpu != cpu)
kvm_migrate_timers(vcpu);
vcpu->cpu = cpu;
@@ -5238,7 +5279,13 @@ static void kvm_set_mmio_spte_mask(void)
* Set the reserved bits and the present bit of an paging-structure
* entry to generate page fault with PFER.RSV = 1.
*/
- mask = ((1ull << (62 - maxphyaddr + 1)) - 1) << maxphyaddr;
+ /* Mask the reserved physical address bits. */
+ mask = ((1ull << (51 - maxphyaddr + 1)) - 1) << maxphyaddr;
+
+ /* Bit 62 is always reserved for 32bit host. */
+ mask |= 0x3ull << 62;
+
+ /* Set the present bit. */
mask |= 1ull;
#ifdef CONFIG_X86_64
@@ -5498,13 +5545,6 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
char instruction[3];
unsigned long rip = kvm_rip_read(vcpu);
- /*
- * Blow out the MMU to ensure that no other VCPU has an active mapping
- * to ensure that the updated hypercall appears atomically across all
- * VCPUs.
- */
- kvm_mmu_zap_all(vcpu->kvm);
-
kvm_x86_ops->patch_hypercall(vcpu, instruction);
return emulator_write_emulated(ctxt, rip, instruction, 3, NULL);
@@ -5702,6 +5742,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
__kvm_migrate_timers(vcpu);
if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu))
kvm_gen_update_masterclock(vcpu->kvm);
+ if (kvm_check_request(KVM_REQ_GLOBAL_CLOCK_UPDATE, vcpu))
+ kvm_gen_kvmclock_update(vcpu);
if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) {
r = kvm_guest_time_update(vcpu);
if (unlikely(r))
@@ -6812,6 +6854,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
return -EINVAL;
INIT_LIST_HEAD(&kvm->arch.active_mmu_pages);
+ INIT_LIST_HEAD(&kvm->arch.zapped_obsolete_pages);
INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);
/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
@@ -7040,22 +7083,18 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
* If memory slot is created, or moved, we need to clear all
* mmio sptes.
*/
- if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) {
- kvm_mmu_zap_mmio_sptes(kvm);
- kvm_reload_remote_mmus(kvm);
- }
+ kvm_mmu_invalidate_mmio_sptes(kvm);
}
void kvm_arch_flush_shadow_all(struct kvm *kvm)
{
- kvm_mmu_zap_all(kvm);
- kvm_reload_remote_mmus(kvm);
+ kvm_mmu_invalidate_zap_all_pages(kvm);
}
void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
struct kvm_memory_slot *slot)
{
- kvm_arch_flush_shadow_all(kvm);
+ kvm_mmu_invalidate_zap_all_pages(kvm);
}
int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
@@ -7263,3 +7302,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intr_vmexit);
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_invlpga);
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_skinit);
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intercepts);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset);
diff --git a/arch/x86/lguest/Makefile b/arch/x86/lguest/Makefile
index 94e0e54056a9..8f38d577a2fa 100644
--- a/arch/x86/lguest/Makefile
+++ b/arch/x86/lguest/Makefile
@@ -1,2 +1,2 @@
-obj-y := i386_head.o boot.o
+obj-y := head_32.o boot.o
CFLAGS_boot.o := $(call cc-option, -fno-stack-protector)
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index d482bcaf61c1..6a22c19da663 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -882,9 +882,9 @@ int lguest_setup_irq(unsigned int irq)
* It would be far better for everyone if the Guest had its own clock, but
* until then the Host gives us the time on every interrupt.
*/
-static unsigned long lguest_get_wallclock(void)
+static void lguest_get_wallclock(struct timespec *now)
{
- return lguest_data.time.tv_sec;
+ *now = lguest_data.time;
}
/*
diff --git a/arch/x86/lguest/i386_head.S b/arch/x86/lguest/head_32.S
index 6ddfe4fc23c3..6ddfe4fc23c3 100644
--- a/arch/x86/lguest/i386_head.S
+++ b/arch/x86/lguest/head_32.S
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 252b8f5489ba..4500142bc4aa 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -1,6 +1,7 @@
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/swap.h> /* for totalram_pages */
+#include <linux/bootmem.h>
void *kmap(struct page *page)
{
@@ -121,6 +122,11 @@ void __init set_highmem_pages_init(void)
struct zone *zone;
int nid;
+ /*
+ * Explicitly reset zone->managed_pages because set_highmem_pages_init()
+ * is invoked before free_all_bootmem()
+ */
+ reset_all_zones_managed_pages();
for_each_zone(zone) {
unsigned long zone_start_pfn, zone_end_pfn;
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index ae1aa71d0115..7e73e8c69096 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -16,169 +16,6 @@
#include <asm/tlbflush.h>
#include <asm/pgalloc.h>
-static unsigned long page_table_shareable(struct vm_area_struct *svma,
- struct vm_area_struct *vma,
- unsigned long addr, pgoff_t idx)
-{
- unsigned long saddr = ((idx - svma->vm_pgoff) << PAGE_SHIFT) +
- svma->vm_start;
- unsigned long sbase = saddr & PUD_MASK;
- unsigned long s_end = sbase + PUD_SIZE;
-
- /* Allow segments to share if only one is marked locked */
- unsigned long vm_flags = vma->vm_flags & ~VM_LOCKED;
- unsigned long svm_flags = svma->vm_flags & ~VM_LOCKED;
-
- /*
- * match the virtual addresses, permission and the alignment of the
- * page table page.
- */
- if (pmd_index(addr) != pmd_index(saddr) ||
- vm_flags != svm_flags ||
- sbase < svma->vm_start || svma->vm_end < s_end)
- return 0;
-
- return saddr;
-}
-
-static int vma_shareable(struct vm_area_struct *vma, unsigned long addr)
-{
- unsigned long base = addr & PUD_MASK;
- unsigned long end = base + PUD_SIZE;
-
- /*
- * check on proper vm_flags and page table alignment
- */
- if (vma->vm_flags & VM_MAYSHARE &&
- vma->vm_start <= base && end <= vma->vm_end)
- return 1;
- return 0;
-}
-
-/*
- * Search for a shareable pmd page for hugetlb. In any case calls pmd_alloc()
- * and returns the corresponding pte. While this is not necessary for the
- * !shared pmd case because we can allocate the pmd later as well, it makes the
- * code much cleaner. pmd allocation is essential for the shared case because
- * pud has to be populated inside the same i_mmap_mutex section - otherwise
- * racing tasks could either miss the sharing (see huge_pte_offset) or select a
- * bad pmd for sharing.
- */
-static pte_t *
-huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
-{
- struct vm_area_struct *vma = find_vma(mm, addr);
- struct address_space *mapping = vma->vm_file->f_mapping;
- pgoff_t idx = ((addr - vma->vm_start) >> PAGE_SHIFT) +
- vma->vm_pgoff;
- struct vm_area_struct *svma;
- unsigned long saddr;
- pte_t *spte = NULL;
- pte_t *pte;
-
- if (!vma_shareable(vma, addr))
- return (pte_t *)pmd_alloc(mm, pud, addr);
-
- mutex_lock(&mapping->i_mmap_mutex);
- vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) {
- if (svma == vma)
- continue;
-
- saddr = page_table_shareable(svma, vma, addr, idx);
- if (saddr) {
- spte = huge_pte_offset(svma->vm_mm, saddr);
- if (spte) {
- get_page(virt_to_page(spte));
- break;
- }
- }
- }
-
- if (!spte)
- goto out;
-
- spin_lock(&mm->page_table_lock);
- if (pud_none(*pud))
- pud_populate(mm, pud, (pmd_t *)((unsigned long)spte & PAGE_MASK));
- else
- put_page(virt_to_page(spte));
- spin_unlock(&mm->page_table_lock);
-out:
- pte = (pte_t *)pmd_alloc(mm, pud, addr);
- mutex_unlock(&mapping->i_mmap_mutex);
- return pte;
-}
-
-/*
- * unmap huge page backed by shared pte.
- *
- * Hugetlb pte page is ref counted at the time of mapping. If pte is shared
- * indicated by page_count > 1, unmap is achieved by clearing pud and
- * decrementing the ref count. If count == 1, the pte page is not shared.
- *
- * called with vma->vm_mm->page_table_lock held.
- *
- * returns: 1 successfully unmapped a shared pte page
- * 0 the underlying pte page is not shared, or it is the last user
- */
-int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
-{
- pgd_t *pgd = pgd_offset(mm, *addr);
- pud_t *pud = pud_offset(pgd, *addr);
-
- BUG_ON(page_count(virt_to_page(ptep)) == 0);
- if (page_count(virt_to_page(ptep)) == 1)
- return 0;
-
- pud_clear(pud);
- put_page(virt_to_page(ptep));
- *addr = ALIGN(*addr, HPAGE_SIZE * PTRS_PER_PTE) - HPAGE_SIZE;
- return 1;
-}
-
-pte_t *huge_pte_alloc(struct mm_struct *mm,
- unsigned long addr, unsigned long sz)
-{
- pgd_t *pgd;
- pud_t *pud;
- pte_t *pte = NULL;
-
- pgd = pgd_offset(mm, addr);
- pud = pud_alloc(mm, pgd, addr);
- if (pud) {
- if (sz == PUD_SIZE) {
- pte = (pte_t *)pud;
- } else {
- BUG_ON(sz != PMD_SIZE);
- if (pud_none(*pud))
- pte = huge_pmd_share(mm, addr, pud);
- else
- pte = (pte_t *)pmd_alloc(mm, pud, addr);
- }
- }
- BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte));
-
- return pte;
-}
-
-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd = NULL;
-
- pgd = pgd_offset(mm, addr);
- if (pgd_present(*pgd)) {
- pud = pud_offset(pgd, addr);
- if (pud_present(*pud)) {
- if (pud_large(*pud))
- return (pte_t *)pud;
- pmd = pmd_offset(pud, addr);
- }
- }
- return (pte_t *) pmd;
-}
-
#if 0 /* This is just for testing */
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
@@ -240,30 +77,6 @@ int pud_huge(pud_t pud)
return !!(pud_val(pud) & _PAGE_PSE);
}
-struct page *
-follow_huge_pmd(struct mm_struct *mm, unsigned long address,
- pmd_t *pmd, int write)
-{
- struct page *page;
-
- page = pte_page(*(pte_t *)pmd);
- if (page)
- page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
- return page;
-}
-
-struct page *
-follow_huge_pud(struct mm_struct *mm, unsigned long address,
- pud_t *pud, int write)
-{
- struct page *page;
-
- page = pte_page(*(pte_t *)pud);
- if (page)
- page += ((address & ~PUD_MASK) >> PAGE_SHIFT);
- return page;
-}
-
#endif
/* x86_64 also uses this file */
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 1f34e9219775..2ec29ac78ae6 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -494,7 +494,6 @@ int devmem_is_allowed(unsigned long pagenr)
void free_init_pages(char *what, unsigned long begin, unsigned long end)
{
- unsigned long addr;
unsigned long begin_aligned, end_aligned;
/* Make sure boundaries are page aligned */
@@ -509,8 +508,6 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
if (begin >= end)
return;
- addr = begin;
-
/*
* If debugging page accesses then do not free this memory but
* mark them not present - any buggy init-section access will
@@ -529,18 +526,13 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
set_memory_nx(begin, (end - begin) >> PAGE_SHIFT);
set_memory_rw(begin, (end - begin) >> PAGE_SHIFT);
- printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
-
- for (; addr < end; addr += PAGE_SIZE) {
- memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- free_reserved_page(virt_to_page(addr));
- }
+ free_reserved_area((void *)begin, (void *)end, POISON_FREE_INITMEM, what);
#endif
}
void free_initmem(void)
{
- free_init_pages("unused kernel memory",
+ free_init_pages("unused kernel",
(unsigned long)(&__init_begin),
(unsigned long)(&__init_end));
}
@@ -566,7 +558,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
* - relocate_initrd()
* So here We can do PAGE_ALIGN() safely to get partial page to be freed
*/
- free_init_pages("initrd memory", start, PAGE_ALIGN(end));
+ free_init_pages("initrd", start, PAGE_ALIGN(end));
}
#endif
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 3ac7e319918d..4287f1ffba7e 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -660,10 +660,8 @@ void __init initmem_init(void)
highstart_pfn = max_low_pfn;
printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
pages_to_mb(highend_pfn - highstart_pfn));
- num_physpages = highend_pfn;
high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
#else
- num_physpages = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
#endif
@@ -671,7 +669,7 @@ void __init initmem_init(void)
sparse_memory_present_with_active_regions(0);
#ifdef CONFIG_FLATMEM
- max_mapnr = num_physpages;
+ max_mapnr = IS_ENABLED(CONFIG_HIGHMEM) ? highend_pfn : max_low_pfn;
#endif
__vmalloc_start_set = true;
@@ -739,9 +737,6 @@ static void __init test_wp_bit(void)
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
- int tmp;
-
pci_iommu_alloc();
#ifdef CONFIG_FLATMEM
@@ -759,32 +754,11 @@ void __init mem_init(void)
set_highmem_pages_init();
/* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem();
-
- reservedpages = 0;
- for (tmp = 0; tmp < max_low_pfn; tmp++)
- /*
- * Only count reserved RAM pages:
- */
- if (page_is_ram(tmp) && PageReserved(pfn_to_page(tmp)))
- reservedpages++;
+ free_all_bootmem();
after_bootmem = 1;
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
- printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
- "%dk reserved, %dk data, %dk init, %ldk highmem)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- num_physpages << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10,
- totalhigh_pages << (PAGE_SHIFT-10));
-
+ mem_init_print_info(NULL);
printk(KERN_INFO "virtual kernel memory layout:\n"
" fixmap : 0x%08lx - 0x%08lx (%4ld kB)\n"
#ifdef CONFIG_HIGHMEM
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index b3940b6b4d7e..104d56a9245f 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -712,36 +712,22 @@ EXPORT_SYMBOL_GPL(arch_add_memory);
static void __meminit free_pagetable(struct page *page, int order)
{
- struct zone *zone;
- bool bootmem = false;
unsigned long magic;
unsigned int nr_pages = 1 << order;
/* bootmem page has reserved flag */
if (PageReserved(page)) {
__ClearPageReserved(page);
- bootmem = true;
magic = (unsigned long)page->lru.next;
if (magic == SECTION_INFO || magic == MIX_SECTION_INFO) {
while (nr_pages--)
put_page_bootmem(page++);
} else
- __free_pages_bootmem(page, order);
+ while (nr_pages--)
+ free_reserved_page(page++);
} else
free_pages((unsigned long)page_address(page), order);
-
- /*
- * SECTION_INFO pages and MIX_SECTION_INFO pages
- * are all allocated by bootmem.
- */
- if (bootmem) {
- zone = page_zone(page);
- zone_span_writelock(zone);
- zone->present_pages += nr_pages;
- zone_span_writeunlock(zone);
- totalram_pages += nr_pages;
- }
}
static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
@@ -1058,9 +1044,6 @@ static void __init register_page_bootmem_info(void)
void __init mem_init(void)
{
- long codesize, reservedpages, datasize, initsize;
- unsigned long absent_pages;
-
pci_iommu_alloc();
/* clear_bss() already clear the empty_zero_page */
@@ -1068,29 +1051,14 @@ void __init mem_init(void)
register_page_bootmem_info();
/* this will put all memory onto the freelists */
- totalram_pages = free_all_bootmem();
-
- absent_pages = absent_pages_in_range(0, max_pfn);
- reservedpages = max_pfn - totalram_pages - absent_pages;
+ free_all_bootmem();
after_bootmem = 1;
- codesize = (unsigned long) &_etext - (unsigned long) &_text;
- datasize = (unsigned long) &_edata - (unsigned long) &_etext;
- initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
-
/* Register memory areas for /proc/kcore */
kclist_add(&kcore_vsyscall, (void *)VSYSCALL_START,
VSYSCALL_END - VSYSCALL_START, KCORE_OTHER);
- printk(KERN_INFO "Memory: %luk/%luk available (%ldk kernel code, "
- "%ldk absent, %ldk reserved, %ldk data, %ldk init)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- max_pfn << (PAGE_SHIFT-10),
- codesize >> 10,
- absent_pages << (PAGE_SHIFT-10),
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10);
+ mem_init_print_info(NULL);
}
#ifdef CONFIG_DEBUG_RODATA
@@ -1166,11 +1134,10 @@ void mark_rodata_ro(void)
set_memory_ro(start, (end-start) >> PAGE_SHIFT);
#endif
- free_init_pages("unused kernel memory",
+ free_init_pages("unused kernel",
(unsigned long) __va(__pa_symbol(text_end)),
(unsigned long) __va(__pa_symbol(rodata_start)));
-
- free_init_pages("unused kernel memory",
+ free_init_pages("unused kernel",
(unsigned long) __va(__pa_symbol(rodata_end)),
(unsigned long) __va(__pa_symbol(_sdata)));
}
diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c
index 845df6835f9f..62c29a5bfe26 100644
--- a/arch/x86/mm/mmap.c
+++ b/arch/x86/mm/mmap.c
@@ -115,10 +115,8 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
if (mmap_is_legacy()) {
mm->mmap_base = mmap_legacy_base();
mm->get_unmapped_area = arch_get_unmapped_area;
- mm->unmap_area = arch_unmap_area;
} else {
mm->mmap_base = mmap_base();
mm->get_unmapped_area = arch_get_unmapped_area_topdown;
- mm->unmap_area = arch_unmap_area_topdown;
}
}
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
index 73a6d7395bd3..0342d27ca798 100644
--- a/arch/x86/mm/numa_32.c
+++ b/arch/x86/mm/numa_32.c
@@ -83,10 +83,8 @@ void __init initmem_init(void)
highstart_pfn = max_low_pfn;
printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
pages_to_mb(highend_pfn - highstart_pfn));
- num_physpages = highend_pfn;
high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
#else
- num_physpages = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
#endif
printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index 17fda6a8b3c2..dfa537a03be1 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -240,7 +240,6 @@ static void pgd_mop_up_pmds(struct mm_struct *mm, pgd_t *pgdp)
static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[])
{
pud_t *pud;
- unsigned long addr;
int i;
if (PREALLOCATED_PMDS == 0) /* Work around gcc-3.4.x bug */
@@ -248,8 +247,7 @@ static void pgd_prepopulate_pmd(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmds[])
pud = pud_offset(pgd, 0);
- for (addr = i = 0; i < PREALLOCATED_PMDS;
- i++, pud++, addr += PUD_SIZE) {
+ for (i = 0; i < PREALLOCATED_PMDS; i++, pud++) {
pmd_t *pmd = pmds[i];
if (i >= KERNEL_PGD_BOUNDARY)
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index f66b54086ce5..79c216aa0e2b 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -12,6 +12,7 @@
#include <linux/netdevice.h>
#include <linux/filter.h>
#include <linux/if_vlan.h>
+#include <linux/random.h>
/*
* Conventions :
@@ -144,6 +145,39 @@ static int pkt_type_offset(void)
return -1;
}
+struct bpf_binary_header {
+ unsigned int pages;
+ /* Note : for security reasons, bpf code will follow a randomly
+ * sized amount of int3 instructions
+ */
+ u8 image[];
+};
+
+static struct bpf_binary_header *bpf_alloc_binary(unsigned int proglen,
+ u8 **image_ptr)
+{
+ unsigned int sz, hole;
+ struct bpf_binary_header *header;
+
+ /* Most of BPF filters are really small,
+ * but if some of them fill a page, allow at least
+ * 128 extra bytes to insert a random section of int3
+ */
+ sz = round_up(proglen + sizeof(*header) + 128, PAGE_SIZE);
+ header = module_alloc(sz);
+ if (!header)
+ return NULL;
+
+ memset(header, 0xcc, sz); /* fill whole space with int3 instructions */
+
+ header->pages = sz / PAGE_SIZE;
+ hole = sz - (proglen + sizeof(*header));
+
+ /* insert a random number of int3 instructions before BPF code */
+ *image_ptr = &header->image[prandom_u32() % hole];
+ return header;
+}
+
void bpf_jit_compile(struct sk_filter *fp)
{
u8 temp[64];
@@ -153,6 +187,7 @@ void bpf_jit_compile(struct sk_filter *fp)
int t_offset, f_offset;
u8 t_op, f_op, seen = 0, pass;
u8 *image = NULL;
+ struct bpf_binary_header *header = NULL;
u8 *func;
int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */
unsigned int cleanup_addr; /* epilogue code offset */
@@ -693,7 +728,7 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
if (unlikely(proglen + ilen > oldproglen)) {
pr_err("bpb_jit_compile fatal error\n");
kfree(addrs);
- module_free(NULL, image);
+ module_free(NULL, header);
return;
}
memcpy(image + proglen, temp, ilen);
@@ -717,10 +752,8 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
break;
}
if (proglen == oldproglen) {
- image = module_alloc(max_t(unsigned int,
- proglen,
- sizeof(struct work_struct)));
- if (!image)
+ header = bpf_alloc_binary(proglen, &image);
+ if (!header)
goto out;
}
oldproglen = proglen;
@@ -730,7 +763,8 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
bpf_jit_dump(flen, proglen, pass, image);
if (image) {
- bpf_flush_icache(image, image + proglen);
+ bpf_flush_icache(header, image + proglen);
+ set_memory_ro((unsigned long)header, header->pages);
fp->bpf_func = (void *)image;
}
out:
@@ -738,20 +772,13 @@ out:
return;
}
-static void jit_free_defer(struct work_struct *arg)
-{
- module_free(NULL, arg);
-}
-
-/* run from softirq, we must use a work_struct to call
- * module_free() from process context
- */
void bpf_jit_free(struct sk_filter *fp)
{
if (fp->bpf_func != sk_run_filter) {
- struct work_struct *work = (struct work_struct *)fp->bpf_func;
+ unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK;
+ struct bpf_binary_header *header = (void *)addr;
- INIT_WORK(work, jit_free_defer);
- schedule_work(work);
+ set_memory_rw(addr, header->pages);
+ module_free(NULL, header);
}
}
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 3e724256dbee..d641897a1f4e 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -324,14 +324,11 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
res->start = start;
res->end = end;
info->res_offset[info->res_num] = addr.translation_offset;
+ info->res_num++;
- if (!pci_use_crs) {
+ if (!pci_use_crs)
dev_printk(KERN_DEBUG, &info->bridge->dev,
"host bridge window %pR (ignored)\n", res);
- return AE_OK;
- }
-
- info->res_num++;
return AE_OK;
}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index b410b71bdcf7..c8d5577044bb 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -274,8 +274,9 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
return status;
}
-int efi_set_rtc_mmss(unsigned long nowtime)
+int efi_set_rtc_mmss(const struct timespec *now)
{
+ unsigned long nowtime = now->tv_sec;
efi_status_t status;
efi_time_t eft;
efi_time_cap_t cap;
@@ -310,7 +311,7 @@ int efi_set_rtc_mmss(unsigned long nowtime)
return 0;
}
-unsigned long efi_get_time(void)
+void efi_get_time(struct timespec *now)
{
efi_status_t status;
efi_time_t eft;
@@ -320,8 +321,9 @@ unsigned long efi_get_time(void)
if (status != EFI_SUCCESS)
pr_err("Oops: efitime: can't read time!\n");
- return mktime(eft.year, eft.month, eft.day, eft.hour,
- eft.minute, eft.second);
+ now->tv_sec = mktime(eft.year, eft.month, eft.day, eft.hour,
+ eft.minute, eft.second);
+ now->tv_nsec = 0;
}
/*
diff --git a/arch/x86/platform/mrst/vrtc.c b/arch/x86/platform/mrst/vrtc.c
index d62b0a3b5c14..5e355b134ba4 100644
--- a/arch/x86/platform/mrst/vrtc.c
+++ b/arch/x86/platform/mrst/vrtc.c
@@ -56,7 +56,7 @@ void vrtc_cmos_write(unsigned char val, unsigned char reg)
}
EXPORT_SYMBOL_GPL(vrtc_cmos_write);
-unsigned long vrtc_get_time(void)
+void vrtc_get_time(struct timespec *now)
{
u8 sec, min, hour, mday, mon;
unsigned long flags;
@@ -82,17 +82,18 @@ unsigned long vrtc_get_time(void)
printk(KERN_INFO "vRTC: sec: %d min: %d hour: %d day: %d "
"mon: %d year: %d\n", sec, min, hour, mday, mon, year);
- return mktime(year, mon, mday, hour, min, sec);
+ now->tv_sec = mktime(year, mon, mday, hour, min, sec);
+ now->tv_nsec = 0;
}
-int vrtc_set_mmss(unsigned long nowtime)
+int vrtc_set_mmss(const struct timespec *now)
{
unsigned long flags;
struct rtc_time tm;
int year;
int retval = 0;
- rtc_time_to_tm(nowtime, &tm);
+ rtc_time_to_tm(now->tv_sec, &tm);
if (!rtc_valid_tm(&tm) && tm.tm_year >= 72) {
/*
* tm.year is the number of years since 1900, and the
@@ -110,7 +111,7 @@ int vrtc_set_mmss(unsigned long nowtime)
} else {
printk(KERN_ERR
"%s: Invalid vRTC value: write of %lx to vRTC failed\n",
- __FUNCTION__, nowtime);
+ __FUNCTION__, now->tv_sec);
retval = -EINVAL;
}
return retval;
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index d99cae8147d1..c1367b29c3b1 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -40,11 +40,15 @@
cpumask_var_t xen_cpu_initialized_map;
-static DEFINE_PER_CPU(int, xen_resched_irq);
-static DEFINE_PER_CPU(int, xen_callfunc_irq);
-static DEFINE_PER_CPU(int, xen_callfuncsingle_irq);
-static DEFINE_PER_CPU(int, xen_irq_work);
-static DEFINE_PER_CPU(int, xen_debug_irq) = -1;
+struct xen_common_irq {
+ int irq;
+ char *name;
+};
+static DEFINE_PER_CPU(struct xen_common_irq, xen_resched_irq) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_callfunc_irq) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_callfuncsingle_irq) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_irq_work) = { .irq = -1 };
+static DEFINE_PER_CPU(struct xen_common_irq, xen_debug_irq) = { .irq = -1 };
static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
@@ -99,10 +103,47 @@ static void __cpuinit cpu_bringup_and_idle(void)
cpu_startup_entry(CPUHP_ONLINE);
}
+static void xen_smp_intr_free(unsigned int cpu)
+{
+ if (per_cpu(xen_resched_irq, cpu).irq >= 0) {
+ unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu).irq, NULL);
+ per_cpu(xen_resched_irq, cpu).irq = -1;
+ kfree(per_cpu(xen_resched_irq, cpu).name);
+ per_cpu(xen_resched_irq, cpu).name = NULL;
+ }
+ if (per_cpu(xen_callfunc_irq, cpu).irq >= 0) {
+ unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu).irq, NULL);
+ per_cpu(xen_callfunc_irq, cpu).irq = -1;
+ kfree(per_cpu(xen_callfunc_irq, cpu).name);
+ per_cpu(xen_callfunc_irq, cpu).name = NULL;
+ }
+ if (per_cpu(xen_debug_irq, cpu).irq >= 0) {
+ unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu).irq, NULL);
+ per_cpu(xen_debug_irq, cpu).irq = -1;
+ kfree(per_cpu(xen_debug_irq, cpu).name);
+ per_cpu(xen_debug_irq, cpu).name = NULL;
+ }
+ if (per_cpu(xen_callfuncsingle_irq, cpu).irq >= 0) {
+ unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu).irq,
+ NULL);
+ per_cpu(xen_callfuncsingle_irq, cpu).irq = -1;
+ kfree(per_cpu(xen_callfuncsingle_irq, cpu).name);
+ per_cpu(xen_callfuncsingle_irq, cpu).name = NULL;
+ }
+ if (xen_hvm_domain())
+ return;
+
+ if (per_cpu(xen_irq_work, cpu).irq >= 0) {
+ unbind_from_irqhandler(per_cpu(xen_irq_work, cpu).irq, NULL);
+ per_cpu(xen_irq_work, cpu).irq = -1;
+ kfree(per_cpu(xen_irq_work, cpu).name);
+ per_cpu(xen_irq_work, cpu).name = NULL;
+ }
+};
static int xen_smp_intr_init(unsigned int cpu)
{
int rc;
- const char *resched_name, *callfunc_name, *debug_name;
+ char *resched_name, *callfunc_name, *debug_name;
resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
@@ -113,7 +154,8 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
- per_cpu(xen_resched_irq, cpu) = rc;
+ per_cpu(xen_resched_irq, cpu).irq = rc;
+ per_cpu(xen_resched_irq, cpu).name = resched_name;
callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
@@ -124,7 +166,8 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
- per_cpu(xen_callfunc_irq, cpu) = rc;
+ per_cpu(xen_callfunc_irq, cpu).irq = rc;
+ per_cpu(xen_callfunc_irq, cpu).name = callfunc_name;
debug_name = kasprintf(GFP_KERNEL, "debug%d", cpu);
rc = bind_virq_to_irqhandler(VIRQ_DEBUG, cpu, xen_debug_interrupt,
@@ -132,7 +175,8 @@ static int xen_smp_intr_init(unsigned int cpu)
debug_name, NULL);
if (rc < 0)
goto fail;
- per_cpu(xen_debug_irq, cpu) = rc;
+ per_cpu(xen_debug_irq, cpu).irq = rc;
+ per_cpu(xen_debug_irq, cpu).name = debug_name;
callfunc_name = kasprintf(GFP_KERNEL, "callfuncsingle%d", cpu);
rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_SINGLE_VECTOR,
@@ -143,7 +187,8 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
- per_cpu(xen_callfuncsingle_irq, cpu) = rc;
+ per_cpu(xen_callfuncsingle_irq, cpu).irq = rc;
+ per_cpu(xen_callfuncsingle_irq, cpu).name = callfunc_name;
/*
* The IRQ worker on PVHVM goes through the native path and uses the
@@ -161,26 +206,13 @@ static int xen_smp_intr_init(unsigned int cpu)
NULL);
if (rc < 0)
goto fail;
- per_cpu(xen_irq_work, cpu) = rc;
+ per_cpu(xen_irq_work, cpu).irq = rc;
+ per_cpu(xen_irq_work, cpu).name = callfunc_name;
return 0;
fail:
- if (per_cpu(xen_resched_irq, cpu) >= 0)
- unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
- if (per_cpu(xen_callfunc_irq, cpu) >= 0)
- unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
- if (per_cpu(xen_debug_irq, cpu) >= 0)
- unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
- if (per_cpu(xen_callfuncsingle_irq, cpu) >= 0)
- unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu),
- NULL);
- if (xen_hvm_domain())
- return rc;
-
- if (per_cpu(xen_irq_work, cpu) >= 0)
- unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
-
+ xen_smp_intr_free(cpu);
return rc;
}
@@ -433,12 +465,7 @@ static void xen_cpu_die(unsigned int cpu)
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ/10);
}
- unbind_from_irqhandler(per_cpu(xen_resched_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_callfunc_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_debug_irq, cpu), NULL);
- unbind_from_irqhandler(per_cpu(xen_callfuncsingle_irq, cpu), NULL);
- if (!xen_hvm_domain())
- unbind_from_irqhandler(per_cpu(xen_irq_work, cpu), NULL);
+ xen_smp_intr_free(cpu);
xen_uninit_lock_cpu(cpu);
xen_teardown_timer(cpu);
}
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
index 3002ec1bb71a..a40f8508e760 100644
--- a/arch/x86/xen/spinlock.c
+++ b/arch/x86/xen/spinlock.c
@@ -7,6 +7,7 @@
#include <linux/debugfs.h>
#include <linux/log2.h>
#include <linux/gfp.h>
+#include <linux/slab.h>
#include <asm/paravirt.h>
@@ -165,6 +166,7 @@ static int xen_spin_trylock(struct arch_spinlock *lock)
return old == 0;
}
+static DEFINE_PER_CPU(char *, irq_name);
static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
@@ -362,7 +364,7 @@ static irqreturn_t dummy_handler(int irq, void *dev_id)
void __cpuinit xen_init_lock_cpu(int cpu)
{
int irq;
- const char *name;
+ char *name;
WARN(per_cpu(lock_kicker_irq, cpu) >= 0, "spinlock on CPU%d exists on IRQ%d!\n",
cpu, per_cpu(lock_kicker_irq, cpu));
@@ -385,6 +387,7 @@ void __cpuinit xen_init_lock_cpu(int cpu)
if (irq >= 0) {
disable_irq(irq); /* make sure it's never delivered */
per_cpu(lock_kicker_irq, cpu) = irq;
+ per_cpu(irq_name, cpu) = name;
}
printk("cpu %d spinlock event irq %d\n", cpu, irq);
@@ -401,6 +404,8 @@ void xen_uninit_lock_cpu(int cpu)
unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
per_cpu(lock_kicker_irq, cpu) = -1;
+ kfree(per_cpu(irq_name, cpu));
+ per_cpu(irq_name, cpu) = NULL;
}
void __init xen_init_spinlocks(void)
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 3d88bfdf9e1c..ee365895b06b 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -14,6 +14,8 @@
#include <linux/kernel_stat.h>
#include <linux/math64.h>
#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/pvclock_gtod.h>
#include <asm/pvclock.h>
#include <asm/xen/hypervisor.h>
@@ -36,9 +38,8 @@ static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
/* snapshots of runstate info */
static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
-/* unused ns of stolen and blocked time */
+/* unused ns of stolen time */
static DEFINE_PER_CPU(u64, xen_residual_stolen);
-static DEFINE_PER_CPU(u64, xen_residual_blocked);
/* return an consistent snapshot of 64-bit time/counter value */
static u64 get64(const u64 *p)
@@ -115,7 +116,7 @@ static void do_stolen_accounting(void)
{
struct vcpu_runstate_info state;
struct vcpu_runstate_info *snap;
- s64 blocked, runnable, offline, stolen;
+ s64 runnable, offline, stolen;
cputime_t ticks;
get_runstate_snapshot(&state);
@@ -125,7 +126,6 @@ static void do_stolen_accounting(void)
snap = &__get_cpu_var(xen_runstate_snapshot);
/* work out how much time the VCPU has not been runn*ing* */
- blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
@@ -141,17 +141,6 @@ static void do_stolen_accounting(void)
ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
__this_cpu_write(xen_residual_stolen, stolen);
account_steal_ticks(ticks);
-
- /* Add the appropriate number of ticks of blocked time,
- including any left-overs from last time. */
- blocked += __this_cpu_read(xen_residual_blocked);
-
- if (blocked < 0)
- blocked = 0;
-
- ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
- __this_cpu_write(xen_residual_blocked, blocked);
- account_idle_ticks(ticks);
}
/* Get the TSC speed from Xen */
@@ -191,34 +180,56 @@ static void xen_read_wallclock(struct timespec *ts)
put_cpu_var(xen_vcpu);
}
-static unsigned long xen_get_wallclock(void)
+static void xen_get_wallclock(struct timespec *now)
{
- struct timespec ts;
+ xen_read_wallclock(now);
+}
- xen_read_wallclock(&ts);
- return ts.tv_sec;
+static int xen_set_wallclock(const struct timespec *now)
+{
+ return -1;
}
-static int xen_set_wallclock(unsigned long now)
+static int xen_pvclock_gtod_notify(struct notifier_block *nb,
+ unsigned long was_set, void *priv)
{
+ /* Protected by the calling core code serialization */
+ static struct timespec next_sync;
+
struct xen_platform_op op;
- int rc;
+ struct timespec now;
- /* do nothing for domU */
- if (!xen_initial_domain())
- return -1;
+ now = __current_kernel_time();
+
+ /*
+ * We only take the expensive HV call when the clock was set
+ * or when the 11 minutes RTC synchronization time elapsed.
+ */
+ if (!was_set && timespec_compare(&now, &next_sync) < 0)
+ return NOTIFY_OK;
op.cmd = XENPF_settime;
- op.u.settime.secs = now;
- op.u.settime.nsecs = 0;
+ op.u.settime.secs = now.tv_sec;
+ op.u.settime.nsecs = now.tv_nsec;
op.u.settime.system_time = xen_clocksource_read();
- rc = HYPERVISOR_dom0_op(&op);
- WARN(rc != 0, "XENPF_settime failed: now=%ld\n", now);
+ (void)HYPERVISOR_dom0_op(&op);
+
+ /*
+ * Move the next drift compensation time 11 minutes
+ * ahead. That's emulating the sync_cmos_clock() update for
+ * the hardware RTC.
+ */
+ next_sync = now;
+ next_sync.tv_sec += 11 * 60;
- return rc;
+ return NOTIFY_OK;
}
+static struct notifier_block xen_pvclock_gtod_notifier = {
+ .notifier_call = xen_pvclock_gtod_notify,
+};
+
static struct clocksource xen_clocksource __read_mostly = {
.name = "xen",
.rating = 400,
@@ -377,11 +388,16 @@ static const struct clock_event_device xen_vcpuop_clockevent = {
static const struct clock_event_device *xen_clockevent =
&xen_timerop_clockevent;
-static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events) = { .irq = -1 };
+
+struct xen_clock_event_device {
+ struct clock_event_device evt;
+ char *name;
+};
+static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt.irq = -1 };
static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
{
- struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
+ struct clock_event_device *evt = &__get_cpu_var(xen_clock_events).evt;
irqreturn_t ret;
ret = IRQ_NONE;
@@ -395,14 +411,30 @@ static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
return ret;
}
+void xen_teardown_timer(int cpu)
+{
+ struct clock_event_device *evt;
+ BUG_ON(cpu == 0);
+ evt = &per_cpu(xen_clock_events, cpu).evt;
+
+ if (evt->irq >= 0) {
+ unbind_from_irqhandler(evt->irq, NULL);
+ evt->irq = -1;
+ kfree(per_cpu(xen_clock_events, cpu).name);
+ per_cpu(xen_clock_events, cpu).name = NULL;
+ }
+}
+
void xen_setup_timer(int cpu)
{
- const char *name;
+ char *name;
struct clock_event_device *evt;
int irq;
- evt = &per_cpu(xen_clock_events, cpu);
+ evt = &per_cpu(xen_clock_events, cpu).evt;
WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
+ if (evt->irq >= 0)
+ xen_teardown_timer(cpu);
printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
@@ -420,22 +452,15 @@ void xen_setup_timer(int cpu)
evt->cpumask = cpumask_of(cpu);
evt->irq = irq;
+ per_cpu(xen_clock_events, cpu).name = name;
}
-void xen_teardown_timer(int cpu)
-{
- struct clock_event_device *evt;
- BUG_ON(cpu == 0);
- evt = &per_cpu(xen_clock_events, cpu);
- unbind_from_irqhandler(evt->irq, NULL);
- evt->irq = -1;
-}
void xen_setup_cpu_clockevents(void)
{
BUG_ON(preemptible());
- clockevents_register_device(&__get_cpu_var(xen_clock_events));
+ clockevents_register_device(&__get_cpu_var(xen_clock_events).evt);
}
void xen_timer_resume(void)
@@ -480,6 +505,9 @@ static void __init xen_time_init(void)
xen_setup_runstate_info(cpu);
xen_setup_timer(cpu);
xen_setup_cpu_clockevents();
+
+ if (xen_initial_domain())
+ pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
}
void __init xen_init_time_ops(void)
@@ -492,7 +520,9 @@ void __init xen_init_time_ops(void)
x86_platform.calibrate_tsc = xen_tsc_khz;
x86_platform.get_wallclock = xen_get_wallclock;
- x86_platform.set_wallclock = xen_set_wallclock;
+ /* Dom0 uses the native method to set the hardware RTC. */
+ if (!xen_initial_domain())
+ x86_platform.set_wallclock = xen_set_wallclock;
}
#ifdef CONFIG_XEN_PVHVM
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 0a1b95f81a32..7ea6451a3a33 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -6,10 +6,12 @@ config XTENSA
select ARCH_WANT_FRAME_POINTERS
select HAVE_IDE
select GENERIC_ATOMIC64
+ select GENERIC_CLOCKEVENTS
select HAVE_GENERIC_HARDIRQS
select VIRT_TO_BUS
select GENERIC_IRQ_SHOW
select GENERIC_CPU_DEVICES
+ select GENERIC_SCHED_CLOCK
select MODULES_USE_ELF_RELA
select GENERIC_PCI_IOMAP
select ARCH_WANT_IPC_PARSE_VERSION
@@ -17,6 +19,7 @@ config XTENSA
select CLONE_BACKWARDS
select IRQ_DOMAIN
select HAVE_OPROFILE
+ select HAVE_FUNCTION_TRACER
help
Xtensa processors are 32-bit RISC machines designed by Tensilica
primarily for embedded systems. These processors are both
diff --git a/arch/xtensa/Kconfig.debug b/arch/xtensa/Kconfig.debug
index a34010e0e51c..af7da74d535f 100644
--- a/arch/xtensa/Kconfig.debug
+++ b/arch/xtensa/Kconfig.debug
@@ -2,6 +2,16 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
+config DEBUG_TLB_SANITY
+ bool "Debug TLB sanity"
+ depends on DEBUG_KERNEL
+ help
+ Enable this to turn on TLB sanity check on each entry to userspace.
+ This check can spot missing TLB invalidation/wrong PTE permissions/
+ premature page freeing.
+
+ If unsure, say N.
+
config LD_NO_RELAX
bool "Disable linker relaxation"
default n
diff --git a/arch/xtensa/boot/.gitignore b/arch/xtensa/boot/.gitignore
new file mode 100644
index 000000000000..be7655998b26
--- /dev/null
+++ b/arch/xtensa/boot/.gitignore
@@ -0,0 +1,3 @@
+uImage
+zImage.redboot
+*.dtb
diff --git a/arch/xtensa/boot/boot-elf/.gitignore b/arch/xtensa/boot/boot-elf/.gitignore
new file mode 100644
index 000000000000..5ff8fbb8561b
--- /dev/null
+++ b/arch/xtensa/boot/boot-elf/.gitignore
@@ -0,0 +1 @@
+boot.lds
diff --git a/arch/xtensa/boot/lib/.gitignore b/arch/xtensa/boot/lib/.gitignore
new file mode 100644
index 000000000000..1629a6167755
--- /dev/null
+++ b/arch/xtensa/boot/lib/.gitignore
@@ -0,0 +1,3 @@
+inffast.c
+inflate.c
+inftrees.c
diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile
index ad8952e8a07f..6868f2ca6af8 100644
--- a/arch/xtensa/boot/lib/Makefile
+++ b/arch/xtensa/boot/lib/Makefile
@@ -7,6 +7,13 @@ zlib := inffast.c inflate.c inftrees.c
lib-y += $(zlib:.c=.o) zmem.o
ccflags-y := -Ilib/zlib_inflate
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_inflate.o = -pg
+CFLAGS_REMOVE_zmem.o = -pg
+CFLAGS_REMOVE_inftrees.o = -pg
+CFLAGS_REMOVE_inffast.o = -pg
+endif
+
quiet_cmd_copy_zlib = COPY $@
cmd_copy_zlib = cat $< > $@
diff --git a/arch/xtensa/include/asm/bootparam.h b/arch/xtensa/include/asm/bootparam.h
index 0c25799facab..23392c5630ce 100644
--- a/arch/xtensa/include/asm/bootparam.h
+++ b/arch/xtensa/include/asm/bootparam.h
@@ -20,7 +20,7 @@
#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/
#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */
#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
-#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */
+#define BP_TAG_SERIAL_BAUDRATE 0x1004 /* baud rate of current console. */
#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */
#define BP_TAG_FDT 0x1006 /* flat device tree addr */
diff --git a/arch/xtensa/include/asm/cmpxchg.h b/arch/xtensa/include/asm/cmpxchg.h
index d9ab131bc1aa..370b26f38414 100644
--- a/arch/xtensa/include/asm/cmpxchg.h
+++ b/arch/xtensa/include/asm/cmpxchg.h
@@ -93,6 +93,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
((__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))
+#define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n))
/*
* xchg_u32
diff --git a/arch/xtensa/include/asm/delay.h b/arch/xtensa/include/asm/delay.h
index 61fc5faeb46c..3899610c1dff 100644
--- a/arch/xtensa/include/asm/delay.h
+++ b/arch/xtensa/include/asm/delay.h
@@ -12,7 +12,7 @@
#ifndef _XTENSA_DELAY_H
#define _XTENSA_DELAY_H
-#include <asm/processor.h>
+#include <asm/timex.h>
#include <asm/param.h>
extern unsigned long loops_per_jiffy;
@@ -24,24 +24,17 @@ static inline void __delay(unsigned long loops)
: "=r" (loops) : "0" (loops));
}
-static __inline__ u32 xtensa_get_ccount(void)
-{
- u32 ccount;
- asm volatile ("rsr %0, ccount\n" : "=r" (ccount));
- return ccount;
-}
-
/* For SMP/NUMA systems, change boot_cpu_data to something like
* local_cpu_data->... where local_cpu_data points to the current
* cpu. */
static __inline__ void udelay (unsigned long usecs)
{
- unsigned long start = xtensa_get_ccount();
+ unsigned long start = get_ccount();
unsigned long cycles = usecs * (loops_per_jiffy / (1000000UL / HZ));
/* Note: all variables are unsigned (can wrap around)! */
- while (((unsigned long)xtensa_get_ccount()) - start < cycles)
+ while (((unsigned long)get_ccount()) - start < cycles)
;
}
diff --git a/arch/xtensa/include/asm/ftrace.h b/arch/xtensa/include/asm/ftrace.h
index 36dc7a684397..73cc3f482304 100644
--- a/arch/xtensa/include/asm/ftrace.h
+++ b/arch/xtensa/include/asm/ftrace.h
@@ -13,6 +13,7 @@
#include <asm/processor.h>
#define HAVE_ARCH_CALLER_ADDR
+#ifndef __ASSEMBLY__
#define CALLER_ADDR0 ({ unsigned long a0, a1; \
__asm__ __volatile__ ( \
"mov %0, a0\n" \
@@ -24,10 +25,22 @@ extern unsigned long return_address(unsigned level);
#define CALLER_ADDR1 return_address(1)
#define CALLER_ADDR2 return_address(2)
#define CALLER_ADDR3 return_address(3)
-#else
+#else /* CONFIG_FRAME_POINTER */
#define CALLER_ADDR1 (0)
#define CALLER_ADDR2 (0)
#define CALLER_ADDR3 (0)
-#endif
+#endif /* CONFIG_FRAME_POINTER */
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define MCOUNT_ADDR ((unsigned long)(_mcount))
+#define MCOUNT_INSN_SIZE 3
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+#define mcount _mcount
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_FUNCTION_TRACER */
#endif /* _XTENSA_FTRACE_H */
diff --git a/arch/xtensa/include/asm/pgtable.h b/arch/xtensa/include/asm/pgtable.h
index 8f017eb309bd..0fdf5d043f82 100644
--- a/arch/xtensa/include/asm/pgtable.h
+++ b/arch/xtensa/include/asm/pgtable.h
@@ -5,7 +5,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Copyright (C) 2001 - 2007 Tensilica Inc.
+ * Copyright (C) 2001 - 2013 Tensilica Inc.
*/
#ifndef _XTENSA_PGTABLE_H
@@ -64,41 +64,82 @@
* Virtual memory area. We keep a distance to other memory regions to be
* on the safe side. We also use this area for cache aliasing.
*/
-
#define VMALLOC_START 0xC0000000
#define VMALLOC_END 0xC7FEFFFF
#define TLBTEMP_BASE_1 0xC7FF0000
#define TLBTEMP_BASE_2 0xC7FF8000
/*
- * Xtensa Linux config PTE layout (when present):
- * 31-12: PPN
- * 11-6: Software
- * 5-4: RING
- * 3-0: CA
+ * For the Xtensa architecture, the PTE layout is as follows:
+ *
+ * 31------12 11 10-9 8-6 5-4 3-2 1-0
+ * +-----------------------------------------+
+ * | | Software | HARDWARE |
+ * | PPN | ADW | RI |Attribute|
+ * +-----------------------------------------+
+ * pte_none | MBZ | 01 | 11 | 00 |
+ * +-----------------------------------------+
+ * present | PPN | 0 | 00 | ADW | RI | CA | wx |
+ * +- - - - - - - - - - - - - - - - - - - - -+
+ * (PAGE_NONE)| PPN | 0 | 00 | ADW | 01 | 11 | 11 |
+ * +-----------------------------------------+
+ * swap | index | type | 01 | 11 | 00 |
+ * +- - - - - - - - - - - - - - - - - - - - -+
+ * file | file offset | 01 | 11 | 10 |
+ * +-----------------------------------------+
+ *
+ * For T1050 hardware and earlier the layout differs for present and (PAGE_NONE)
+ * +-----------------------------------------+
+ * present | PPN | 0 | 00 | ADW | RI | CA | w1 |
+ * +-----------------------------------------+
+ * (PAGE_NONE)| PPN | 0 | 00 | ADW | 01 | 01 | 00 |
+ * +-----------------------------------------+
*
- * Similar to the Alpha and MIPS ports, we need to keep track of the ref
- * and mod bits in software. We have a software "you can read
- * from this page" bit, and a hardware one which actually lets the
- * process read from the page. On the same token we have a software
- * writable bit and the real hardware one which actually lets the
- * process write to the page.
+ * Legend:
+ * PPN Physical Page Number
+ * ADW software: accessed (young) / dirty / writable
+ * RI ring (0=privileged, 1=user, 2 and 3 are unused)
+ * CA cache attribute: 00 bypass, 01 writeback, 10 writethrough
+ * (11 is invalid and used to mark pages that are not present)
+ * w page is writable (hw)
+ * x page is executable (hw)
+ * index swap offset / PAGE_SIZE (bit 11-31: 21 bits -> 8 GB)
+ * (note that the index is always non-zero)
+ * type swap type (5 bits -> 32 types)
+ * file offset 26-bit offset into the file, in increments of PAGE_SIZE
*
- * See further below for PTE layout for swapped-out pages.
+ * Notes:
+ * - (PROT_NONE) is a special case of 'present' but causes an exception for
+ * any access (read, write, and execute).
+ * - 'multihit-exception' has the highest priority of all MMU exceptions,
+ * so the ring must be set to 'RING_USER' even for 'non-present' pages.
+ * - on older hardware, the exectuable flag was not supported and
+ * used as a 'valid' flag, so it needs to be always set.
+ * - we need to keep track of certain flags in software (dirty and young)
+ * to do this, we use write exceptions and have a separate software w-flag.
+ * - attribute value 1101 (and 1111 on T1050 and earlier) is reserved
*/
+#define _PAGE_ATTRIB_MASK 0xf
+
#define _PAGE_HW_EXEC (1<<0) /* hardware: page is executable */
#define _PAGE_HW_WRITE (1<<1) /* hardware: page is writable */
-#define _PAGE_FILE (1<<1) /* non-linear mapping, if !present */
-#define _PAGE_PROTNONE (3<<0) /* special case for VM_PROT_NONE */
-
-/* None of these cache modes include MP coherency: */
#define _PAGE_CA_BYPASS (0<<2) /* bypass, non-speculative */
#define _PAGE_CA_WB (1<<2) /* write-back */
#define _PAGE_CA_WT (2<<2) /* write-through */
#define _PAGE_CA_MASK (3<<2)
-#define _PAGE_INVALID (3<<2)
+#define _PAGE_CA_INVALID (3<<2)
+
+/* We use invalid attribute values to distinguish special pte entries */
+#if XCHAL_HW_VERSION_MAJOR < 2000
+#define _PAGE_HW_VALID 0x01 /* older HW needed this bit set */
+#define _PAGE_NONE 0x04
+#else
+#define _PAGE_HW_VALID 0x00
+#define _PAGE_NONE 0x0f
+#endif
+#define _PAGE_FILE (1<<1) /* file mapped page, only if !present */
#define _PAGE_USER (1<<4) /* user access (ring=1) */
@@ -108,19 +149,12 @@
#define _PAGE_DIRTY (1<<7) /* software: page dirty */
#define _PAGE_ACCESSED (1<<8) /* software: page accessed (read) */
-/* On older HW revisions, we always have to set bit 0 */
-#if XCHAL_HW_VERSION_MAJOR < 2000
-# define _PAGE_VALID (1<<0)
-#else
-# define _PAGE_VALID 0
-#endif
-
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_PRESENT (_PAGE_VALID | _PAGE_CA_WB | _PAGE_ACCESSED)
-
#ifdef CONFIG_MMU
-#define PAGE_NONE __pgprot(_PAGE_INVALID | _PAGE_USER | _PAGE_PROTNONE)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_PRESENT (_PAGE_HW_VALID | _PAGE_CA_WB | _PAGE_ACCESSED)
+
+#define PAGE_NONE __pgprot(_PAGE_NONE | _PAGE_USER)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER)
#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER)
@@ -132,9 +166,9 @@
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC)
#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED)
+# define _PAGE_DIRECTORY (_PAGE_HW_VALID | _PAGE_ACCESSED | _PAGE_CA_BYPASS)
#else
-# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB)
+# define _PAGE_DIRECTORY (_PAGE_HW_VALID | _PAGE_ACCESSED | _PAGE_CA_WB)
#endif
#else /* no mmu */
@@ -202,12 +236,16 @@ static inline void pgtable_cache_init(void) { }
/*
* pte status.
*/
-#define pte_none(pte) (pte_val(pte) == _PAGE_INVALID)
-#define pte_present(pte) \
- (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_INVALID) \
- || ((pte_val(pte) & _PAGE_PROTNONE) == _PAGE_PROTNONE))
+# define pte_none(pte) (pte_val(pte) == (_PAGE_CA_INVALID | _PAGE_USER))
+#if XCHAL_HW_VERSION_MAJOR < 2000
+# define pte_present(pte) ((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_CA_INVALID)
+#else
+# define pte_present(pte) \
+ (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_CA_INVALID) \
+ || ((pte_val(pte) & _PAGE_ATTRIB_MASK) == _PAGE_NONE))
+#endif
#define pte_clear(mm,addr,ptep) \
- do { update_pte(ptep, __pte(_PAGE_INVALID)); } while(0)
+ do { update_pte(ptep, __pte(_PAGE_CA_INVALID | _PAGE_USER)); } while (0)
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK)
@@ -328,35 +366,23 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
/*
- * Encode and decode a swap entry.
- *
- * Format of swap pte:
- * bit 0 MBZ
- * bit 1 page-file (must be zero)
- * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID)
- * bits 4 - 5 ring protection (must be 01: _PAGE_USER)
- * bits 6 - 10 swap type (5 bits -> 32 types)
- * bits 11 - 31 swap offset / PAGE_SIZE (21 bits -> 8GB)
-
- * Format of file pte:
- * bit 0 MBZ
- * bit 1 page-file (must be one: _PAGE_FILE)
- * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID)
- * bits 4 - 5 ring protection (must be 01: _PAGE_USER)
- * bits 6 - 31 file offset / PAGE_SIZE
+ * Encode and decode a swap and file entry.
*/
+#define SWP_TYPE_BITS 5
+#define MAX_SWAPFILES_CHECK() BUILD_BUG_ON(MAX_SWAPFILES_SHIFT > SWP_TYPE_BITS)
#define __swp_type(entry) (((entry).val >> 6) & 0x1f)
#define __swp_offset(entry) ((entry).val >> 11)
#define __swp_entry(type,offs) \
- ((swp_entry_t) {((type) << 6) | ((offs) << 11) | _PAGE_INVALID})
+ ((swp_entry_t){((type) << 6) | ((offs) << 11) | \
+ _PAGE_CA_INVALID | _PAGE_USER})
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
-#define PTE_FILE_MAX_BITS 28
-#define pte_to_pgoff(pte) (pte_val(pte) >> 4)
+#define PTE_FILE_MAX_BITS 26
+#define pte_to_pgoff(pte) (pte_val(pte) >> 6)
#define pgoff_to_pte(off) \
- ((pte_t) { ((off) << 4) | _PAGE_INVALID | _PAGE_FILE })
+ ((pte_t) { ((off) << 6) | _PAGE_CA_INVALID | _PAGE_FILE | _PAGE_USER })
#endif /* !defined (__ASSEMBLY__) */
diff --git a/arch/xtensa/include/asm/platform.h b/arch/xtensa/include/asm/platform.h
index ec098b68fb9a..32e98f27ce97 100644
--- a/arch/xtensa/include/asm/platform.h
+++ b/arch/xtensa/include/asm/platform.h
@@ -30,11 +30,6 @@ extern void platform_init(bp_tag_t*);
extern void platform_setup (char **);
/*
- * platform_init_irq is called from init_IRQ.
- */
-extern void platform_init_irq (void);
-
-/*
* platform_restart is called to restart the system.
*/
extern void platform_restart (void);
diff --git a/arch/xtensa/include/asm/timex.h b/arch/xtensa/include/asm/timex.h
index 3d35e5d0367e..69f901713fb6 100644
--- a/arch/xtensa/include/asm/timex.h
+++ b/arch/xtensa/include/asm/timex.h
@@ -35,19 +35,11 @@
# error "Bad timer number for Linux configurations!"
#endif
-#define LINUX_TIMER_MASK (1L << LINUX_TIMER_INT)
-
-#define CLOCK_TICK_RATE 1193180 /* (everyone is using this value) */
-#define CLOCK_TICK_FACTOR 20 /* Factor of both 10^6 and CLOCK_TICK_RATE */
-
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
-extern unsigned long ccount_per_jiffy;
-extern unsigned long nsec_per_ccount;
-#define CCOUNT_PER_JIFFY ccount_per_jiffy
-#define NSEC_PER_CCOUNT nsec_per_ccount
+extern unsigned long ccount_freq;
+#define CCOUNT_PER_JIFFY (ccount_freq / HZ)
#else
#define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ))
-#define NSEC_PER_CCOUNT (1000UL / CONFIG_XTENSA_CPU_CLOCK)
#endif
diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h
index a8f44f50e651..b21ace4fc9ba 100644
--- a/arch/xtensa/include/uapi/asm/socket.h
+++ b/arch/xtensa/include/uapi/asm/socket.h
@@ -85,4 +85,6 @@
#define SO_SELECT_ERR_QUEUE 45
+#define SO_LL 46
+
#endif /* _XTENSA_SOCKET_H */
diff --git a/arch/xtensa/kernel/.gitignore b/arch/xtensa/kernel/.gitignore
new file mode 100644
index 000000000000..c5f676c3c224
--- /dev/null
+++ b/arch/xtensa/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 1e7fc87a94bb..f90265ec1ccc 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -11,6 +11,7 @@ obj-y := align.o coprocessor.o entry.o irq.o pci-dma.o platform.o process.o \
obj-$(CONFIG_KGDB) += xtensa-stub.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
+obj-$(CONFIG_FUNCTION_TRACER) += mcount.o
AFLAGS_head.o += -mtext-section-literals
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 5082507d5631..9298742f0fd0 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -458,7 +458,7 @@ common_exception_return:
_bbsi.l a4, TIF_NEED_RESCHED, 3f
_bbsi.l a4, TIF_NOTIFY_RESUME, 2f
- _bbci.l a4, TIF_SIGPENDING, 4f
+ _bbci.l a4, TIF_SIGPENDING, 5f
2: l32i a4, a1, PT_DEPC
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
@@ -476,6 +476,13 @@ common_exception_return:
callx4 a4
j 1b
+5:
+#ifdef CONFIG_DEBUG_TLB_SANITY
+ l32i a4, a1, PT_DEPC
+ bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
+ movi a4, check_tlb_sanity
+ callx4 a4
+#endif
4: /* Restore optional registers. */
load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
@@ -1792,10 +1799,15 @@ ENTRY(fast_store_prohibited)
l32i a0, a0, 0
beqz a0, 2f
- /* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/
+ /*
+ * Note that we test _PAGE_WRITABLE_BIT only if PTE is present
+ * and is not PAGE_NONE. See pgtable.h for possible PTE layouts.
+ */
_PTE_OFFSET(a0, a1, a4)
l32i a4, a0, 0 # read pteval
+ movi a1, _PAGE_CA_INVALID
+ ball a4, a1, 2f
bbci.l a4, _PAGE_WRITABLE_BIT, 2f
movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index ef12c0e6fa25..7d740ebbe198 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -68,6 +68,15 @@ _SetupMMU:
#ifdef CONFIG_INITIALIZE_XTENSA_MMU_INSIDE_VMLINUX
initialize_mmu
+#if defined(CONFIG_MMU) && XCHAL_HAVE_PTP_MMU && XCHAL_HAVE_SPANNING_WAY
+ rsr a2, excsave1
+ movi a3, 0x08000000
+ bgeu a2, a3, 1f
+ movi a3, 0xd0000000
+ add a2, a2, a3
+ wsr a2, excsave1
+1:
+#endif
#endif
.end no-absolute-literals
diff --git a/arch/xtensa/kernel/mcount.S b/arch/xtensa/kernel/mcount.S
new file mode 100644
index 000000000000..0eeda2e4a25e
--- /dev/null
+++ b/arch/xtensa/kernel/mcount.S
@@ -0,0 +1,50 @@
+/*
+ * arch/xtensa/kernel/mcount.S
+ *
+ * Xtensa specific mcount support
+ *
+ * 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.
+ *
+ * Copyright (C) 2013 Tensilica Inc.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ftrace.h>
+
+/*
+ * Entry condition:
+ *
+ * a2: a0 of the caller
+ */
+
+ENTRY(_mcount)
+
+ entry a1, 16
+
+ movi a4, ftrace_trace_function
+ l32i a4, a4, 0
+ movi a3, ftrace_stub
+ bne a3, a4, 1f
+ retw
+
+1: xor a7, a2, a1
+ movi a3, 0x3fffffff
+ and a7, a7, a3
+ xor a7, a7, a1
+
+ xor a6, a0, a1
+ and a6, a6, a3
+ xor a6, a6, a1
+ addi a6, a6, -MCOUNT_INSN_SIZE
+ callx4 a4
+
+ retw
+
+ENDPROC(_mcount)
+
+ENTRY(ftrace_stub)
+ entry a1, 16
+ retw
+ENDPROC(ftrace_stub)
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 126c18839409..5b3403388d7f 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -77,9 +77,9 @@ pcibios_align_resource(void *data, const struct resource *res,
if (res->flags & IORESOURCE_IO) {
if (size > 0x100) {
- printk(KERN_ERR "PCI: I/O Region %s/%d too large"
- " (%ld bytes)\n", pci_name(dev),
- dev->resource - res, size);
+ pr_err("PCI: I/O Region %s/%d too large (%u bytes)\n",
+ pci_name(dev), dev->resource - res,
+ size);
}
if (start & 0x300)
@@ -174,7 +174,7 @@ static int __init pcibios_init(void)
struct pci_controller *pci_ctrl;
struct list_head resources;
struct pci_bus *bus;
- int next_busno = 0, i;
+ int next_busno = 0;
printk("PCI: Probing PCI hardware\n");
@@ -197,7 +197,7 @@ static int __init pcibios_init(void)
subsys_initcall(pcibios_init);
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void pcibios_fixup_bus(struct pci_bus *bus)
{
if (bus->parent) {
/* This is a subordinate bridge */
diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c
index 2bd6c351f37c..1cf008284dd2 100644
--- a/arch/xtensa/kernel/platform.c
+++ b/arch/xtensa/kernel/platform.c
@@ -29,7 +29,6 @@
*/
_F(void, setup, (char** cmd), { });
-_F(void, init_irq, (void), { });
_F(void, restart, (void), { while(1); });
_F(void, halt, (void), { while(1); });
_F(void, power_off, (void), { while(1); });
@@ -42,6 +41,6 @@ _F(void, pcibios_init, (void), { });
_F(void, calibrate_ccount, (void),
{
pr_err("ERROR: Cannot calibrate cpu frequency! Assuming 10MHz.\n");
- ccount_per_jiffy = 10 * (1000000UL/HZ);
+ ccount_freq = 10 * 1000000UL;
});
#endif
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 6dd25ecde3f5..42a8bba0b0ea 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -152,8 +152,8 @@ static int __init parse_tag_initrd(const bp_tag_t* tag)
{
meminfo_t* mi;
mi = (meminfo_t*)(tag->data);
- initrd_start = (void*)(mi->start);
- initrd_end = (void*)(mi->end);
+ initrd_start = __va(mi->start);
+ initrd_end = __va(mi->end);
return 0;
}
@@ -164,7 +164,7 @@ __tagtable(BP_TAG_INITRD, parse_tag_initrd);
static int __init parse_tag_fdt(const bp_tag_t *tag)
{
- dtb_start = (void *)(tag->data[0]);
+ dtb_start = __va(tag->data[0]);
return 0;
}
@@ -256,7 +256,7 @@ void __init early_init_devtree(void *params)
static void __init copy_devtree(void)
{
void *alloc = early_init_dt_alloc_memory_arch(
- be32_to_cpu(initial_boot_params->totalsize), 0);
+ be32_to_cpu(initial_boot_params->totalsize), 8);
if (alloc) {
memcpy(alloc, initial_boot_params,
be32_to_cpu(initial_boot_params->totalsize));
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index ffb474104311..bdbb17312526 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -23,13 +24,13 @@
#include <linux/profile.h>
#include <linux/delay.h>
#include <linux/irqdomain.h>
+#include <linux/sched_clock.h>
#include <asm/timex.h>
#include <asm/platform.h>
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
-unsigned long ccount_per_jiffy; /* per 1/HZ */
-unsigned long nsec_per_ccount; /* nsec per ccount increment */
+unsigned long ccount_freq; /* ccount Hz */
#endif
static cycle_t ccount_read(struct clocksource *cs)
@@ -37,6 +38,11 @@ static cycle_t ccount_read(struct clocksource *cs)
return (cycle_t)get_ccount();
}
+static u32 notrace ccount_sched_clock_read(void)
+{
+ return get_ccount();
+}
+
static struct clocksource ccount_clocksource = {
.name = "ccount",
.rating = 200,
@@ -44,29 +50,98 @@ static struct clocksource ccount_clocksource = {
.mask = CLOCKSOURCE_MASK(32),
};
+static int ccount_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *dev);
+static void ccount_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt);
+static struct ccount_timer_t {
+ struct clock_event_device evt;
+ int irq_enabled;
+} ccount_timer = {
+ .evt = {
+ .name = "ccount_clockevent",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 300,
+ .set_next_event = ccount_timer_set_next_event,
+ .set_mode = ccount_timer_set_mode,
+ },
+};
+
+static int ccount_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ unsigned long flags, next;
+ int ret = 0;
+
+ local_irq_save(flags);
+ next = get_ccount() + delta;
+ set_linux_timer(next);
+ if (next - get_ccount() > delta)
+ ret = -ETIME;
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static void ccount_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ struct ccount_timer_t *timer =
+ container_of(evt, struct ccount_timer_t, evt);
+
+ /*
+ * There is no way to disable the timer interrupt at the device level,
+ * only at the intenable register itself. Since enable_irq/disable_irq
+ * calls are nested, we need to make sure that these calls are
+ * balanced.
+ */
+ switch (mode) {
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ if (timer->irq_enabled) {
+ disable_irq(evt->irq);
+ timer->irq_enabled = 0;
+ }
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ case CLOCK_EVT_MODE_ONESHOT:
+ if (!timer->irq_enabled) {
+ enable_irq(evt->irq);
+ timer->irq_enabled = 1;
+ }
+ default:
+ break;
+ }
+}
+
static irqreturn_t timer_interrupt(int irq, void *dev_id);
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_TIMER,
.name = "timer",
+ .dev_id = &ccount_timer,
};
void __init time_init(void)
{
- unsigned int irq;
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
printk("Calibrating CPU frequency ");
platform_calibrate_ccount();
- printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ),
- (int)(ccount_per_jiffy/(10000/HZ))%100);
+ printk("%d.%02d MHz\n", (int)ccount_freq/1000000,
+ (int)(ccount_freq/10000)%100);
#endif
clocksource_register_hz(&ccount_clocksource, CCOUNT_PER_JIFFY * HZ);
- /* Initialize the linux timer interrupt. */
+ ccount_timer.evt.cpumask = cpumask_of(0);
+ ccount_timer.evt.irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
+ if (WARN(!ccount_timer.evt.irq, "error: can't map timer irq"))
+ return;
+ clockevents_config_and_register(&ccount_timer.evt, ccount_freq, 0xf,
+ 0xffffffff);
+ setup_irq(ccount_timer.evt.irq, &timer_irqaction);
+ ccount_timer.irq_enabled = 1;
- irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
- setup_irq(irq, &timer_irqaction);
- set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
+ setup_sched_clock(ccount_sched_clock_read, 32, ccount_freq);
}
/*
@@ -75,36 +150,14 @@ void __init time_init(void)
irqreturn_t timer_interrupt (int irq, void *dev_id)
{
+ struct ccount_timer_t *timer = dev_id;
+ struct clock_event_device *evt = &timer->evt;
- unsigned long next;
-
- next = get_linux_timer();
-
-again:
- while ((signed long)(get_ccount() - next) > 0) {
-
- profile_tick(CPU_PROFILING);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
-
- xtime_update(1); /* Linux handler in kernel/time/timekeeping */
-
- /* Note that writing CCOMPARE clears the interrupt. */
-
- next += CCOUNT_PER_JIFFY;
- set_linux_timer(next);
- }
+ evt->event_handler(evt);
/* Allow platform to do something useful (Wdog). */
-
platform_heartbeat();
- /* Make sure we didn't miss any tick... */
-
- if ((signed long)(get_ccount() - next) > 0)
- goto again;
-
return IRQ_HANDLED;
}
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 42c53c87c204..d8507f812f46 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -124,3 +124,7 @@ extern long common_exception_return;
extern long _spill_registers;
EXPORT_SYMBOL(common_exception_return);
EXPORT_SYMBOL(_spill_registers);
+
+#ifdef CONFIG_FUNCTION_TRACER
+EXPORT_SYMBOL(_mcount);
+#endif
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index bba125b4bb06..479d7537a32a 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -173,39 +173,16 @@ void __init zones_init(void)
void __init mem_init(void)
{
- unsigned long codesize, reservedpages, datasize, initsize;
- unsigned long highmemsize, tmp, ram;
-
- max_mapnr = num_physpages = max_low_pfn - ARCH_PFN_OFFSET;
+ max_mapnr = max_low_pfn - ARCH_PFN_OFFSET;
high_memory = (void *) __va(max_low_pfn << PAGE_SHIFT);
- highmemsize = 0;
#ifdef CONFIG_HIGHMEM
#error HIGHGMEM not implemented in init.c
#endif
- totalram_pages += free_all_bootmem();
-
- reservedpages = ram = 0;
- for (tmp = 0; tmp < max_mapnr; tmp++) {
- ram++;
- if (PageReserved(mem_map+tmp))
- reservedpages++;
- }
+ free_all_bootmem();
- codesize = (unsigned long) _etext - (unsigned long) _stext;
- datasize = (unsigned long) _edata - (unsigned long) _sdata;
- initsize = (unsigned long) __init_end - (unsigned long) __init_begin;
-
- printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
- "%ldk data, %ldk init %ldk highmem)\n",
- nr_free_pages() << (PAGE_SHIFT-10),
- ram << (PAGE_SHIFT-10),
- codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
- datasize >> 10,
- initsize >> 10,
- highmemsize >> 10);
+ mem_init_print_info(NULL);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -214,11 +191,11 @@ extern int initrd_is_mapped;
void free_initrd_mem(unsigned long start, unsigned long end)
{
if (initrd_is_mapped)
- free_reserved_area(start, end, 0, "initrd");
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
void free_initmem(void)
{
- free_initmem_default(0);
+ free_initmem_default(-1);
}
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
index 5411aa67c68e..ca9d2366bf12 100644
--- a/arch/xtensa/mm/tlb.c
+++ b/arch/xtensa/mm/tlb.c
@@ -64,7 +64,7 @@ void flush_tlb_mm(struct mm_struct *mm)
{
if (mm == current->active_mm) {
unsigned long flags;
- local_save_flags(flags);
+ local_irq_save(flags);
__get_new_mmu_context(mm);
__load_mmu_context(mm);
local_irq_restore(flags);
@@ -94,7 +94,7 @@ void flush_tlb_range (struct vm_area_struct *vma,
printk("[tlbrange<%02lx,%08lx,%08lx>]\n",
(unsigned long)mm->context, start, end);
#endif
- local_save_flags(flags);
+ local_irq_save(flags);
if (end-start + (PAGE_SIZE-1) <= _TLB_ENTRIES << PAGE_SHIFT) {
int oldpid = get_rasid_register();
@@ -128,9 +128,10 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
if(mm->context == NO_CONTEXT)
return;
- local_save_flags(flags);
+ local_irq_save(flags);
oldpid = get_rasid_register();
+ set_rasid_register(ASID_INSERT(mm->context));
if (vma->vm_flags & VM_EXEC)
invalidate_itlb_mapping(page);
@@ -140,3 +141,116 @@ void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
local_irq_restore(flags);
}
+
+#ifdef CONFIG_DEBUG_TLB_SANITY
+
+static unsigned get_pte_for_vaddr(unsigned vaddr)
+{
+ struct task_struct *task = get_current();
+ struct mm_struct *mm = task->mm;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (!mm)
+ mm = task->active_mm;
+ pgd = pgd_offset(mm, vaddr);
+ if (pgd_none_or_clear_bad(pgd))
+ return 0;
+ pmd = pmd_offset(pgd, vaddr);
+ if (pmd_none_or_clear_bad(pmd))
+ return 0;
+ pte = pte_offset_map(pmd, vaddr);
+ if (!pte)
+ return 0;
+ return pte_val(*pte);
+}
+
+enum {
+ TLB_SUSPICIOUS = 1,
+ TLB_INSANE = 2,
+};
+
+static void tlb_insane(void)
+{
+ BUG_ON(1);
+}
+
+static void tlb_suspicious(void)
+{
+ WARN_ON(1);
+}
+
+/*
+ * Check that TLB entries with kernel ASID (1) have kernel VMA (>= TASK_SIZE),
+ * and TLB entries with user ASID (>=4) have VMA < TASK_SIZE.
+ *
+ * Check that valid TLB entries either have the same PA as the PTE, or PTE is
+ * marked as non-present. Non-present PTE and the page with non-zero refcount
+ * and zero mapcount is normal for batched TLB flush operation. Zero refcount
+ * means that the page was freed prematurely. Non-zero mapcount is unusual,
+ * but does not necessary means an error, thus marked as suspicious.
+ */
+static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
+{
+ unsigned tlbidx = w | (e << PAGE_SHIFT);
+ unsigned r0 = dtlb ?
+ read_dtlb_virtual(tlbidx) : read_itlb_virtual(tlbidx);
+ unsigned vpn = (r0 & PAGE_MASK) | (e << PAGE_SHIFT);
+ unsigned pte = get_pte_for_vaddr(vpn);
+ unsigned mm_asid = (get_rasid_register() >> 8) & ASID_MASK;
+ unsigned tlb_asid = r0 & ASID_MASK;
+ bool kernel = tlb_asid == 1;
+ int rc = 0;
+
+ if (tlb_asid > 0 && ((vpn < TASK_SIZE) == kernel)) {
+ pr_err("%cTLB: way: %u, entry: %u, VPN %08x in %s PTE\n",
+ dtlb ? 'D' : 'I', w, e, vpn,
+ kernel ? "kernel" : "user");
+ rc |= TLB_INSANE;
+ }
+
+ if (tlb_asid == mm_asid) {
+ unsigned r1 = dtlb ? read_dtlb_translation(tlbidx) :
+ read_itlb_translation(tlbidx);
+ if ((pte ^ r1) & PAGE_MASK) {
+ pr_err("%cTLB: way: %u, entry: %u, mapping: %08x->%08x, PTE: %08x\n",
+ dtlb ? 'D' : 'I', w, e, r0, r1, pte);
+ if (pte == 0 || !pte_present(__pte(pte))) {
+ struct page *p = pfn_to_page(r1 >> PAGE_SHIFT);
+ pr_err("page refcount: %d, mapcount: %d\n",
+ page_count(p),
+ page_mapcount(p));
+ if (!page_count(p))
+ rc |= TLB_INSANE;
+ else if (page_mapped(p))
+ rc |= TLB_SUSPICIOUS;
+ } else {
+ rc |= TLB_INSANE;
+ }
+ }
+ }
+ return rc;
+}
+
+void check_tlb_sanity(void)
+{
+ unsigned long flags;
+ unsigned w, e;
+ int bug = 0;
+
+ local_irq_save(flags);
+ for (w = 0; w < DTLB_ARF_WAYS; ++w)
+ for (e = 0; e < (1 << XCHAL_DTLB_ARF_ENTRIES_LOG2); ++e)
+ bug |= check_tlb_entry(w, e, true);
+ for (w = 0; w < ITLB_ARF_WAYS; ++w)
+ for (e = 0; e < (1 << XCHAL_ITLB_ARF_ENTRIES_LOG2); ++e)
+ bug |= check_tlb_entry(w, e, false);
+ if (bug & TLB_INSANE)
+ tlb_insane();
+ if (bug & TLB_SUSPICIOUS)
+ tlb_suspicious();
+ local_irq_restore(flags);
+}
+
+#endif /* CONFIG_DEBUG_TLB_SANITY */
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c
index 7d0fea6d7f20..56f88b7afe2f 100644
--- a/arch/xtensa/platforms/iss/network.c
+++ b/arch/xtensa/platforms/iss/network.c
@@ -700,7 +700,7 @@ struct iss_net_init {
#define ERR KERN_ERR "iss_net_setup: "
-static int iss_net_setup(char *str)
+static int __init iss_net_setup(char *str)
{
struct iss_net_private *device = NULL;
struct iss_net_init *new;
diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c
index c0edb35424ce..8c6e819cd8ed 100644
--- a/arch/xtensa/platforms/iss/simdisk.c
+++ b/arch/xtensa/platforms/iss/simdisk.c
@@ -108,13 +108,13 @@ static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio)
sector_t sector = bio->bi_sector;
bio_for_each_segment(bvec, bio, i) {
- char *buffer = __bio_kmap_atomic(bio, i, KM_USER0);
+ char *buffer = __bio_kmap_atomic(bio, i);
unsigned len = bvec->bv_len >> SECTOR_SHIFT;
simdisk_transfer(dev, sector, len, buffer,
bio_data_dir(bio) == WRITE);
sector += len;
- __bio_kunmap_atomic(bio, KM_USER0);
+ __bio_kunmap_atomic(bio);
}
return 0;
}
diff --git a/arch/xtensa/platforms/xtfpga/setup.c b/arch/xtensa/platforms/xtfpga/setup.c
index 96ef8eeb064e..74bb74fa3f87 100644
--- a/arch/xtensa/platforms/xtfpga/setup.c
+++ b/arch/xtensa/platforms/xtfpga/setup.c
@@ -163,7 +163,7 @@ void platform_heartbeat(void)
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
-void platform_calibrate_ccount(void)
+void __init platform_calibrate_ccount(void)
{
long clk_freq = 0;
#ifdef CONFIG_OF
@@ -179,8 +179,7 @@ void platform_calibrate_ccount(void)
if (!clk_freq)
clk_freq = *(long *)XTFPGA_CLKFRQ_VADDR;
- ccount_per_jiffy = clk_freq / HZ;
- nsec_per_ccount = 1000000000UL / clk_freq;
+ ccount_freq = clk_freq;
}
#endif
diff --git a/arch/xtensa/variants/s6000/delay.c b/arch/xtensa/variants/s6000/delay.c
index 54b2b573f166..39154563ee17 100644
--- a/arch/xtensa/variants/s6000/delay.c
+++ b/arch/xtensa/variants/s6000/delay.c
@@ -1,4 +1,3 @@
-#include <asm/delay.h>
#include <asm/timex.h>
#include <asm/io.h>
#include <variant/hardware.h>
@@ -17,11 +16,10 @@ void platform_calibrate_ccount(void)
"1: l32i %0, %2, 0 ;"
" beq %0, %1, 1b ;"
: "=&a"(u) : "a"(t), "a"(tstamp));
- b = xtensa_get_ccount();
+ b = get_ccount();
if (i == LOOPS)
a = b;
} while (--i >= 0);
b -= a;
- nsec_per_ccount = (LOOPS * 10000) / b;
- ccount_per_jiffy = b * (100000UL / (LOOPS * HZ));
+ ccount_freq = b * (100000UL / LOOPS);
}
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index e8918ffaf96d..290792a13e3c 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -32,26 +32,6 @@ EXPORT_SYMBOL_GPL(blkcg_root);
static struct blkcg_policy *blkcg_policy[BLKCG_MAX_POLS];
-static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
- struct request_queue *q, bool update_hint);
-
-/**
- * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
- * @d_blkg: loop cursor pointing to the current descendant
- * @pos_cgrp: used for iteration
- * @p_blkg: target blkg to walk descendants of
- *
- * Walk @c_blkg through the descendants of @p_blkg. Must be used with RCU
- * read locked. If called under either blkcg or queue lock, the iteration
- * is guaranteed to include all and only online blkgs. The caller may
- * update @pos_cgrp by calling cgroup_rightmost_descendant() to skip
- * subtree.
- */
-#define blkg_for_each_descendant_pre(d_blkg, pos_cgrp, p_blkg) \
- cgroup_for_each_descendant_pre((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
- if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
- (p_blkg)->q, false)))
-
static bool blkcg_policy_enabled(struct request_queue *q,
const struct blkcg_policy *pol)
{
@@ -71,18 +51,8 @@ static void blkg_free(struct blkcg_gq *blkg)
if (!blkg)
return;
- for (i = 0; i < BLKCG_MAX_POLS; i++) {
- struct blkcg_policy *pol = blkcg_policy[i];
- struct blkg_policy_data *pd = blkg->pd[i];
-
- if (!pd)
- continue;
-
- if (pol && pol->pd_exit_fn)
- pol->pd_exit_fn(blkg);
-
- kfree(pd);
- }
+ for (i = 0; i < BLKCG_MAX_POLS; i++)
+ kfree(blkg->pd[i]);
blk_exit_rl(&blkg->rl);
kfree(blkg);
@@ -134,10 +104,6 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct request_queue *q,
blkg->pd[i] = pd;
pd->blkg = blkg;
pd->plid = i;
-
- /* invoke per-policy init */
- if (pol->pd_init_fn)
- pol->pd_init_fn(blkg);
}
return blkg;
@@ -158,8 +124,8 @@ err_free:
* @q's bypass state. If @update_hint is %true, the caller should be
* holding @q->queue_lock and lookup hint is updated on success.
*/
-static struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,
- struct request_queue *q, bool update_hint)
+struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, struct request_queue *q,
+ bool update_hint)
{
struct blkcg_gq *blkg;
@@ -234,16 +200,25 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg,
}
blkg = new_blkg;
- /* link parent and insert */
+ /* link parent */
if (blkcg_parent(blkcg)) {
blkg->parent = __blkg_lookup(blkcg_parent(blkcg), q, false);
if (WARN_ON_ONCE(!blkg->parent)) {
- blkg = ERR_PTR(-EINVAL);
+ ret = -EINVAL;
goto err_put_css;
}
blkg_get(blkg->parent);
}
+ /* invoke per-policy init */
+ for (i = 0; i < BLKCG_MAX_POLS; i++) {
+ struct blkcg_policy *pol = blkcg_policy[i];
+
+ if (blkg->pd[i] && pol->pd_init_fn)
+ pol->pd_init_fn(blkg);
+ }
+
+ /* insert */
spin_lock(&blkcg->lock);
ret = radix_tree_insert(&blkcg->blkg_tree, q->id, blkg);
if (likely(!ret)) {
@@ -394,30 +369,38 @@ static void blkg_destroy_all(struct request_queue *q)
q->root_rl.blkg = NULL;
}
-static void blkg_rcu_free(struct rcu_head *rcu_head)
+/*
+ * A group is RCU protected, but having an rcu lock does not mean that one
+ * can access all the fields of blkg and assume these are valid. For
+ * example, don't try to follow throtl_data and request queue links.
+ *
+ * Having a reference to blkg under an rcu allows accesses to only values
+ * local to groups like group stats and group rate limits.
+ */
+void __blkg_release_rcu(struct rcu_head *rcu_head)
{
- blkg_free(container_of(rcu_head, struct blkcg_gq, rcu_head));
-}
+ struct blkcg_gq *blkg = container_of(rcu_head, struct blkcg_gq, rcu_head);
+ int i;
+
+ /* tell policies that this one is being freed */
+ for (i = 0; i < BLKCG_MAX_POLS; i++) {
+ struct blkcg_policy *pol = blkcg_policy[i];
+
+ if (blkg->pd[i] && pol->pd_exit_fn)
+ pol->pd_exit_fn(blkg);
+ }
-void __blkg_release(struct blkcg_gq *blkg)
-{
/* release the blkcg and parent blkg refs this blkg has been holding */
css_put(&blkg->blkcg->css);
- if (blkg->parent)
+ if (blkg->parent) {
+ spin_lock_irq(blkg->q->queue_lock);
blkg_put(blkg->parent);
+ spin_unlock_irq(blkg->q->queue_lock);
+ }
- /*
- * A group is freed in rcu manner. But having an rcu lock does not
- * mean that one can access all the fields of blkg and assume these
- * are valid. For example, don't try to follow throtl_data and
- * request queue links.
- *
- * Having a reference to blkg under an rcu allows acess to only
- * values local to groups like group stats and group rate limits
- */
- call_rcu(&blkg->rcu_head, blkg_rcu_free);
+ blkg_free(blkg);
}
-EXPORT_SYMBOL_GPL(__blkg_release);
+EXPORT_SYMBOL_GPL(__blkg_release_rcu);
/*
* The next function used by blk_queue_for_each_rl(). It's a bit tricky
@@ -928,14 +911,6 @@ struct cgroup_subsys blkio_subsys = {
.subsys_id = blkio_subsys_id,
.base_cftypes = blkcg_files,
.module = THIS_MODULE,
-
- /*
- * blkio subsystem is utterly broken in terms of hierarchy support.
- * It treats all cgroups equally regardless of where they're
- * located in the hierarchy - all cgroups are treated as if they're
- * right below the root. Fix it and remove the following.
- */
- .broken_hierarchy = true,
};
EXPORT_SYMBOL_GPL(blkio_subsys);
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 4e595ee8c915..8056c03a3382 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -266,7 +266,7 @@ static inline void blkg_get(struct blkcg_gq *blkg)
blkg->refcnt++;
}
-void __blkg_release(struct blkcg_gq *blkg);
+void __blkg_release_rcu(struct rcu_head *rcu);
/**
* blkg_put - put a blkg reference
@@ -279,9 +279,43 @@ static inline void blkg_put(struct blkcg_gq *blkg)
lockdep_assert_held(blkg->q->queue_lock);
WARN_ON_ONCE(blkg->refcnt <= 0);
if (!--blkg->refcnt)
- __blkg_release(blkg);
+ call_rcu(&blkg->rcu_head, __blkg_release_rcu);
}
+struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, struct request_queue *q,
+ bool update_hint);
+
+/**
+ * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
+ * @d_blkg: loop cursor pointing to the current descendant
+ * @pos_cgrp: used for iteration
+ * @p_blkg: target blkg to walk descendants of
+ *
+ * Walk @c_blkg through the descendants of @p_blkg. Must be used with RCU
+ * read locked. If called under either blkcg or queue lock, the iteration
+ * is guaranteed to include all and only online blkgs. The caller may
+ * update @pos_cgrp by calling cgroup_rightmost_descendant() to skip
+ * subtree.
+ */
+#define blkg_for_each_descendant_pre(d_blkg, pos_cgrp, p_blkg) \
+ cgroup_for_each_descendant_pre((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
+ if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
+ (p_blkg)->q, false)))
+
+/**
+ * blkg_for_each_descendant_post - post-order walk of a blkg's descendants
+ * @d_blkg: loop cursor pointing to the current descendant
+ * @pos_cgrp: used for iteration
+ * @p_blkg: target blkg to walk descendants of
+ *
+ * Similar to blkg_for_each_descendant_pre() but performs post-order
+ * traversal instead. Synchronization rules are the same.
+ */
+#define blkg_for_each_descendant_post(d_blkg, pos_cgrp, p_blkg) \
+ cgroup_for_each_descendant_post((pos_cgrp), (p_blkg)->blkcg->css.cgroup) \
+ if (((d_blkg) = __blkg_lookup(cgroup_to_blkcg(pos_cgrp), \
+ (p_blkg)->q, false)))
+
/**
* blk_get_rl - get request_list to use
* @q: request_queue of interest
diff --git a/block/blk-core.c b/block/blk-core.c
index d5745b5833c9..93a18d1d3da8 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2315,6 +2315,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
case -EBADE:
error_type = "critical nexus";
break;
+ case -ETIMEDOUT:
+ error_type = "timeout";
+ break;
case -EIO:
default:
error_type = "I/O";
@@ -3180,7 +3183,8 @@ int __init blk_dev_init(void)
/* used for unplugging and affects IO latency/throughput - HIGHPRI */
kblockd_workqueue = alloc_workqueue("kblockd",
- WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
+ WQ_MEM_RECLAIM | WQ_HIGHPRI |
+ WQ_POWER_EFFICIENT, 0);
if (!kblockd_workqueue)
panic("Failed to create kblockd\n");
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index 9c4bb8266bc8..4464c823cff2 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -144,7 +144,8 @@ void put_io_context(struct io_context *ioc)
if (atomic_long_dec_and_test(&ioc->refcount)) {
spin_lock_irqsave(&ioc->lock, flags);
if (!hlist_empty(&ioc->icq_list))
- schedule_work(&ioc->release_work);
+ queue_work(system_power_efficient_wq,
+ &ioc->release_work);
else
free_ioc = true;
spin_unlock_irqrestore(&ioc->lock, flags);
diff --git a/block/blk-tag.c b/block/blk-tag.c
index cc345e1d8d4e..3f33d8672268 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -348,9 +348,16 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
*/
max_depth = bqt->max_depth;
if (!rq_is_sync(rq) && max_depth > 1) {
- max_depth -= 2;
- if (!max_depth)
+ switch (max_depth) {
+ case 2:
max_depth = 1;
+ break;
+ case 3:
+ max_depth = 2;
+ break;
+ default:
+ max_depth -= 2;
+ }
if (q->in_flight[BLK_RW_ASYNC] > max_depth)
return 1;
}
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 31146225f3d0..08a32dfd3844 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -25,18 +25,61 @@ static struct blkcg_policy blkcg_policy_throtl;
/* A workqueue to queue throttle related work */
static struct workqueue_struct *kthrotld_workqueue;
-static void throtl_schedule_delayed_work(struct throtl_data *td,
- unsigned long delay);
-
-struct throtl_rb_root {
- struct rb_root rb;
- struct rb_node *left;
- unsigned int count;
- unsigned long min_disptime;
+
+/*
+ * To implement hierarchical throttling, throtl_grps form a tree and bios
+ * are dispatched upwards level by level until they reach the top and get
+ * issued. When dispatching bios from the children and local group at each
+ * level, if the bios are dispatched into a single bio_list, there's a risk
+ * of a local or child group which can queue many bios at once filling up
+ * the list starving others.
+ *
+ * To avoid such starvation, dispatched bios are queued separately
+ * according to where they came from. When they are again dispatched to
+ * the parent, they're popped in round-robin order so that no single source
+ * hogs the dispatch window.
+ *
+ * throtl_qnode is used to keep the queued bios separated by their sources.
+ * Bios are queued to throtl_qnode which in turn is queued to
+ * throtl_service_queue and then dispatched in round-robin order.
+ *
+ * It's also used to track the reference counts on blkg's. A qnode always
+ * belongs to a throtl_grp and gets queued on itself or the parent, so
+ * incrementing the reference of the associated throtl_grp when a qnode is
+ * queued and decrementing when dequeued is enough to keep the whole blkg
+ * tree pinned while bios are in flight.
+ */
+struct throtl_qnode {
+ struct list_head node; /* service_queue->queued[] */
+ struct bio_list bios; /* queued bios */
+ struct throtl_grp *tg; /* tg this qnode belongs to */
};
-#define THROTL_RB_ROOT (struct throtl_rb_root) { .rb = RB_ROOT, .left = NULL, \
- .count = 0, .min_disptime = 0}
+struct throtl_service_queue {
+ struct throtl_service_queue *parent_sq; /* the parent service_queue */
+
+ /*
+ * Bios queued directly to this service_queue or dispatched from
+ * children throtl_grp's.
+ */
+ struct list_head queued[2]; /* throtl_qnode [READ/WRITE] */
+ unsigned int nr_queued[2]; /* number of queued bios */
+
+ /*
+ * RB tree of active children throtl_grp's, which are sorted by
+ * their ->disptime.
+ */
+ struct rb_root pending_tree; /* RB tree of active tgs */
+ struct rb_node *first_pending; /* first node in the tree */
+ unsigned int nr_pending; /* # queued in the tree */
+ unsigned long first_pending_disptime; /* disptime of the first tg */
+ struct timer_list pending_timer; /* fires on first_pending_disptime */
+};
+
+enum tg_state_flags {
+ THROTL_TG_PENDING = 1 << 0, /* on parent's pending tree */
+ THROTL_TG_WAS_EMPTY = 1 << 1, /* bio_lists[] became non-empty */
+};
#define rb_entry_tg(node) rb_entry((node), struct throtl_grp, rb_node)
@@ -52,9 +95,26 @@ struct throtl_grp {
/* must be the first member */
struct blkg_policy_data pd;
- /* active throtl group service_tree member */
+ /* active throtl group service_queue member */
struct rb_node rb_node;
+ /* throtl_data this group belongs to */
+ struct throtl_data *td;
+
+ /* this group's service queue */
+ struct throtl_service_queue service_queue;
+
+ /*
+ * qnode_on_self is used when bios are directly queued to this
+ * throtl_grp so that local bios compete fairly with bios
+ * dispatched from children. qnode_on_parent is used when bios are
+ * dispatched from this throtl_grp into its parent and will compete
+ * with the sibling qnode_on_parents and the parent's
+ * qnode_on_self.
+ */
+ struct throtl_qnode qnode_on_self[2];
+ struct throtl_qnode qnode_on_parent[2];
+
/*
* Dispatch time in jiffies. This is the estimated time when group
* will unthrottle and is ready to dispatch more bio. It is used as
@@ -64,11 +124,8 @@ struct throtl_grp {
unsigned int flags;
- /* Two lists for READ and WRITE */
- struct bio_list bio_lists[2];
-
- /* Number of queued bios on READ and WRITE lists */
- unsigned int nr_queued[2];
+ /* are there any throtl rules between this group and td? */
+ bool has_rules[2];
/* bytes per second rate limits */
uint64_t bps[2];
@@ -85,9 +142,6 @@ struct throtl_grp {
unsigned long slice_start[2];
unsigned long slice_end[2];
- /* Some throttle limits got updated for the group */
- int limits_changed;
-
/* Per cpu stats pointer */
struct tg_stats_cpu __percpu *stats_cpu;
@@ -98,7 +152,7 @@ struct throtl_grp {
struct throtl_data
{
/* service tree for active throtl groups */
- struct throtl_rb_root tg_service_tree;
+ struct throtl_service_queue service_queue;
struct request_queue *queue;
@@ -111,9 +165,7 @@ struct throtl_data
unsigned int nr_undestroyed_grps;
/* Work for dispatching throttled bios */
- struct delayed_work throtl_work;
-
- int limits_changed;
+ struct work_struct dispatch_work;
};
/* list and work item to allocate percpu group stats */
@@ -123,6 +175,8 @@ static LIST_HEAD(tg_stats_alloc_list);
static void tg_stats_alloc_fn(struct work_struct *);
static DECLARE_DELAYED_WORK(tg_stats_alloc_work, tg_stats_alloc_fn);
+static void throtl_pending_timer_fn(unsigned long arg);
+
static inline struct throtl_grp *pd_to_tg(struct blkg_policy_data *pd)
{
return pd ? container_of(pd, struct throtl_grp, pd) : NULL;
@@ -143,41 +197,65 @@ static inline struct throtl_grp *td_root_tg(struct throtl_data *td)
return blkg_to_tg(td->queue->root_blkg);
}
-enum tg_state_flags {
- THROTL_TG_FLAG_on_rr = 0, /* on round-robin busy list */
-};
-
-#define THROTL_TG_FNS(name) \
-static inline void throtl_mark_tg_##name(struct throtl_grp *tg) \
-{ \
- (tg)->flags |= (1 << THROTL_TG_FLAG_##name); \
-} \
-static inline void throtl_clear_tg_##name(struct throtl_grp *tg) \
-{ \
- (tg)->flags &= ~(1 << THROTL_TG_FLAG_##name); \
-} \
-static inline int throtl_tg_##name(const struct throtl_grp *tg) \
-{ \
- return ((tg)->flags & (1 << THROTL_TG_FLAG_##name)) != 0; \
+/**
+ * sq_to_tg - return the throl_grp the specified service queue belongs to
+ * @sq: the throtl_service_queue of interest
+ *
+ * Return the throtl_grp @sq belongs to. If @sq is the top-level one
+ * embedded in throtl_data, %NULL is returned.
+ */
+static struct throtl_grp *sq_to_tg(struct throtl_service_queue *sq)
+{
+ if (sq && sq->parent_sq)
+ return container_of(sq, struct throtl_grp, service_queue);
+ else
+ return NULL;
}
-THROTL_TG_FNS(on_rr);
+/**
+ * sq_to_td - return throtl_data the specified service queue belongs to
+ * @sq: the throtl_service_queue of interest
+ *
+ * A service_queue can be embeded in either a throtl_grp or throtl_data.
+ * Determine the associated throtl_data accordingly and return it.
+ */
+static struct throtl_data *sq_to_td(struct throtl_service_queue *sq)
+{
+ struct throtl_grp *tg = sq_to_tg(sq);
-#define throtl_log_tg(td, tg, fmt, args...) do { \
- char __pbuf[128]; \
+ if (tg)
+ return tg->td;
+ else
+ return container_of(sq, struct throtl_data, service_queue);
+}
+
+/**
+ * throtl_log - log debug message via blktrace
+ * @sq: the service_queue being reported
+ * @fmt: printf format string
+ * @args: printf args
+ *
+ * The messages are prefixed with "throtl BLKG_NAME" if @sq belongs to a
+ * throtl_grp; otherwise, just "throtl".
+ *
+ * TODO: this should be made a function and name formatting should happen
+ * after testing whether blktrace is enabled.
+ */
+#define throtl_log(sq, fmt, args...) do { \
+ struct throtl_grp *__tg = sq_to_tg((sq)); \
+ struct throtl_data *__td = sq_to_td((sq)); \
+ \
+ (void)__td; \
+ if ((__tg)) { \
+ char __pbuf[128]; \
\
- blkg_path(tg_to_blkg(tg), __pbuf, sizeof(__pbuf)); \
- blk_add_trace_msg((td)->queue, "throtl %s " fmt, __pbuf, ##args); \
+ blkg_path(tg_to_blkg(__tg), __pbuf, sizeof(__pbuf)); \
+ blk_add_trace_msg(__td->queue, "throtl %s " fmt, __pbuf, ##args); \
+ } else { \
+ blk_add_trace_msg(__td->queue, "throtl " fmt, ##args); \
+ } \
} while (0)
-#define throtl_log(td, fmt, args...) \
- blk_add_trace_msg((td)->queue, "throtl " fmt, ##args)
-
-static inline unsigned int total_nr_queued(struct throtl_data *td)
-{
- return td->nr_queued[0] + td->nr_queued[1];
-}
-
/*
* Worker for allocating per cpu stat for tgs. This is scheduled on the
* system_wq once there are some groups on the alloc_list waiting for
@@ -215,15 +293,141 @@ alloc_stats:
goto alloc_stats;
}
+static void throtl_qnode_init(struct throtl_qnode *qn, struct throtl_grp *tg)
+{
+ INIT_LIST_HEAD(&qn->node);
+ bio_list_init(&qn->bios);
+ qn->tg = tg;
+}
+
+/**
+ * throtl_qnode_add_bio - add a bio to a throtl_qnode and activate it
+ * @bio: bio being added
+ * @qn: qnode to add bio to
+ * @queued: the service_queue->queued[] list @qn belongs to
+ *
+ * Add @bio to @qn and put @qn on @queued if it's not already on.
+ * @qn->tg's reference count is bumped when @qn is activated. See the
+ * comment on top of throtl_qnode definition for details.
+ */
+static void throtl_qnode_add_bio(struct bio *bio, struct throtl_qnode *qn,
+ struct list_head *queued)
+{
+ bio_list_add(&qn->bios, bio);
+ if (list_empty(&qn->node)) {
+ list_add_tail(&qn->node, queued);
+ blkg_get(tg_to_blkg(qn->tg));
+ }
+}
+
+/**
+ * throtl_peek_queued - peek the first bio on a qnode list
+ * @queued: the qnode list to peek
+ */
+static struct bio *throtl_peek_queued(struct list_head *queued)
+{
+ struct throtl_qnode *qn = list_first_entry(queued, struct throtl_qnode, node);
+ struct bio *bio;
+
+ if (list_empty(queued))
+ return NULL;
+
+ bio = bio_list_peek(&qn->bios);
+ WARN_ON_ONCE(!bio);
+ return bio;
+}
+
+/**
+ * throtl_pop_queued - pop the first bio form a qnode list
+ * @queued: the qnode list to pop a bio from
+ * @tg_to_put: optional out argument for throtl_grp to put
+ *
+ * Pop the first bio from the qnode list @queued. After popping, the first
+ * qnode is removed from @queued if empty or moved to the end of @queued so
+ * that the popping order is round-robin.
+ *
+ * When the first qnode is removed, its associated throtl_grp should be put
+ * too. If @tg_to_put is NULL, this function automatically puts it;
+ * otherwise, *@tg_to_put is set to the throtl_grp to put and the caller is
+ * responsible for putting it.
+ */
+static struct bio *throtl_pop_queued(struct list_head *queued,
+ struct throtl_grp **tg_to_put)
+{
+ struct throtl_qnode *qn = list_first_entry(queued, struct throtl_qnode, node);
+ struct bio *bio;
+
+ if (list_empty(queued))
+ return NULL;
+
+ bio = bio_list_pop(&qn->bios);
+ WARN_ON_ONCE(!bio);
+
+ if (bio_list_empty(&qn->bios)) {
+ list_del_init(&qn->node);
+ if (tg_to_put)
+ *tg_to_put = qn->tg;
+ else
+ blkg_put(tg_to_blkg(qn->tg));
+ } else {
+ list_move_tail(&qn->node, queued);
+ }
+
+ return bio;
+}
+
+/* init a service_queue, assumes the caller zeroed it */
+static void throtl_service_queue_init(struct throtl_service_queue *sq,
+ struct throtl_service_queue *parent_sq)
+{
+ INIT_LIST_HEAD(&sq->queued[0]);
+ INIT_LIST_HEAD(&sq->queued[1]);
+ sq->pending_tree = RB_ROOT;
+ sq->parent_sq = parent_sq;
+ setup_timer(&sq->pending_timer, throtl_pending_timer_fn,
+ (unsigned long)sq);
+}
+
+static void throtl_service_queue_exit(struct throtl_service_queue *sq)
+{
+ del_timer_sync(&sq->pending_timer);
+}
+
static void throtl_pd_init(struct blkcg_gq *blkg)
{
struct throtl_grp *tg = blkg_to_tg(blkg);
+ struct throtl_data *td = blkg->q->td;
+ struct throtl_service_queue *parent_sq;
unsigned long flags;
+ int rw;
+
+ /*
+ * If sane_hierarchy is enabled, we switch to properly hierarchical
+ * behavior where limits on a given throtl_grp are applied to the
+ * whole subtree rather than just the group itself. e.g. If 16M
+ * read_bps limit is set on the root group, the whole system can't
+ * exceed 16M for the device.
+ *
+ * If sane_hierarchy is not enabled, the broken flat hierarchy
+ * behavior is retained where all throtl_grps are treated as if
+ * they're all separate root groups right below throtl_data.
+ * Limits of a group don't interact with limits of other groups
+ * regardless of the position of the group in the hierarchy.
+ */
+ parent_sq = &td->service_queue;
+
+ if (cgroup_sane_behavior(blkg->blkcg->css.cgroup) && blkg->parent)
+ parent_sq = &blkg_to_tg(blkg->parent)->service_queue;
+
+ throtl_service_queue_init(&tg->service_queue, parent_sq);
+
+ for (rw = READ; rw <= WRITE; rw++) {
+ throtl_qnode_init(&tg->qnode_on_self[rw], tg);
+ throtl_qnode_init(&tg->qnode_on_parent[rw], tg);
+ }
RB_CLEAR_NODE(&tg->rb_node);
- bio_list_init(&tg->bio_lists[0]);
- bio_list_init(&tg->bio_lists[1]);
- tg->limits_changed = false;
+ tg->td = td;
tg->bps[READ] = -1;
tg->bps[WRITE] = -1;
@@ -241,6 +445,30 @@ static void throtl_pd_init(struct blkcg_gq *blkg)
spin_unlock_irqrestore(&tg_stats_alloc_lock, flags);
}
+/*
+ * Set has_rules[] if @tg or any of its parents have limits configured.
+ * This doesn't require walking up to the top of the hierarchy as the
+ * parent's has_rules[] is guaranteed to be correct.
+ */
+static void tg_update_has_rules(struct throtl_grp *tg)
+{
+ struct throtl_grp *parent_tg = sq_to_tg(tg->service_queue.parent_sq);
+ int rw;
+
+ for (rw = READ; rw <= WRITE; rw++)
+ tg->has_rules[rw] = (parent_tg && parent_tg->has_rules[rw]) ||
+ (tg->bps[rw] != -1 || tg->iops[rw] != -1);
+}
+
+static void throtl_pd_online(struct blkcg_gq *blkg)
+{
+ /*
+ * We don't want new groups to escape the limits of its ancestors.
+ * Update has_rules[] after a new group is brought online.
+ */
+ tg_update_has_rules(blkg_to_tg(blkg));
+}
+
static void throtl_pd_exit(struct blkcg_gq *blkg)
{
struct throtl_grp *tg = blkg_to_tg(blkg);
@@ -251,6 +479,8 @@ static void throtl_pd_exit(struct blkcg_gq *blkg)
spin_unlock_irqrestore(&tg_stats_alloc_lock, flags);
free_percpu(tg->stats_cpu);
+
+ throtl_service_queue_exit(&tg->service_queue);
}
static void throtl_pd_reset_stats(struct blkcg_gq *blkg)
@@ -309,17 +539,18 @@ static struct throtl_grp *throtl_lookup_create_tg(struct throtl_data *td,
return tg;
}
-static struct throtl_grp *throtl_rb_first(struct throtl_rb_root *root)
+static struct throtl_grp *
+throtl_rb_first(struct throtl_service_queue *parent_sq)
{
/* Service tree is empty */
- if (!root->count)
+ if (!parent_sq->nr_pending)
return NULL;
- if (!root->left)
- root->left = rb_first(&root->rb);
+ if (!parent_sq->first_pending)
+ parent_sq->first_pending = rb_first(&parent_sq->pending_tree);
- if (root->left)
- return rb_entry_tg(root->left);
+ if (parent_sq->first_pending)
+ return rb_entry_tg(parent_sq->first_pending);
return NULL;
}
@@ -330,29 +561,30 @@ static void rb_erase_init(struct rb_node *n, struct rb_root *root)
RB_CLEAR_NODE(n);
}
-static void throtl_rb_erase(struct rb_node *n, struct throtl_rb_root *root)
+static void throtl_rb_erase(struct rb_node *n,
+ struct throtl_service_queue *parent_sq)
{
- if (root->left == n)
- root->left = NULL;
- rb_erase_init(n, &root->rb);
- --root->count;
+ if (parent_sq->first_pending == n)
+ parent_sq->first_pending = NULL;
+ rb_erase_init(n, &parent_sq->pending_tree);
+ --parent_sq->nr_pending;
}
-static void update_min_dispatch_time(struct throtl_rb_root *st)
+static void update_min_dispatch_time(struct throtl_service_queue *parent_sq)
{
struct throtl_grp *tg;
- tg = throtl_rb_first(st);
+ tg = throtl_rb_first(parent_sq);
if (!tg)
return;
- st->min_disptime = tg->disptime;
+ parent_sq->first_pending_disptime = tg->disptime;
}
-static void
-tg_service_tree_add(struct throtl_rb_root *st, struct throtl_grp *tg)
+static void tg_service_queue_add(struct throtl_grp *tg)
{
- struct rb_node **node = &st->rb.rb_node;
+ struct throtl_service_queue *parent_sq = tg->service_queue.parent_sq;
+ struct rb_node **node = &parent_sq->pending_tree.rb_node;
struct rb_node *parent = NULL;
struct throtl_grp *__tg;
unsigned long key = tg->disptime;
@@ -371,89 +603,135 @@ tg_service_tree_add(struct throtl_rb_root *st, struct throtl_grp *tg)
}
if (left)
- st->left = &tg->rb_node;
+ parent_sq->first_pending = &tg->rb_node;
rb_link_node(&tg->rb_node, parent, node);
- rb_insert_color(&tg->rb_node, &st->rb);
+ rb_insert_color(&tg->rb_node, &parent_sq->pending_tree);
}
-static void __throtl_enqueue_tg(struct throtl_data *td, struct throtl_grp *tg)
+static void __throtl_enqueue_tg(struct throtl_grp *tg)
{
- struct throtl_rb_root *st = &td->tg_service_tree;
+ tg_service_queue_add(tg);
+ tg->flags |= THROTL_TG_PENDING;
+ tg->service_queue.parent_sq->nr_pending++;
+}
- tg_service_tree_add(st, tg);
- throtl_mark_tg_on_rr(tg);
- st->count++;
+static void throtl_enqueue_tg(struct throtl_grp *tg)
+{
+ if (!(tg->flags & THROTL_TG_PENDING))
+ __throtl_enqueue_tg(tg);
}
-static void throtl_enqueue_tg(struct throtl_data *td, struct throtl_grp *tg)
+static void __throtl_dequeue_tg(struct throtl_grp *tg)
{
- if (!throtl_tg_on_rr(tg))
- __throtl_enqueue_tg(td, tg);
+ throtl_rb_erase(&tg->rb_node, tg->service_queue.parent_sq);
+ tg->flags &= ~THROTL_TG_PENDING;
}
-static void __throtl_dequeue_tg(struct throtl_data *td, struct throtl_grp *tg)
+static void throtl_dequeue_tg(struct throtl_grp *tg)
{
- throtl_rb_erase(&tg->rb_node, &td->tg_service_tree);
- throtl_clear_tg_on_rr(tg);
+ if (tg->flags & THROTL_TG_PENDING)
+ __throtl_dequeue_tg(tg);
}
-static void throtl_dequeue_tg(struct throtl_data *td, struct throtl_grp *tg)
+/* Call with queue lock held */
+static void throtl_schedule_pending_timer(struct throtl_service_queue *sq,
+ unsigned long expires)
{
- if (throtl_tg_on_rr(tg))
- __throtl_dequeue_tg(td, tg);
+ mod_timer(&sq->pending_timer, expires);
+ throtl_log(sq, "schedule timer. delay=%lu jiffies=%lu",
+ expires - jiffies, jiffies);
}
-static void throtl_schedule_next_dispatch(struct throtl_data *td)
+/**
+ * throtl_schedule_next_dispatch - schedule the next dispatch cycle
+ * @sq: the service_queue to schedule dispatch for
+ * @force: force scheduling
+ *
+ * Arm @sq->pending_timer so that the next dispatch cycle starts on the
+ * dispatch time of the first pending child. Returns %true if either timer
+ * is armed or there's no pending child left. %false if the current
+ * dispatch window is still open and the caller should continue
+ * dispatching.
+ *
+ * If @force is %true, the dispatch timer is always scheduled and this
+ * function is guaranteed to return %true. This is to be used when the
+ * caller can't dispatch itself and needs to invoke pending_timer
+ * unconditionally. Note that forced scheduling is likely to induce short
+ * delay before dispatch starts even if @sq->first_pending_disptime is not
+ * in the future and thus shouldn't be used in hot paths.
+ */
+static bool throtl_schedule_next_dispatch(struct throtl_service_queue *sq,
+ bool force)
{
- struct throtl_rb_root *st = &td->tg_service_tree;
+ /* any pending children left? */
+ if (!sq->nr_pending)
+ return true;
- /*
- * If there are more bios pending, schedule more work.
- */
- if (!total_nr_queued(td))
- return;
+ update_min_dispatch_time(sq);
- BUG_ON(!st->count);
+ /* is the next dispatch time in the future? */
+ if (force || time_after(sq->first_pending_disptime, jiffies)) {
+ throtl_schedule_pending_timer(sq, sq->first_pending_disptime);
+ return true;
+ }
- update_min_dispatch_time(st);
+ /* tell the caller to continue dispatching */
+ return false;
+}
- if (time_before_eq(st->min_disptime, jiffies))
- throtl_schedule_delayed_work(td, 0);
- else
- throtl_schedule_delayed_work(td, (st->min_disptime - jiffies));
+static inline void throtl_start_new_slice_with_credit(struct throtl_grp *tg,
+ bool rw, unsigned long start)
+{
+ tg->bytes_disp[rw] = 0;
+ tg->io_disp[rw] = 0;
+
+ /*
+ * Previous slice has expired. We must have trimmed it after last
+ * bio dispatch. That means since start of last slice, we never used
+ * that bandwidth. Do try to make use of that bandwidth while giving
+ * credit.
+ */
+ if (time_after_eq(start, tg->slice_start[rw]))
+ tg->slice_start[rw] = start;
+
+ tg->slice_end[rw] = jiffies + throtl_slice;
+ throtl_log(&tg->service_queue,
+ "[%c] new slice with credit start=%lu end=%lu jiffies=%lu",
+ rw == READ ? 'R' : 'W', tg->slice_start[rw],
+ tg->slice_end[rw], jiffies);
}
-static inline void
-throtl_start_new_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+static inline void throtl_start_new_slice(struct throtl_grp *tg, bool rw)
{
tg->bytes_disp[rw] = 0;
tg->io_disp[rw] = 0;
tg->slice_start[rw] = jiffies;
tg->slice_end[rw] = jiffies + throtl_slice;
- throtl_log_tg(td, tg, "[%c] new slice start=%lu end=%lu jiffies=%lu",
- rw == READ ? 'R' : 'W', tg->slice_start[rw],
- tg->slice_end[rw], jiffies);
+ throtl_log(&tg->service_queue,
+ "[%c] new slice start=%lu end=%lu jiffies=%lu",
+ rw == READ ? 'R' : 'W', tg->slice_start[rw],
+ tg->slice_end[rw], jiffies);
}
-static inline void throtl_set_slice_end(struct throtl_data *td,
- struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+static inline void throtl_set_slice_end(struct throtl_grp *tg, bool rw,
+ unsigned long jiffy_end)
{
tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
}
-static inline void throtl_extend_slice(struct throtl_data *td,
- struct throtl_grp *tg, bool rw, unsigned long jiffy_end)
+static inline void throtl_extend_slice(struct throtl_grp *tg, bool rw,
+ unsigned long jiffy_end)
{
tg->slice_end[rw] = roundup(jiffy_end, throtl_slice);
- throtl_log_tg(td, tg, "[%c] extend slice start=%lu end=%lu jiffies=%lu",
- rw == READ ? 'R' : 'W', tg->slice_start[rw],
- tg->slice_end[rw], jiffies);
+ throtl_log(&tg->service_queue,
+ "[%c] extend slice start=%lu end=%lu jiffies=%lu",
+ rw == READ ? 'R' : 'W', tg->slice_start[rw],
+ tg->slice_end[rw], jiffies);
}
/* Determine if previously allocated or extended slice is complete or not */
-static bool
-throtl_slice_used(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+static bool throtl_slice_used(struct throtl_grp *tg, bool rw)
{
if (time_in_range(jiffies, tg->slice_start[rw], tg->slice_end[rw]))
return 0;
@@ -462,8 +740,7 @@ throtl_slice_used(struct throtl_data *td, struct throtl_grp *tg, bool rw)
}
/* Trim the used slices and adjust slice start accordingly */
-static inline void
-throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
+static inline void throtl_trim_slice(struct throtl_grp *tg, bool rw)
{
unsigned long nr_slices, time_elapsed, io_trim;
u64 bytes_trim, tmp;
@@ -475,7 +752,7 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
* renewed. Don't try to trim the slice if slice is used. A new
* slice will start when appropriate.
*/
- if (throtl_slice_used(td, tg, rw))
+ if (throtl_slice_used(tg, rw))
return;
/*
@@ -486,7 +763,7 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
* is bad because it does not allow new slice to start.
*/
- throtl_set_slice_end(td, tg, rw, jiffies + throtl_slice);
+ throtl_set_slice_end(tg, rw, jiffies + throtl_slice);
time_elapsed = jiffies - tg->slice_start[rw];
@@ -515,14 +792,14 @@ throtl_trim_slice(struct throtl_data *td, struct throtl_grp *tg, bool rw)
tg->slice_start[rw] += nr_slices * throtl_slice;
- throtl_log_tg(td, tg, "[%c] trim slice nr=%lu bytes=%llu io=%lu"
- " start=%lu end=%lu jiffies=%lu",
- rw == READ ? 'R' : 'W', nr_slices, bytes_trim, io_trim,
- tg->slice_start[rw], tg->slice_end[rw], jiffies);
+ throtl_log(&tg->service_queue,
+ "[%c] trim slice nr=%lu bytes=%llu io=%lu start=%lu end=%lu jiffies=%lu",
+ rw == READ ? 'R' : 'W', nr_slices, bytes_trim, io_trim,
+ tg->slice_start[rw], tg->slice_end[rw], jiffies);
}
-static bool tg_with_in_iops_limit(struct throtl_data *td, struct throtl_grp *tg,
- struct bio *bio, unsigned long *wait)
+static bool tg_with_in_iops_limit(struct throtl_grp *tg, struct bio *bio,
+ unsigned long *wait)
{
bool rw = bio_data_dir(bio);
unsigned int io_allowed;
@@ -571,8 +848,8 @@ static bool tg_with_in_iops_limit(struct throtl_data *td, struct throtl_grp *tg,
return 0;
}
-static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
- struct bio *bio, unsigned long *wait)
+static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio,
+ unsigned long *wait)
{
bool rw = bio_data_dir(bio);
u64 bytes_allowed, extra_bytes, tmp;
@@ -613,18 +890,12 @@ static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
return 0;
}
-static bool tg_no_rule_group(struct throtl_grp *tg, bool rw) {
- if (tg->bps[rw] == -1 && tg->iops[rw] == -1)
- return 1;
- return 0;
-}
-
/*
* Returns whether one can dispatch a bio or not. Also returns approx number
* of jiffies to wait before this bio is with-in IO rate and can be dispatched
*/
-static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
- struct bio *bio, unsigned long *wait)
+static bool tg_may_dispatch(struct throtl_grp *tg, struct bio *bio,
+ unsigned long *wait)
{
bool rw = bio_data_dir(bio);
unsigned long bps_wait = 0, iops_wait = 0, max_wait = 0;
@@ -635,7 +906,8 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
* this function with a different bio if there are other bios
* queued.
*/
- BUG_ON(tg->nr_queued[rw] && bio != bio_list_peek(&tg->bio_lists[rw]));
+ BUG_ON(tg->service_queue.nr_queued[rw] &&
+ bio != throtl_peek_queued(&tg->service_queue.queued[rw]));
/* If tg->bps = -1, then BW is unlimited */
if (tg->bps[rw] == -1 && tg->iops[rw] == -1) {
@@ -649,15 +921,15 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
* existing slice to make sure it is at least throtl_slice interval
* long since now.
*/
- if (throtl_slice_used(td, tg, rw))
- throtl_start_new_slice(td, tg, rw);
+ if (throtl_slice_used(tg, rw))
+ throtl_start_new_slice(tg, rw);
else {
if (time_before(tg->slice_end[rw], jiffies + throtl_slice))
- throtl_extend_slice(td, tg, rw, jiffies + throtl_slice);
+ throtl_extend_slice(tg, rw, jiffies + throtl_slice);
}
- if (tg_with_in_bps_limit(td, tg, bio, &bps_wait)
- && tg_with_in_iops_limit(td, tg, bio, &iops_wait)) {
+ if (tg_with_in_bps_limit(tg, bio, &bps_wait) &&
+ tg_with_in_iops_limit(tg, bio, &iops_wait)) {
if (wait)
*wait = 0;
return 1;
@@ -669,7 +941,7 @@ static bool tg_may_dispatch(struct throtl_data *td, struct throtl_grp *tg,
*wait = max_wait;
if (time_before(tg->slice_end[rw], jiffies + max_wait))
- throtl_extend_slice(td, tg, rw, jiffies + max_wait);
+ throtl_extend_slice(tg, rw, jiffies + max_wait);
return 0;
}
@@ -708,65 +980,136 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
tg->bytes_disp[rw] += bio->bi_size;
tg->io_disp[rw]++;
- throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, bio->bi_rw);
+ /*
+ * REQ_THROTTLED is used to prevent the same bio to be throttled
+ * more than once as a throttled bio will go through blk-throtl the
+ * second time when it eventually gets issued. Set it when a bio
+ * is being charged to a tg.
+ *
+ * Dispatch stats aren't recursive and each @bio should only be
+ * accounted by the @tg it was originally associated with. Let's
+ * update the stats when setting REQ_THROTTLED for the first time
+ * which is guaranteed to be for the @bio's original tg.
+ */
+ if (!(bio->bi_rw & REQ_THROTTLED)) {
+ bio->bi_rw |= REQ_THROTTLED;
+ throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size,
+ bio->bi_rw);
+ }
}
-static void throtl_add_bio_tg(struct throtl_data *td, struct throtl_grp *tg,
- struct bio *bio)
+/**
+ * throtl_add_bio_tg - add a bio to the specified throtl_grp
+ * @bio: bio to add
+ * @qn: qnode to use
+ * @tg: the target throtl_grp
+ *
+ * Add @bio to @tg's service_queue using @qn. If @qn is not specified,
+ * tg->qnode_on_self[] is used.
+ */
+static void throtl_add_bio_tg(struct bio *bio, struct throtl_qnode *qn,
+ struct throtl_grp *tg)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
bool rw = bio_data_dir(bio);
- bio_list_add(&tg->bio_lists[rw], bio);
- /* Take a bio reference on tg */
- blkg_get(tg_to_blkg(tg));
- tg->nr_queued[rw]++;
- td->nr_queued[rw]++;
- throtl_enqueue_tg(td, tg);
+ if (!qn)
+ qn = &tg->qnode_on_self[rw];
+
+ /*
+ * If @tg doesn't currently have any bios queued in the same
+ * direction, queueing @bio can change when @tg should be
+ * dispatched. Mark that @tg was empty. This is automatically
+ * cleaered on the next tg_update_disptime().
+ */
+ if (!sq->nr_queued[rw])
+ tg->flags |= THROTL_TG_WAS_EMPTY;
+
+ throtl_qnode_add_bio(bio, qn, &sq->queued[rw]);
+
+ sq->nr_queued[rw]++;
+ throtl_enqueue_tg(tg);
}
-static void tg_update_disptime(struct throtl_data *td, struct throtl_grp *tg)
+static void tg_update_disptime(struct throtl_grp *tg)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
unsigned long read_wait = -1, write_wait = -1, min_wait = -1, disptime;
struct bio *bio;
- if ((bio = bio_list_peek(&tg->bio_lists[READ])))
- tg_may_dispatch(td, tg, bio, &read_wait);
+ if ((bio = throtl_peek_queued(&sq->queued[READ])))
+ tg_may_dispatch(tg, bio, &read_wait);
- if ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
- tg_may_dispatch(td, tg, bio, &write_wait);
+ if ((bio = throtl_peek_queued(&sq->queued[WRITE])))
+ tg_may_dispatch(tg, bio, &write_wait);
min_wait = min(read_wait, write_wait);
disptime = jiffies + min_wait;
/* Update dispatch time */
- throtl_dequeue_tg(td, tg);
+ throtl_dequeue_tg(tg);
tg->disptime = disptime;
- throtl_enqueue_tg(td, tg);
+ throtl_enqueue_tg(tg);
+
+ /* see throtl_add_bio_tg() */
+ tg->flags &= ~THROTL_TG_WAS_EMPTY;
}
-static void tg_dispatch_one_bio(struct throtl_data *td, struct throtl_grp *tg,
- bool rw, struct bio_list *bl)
+static void start_parent_slice_with_credit(struct throtl_grp *child_tg,
+ struct throtl_grp *parent_tg, bool rw)
{
- struct bio *bio;
+ if (throtl_slice_used(parent_tg, rw)) {
+ throtl_start_new_slice_with_credit(parent_tg, rw,
+ child_tg->slice_start[rw]);
+ }
+
+}
- bio = bio_list_pop(&tg->bio_lists[rw]);
- tg->nr_queued[rw]--;
- /* Drop bio reference on blkg */
- blkg_put(tg_to_blkg(tg));
+static void tg_dispatch_one_bio(struct throtl_grp *tg, bool rw)
+{
+ struct throtl_service_queue *sq = &tg->service_queue;
+ struct throtl_service_queue *parent_sq = sq->parent_sq;
+ struct throtl_grp *parent_tg = sq_to_tg(parent_sq);
+ struct throtl_grp *tg_to_put = NULL;
+ struct bio *bio;
- BUG_ON(td->nr_queued[rw] <= 0);
- td->nr_queued[rw]--;
+ /*
+ * @bio is being transferred from @tg to @parent_sq. Popping a bio
+ * from @tg may put its reference and @parent_sq might end up
+ * getting released prematurely. Remember the tg to put and put it
+ * after @bio is transferred to @parent_sq.
+ */
+ bio = throtl_pop_queued(&sq->queued[rw], &tg_to_put);
+ sq->nr_queued[rw]--;
throtl_charge_bio(tg, bio);
- bio_list_add(bl, bio);
- bio->bi_rw |= REQ_THROTTLED;
- throtl_trim_slice(td, tg, rw);
+ /*
+ * If our parent is another tg, we just need to transfer @bio to
+ * the parent using throtl_add_bio_tg(). If our parent is
+ * @td->service_queue, @bio is ready to be issued. Put it on its
+ * bio_lists[] and decrease total number queued. The caller is
+ * responsible for issuing these bios.
+ */
+ if (parent_tg) {
+ throtl_add_bio_tg(bio, &tg->qnode_on_parent[rw], parent_tg);
+ start_parent_slice_with_credit(tg, parent_tg, rw);
+ } else {
+ throtl_qnode_add_bio(bio, &tg->qnode_on_parent[rw],
+ &parent_sq->queued[rw]);
+ BUG_ON(tg->td->nr_queued[rw] <= 0);
+ tg->td->nr_queued[rw]--;
+ }
+
+ throtl_trim_slice(tg, rw);
+
+ if (tg_to_put)
+ blkg_put(tg_to_blkg(tg_to_put));
}
-static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
- struct bio_list *bl)
+static int throtl_dispatch_tg(struct throtl_grp *tg)
{
+ struct throtl_service_queue *sq = &tg->service_queue;
unsigned int nr_reads = 0, nr_writes = 0;
unsigned int max_nr_reads = throtl_grp_quantum*3/4;
unsigned int max_nr_writes = throtl_grp_quantum - max_nr_reads;
@@ -774,20 +1117,20 @@ static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
/* Try to dispatch 75% READS and 25% WRITES */
- while ((bio = bio_list_peek(&tg->bio_lists[READ]))
- && tg_may_dispatch(td, tg, bio, NULL)) {
+ while ((bio = throtl_peek_queued(&sq->queued[READ])) &&
+ tg_may_dispatch(tg, bio, NULL)) {
- tg_dispatch_one_bio(td, tg, bio_data_dir(bio), bl);
+ tg_dispatch_one_bio(tg, bio_data_dir(bio));
nr_reads++;
if (nr_reads >= max_nr_reads)
break;
}
- while ((bio = bio_list_peek(&tg->bio_lists[WRITE]))
- && tg_may_dispatch(td, tg, bio, NULL)) {
+ while ((bio = throtl_peek_queued(&sq->queued[WRITE])) &&
+ tg_may_dispatch(tg, bio, NULL)) {
- tg_dispatch_one_bio(td, tg, bio_data_dir(bio), bl);
+ tg_dispatch_one_bio(tg, bio_data_dir(bio));
nr_writes++;
if (nr_writes >= max_nr_writes)
@@ -797,14 +1140,13 @@ static int throtl_dispatch_tg(struct throtl_data *td, struct throtl_grp *tg,
return nr_reads + nr_writes;
}
-static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
+static int throtl_select_dispatch(struct throtl_service_queue *parent_sq)
{
unsigned int nr_disp = 0;
- struct throtl_grp *tg;
- struct throtl_rb_root *st = &td->tg_service_tree;
while (1) {
- tg = throtl_rb_first(st);
+ struct throtl_grp *tg = throtl_rb_first(parent_sq);
+ struct throtl_service_queue *sq = &tg->service_queue;
if (!tg)
break;
@@ -812,14 +1154,12 @@ static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
if (time_before(jiffies, tg->disptime))
break;
- throtl_dequeue_tg(td, tg);
+ throtl_dequeue_tg(tg);
- nr_disp += throtl_dispatch_tg(td, tg, bl);
+ nr_disp += throtl_dispatch_tg(tg);
- if (tg->nr_queued[0] || tg->nr_queued[1]) {
- tg_update_disptime(td, tg);
- throtl_enqueue_tg(td, tg);
- }
+ if (sq->nr_queued[0] || sq->nr_queued[1])
+ tg_update_disptime(tg);
if (nr_disp >= throtl_quantum)
break;
@@ -828,111 +1168,111 @@ static int throtl_select_dispatch(struct throtl_data *td, struct bio_list *bl)
return nr_disp;
}
-static void throtl_process_limit_change(struct throtl_data *td)
+/**
+ * throtl_pending_timer_fn - timer function for service_queue->pending_timer
+ * @arg: the throtl_service_queue being serviced
+ *
+ * This timer is armed when a child throtl_grp with active bio's become
+ * pending and queued on the service_queue's pending_tree and expires when
+ * the first child throtl_grp should be dispatched. This function
+ * dispatches bio's from the children throtl_grps to the parent
+ * service_queue.
+ *
+ * If the parent's parent is another throtl_grp, dispatching is propagated
+ * by either arming its pending_timer or repeating dispatch directly. If
+ * the top-level service_tree is reached, throtl_data->dispatch_work is
+ * kicked so that the ready bio's are issued.
+ */
+static void throtl_pending_timer_fn(unsigned long arg)
{
+ struct throtl_service_queue *sq = (void *)arg;
+ struct throtl_grp *tg = sq_to_tg(sq);
+ struct throtl_data *td = sq_to_td(sq);
struct request_queue *q = td->queue;
- struct blkcg_gq *blkg, *n;
-
- if (!td->limits_changed)
- return;
-
- xchg(&td->limits_changed, false);
-
- throtl_log(td, "limits changed");
-
- list_for_each_entry_safe(blkg, n, &q->blkg_list, q_node) {
- struct throtl_grp *tg = blkg_to_tg(blkg);
+ struct throtl_service_queue *parent_sq;
+ bool dispatched;
+ int ret;
- if (!tg->limits_changed)
- continue;
+ spin_lock_irq(q->queue_lock);
+again:
+ parent_sq = sq->parent_sq;
+ dispatched = false;
+
+ while (true) {
+ throtl_log(sq, "dispatch nr_queued=%u read=%u write=%u",
+ sq->nr_queued[READ] + sq->nr_queued[WRITE],
+ sq->nr_queued[READ], sq->nr_queued[WRITE]);
+
+ ret = throtl_select_dispatch(sq);
+ if (ret) {
+ throtl_log(sq, "bios disp=%u", ret);
+ dispatched = true;
+ }
- if (!xchg(&tg->limits_changed, false))
- continue;
+ if (throtl_schedule_next_dispatch(sq, false))
+ break;
- throtl_log_tg(td, tg, "limit change rbps=%llu wbps=%llu"
- " riops=%u wiops=%u", tg->bps[READ], tg->bps[WRITE],
- tg->iops[READ], tg->iops[WRITE]);
+ /* this dispatch windows is still open, relax and repeat */
+ spin_unlock_irq(q->queue_lock);
+ cpu_relax();
+ spin_lock_irq(q->queue_lock);
+ }
- /*
- * Restart the slices for both READ and WRITES. It
- * might happen that a group's limit are dropped
- * suddenly and we don't want to account recently
- * dispatched IO with new low rate
- */
- throtl_start_new_slice(td, tg, 0);
- throtl_start_new_slice(td, tg, 1);
+ if (!dispatched)
+ goto out_unlock;
- if (throtl_tg_on_rr(tg))
- tg_update_disptime(td, tg);
+ if (parent_sq) {
+ /* @parent_sq is another throl_grp, propagate dispatch */
+ if (tg->flags & THROTL_TG_WAS_EMPTY) {
+ tg_update_disptime(tg);
+ if (!throtl_schedule_next_dispatch(parent_sq, false)) {
+ /* window is already open, repeat dispatching */
+ sq = parent_sq;
+ tg = sq_to_tg(sq);
+ goto again;
+ }
+ }
+ } else {
+ /* reached the top-level, queue issueing */
+ queue_work(kthrotld_workqueue, &td->dispatch_work);
}
+out_unlock:
+ spin_unlock_irq(q->queue_lock);
}
-/* Dispatch throttled bios. Should be called without queue lock held. */
-static int throtl_dispatch(struct request_queue *q)
+/**
+ * blk_throtl_dispatch_work_fn - work function for throtl_data->dispatch_work
+ * @work: work item being executed
+ *
+ * This function is queued for execution when bio's reach the bio_lists[]
+ * of throtl_data->service_queue. Those bio's are ready and issued by this
+ * function.
+ */
+void blk_throtl_dispatch_work_fn(struct work_struct *work)
{
- struct throtl_data *td = q->td;
- unsigned int nr_disp = 0;
+ struct throtl_data *td = container_of(work, struct throtl_data,
+ dispatch_work);
+ struct throtl_service_queue *td_sq = &td->service_queue;
+ struct request_queue *q = td->queue;
struct bio_list bio_list_on_stack;
struct bio *bio;
struct blk_plug plug;
-
- spin_lock_irq(q->queue_lock);
-
- throtl_process_limit_change(td);
-
- if (!total_nr_queued(td))
- goto out;
+ int rw;
bio_list_init(&bio_list_on_stack);
- throtl_log(td, "dispatch nr_queued=%u read=%u write=%u",
- total_nr_queued(td), td->nr_queued[READ],
- td->nr_queued[WRITE]);
-
- nr_disp = throtl_select_dispatch(td, &bio_list_on_stack);
-
- if (nr_disp)
- throtl_log(td, "bios disp=%u", nr_disp);
-
- throtl_schedule_next_dispatch(td);
-out:
+ spin_lock_irq(q->queue_lock);
+ for (rw = READ; rw <= WRITE; rw++)
+ while ((bio = throtl_pop_queued(&td_sq->queued[rw], NULL)))
+ bio_list_add(&bio_list_on_stack, bio);
spin_unlock_irq(q->queue_lock);
- /*
- * If we dispatched some requests, unplug the queue to make sure
- * immediate dispatch
- */
- if (nr_disp) {
+ if (!bio_list_empty(&bio_list_on_stack)) {
blk_start_plug(&plug);
while((bio = bio_list_pop(&bio_list_on_stack)))
generic_make_request(bio);
blk_finish_plug(&plug);
}
- return nr_disp;
-}
-
-void blk_throtl_work(struct work_struct *work)
-{
- struct throtl_data *td = container_of(work, struct throtl_data,
- throtl_work.work);
- struct request_queue *q = td->queue;
-
- throtl_dispatch(q);
-}
-
-/* Call with queue lock held */
-static void
-throtl_schedule_delayed_work(struct throtl_data *td, unsigned long delay)
-{
-
- struct delayed_work *dwork = &td->throtl_work;
-
- /* schedule work if limits changed even if no bio is queued */
- if (total_nr_queued(td) || td->limits_changed) {
- mod_delayed_work(kthrotld_workqueue, dwork, delay);
- throtl_log(td, "schedule work. delay=%lu jiffies=%lu",
- delay, jiffies);
- }
}
static u64 tg_prfill_cpu_rwstat(struct seq_file *sf,
@@ -1007,7 +1347,9 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
struct blkcg *blkcg = cgroup_to_blkcg(cgrp);
struct blkg_conf_ctx ctx;
struct throtl_grp *tg;
- struct throtl_data *td;
+ struct throtl_service_queue *sq;
+ struct blkcg_gq *blkg;
+ struct cgroup *pos_cgrp;
int ret;
ret = blkg_conf_prep(blkcg, &blkcg_policy_throtl, buf, &ctx);
@@ -1015,7 +1357,7 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
return ret;
tg = blkg_to_tg(ctx.blkg);
- td = ctx.blkg->q->td;
+ sq = &tg->service_queue;
if (!ctx.v)
ctx.v = -1;
@@ -1025,10 +1367,37 @@ static int tg_set_conf(struct cgroup *cgrp, struct cftype *cft, const char *buf,
else
*(unsigned int *)((void *)tg + cft->private) = ctx.v;
- /* XXX: we don't need the following deferred processing */
- xchg(&tg->limits_changed, true);
- xchg(&td->limits_changed, true);
- throtl_schedule_delayed_work(td, 0);
+ throtl_log(&tg->service_queue,
+ "limit change rbps=%llu wbps=%llu riops=%u wiops=%u",
+ tg->bps[READ], tg->bps[WRITE],
+ tg->iops[READ], tg->iops[WRITE]);
+
+ /*
+ * Update has_rules[] flags for the updated tg's subtree. A tg is
+ * considered to have rules if either the tg itself or any of its
+ * ancestors has rules. This identifies groups without any
+ * restrictions in the whole hierarchy and allows them to bypass
+ * blk-throttle.
+ */
+ tg_update_has_rules(tg);
+ blkg_for_each_descendant_pre(blkg, pos_cgrp, ctx.blkg)
+ tg_update_has_rules(blkg_to_tg(blkg));
+
+ /*
+ * We're already holding queue_lock and know @tg is valid. Let's
+ * apply the new config directly.
+ *
+ * Restart the slices for both READ and WRITES. It might happen
+ * that a group's limit are dropped suddenly and we don't want to
+ * account recently dispatched IO with new low rate.
+ */
+ throtl_start_new_slice(tg, 0);
+ throtl_start_new_slice(tg, 1);
+
+ if (tg->flags & THROTL_TG_PENDING) {
+ tg_update_disptime(tg);
+ throtl_schedule_next_dispatch(sq->parent_sq, true);
+ }
blkg_conf_finish(&ctx);
return 0;
@@ -1092,7 +1461,7 @@ static void throtl_shutdown_wq(struct request_queue *q)
{
struct throtl_data *td = q->td;
- cancel_delayed_work_sync(&td->throtl_work);
+ cancel_work_sync(&td->dispatch_work);
}
static struct blkcg_policy blkcg_policy_throtl = {
@@ -1100,6 +1469,7 @@ static struct blkcg_policy blkcg_policy_throtl = {
.cftypes = throtl_files,
.pd_init_fn = throtl_pd_init,
+ .pd_online_fn = throtl_pd_online,
.pd_exit_fn = throtl_pd_exit,
.pd_reset_stats_fn = throtl_pd_reset_stats,
};
@@ -1107,15 +1477,16 @@ static struct blkcg_policy blkcg_policy_throtl = {
bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
{
struct throtl_data *td = q->td;
+ struct throtl_qnode *qn = NULL;
struct throtl_grp *tg;
- bool rw = bio_data_dir(bio), update_disptime = true;
+ struct throtl_service_queue *sq;
+ bool rw = bio_data_dir(bio);
struct blkcg *blkcg;
bool throttled = false;
- if (bio->bi_rw & REQ_THROTTLED) {
- bio->bi_rw &= ~REQ_THROTTLED;
+ /* see throtl_charge_bio() */
+ if (bio->bi_rw & REQ_THROTTLED)
goto out;
- }
/*
* A throtl_grp pointer retrieved under rcu can be used to access
@@ -1126,7 +1497,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
blkcg = bio_blkcg(bio);
tg = throtl_lookup_tg(td, blkcg);
if (tg) {
- if (tg_no_rule_group(tg, rw)) {
+ if (!tg->has_rules[rw]) {
throtl_update_dispatch_stats(tg_to_blkg(tg),
bio->bi_size, bio->bi_rw);
goto out_unlock_rcu;
@@ -1142,18 +1513,18 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
if (unlikely(!tg))
goto out_unlock;
- if (tg->nr_queued[rw]) {
- /*
- * There is already another bio queued in same dir. No
- * need to update dispatch time.
- */
- update_disptime = false;
- goto queue_bio;
+ sq = &tg->service_queue;
- }
+ while (true) {
+ /* throtl is FIFO - if bios are already queued, should queue */
+ if (sq->nr_queued[rw])
+ break;
+
+ /* if above limits, break to queue */
+ if (!tg_may_dispatch(tg, bio, NULL))
+ break;
- /* Bio is with-in rate limit of group */
- if (tg_may_dispatch(td, tg, bio, NULL)) {
+ /* within limits, let's charge and dispatch directly */
throtl_charge_bio(tg, bio);
/*
@@ -1167,25 +1538,41 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
*
* So keep on trimming slice even if bio is not queued.
*/
- throtl_trim_slice(td, tg, rw);
- goto out_unlock;
+ throtl_trim_slice(tg, rw);
+
+ /*
+ * @bio passed through this layer without being throttled.
+ * Climb up the ladder. If we''re already at the top, it
+ * can be executed directly.
+ */
+ qn = &tg->qnode_on_parent[rw];
+ sq = sq->parent_sq;
+ tg = sq_to_tg(sq);
+ if (!tg)
+ goto out_unlock;
}
-queue_bio:
- throtl_log_tg(td, tg, "[%c] bio. bdisp=%llu sz=%u bps=%llu"
- " iodisp=%u iops=%u queued=%d/%d",
- rw == READ ? 'R' : 'W',
- tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
- tg->io_disp[rw], tg->iops[rw],
- tg->nr_queued[READ], tg->nr_queued[WRITE]);
+ /* out-of-limit, queue to @tg */
+ throtl_log(sq, "[%c] bio. bdisp=%llu sz=%u bps=%llu iodisp=%u iops=%u queued=%d/%d",
+ rw == READ ? 'R' : 'W',
+ tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
+ tg->io_disp[rw], tg->iops[rw],
+ sq->nr_queued[READ], sq->nr_queued[WRITE]);
bio_associate_current(bio);
- throtl_add_bio_tg(q->td, tg, bio);
+ tg->td->nr_queued[rw]++;
+ throtl_add_bio_tg(bio, qn, tg);
throttled = true;
- if (update_disptime) {
- tg_update_disptime(td, tg);
- throtl_schedule_next_dispatch(td);
+ /*
+ * Update @tg's dispatch time and force schedule dispatch if @tg
+ * was empty before @bio. The forced scheduling isn't likely to
+ * cause undue delay as @bio is likely to be dispatched directly if
+ * its @tg's disptime is not in the future.
+ */
+ if (tg->flags & THROTL_TG_WAS_EMPTY) {
+ tg_update_disptime(tg);
+ throtl_schedule_next_dispatch(tg->service_queue.parent_sq, true);
}
out_unlock:
@@ -1193,9 +1580,38 @@ out_unlock:
out_unlock_rcu:
rcu_read_unlock();
out:
+ /*
+ * As multiple blk-throtls may stack in the same issue path, we
+ * don't want bios to leave with the flag set. Clear the flag if
+ * being issued.
+ */
+ if (!throttled)
+ bio->bi_rw &= ~REQ_THROTTLED;
return throttled;
}
+/*
+ * Dispatch all bios from all children tg's queued on @parent_sq. On
+ * return, @parent_sq is guaranteed to not have any active children tg's
+ * and all bios from previously active tg's are on @parent_sq->bio_lists[].
+ */
+static void tg_drain_bios(struct throtl_service_queue *parent_sq)
+{
+ struct throtl_grp *tg;
+
+ while ((tg = throtl_rb_first(parent_sq))) {
+ struct throtl_service_queue *sq = &tg->service_queue;
+ struct bio *bio;
+
+ throtl_dequeue_tg(tg);
+
+ while ((bio = throtl_peek_queued(&sq->queued[READ])))
+ tg_dispatch_one_bio(tg, bio_data_dir(bio));
+ while ((bio = throtl_peek_queued(&sq->queued[WRITE])))
+ tg_dispatch_one_bio(tg, bio_data_dir(bio));
+ }
+}
+
/**
* blk_throtl_drain - drain throttled bios
* @q: request_queue to drain throttled bios for
@@ -1206,27 +1622,36 @@ void blk_throtl_drain(struct request_queue *q)
__releases(q->queue_lock) __acquires(q->queue_lock)
{
struct throtl_data *td = q->td;
- struct throtl_rb_root *st = &td->tg_service_tree;
- struct throtl_grp *tg;
- struct bio_list bl;
+ struct blkcg_gq *blkg;
+ struct cgroup *pos_cgrp;
struct bio *bio;
+ int rw;
queue_lockdep_assert_held(q);
+ rcu_read_lock();
+
+ /*
+ * Drain each tg while doing post-order walk on the blkg tree, so
+ * that all bios are propagated to td->service_queue. It'd be
+ * better to walk service_queue tree directly but blkg walk is
+ * easier.
+ */
+ blkg_for_each_descendant_post(blkg, pos_cgrp, td->queue->root_blkg)
+ tg_drain_bios(&blkg_to_tg(blkg)->service_queue);
- bio_list_init(&bl);
+ tg_drain_bios(&td_root_tg(td)->service_queue);
- while ((tg = throtl_rb_first(st))) {
- throtl_dequeue_tg(td, tg);
+ /* finally, transfer bios from top-level tg's into the td */
+ tg_drain_bios(&td->service_queue);
- while ((bio = bio_list_peek(&tg->bio_lists[READ])))
- tg_dispatch_one_bio(td, tg, bio_data_dir(bio), &bl);
- while ((bio = bio_list_peek(&tg->bio_lists[WRITE])))
- tg_dispatch_one_bio(td, tg, bio_data_dir(bio), &bl);
- }
+ rcu_read_unlock();
spin_unlock_irq(q->queue_lock);
- while ((bio = bio_list_pop(&bl)))
- generic_make_request(bio);
+ /* all bios now should be in td->service_queue, issue them */
+ for (rw = READ; rw <= WRITE; rw++)
+ while ((bio = throtl_pop_queued(&td->service_queue.queued[rw],
+ NULL)))
+ generic_make_request(bio);
spin_lock_irq(q->queue_lock);
}
@@ -1240,9 +1665,8 @@ int blk_throtl_init(struct request_queue *q)
if (!td)
return -ENOMEM;
- td->tg_service_tree = THROTL_RB_ROOT;
- td->limits_changed = false;
- INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
+ INIT_WORK(&td->dispatch_work, blk_throtl_dispatch_work_fn);
+ throtl_service_queue_init(&td->service_queue, NULL);
q->td = td;
td->queue = q;
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index 6e4744cbfb56..65f103563969 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -82,9 +82,10 @@ void blk_delete_timer(struct request *req)
static void blk_rq_timed_out(struct request *req)
{
struct request_queue *q = req->q;
- enum blk_eh_timer_return ret;
+ enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER;
- ret = q->rq_timed_out_fn(req);
+ if (q->rq_timed_out_fn)
+ ret = q->rq_timed_out_fn(req);
switch (ret) {
case BLK_EH_HANDLED:
__blk_complete_request(req);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index d5cd3131c57a..d5bbdcfd0dab 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -4347,18 +4347,28 @@ static void cfq_exit_queue(struct elevator_queue *e)
kfree(cfqd);
}
-static int cfq_init_queue(struct request_queue *q)
+static int cfq_init_queue(struct request_queue *q, struct elevator_type *e)
{
struct cfq_data *cfqd;
struct blkcg_gq *blkg __maybe_unused;
int i, ret;
+ struct elevator_queue *eq;
+
+ eq = elevator_alloc(q, e);
+ if (!eq)
+ return -ENOMEM;
cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
- if (!cfqd)
+ if (!cfqd) {
+ kobject_put(&eq->kobj);
return -ENOMEM;
+ }
+ eq->elevator_data = cfqd;
cfqd->queue = q;
- q->elevator->elevator_data = cfqd;
+ spin_lock_irq(q->queue_lock);
+ q->elevator = eq;
+ spin_unlock_irq(q->queue_lock);
/* Init root service tree */
cfqd->grp_service_tree = CFQ_RB_ROOT;
@@ -4433,6 +4443,7 @@ static int cfq_init_queue(struct request_queue *q)
out_free:
kfree(cfqd);
+ kobject_put(&eq->kobj);
return ret;
}
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 7c668c8a6f95..7e5d474dc6ba 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -59,6 +59,7 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
if (!disk->fops->getgeo)
return -ENOTTY;
+ memset(&geo, 0, sizeof(geo));
/*
* We need to set the startsect first, the driver may
* want to override it.
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index ba19a3afab79..20614a332362 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -337,13 +337,21 @@ static void deadline_exit_queue(struct elevator_queue *e)
/*
* initialize elevator private data (deadline_data).
*/
-static int deadline_init_queue(struct request_queue *q)
+static int deadline_init_queue(struct request_queue *q, struct elevator_type *e)
{
struct deadline_data *dd;
+ struct elevator_queue *eq;
+
+ eq = elevator_alloc(q, e);
+ if (!eq)
+ return -ENOMEM;
dd = kmalloc_node(sizeof(*dd), GFP_KERNEL | __GFP_ZERO, q->node);
- if (!dd)
+ if (!dd) {
+ kobject_put(&eq->kobj);
return -ENOMEM;
+ }
+ eq->elevator_data = dd;
INIT_LIST_HEAD(&dd->fifo_list[READ]);
INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
@@ -355,7 +363,9 @@ static int deadline_init_queue(struct request_queue *q)
dd->front_merges = 1;
dd->fifo_batch = fifo_batch;
- q->elevator->elevator_data = dd;
+ spin_lock_irq(q->queue_lock);
+ q->elevator = eq;
+ spin_unlock_irq(q->queue_lock);
return 0;
}
diff --git a/block/elevator.c b/block/elevator.c
index eba5b04c29b1..668394d18588 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -150,7 +150,7 @@ void __init load_default_elevator_module(void)
static struct kobj_type elv_ktype;
-static struct elevator_queue *elevator_alloc(struct request_queue *q,
+struct elevator_queue *elevator_alloc(struct request_queue *q,
struct elevator_type *e)
{
struct elevator_queue *eq;
@@ -170,6 +170,7 @@ err:
elevator_put(e);
return NULL;
}
+EXPORT_SYMBOL(elevator_alloc);
static void elevator_release(struct kobject *kobj)
{
@@ -221,16 +222,7 @@ int elevator_init(struct request_queue *q, char *name)
}
}
- q->elevator = elevator_alloc(q, e);
- if (!q->elevator)
- return -ENOMEM;
-
- err = e->ops.elevator_init_fn(q);
- if (err) {
- kobject_put(&q->elevator->kobj);
- return err;
- }
-
+ err = e->ops.elevator_init_fn(q, e);
return 0;
}
EXPORT_SYMBOL(elevator_init);
@@ -935,16 +927,9 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
spin_unlock_irq(q->queue_lock);
/* allocate, init and register new elevator */
- err = -ENOMEM;
- q->elevator = elevator_alloc(q, new_e);
- if (!q->elevator)
- goto fail_init;
-
- err = new_e->ops.elevator_init_fn(q);
- if (err) {
- kobject_put(&q->elevator->kobj);
+ err = new_e->ops.elevator_init_fn(q, new_e);
+ if (err)
goto fail_init;
- }
if (registered) {
err = elv_register_queue(q);
diff --git a/block/genhd.c b/block/genhd.c
index 20625eed5511..dadf42b454a3 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -512,7 +512,7 @@ static void register_disk(struct gendisk *disk)
ddev->parent = disk->driverfs_dev;
- dev_set_name(ddev, disk->disk_name);
+ dev_set_name(ddev, "%s", disk->disk_name);
/* delay uevents, until we scanned partition table */
dev_set_uevent_suppress(ddev, 1);
@@ -1489,9 +1489,11 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now)
intv = disk_events_poll_jiffies(disk);
set_timer_slack(&ev->dwork.timer, intv / 4);
if (check_now)
- queue_delayed_work(system_freezable_wq, &ev->dwork, 0);
+ queue_delayed_work(system_freezable_power_efficient_wq,
+ &ev->dwork, 0);
else if (intv)
- queue_delayed_work(system_freezable_wq, &ev->dwork, intv);
+ queue_delayed_work(system_freezable_power_efficient_wq,
+ &ev->dwork, intv);
out_unlock:
spin_unlock_irqrestore(&ev->lock, flags);
}
@@ -1534,7 +1536,8 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
spin_lock_irq(&ev->lock);
ev->clearing |= mask;
if (!ev->block)
- mod_delayed_work(system_freezable_wq, &ev->dwork, 0);
+ mod_delayed_work(system_freezable_power_efficient_wq,
+ &ev->dwork, 0);
spin_unlock_irq(&ev->lock);
}
@@ -1627,7 +1630,8 @@ static void disk_check_events(struct disk_events *ev,
intv = disk_events_poll_jiffies(disk);
if (!ev->block && intv)
- queue_delayed_work(system_freezable_wq, &ev->dwork, intv);
+ queue_delayed_work(system_freezable_power_efficient_wq,
+ &ev->dwork, intv);
spin_unlock_irq(&ev->lock);
diff --git a/block/noop-iosched.c b/block/noop-iosched.c
index 5d1bf70e33d5..3de89d4690f3 100644
--- a/block/noop-iosched.c
+++ b/block/noop-iosched.c
@@ -59,16 +59,27 @@ noop_latter_request(struct request_queue *q, struct request *rq)
return list_entry(rq->queuelist.next, struct request, queuelist);
}
-static int noop_init_queue(struct request_queue *q)
+static int noop_init_queue(struct request_queue *q, struct elevator_type *e)
{
struct noop_data *nd;
+ struct elevator_queue *eq;
+
+ eq = elevator_alloc(q, e);
+ if (!eq)
+ return -ENOMEM;
nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node);
- if (!nd)
+ if (!nd) {
+ kobject_put(&eq->kobj);
return -ENOMEM;
+ }
+ eq->elevator_data = nd;
INIT_LIST_HEAD(&nd->queue);
- q->elevator->elevator_data = nd;
+
+ spin_lock_irq(q->queue_lock);
+ q->elevator = eq;
+ spin_unlock_irq(q->queue_lock);
return 0;
}
diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig
index 75a54e1adbb5..4cebb2f0d2f4 100644
--- a/block/partitions/Kconfig
+++ b/block/partitions/Kconfig
@@ -68,6 +68,17 @@ config ACORN_PARTITION_RISCIX
of machines called RISCiX. If you say 'Y' here, Linux will be able
to read disks partitioned under RISCiX.
+config AIX_PARTITION
+ bool "AIX basic partition table support" if PARTITION_ADVANCED
+ help
+ Say Y here if you would like to be able to read the hard disk
+ partition table format used by IBM or Motorola PowerPC machines
+ running AIX. AIX actually uses a Logical Volume Manager, where
+ "logical volumes" can be spread across one or multiple disks,
+ but this driver works only for the simple case of partitions which
+ are contiguous.
+ Otherwise, say N.
+
config OSF_PARTITION
bool "Alpha OSF partition support" if PARTITION_ADVANCED
default y if ALPHA
diff --git a/block/partitions/Makefile b/block/partitions/Makefile
index 03af8eac51da..2be4d7ba4e3a 100644
--- a/block/partitions/Makefile
+++ b/block/partitions/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_BLOCK) := check.o
obj-$(CONFIG_ACORN_PARTITION) += acorn.o
obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
obj-$(CONFIG_ATARI_PARTITION) += atari.o
+obj-$(CONFIG_AIX_PARTITION) += aix.o
obj-$(CONFIG_MAC_PARTITION) += mac.o
obj-$(CONFIG_LDM_PARTITION) += ldm.o
obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
diff --git a/block/partitions/aix.c b/block/partitions/aix.c
new file mode 100644
index 000000000000..43be471d9b1d
--- /dev/null
+++ b/block/partitions/aix.c
@@ -0,0 +1,293 @@
+/*
+ * fs/partitions/aix.c
+ *
+ * Copyright (C) 2012-2013 Philippe De Muyter <phdm@macqel.be>
+ */
+
+#include "check.h"
+#include "aix.h"
+
+struct lvm_rec {
+ char lvm_id[4]; /* "_LVM" */
+ char reserved4[16];
+ __be32 lvmarea_len;
+ __be32 vgda_len;
+ __be32 vgda_psn[2];
+ char reserved36[10];
+ __be16 pp_size; /* log2(pp_size) */
+ char reserved46[12];
+ __be16 version;
+ };
+
+struct vgda {
+ __be32 secs;
+ __be32 usec;
+ char reserved8[16];
+ __be16 numlvs;
+ __be16 maxlvs;
+ __be16 pp_size;
+ __be16 numpvs;
+ __be16 total_vgdas;
+ __be16 vgda_size;
+ };
+
+struct lvd {
+ __be16 lv_ix;
+ __be16 res2;
+ __be16 res4;
+ __be16 maxsize;
+ __be16 lv_state;
+ __be16 mirror;
+ __be16 mirror_policy;
+ __be16 num_lps;
+ __be16 res10[8];
+ };
+
+struct lvname {
+ char name[64];
+ };
+
+struct ppe {
+ __be16 lv_ix;
+ unsigned short res2;
+ unsigned short res4;
+ __be16 lp_ix;
+ unsigned short res8[12];
+ };
+
+struct pvd {
+ char reserved0[16];
+ __be16 pp_count;
+ char reserved18[2];
+ __be32 psn_part1;
+ char reserved24[8];
+ struct ppe ppe[1016];
+ };
+
+#define LVM_MAXLVS 256
+
+/**
+ * last_lba(): return number of last logical block of device
+ * @bdev: block device
+ *
+ * Description: Returns last LBA value on success, 0 on error.
+ * This is stored (by sd and ide-geometry) in
+ * the part[0] entry for this disk, and is the number of
+ * physical sectors available on the disk.
+ */
+static u64 last_lba(struct block_device *bdev)
+{
+ if (!bdev || !bdev->bd_inode)
+ return 0;
+ return (bdev->bd_inode->i_size >> 9) - 1ULL;
+}
+
+/**
+ * read_lba(): Read bytes from disk, starting at given LBA
+ * @state
+ * @lba
+ * @buffer
+ * @count
+ *
+ * Description: Reads @count bytes from @state->bdev into @buffer.
+ * Returns number of bytes read on success, 0 on error.
+ */
+static size_t read_lba(struct parsed_partitions *state, u64 lba, u8 *buffer,
+ size_t count)
+{
+ size_t totalreadcount = 0;
+
+ if (!buffer || lba + count / 512 > last_lba(state->bdev))
+ return 0;
+
+ while (count) {
+ int copied = 512;
+ Sector sect;
+ unsigned char *data = read_part_sector(state, lba++, &sect);
+ if (!data)
+ break;
+ if (copied > count)
+ copied = count;
+ memcpy(buffer, data, copied);
+ put_dev_sector(sect);
+ buffer += copied;
+ totalreadcount += copied;
+ count -= copied;
+ }
+ return totalreadcount;
+}
+
+/**
+ * alloc_pvd(): reads physical volume descriptor
+ * @state
+ * @lba
+ *
+ * Description: Returns pvd on success, NULL on error.
+ * Allocates space for pvd and fill it with disk blocks at @lba
+ * Notes: remember to free pvd when you're done!
+ */
+static struct pvd *alloc_pvd(struct parsed_partitions *state, u32 lba)
+{
+ size_t count = sizeof(struct pvd);
+ struct pvd *p;
+
+ p = kmalloc(count, GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ if (read_lba(state, lba, (u8 *) p, count) < count) {
+ kfree(p);
+ return NULL;
+ }
+ return p;
+}
+
+/**
+ * alloc_lvn(): reads logical volume names
+ * @state
+ * @lba
+ *
+ * Description: Returns lvn on success, NULL on error.
+ * Allocates space for lvn and fill it with disk blocks at @lba
+ * Notes: remember to free lvn when you're done!
+ */
+static struct lvname *alloc_lvn(struct parsed_partitions *state, u32 lba)
+{
+ size_t count = sizeof(struct lvname) * LVM_MAXLVS;
+ struct lvname *p;
+
+ p = kmalloc(count, GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ if (read_lba(state, lba, (u8 *) p, count) < count) {
+ kfree(p);
+ return NULL;
+ }
+ return p;
+}
+
+int aix_partition(struct parsed_partitions *state)
+{
+ int ret = 0;
+ Sector sect;
+ unsigned char *d;
+ u32 pp_bytes_size;
+ u32 pp_blocks_size = 0;
+ u32 vgda_sector = 0;
+ u32 vgda_len = 0;
+ int numlvs = 0;
+ struct pvd *pvd;
+ struct lv_info {
+ unsigned short pps_per_lv;
+ unsigned short pps_found;
+ unsigned char lv_is_contiguous;
+ } *lvip;
+ struct lvname *n = NULL;
+
+ d = read_part_sector(state, 7, &sect);
+ if (d) {
+ struct lvm_rec *p = (struct lvm_rec *)d;
+ u16 lvm_version = be16_to_cpu(p->version);
+ char tmp[64];
+
+ if (lvm_version == 1) {
+ int pp_size_log2 = be16_to_cpu(p->pp_size);
+
+ pp_bytes_size = 1 << pp_size_log2;
+ pp_blocks_size = pp_bytes_size / 512;
+ snprintf(tmp, sizeof(tmp),
+ " AIX LVM header version %u found\n",
+ lvm_version);
+ vgda_len = be32_to_cpu(p->vgda_len);
+ vgda_sector = be32_to_cpu(p->vgda_psn[0]);
+ } else {
+ snprintf(tmp, sizeof(tmp),
+ " unsupported AIX LVM version %d found\n",
+ lvm_version);
+ }
+ strlcat(state->pp_buf, tmp, PAGE_SIZE);
+ put_dev_sector(sect);
+ }
+ if (vgda_sector && (d = read_part_sector(state, vgda_sector, &sect))) {
+ struct vgda *p = (struct vgda *)d;
+
+ numlvs = be16_to_cpu(p->numlvs);
+ put_dev_sector(sect);
+ }
+ lvip = kzalloc(sizeof(struct lv_info) * state->limit, GFP_KERNEL);
+ if (!lvip)
+ return 0;
+ if (numlvs && (d = read_part_sector(state, vgda_sector + 1, &sect))) {
+ struct lvd *p = (struct lvd *)d;
+ int i;
+
+ n = alloc_lvn(state, vgda_sector + vgda_len - 33);
+ if (n) {
+ int foundlvs = 0;
+
+ for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) {
+ lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps);
+ if (lvip[i].pps_per_lv)
+ foundlvs += 1;
+ }
+ }
+ put_dev_sector(sect);
+ }
+ pvd = alloc_pvd(state, vgda_sector + 17);
+ if (pvd) {
+ int numpps = be16_to_cpu(pvd->pp_count);
+ int psn_part1 = be32_to_cpu(pvd->psn_part1);
+ int i;
+ int cur_lv_ix = -1;
+ int next_lp_ix = 1;
+ int lp_ix;
+
+ for (i = 0; i < numpps; i += 1) {
+ struct ppe *p = pvd->ppe + i;
+ unsigned int lv_ix;
+
+ lp_ix = be16_to_cpu(p->lp_ix);
+ if (!lp_ix) {
+ next_lp_ix = 1;
+ continue;
+ }
+ lv_ix = be16_to_cpu(p->lv_ix) - 1;
+ if (lv_ix > state->limit) {
+ cur_lv_ix = -1;
+ continue;
+ }
+ lvip[lv_ix].pps_found += 1;
+ if (lp_ix == 1) {
+ cur_lv_ix = lv_ix;
+ next_lp_ix = 1;
+ } else if (lv_ix != cur_lv_ix || lp_ix != next_lp_ix) {
+ next_lp_ix = 1;
+ continue;
+ }
+ if (lp_ix == lvip[lv_ix].pps_per_lv) {
+ char tmp[70];
+
+ put_partition(state, lv_ix + 1,
+ (i + 1 - lp_ix) * pp_blocks_size + psn_part1,
+ lvip[lv_ix].pps_per_lv * pp_blocks_size);
+ snprintf(tmp, sizeof(tmp), " <%s>\n",
+ n[lv_ix].name);
+ strlcat(state->pp_buf, tmp, PAGE_SIZE);
+ lvip[lv_ix].lv_is_contiguous = 1;
+ ret = 1;
+ next_lp_ix = 1;
+ } else
+ next_lp_ix += 1;
+ }
+ for (i = 0; i < state->limit; i += 1)
+ if (lvip[i].pps_found && !lvip[i].lv_is_contiguous)
+ pr_warn("partition %s (%u pp's found) is "
+ "not contiguous\n",
+ n[i].name, lvip[i].pps_found);
+ kfree(pvd);
+ }
+ kfree(n);
+ kfree(lvip);
+ return ret;
+}
diff --git a/block/partitions/aix.h b/block/partitions/aix.h
new file mode 100644
index 000000000000..e0c66a987523
--- /dev/null
+++ b/block/partitions/aix.h
@@ -0,0 +1 @@
+extern int aix_partition(struct parsed_partitions *state);
diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c
index 7681cd295ab8..9123f250b425 100644
--- a/block/partitions/msdos.c
+++ b/block/partitions/msdos.c
@@ -23,6 +23,7 @@
#include "check.h"
#include "msdos.h"
#include "efi.h"
+#include "aix.h"
/*
* Many architectures don't like unaligned accesses, while
@@ -90,7 +91,7 @@ static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
ret = 1;
put_dev_sector(sect);
- };
+ }
return ret;
}
@@ -142,7 +143,7 @@ static void parse_extended(struct parsed_partitions *state,
return;
if (!msdos_magic_present(data + 510))
- goto done;
+ goto done;
p = (struct partition *) (data + 0x1be);
@@ -155,7 +156,7 @@ static void parse_extended(struct parsed_partitions *state,
* and OS/2 seems to use all four entries.
*/
- /*
+ /*
* First process the data partition(s)
*/
for (i=0; i<4; i++, p++) {
@@ -263,7 +264,7 @@ static void parse_solaris_x86(struct parsed_partitions *state,
}
#if defined(CONFIG_BSD_DISKLABEL)
-/*
+/*
* Create devices for BSD partitions listed in a disklabel, under a
* dos-like partition. See parse_extended() for more information.
*/
@@ -294,7 +295,7 @@ static void parse_bsd(struct parsed_partitions *state,
if (state->next == state->limit)
break;
- if (p->p_fstype == BSD_FS_UNUSED)
+ if (p->p_fstype == BSD_FS_UNUSED)
continue;
bsd_start = le32_to_cpu(p->p_offset);
bsd_size = le32_to_cpu(p->p_size);
@@ -441,7 +442,7 @@ static struct {
{NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
{0, NULL},
};
-
+
int msdos_partition(struct parsed_partitions *state)
{
sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
@@ -462,8 +463,12 @@ int msdos_partition(struct parsed_partitions *state)
*/
if (aix_magic_present(state, data)) {
put_dev_sector(sect);
+#ifdef CONFIG_AIX_PARTITION
+ return aix_partition(state);
+#else
strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
return 0;
+#endif
}
if (!msdos_magic_present(data + 510)) {
diff --git a/crypto/Kconfig b/crypto/Kconfig
index bf8148e74e73..69ce573f1224 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -376,6 +376,25 @@ config CRYPTO_CRC32_PCLMUL
which will enable any routine to use the CRC-32-IEEE 802.3 checksum
and gain better performance as compared with the table implementation.
+config CRYPTO_CRCT10DIF
+ tristate "CRCT10DIF algorithm"
+ select CRYPTO_HASH
+ help
+ CRC T10 Data Integrity Field computation is being cast as
+ a crypto transform. This allows for faster crc t10 diff
+ transforms to be used if they are available.
+
+config CRYPTO_CRCT10DIF_PCLMUL
+ tristate "CRCT10DIF PCLMULQDQ hardware acceleration"
+ depends on X86 && 64BIT && CRC_T10DIF
+ select CRYPTO_HASH
+ help
+ For x86_64 processors with SSE4.2 and PCLMULQDQ supported,
+ CRC T10 DIF PCLMULQDQ computation can be hardware
+ accelerated PCLMULQDQ instruction. This option will create
+ 'crct10dif-plcmul' module, which is faster when computing the
+ crct10dif checksum as compared with the generic table implementation.
+
config CRYPTO_GHASH
tristate "GHASH digest algorithm"
select CRYPTO_GF128MUL
@@ -820,25 +839,6 @@ config CRYPTO_BLOWFISH_X86_64
See also:
<http://www.schneier.com/blowfish.html>
-config CRYPTO_BLOWFISH_AVX2_X86_64
- tristate "Blowfish cipher algorithm (x86_64/AVX2)"
- depends on X86 && 64BIT
- depends on BROKEN
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER_X86
- select CRYPTO_BLOWFISH_COMMON
- select CRYPTO_BLOWFISH_X86_64
- help
- Blowfish cipher algorithm (x86_64/AVX2), by Bruce Schneier.
-
- This is a variable key length cipher which can use keys from 32
- bits to 448 bits in length. It's fast, simple and specifically
- designed for use on "large microprocessors".
-
- See also:
- <http://www.schneier.com/blowfish.html>
-
config CRYPTO_CAMELLIA
tristate "Camellia cipher algorithms"
depends on CRYPTO
@@ -1297,31 +1297,6 @@ config CRYPTO_TWOFISH_AVX_X86_64
See also:
<http://www.schneier.com/twofish.html>
-config CRYPTO_TWOFISH_AVX2_X86_64
- tristate "Twofish cipher algorithm (x86_64/AVX2)"
- depends on X86 && 64BIT
- depends on BROKEN
- select CRYPTO_ALGAPI
- select CRYPTO_CRYPTD
- select CRYPTO_ABLK_HELPER_X86
- select CRYPTO_GLUE_HELPER_X86
- select CRYPTO_TWOFISH_COMMON
- select CRYPTO_TWOFISH_X86_64
- select CRYPTO_TWOFISH_X86_64_3WAY
- select CRYPTO_TWOFISH_AVX_X86_64
- select CRYPTO_LRW
- select CRYPTO_XTS
- help
- Twofish cipher algorithm (x86_64/AVX2).
-
- Twofish was submitted as an AES (Advanced Encryption Standard)
- candidate cipher by researchers at CounterPane Systems. It is a
- 16 round block cipher supporting key sizes of 128, 192, and 256
- bits.
-
- See also:
- <http://www.schneier.com/twofish.html>
-
comment "Compression"
config CRYPTO_DEFLATE
@@ -1361,6 +1336,22 @@ config CRYPTO_842
help
This is the 842 algorithm.
+config CRYPTO_LZ4
+ tristate "LZ4 compression algorithm"
+ select CRYPTO_ALGAPI
+ select LZ4_COMPRESS
+ select LZ4_DECOMPRESS
+ help
+ This is the LZ4 algorithm.
+
+config CRYPTO_LZ4HC
+ tristate "LZ4HC compression algorithm"
+ select CRYPTO_ALGAPI
+ select LZ4HC_COMPRESS
+ select LZ4_DECOMPRESS
+ help
+ This is the LZ4 high compression mode algorithm.
+
comment "Random Number Generation"
config CRYPTO_ANSI_CPRNG
diff --git a/crypto/Makefile b/crypto/Makefile
index a8e9b0fefbe9..2d5ed08a239f 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -83,8 +83,11 @@ obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
+obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif.o
obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+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
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 6149a6e09643..7a1ae87f1683 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -495,7 +495,8 @@ static struct crypto_template *__crypto_lookup_template(const char *name)
struct crypto_template *crypto_lookup_template(const char *name)
{
- return try_then_request_module(__crypto_lookup_template(name), name);
+ return try_then_request_module(__crypto_lookup_template(name), "%s",
+ name);
}
EXPORT_SYMBOL_GPL(crypto_lookup_template);
diff --git a/crypto/async_tx/Kconfig b/crypto/async_tx/Kconfig
index 1b11abbb5c91..f38a58aef3ec 100644
--- a/crypto/async_tx/Kconfig
+++ b/crypto/async_tx/Kconfig
@@ -10,10 +10,6 @@ config ASYNC_XOR
select ASYNC_CORE
select XOR_BLOCKS
-config ASYNC_MEMSET
- tristate
- select ASYNC_CORE
-
config ASYNC_PQ
tristate
select ASYNC_CORE
diff --git a/crypto/async_tx/Makefile b/crypto/async_tx/Makefile
index d1e0e6f72bc1..462e4abbfe69 100644
--- a/crypto/async_tx/Makefile
+++ b/crypto/async_tx/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_ASYNC_CORE) += async_tx.o
obj-$(CONFIG_ASYNC_MEMCPY) += async_memcpy.o
-obj-$(CONFIG_ASYNC_MEMSET) += async_memset.o
obj-$(CONFIG_ASYNC_XOR) += async_xor.o
obj-$(CONFIG_ASYNC_PQ) += async_pq.o
obj-$(CONFIG_ASYNC_RAID6_RECOV) += async_raid6_recov.o
diff --git a/crypto/async_tx/async_memset.c b/crypto/async_tx/async_memset.c
deleted file mode 100644
index 05a4d1e00148..000000000000
--- a/crypto/async_tx/async_memset.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * memory fill offload engine support
- *
- * Copyright © 2006, Intel Corporation.
- *
- * Dan Williams <dan.j.williams@intel.com>
- *
- * with architecture considerations by:
- * Neil Brown <neilb@suse.de>
- * Jeff Garzik <jeff@garzik.org>
- *
- * 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, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/dma-mapping.h>
-#include <linux/async_tx.h>
-
-/**
- * async_memset - attempt to fill memory with a dma engine.
- * @dest: destination page
- * @val: fill value
- * @offset: offset in pages to start transaction
- * @len: length in bytes
- *
- * honored flags: ASYNC_TX_ACK
- */
-struct dma_async_tx_descriptor *
-async_memset(struct page *dest, int val, unsigned int offset, size_t len,
- struct async_submit_ctl *submit)
-{
- struct dma_chan *chan = async_tx_find_channel(submit, DMA_MEMSET,
- &dest, 1, NULL, 0, len);
- struct dma_device *device = chan ? chan->device : NULL;
- struct dma_async_tx_descriptor *tx = NULL;
-
- if (device && is_dma_fill_aligned(device, offset, 0, len)) {
- dma_addr_t dma_dest;
- unsigned long dma_prep_flags = 0;
-
- if (submit->cb_fn)
- dma_prep_flags |= DMA_PREP_INTERRUPT;
- if (submit->flags & ASYNC_TX_FENCE)
- dma_prep_flags |= DMA_PREP_FENCE;
- dma_dest = dma_map_page(device->dev, dest, offset, len,
- DMA_FROM_DEVICE);
-
- tx = device->device_prep_dma_memset(chan, dma_dest, val, len,
- dma_prep_flags);
- }
-
- if (tx) {
- pr_debug("%s: (async) len: %zu\n", __func__, len);
- async_tx_submit(chan, tx, submit);
- } else { /* run the memset synchronously */
- void *dest_buf;
- pr_debug("%s: (sync) len: %zu\n", __func__, len);
-
- dest_buf = page_address(dest) + offset;
-
- /* wait for any prerequisite operations */
- async_tx_quiesce(&submit->depend_tx);
-
- memset(dest_buf, val, len);
-
- async_tx_sync_epilog(submit);
- }
-
- return tx;
-}
-EXPORT_SYMBOL_GPL(async_memset);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_DESCRIPTION("asynchronous memset api");
-MODULE_LICENSE("GPL");
diff --git a/crypto/crct10dif.c b/crypto/crct10dif.c
new file mode 100644
index 000000000000..92aca96d6b98
--- /dev/null
+++ b/crypto/crct10dif.c
@@ -0,0 +1,178 @@
+/*
+ * Cryptographic API.
+ *
+ * T10 Data Integrity Field CRC16 Crypto Transform
+ *
+ * Copyright (c) 2007 Oracle Corporation. All rights reserved.
+ * Written by Martin K. Petersen <martin.petersen@oracle.com>
+ * 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/crc-t10dif.h>
+#include <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+struct chksum_desc_ctx {
+ __u16 crc;
+};
+
+/* Table generated using the following polynomium:
+ * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
+ * gt: 0x8bb7
+ */
+static const __u16 t10_dif_crc_table[256] = {
+ 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
+ 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
+ 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
+ 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
+ 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
+ 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
+ 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
+ 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
+ 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
+ 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
+ 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
+ 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
+ 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
+ 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
+ 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
+ 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
+ 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
+ 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
+ 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
+ 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
+ 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
+ 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
+ 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
+ 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
+ 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
+ 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
+ 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
+ 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
+ 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
+ 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
+ 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
+ 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
+};
+
+__u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len)
+{
+ unsigned int i;
+
+ for (i = 0 ; i < len ; i++)
+ crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
+
+ return crc;
+}
+EXPORT_SYMBOL(crc_t10dif_generic);
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static int chksum_init(struct shash_desc *desc)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ ctx->crc = 0;
+
+ return 0;
+}
+
+static int chksum_update(struct shash_desc *desc, const u8 *data,
+ unsigned int length)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
+ return 0;
+}
+
+static int chksum_final(struct shash_desc *desc, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ *(__u16 *)out = ctx->crc;
+ return 0;
+}
+
+static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
+ u8 *out)
+{
+ *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
+ return 0;
+}
+
+static int chksum_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ return __chksum_finup(&ctx->crc, data, len, out);
+}
+
+static int chksum_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int length, u8 *out)
+{
+ struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+ return __chksum_finup(&ctx->crc, data, length, out);
+}
+
+static struct shash_alg alg = {
+ .digestsize = CRC_T10DIF_DIGEST_SIZE,
+ .init = chksum_init,
+ .update = chksum_update,
+ .final = chksum_final,
+ .finup = chksum_finup,
+ .digest = chksum_digest,
+ .descsize = sizeof(struct chksum_desc_ctx),
+ .base = {
+ .cra_name = "crct10dif",
+ .cra_driver_name = "crct10dif-generic",
+ .cra_priority = 100,
+ .cra_blocksize = CRC_T10DIF_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static int __init crct10dif_mod_init(void)
+{
+ int ret;
+
+ ret = crypto_register_shash(&alg);
+ return ret;
+}
+
+static void __exit crct10dif_mod_fini(void)
+{
+ crypto_unregister_shash(&alg);
+}
+
+module_init(crct10dif_mod_init);
+module_exit(crct10dif_mod_fini);
+
+MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
+MODULE_DESCRIPTION("T10 DIF CRC calculation.");
+MODULE_LICENSE("GPL");
diff --git a/crypto/lz4.c b/crypto/lz4.c
new file mode 100644
index 000000000000..4586dd15b0d8
--- /dev/null
+++ b/crypto/lz4.c
@@ -0,0 +1,106 @@
+/*
+ * Cryptographic API.
+ *
+ * Copyright (c) 2013 Chanho Min <chanho.min@lge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/lz4.h>
+
+struct lz4_ctx {
+ void *lz4_comp_mem;
+};
+
+static int lz4_init(struct crypto_tfm *tfm)
+{
+ struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->lz4_comp_mem = vmalloc(LZ4_MEM_COMPRESS);
+ if (!ctx->lz4_comp_mem)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void lz4_exit(struct crypto_tfm *tfm)
+{
+ struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);
+ vfree(ctx->lz4_comp_mem);
+}
+
+static int lz4_compress_crypto(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct lz4_ctx *ctx = crypto_tfm_ctx(tfm);
+ size_t tmp_len = *dlen;
+ int err;
+
+ err = lz4_compress(src, slen, dst, &tmp_len, ctx->lz4_comp_mem);
+
+ if (err < 0)
+ return -EINVAL;
+
+ *dlen = tmp_len;
+ return 0;
+}
+
+static int lz4_decompress_crypto(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ int err;
+ size_t tmp_len = *dlen;
+ size_t __slen = slen;
+
+ err = lz4_decompress(src, &__slen, dst, tmp_len);
+ if (err < 0)
+ return -EINVAL;
+
+ *dlen = tmp_len;
+ return err;
+}
+
+static struct crypto_alg alg_lz4 = {
+ .cra_name = "lz4",
+ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
+ .cra_ctxsize = sizeof(struct lz4_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(alg_lz4.cra_list),
+ .cra_init = lz4_init,
+ .cra_exit = lz4_exit,
+ .cra_u = { .compress = {
+ .coa_compress = lz4_compress_crypto,
+ .coa_decompress = lz4_decompress_crypto } }
+};
+
+static int __init lz4_mod_init(void)
+{
+ return crypto_register_alg(&alg_lz4);
+}
+
+static void __exit lz4_mod_fini(void)
+{
+ crypto_unregister_alg(&alg_lz4);
+}
+
+module_init(lz4_mod_init);
+module_exit(lz4_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LZ4 Compression Algorithm");
diff --git a/crypto/lz4hc.c b/crypto/lz4hc.c
new file mode 100644
index 000000000000..151ba31d34e3
--- /dev/null
+++ b/crypto/lz4hc.c
@@ -0,0 +1,106 @@
+/*
+ * Cryptographic API.
+ *
+ * Copyright (c) 2013 Chanho Min <chanho.min@lge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 51
+ * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/lz4.h>
+
+struct lz4hc_ctx {
+ void *lz4hc_comp_mem;
+};
+
+static int lz4hc_init(struct crypto_tfm *tfm)
+{
+ struct lz4hc_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->lz4hc_comp_mem = vmalloc(LZ4HC_MEM_COMPRESS);
+ if (!ctx->lz4hc_comp_mem)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void lz4hc_exit(struct crypto_tfm *tfm)
+{
+ struct lz4hc_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ vfree(ctx->lz4hc_comp_mem);
+}
+
+static int lz4hc_compress_crypto(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ struct lz4hc_ctx *ctx = crypto_tfm_ctx(tfm);
+ size_t tmp_len = *dlen;
+ int err;
+
+ err = lz4hc_compress(src, slen, dst, &tmp_len, ctx->lz4hc_comp_mem);
+
+ if (err < 0)
+ return -EINVAL;
+
+ *dlen = tmp_len;
+ return 0;
+}
+
+static int lz4hc_decompress_crypto(struct crypto_tfm *tfm, const u8 *src,
+ unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+ int err;
+ size_t tmp_len = *dlen;
+ size_t __slen = slen;
+
+ err = lz4_decompress(src, &__slen, dst, tmp_len);
+ if (err < 0)
+ return -EINVAL;
+
+ *dlen = tmp_len;
+ return err;
+}
+
+static struct crypto_alg alg_lz4hc = {
+ .cra_name = "lz4hc",
+ .cra_flags = CRYPTO_ALG_TYPE_COMPRESS,
+ .cra_ctxsize = sizeof(struct lz4hc_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(alg_lz4hc.cra_list),
+ .cra_init = lz4hc_init,
+ .cra_exit = lz4hc_exit,
+ .cra_u = { .compress = {
+ .coa_compress = lz4hc_compress_crypto,
+ .coa_decompress = lz4hc_decompress_crypto } }
+};
+
+static int __init lz4hc_mod_init(void)
+{
+ return crypto_register_alg(&alg_lz4hc);
+}
+
+static void __exit lz4hc_mod_fini(void)
+{
+ crypto_unregister_alg(&alg_lz4hc);
+}
+
+module_init(lz4hc_mod_init);
+module_exit(lz4hc_mod_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("LZ4HC Compression Algorithm");
diff --git a/crypto/pcrypt.c b/crypto/pcrypt.c
index b2c99dc1c5e2..f8c920cafe63 100644
--- a/crypto/pcrypt.c
+++ b/crypto/pcrypt.c
@@ -455,8 +455,8 @@ static int pcrypt_init_padata(struct padata_pcrypt *pcrypt,
get_online_cpus();
- pcrypt->wq = alloc_workqueue(name,
- WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+ pcrypt->wq = alloc_workqueue("%s", WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE,
+ 1, name);
if (!pcrypt->wq)
goto err;
diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c
index 4c5862095679..6ed124f3ea0f 100644
--- a/crypto/sha512_generic.c
+++ b/crypto/sha512_generic.c
@@ -251,6 +251,7 @@ static struct shash_alg sha512_algs[2] = { {
.descsize = sizeof(struct sha512_state),
.base = {
.cra_name = "sha512",
+ .cra_driver_name = "sha512-generic",
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_module = THIS_MODULE,
@@ -263,6 +264,7 @@ static struct shash_alg sha512_algs[2] = { {
.descsize = sizeof(struct sha512_state),
.base = {
.cra_name = "sha384",
+ .cra_driver_name = "sha384-generic",
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_module = THIS_MODULE,
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 66d254ce0d11..25a5934f0e50 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1174,6 +1174,10 @@ static int do_test(int m)
ret += tcrypt_test("ghash");
break;
+ case 47:
+ ret += tcrypt_test("crct10dif");
+ break;
+
case 100:
ret += tcrypt_test("hmac(md5)");
break;
@@ -1498,6 +1502,10 @@ static int do_test(int m)
test_hash_speed("crc32c", sec, generic_hash_speed_template);
if (mode > 300 && mode < 400) break;
+ case 320:
+ test_hash_speed("crct10dif", sec, generic_hash_speed_template);
+ if (mode > 300 && mode < 400) break;
+
case 399:
break;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5823735cf381..2f00607039e2 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -184,8 +184,9 @@ static int do_one_async_hash_op(struct ahash_request *req,
return ret;
}
-static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
- unsigned int tcount, bool use_digest)
+static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
+ unsigned int tcount, bool use_digest,
+ const int align_offset)
{
const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm));
unsigned int i, j, k, temp;
@@ -216,10 +217,15 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
if (template[i].np)
continue;
+ ret = -EINVAL;
+ if (WARN_ON(align_offset + template[i].psize > PAGE_SIZE))
+ goto out;
+
j++;
memset(result, 0, 64);
hash_buff = xbuf[0];
+ hash_buff += align_offset;
memcpy(hash_buff, template[i].plaintext, template[i].psize);
sg_init_one(&sg[0], hash_buff, template[i].psize);
@@ -281,6 +287,10 @@ static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
j = 0;
for (i = 0; i < tcount; i++) {
+ /* alignment tests are only done with continuous buffers */
+ if (align_offset != 0)
+ break;
+
if (template[i].np) {
j++;
memset(result, 0, 64);
@@ -358,9 +368,36 @@ out_nobuf:
return ret;
}
+static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
+ unsigned int tcount, bool use_digest)
+{
+ unsigned int alignmask;
+ int ret;
+
+ ret = __test_hash(tfm, template, tcount, use_digest, 0);
+ if (ret)
+ return ret;
+
+ /* test unaligned buffers, check with one byte offset */
+ ret = __test_hash(tfm, template, tcount, use_digest, 1);
+ if (ret)
+ return ret;
+
+ alignmask = crypto_tfm_alg_alignmask(&tfm->base);
+ if (alignmask) {
+ /* Check if alignment mask for tfm is correctly set. */
+ ret = __test_hash(tfm, template, tcount, use_digest,
+ alignmask + 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int __test_aead(struct crypto_aead *tfm, int enc,
struct aead_testvec *template, unsigned int tcount,
- const bool diff_dst)
+ const bool diff_dst, const int align_offset)
{
const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
unsigned int i, j, k, n, temp;
@@ -423,15 +460,16 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
if (!template[i].np) {
j++;
- /* some tepmplates have no input data but they will
+ /* some templates have no input data but they will
* touch input
*/
input = xbuf[0];
+ input += align_offset;
assoc = axbuf[0];
ret = -EINVAL;
- if (WARN_ON(template[i].ilen > PAGE_SIZE ||
- template[i].alen > PAGE_SIZE))
+ if (WARN_ON(align_offset + template[i].ilen >
+ PAGE_SIZE || template[i].alen > PAGE_SIZE))
goto out;
memcpy(input, template[i].input, template[i].ilen);
@@ -470,6 +508,7 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
if (diff_dst) {
output = xoutbuf[0];
+ output += align_offset;
sg_init_one(&sgout[0], output,
template[i].ilen +
(enc ? authsize : 0));
@@ -530,6 +569,10 @@ static int __test_aead(struct crypto_aead *tfm, int enc,
}
for (i = 0, j = 0; i < tcount; i++) {
+ /* alignment tests are only done with continuous buffers */
+ if (align_offset != 0)
+ break;
+
if (template[i].np) {
j++;
@@ -732,15 +775,34 @@ out_noxbuf:
static int test_aead(struct crypto_aead *tfm, int enc,
struct aead_testvec *template, unsigned int tcount)
{
+ unsigned int alignmask;
int ret;
/* test 'dst == src' case */
- ret = __test_aead(tfm, enc, template, tcount, false);
+ ret = __test_aead(tfm, enc, template, tcount, false, 0);
if (ret)
return ret;
/* test 'dst != src' case */
- return __test_aead(tfm, enc, template, tcount, true);
+ ret = __test_aead(tfm, enc, template, tcount, true, 0);
+ if (ret)
+ return ret;
+
+ /* test unaligned buffers, check with one byte offset */
+ ret = __test_aead(tfm, enc, template, tcount, true, 1);
+ if (ret)
+ return ret;
+
+ alignmask = crypto_tfm_alg_alignmask(&tfm->base);
+ if (alignmask) {
+ /* Check if alignment mask for tfm is correctly set. */
+ ret = __test_aead(tfm, enc, template, tcount, true,
+ alignmask + 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int test_cipher(struct crypto_cipher *tfm, int enc,
@@ -820,7 +882,7 @@ out_nobuf:
static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc,
struct cipher_testvec *template, unsigned int tcount,
- const bool diff_dst)
+ const bool diff_dst, const int align_offset)
{
const char *algo =
crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm));
@@ -876,10 +938,12 @@ static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc,
j++;
ret = -EINVAL;
- if (WARN_ON(template[i].ilen > PAGE_SIZE))
+ if (WARN_ON(align_offset + template[i].ilen >
+ PAGE_SIZE))
goto out;
data = xbuf[0];
+ data += align_offset;
memcpy(data, template[i].input, template[i].ilen);
crypto_ablkcipher_clear_flags(tfm, ~0);
@@ -900,6 +964,7 @@ static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc,
sg_init_one(&sg[0], data, template[i].ilen);
if (diff_dst) {
data = xoutbuf[0];
+ data += align_offset;
sg_init_one(&sgout[0], data, template[i].ilen);
}
@@ -941,6 +1006,9 @@ static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc,
j = 0;
for (i = 0; i < tcount; i++) {
+ /* alignment tests are only done with continuous buffers */
+ if (align_offset != 0)
+ break;
if (template[i].iv)
memcpy(iv, template[i].iv, MAX_IVLEN);
@@ -1075,15 +1143,34 @@ out_nobuf:
static int test_skcipher(struct crypto_ablkcipher *tfm, int enc,
struct cipher_testvec *template, unsigned int tcount)
{
+ unsigned int alignmask;
int ret;
/* test 'dst == src' case */
- ret = __test_skcipher(tfm, enc, template, tcount, false);
+ ret = __test_skcipher(tfm, enc, template, tcount, false, 0);
if (ret)
return ret;
/* test 'dst != src' case */
- return __test_skcipher(tfm, enc, template, tcount, true);
+ ret = __test_skcipher(tfm, enc, template, tcount, true, 0);
+ if (ret)
+ return ret;
+
+ /* test unaligned buffers, check with one byte offset */
+ ret = __test_skcipher(tfm, enc, template, tcount, true, 1);
+ if (ret)
+ return ret;
+
+ alignmask = crypto_tfm_alg_alignmask(&tfm->base);
+ if (alignmask) {
+ /* Check if alignment mask for tfm is correctly set. */
+ ret = __test_skcipher(tfm, enc, template, tcount, true,
+ alignmask + 1);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate,
@@ -1654,16 +1741,10 @@ static const struct alg_test_desc alg_test_descs[] = {
.alg = "__cbc-twofish-avx",
.test = alg_test_null,
}, {
- .alg = "__cbc-twofish-avx2",
- .test = alg_test_null,
- }, {
.alg = "__driver-cbc-aes-aesni",
.test = alg_test_null,
.fips_allowed = 1,
}, {
- .alg = "__driver-cbc-blowfish-avx2",
- .test = alg_test_null,
- }, {
.alg = "__driver-cbc-camellia-aesni",
.test = alg_test_null,
}, {
@@ -1688,16 +1769,10 @@ static const struct alg_test_desc alg_test_descs[] = {
.alg = "__driver-cbc-twofish-avx",
.test = alg_test_null,
}, {
- .alg = "__driver-cbc-twofish-avx2",
- .test = alg_test_null,
- }, {
.alg = "__driver-ecb-aes-aesni",
.test = alg_test_null,
.fips_allowed = 1,
}, {
- .alg = "__driver-ecb-blowfish-avx2",
- .test = alg_test_null,
- }, {
.alg = "__driver-ecb-camellia-aesni",
.test = alg_test_null,
}, {
@@ -1722,9 +1797,6 @@ static const struct alg_test_desc alg_test_descs[] = {
.alg = "__driver-ecb-twofish-avx",
.test = alg_test_null,
}, {
- .alg = "__driver-ecb-twofish-avx2",
- .test = alg_test_null,
- }, {
.alg = "__ghash-pclmulqdqni",
.test = alg_test_null,
.fips_allowed = 1,
@@ -1974,12 +2046,19 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
- .alg = "cryptd(__driver-cbc-aes-aesni)",
- .test = alg_test_null,
+ .alg = "crct10dif",
+ .test = alg_test_hash,
.fips_allowed = 1,
+ .suite = {
+ .hash = {
+ .vecs = crct10dif_tv_template,
+ .count = CRCT10DIF_TEST_VECTORS
+ }
+ }
}, {
- .alg = "cryptd(__driver-cbc-blowfish-avx2)",
+ .alg = "cryptd(__driver-cbc-aes-aesni)",
.test = alg_test_null,
+ .fips_allowed = 1,
}, {
.alg = "cryptd(__driver-cbc-camellia-aesni)",
.test = alg_test_null,
@@ -1994,9 +2073,6 @@ static const struct alg_test_desc alg_test_descs[] = {
.test = alg_test_null,
.fips_allowed = 1,
}, {
- .alg = "cryptd(__driver-ecb-blowfish-avx2)",
- .test = alg_test_null,
- }, {
.alg = "cryptd(__driver-ecb-camellia-aesni)",
.test = alg_test_null,
}, {
@@ -2021,9 +2097,6 @@ static const struct alg_test_desc alg_test_descs[] = {
.alg = "cryptd(__driver-ecb-twofish-avx)",
.test = alg_test_null,
}, {
- .alg = "cryptd(__driver-ecb-twofish-avx2)",
- .test = alg_test_null,
- }, {
.alg = "cryptd(__driver-gcm-aes-aesni)",
.test = alg_test_null,
.fips_allowed = 1,
@@ -3068,6 +3141,35 @@ static const struct alg_test_desc alg_test_descs[] = {
}
};
+static bool alg_test_descs_checked;
+
+static void alg_test_descs_check_order(void)
+{
+ int i;
+
+ /* only check once */
+ if (alg_test_descs_checked)
+ return;
+
+ alg_test_descs_checked = true;
+
+ for (i = 1; i < ARRAY_SIZE(alg_test_descs); i++) {
+ int diff = strcmp(alg_test_descs[i - 1].alg,
+ alg_test_descs[i].alg);
+
+ if (WARN_ON(diff > 0)) {
+ pr_warn("testmgr: alg_test_descs entries in wrong order: '%s' before '%s'\n",
+ alg_test_descs[i - 1].alg,
+ alg_test_descs[i].alg);
+ }
+
+ if (WARN_ON(diff == 0)) {
+ pr_warn("testmgr: duplicate alg_test_descs entry: '%s'\n",
+ alg_test_descs[i].alg);
+ }
+ }
+}
+
static int alg_find_test(const char *alg)
{
int start = 0;
@@ -3099,6 +3201,8 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
int j;
int rc;
+ alg_test_descs_check_order();
+
if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) {
char nalg[CRYPTO_MAX_ALG_NAME];
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 1e701bc075b9..7d44aa3d6b44 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -450,6 +450,39 @@ static struct hash_testvec rmd320_tv_template[] = {
}
};
+#define CRCT10DIF_TEST_VECTORS 3
+static struct hash_testvec crct10dif_tv_template[] = {
+ {
+ .plaintext = "abc",
+ .psize = 3,
+#ifdef __LITTLE_ENDIAN
+ .digest = "\x3b\x44",
+#else
+ .digest = "\x44\x3b",
+#endif
+ }, {
+ .plaintext = "1234567890123456789012345678901234567890"
+ "123456789012345678901234567890123456789",
+ .psize = 79,
+#ifdef __LITTLE_ENDIAN
+ .digest = "\x70\x4b",
+#else
+ .digest = "\x4b\x70",
+#endif
+ }, {
+ .plaintext =
+ "abcddddddddddddddddddddddddddddddddddddddddddddddddddddd",
+ .psize = 56,
+#ifdef __LITTLE_ENDIAN
+ .digest = "\xe3\x9c",
+#else
+ .digest = "\x9c\xe3",
+#endif
+ .np = 2,
+ .tap = { 28, 28 }
+ }
+};
+
/*
* SHA1 test vectors from from FIPS PUB 180-1
* Long vector from CAVS 5.0
diff --git a/drivers/Kconfig b/drivers/Kconfig
index ae050b54c368..aa43b911ccef 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,8 +52,6 @@ source "drivers/i2c/Kconfig"
source "drivers/spi/Kconfig"
-source "drivers/ssbi/Kconfig"
-
source "drivers/hsi/Kconfig"
source "drivers/pps/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 336b0ad0acd0..ab93de8297f1 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -117,7 +117,6 @@ obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
obj-$(CONFIG_ARCH_SHMOBILE) += sh/
-obj-$(CONFIG_SSBI) += ssbi/
ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
obj-y += clocksource/
endif
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 536562c626a2..81dbeb83bb45 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -34,6 +34,7 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o
acpi-y += bus.o glue.o
acpi-y += scan.o
acpi-y += resource.o
+acpi-y += acpi_processor.o
acpi-y += processor_core.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
@@ -43,6 +44,7 @@ acpi-y += acpi_platform.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+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
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
new file mode 100644
index 000000000000..84190ed89c04
--- /dev/null
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -0,0 +1,92 @@
+/*
+ * ACPI support for CMOS RTC Address Space access
+ *
+ * Copyright (C) 2013, Intel Corporation
+ * Authors: Lan Tianyu <tianyu.lan@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm-generic/rtc.h>
+
+#include "internal.h"
+
+#define PREFIX "ACPI: "
+
+ACPI_MODULE_NAME("cmos rtc");
+
+static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
+ { "PNP0B00" },
+ { "PNP0B01" },
+ { "PNP0B02" },
+ {}
+};
+
+static acpi_status
+acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ int i;
+ u8 *value = (u8 *)&value64;
+
+ if (address > 0xff || !value64)
+ return AE_BAD_PARAMETER;
+
+ if (function != ACPI_WRITE && function != ACPI_READ)
+ return AE_BAD_PARAMETER;
+
+ spin_lock_irq(&rtc_lock);
+
+ for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
+ if (function == ACPI_READ)
+ *value = CMOS_READ(address);
+ else
+ CMOS_WRITE(*value, address);
+
+ spin_unlock_irq(&rtc_lock);
+
+ return AE_OK;
+}
+
+static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+ acpi_status status;
+
+ status = acpi_install_address_space_handler(adev->handle,
+ ACPI_ADR_SPACE_CMOS,
+ &acpi_cmos_rtc_space_handler,
+ NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ pr_err(PREFIX "Error installing CMOS-RTC region handler\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
+{
+ if (ACPI_FAILURE(acpi_remove_address_space_handler(adev->handle,
+ ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
+ pr_err(PREFIX "Error removing CMOS-RTC region handler\n");
+}
+
+static struct acpi_scan_handler cmos_rtc_handler = {
+ .ids = acpi_cmos_rtc_ids,
+ .attach = acpi_install_cmos_rtc_space_handler,
+ .detach = acpi_remove_cmos_rtc_space_handler,
+};
+
+void __init acpi_cmos_rtc_init(void)
+{
+ acpi_scan_add_handler(&cmos_rtc_handler);
+}
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index cab13f2fc28e..6a382188fa20 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -32,12 +32,26 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
#define LPSS_SW_LTR 0x10
#define LPSS_AUTO_LTR 0x14
+#define LPSS_TX_INT 0x20
+#define LPSS_TX_INT_MASK BIT(1)
+
+struct lpss_shared_clock {
+ const char *name;
+ unsigned long rate;
+ struct clk *clk;
+};
+
+struct lpss_private_data;
struct lpss_device_desc {
bool clk_required;
const char *clkdev_name;
bool ltr_required;
unsigned int prv_offset;
+ size_t prv_size_override;
+ bool clk_gate;
+ struct lpss_shared_clock *shared_clock;
+ void (*setup)(struct lpss_private_data *pdata);
};
static struct lpss_device_desc lpss_dma_desc = {
@@ -52,17 +66,76 @@ struct lpss_private_data {
const struct lpss_device_desc *dev_desc;
};
+static void lpss_uart_setup(struct lpss_private_data *pdata)
+{
+ unsigned int tx_int_offset = pdata->dev_desc->prv_offset + LPSS_TX_INT;
+ u32 reg;
+
+ reg = readl(pdata->mmio_base + tx_int_offset);
+ writel(reg | LPSS_TX_INT_MASK, pdata->mmio_base + tx_int_offset);
+}
+
static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
+ .clk_gate = true,
+};
+
+static struct lpss_device_desc lpt_uart_dev_desc = {
+ .clk_required = true,
+ .prv_offset = 0x800,
+ .ltr_required = true,
+ .clk_gate = true,
+ .setup = lpss_uart_setup,
};
static struct lpss_device_desc lpt_sdio_dev_desc = {
.prv_offset = 0x1000,
+ .prv_size_override = 0x1018,
.ltr_required = true,
};
+static struct lpss_shared_clock uart_clock = {
+ .name = "uart_clk",
+ .rate = 44236800,
+};
+
+static struct lpss_device_desc byt_uart_dev_desc = {
+ .clk_required = true,
+ .prv_offset = 0x800,
+ .clk_gate = true,
+ .shared_clock = &uart_clock,
+ .setup = lpss_uart_setup,
+};
+
+static struct lpss_shared_clock spi_clock = {
+ .name = "spi_clk",
+ .rate = 50000000,
+};
+
+static struct lpss_device_desc byt_spi_dev_desc = {
+ .clk_required = true,
+ .prv_offset = 0x400,
+ .clk_gate = true,
+ .shared_clock = &spi_clock,
+};
+
+static struct lpss_device_desc byt_sdio_dev_desc = {
+ .clk_required = true,
+};
+
+static struct lpss_shared_clock i2c_clock = {
+ .name = "i2c_clk",
+ .rate = 100000000,
+};
+
+static struct lpss_device_desc byt_i2c_dev_desc = {
+ .clk_required = true,
+ .prv_offset = 0x800,
+ .shared_clock = &i2c_clock,
+};
+
static const struct acpi_device_id acpi_lpss_device_ids[] = {
/* Generic LPSS devices */
{ "INTL9C60", (unsigned long)&lpss_dma_desc },
@@ -72,11 +145,18 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
{ "INT33C1", (unsigned long)&lpt_dev_desc },
{ "INT33C2", (unsigned long)&lpt_dev_desc },
{ "INT33C3", (unsigned long)&lpt_dev_desc },
- { "INT33C4", (unsigned long)&lpt_dev_desc },
- { "INT33C5", (unsigned long)&lpt_dev_desc },
+ { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
+ { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
{ "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
{ "INT33C7", },
+ /* BayTrail LPSS devices */
+ { "80860F0A", (unsigned long)&byt_uart_dev_desc },
+ { "80860F0E", (unsigned long)&byt_spi_dev_desc },
+ { "80860F14", (unsigned long)&byt_sdio_dev_desc },
+ { "80860F41", (unsigned long)&byt_i2c_dev_desc },
+ { "INT33B2", },
+
{ }
};
@@ -98,7 +178,10 @@ static int register_device_clock(struct acpi_device *adev,
struct lpss_private_data *pdata)
{
const struct lpss_device_desc *dev_desc = pdata->dev_desc;
+ struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
+ struct clk *clk = ERR_PTR(-ENODEV);
struct lpss_clk_data *clk_data;
+ const char *parent;
if (!lpss_clk_dev)
lpt_register_clock_device();
@@ -117,14 +200,30 @@ static int register_device_clock(struct acpi_device *adev,
|| pdata->mmio_size < dev_desc->prv_offset + LPSS_CLK_SIZE)
return -ENODATA;
- pdata->clk = clk_register_gate(NULL, dev_name(&adev->dev),
- clk_data->name, 0,
- pdata->mmio_base + dev_desc->prv_offset,
- 0, 0, NULL);
- if (IS_ERR(pdata->clk))
- return PTR_ERR(pdata->clk);
+ parent = clk_data->name;
+
+ if (shared_clock) {
+ clk = shared_clock->clk;
+ if (!clk) {
+ clk = clk_register_fixed_rate(NULL, shared_clock->name,
+ "lpss_clk", 0,
+ shared_clock->rate);
+ shared_clock->clk = clk;
+ }
+ parent = shared_clock->name;
+ }
+
+ if (dev_desc->clk_gate) {
+ clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0,
+ pdata->mmio_base + dev_desc->prv_offset,
+ 0, 0, NULL);
+ pdata->clk = clk;
+ }
- clk_register_clkdev(pdata->clk, NULL, dev_name(&adev->dev));
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ clk_register_clkdev(clk, NULL, dev_name(&adev->dev));
return 0;
}
@@ -152,7 +251,10 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
list_for_each_entry(rentry, &resource_list, node)
if (resource_type(&rentry->res) == IORESOURCE_MEM) {
- pdata->mmio_size = resource_size(&rentry->res);
+ if (dev_desc->prv_size_override)
+ pdata->mmio_size = dev_desc->prv_size_override;
+ else
+ pdata->mmio_size = resource_size(&rentry->res);
pdata->mmio_base = ioremap(rentry->res.start,
pdata->mmio_size);
pdata->dev_desc = dev_desc;
@@ -182,6 +284,9 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
goto err_out;
}
+ if (dev_desc->setup)
+ dev_desc->setup(pdata);
+
adev->driver_data = pdata;
ret = acpi_create_platform_device(adev, id);
if (ret > 0)
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 5e6301e94920..c711d1144044 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -28,6 +28,7 @@
*/
#include <linux/acpi.h>
+#include <linux/memory.h>
#include <linux/memory_hotplug.h>
#include "internal.h"
@@ -166,13 +167,50 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
return 0;
}
+static unsigned long acpi_meminfo_start_pfn(struct acpi_memory_info *info)
+{
+ return PFN_DOWN(info->start_addr);
+}
+
+static unsigned long acpi_meminfo_end_pfn(struct acpi_memory_info *info)
+{
+ return PFN_UP(info->start_addr + info->length-1);
+}
+
+static int acpi_bind_memblk(struct memory_block *mem, void *arg)
+{
+ return acpi_bind_one(&mem->dev, (acpi_handle)arg);
+}
+
+static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
+ acpi_handle handle)
+{
+ return walk_memory_range(acpi_meminfo_start_pfn(info),
+ acpi_meminfo_end_pfn(info), (void *)handle,
+ acpi_bind_memblk);
+}
+
+static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
+{
+ acpi_unbind_one(&mem->dev);
+ return 0;
+}
+
+static void acpi_unbind_memory_blocks(struct acpi_memory_info *info,
+ acpi_handle handle)
+{
+ walk_memory_range(acpi_meminfo_start_pfn(info),
+ acpi_meminfo_end_pfn(info), NULL, acpi_unbind_memblk);
+}
+
static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
{
+ acpi_handle handle = mem_device->device->handle;
int result, num_enabled = 0;
struct acpi_memory_info *info;
int node;
- node = acpi_get_node(mem_device->device->handle);
+ node = acpi_get_node(handle);
/*
* Tell the VM there is more memory here...
* Note: Assume that this function returns zero on success
@@ -203,6 +241,12 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
if (result && result != -EEXIST)
continue;
+ result = acpi_bind_memory_blocks(info, handle);
+ if (result) {
+ acpi_unbind_memory_blocks(info, handle);
+ return -ENODEV;
+ }
+
info->enabled = 1;
/*
@@ -227,12 +271,11 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
return 0;
}
-static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
+static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
{
- int result = 0, nid;
+ acpi_handle handle = mem_device->device->handle;
struct acpi_memory_info *info, *n;
-
- nid = acpi_get_node(mem_device->device->handle);
+ int nid = acpi_get_node(handle);
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
if (!info->enabled)
@@ -240,15 +283,12 @@ static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
if (nid < 0)
nid = memory_add_physaddr_to_nid(info->start_addr);
- result = remove_memory(nid, info->start_addr, info->length);
- if (result)
- return result;
+ acpi_unbind_memory_blocks(info, handle);
+ remove_memory(nid, info->start_addr, info->length);
list_del(&info->list);
kfree(info);
}
-
- return result;
}
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
@@ -300,7 +340,7 @@ static int acpi_memory_device_add(struct acpi_device *device,
if (result) {
dev_err(&device->dev, "acpi_memory_enable_device() error\n");
acpi_memory_device_free(mem_device);
- return -ENODEV;
+ return result;
}
dev_dbg(&device->dev, "Memory device configured by ACPI\n");
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
new file mode 100644
index 000000000000..e9b01e35ac37
--- /dev/null
+++ b/drivers/acpi/acpi_processor.c
@@ -0,0 +1,494 @@
+/*
+ * acpi_processor.c - ACPI processor enumeration support
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * Copyright (C) 2013, Intel Corporation
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include <acpi/processor.h>
+
+#include <asm/cpu.h>
+
+#include "internal.h"
+
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+
+ACPI_MODULE_NAME("processor");
+
+DEFINE_PER_CPU(struct acpi_processor *, processors);
+EXPORT_PER_CPU_SYMBOL(processors);
+
+/* --------------------------------------------------------------------------
+ Errata Handling
+ -------------------------------------------------------------------------- */
+
+struct acpi_processor_errata errata __read_mostly;
+EXPORT_SYMBOL_GPL(errata);
+
+static int acpi_processor_errata_piix4(struct pci_dev *dev)
+{
+ u8 value1 = 0;
+ u8 value2 = 0;
+
+
+ if (!dev)
+ return -EINVAL;
+
+ /*
+ * Note that 'dev' references the PIIX4 ACPI Controller.
+ */
+
+ switch (dev->revision) {
+ case 0:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
+ break;
+ case 1:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
+ break;
+ case 2:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
+ break;
+ case 3:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
+ break;
+ }
+
+ switch (dev->revision) {
+
+ case 0: /* PIIX4 A-step */
+ case 1: /* PIIX4 B-step */
+ /*
+ * See specification changes #13 ("Manual Throttle Duty Cycle")
+ * and #14 ("Enabling and Disabling Manual Throttle"), plus
+ * erratum #5 ("STPCLK# Deassertion Time") from the January
+ * 2002 PIIX4 specification update. Applies to only older
+ * PIIX4 models.
+ */
+ errata.piix4.throttle = 1;
+
+ case 2: /* PIIX4E */
+ case 3: /* PIIX4M */
+ /*
+ * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
+ * Livelock") from the January 2002 PIIX4 specification update.
+ * Applies to all PIIX4 models.
+ */
+
+ /*
+ * BM-IDE
+ * ------
+ * Find the PIIX4 IDE Controller and get the Bus Master IDE
+ * Status register address. We'll use this later to read
+ * each IDE controller's DMA status to make sure we catch all
+ * DMA activity.
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB,
+ PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ errata.piix4.bmisx = pci_resource_start(dev, 4);
+ pci_dev_put(dev);
+ }
+
+ /*
+ * Type-F DMA
+ * ----------
+ * Find the PIIX4 ISA Controller and read the Motherboard
+ * DMA controller's status to see if Type-F (Fast) DMA mode
+ * is enabled (bit 7) on either channel. Note that we'll
+ * disable C3 support if this is enabled, as some legacy
+ * devices won't operate well if fast DMA is disabled.
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_0,
+ PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ pci_read_config_byte(dev, 0x76, &value1);
+ pci_read_config_byte(dev, 0x77, &value2);
+ if ((value1 & 0x80) || (value2 & 0x80))
+ errata.piix4.fdma = 1;
+ pci_dev_put(dev);
+ }
+
+ break;
+ }
+
+ if (errata.piix4.bmisx)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Bus master activity detection (BM-IDE) erratum enabled\n"));
+ if (errata.piix4.fdma)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Type-F DMA livelock erratum (C3 disabled)\n"));
+
+ return 0;
+}
+
+static int acpi_processor_errata(struct acpi_processor *pr)
+{
+ int result = 0;
+ struct pci_dev *dev = NULL;
+
+
+ if (!pr)
+ return -EINVAL;
+
+ /*
+ * PIIX4
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
+ PCI_ANY_ID, NULL);
+ if (dev) {
+ result = acpi_processor_errata_piix4(dev);
+ pci_dev_put(dev);
+ }
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------
+ Initialization
+ -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+static int acpi_processor_hotadd_init(struct acpi_processor *pr)
+{
+ unsigned long long sta;
+ acpi_status status;
+ int ret;
+
+ status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT))
+ return -ENODEV;
+
+ ret = acpi_map_lsapic(pr->handle, &pr->id);
+ if (ret)
+ return ret;
+
+ ret = arch_register_cpu(pr->id);
+ if (ret) {
+ acpi_unmap_lsapic(pr->id);
+ return ret;
+ }
+
+ /*
+ * CPU got hot-added, but cpu_data is not initialized yet. Set a flag
+ * to delay cpu_idle/throttling initialization and do it when the CPU
+ * gets online for the first time.
+ */
+ pr_info("CPU%d has been hot-added\n", pr->id);
+ pr->flags.need_hotplug_init = 1;
+ return 0;
+}
+#else
+static inline int acpi_processor_hotadd_init(struct acpi_processor *pr)
+{
+ return -ENODEV;
+}
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
+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);
+ int cpu_index, device_declaration = 0;
+ acpi_status status = AE_OK;
+ static int cpu0_initialized;
+
+ if (num_online_cpus() > 1)
+ errata.smp = TRUE;
+
+ acpi_processor_errata(pr);
+
+ /*
+ * Check to see if we have bus mastering arbitration control. This
+ * is required for proper C3 usage (to maintain cache coherency).
+ */
+ if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
+ pr->flags.bm_control = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Bus mastering arbitration control present\n"));
+ } else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No bus mastering arbitration control\n"));
+
+ if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
+ /* Declared with "Processor" statement; match ProcessorID */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&device->dev,
+ "Failed to evaluate processor object (0x%x)\n",
+ status);
+ return -ENODEV;
+ }
+
+ /*
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in
+ * arch/xxx/acpi.c
+ */
+ pr->acpi_id = object.processor.proc_id;
+ } else {
+ /*
+ * Declared with "Device" statement; match _UID.
+ * Note that we don't handle string _UIDs yet.
+ */
+ unsigned long long value;
+ status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+ NULL, &value);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&device->dev,
+ "Failed to evaluate processor _UID (0x%x)\n",
+ status);
+ return -ENODEV;
+ }
+ device_declaration = 1;
+ pr->acpi_id = value;
+ }
+ cpu_index = acpi_get_cpuid(pr->handle, device_declaration, pr->acpi_id);
+
+ /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ if (!cpu0_initialized && (cpu_index == -1) &&
+ (num_online_cpus() == 1)) {
+ cpu_index = 0;
+ }
+
+ cpu0_initialized = 1;
+
+ 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) {
+ int ret = acpi_processor_hotadd_init(pr);
+ if (ret)
+ return ret;
+ }
+ /*
+ * On some boxes several processors use the same processor bus id.
+ * But they are located in different scope. For example:
+ * \_SB.SCK0.CPU0
+ * \_SB.SCK1.CPU0
+ * Rename the processor device bus id. And the new bus id will be
+ * generated as the following format:
+ * CPU+CPU ID.
+ */
+ sprintf(acpi_device_bid(device), "CPU%X", pr->id);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
+ pr->acpi_id));
+
+ if (!object.processor.pblk_address)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
+ else if (object.processor.pblk_length != 6)
+ dev_err(&device->dev, "Invalid PBLK length [%d]\n",
+ object.processor.pblk_length);
+ else {
+ pr->throttling.address = object.processor.pblk_address;
+ pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+ pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
+
+ pr->pblk = object.processor.pblk_address;
+
+ /*
+ * We don't care about error returns - we just try to mark
+ * these reserved so that nobody else is confused into thinking
+ * that this region might be unused..
+ *
+ * (In particular, allocating the IO range for Cardbus)
+ */
+ request_region(pr->throttling.address, 6, "ACPI CPU throttle");
+ }
+
+ /*
+ * If ACPI describes a slot number for this CPU, we can use it to
+ * ensure we get the right value in the "physical id" field
+ * of /proc/cpuinfo
+ */
+ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
+ if (ACPI_SUCCESS(status))
+ arch_fix_phys_package_id(pr->id, object.integer.value);
+
+ return 0;
+}
+
+/*
+ * Do not put anything in here which needs the core to be online.
+ * For example MSR access or setting up things which check for cpuinfo_x86
+ * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.
+ * Such things have to be put in and set up by the processor driver's .probe().
+ */
+static DEFINE_PER_CPU(void *, processor_device_array);
+
+static int __cpuinit acpi_processor_add(struct acpi_device *device,
+ const struct acpi_device_id *id)
+{
+ struct acpi_processor *pr;
+ struct device *dev;
+ int result = 0;
+
+ pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+ if (!pr)
+ return -ENOMEM;
+
+ if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
+ result = -ENOMEM;
+ goto err_free_pr;
+ }
+
+ pr->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
+ device->driver_data = pr;
+
+ result = acpi_processor_get_info(device);
+ if (result) /* Processor is not physically present or unavailable */
+ return 0;
+
+#ifdef CONFIG_SMP
+ if (pr->id >= setup_max_cpus && pr->id != 0)
+ return 0;
+#endif
+
+ BUG_ON(pr->id >= nr_cpu_ids);
+
+ /*
+ * Buggy BIOS check.
+ * ACPI id of processors can be reported wrongly by the BIOS.
+ * Don't trust it blindly
+ */
+ if (per_cpu(processor_device_array, pr->id) != NULL &&
+ per_cpu(processor_device_array, pr->id) != device) {
+ dev_warn(&device->dev,
+ "BIOS reported wrong ACPI id %d for the processor\n",
+ pr->id);
+ /* Give up, but do not abort the namespace scan. */
+ goto err;
+ }
+ /*
+ * processor_device_array is not cleared on errors to allow buggy BIOS
+ * checks.
+ */
+ per_cpu(processor_device_array, pr->id) = device;
+ per_cpu(processors, pr->id) = pr;
+
+ dev = get_cpu_device(pr->id);
+ if (!dev) {
+ result = -ENODEV;
+ goto err;
+ }
+
+ result = acpi_bind_one(dev, pr->handle);
+ if (result)
+ goto err;
+
+ pr->dev = dev;
+ dev->offline = pr->flags.need_hotplug_init;
+
+ /* Trigger the processor driver's .probe() if present. */
+ if (device_attach(dev) >= 0)
+ return 1;
+
+ dev_err(dev, "Processor driver could not be attached\n");
+ acpi_unbind_one(dev);
+
+ err:
+ free_cpumask_var(pr->throttling.shared_cpu_map);
+ device->driver_data = NULL;
+ per_cpu(processors, pr->id) = NULL;
+ err_free_pr:
+ kfree(pr);
+ return result;
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/* --------------------------------------------------------------------------
+ Removal
+ -------------------------------------------------------------------------- */
+
+static void acpi_processor_remove(struct acpi_device *device)
+{
+ struct acpi_processor *pr;
+
+ if (!device || !acpi_driver_data(device))
+ return;
+
+ pr = acpi_driver_data(device);
+ if (pr->id >= nr_cpu_ids)
+ goto out;
+
+ /*
+ * The only reason why we ever get here is CPU hot-removal. The CPU is
+ * already offline and the ACPI device removal locking prevents it from
+ * being put back online at this point.
+ *
+ * Unbind the driver from the processor device and detach it from the
+ * ACPI companion object.
+ */
+ device_release_driver(pr->dev);
+ acpi_unbind_one(pr->dev);
+
+ /* Clean up. */
+ per_cpu(processor_device_array, pr->id) = NULL;
+ per_cpu(processors, pr->id) = NULL;
+ try_offline_node(cpu_to_node(pr->id));
+
+ /* Remove the CPU. */
+ get_online_cpus();
+ arch_unregister_cpu(pr->id);
+ acpi_unmap_lsapic(pr->id);
+ put_online_cpus();
+
+ out:
+ free_cpumask_var(pr->throttling.shared_cpu_map);
+ kfree(pr);
+}
+#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+
+/*
+ * The following ACPI IDs are known to be suitable for representing as
+ * processor devices.
+ */
+static const struct acpi_device_id processor_device_ids[] = {
+
+ { ACPI_PROCESSOR_OBJECT_HID, },
+ { ACPI_PROCESSOR_DEVICE_HID, },
+
+ { }
+};
+
+static struct acpi_scan_handler __refdata processor_handler = {
+ .ids = processor_device_ids,
+ .attach = acpi_processor_add,
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ .detach = acpi_processor_remove,
+#endif
+ .hotplug = {
+ .enabled = true,
+ },
+};
+
+void __init acpi_processor_init(void)
+{
+ acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
+}
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index 7ddf29eca9f5..438304086ff1 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -83,6 +83,7 @@ acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o
acpi-y += \
nsaccess.o \
nsalloc.o \
+ nsarguments.o \
nsconvert.o \
nsdump.o \
nseval.o \
@@ -137,6 +138,7 @@ acpi-y += \
tbfadt.o \
tbfind.o \
tbinstal.o \
+ tbprint.o \
tbutils.o \
tbxface.o \
tbxfload.o \
@@ -145,11 +147,13 @@ acpi-y += \
acpi-y += \
utaddress.o \
utalloc.o \
+ utbuffer.o \
utcopy.o \
utexcep.o \
utdebug.o \
utdecode.o \
utdelete.o \
+ uterror.o \
uteval.o \
utglobal.o \
utids.o \
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 07160928ca25..b8d38117a20c 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -132,6 +132,12 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_auto_repair, FALSE);
+/*
+ * Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
+ * This can be useful for debugging ACPI problems on some machines.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_disable_ssdt_table_load, FALSE);
+
/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
struct acpi_table_fadt acpi_gbl_FADT;
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index d5bfbd331bfd..dfed26545ba2 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -362,23 +362,6 @@ union acpi_predefined_info {
#pragma pack()
-/* Data block used during object validation */
-
-struct acpi_predefined_data {
- char *pathname;
- const union acpi_predefined_info *predefined;
- union acpi_operand_object *parent_package;
- struct acpi_namespace_node *node;
- u32 flags;
- u32 return_btype;
- u8 node_flags;
-};
-
-/* Defines for Flags field above */
-
-#define ACPI_OBJECT_REPAIRED 1
-#define ACPI_OBJECT_WRAPPED 2
-
/* Return object auto-repair info */
typedef acpi_status(*acpi_object_converter) (union acpi_operand_object
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 53666bd9193d..530a2f8c1252 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -374,10 +374,11 @@
* the plist contains a set of parens to allow variable-length lists.
* These macros are used for both the debug and non-debug versions of the code.
*/
-#define ACPI_ERROR_NAMESPACE(s, e) acpi_ut_namespace_error (AE_INFO, s, e);
-#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ut_method_error (AE_INFO, s, n, p, e);
-#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist
-#define ACPI_INFO_PREDEFINED(plist) acpi_ut_predefined_info plist
+#define ACPI_ERROR_NAMESPACE(s, e) acpi_ut_namespace_error (AE_INFO, s, e);
+#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ut_method_error (AE_INFO, s, n, p, e);
+#define ACPI_WARN_PREDEFINED(plist) acpi_ut_predefined_warning plist
+#define ACPI_INFO_PREDEFINED(plist) acpi_ut_predefined_info plist
+#define ACPI_BIOS_ERROR_PREDEFINED(plist) acpi_ut_predefined_bios_error plist
#else
@@ -387,6 +388,7 @@
#define ACPI_ERROR_METHOD(s, n, p, e)
#define ACPI_WARN_PREDEFINED(plist)
#define ACPI_INFO_PREDEFINED(plist)
+#define ACPI_BIOS_ERROR_PREDEFINED(plist)
#endif /* ACPI_NO_ERROR_MESSAGES */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index d2e491876bc0..b83dc32a5ae0 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -223,22 +223,33 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info);
void acpi_ns_exec_module_code_list(void);
/*
- * nspredef - Support for predefined/reserved names
+ * nsarguments - Argument count/type checking for predefined/reserved names
*/
-acpi_status
-acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
- u32 user_param_count,
- acpi_status return_status,
- union acpi_operand_object **return_object);
+void
+acpi_ns_check_argument_count(char *pathname,
+ struct acpi_namespace_node *node,
+ u32 user_param_count,
+ const union acpi_predefined_info *info);
void
-acpi_ns_check_parameter_count(char *pathname,
+acpi_ns_check_acpi_compliance(char *pathname,
struct acpi_namespace_node *node,
- u32 user_param_count,
- const union acpi_predefined_info *info);
+ const union acpi_predefined_info *predefined);
+
+void acpi_ns_check_argument_types(struct acpi_evaluate_info *info);
+
+/*
+ * nspredef - Return value checking for predefined/reserved names
+ */
+acpi_status
+acpi_ns_check_return_value(struct acpi_namespace_node *node,
+ struct acpi_evaluate_info *info,
+ u32 user_param_count,
+ acpi_status return_status,
+ union acpi_operand_object **return_object);
acpi_status
-acpi_ns_check_object_type(struct acpi_predefined_data *data,
+acpi_ns_check_object_type(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index);
@@ -246,7 +257,7 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
* nsprepkg - Validation of predefined name packages
*/
acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
+acpi_ns_check_package(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
/*
@@ -308,24 +319,24 @@ acpi_ns_get_attached_data(struct acpi_namespace_node *node,
* predefined methods/objects
*/
acpi_status
-acpi_ns_simple_repair(struct acpi_predefined_data *data,
+acpi_ns_simple_repair(struct acpi_evaluate_info *info,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr);
acpi_status
-acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
+acpi_ns_wrap_with_package(struct acpi_evaluate_info *info,
union acpi_operand_object *original_object,
union acpi_operand_object **obj_desc_ptr);
acpi_status
-acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+acpi_ns_repair_null_element(struct acpi_evaluate_info *info,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr);
void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
u8 package_type,
union acpi_operand_object *obj_desc);
@@ -334,7 +345,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
* predefined methods/objects
*/
acpi_status
-acpi_ns_complex_repairs(struct acpi_predefined_data *data,
+acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
struct acpi_namespace_node *node,
acpi_status validate_status,
union acpi_operand_object **return_object_ptr);
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index b22b70944fd6..f600aded7261 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -128,8 +128,8 @@ enum acpi_return_package_types {
#define ARG_COUNT_IS_MINIMUM 0x8000
#define METHOD_MAX_ARG_TYPE ACPI_TYPE_PACKAGE
-#define METHOD_GET_COUNT(arg_list) (arg_list & METHOD_ARG_MASK)
-#define METHOD_GET_NEXT_ARG(arg_list) (arg_list >> METHOD_ARG_BIT_WIDTH)
+#define METHOD_GET_ARG_COUNT(arg_list) ((arg_list) & METHOD_ARG_MASK)
+#define METHOD_GET_NEXT_TYPE(arg_list) (((arg_list) >>= METHOD_ARG_BIT_WIDTH) & METHOD_ARG_MASK)
/* Macros used to build the predefined info table */
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 7896d85876ca..fc83c0a5ca70 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -178,25 +178,41 @@ union acpi_aml_operands {
};
/*
- * Structure used to pass object evaluation parameters.
+ * Structure used to pass object evaluation information and parameters.
* Purpose is to reduce CPU stack use.
*/
struct acpi_evaluate_info {
- struct acpi_namespace_node *prefix_node;
- char *pathname;
- union acpi_operand_object *obj_desc;
- union acpi_operand_object **parameters;
- struct acpi_namespace_node *resolved_node;
- union acpi_operand_object *return_object;
- u8 param_count;
- u8 pass_number;
- u8 return_object_type;
- u8 flags;
+ /* The first 3 elements are passed by the caller to acpi_ns_evaluate */
+
+ struct acpi_namespace_node *prefix_node; /* Input: starting node */
+ char *relative_pathname; /* Input: path relative to prefix_node */
+ union acpi_operand_object **parameters; /* Input: argument list */
+
+ struct acpi_namespace_node *node; /* Resolved node (prefix_node:relative_pathname) */
+ union acpi_operand_object *obj_desc; /* Object attached to the resolved node */
+ char *full_pathname; /* Full pathname of the resolved node */
+
+ const union acpi_predefined_info *predefined; /* Used if Node is a predefined name */
+ union acpi_operand_object *return_object; /* Object returned from the evaluation */
+ union acpi_operand_object *parent_package; /* Used if return object is a Package */
+
+ u32 return_flags; /* Used for return value analysis */
+ u32 return_btype; /* Bitmapped type of the returned object */
+ u16 param_count; /* Count of the input argument list */
+ u8 pass_number; /* Parser pass number */
+ u8 return_object_type; /* Object type of the returned object */
+ u8 node_flags; /* Same as Node->Flags */
+ u8 flags; /* General flags */
};
/* Values for Flags above */
-#define ACPI_IGNORE_RETURN_VALUE 1
+#define ACPI_IGNORE_RETURN_VALUE 1
+
+/* Defines for return_flags field above */
+
+#define ACPI_OBJECT_REPAIRED 1
+#define ACPI_OBJECT_WRAPPED 2
/* Info used by acpi_ns_initialize_devices */
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 202f4f12d3e2..3c76edea6803 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -87,6 +87,48 @@ extern const char *acpi_gbl_fc_decode[];
extern const char *acpi_gbl_pt_decode[];
#endif
+/*
+ * For the iASL compiler case, the output is redirected to stderr so that
+ * any of the various ACPI errors and warnings do not appear in the output
+ * files, for either the compiler or disassembler portions of the tool.
+ */
+#ifdef ACPI_ASL_COMPILER
+
+#include <stdio.h>
+extern FILE *acpi_gbl_output_file;
+
+#define ACPI_MSG_REDIRECT_BEGIN \
+ FILE *output_file = acpi_gbl_output_file; \
+ acpi_os_redirect_output (stderr);
+
+#define ACPI_MSG_REDIRECT_END \
+ acpi_os_redirect_output (output_file);
+
+#else
+/*
+ * non-iASL case - no redirection, nothing to do
+ */
+#define ACPI_MSG_REDIRECT_BEGIN
+#define ACPI_MSG_REDIRECT_END
+#endif
+
+/*
+ * Common error message prefixes
+ */
+#define ACPI_MSG_ERROR "ACPI Error: "
+#define ACPI_MSG_EXCEPTION "ACPI Exception: "
+#define ACPI_MSG_WARNING "ACPI Warning: "
+#define ACPI_MSG_INFO "ACPI: "
+
+#define ACPI_MSG_BIOS_ERROR "ACPI BIOS Error (bug): "
+#define ACPI_MSG_BIOS_WARNING "ACPI BIOS Warning (bug): "
+
+/*
+ * Common message suffix
+ */
+#define ACPI_MSG_SUFFIX \
+ acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
+
/* Types for Resource descriptor entries */
#define ACPI_INVALID_RESOURCE 0
@@ -578,7 +620,7 @@ void acpi_ut_print_string(char *string, u8 max_length);
void ut_convert_backslashes(char *pathname);
-u8 acpi_ut_valid_acpi_name(u32 name);
+u8 acpi_ut_valid_acpi_name(char *name);
u8 acpi_ut_valid_acpi_char(char character, u32 position);
@@ -670,6 +712,12 @@ acpi_ut_predefined_info(const char *module_name,
u32 line_number,
char *pathname, u8 node_flags, const char *format, ...);
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_bios_error(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...);
+
void
acpi_ut_namespace_error(const char *module_name,
u32 line_number,
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 7ea0f162f11c..eb56b66444b5 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -78,7 +78,6 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
switch (op->common.aml_opcode) {
case AML_WHILE_OP:
-
/*
* If this is an additional iteration of a while loop, continue.
* There is no need to allocate a new control state.
@@ -99,7 +98,6 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
/*lint -fallthrough */
case AML_IF_OP:
-
/*
* IF/WHILE: Create a new control state to manage these
* constructs. We need to manage these as a stack, in order
@@ -142,6 +140,7 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
break;
default:
+
break;
}
@@ -344,6 +343,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
case AML_NOOP_OP:
/* Just do nothing! */
+
break;
case AML_BREAK_POINT_OP:
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index feadeed1012d..d4bfe7b7f90a 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -563,21 +563,25 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
*/
switch (walk_state->opcode) {
case AML_FIELD_OP:
+
arg = acpi_ps_get_arg(op, 2);
type = ACPI_TYPE_LOCAL_REGION_FIELD;
break;
case AML_BANK_FIELD_OP:
+
arg = acpi_ps_get_arg(op, 4);
type = ACPI_TYPE_LOCAL_BANK_FIELD;
break;
case AML_INDEX_FIELD_OP:
+
arg = acpi_ps_get_arg(op, 3);
type = ACPI_TYPE_LOCAL_INDEX_FIELD;
break;
default:
+
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index bc8e63f7784b..14424200d246 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -127,6 +127,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
break;
default:
+
break;
}
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index 3da80460ce38..c4b0b3657237 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -285,6 +285,7 @@ acpi_ds_method_data_get_node(u8 type,
break;
default:
+
ACPI_ERROR((AE_INFO, "Type %u is invalid", type));
return_ACPI_STATUS(AE_TYPE);
}
@@ -428,7 +429,6 @@ acpi_ds_method_data_get_value(u8 type,
return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
case ACPI_REFCLASS_LOCAL:
-
/*
* No error message for this case, will be trapped again later to
* detect and ignore cases of Store(local_x,local_x)
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index e20e9f84eee8..63f0d220ca3d 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -648,7 +648,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
switch (obj_desc->common.type) {
case ACPI_TYPE_BUFFER:
-
/*
* Defer evaluation of Buffer term_arg operand
*/
@@ -660,7 +659,6 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
break;
case ACPI_TYPE_PACKAGE:
-
/*
* Defer evaluation of Package term_arg operand
*/
@@ -741,6 +739,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
break;
default:
+
ACPI_ERROR((AE_INFO, "Unknown Integer type 0x%X",
op_info->type));
status = AE_AML_OPERAND_TYPE;
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index ee6367b8eaf7..1fc1ff114f26 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -636,6 +636,7 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
break;
default:
+
return_ACPI_STATUS(AE_AML_BAD_OPCODE);
}
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 99778997c35a..c666fc014987 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -240,7 +240,6 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
case AML_IF_OP:
case AML_WHILE_OP:
-
/*
* If we are executing the predicate AND this is the predicate op,
* we will use the return value
@@ -254,7 +253,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
break;
default:
+
/* Ignore other control opcodes */
+
break;
}
@@ -263,7 +264,6 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
goto result_not_used;
case AML_CLASS_CREATE:
-
/*
* These opcodes allow term_arg(s) as operands and therefore
* the operands can be method calls. The result is used.
@@ -292,7 +292,6 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
goto result_not_used;
default:
-
/*
* In all other cases. the parent will actually use the return
* object, so keep it.
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index e2199a947470..151d924817e1 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -327,6 +327,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
break;
default:
+
break;
}
@@ -488,7 +489,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
break;
case AML_TYPE_METHOD_CALL:
-
/*
* If the method is referenced from within a package
* declaration, it is not a invocation of the method, just
@@ -582,7 +582,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
switch (op->common.parent->common.aml_opcode) {
case AML_NAME_OP:
-
/*
* Put the Node on the object stack (Contains the ACPI Name
* of this object)
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 6e17c0e24e63..95e681a36f9c 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -74,6 +74,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
switch (pass_number) {
case 1:
+
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load1_begin_op;
@@ -81,6 +82,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
break;
case 2:
+
walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load2_begin_op;
@@ -88,6 +90,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
break;
case 3:
+
#ifndef ACPI_NO_METHOD_EXECUTION
walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
ACPI_PARSE_DELETE_TREE;
@@ -97,6 +100,7 @@ acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
break;
default:
+
return (AE_BAD_PARAMETER);
}
@@ -161,7 +165,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
switch (walk_state->opcode) {
case AML_SCOPE_OP:
-
/*
* The target name of the Scope() operator must exist at this point so
* that we can actually open the scope to enter new names underneath it.
@@ -210,7 +213,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
-
/*
* These types we will allow, but we will change the type.
* This enables some existing code of the form:
@@ -232,7 +234,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
break;
case ACPI_TYPE_METHOD:
-
/*
* Allow scope change to root during execution of module-level
* code. Root is typed METHOD during this time.
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
index 4407ff2377d5..b1f8f4725c23 100644
--- a/drivers/acpi/acpica/dswload2.c
+++ b/drivers/acpi/acpica/dswload2.c
@@ -509,6 +509,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
break;
default:
+
/* All NAMED_FIELD opcodes must be handled above */
break;
}
@@ -548,6 +549,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
break;
default:
+
/* Unknown opcode */
status = AE_OK;
@@ -674,6 +676,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
#endif /* ACPI_NO_METHOD_EXECUTION */
default:
+
/* All NAMED_COMPLEX opcodes must be handled above */
break;
}
@@ -721,6 +724,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
break;
default:
+
break;
}
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index a621481c6cf2..fdb0a76e40a3 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -128,6 +128,7 @@ acpi_status acpi_ev_remove_global_lock_handler(void)
status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
acpi_ev_global_lock_handler);
+ acpi_os_delete_lock(acpi_gbl_global_lock_pending_lock);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index a493b528f8f9..c8a1f7d5931f 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -529,7 +529,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
case ACPI_GPE_DISPATCH_NOTIFY:
-
/*
* Implicit notify.
* Dispatch a DEVICE_WAKE notify to the appropriate handler.
@@ -579,11 +578,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
(local_gpe_event_info->dispatch.
method_node)));
}
-
break;
default:
- return_VOID; /* Should never happen */
+
+ return_VOID; /* Should never happen */
}
/* Defer enabling of GPE until all notify handlers are done */
@@ -755,7 +754,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
case ACPI_GPE_DISPATCH_METHOD:
case ACPI_GPE_DISPATCH_NOTIFY:
-
/*
* Execute the method associated with the GPE
* NOTE: Level-triggered GPEs are cleared after the method completes.
@@ -771,7 +769,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
break;
default:
-
/*
* No handler or method to run!
* 03/2010: This case should no longer be possible. We will not allow
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index a2d688bbac02..c1aa1eda26c3 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -382,6 +382,8 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
status = acpi_ev_install_gpe_block(gpe_block, interrupt_number);
if (ACPI_FAILURE(status)) {
+ ACPI_FREE(gpe_block->register_info);
+ ACPI_FREE(gpe_block->event_info);
ACPI_FREE(gpe_block);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 72b8f6b3f4ca..9037f17c9608 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -363,14 +363,17 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
*/
switch (name[1]) {
case 'L':
+
type = ACPI_GPE_LEVEL_TRIGGERED;
break;
case 'E':
+
type = ACPI_GPE_EDGE_TRIGGERED;
break;
default:
+
/* Unknown method type, just ignore it */
ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
index d4f83112c2e2..068af96134b8 100644
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -354,36 +354,43 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node,
switch (space_id) {
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+
handler = acpi_ex_system_memory_space_handler;
setup = acpi_ev_system_memory_region_setup;
break;
case ACPI_ADR_SPACE_SYSTEM_IO:
+
handler = acpi_ex_system_io_space_handler;
setup = acpi_ev_io_space_region_setup;
break;
case ACPI_ADR_SPACE_PCI_CONFIG:
+
handler = acpi_ex_pci_config_space_handler;
setup = acpi_ev_pci_config_region_setup;
break;
case ACPI_ADR_SPACE_CMOS:
+
handler = acpi_ex_cmos_space_handler;
setup = acpi_ev_cmos_region_setup;
break;
case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+
handler = acpi_ex_pci_bar_space_handler;
setup = acpi_ev_pci_bar_region_setup;
break;
case ACPI_ADR_SPACE_DATA_TABLE:
+
handler = acpi_ex_data_table_space_handler;
setup = NULL;
break;
default:
+
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index c986b2336b81..1b111ef74903 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -78,6 +78,7 @@ u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
return (TRUE);
default:
+
return (FALSE);
}
}
@@ -275,6 +276,8 @@ void acpi_ev_terminate(void)
ACPI_ERROR((AE_INFO,
"Could not remove Global Lock handler"));
}
+
+ acpi_gbl_events_initialized = FALSE;
}
/* Deallocate all handler objects installed within GPE info structs */
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 6555e350fc1f..cea14d6fc76c 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -54,7 +54,8 @@ extern u8 acpi_gbl_default_address_spaces[];
/* Local prototypes */
-static void acpi_ev_orphan_ec_reg_method(void);
+static void
+acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node);
static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,
@@ -532,7 +533,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
}
info->prefix_node = region_obj2->extra.method_REG;
- info->pathname = NULL;
+ info->relative_pathname = NULL;
info->parameters = args;
info->flags = ACPI_IGNORE_RETURN_VALUE;
@@ -612,7 +613,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
/* Special case for EC: handle "orphan" _REG methods with no region */
if (space_id == ACPI_ADR_SPACE_EC) {
- acpi_ev_orphan_ec_reg_method();
+ acpi_ev_orphan_ec_reg_method(node);
}
return_ACPI_STATUS(status);
@@ -681,7 +682,7 @@ acpi_ev_reg_run(acpi_handle obj_handle,
*
* FUNCTION: acpi_ev_orphan_ec_reg_method
*
- * PARAMETERS: None
+ * PARAMETERS: ec_device_node - Namespace node for an EC device
*
* RETURN: None
*
@@ -693,37 +694,27 @@ acpi_ev_reg_run(acpi_handle obj_handle,
* detected by providing a _REG method object underneath the
* Embedded Controller device."
*
- * To quickly access the EC device, we use the EC_ID that appears
- * within the ECDT. Otherwise, we would need to perform a time-
- * consuming namespace walk, executing _HID methods to find the
- * EC device.
+ * To quickly access the EC device, we use the ec_device_node used
+ * during EC handler installation. Otherwise, we would need to
+ * perform a time consuming namespace walk, executing _HID
+ * methods to find the EC device.
+ *
+ * MUTEX: Assumes the namespace is locked
*
******************************************************************************/
-static void acpi_ev_orphan_ec_reg_method(void)
+static void
+acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
{
- struct acpi_table_ecdt *table;
+ acpi_handle reg_method;
+ struct acpi_namespace_node *next_node;
acpi_status status;
struct acpi_object_list args;
union acpi_object objects[2];
- struct acpi_namespace_node *ec_device_node;
- struct acpi_namespace_node *reg_method;
- struct acpi_namespace_node *next_node;
ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
- /* Get the ECDT (if present in system) */
-
- status = acpi_get_table(ACPI_SIG_ECDT, 0,
- ACPI_CAST_INDIRECT_PTR(struct acpi_table_header,
- &table));
- if (ACPI_FAILURE(status)) {
- return_VOID;
- }
-
- /* We need a valid EC_ID string */
-
- if (!(*table->id)) {
+ if (!ec_device_node) {
return_VOID;
}
@@ -731,22 +722,11 @@ static void acpi_ev_orphan_ec_reg_method(void)
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- /* Get a handle to the EC device referenced in the ECDT */
-
- status = acpi_get_handle(NULL,
- ACPI_CAST_PTR(char, table->id),
- ACPI_CAST_PTR(acpi_handle, &ec_device_node));
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
/* Get a handle to a _REG method immediately under the EC device */
- status = acpi_get_handle(ec_device_node,
- METHOD_NAME__REG, ACPI_CAST_PTR(acpi_handle,
- &reg_method));
+ status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, &reg_method);
if (ACPI_FAILURE(status)) {
- goto exit;
+ goto exit; /* There is no _REG method present */
}
/*
@@ -754,19 +734,20 @@ static void acpi_ev_orphan_ec_reg_method(void)
* this scope with the Embedded Controller space ID. Otherwise, it
* will already have been executed. Note, this allows for Regions
* with other space IDs to be present; but the code below will then
- * execute the _REG method with the EC space ID argument.
+ * execute the _REG method with the embedded_control space_ID argument.
*/
next_node = acpi_ns_get_next_node(ec_device_node, NULL);
while (next_node) {
if ((next_node->type == ACPI_TYPE_REGION) &&
(next_node->object) &&
(next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
- goto exit; /* Do not execute _REG */
+ goto exit; /* Do not execute the _REG */
}
+
next_node = acpi_ns_get_next_node(ec_device_node, next_node);
}
- /* Evaluate the _REG(EC,Connect) method */
+ /* Evaluate the _REG(embedded_control,Connect) method */
args.count = 2;
args.pointer = objects;
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 3bb616794b3b..8354c4f7f10c 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -596,7 +596,9 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
break;
default:
+
/* Ignore other objects */
+
break;
}
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index aff4cc261211..7662f1a42ff6 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -366,16 +366,19 @@ acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action)
switch (action) {
case ACPI_GPE_ENABLE:
+
ACPI_SET_BIT(gpe_register_info->enable_for_wake,
(u8)register_bit);
break;
case ACPI_GPE_DISABLE:
+
ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
(u8)register_bit);
break;
default:
+
ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
status = AE_BAD_PARAMETER;
break;
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 96c9e5f355ae..80cecf838591 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -139,6 +139,7 @@ acpi_install_address_space_handler(acpi_handle device,
break;
default:
+
break;
}
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index d93b70be60ad..06d216c8d43a 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -480,6 +480,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
break;
default:
+
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
@@ -588,7 +589,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
(ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
(ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) ||
(!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
/* Get the table index from the ddb_handle */
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index d2b9613bbf01..69e4a8cc9b71 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -99,6 +99,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
break;
default:
+
return_ACPI_STATUS(AE_TYPE);
}
@@ -117,7 +118,6 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
switch (obj_desc->common.type) {
case ACPI_TYPE_STRING:
-
/*
* Convert string to an integer - for most cases, the string must be
* hexadecimal as per the ACPI specification. The only exception (as
@@ -161,6 +161,7 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
default:
/* No other types can get here */
+
break;
}
@@ -213,7 +214,6 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_OK);
case ACPI_TYPE_INTEGER:
-
/*
* Create a new Buffer object.
* Need enough space for one integer
@@ -233,7 +233,6 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
break;
case ACPI_TYPE_STRING:
-
/*
* Create a new Buffer object
* Size will be the string length
@@ -258,6 +257,7 @@ acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc,
break;
default:
+
return_ACPI_STATUS(AE_TYPE);
}
@@ -304,15 +304,18 @@ acpi_ex_convert_to_ascii(u64 integer, u16 base, u8 *string, u8 data_width)
switch (data_width) {
case 1:
+
decimal_length = ACPI_MAX8_DECIMAL_DIGITS;
break;
case 4:
+
decimal_length = ACPI_MAX32_DECIMAL_DIGITS;
break;
case 8:
default:
+
decimal_length = ACPI_MAX64_DECIMAL_DIGITS;
break;
}
@@ -546,6 +549,7 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc,
break;
default:
+
return_ACPI_STATUS(AE_TYPE);
}
@@ -599,6 +603,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
break;
default:
+
/* No conversion allowed for these types */
if (destination_type != source_desc->common.type) {
@@ -649,6 +654,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
break;
default:
+
ACPI_ERROR((AE_INFO,
"Bad destination type during conversion: 0x%X",
destination_type));
@@ -664,6 +670,7 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
break;
default:
+
ACPI_ERROR((AE_INFO,
"Unknown Target type ID 0x%X AmlOpcode 0x%X DestType %s",
GET_CURRENT_ARG_TYPE(walk_state->op_info->
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 26a13f67977e..269e81d86ef4 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -103,7 +103,6 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
case ACPI_TYPE_BUFFER:
case ACPI_TYPE_PACKAGE:
case ACPI_TYPE_BUFFER_FIELD:
-
/*
* These types open a new scope, so we need the NS node in order to access
* any children.
@@ -113,7 +112,6 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_LOCAL_SCOPE:
-
/*
* The new alias has the type ALIAS and points to the original
* NS node, not the object itself.
@@ -124,7 +122,6 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
break;
case ACPI_TYPE_METHOD:
-
/*
* Control method aliases need to be differentiated
*/
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index 7eb853cd279f..81c72a4ecd82 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -193,6 +193,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
return_VOID;
default:
+
break;
}
@@ -226,6 +227,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
break;
default:
+
acpi_ex_do_debug_object((source_desc->
reference.
node)->object,
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index e5a3c249f7fa..c740f24e3101 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -357,6 +357,7 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
switch (info->opcode) {
case ACPI_EXD_INIT:
+
break;
case ACPI_EXD_TYPE:
@@ -718,6 +719,7 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth)
break;
default:
+
/* Unknown Type */
acpi_os_printf("Unknown Type %X\n", obj_desc->common.type);
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index 7d4bae71e8c6..c2a65aaf29af 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -331,21 +331,25 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc,
switch (source_desc->common.type) {
case ACPI_TYPE_INTEGER:
+
buffer = &source_desc->integer.value;
length = sizeof(source_desc->integer.value);
break;
case ACPI_TYPE_BUFFER:
+
buffer = source_desc->buffer.pointer;
length = source_desc->buffer.length;
break;
case ACPI_TYPE_STRING:
+
buffer = source_desc->string.pointer;
length = source_desc->string.length;
break;
default:
+
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index c84ee956fa4c..7e0afe72487e 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -446,7 +446,6 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
break;
case ACPI_TYPE_LOCAL_BANK_FIELD:
-
/*
* Ensure that the bank_value is not beyond the capacity of
* the register
@@ -488,7 +487,6 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
-
/*
* Ensure that the index_value is not beyond the capacity of
* the register
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 72a2a13b6d36..00bf29877574 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -105,7 +105,6 @@ acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
break;
case ACPI_DESC_TYPE_NAMED:
-
/*
* A named reference that has already been resolved to a Node
*/
@@ -261,20 +260,24 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0,
*/
switch (operand0->common.type) {
case ACPI_TYPE_INTEGER:
+
status =
acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
break;
case ACPI_TYPE_STRING:
+
status = acpi_ex_convert_to_string(operand1, &local_operand1,
ACPI_IMPLICIT_CONVERT_HEX);
break;
case ACPI_TYPE_BUFFER:
+
status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
break;
default:
+
ACPI_ERROR((AE_INFO, "Invalid object type: 0x%X",
operand0->common.type));
status = AE_AML_INTERNAL;
@@ -519,6 +522,7 @@ acpi_ex_do_logical_numeric_op(u16 opcode,
break;
default:
+
status = AE_AML_INTERNAL;
break;
}
@@ -580,20 +584,24 @@ acpi_ex_do_logical_op(u16 opcode,
*/
switch (operand0->common.type) {
case ACPI_TYPE_INTEGER:
+
status =
acpi_ex_convert_to_integer(operand1, &local_operand1, 16);
break;
case ACPI_TYPE_STRING:
+
status = acpi_ex_convert_to_string(operand1, &local_operand1,
ACPI_IMPLICIT_CONVERT_HEX);
break;
case ACPI_TYPE_BUFFER:
+
status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
break;
default:
+
status = AE_AML_INTERNAL;
break;
}
@@ -636,6 +644,7 @@ acpi_ex_do_logical_op(u16 opcode,
break;
default:
+
status = AE_AML_INTERNAL;
break;
}
@@ -703,6 +712,7 @@ acpi_ex_do_logical_op(u16 opcode,
break;
default:
+
status = AE_AML_INTERNAL;
break;
}
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index b60c877f5906..814b4a3d656a 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -327,7 +327,6 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
break;
case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */
-
/*
* The 64-bit ACPI integer can hold 16 4-bit BCD characters
* (if table is 32-bit, integer can hold 8 BCD characters)
@@ -407,7 +406,6 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
break;
case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */
-
/*
* This op is a little strange because the internal return value is
* different than the return value stored in the result descriptor
@@ -442,13 +440,14 @@ acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state)
goto cleanup;
default:
+
/* No other opcodes get here */
+
break;
}
break;
case AML_STORE_OP: /* Store (Source, Target) */
-
/*
* A store operand is typically a number, string, buffer or lvalue
* Be careful about deleting the source object,
@@ -615,7 +614,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
case AML_DECREMENT_OP: /* Decrement (Operand) */
case AML_INCREMENT_OP: /* Increment (Operand) */
-
/*
* Create a new integer. Can't just get the base integer and
* increment it because it may be an Arg or Field.
@@ -682,7 +680,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
case AML_TYPE_OP: /* object_type (source_object) */
-
/*
* Note: The operand is not resolved at this point because we want to
* get the associated object, not its value. For example, we don't
@@ -709,7 +706,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
case AML_SIZE_OF_OP: /* size_of (source_object) */
-
/*
* Note: The operand is not resolved at this point because we want to
* get the associated object, not its value.
@@ -735,10 +731,12 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
*/
switch (type) {
case ACPI_TYPE_INTEGER:
+
value = acpi_gbl_integer_byte_width;
break;
case ACPI_TYPE_STRING:
+
value = temp_desc->string.length;
break;
@@ -759,6 +757,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
default:
+
ACPI_ERROR((AE_INFO,
"Operand must be Buffer/Integer/String/Package - found type %s",
acpi_ut_get_type_name(type)));
@@ -860,9 +859,11 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
case ACPI_TYPE_STRING:
+
break;
default:
+
status = AE_AML_OPERAND_TYPE;
goto cleanup;
}
@@ -923,7 +924,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
*/
switch (operand[0]->reference.class) {
case ACPI_REFCLASS_INDEX:
-
/*
* The target type for the Index operator must be
* either a Buffer or a Package
@@ -956,7 +956,6 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
case ACPI_TYPE_PACKAGE:
-
/*
* Return the referenced element of the package. We must
* add another reference to the referenced object, however.
@@ -999,6 +998,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state)
break;
default:
+
ACPI_ERROR((AE_INFO,
"Unknown class in reference(%p) - 0x%2.2X",
operand[0],
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index b0838a4ea53e..d5088f7030c7 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -304,7 +304,6 @@ acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state)
break;
case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */
-
/*
* Input object is guaranteed to be a buffer at this point (it may have
* been converted.) Copy the raw buffer data to a new object of
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 2d7491f3126e..37656f12f204 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -155,7 +155,6 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
switch (walk_state->opcode) {
case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */
-
/*
* Create the return object. The Source operand is guaranteed to be
* either a String or a Buffer, so just use its type.
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index b76b97002dff..879b6cd8319c 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -119,7 +119,6 @@ acpi_ex_do_match(u32 match_op,
break;
case MATCH_MEQ:
-
/*
* True if equal: (P[i] == M)
* Change to: (M == P[i])
@@ -133,7 +132,6 @@ acpi_ex_do_match(u32 match_op,
break;
case MATCH_MLE:
-
/*
* True if less than or equal: (P[i] <= M) (P[i] not_greater than M)
* Change to: (M >= P[i]) (M not_less than P[i])
@@ -148,7 +146,6 @@ acpi_ex_do_match(u32 match_op,
break;
case MATCH_MLT:
-
/*
* True if less than: (P[i] < M)
* Change to: (M > P[i])
@@ -162,7 +159,6 @@ acpi_ex_do_match(u32 match_op,
break;
case MATCH_MGE:
-
/*
* True if greater than or equal: (P[i] >= M) (P[i] not_less than M)
* Change to: (M <= P[i]) (M not_greater than P[i])
@@ -177,7 +173,6 @@ acpi_ex_do_match(u32 match_op,
break;
case MATCH_MGT:
-
/*
* True if greater than: (P[i] > M)
* Change to: (M < P[i])
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 6b728aef2dca..5a588611ab48 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -253,26 +253,31 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc,
case AML_FIELD_ACCESS_BYTE:
case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */
+
byte_alignment = 1;
bit_length = 8;
break;
case AML_FIELD_ACCESS_WORD:
+
byte_alignment = 2;
bit_length = 16;
break;
case AML_FIELD_ACCESS_DWORD:
+
byte_alignment = 4;
bit_length = 32;
break;
case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */
+
byte_alignment = 8;
bit_length = 64;
break;
default:
+
/* Invalid field access type */
ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access));
@@ -598,7 +603,9 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
break;
default:
+
/* No other types should get here */
+
break;
}
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 182abaf045e1..303429bb4d5d 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -88,22 +88,27 @@ acpi_ex_system_memory_space_handler(u32 function,
switch (bit_width) {
case 8:
+
length = 1;
break;
case 16:
+
length = 2;
break;
case 32:
+
length = 4;
break;
case 64:
+
length = 8;
break;
default:
+
ACPI_ERROR((AE_INFO, "Invalid SystemMemory width %u",
bit_width));
return_ACPI_STATUS(AE_AML_OPERAND_VALUE);
@@ -214,23 +219,29 @@ acpi_ex_system_memory_space_handler(u32 function,
*value = 0;
switch (bit_width) {
case 8:
- *value = (u64) ACPI_GET8(logical_addr_ptr);
+
+ *value = (u64)ACPI_GET8(logical_addr_ptr);
break;
case 16:
- *value = (u64) ACPI_GET16(logical_addr_ptr);
+
+ *value = (u64)ACPI_GET16(logical_addr_ptr);
break;
case 32:
- *value = (u64) ACPI_GET32(logical_addr_ptr);
+
+ *value = (u64)ACPI_GET32(logical_addr_ptr);
break;
case 64:
- *value = (u64) ACPI_GET64(logical_addr_ptr);
+
+ *value = (u64)ACPI_GET64(logical_addr_ptr);
break;
default:
+
/* bit_width was already validated */
+
break;
}
break;
@@ -239,28 +250,35 @@ acpi_ex_system_memory_space_handler(u32 function,
switch (bit_width) {
case 8:
+
ACPI_SET8(logical_addr_ptr, *value);
break;
case 16:
+
ACPI_SET16(logical_addr_ptr, *value);
break;
case 32:
+
ACPI_SET32(logical_addr_ptr, *value);
break;
case 64:
+
ACPI_SET64(logical_addr_ptr, *value);
break;
default:
+
/* bit_width was already validated */
+
break;
}
break;
default:
+
status = AE_BAD_PARAMETER;
break;
}
@@ -320,6 +338,7 @@ acpi_ex_system_io_space_handler(u32 function,
break;
default:
+
status = AE_BAD_PARAMETER;
break;
}
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index 8565b6bd12bb..acd34f599313 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -248,6 +248,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr,
break;
default:
+
/* No named references are allowed here */
ACPI_ERROR((AE_INFO,
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index e4f9dfbb2a13..ac04278ad28f 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -156,7 +156,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
switch (ref_type) {
case ACPI_REFCLASS_LOCAL:
case ACPI_REFCLASS_ARG:
-
/*
* Get the local from the method's state info
* Note: this increments the local's object reference count
@@ -309,6 +308,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
break;
default:
+
break;
}
@@ -348,10 +348,12 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
case ACPI_DESC_TYPE_OPERAND:
+
type = obj_desc->common.type;
break;
case ACPI_DESC_TYPE_NAMED:
+
type = ((struct acpi_namespace_node *)obj_desc)->type;
obj_desc =
acpi_ns_get_attached_object((struct acpi_namespace_node *)
@@ -538,7 +540,9 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,
break;
default:
+
/* No change to Type required */
+
break;
}
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index 9fb9f5e9a4da..00e5af7129c1 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -307,7 +307,6 @@ acpi_ex_resolve_operands(u16 opcode,
case ARGI_TARGETREF: /* Allows implicit conversion rules before store */
case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
case ARGI_SIMPLE_TARGET: /* Name, Local, or arg - no implicit conversion */
-
/*
* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
* A Namespace Node is OK as-is
@@ -326,7 +325,6 @@ acpi_ex_resolve_operands(u16 opcode,
goto next_operand;
case ARGI_DATAREFOBJ: /* Store operator only */
-
/*
* We don't want to resolve index_op reference objects during
* a store because this would be an implicit de_ref_of operation.
@@ -343,7 +341,9 @@ acpi_ex_resolve_operands(u16 opcode,
break;
default:
+
/* All cases covered above */
+
break;
}
@@ -433,7 +433,6 @@ acpi_ex_resolve_operands(u16 opcode,
goto next_operand;
case ARGI_BUFFER:
-
/*
* Need an operand of type ACPI_TYPE_BUFFER,
* But we can implicitly convert from a STRING or INTEGER
@@ -459,7 +458,6 @@ acpi_ex_resolve_operands(u16 opcode,
goto next_operand;
case ARGI_STRING:
-
/*
* Need an operand of type ACPI_TYPE_STRING,
* But we can implicitly convert from a BUFFER or INTEGER
@@ -562,6 +560,7 @@ acpi_ex_resolve_operands(u16 opcode,
break;
default:
+
ACPI_ERROR((AE_INFO,
"Needed [Buffer/String/Package/Reference], found [%s] %p",
acpi_ut_get_object_type_name
@@ -584,6 +583,7 @@ acpi_ex_resolve_operands(u16 opcode,
break;
default:
+
ACPI_ERROR((AE_INFO,
"Needed [Buffer/String/Package], found [%s] %p",
acpi_ut_get_object_type_name
@@ -605,6 +605,7 @@ acpi_ex_resolve_operands(u16 opcode,
break;
default:
+
ACPI_ERROR((AE_INFO,
"Needed [Region/Buffer], found [%s] %p",
acpi_ut_get_object_type_name
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index 93c6049c2d75..2bdba6f7d762 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -114,6 +114,7 @@ acpi_ex_store(union acpi_operand_object *source_desc,
switch (dest_desc->common.type) {
case ACPI_TYPE_LOCAL_REFERENCE:
+
break;
case ACPI_TYPE_INTEGER:
@@ -178,7 +179,6 @@ acpi_ex_store(union acpi_operand_object *source_desc,
break;
case ACPI_REFCLASS_DEBUG:
-
/*
* Storing to the Debug object causes the value stored to be
* displayed and otherwise has no effect -- see ACPI Specification
@@ -291,7 +291,6 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
break;
case ACPI_TYPE_BUFFER_FIELD:
-
/*
* Store into a Buffer or String (not actually a real buffer_field)
* at a location defined by an Index.
@@ -447,7 +446,6 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
-
/*
* These target types are all of type Integer/String/Buffer, and
* therefore support implicit conversion before the store.
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 1cefe777068e..20d809d90c5b 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -85,11 +85,9 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
* These cases all require only Integers or values that
* can be converted to Integers (Strings or Buffers)
*/
-
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
-
/*
* Stores into a Field/Region or into a Integer/Buffer/String
* are all essentially the same. This case handles the
@@ -133,7 +131,6 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
case ACPI_TYPE_LOCAL_ALIAS:
case ACPI_TYPE_LOCAL_METHOD_ALIAS:
-
/*
* All aliases should have been resolved earlier, during the
* operand resolution phase.
@@ -144,7 +141,6 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr,
case ACPI_TYPE_PACKAGE:
default:
-
/*
* All other types than Alias and the various Fields come here,
* including the untyped case - ACPI_TYPE_ANY.
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 579c3a53ac87..3d36df828f52 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -108,7 +108,6 @@ acpi_status acpi_hw_set_mode(u32 mode)
break;
case ACPI_SYS_MODE_LEGACY:
-
/*
* BIOS should clear all fixed status bits and restore fixed event
* enable bits to default
@@ -120,6 +119,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
break;
default:
+
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 20d02e93c990..96540506058f 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -127,14 +127,17 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/*lint -fallthrough */
case ACPI_GPE_ENABLE:
+
ACPI_SET_BIT(enable_mask, register_bit);
break;
case ACPI_GPE_DISABLE:
+
ACPI_CLEAR_BIT(enable_mask, register_bit);
break;
default:
+
ACPI_ERROR((AE_INFO, "Invalid GPE Action, %u", action));
return (AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index 083d6551f0e2..8d2e866be15f 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -419,6 +419,7 @@ acpi_status acpi_hw_register_read(u32 register_id, u32 *return_value)
break;
default:
+
ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
status = AE_BAD_PARAMETER;
break;
@@ -491,7 +492,6 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
break;
case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */
-
/*
* Perform a read first to preserve certain bits (per ACPI spec)
* Note: This includes SCI_EN, we never want to change this bit
@@ -520,7 +520,6 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
break;
case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
-
/*
* For control registers, all reserved bits must be preserved,
* as per the ACPI spec.
@@ -555,6 +554,7 @@ acpi_status acpi_hw_register_write(u32 register_id, u32 value)
break;
default:
+
ACPI_ERROR((AE_INFO, "Unknown Register ID: 0x%X", register_id));
status = AE_BAD_PARAMETER;
break;
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 04c2e16f2c0a..5ee7a814cd92 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -495,7 +495,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
* Evaluate the \_Sx namespace object containing the register values
* for this state
*/
- info->pathname =
+ info->relative_pathname =
ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]);
status = acpi_ns_evaluate(info);
if (ACPI_FAILURE(status)) {
@@ -506,7 +506,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
if (!info->return_object) {
ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]",
- info->pathname));
+ info->relative_pathname));
status = AE_AML_NO_RETURN_VALUE;
goto cleanup;
}
@@ -528,10 +528,12 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
elements = info->return_object->package.elements;
switch (info->return_object->package.count) {
case 0:
+
status = AE_AML_PACKAGE_LIMIT;
break;
case 1:
+
if (elements[0]->common.type != ACPI_TYPE_INTEGER) {
status = AE_AML_OPERAND_TYPE;
break;
@@ -545,6 +547,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
case 2:
default:
+
if ((elements[0]->common.type != ACPI_TYPE_INTEGER) ||
(elements[1]->common.type != ACPI_TYPE_INTEGER)) {
status = AE_AML_OPERAND_TYPE;
@@ -565,7 +568,7 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"While evaluating Sleep State [%s]",
- info->pathname));
+ info->relative_pathname));
}
ACPI_FREE(info);
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 35eebdac0f9d..f2e669db8b65 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -240,12 +240,14 @@ static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id)
&acpi_sleep_dispatch[function_id];
#if (!ACPI_REDUCED_HARDWARE)
-
/*
* If the Hardware Reduced flag is set (from the FADT), we must
- * use the extended sleep registers
+ * use the extended sleep registers (FADT). Note: As per the ACPI
+ * specification, these extended registers are to be used for HW-reduced
+ * platforms only. They are not general-purpose replacements for the
+ * legacy PM register sleep support.
*/
- if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) {
+ if (acpi_gbl_reduced_hardware) {
status = sleep_functions->extended_function(sleep_state);
} else {
/* Legacy sleep */
@@ -314,20 +316,24 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state)
switch (sleep_state) {
case ACPI_STATE_S0:
+
sst_value = ACPI_SST_WORKING;
break;
case ACPI_STATE_S1:
case ACPI_STATE_S2:
case ACPI_STATE_S3:
+
sst_value = ACPI_SST_SLEEPING;
break;
case ACPI_STATE_S4:
+
sst_value = ACPI_SST_SLEEP_CONTEXT;
break;
default:
+
sst_value = ACPI_SST_INDICATOR_OFF; /* Default is off */
break;
}
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 8769cf83b044..c5316e5bd4ab 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -151,6 +151,7 @@ acpi_status acpi_ns_root_initialize(void)
*/
switch (init_val->type) {
case ACPI_TYPE_METHOD:
+
obj_desc->method.param_count =
(u8) ACPI_TO_INTEGER(val);
obj_desc->common.flags |= AOPOBJ_DATA_VALID;
diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c
new file mode 100644
index 000000000000..74b24c82707e
--- /dev/null
+++ b/drivers/acpi/acpica/nsarguments.c
@@ -0,0 +1,294 @@
+/******************************************************************************
+ *
+ * Module Name: nsarguments - Validation of args for ACPI predefined methods
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "acpredef.h"
+
+#define _COMPONENT ACPI_NAMESPACE
+ACPI_MODULE_NAME("nsarguments")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_argument_types
+ *
+ * PARAMETERS: info - Method execution information block
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Check the incoming argument count and all argument types
+ * against the argument type list for a predefined name.
+ *
+ ******************************************************************************/
+void acpi_ns_check_argument_types(struct acpi_evaluate_info *info)
+{
+ u16 arg_type_list;
+ u8 arg_count;
+ u8 arg_type;
+ u8 user_arg_type;
+ u32 i;
+
+ /* If not a predefined name, cannot typecheck args */
+
+ if (!info->predefined) {
+ return;
+ }
+
+ arg_type_list = info->predefined->info.argument_list;
+ arg_count = METHOD_GET_ARG_COUNT(arg_type_list);
+
+ /* Typecheck all arguments */
+
+ for (i = 0; ((i < arg_count) && (i < info->param_count)); i++) {
+ arg_type = METHOD_GET_NEXT_TYPE(arg_type_list);
+ user_arg_type = info->parameters[i]->common.type;
+
+ if (user_arg_type != arg_type) {
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ ACPI_WARN_ALWAYS,
+ "Argument #%u type mismatch - "
+ "Found [%s], ACPI requires [%s]",
+ (i + 1),
+ acpi_ut_get_type_name
+ (user_arg_type),
+ acpi_ut_get_type_name(arg_type)));
+ }
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_acpi_compliance
+ *
+ * PARAMETERS: pathname - Full pathname to the node (for error msgs)
+ * node - Namespace node for the method/object
+ * predefined - Pointer to entry in predefined name table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Check that the declared parameter count (in ASL/AML) for a
+ * predefined name is what is expected (matches what is defined in
+ * the ACPI specification for this predefined name.)
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_check_acpi_compliance(char *pathname,
+ struct acpi_namespace_node *node,
+ const union acpi_predefined_info *predefined)
+{
+ u32 aml_param_count;
+ u32 required_param_count;
+
+ if (!predefined) {
+ return;
+ }
+
+ /* Get the ACPI-required arg count from the predefined info table */
+
+ required_param_count =
+ METHOD_GET_ARG_COUNT(predefined->info.argument_list);
+
+ /*
+ * If this object is not a control method, we can check if the ACPI
+ * spec requires that it be a method.
+ */
+ if (node->type != ACPI_TYPE_METHOD) {
+ if (required_param_count > 0) {
+
+ /* Object requires args, must be implemented as a method */
+
+ ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Object (%s) must be a control method with %u arguments",
+ acpi_ut_get_type_name(node->
+ type),
+ required_param_count));
+ } else if (!required_param_count
+ && !predefined->info.expected_btypes) {
+
+ /* Object requires no args and no return value, must be a method */
+
+ ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Object (%s) must be a control method "
+ "with no arguments and no return value",
+ acpi_ut_get_type_name(node->
+ type)));
+ }
+
+ return;
+ }
+
+ /*
+ * This is a control method.
+ * Check that the ASL/AML-defined parameter count for this method
+ * matches the ACPI-required parameter count
+ *
+ * Some methods are allowed to have a "minimum" number of args (_SCP)
+ * because their definition in ACPI has changed over time.
+ *
+ * Note: These are BIOS errors in the declaration of the object
+ */
+ aml_param_count = node->object->method.param_count;
+
+ if (aml_param_count < required_param_count) {
+ ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+ "Insufficient arguments - "
+ "ASL declared %u, ACPI requires %u",
+ aml_param_count,
+ required_param_count));
+ } else if ((aml_param_count > required_param_count)
+ && !(predefined->info.
+ argument_list & ARG_COUNT_IS_MINIMUM)) {
+ ACPI_BIOS_ERROR_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+ "Excess arguments - "
+ "ASL declared %u, ACPI requires %u",
+ aml_param_count,
+ required_param_count));
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_check_argument_count
+ *
+ * PARAMETERS: pathname - Full pathname to the node (for error msgs)
+ * node - Namespace node for the method/object
+ * user_param_count - Number of args passed in by the caller
+ * predefined - Pointer to entry in predefined name table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Check that incoming argument count matches the declared
+ * parameter count (in the ASL/AML) for an object.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_check_argument_count(char *pathname,
+ struct acpi_namespace_node *node,
+ u32 user_param_count,
+ const union acpi_predefined_info *predefined)
+{
+ u32 aml_param_count;
+ u32 required_param_count;
+
+ if (!predefined) {
+ /*
+ * Not a predefined name. Check the incoming user argument count
+ * against the count that is specified in the method/object.
+ */
+ if (node->type != ACPI_TYPE_METHOD) {
+ if (user_param_count) {
+ ACPI_INFO_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "%u arguments were passed to a non-method ACPI object (%s)",
+ user_param_count,
+ acpi_ut_get_type_name
+ (node->type)));
+ }
+
+ return;
+ }
+
+ /*
+ * This is a control method. Check the parameter count.
+ * We can only check the incoming argument count against the
+ * argument count declared for the method in the ASL/AML.
+ *
+ * Emit a message if too few or too many arguments have been passed
+ * by the caller.
+ *
+ * Note: Too many arguments will not cause the method to
+ * fail. However, the method will fail if there are too few
+ * arguments and the method attempts to use one of the missing ones.
+ */
+ aml_param_count = node->object->method.param_count;
+
+ if (user_param_count < aml_param_count) {
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Insufficient arguments - "
+ "Caller passed %u, method requires %u",
+ user_param_count,
+ aml_param_count));
+ } else if (user_param_count > aml_param_count) {
+ ACPI_INFO_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Excess arguments - "
+ "Caller passed %u, method requires %u",
+ user_param_count,
+ aml_param_count));
+ }
+
+ return;
+ }
+
+ /*
+ * This is a predefined name. Validate the user-supplied parameter
+ * count against the ACPI specification. We don't validate against
+ * the method itself because what is important here is that the
+ * caller is in conformance with the spec. (The arg count for the
+ * method was checked against the ACPI spec earlier.)
+ *
+ * Some methods are allowed to have a "minimum" number of args (_SCP)
+ * because their definition in ACPI has changed over time.
+ */
+ required_param_count =
+ METHOD_GET_ARG_COUNT(predefined->info.argument_list);
+
+ if (user_param_count < required_param_count) {
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+ "Insufficient arguments - "
+ "Caller passed %u, ACPI requires %u",
+ user_param_count, required_param_count));
+ } else if ((user_param_count > required_param_count) &&
+ !(predefined->info.argument_list & ARG_COUNT_IS_MINIMUM)) {
+ ACPI_INFO_PREDEFINED((AE_INFO, pathname, ACPI_WARN_ALWAYS,
+ "Excess arguments - "
+ "Caller passed %u, ACPI requires %u",
+ user_param_count, required_param_count));
+ }
+}
diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c
index 8f79a9d2d50e..acd2964c2690 100644
--- a/drivers/acpi/acpica/nsconvert.c
+++ b/drivers/acpi/acpica/nsconvert.c
@@ -103,6 +103,7 @@ acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
break;
default:
+
return (AE_AML_OPERAND_TYPE);
}
@@ -191,6 +192,7 @@ acpi_ns_convert_to_string(union acpi_operand_object *original_object,
break;
default:
+
return (AE_AML_OPERAND_TYPE);
}
@@ -294,6 +296,7 @@ acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
break;
default:
+
return (AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index ce6e97326205..7418c77fde8c 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -244,10 +244,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
case ACPI_TYPE_BUFFER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_METHOD:
+
acpi_os_printf("<No attached object>");
break;
default:
+
break;
}
@@ -433,6 +435,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
break;
default:
+
break;
}
break;
@@ -567,32 +570,39 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
goto cleanup;
case ACPI_TYPE_BUFFER_FIELD:
+
obj_desc =
(union acpi_operand_object *)obj_desc->buffer_field.
buffer_obj;
break;
case ACPI_TYPE_PACKAGE:
+
obj_desc = (void *)obj_desc->package.elements;
break;
case ACPI_TYPE_METHOD:
+
obj_desc = (void *)obj_desc->method.aml_start;
break;
case ACPI_TYPE_LOCAL_REGION_FIELD:
+
obj_desc = (void *)obj_desc->field.region_obj;
break;
case ACPI_TYPE_LOCAL_BANK_FIELD:
+
obj_desc = (void *)obj_desc->bank_field.region_obj;
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
obj_desc = (void *)obj_desc->index_field.index_obj;
break;
default:
+
goto cleanup;
}
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index b61db69d5675..18108bc2e51c 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -61,7 +61,7 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
*
* PARAMETERS: info - Evaluation info block, contains:
* prefix_node - Prefix or Method/Object Node to execute
- * pathname - Name of method to execute, If NULL, the
+ * relative_path - Name of method to execute, If NULL, the
* Node is the object to execute
* parameters - List of parameters to pass to the method,
* terminated by NULL. Params itself may be
@@ -82,10 +82,9 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
*
******************************************************************************/
-acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
{
acpi_status status;
- struct acpi_namespace_node *node;
ACPI_FUNCTION_TRACE(ns_evaluate);
@@ -93,83 +92,138 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Initialize the return value to an invalid object */
-
- info->return_object = NULL;
- info->param_count = 0;
-
- if (!info->resolved_node) {
+ if (!info->node) {
/*
- * Get the actual namespace node for the target object if we need to.
- * Handles these cases:
+ * Get the actual namespace node for the target object if we
+ * need to. Handles these cases:
*
- * 1) Null node, Pathname (absolute path)
- * 2) Node, Pathname (path relative to Node)
- * 3) Node, Null Pathname
+ * 1) Null node, valid pathname from root (absolute path)
+ * 2) Node and valid pathname (path relative to Node)
+ * 3) Node, Null pathname
*/
- status = acpi_ns_get_node(info->prefix_node, info->pathname,
- ACPI_NS_NO_UPSEARCH,
- &info->resolved_node);
+ status =
+ acpi_ns_get_node(info->prefix_node, info->relative_pathname,
+ ACPI_NS_NO_UPSEARCH, &info->node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
}
/*
- * For a method alias, we must grab the actual method node so that proper
- * scoping context will be established before execution.
+ * For a method alias, we must grab the actual method node so that
+ * proper scoping context will be established before execution.
*/
- if (acpi_ns_get_type(info->resolved_node) ==
- ACPI_TYPE_LOCAL_METHOD_ALIAS) {
- info->resolved_node =
+ if (acpi_ns_get_type(info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+ info->node =
ACPI_CAST_PTR(struct acpi_namespace_node,
- info->resolved_node->object);
+ info->node->object);
+ }
+
+ /* Complete the info block initialization */
+
+ info->return_object = NULL;
+ info->node_flags = info->node->flags;
+ info->obj_desc = acpi_ns_get_attached_object(info->node);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n",
+ info->relative_pathname, info->node,
+ acpi_ns_get_attached_object(info->node)));
+
+ /* Get info if we have a predefined name (_HID, etc.) */
+
+ info->predefined =
+ acpi_ut_match_predefined_method(info->node->name.ascii);
+
+ /* Get the full pathname to the object, for use in warning messages */
+
+ info->full_pathname = acpi_ns_get_external_pathname(info->node);
+ if (!info->full_pathname) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "%s [%p] Value %p\n", info->pathname,
- info->resolved_node,
- acpi_ns_get_attached_object(info->resolved_node)));
+ /* Count the number of arguments being passed in */
+
+ info->param_count = 0;
+ if (info->parameters) {
+ while (info->parameters[info->param_count]) {
+ info->param_count++;
+ }
+
+ /* Warn on impossible argument count */
+
+ if (info->param_count > ACPI_METHOD_NUM_ARGS) {
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ ACPI_WARN_ALWAYS,
+ "Excess arguments (%u) - using only %u",
+ info->param_count,
+ ACPI_METHOD_NUM_ARGS));
+
+ info->param_count = ACPI_METHOD_NUM_ARGS;
+ }
+ }
+
+ /*
+ * For predefined names: Check that the declared argument count
+ * matches the ACPI spec -- otherwise this is a BIOS error.
+ */
+ acpi_ns_check_acpi_compliance(info->full_pathname, info->node,
+ info->predefined);
+
+ /*
+ * For all names: Check that the incoming argument count for
+ * this method/object matches the actual ASL/AML definition.
+ */
+ acpi_ns_check_argument_count(info->full_pathname, info->node,
+ info->param_count, info->predefined);
- node = info->resolved_node;
+ /* For predefined names: Typecheck all incoming arguments */
+
+ acpi_ns_check_argument_types(info);
/*
- * Two major cases here:
+ * Three major evaluation cases:
*
- * 1) The object is a control method -- execute it
- * 2) The object is not a method -- just return it's current value
+ * 1) Object types that cannot be evaluated by definition
+ * 2) The object is a control method -- execute it
+ * 3) The object is not a method -- just return it's current value
*/
- if (acpi_ns_get_type(info->resolved_node) == ACPI_TYPE_METHOD) {
+ switch (acpi_ns_get_type(info->node)) {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_EVENT:
+ case ACPI_TYPE_MUTEX:
+ case ACPI_TYPE_REGION:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_LOCAL_SCOPE:
+ /*
+ * 1) Disallow evaluation of certain object types. For these,
+ * object evaluation is undefined and not supported.
+ */
+ ACPI_ERROR((AE_INFO,
+ "%s: Evaluation of object type [%s] is not supported",
+ info->full_pathname,
+ acpi_ut_get_type_name(info->node->type)));
+
+ status = AE_TYPE;
+ goto cleanup;
+
+ case ACPI_TYPE_METHOD:
/*
- * 1) Object is a control method - execute it
+ * 2) Object is a control method - execute it
*/
/* Verify that there is a method object associated with this node */
- info->obj_desc =
- acpi_ns_get_attached_object(info->resolved_node);
if (!info->obj_desc) {
ACPI_ERROR((AE_INFO,
- "Control method has no attached sub-object"));
- return_ACPI_STATUS(AE_NULL_OBJECT);
+ "%s: Method has no attached sub-object",
+ info->full_pathname));
+ status = AE_NULL_OBJECT;
+ goto cleanup;
}
- /* Count the number of arguments being passed to the method */
-
- if (info->parameters) {
- while (info->parameters[info->param_count]) {
- if (info->param_count > ACPI_METHOD_MAX_ARG) {
- return_ACPI_STATUS(AE_LIMIT);
- }
- info->param_count++;
- }
- }
-
-
- ACPI_DUMP_PATHNAME(info->resolved_node, "ACPI: Execute Method",
- ACPI_LV_INFO, _COMPONENT);
-
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Method at AML address %p Length %X\n",
+ "**** Execute method [%s] at AML address %p length %X\n",
+ info->full_pathname,
info->obj_desc->method.aml_start + 1,
info->obj_desc->method.aml_length - 1));
@@ -184,81 +238,61 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
acpi_ex_enter_interpreter();
status = acpi_ps_execute_method(info);
acpi_ex_exit_interpreter();
- } else {
+ break;
+
+ default:
/*
- * 2) Object is not a method, return its current value
- *
- * Disallow certain object types. For these, "evaluation" is undefined.
+ * 3) All other non-method objects -- get the current object value
*/
- switch (info->resolved_node->type) {
- case ACPI_TYPE_DEVICE:
- case ACPI_TYPE_EVENT:
- case ACPI_TYPE_MUTEX:
- case ACPI_TYPE_REGION:
- case ACPI_TYPE_THERMAL:
- case ACPI_TYPE_LOCAL_SCOPE:
-
- ACPI_ERROR((AE_INFO,
- "[%4.4s] Evaluation of object type [%s] is not supported",
- info->resolved_node->name.ascii,
- acpi_ut_get_type_name(info->resolved_node->
- type)));
-
- return_ACPI_STATUS(AE_TYPE);
-
- default:
- break;
- }
/*
- * Objects require additional resolution steps (e.g., the Node may be
- * a field that must be read, etc.) -- we can't just grab the object
- * out of the node.
+ * Some objects require additional resolution steps (e.g., the Node
+ * may be a field that must be read, etc.) -- we can't just grab
+ * the object out of the node.
*
* Use resolve_node_to_value() to get the associated value.
*
* NOTE: we can get away with passing in NULL for a walk state because
- * resolved_node is guaranteed to not be a reference to either a method
+ * the Node is guaranteed to not be a reference to either a method
* local or a method argument (because this interface is never called
* from a running method.)
*
* Even though we do not directly invoke the interpreter for object
- * resolution, we must lock it because we could access an opregion.
- * The opregion access code assumes that the interpreter is locked.
+ * resolution, we must lock it because we could access an op_region.
+ * The op_region access code assumes that the interpreter is locked.
*/
acpi_ex_enter_interpreter();
- /* Function has a strange interface */
+ /* TBD: resolve_node_to_value has a strange interface, fix */
+
+ info->return_object =
+ ACPI_CAST_PTR(union acpi_operand_object, info->node);
status =
- acpi_ex_resolve_node_to_value(&info->resolved_node, NULL);
+ acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
+ (struct acpi_namespace_node,
+ &info->return_object), NULL);
acpi_ex_exit_interpreter();
- /*
- * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
- * in resolved_node.
- */
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_RETURN_VALUE;
- info->return_object =
- ACPI_CAST_PTR(union acpi_operand_object,
- info->resolved_node);
-
- ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "Returning object %p [%s]\n",
- info->return_object,
- acpi_ut_get_object_type_name(info->
- return_object)));
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
}
+
+ ACPI_DEBUG_PRINT((ACPI_DB_NAMES, "Returned object %p [%s]\n",
+ info->return_object,
+ acpi_ut_get_object_type_name(info->
+ return_object)));
+
+ status = AE_CTRL_RETURN_VALUE; /* Always has a "return value" */
+ break;
}
/*
- * Check input argument count against the ASL-defined count for a method.
- * Also check predefined names: argument count and return value against
- * the ACPI specification. Some incorrect return value types are repaired.
+ * For predefined names, check the return value against the ACPI
+ * specification. Some incorrect return value types are repaired.
*/
- (void)acpi_ns_check_predefined_names(node, info->param_count,
- status, &info->return_object);
+ (void)acpi_ns_check_return_value(info->node, info, info->param_count,
+ status, &info->return_object);
/* Check if there is a return value that must be dealt with */
@@ -278,12 +312,15 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"*** Completed evaluation of object %s ***\n",
- info->pathname));
+ info->relative_pathname));
+ cleanup:
/*
* Namespace was unlocked by the handling acpi_ns* function, so we
- * just return
+ * just free the pathname and return
*/
+ ACPI_FREE(info->full_pathname);
+ info->full_pathname = NULL;
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 46f0f83417a1..dd2ceae3f717 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -176,7 +176,7 @@ acpi_status acpi_ns_initialize_devices(void)
* part of the ACPI specification.
*/
info.evaluate_info->prefix_node = acpi_gbl_root_node;
- info.evaluate_info->pathname = METHOD_NAME__INI;
+ info.evaluate_info->relative_pathname = METHOD_NAME__INI;
info.evaluate_info->parameters = NULL;
info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;
@@ -266,28 +266,34 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
switch (type) {
case ACPI_TYPE_REGION:
+
info->op_region_count++;
break;
case ACPI_TYPE_BUFFER_FIELD:
+
info->field_count++;
break;
case ACPI_TYPE_LOCAL_BANK_FIELD:
+
info->field_count++;
break;
case ACPI_TYPE_BUFFER:
+
info->buffer_count++;
break;
case ACPI_TYPE_PACKAGE:
+
info->package_count++;
break;
default:
/* No init required, just exit now */
+
return (AE_OK);
}
@@ -337,7 +343,9 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
break;
default:
+
/* No other types can get here */
+
break;
}
@@ -416,6 +424,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
break;
default:
+
break;
}
@@ -560,7 +569,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
ACPI_MEMSET(info, 0, sizeof(struct acpi_evaluate_info));
info->prefix_node = device_node;
- info->pathname = METHOD_NAME__INI;
+ info->relative_pathname = METHOD_NAME__INI;
info->parameters = NULL;
info->flags = ACPI_IGNORE_RETURN_VALUE;
@@ -574,8 +583,7 @@ acpi_ns_init_one_device(acpi_handle obj_handle,
/* Ignore error and move on to next device */
- char *scope_name =
- acpi_ns_get_external_pathname(info->resolved_node);
+ char *scope_name = acpi_ns_get_external_pathname(info->node);
ACPI_EXCEPTION((AE_INFO, status, "during %s._INI execution",
scope_name));
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 8a52916148cb..24b71a01bf93 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -61,28 +61,29 @@ ACPI_MODULE_NAME("nspredef")
* There are several areas that are validated:
*
* 1) The number of input arguments as defined by the method/object in the
- * ASL is validated against the ACPI specification.
+ * ASL is validated against the ACPI specification.
* 2) The type of the return object (if any) is validated against the ACPI
- * specification.
+ * specification.
* 3) For returned package objects, the count of package elements is
- * validated, as well as the type of each package element. Nested
- * packages are supported.
+ * validated, as well as the type of each package element. Nested
+ * packages are supported.
*
* For any problems found, a warning message is issued.
*
******************************************************************************/
/* Local prototypes */
static acpi_status
-acpi_ns_check_reference(struct acpi_predefined_data *data,
+acpi_ns_check_reference(struct acpi_evaluate_info *info,
union acpi_operand_object *return_object);
static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object);
/*******************************************************************************
*
- * FUNCTION: acpi_ns_check_predefined_names
+ * FUNCTION: acpi_ns_check_return_value
*
* PARAMETERS: node - Namespace node for the method/object
+ * info - Method execution information block
* user_param_count - Number of parameters actually passed
* return_status - Status from the object evaluation
* return_object_ptr - Pointer to the object returned from the
@@ -90,44 +91,25 @@ static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object);
*
* RETURN: Status
*
- * DESCRIPTION: Check an ACPI name for a match in the predefined name list.
+ * DESCRIPTION: Check the value returned from a predefined name.
*
******************************************************************************/
acpi_status
-acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
- u32 user_param_count,
- acpi_status return_status,
- union acpi_operand_object **return_object_ptr)
+acpi_ns_check_return_value(struct acpi_namespace_node *node,
+ struct acpi_evaluate_info *info,
+ u32 user_param_count,
+ acpi_status return_status,
+ union acpi_operand_object **return_object_ptr)
{
- acpi_status status = AE_OK;
+ acpi_status status;
const union acpi_predefined_info *predefined;
- char *pathname;
- struct acpi_predefined_data *data;
-
- /* Match the name for this method/object against the predefined list */
-
- predefined = acpi_ut_match_predefined_method(node->name.ascii);
-
- /* Get the full pathname to the object, for use in warning messages */
-
- pathname = acpi_ns_get_external_pathname(node);
- if (!pathname) {
- return (AE_OK); /* Could not get pathname, ignore */
- }
-
- /*
- * Check that the parameter count for this method matches the ASL
- * definition. For predefined names, ensure that both the caller and
- * the method itself are in accordance with the ACPI specification.
- */
- acpi_ns_check_parameter_count(pathname, node, user_param_count,
- predefined);
/* If not a predefined name, we cannot validate the return object */
+ predefined = info->predefined;
if (!predefined) {
- goto cleanup;
+ return (AE_OK);
}
/*
@@ -135,7 +117,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* validate the return object
*/
if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) {
- goto cleanup;
+ return (AE_OK);
}
/*
@@ -154,25 +136,14 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
if (acpi_gbl_disable_auto_repair ||
(!predefined->info.expected_btypes) ||
(predefined->info.expected_btypes == ACPI_RTYPE_ALL)) {
- goto cleanup;
- }
-
- /* Create the parameter data block for object validation */
-
- data = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_predefined_data));
- if (!data) {
- goto cleanup;
+ return (AE_OK);
}
- data->predefined = predefined;
- data->node = node;
- data->node_flags = node->flags;
- data->pathname = pathname;
/*
* Check that the type of the main return object is what is expected
* for this predefined name
*/
- status = acpi_ns_check_object_type(data, return_object_ptr,
+ status = acpi_ns_check_object_type(info, return_object_ptr,
predefined->info.expected_btypes,
ACPI_NOT_PACKAGE_ELEMENT);
if (ACPI_FAILURE(status)) {
@@ -184,10 +155,16 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* Note: Package may have been newly created by call above.
*/
if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) {
- data->parent_package = *return_object_ptr;
- status = acpi_ns_check_package(data, return_object_ptr);
+ info->parent_package = *return_object_ptr;
+ status = acpi_ns_check_package(info, return_object_ptr);
if (ACPI_FAILURE(status)) {
- goto exit;
+
+ /* We might be able to fix some errors */
+
+ if ((status != AE_AML_OPERAND_TYPE) &&
+ (status != AE_AML_OPERAND_VALUE)) {
+ goto exit;
+ }
}
}
@@ -199,7 +176,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
* performed on a per-name basis, i.e., the code is specific to
* particular predefined names.
*/
- status = acpi_ns_complex_repairs(data, node, status, return_object_ptr);
+ status = acpi_ns_complex_repairs(info, node, status, return_object_ptr);
exit:
/*
@@ -207,112 +184,18 @@ exit:
* or more objects, mark the parent node to suppress further warning
* messages during the next evaluation of the same method/object.
*/
- if (ACPI_FAILURE(status) || (data->flags & ACPI_OBJECT_REPAIRED)) {
+ if (ACPI_FAILURE(status) || (info->return_flags & ACPI_OBJECT_REPAIRED)) {
node->flags |= ANOBJ_EVALUATED;
}
- ACPI_FREE(data);
-cleanup:
- ACPI_FREE(pathname);
return (status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_ns_check_parameter_count
- *
- * PARAMETERS: pathname - Full pathname to the node (for error msgs)
- * node - Namespace node for the method/object
- * user_param_count - Number of args passed in by the caller
- * predefined - Pointer to entry in predefined name table
- *
- * RETURN: None
- *
- * DESCRIPTION: Check that the declared (in ASL/AML) parameter count for a
- * predefined name is what is expected (i.e., what is defined in
- * the ACPI specification for this predefined name.)
- *
- ******************************************************************************/
-
-void
-acpi_ns_check_parameter_count(char *pathname,
- struct acpi_namespace_node *node,
- u32 user_param_count,
- const union acpi_predefined_info *predefined)
-{
- u32 param_count;
- u32 required_params_current;
- u32 required_params_old;
-
- /* Methods have 0-7 parameters. All other types have zero. */
-
- param_count = 0;
- if (node->type == ACPI_TYPE_METHOD) {
- param_count = node->object->method.param_count;
- }
-
- if (!predefined) {
- /*
- * Check the parameter count for non-predefined methods/objects.
- *
- * Warning if too few or too many arguments have been passed by the
- * caller. An incorrect number of arguments may not cause the method
- * to fail. However, the method will fail if there are too few
- * arguments and the method attempts to use one of the missing ones.
- */
- if (user_param_count < param_count) {
- ACPI_WARN_PREDEFINED((AE_INFO, pathname,
- ACPI_WARN_ALWAYS,
- "Insufficient arguments - needs %u, found %u",
- param_count, user_param_count));
- } else if (user_param_count > param_count) {
- ACPI_WARN_PREDEFINED((AE_INFO, pathname,
- ACPI_WARN_ALWAYS,
- "Excess arguments - needs %u, found %u",
- param_count, user_param_count));
- }
- return;
- }
-
- /*
- * Validate the user-supplied parameter count.
- * Allow two different legal argument counts (_SCP, etc.)
- */
- required_params_current =
- predefined->info.argument_list & METHOD_ARG_MASK;
- required_params_old =
- predefined->info.argument_list >> METHOD_ARG_BIT_WIDTH;
-
- if (user_param_count != ACPI_UINT32_MAX) {
- if ((user_param_count != required_params_current) &&
- (user_param_count != required_params_old)) {
- ACPI_WARN_PREDEFINED((AE_INFO, pathname,
- ACPI_WARN_ALWAYS,
- "Parameter count mismatch - "
- "caller passed %u, ACPI requires %u",
- user_param_count,
- required_params_current));
- }
- }
-
- /*
- * Check that the ASL-defined parameter count is what is expected for
- * this predefined name (parameter count as defined by the ACPI
- * specification)
- */
- if ((param_count != required_params_current) &&
- (param_count != required_params_old)) {
- ACPI_WARN_PREDEFINED((AE_INFO, pathname, node->flags,
- "Parameter count mismatch - ASL declared %u, ACPI requires %u",
- param_count, required_params_current));
- }
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_check_object_type
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
* expected_btypes - Bitmap of expected return type(s)
@@ -328,7 +211,7 @@ acpi_ns_check_parameter_count(char *pathname,
******************************************************************************/
acpi_status
-acpi_ns_check_object_type(struct acpi_predefined_data *data,
+acpi_ns_check_object_type(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr,
u32 expected_btypes, u32 package_index)
{
@@ -340,7 +223,8 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
if (return_object &&
ACPI_GET_DESCRIPTOR_TYPE(return_object) == ACPI_DESC_TYPE_NAMED) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Invalid return type - Found a Namespace node [%4.4s] type %s",
return_object->node.name.ascii,
acpi_ut_get_type_name(return_object->node.
@@ -356,8 +240,8 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
* from all of the predefined names (including elements of returned
* packages)
*/
- data->return_btype = acpi_ns_get_bitmapped_type(return_object);
- if (data->return_btype == ACPI_RTYPE_ANY) {
+ info->return_btype = acpi_ns_get_bitmapped_type(return_object);
+ if (info->return_btype == ACPI_RTYPE_ANY) {
/* Not one of the supported objects, must be incorrect */
goto type_error_exit;
@@ -365,16 +249,18 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
/* For reference objects, check that the reference type is correct */
- if ((data->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) {
- status = acpi_ns_check_reference(data, return_object);
+ if ((info->return_btype & expected_btypes) == ACPI_RTYPE_REFERENCE) {
+ status = acpi_ns_check_reference(info, return_object);
return (status);
}
/* Attempt simple repair of the returned object if necessary */
- status = acpi_ns_simple_repair(data, expected_btypes,
+ status = acpi_ns_simple_repair(info, expected_btypes,
package_index, return_object_ptr);
- return (status);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK); /* Successful repair */
+ }
type_error_exit:
@@ -383,12 +269,14 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
acpi_ut_get_expected_return_types(type_buffer, expected_btypes);
if (package_index == ACPI_NOT_PACKAGE_ELEMENT) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Return type mismatch - found %s, expected %s",
acpi_ut_get_object_type_name
(return_object), type_buffer));
} else {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Return Package type mismatch at index %u - "
"found %s, expected %s", package_index,
acpi_ut_get_object_type_name
@@ -402,7 +290,7 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_check_reference
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object - Object returned from the evaluation of a
* method or object
*
@@ -415,7 +303,7 @@ acpi_ns_check_object_type(struct acpi_predefined_data *data,
******************************************************************************/
static acpi_status
-acpi_ns_check_reference(struct acpi_predefined_data *data,
+acpi_ns_check_reference(struct acpi_evaluate_info *info,
union acpi_operand_object *return_object)
{
@@ -428,7 +316,7 @@ acpi_ns_check_reference(struct acpi_predefined_data *data,
return (AE_OK);
}
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
"Return type mismatch - unexpected reference object type [%s] %2.2X",
acpi_ut_get_reference_name(return_object),
return_object->reference.class));
@@ -462,26 +350,32 @@ static u32 acpi_ns_get_bitmapped_type(union acpi_operand_object *return_object)
switch (return_object->common.type) {
case ACPI_TYPE_INTEGER:
+
return_btype = ACPI_RTYPE_INTEGER;
break;
case ACPI_TYPE_BUFFER:
+
return_btype = ACPI_RTYPE_BUFFER;
break;
case ACPI_TYPE_STRING:
+
return_btype = ACPI_RTYPE_STRING;
break;
case ACPI_TYPE_PACKAGE:
+
return_btype = ACPI_RTYPE_PACKAGE;
break;
case ACPI_TYPE_LOCAL_REFERENCE:
+
return_btype = ACPI_RTYPE_REFERENCE;
break;
default:
+
/* Not one of the supported objects, must be incorrect */
return_btype = ACPI_RTYPE_ANY;
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index 77cdd539de16..6d55cef7916c 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -51,12 +51,12 @@ ACPI_MODULE_NAME("nsprepkg")
/* Local prototypes */
static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
+acpi_ns_check_package_list(struct acpi_evaluate_info *info,
const union acpi_predefined_info *package,
union acpi_operand_object **elements, u32 count);
static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
union acpi_operand_object **elements,
u8 type1,
u32 count1,
@@ -66,7 +66,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_check_package
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -78,7 +78,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
******************************************************************************/
acpi_status
-acpi_ns_check_package(struct acpi_predefined_data *data,
+acpi_ns_check_package(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
@@ -93,18 +93,18 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* The package info for this name is in the next table entry */
- package = data->predefined + 1;
+ package = info->predefined + 1;
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
"%s Validating return Package of Type %X, Count %X\n",
- data->pathname, package->ret_info.type,
+ info->full_pathname, package->ret_info.type,
return_object->package.count));
/*
* For variable-length Packages, we can safely remove all embedded
* and trailing NULL package elements
*/
- acpi_ns_remove_null_elements(data, package->ret_info.type,
+ acpi_ns_remove_null_elements(info, package->ret_info.type,
return_object);
/* Extract package count and elements array */
@@ -121,7 +121,8 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
return (AE_OK);
}
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Return Package has no elements (empty)"));
return (AE_AML_OPERAND_VALUE);
@@ -135,7 +136,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
*/
switch (package->ret_info.type) {
case ACPI_PTYPE1_FIXED:
-
/*
* The package count is fixed and there are no sub-packages
*
@@ -150,13 +150,13 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Return Package is larger than needed - "
"found %u, expected %u\n",
- data->pathname, count,
+ info->full_pathname, count,
expected_count));
}
/* Validate all elements of the returned package */
- status = acpi_ns_check_package_elements(data, elements,
+ status = acpi_ns_check_package_elements(info, elements,
package->ret_info.
object_type1,
package->ret_info.
@@ -168,13 +168,12 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
break;
case ACPI_PTYPE1_VAR:
-
/*
* The package count is variable, there are no sub-packages, and all
* elements must be of the same type
*/
for (i = 0; i < count; i++) {
- status = acpi_ns_check_object_type(data, elements,
+ status = acpi_ns_check_object_type(info, elements,
package->ret_info.
object_type1, i);
if (ACPI_FAILURE(status)) {
@@ -185,7 +184,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
break;
case ACPI_PTYPE1_OPTION:
-
/*
* The package count is variable, there are no sub-packages. There are
* a fixed number of required elements, and a variable number of
@@ -206,7 +204,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* These are the required package elements (0, 1, or 2) */
status =
- acpi_ns_check_object_type(data, elements,
+ acpi_ns_check_object_type(info, elements,
package->
ret_info3.
object_type[i],
@@ -218,7 +216,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* These are the optional package elements */
status =
- acpi_ns_check_object_type(data, elements,
+ acpi_ns_check_object_type(info, elements,
package->
ret_info3.
tail_object_type,
@@ -235,7 +233,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* First element is the (Integer) revision */
- status = acpi_ns_check_object_type(data, elements,
+ status = acpi_ns_check_object_type(info, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
@@ -247,14 +245,14 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* Examine the sub-packages */
status =
- acpi_ns_check_package_list(data, package, elements, count);
+ acpi_ns_check_package_list(info, package, elements, count);
break;
case ACPI_PTYPE2_PKG_COUNT:
/* First element is the (Integer) count of sub-packages to follow */
- status = acpi_ns_check_object_type(data, elements,
+ status = acpi_ns_check_object_type(info, elements,
ACPI_RTYPE_INTEGER, 0);
if (ACPI_FAILURE(status)) {
return (status);
@@ -275,7 +273,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* Examine the sub-packages */
status =
- acpi_ns_check_package_list(data, package, elements, count);
+ acpi_ns_check_package_list(info, package, elements, count);
break;
case ACPI_PTYPE2:
@@ -283,7 +281,6 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
case ACPI_PTYPE2_MIN:
case ACPI_PTYPE2_COUNT:
case ACPI_PTYPE2_FIX_VAR:
-
/*
* These types all return a single Package that consists of a
* variable number of sub-Packages.
@@ -300,7 +297,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* Create the new outer package and populate it */
status =
- acpi_ns_wrap_with_package(data, return_object,
+ acpi_ns_wrap_with_package(info, return_object,
return_object_ptr);
if (ACPI_FAILURE(status)) {
return (status);
@@ -316,14 +313,15 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* Examine the sub-packages */
status =
- acpi_ns_check_package_list(data, package, elements, count);
+ acpi_ns_check_package_list(info, package, elements, count);
break;
default:
/* Should not get here if predefined info table is correct */
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Invalid internal return type in table entry: %X",
package->ret_info.type));
@@ -336,7 +334,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
/* Error exit for the case with an incorrect package count */
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
"Return Package is too small - found %u elements, expected %u",
count, expected_count));
@@ -347,7 +345,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_check_package_list
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* package - Pointer to package-specific info for method
* elements - Element list of parent package. All elements
* of this list should be of type Package.
@@ -360,7 +358,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
******************************************************************************/
static acpi_status
-acpi_ns_check_package_list(struct acpi_predefined_data *data,
+acpi_ns_check_package_list(struct acpi_evaluate_info *info,
const union acpi_predefined_info *package,
union acpi_operand_object **elements, u32 count)
{
@@ -381,11 +379,11 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
for (i = 0; i < count; i++) {
sub_package = *elements;
sub_elements = sub_package->package.elements;
- data->parent_package = sub_package;
+ info->parent_package = sub_package;
/* Each sub-object must be of type Package */
- status = acpi_ns_check_object_type(data, &sub_package,
+ status = acpi_ns_check_object_type(info, &sub_package,
ACPI_RTYPE_PACKAGE, i);
if (ACPI_FAILURE(status)) {
return (status);
@@ -393,7 +391,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
/* Examine the different types of expected sub-packages */
- data->parent_package = sub_package;
+ info->parent_package = sub_package;
switch (package->ret_info.type) {
case ACPI_PTYPE2:
case ACPI_PTYPE2_PKG_COUNT:
@@ -408,7 +406,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
}
status =
- acpi_ns_check_package_elements(data, sub_elements,
+ acpi_ns_check_package_elements(info, sub_elements,
package->ret_info.
object_type1,
package->ret_info.
@@ -434,7 +432,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
}
status =
- acpi_ns_check_package_elements(data, sub_elements,
+ acpi_ns_check_package_elements(info, sub_elements,
package->ret_info.
object_type1,
package->ret_info.
@@ -463,7 +461,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
for (j = 0; j < expected_count; j++) {
status =
- acpi_ns_check_object_type(data,
+ acpi_ns_check_object_type(info,
&sub_elements[j],
package->
ret_info2.
@@ -487,7 +485,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
/* Check the type of each sub-package element */
status =
- acpi_ns_check_package_elements(data, sub_elements,
+ acpi_ns_check_package_elements(info, sub_elements,
package->ret_info.
object_type1,
sub_package->package.
@@ -498,12 +496,11 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
break;
case ACPI_PTYPE2_COUNT:
-
/*
* First element is the (Integer) count of elements, including
* the count field (the ACPI name is num_elements)
*/
- status = acpi_ns_check_object_type(data, sub_elements,
+ status = acpi_ns_check_object_type(info, sub_elements,
ACPI_RTYPE_INTEGER,
0);
if (ACPI_FAILURE(status)) {
@@ -537,7 +534,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
/* Check the type of each sub-package element */
status =
- acpi_ns_check_package_elements(data,
+ acpi_ns_check_package_elements(info,
(sub_elements + 1),
package->ret_info.
object_type1,
@@ -562,7 +559,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
/* The sub-package count was smaller than required */
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname, info->node_flags,
"Return Sub-Package[%u] is too small - found %u elements, expected %u",
i, sub_package->package.count, expected_count));
@@ -573,7 +570,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_check_package_elements
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* elements - Pointer to the package elements array
* type1 - Object type for first group
* count1 - Count for first group
@@ -589,7 +586,7 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
******************************************************************************/
static acpi_status
-acpi_ns_check_package_elements(struct acpi_predefined_data *data,
+acpi_ns_check_package_elements(struct acpi_evaluate_info *info,
union acpi_operand_object **elements,
u8 type1,
u32 count1,
@@ -605,7 +602,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
* The second group can have a count of zero.
*/
for (i = 0; i < count1; i++) {
- status = acpi_ns_check_object_type(data, this_element,
+ status = acpi_ns_check_object_type(info, this_element,
type1, i + start_index);
if (ACPI_FAILURE(status)) {
return (status);
@@ -614,7 +611,7 @@ acpi_ns_check_package_elements(struct acpi_predefined_data *data,
}
for (i = 0; i < count2; i++) {
- status = acpi_ns_check_object_type(data, this_element,
+ status = acpi_ns_check_object_type(info, this_element,
type2,
(i + count1 + start_index));
if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 18f02e4ece01..f8e71ea60319 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -130,7 +130,7 @@ static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
*
* FUNCTION: acpi_ns_simple_repair
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* expected_btypes - Object types expected
* package_index - Index of object within parent package (if
* applicable - ACPI_NOT_PACKAGE_ELEMENT
@@ -146,7 +146,7 @@ static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
******************************************************************************/
acpi_status
-acpi_ns_simple_repair(struct acpi_predefined_data *data,
+acpi_ns_simple_repair(struct acpi_evaluate_info *info,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr)
@@ -162,12 +162,12 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
* Special repairs for certain names that are in the repair table.
* Check if this name is in the list of repairable names.
*/
- predefined = acpi_ns_match_simple_repair(data->node,
- data->return_btype,
+ predefined = acpi_ns_match_simple_repair(info->node,
+ info->return_btype,
package_index);
if (predefined) {
if (!return_object) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
ACPI_WARN_ALWAYS,
"Missing expected return value"));
}
@@ -191,7 +191,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
* Do not perform simple object repair unless the return type is not
* expected.
*/
- if (data->return_btype & expected_btypes) {
+ if (info->return_btype & expected_btypes) {
return (AE_OK);
}
@@ -211,7 +211,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
*/
if (!return_object) {
if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
ACPI_WARN_ALWAYS,
"Missing expected return value"));
@@ -247,14 +247,14 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
* for correct contents (expected object type or types).
*/
status =
- acpi_ns_wrap_with_package(data, return_object, &new_object);
+ acpi_ns_wrap_with_package(info, return_object, &new_object);
if (ACPI_SUCCESS(status)) {
/*
* The original object just had its reference count
* incremented for being inserted into the new package.
*/
*return_object_ptr = new_object; /* New Package object */
- data->flags |= ACPI_OBJECT_REPAIRED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
return (AE_OK);
}
}
@@ -277,7 +277,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
* package object as part of the repair, we don't need to
* change the reference count.
*/
- if (!(data->flags & ACPI_OBJECT_WRAPPED)) {
+ if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) {
new_object->common.reference_count =
return_object->common.reference_count;
@@ -288,14 +288,14 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Converted %s to expected %s at Package index %u\n",
- data->pathname,
+ info->full_pathname,
acpi_ut_get_object_type_name(return_object),
acpi_ut_get_object_type_name(new_object),
package_index));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Converted %s to expected %s\n",
- data->pathname,
+ info->full_pathname,
acpi_ut_get_object_type_name(return_object),
acpi_ut_get_object_type_name(new_object)));
}
@@ -304,7 +304,7 @@ acpi_ns_simple_repair(struct acpi_predefined_data *data,
acpi_ut_remove_reference(return_object);
*return_object_ptr = new_object;
- data->flags |= ACPI_OBJECT_REPAIRED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
return (AE_OK);
}
@@ -359,7 +359,7 @@ static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
*
* FUNCTION: acpi_ns_repair_null_element
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* expected_btypes - Object types expected
* package_index - Index of object within parent package (if
* applicable - ACPI_NOT_PACKAGE_ELEMENT
@@ -374,7 +374,7 @@ static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
******************************************************************************/
acpi_status
-acpi_ns_repair_null_element(struct acpi_predefined_data *data,
+acpi_ns_repair_null_element(struct acpi_evaluate_info * info,
u32 expected_btypes,
u32 package_index,
union acpi_operand_object **return_object_ptr)
@@ -424,16 +424,16 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
/* Set the reference count according to the parent Package object */
new_object->common.reference_count =
- data->parent_package->common.reference_count;
+ info->parent_package->common.reference_count;
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Converted NULL package element to expected %s at index %u\n",
- data->pathname,
+ info->full_pathname,
acpi_ut_get_object_type_name(new_object),
package_index));
*return_object_ptr = new_object;
- data->flags |= ACPI_OBJECT_REPAIRED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
return (AE_OK);
}
@@ -441,7 +441,7 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_remove_null_elements
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* package_type - An acpi_return_package_types value
* obj_desc - A Package object
*
@@ -454,7 +454,7 @@ acpi_ns_repair_null_element(struct acpi_predefined_data *data,
*****************************************************************************/
void
-acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
+acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
u8 package_type,
union acpi_operand_object *obj_desc)
{
@@ -480,6 +480,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
case ACPI_PTYPE2_MIN:
case ACPI_PTYPE2_REV_FIXED:
case ACPI_PTYPE2_FIX_VAR:
+
break;
default:
@@ -511,7 +512,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
if (new_count < count) {
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Found and removed %u NULL elements\n",
- data->pathname, (count - new_count)));
+ info->full_pathname, (count - new_count)));
/* NULL terminate list and update the package count */
@@ -524,7 +525,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_wrap_with_package
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* original_object - Pointer to the object to repair.
* obj_desc_ptr - The new package object is returned here
*
@@ -545,7 +546,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
******************************************************************************/
acpi_status
-acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
+acpi_ns_wrap_with_package(struct acpi_evaluate_info *info,
union acpi_operand_object *original_object,
union acpi_operand_object **obj_desc_ptr)
{
@@ -566,12 +567,12 @@ acpi_ns_wrap_with_package(struct acpi_predefined_data *data,
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Wrapped %s with expected Package object\n",
- data->pathname,
+ info->full_pathname,
acpi_ut_get_object_type_name(original_object)));
/* Return the new object in the object pointer */
*obj_desc_ptr = pkg_obj_desc;
- data->flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
return (AE_OK);
}
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 149e9b9c2c1b..c84603ee83ae 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("nsrepair2")
* be repaired on a per-name basis.
*/
typedef
-acpi_status(*acpi_repair_function) (struct acpi_predefined_data *data,
+acpi_status(*acpi_repair_function) (struct acpi_evaluate_info * info,
union acpi_operand_object
**return_object_ptr);
@@ -71,45 +71,57 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
*node);
static acpi_status
-acpi_ns_repair_ALR(struct acpi_predefined_data *data,
+acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_repair_CID(struct acpi_predefined_data *data,
+acpi_ns_repair_CID(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_repair_FDE(struct acpi_predefined_data *data,
+acpi_ns_repair_CST(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_repair_HID(struct acpi_predefined_data *data,
+acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_repair_PSS(struct acpi_predefined_data *data,
+acpi_ns_repair_HID(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_repair_TSS(struct acpi_predefined_data *data,
+acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr);
static acpi_status
-acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
+acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
+ union acpi_operand_object **return_object_ptr);
+
+static acpi_status
+acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
+ union acpi_operand_object **return_object_ptr);
+
+static acpi_status
+acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
union acpi_operand_object *return_object,
+ u32 start_index,
u32 expected_count,
u32 sort_index,
u8 sort_direction, char *sort_key_name);
-static void
-acpi_ns_sort_list(union acpi_operand_object **elements,
- u32 count, u32 index, u8 sort_direction);
-
/* Values for sort_direction above */
#define ACPI_SORT_ASCENDING 0
#define ACPI_SORT_DESCENDING 1
+static void
+acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
+
+static void
+acpi_ns_sort_list(union acpi_operand_object **elements,
+ u32 count, u32 index, u8 sort_direction);
+
/*
* This table contains the names of the predefined methods for which we can
* perform more complex repairs.
@@ -118,9 +130,11 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
*
* _ALR: Sort the list ascending by ambient_illuminance
* _CID: Strings: uppercase all, remove any leading asterisk
+ * _CST: Sort the list ascending by C state type
* _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
* _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
* _HID: Strings: uppercase all, remove any leading asterisk
+ * _PRT: Fix reversed source_name and source_index
* _PSS: Sort the list descending by Power
* _TSS: Sort the list descending by Power
*
@@ -134,9 +148,11 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
{"_ALR", acpi_ns_repair_ALR},
{"_CID", acpi_ns_repair_CID},
+ {"_CST", acpi_ns_repair_CST},
{"_FDE", acpi_ns_repair_FDE},
{"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */
{"_HID", acpi_ns_repair_HID},
+ {"_PRT", acpi_ns_repair_PRT},
{"_PSS", acpi_ns_repair_PSS},
{"_TSS", acpi_ns_repair_TSS},
{{0, 0, 0, 0}, NULL} /* Table terminator */
@@ -150,7 +166,7 @@ static const struct acpi_repair_info acpi_ns_repairable_names[] = {
*
* FUNCTION: acpi_ns_complex_repairs
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* node - Namespace node for the method/object
* validate_status - Original status of earlier validation
* return_object_ptr - Pointer to the object returned from the
@@ -165,7 +181,7 @@ static const struct acpi_repair_info acpi_ns_repairable_names[] = {
*****************************************************************************/
acpi_status
-acpi_ns_complex_repairs(struct acpi_predefined_data *data,
+acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
struct acpi_namespace_node *node,
acpi_status validate_status,
union acpi_operand_object **return_object_ptr)
@@ -180,7 +196,7 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
return (validate_status);
}
- status = predefined->repair_function(data, return_object_ptr);
+ status = predefined->repair_function(info, return_object_ptr);
return (status);
}
@@ -219,7 +235,7 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
*
* FUNCTION: acpi_ns_repair_ALR
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -231,13 +247,13 @@ static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
*****************************************************************************/
static acpi_status
-acpi_ns_repair_ALR(struct acpi_predefined_data *data,
+acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
acpi_status status;
- status = acpi_ns_check_sorted_list(data, return_object, 2, 1,
+ status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
ACPI_SORT_ASCENDING,
"AmbientIlluminance");
@@ -248,7 +264,7 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_repair_FDE
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -262,7 +278,7 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data,
*****************************************************************************/
static acpi_status
-acpi_ns_repair_FDE(struct acpi_predefined_data *data,
+acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
@@ -285,8 +301,8 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
/* We can only repair if we have exactly 5 BYTEs */
if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
- data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Incorrect return buffer length %u, expected %u",
return_object->buffer.length,
ACPI_FDE_DWORD_BUFFER_SIZE));
@@ -316,10 +332,11 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s Expanded Byte Buffer to expected DWord Buffer\n",
- data->pathname));
+ info->full_pathname));
break;
default:
+
return (AE_AML_OPERAND_TYPE);
}
@@ -328,7 +345,7 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
acpi_ut_remove_reference(return_object);
*return_object_ptr = buffer_object;
- data->flags |= ACPI_OBJECT_REPAIRED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
return (AE_OK);
}
@@ -336,7 +353,7 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
*
* FUNCTION: acpi_ns_repair_CID
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -349,7 +366,7 @@ acpi_ns_repair_FDE(struct acpi_predefined_data *data,
*****************************************************************************/
static acpi_status
-acpi_ns_repair_CID(struct acpi_predefined_data *data,
+acpi_ns_repair_CID(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
acpi_status status;
@@ -362,7 +379,7 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
/* Check for _CID as a simple string */
if (return_object->common.type == ACPI_TYPE_STRING) {
- status = acpi_ns_repair_HID(data, return_object_ptr);
+ status = acpi_ns_repair_HID(info, return_object_ptr);
return (status);
}
@@ -379,7 +396,7 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
original_element = *element_ptr;
original_ref_count = original_element->common.reference_count;
- status = acpi_ns_repair_HID(data, element_ptr);
+ status = acpi_ns_repair_HID(info, element_ptr);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -404,9 +421,95 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
/******************************************************************************
*
+ * FUNCTION: acpi_ns_repair_CST
+ *
+ * PARAMETERS: info - Method execution information block
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _CST object:
+ * 1. Sort the list ascending by C state type
+ * 2. Ensure type cannot be zero
+ * 3. A sub-package count of zero means _CST is meaningless
+ * 4. Count must match the number of C state sub-packages
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_CST(struct acpi_evaluate_info *info,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ union acpi_operand_object **outer_elements;
+ u32 outer_element_count;
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ u8 removing;
+ u32 i;
+
+ ACPI_FUNCTION_NAME(ns_repair_CST);
+
+ /*
+ * Check if the C-state type values are proportional.
+ */
+ outer_element_count = return_object->package.count - 1;
+ i = 0;
+ while (i < outer_element_count) {
+ outer_elements = &return_object->package.elements[i + 1];
+ removing = FALSE;
+
+ if ((*outer_elements)->package.count == 0) {
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
+ "SubPackage[%u] - removing entry due to zero count",
+ i));
+ removing = TRUE;
+ goto remove_element;
+ }
+
+ obj_desc = (*outer_elements)->package.elements[1]; /* Index1 = Type */
+ if ((u32)obj_desc->integer.value == 0) {
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
+ "SubPackage[%u] - removing entry due to invalid Type(0)",
+ i));
+ removing = TRUE;
+ }
+
+ remove_element:
+ if (removing) {
+ acpi_ns_remove_element(return_object, i + 1);
+ outer_element_count--;
+ } else {
+ i++;
+ }
+ }
+
+ /* Update top-level package count, Type "Integer" checked elsewhere */
+
+ obj_desc = return_object->package.elements[0];
+ obj_desc->integer.value = outer_element_count;
+
+ /*
+ * Entries (subpackages) in the _CST Package must be sorted by the
+ * C-state type, in ascending order.
+ */
+ status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
+ ACPI_SORT_ASCENDING, "C-State Type");
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ return (AE_OK);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_ns_repair_HID
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -418,7 +521,7 @@ acpi_ns_repair_CID(struct acpi_predefined_data *data,
*****************************************************************************/
static acpi_status
-acpi_ns_repair_HID(struct acpi_predefined_data *data,
+acpi_ns_repair_HID(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
@@ -435,12 +538,13 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
}
if (return_object->string.length == 0) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"Invalid zero-length _HID or _CID string"));
/* Return AE_OK anyway, let driver handle it */
- data->flags |= ACPI_OBJECT_REPAIRED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
return (AE_OK);
}
@@ -464,7 +568,7 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Removed invalid leading asterisk\n",
- data->pathname));
+ info->full_pathname));
}
/*
@@ -486,53 +590,69 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data,
/******************************************************************************
*
- * FUNCTION: acpi_ns_repair_TSS
+ * FUNCTION: acpi_ns_repair_PRT
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
* RETURN: Status. AE_OK if object is OK or was repaired successfully
*
- * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
- * descending by the power dissipation values.
+ * DESCRIPTION: Repair for the _PRT object. If necessary, fix reversed
+ * source_name and source_index field, a common BIOS bug.
*
*****************************************************************************/
static acpi_status
-acpi_ns_repair_TSS(struct acpi_predefined_data *data,
+acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
- union acpi_operand_object *return_object = *return_object_ptr;
- acpi_status status;
- struct acpi_namespace_node *node;
+ union acpi_operand_object *package_object = *return_object_ptr;
+ union acpi_operand_object **top_object_list;
+ union acpi_operand_object **sub_object_list;
+ union acpi_operand_object *obj_desc;
+ u32 element_count;
+ u32 index;
- /*
- * We can only sort the _TSS return package if there is no _PSS in the
- * same scope. This is because if _PSS is present, the ACPI specification
- * dictates that the _TSS Power Dissipation field is to be ignored, and
- * therefore some BIOSs leave garbage values in the _TSS Power field(s).
- * In this case, it is best to just return the _TSS package as-is.
- * (May, 2011)
- */
- status =
- acpi_ns_get_node(data->node, "^_PSS", ACPI_NS_NO_UPSEARCH, &node);
- if (ACPI_SUCCESS(status)) {
- return (AE_OK);
- }
+ /* Each element in the _PRT package is a subpackage */
- status = acpi_ns_check_sorted_list(data, return_object, 5, 1,
- ACPI_SORT_DESCENDING,
- "PowerDissipation");
+ top_object_list = package_object->package.elements;
+ element_count = package_object->package.count;
- return (status);
+ for (index = 0; index < element_count; index++) {
+ sub_object_list = (*top_object_list)->package.elements;
+
+ /*
+ * If the BIOS has erroneously reversed the _PRT source_name (index 2)
+ * and the source_index (index 3), fix it. _PRT is important enough to
+ * workaround this BIOS error. This also provides compatibility with
+ * other ACPI implementations.
+ */
+ obj_desc = sub_object_list[3];
+ if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
+ sub_object_list[3] = sub_object_list[2];
+ sub_object_list[2] = obj_desc;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
+
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
+ "PRT[%X]: Fixed reversed SourceName and SourceIndex",
+ index));
+ }
+
+ /* Point to the next union acpi_operand_object in the top level package */
+
+ top_object_list++;
+ }
+
+ return (AE_OK);
}
/******************************************************************************
*
* FUNCTION: acpi_ns_repair_PSS
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object_ptr - Pointer to the object returned from the
* evaluation of a method or object
*
@@ -546,7 +666,7 @@ acpi_ns_repair_TSS(struct acpi_predefined_data *data,
*****************************************************************************/
static acpi_status
-acpi_ns_repair_PSS(struct acpi_predefined_data *data,
+acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
union acpi_operand_object **return_object_ptr)
{
union acpi_operand_object *return_object = *return_object_ptr;
@@ -564,7 +684,7 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
* incorrectly sorted, sort it. We sort by cpu_frequency, since this
* should be proportional to the power.
*/
- status = acpi_ns_check_sorted_list(data, return_object, 6, 0,
+ status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
ACPI_SORT_DESCENDING,
"CpuFrequency");
if (ACPI_FAILURE(status)) {
@@ -584,8 +704,8 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
obj_desc = elements[1]; /* Index1 = power_dissipation */
if ((u32) obj_desc->integer.value > previous_value) {
- ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
- data->node_flags,
+ ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
+ info->node_flags,
"SubPackage[%u,%u] - suspicious power dissipation values",
i - 1, i));
}
@@ -599,10 +719,55 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
/******************************************************************************
*
+ * FUNCTION: acpi_ns_repair_TSS
+ *
+ * PARAMETERS: info - Method execution information block
+ * return_object_ptr - Pointer to the object returned from the
+ * evaluation of a method or object
+ *
+ * RETURN: Status. AE_OK if object is OK or was repaired successfully
+ *
+ * DESCRIPTION: Repair for the _TSS object. If necessary, sort the object list
+ * descending by the power dissipation values.
+ *
+ *****************************************************************************/
+
+static acpi_status
+acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
+ union acpi_operand_object **return_object_ptr)
+{
+ union acpi_operand_object *return_object = *return_object_ptr;
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+ /*
+ * We can only sort the _TSS return package if there is no _PSS in the
+ * same scope. This is because if _PSS is present, the ACPI specification
+ * dictates that the _TSS Power Dissipation field is to be ignored, and
+ * therefore some BIOSs leave garbage values in the _TSS Power field(s).
+ * In this case, it is best to just return the _TSS package as-is.
+ * (May, 2011)
+ */
+ status = acpi_ns_get_node(info->node, "^_PSS",
+ ACPI_NS_NO_UPSEARCH, &node);
+ if (ACPI_SUCCESS(status)) {
+ return (AE_OK);
+ }
+
+ status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
+ ACPI_SORT_DESCENDING,
+ "PowerDissipation");
+
+ return (status);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_ns_check_sorted_list
*
- * PARAMETERS: data - Pointer to validation data structure
+ * PARAMETERS: info - Method execution information block
* return_object - Pointer to the top-level returned object
+ * start_index - Index of the first sub-package
* expected_count - Minimum length of each sub-package
* sort_index - Sub-package entry to sort on
* sort_direction - Ascending or descending
@@ -617,8 +782,9 @@ acpi_ns_repair_PSS(struct acpi_predefined_data *data,
*****************************************************************************/
static acpi_status
-acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
+acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
union acpi_operand_object *return_object,
+ u32 start_index,
u32 expected_count,
u32 sort_index,
u8 sort_direction, char *sort_key_name)
@@ -643,12 +809,14 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
* Any NULL elements should have been removed by earlier call
* to acpi_ns_remove_null_elements.
*/
- outer_elements = return_object->package.elements;
outer_element_count = return_object->package.count;
- if (!outer_element_count) {
+ if (!outer_element_count || start_index >= outer_element_count) {
return (AE_AML_PACKAGE_LIMIT);
}
+ outer_elements = &return_object->package.elements[start_index];
+ outer_element_count -= start_index;
+
previous_value = 0;
if (sort_direction == ACPI_SORT_DESCENDING) {
previous_value = ACPI_UINT32_MAX;
@@ -685,15 +853,16 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
(obj_desc->integer.value < previous_value)) ||
((sort_direction == ACPI_SORT_DESCENDING) &&
(obj_desc->integer.value > previous_value))) {
- acpi_ns_sort_list(return_object->package.elements,
+ acpi_ns_sort_list(&return_object->package.
+ elements[start_index],
outer_element_count, sort_index,
sort_direction);
- data->flags |= ACPI_OBJECT_REPAIRED;
+ info->return_flags |= ACPI_OBJECT_REPAIRED;
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
"%s: Repaired unsorted list - now sorted by %s\n",
- data->pathname, sort_key_name));
+ info->full_pathname, sort_key_name));
return (AE_OK);
}
@@ -752,3 +921,52 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
}
}
}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ns_remove_element
+ *
+ * PARAMETERS: obj_desc - Package object element list
+ * index - Index of element to remove
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Remove the requested element of a package and delete it.
+ *
+ *****************************************************************************/
+
+static void
+acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
+{
+ union acpi_operand_object **source;
+ union acpi_operand_object **dest;
+ u32 count;
+ u32 new_count;
+ u32 i;
+
+ ACPI_FUNCTION_NAME(ns_remove_element);
+
+ count = obj_desc->package.count;
+ new_count = count - 1;
+
+ source = obj_desc->package.elements;
+ dest = source;
+
+ /* Examine all elements of the package object, remove matched index */
+
+ for (i = 0; i < count; i++) {
+ if (i == index) {
+ acpi_ut_remove_reference(*source); /* Remove one ref for being in pkg */
+ acpi_ut_remove_reference(*source);
+ } else {
+ *dest = *source;
+ dest++;
+ }
+ source++;
+ }
+
+ /* NULL terminate list and update the package count */
+
+ *dest = NULL;
+ obj_desc->package.count = new_count;
+}
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 2808586fad30..08c0b5beec88 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -419,10 +419,12 @@ acpi_ns_externalize_name(u32 internal_name_length,
switch (internal_name[0]) {
case AML_ROOT_PREFIX:
+
prefix_length = 1;
break;
case AML_PARENT_PREFIX:
+
for (i = 0; i < internal_name_length; i++) {
if (ACPI_IS_PARENT_PREFIX(internal_name[i])) {
prefix_length = i + 1;
@@ -438,6 +440,7 @@ acpi_ns_externalize_name(u32 internal_name_length,
break;
default:
+
break;
}
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index fc69949151bb..f553cfdb71dd 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -187,8 +187,6 @@ acpi_evaluate_object(acpi_handle handle,
return_ACPI_STATUS(AE_NO_MEMORY);
}
- info->pathname = pathname;
-
/* Convert and validate the device handle */
info->prefix_node = acpi_ns_validate_handle(handle);
@@ -198,17 +196,64 @@ acpi_evaluate_object(acpi_handle handle,
}
/*
- * If there are parameters to be passed to a control method, the external
- * objects must all be converted to internal objects
+ * Get the actual namespace node for the target object.
+ * Handles these cases:
+ *
+ * 1) Null node, valid pathname from root (absolute path)
+ * 2) Node and valid pathname (path relative to Node)
+ * 3) Node, Null pathname
+ */
+ if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) {
+
+ /* The path is fully qualified, just evaluate by name */
+
+ info->prefix_node = NULL;
+ } else if (!handle) {
+ /*
+ * A handle is optional iff a fully qualified pathname is specified.
+ * Since we've already handled fully qualified names above, this is
+ * an error.
+ */
+ if (!pathname) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Both Handle and Pathname are NULL"));
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Null Handle with relative pathname [%s]",
+ pathname));
+ }
+
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ info->relative_pathname = pathname;
+
+ /*
+ * Convert all external objects passed as arguments to the
+ * internal version(s).
*/
if (external_params && external_params->count) {
+ info->param_count = (u16)external_params->count;
+
+ /* Warn on impossible argument count */
+
+ if (info->param_count > ACPI_METHOD_NUM_ARGS) {
+ ACPI_WARN_PREDEFINED((AE_INFO, pathname,
+ ACPI_WARN_ALWAYS,
+ "Excess arguments (%u) - using only %u",
+ info->param_count,
+ ACPI_METHOD_NUM_ARGS));
+
+ info->param_count = ACPI_METHOD_NUM_ARGS;
+ }
+
/*
* Allocate a new parameter block for the internal objects
* Add 1 to count to allow for null terminated internal list
*/
- info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size)
- external_params->
- count +
+ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size) info->
+ param_count +
1) * sizeof(void *));
if (!info->parameters) {
status = AE_NO_MEMORY;
@@ -217,7 +262,7 @@ acpi_evaluate_object(acpi_handle handle,
/* Convert each external object in the list to an internal object */
- for (i = 0; i < external_params->count; i++) {
+ for (i = 0; i < info->param_count; i++) {
status =
acpi_ut_copy_eobject_to_iobject(&external_params->
pointer[i],
@@ -227,43 +272,96 @@ acpi_evaluate_object(acpi_handle handle,
goto cleanup;
}
}
- info->parameters[external_params->count] = NULL;
+
+ info->parameters[info->param_count] = NULL;
}
+#if 0
+
/*
- * Three major cases:
- * 1) Fully qualified pathname
- * 2) No handle, not fully qualified pathname (error)
- * 3) Valid handle
+ * Begin incoming argument count analysis. Check for too few args
+ * and too many args.
*/
- if ((pathname) && (ACPI_IS_ROOT_PREFIX(pathname[0]))) {
- /* The path is fully qualified, just evaluate by name */
+ switch (acpi_ns_get_type(info->node)) {
+ case ACPI_TYPE_METHOD:
+
+ /* Check incoming argument count against the method definition */
+
+ if (info->obj_desc->method.param_count > info->param_count) {
+ ACPI_ERROR((AE_INFO,
+ "Insufficient arguments (%u) - %u are required",
+ info->param_count,
+ info->obj_desc->method.param_count));
+
+ status = AE_MISSING_ARGUMENTS;
+ goto cleanup;
+ }
+
+ else if (info->obj_desc->method.param_count < info->param_count) {
+ ACPI_WARNING((AE_INFO,
+ "Excess arguments (%u) - only %u are required",
+ info->param_count,
+ info->obj_desc->method.param_count));
+
+ /* Just pass the required number of arguments */
+
+ info->param_count = info->obj_desc->method.param_count;
+ }
- info->prefix_node = NULL;
- status = acpi_ns_evaluate(info);
- } else if (!handle) {
/*
- * A handle is optional iff a fully qualified pathname is specified.
- * Since we've already handled fully qualified names above, this is
- * an error
+ * Any incoming external objects to be passed as arguments to the
+ * method must be converted to internal objects
*/
- if (!pathname) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Both Handle and Pathname are NULL"));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Null Handle with relative pathname [%s]",
- pathname));
+ if (info->param_count) {
+ /*
+ * Allocate a new parameter block for the internal objects
+ * Add 1 to count to allow for null terminated internal list
+ */
+ info->parameters = ACPI_ALLOCATE_ZEROED(((acpi_size)
+ info->
+ param_count +
+ 1) *
+ sizeof(void *));
+ if (!info->parameters) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Convert each external object in the list to an internal object */
+
+ for (i = 0; i < info->param_count; i++) {
+ status =
+ acpi_ut_copy_eobject_to_iobject
+ (&external_params->pointer[i],
+ &info->parameters[i]);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+
+ info->parameters[info->param_count] = NULL;
}
+ break;
- status = AE_BAD_PARAMETER;
- } else {
- /* We have a namespace a node and a possible relative path */
+ default:
+
+ /* Warn if arguments passed to an object that is not a method */
- status = acpi_ns_evaluate(info);
+ if (info->param_count) {
+ ACPI_WARNING((AE_INFO,
+ "%u arguments were passed to a non-method ACPI object",
+ info->param_count));
+ }
+ break;
}
+#endif
+
+ /* Now we can evaluate the object */
+
+ status = acpi_ns_evaluate(info);
+
/*
* If we are expecting a return value, and all went well above,
* copy the return value to an external object.
@@ -413,6 +511,7 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info)
break;
default:
+
return;
}
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 9f25a3d4e992..91a5a69db80c 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -629,24 +629,28 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state
switch (opcode) {
case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
+
buffer_length =
ACPI_GET8(parser_state->aml);
parser_state->aml += 1;
break;
case AML_WORD_OP: /* AML_WORDDATA_ARG */
+
buffer_length =
ACPI_GET16(parser_state->aml);
parser_state->aml += 2;
break;
case AML_DWORD_OP: /* AML_DWORDATA_ARG */
+
buffer_length =
ACPI_GET32(parser_state->aml);
parser_state->aml += 4;
break;
default:
+
buffer_length = 0;
break;
}
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 63c455447481..065b44ae538f 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -164,7 +164,6 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
case AML_IF_OP:
case AML_ELSE_OP:
case AML_WHILE_OP:
-
/*
* Currently supported module-level opcodes are:
* IF/ELSE/WHILE. These appear to be the most common,
@@ -289,6 +288,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
default:
/* No action for all other opcodes */
+
break;
}
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
index 12c4028002b1..95dc608a66a8 100644
--- a/drivers/acpi/acpica/psobject.c
+++ b/drivers/acpi/acpica/psobject.c
@@ -402,6 +402,7 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
switch (status) {
case AE_OK:
+
break;
case AE_CTRL_TRANSFER:
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index abc4c48b2edd..86198a9139b5 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -176,10 +176,10 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
switch (parent_info->class) {
case AML_CLASS_CONTROL:
+
break;
case AML_CLASS_CREATE:
-
/*
* These opcodes contain term_arg operands. The current
* op must be replaced by a placeholder return op
@@ -192,7 +192,6 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
break;
case AML_CLASS_NAMED_OBJECT:
-
/*
* These opcodes contain term_arg operands. The current
* op must be replaced by a placeholder return op
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index c1934bf04f0a..877dc0de8df3 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -308,7 +308,9 @@ union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
break;
default:
+
/* All others have no children */
+
break;
}
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index f68254268965..11b99ab20bb3 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -125,7 +125,7 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info)
}
if ((!acpi_gbl_trace_method_name) ||
- (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) {
+ (acpi_gbl_trace_method_name != info->node->name.integer)) {
goto exit;
}
@@ -170,7 +170,7 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
}
if ((!acpi_gbl_trace_method_name) ||
- (acpi_gbl_trace_method_name != info->resolved_node->name.integer)) {
+ (acpi_gbl_trace_method_name != info->node->name.integer)) {
goto exit;
}
@@ -226,15 +226,14 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
/* Validate the Info and method Node */
- if (!info || !info->resolved_node) {
+ if (!info || !info->node) {
return_ACPI_STATUS(AE_NULL_ENTRY);
}
/* Init for new method, wait on concurrency semaphore */
status =
- acpi_ds_begin_method_execution(info->resolved_node, info->obj_desc,
- NULL);
+ acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -253,8 +252,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
- info->resolved_node->name.ascii, info->resolved_node,
- info->obj_desc));
+ info->node->name.ascii, info->node, info->obj_desc));
/* Create and init a Root Node */
@@ -275,7 +273,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
goto cleanup;
}
- status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+ status = acpi_ds_init_aml_walk(walk_state, op, info->node,
info->obj_desc->method.aml_start,
info->obj_desc->method.aml_length, info,
info->pass_number);
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 72077fa1eea5..b62a0f4f4f9b 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -352,6 +352,7 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed)
break;
default:
+
break;
}
@@ -539,6 +540,7 @@ acpi_rs_get_list_length(u8 * aml_buffer,
break;
default:
+
break;
}
@@ -650,8 +652,9 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
name_found = FALSE;
- for (table_index = 0; table_index < 4 && !name_found;
- table_index++) {
+ for (table_index = 0;
+ table_index < package_element->package.count
+ && !name_found; table_index++) {
if (*sub_object_list && /* Null object allowed */
((ACPI_TYPE_STRING ==
(*sub_object_list)->common.type) ||
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index f8b55b426c9d..65f3e1c5b598 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -273,17 +273,6 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
*/
user_prt->length = (sizeof(struct acpi_pci_routing_table) - 4);
- /* Each element of the top-level package must also be a package */
-
- if ((*top_object_list)->common.type != ACPI_TYPE_PACKAGE) {
- ACPI_ERROR((AE_INFO,
- "(PRT[%u]) Need sub-package, found %s",
- index,
- acpi_ut_get_object_type_name
- (*top_object_list)));
- return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
- }
-
/* Each sub-package must be of length 4 */
if ((*top_object_list)->package.count != 4) {
@@ -327,22 +316,6 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
user_prt->pin = (u32) obj_desc->integer.value;
/*
- * If the BIOS has erroneously reversed the _PRT source_name (index 2)
- * and the source_index (index 3), fix it. _PRT is important enough to
- * workaround this BIOS error. This also provides compatibility with
- * other ACPI implementations.
- */
- obj_desc = sub_object_list[3];
- if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
- sub_object_list[3] = sub_object_list[2];
- sub_object_list[2] = obj_desc;
-
- ACPI_WARNING((AE_INFO,
- "(PRT[%X].Source) SourceName and SourceIndex are reversed, fixed",
- index));
- }
-
- /*
* 3) Third subobject: Dereference the PRT.source_name
* The name may be unresolved (slack mode), so allow a null object
*/
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index b5fc0db2e87b..8a2d4986b0aa 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -120,17 +120,20 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
/* Strings */
case ACPI_RSD_LITERAL:
+
acpi_rs_out_string(name,
ACPI_CAST_PTR(char, table->pointer));
break;
case ACPI_RSD_STRING:
+
acpi_rs_out_string(name, ACPI_CAST_PTR(char, target));
break;
/* Data items, 8/16/32/64 bit */
case ACPI_RSD_UINT8:
+
if (table->pointer) {
acpi_rs_out_string(name, ACPI_CAST_PTR(char,
table->
@@ -142,20 +145,24 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
break;
case ACPI_RSD_UINT16:
+
acpi_rs_out_integer16(name, ACPI_GET16(target));
break;
case ACPI_RSD_UINT32:
+
acpi_rs_out_integer32(name, ACPI_GET32(target));
break;
case ACPI_RSD_UINT64:
+
acpi_rs_out_integer64(name, ACPI_GET64(target));
break;
/* Flags: 1-bit and 2-bit flags supported */
case ACPI_RSD_1BITFLAG:
+
acpi_rs_out_string(name, ACPI_CAST_PTR(char,
table->
pointer[*target &
@@ -163,6 +170,7 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
break;
case ACPI_RSD_2BITFLAG:
+
acpi_rs_out_string(name, ACPI_CAST_PTR(char,
table->
pointer[*target &
@@ -170,6 +178,7 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
break;
case ACPI_RSD_3BITFLAG:
+
acpi_rs_out_string(name, ACPI_CAST_PTR(char,
table->
pointer[*target &
@@ -258,6 +267,7 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table)
break;
default:
+
acpi_os_printf("**** Invalid table opcode [%X] ****\n",
table->opcode);
return;
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index d5bf05a96096..80d12994e0d0 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -194,7 +194,6 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
break;
case ACPI_RSC_COUNT_GPIO_RES:
-
/*
* Vendor data is optional (length/offset may both be zero)
* Examine vendor data length field first
@@ -410,12 +409,14 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource,
*/
switch (info->resource_offset) {
case ACPI_RSC_COMPARE_AML_LENGTH:
+
if (aml_resource_length != info->value) {
goto exit;
}
break;
case ACPI_RSC_COMPARE_VALUE:
+
if (ACPI_GET8(source) != info->value) {
goto exit;
}
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index a44953c6f75d..480b6b40c5ea 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -147,6 +147,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
case ACPI_RSC_MOVE_GPIO_RES:
case ACPI_RSC_MOVE_SERIAL_VEN:
case ACPI_RSC_MOVE_SERIAL_RES:
+
ACPI_MEMCPY(destination, source, item_count);
return;
@@ -157,21 +158,25 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type)
*/
case ACPI_RSC_MOVE16:
case ACPI_RSC_MOVE_GPIO_PIN:
+
ACPI_MOVE_16_TO_16(&ACPI_CAST_PTR(u16, destination)[i],
&ACPI_CAST_PTR(u16, source)[i]);
break;
case ACPI_RSC_MOVE32:
+
ACPI_MOVE_32_TO_32(&ACPI_CAST_PTR(u32, destination)[i],
&ACPI_CAST_PTR(u32, source)[i]);
break;
case ACPI_RSC_MOVE64:
+
ACPI_MOVE_64_TO_64(&ACPI_CAST_PTR(u64, destination)[i],
&ACPI_CAST_PTR(u64, source)[i]);
break;
default:
+
return;
}
}
@@ -736,7 +741,7 @@ acpi_rs_set_srs_method_data(struct acpi_namespace_node *node,
}
info->prefix_node = node;
- info->pathname = METHOD_NAME__SRS;
+ info->relative_pathname = METHOD_NAME__SRS;
info->parameters = args;
info->flags = ACPI_IGNORE_RETURN_VALUE;
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index c0e5d2d3ce67..94e3517554f9 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -402,6 +402,7 @@ acpi_resource_to_address64(struct acpi_resource *resource,
break;
default:
+
return (AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index e57cd38004e3..42a13c0d7015 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -141,8 +141,7 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
ACPI_BIOS_ERROR((AE_INFO,
"Table has invalid signature [%4.4s] (0x%8.8X), "
"must be SSDT or OEMx",
- acpi_ut_valid_acpi_name(*(u32 *)table_desc->
- pointer->
+ acpi_ut_valid_acpi_name(table_desc->pointer->
signature) ?
table_desc->pointer->signature : "????",
*(u32 *)table_desc->pointer->signature));
@@ -471,15 +470,19 @@ void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
}
switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
case ACPI_TABLE_ORIGIN_MAPPED:
+
acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
break;
+
case ACPI_TABLE_ORIGIN_ALLOCATED:
+
ACPI_FREE(table_desc->pointer);
break;
/* Not mapped or allocated, there is nothing we can do */
default:
+
return;
}
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
new file mode 100644
index 000000000000..dc963f823d2c
--- /dev/null
+++ b/drivers/acpi/acpica/tbprint.c
@@ -0,0 +1,237 @@
+/******************************************************************************
+ *
+ * Module Name: tbprint - Table output utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "actables.h"
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbprint")
+
+/* Local prototypes */
+static void acpi_tb_fix_string(char *string, acpi_size length);
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+ struct acpi_table_header *header);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_fix_string
+ *
+ * PARAMETERS: string - String to be repaired
+ * length - Maximum length
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
+ * with a question mark '?'.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_fix_string(char *string, acpi_size length)
+{
+
+ while (length && *string) {
+ if (!ACPI_IS_PRINT(*string)) {
+ *string = '?';
+ }
+ string++;
+ length--;
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_cleanup_table_header
+ *
+ * PARAMETERS: out_header - Where the cleaned header is returned
+ * header - Input ACPI table header
+ *
+ * RETURN: Returns the cleaned header in out_header
+ *
+ * DESCRIPTION: Copy the table header and ensure that all "string" fields in
+ * the header consist of printable characters.
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
+ struct acpi_table_header *header)
+{
+
+ ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header));
+
+ acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE);
+ acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE);
+ acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+ acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_print_table_header
+ *
+ * PARAMETERS: address - Table physical address
+ * header - Table header
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+ struct acpi_table_header *header)
+{
+ struct acpi_table_header local_header;
+
+ /*
+ * The reason that the Address is cast to a void pointer is so that we
+ * can use %p which will work properly on both 32-bit and 64-bit hosts.
+ */
+ if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
+
+ /* FACS only has signature and length fields */
+
+ ACPI_INFO((AE_INFO, "%4.4s %p %05X",
+ header->signature, ACPI_CAST_PTR(void, address),
+ header->length));
+ } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
+
+ /* RSDP has no common fields */
+
+ ACPI_MEMCPY(local_header.oem_id,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->oem_id, ACPI_OEM_ID_SIZE);
+ acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
+
+ ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
+ ACPI_CAST_PTR(void, address),
+ (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+ revision >
+ 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->length : 20,
+ ACPI_CAST_PTR(struct acpi_table_rsdp,
+ header)->revision,
+ local_header.oem_id));
+ } else {
+ /* Standard ACPI table with full common header */
+
+ acpi_tb_cleanup_table_header(&local_header, header);
+
+ ACPI_INFO((AE_INFO,
+ "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
+ local_header.signature, ACPI_CAST_PTR(void, address),
+ local_header.length, local_header.revision,
+ local_header.oem_id, local_header.oem_table_id,
+ local_header.oem_revision,
+ local_header.asl_compiler_id,
+ local_header.asl_compiler_revision));
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_checksum
+ *
+ * PARAMETERS: table - ACPI table to verify
+ * length - Length of entire table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ * exception on bad checksum.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
+{
+ u8 checksum;
+
+ /* Compute the checksum on the table */
+
+ checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
+
+ /* Checksum ok? (should be zero) */
+
+ if (checksum) {
+ ACPI_BIOS_WARNING((AE_INFO,
+ "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
+ "should be 0x%2.2X",
+ table->signature, table->checksum,
+ (u8)(table->checksum - checksum)));
+
+#if (ACPI_CHECKSUM_ABORT)
+ return (AE_BAD_CHECKSUM);
+#endif
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_checksum
+ *
+ * PARAMETERS: buffer - Pointer to memory region to be checked
+ * length - Length of this memory region
+ *
+ * RETURN: Checksum (u8)
+ *
+ * DESCRIPTION: Calculates circular checksum of memory region.
+ *
+ ******************************************************************************/
+
+u8 acpi_tb_checksum(u8 *buffer, u32 length)
+{
+ u8 sum = 0;
+ u8 *end = buffer + length;
+
+ while (buffer < end) {
+ sum = (u8)(sum + *(buffer++));
+ }
+
+ return (sum);
+}
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index ce3d5db39a9c..bffdfc7b8322 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Module Name: tbutils - table utilities
+ * Module Name: tbutils - ACPI Table utilities
*
*****************************************************************************/
@@ -49,12 +49,6 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
-static void acpi_tb_fix_string(char *string, acpi_size length);
-
-static void
-acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
- struct acpi_table_header *header);
-
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
@@ -176,189 +170,6 @@ u8 acpi_tb_tables_loaded(void)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_fix_string
- *
- * PARAMETERS: string - String to be repaired
- * length - Maximum length
- *
- * RETURN: None
- *
- * DESCRIPTION: Replace every non-printable or non-ascii byte in the string
- * with a question mark '?'.
- *
- ******************************************************************************/
-
-static void acpi_tb_fix_string(char *string, acpi_size length)
-{
-
- while (length && *string) {
- if (!ACPI_IS_PRINT(*string)) {
- *string = '?';
- }
- string++;
- length--;
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_cleanup_table_header
- *
- * PARAMETERS: out_header - Where the cleaned header is returned
- * header - Input ACPI table header
- *
- * RETURN: Returns the cleaned header in out_header
- *
- * DESCRIPTION: Copy the table header and ensure that all "string" fields in
- * the header consist of printable characters.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_cleanup_table_header(struct acpi_table_header *out_header,
- struct acpi_table_header *header)
-{
-
- ACPI_MEMCPY(out_header, header, sizeof(struct acpi_table_header));
-
- acpi_tb_fix_string(out_header->signature, ACPI_NAME_SIZE);
- acpi_tb_fix_string(out_header->oem_id, ACPI_OEM_ID_SIZE);
- acpi_tb_fix_string(out_header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
- acpi_tb_fix_string(out_header->asl_compiler_id, ACPI_NAME_SIZE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_print_table_header
- *
- * PARAMETERS: address - Table physical address
- * header - Table header
- *
- * RETURN: None
- *
- * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
- *
- ******************************************************************************/
-
-void
-acpi_tb_print_table_header(acpi_physical_address address,
- struct acpi_table_header *header)
-{
- struct acpi_table_header local_header;
-
- /*
- * The reason that the Address is cast to a void pointer is so that we
- * can use %p which will work properly on both 32-bit and 64-bit hosts.
- */
- if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
-
- /* FACS only has signature and length fields */
-
- ACPI_INFO((AE_INFO, "%4.4s %p %05X",
- header->signature, ACPI_CAST_PTR(void, address),
- header->length));
- } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
-
- /* RSDP has no common fields */
-
- ACPI_MEMCPY(local_header.oem_id,
- ACPI_CAST_PTR(struct acpi_table_rsdp,
- header)->oem_id, ACPI_OEM_ID_SIZE);
- acpi_tb_fix_string(local_header.oem_id, ACPI_OEM_ID_SIZE);
-
- ACPI_INFO((AE_INFO, "RSDP %p %05X (v%.2d %6.6s)",
- ACPI_CAST_PTR (void, address),
- (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
- revision >
- 0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
- header)->length : 20,
- ACPI_CAST_PTR(struct acpi_table_rsdp,
- header)->revision,
- local_header.oem_id));
- } else {
- /* Standard ACPI table with full common header */
-
- acpi_tb_cleanup_table_header(&local_header, header);
-
- ACPI_INFO((AE_INFO,
- "%4.4s %p %05X (v%.2d %6.6s %8.8s %08X %4.4s %08X)",
- local_header.signature, ACPI_CAST_PTR(void, address),
- local_header.length, local_header.revision,
- local_header.oem_id, local_header.oem_table_id,
- local_header.oem_revision,
- local_header.asl_compiler_id,
- local_header.asl_compiler_revision));
-
- }
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_validate_checksum
- *
- * PARAMETERS: table - ACPI table to verify
- * length - Length of entire table
- *
- * RETURN: Status
- *
- * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
- * exception on bad checksum.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
-{
- u8 checksum;
-
- /* Compute the checksum on the table */
-
- checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
-
- /* Checksum ok? (should be zero) */
-
- if (checksum) {
- ACPI_BIOS_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - 0x%2.2X, "
- "should be 0x%2.2X",
- table->signature, table->checksum,
- (u8)(table->checksum - checksum)));
-
-#if (ACPI_CHECKSUM_ABORT)
-
- return (AE_BAD_CHECKSUM);
-#endif
- }
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_checksum
- *
- * PARAMETERS: buffer - Pointer to memory region to be checked
- * length - Length of this memory region
- *
- * RETURN: Checksum (u8)
- *
- * DESCRIPTION: Calculates circular checksum of memory region.
- *
- ******************************************************************************/
-
-u8 acpi_tb_checksum(u8 *buffer, u32 length)
-{
- u8 sum = 0;
- u8 *end = buffer + length;
-
- while (buffer < end) {
- sum = (u8) (sum + *(buffer++));
- }
-
- return (sum);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_tb_check_dsdt_header
*
* PARAMETERS: None
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 67e046ec8f0a..0ba9e328d5d7 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -53,8 +53,6 @@ ACPI_MODULE_NAME("tbxfload")
/* Local prototypes */
static acpi_status acpi_tb_load_namespace(void);
-static int no_auto_ssdt;
-
/*******************************************************************************
*
* FUNCTION: acpi_load_tables
@@ -180,8 +178,16 @@ static acpi_status acpi_tb_load_namespace(void)
continue;
}
- if (no_auto_ssdt) {
- printk(KERN_WARNING "ACPI: SSDT ignored due to \"acpi_no_auto_ssdt\"\n");
+ /*
+ * Optionally do not load any SSDTs from the RSDT/XSDT. This can
+ * be useful for debugging ACPI problems on some machines.
+ */
+ if (acpi_gbl_disable_ssdt_table_load) {
+ ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p",
+ acpi_gbl_root_table_list.tables[i].signature.
+ ascii, ACPI_CAST_PTR(void,
+ acpi_gbl_root_table_list.
+ tables[i].address)));
continue;
}
@@ -376,14 +382,3 @@ acpi_status acpi_unload_parent_table(acpi_handle object)
}
ACPI_EXPORT_SYMBOL(acpi_unload_parent_table)
-
-static int __init acpi_no_auto_ssdt_setup(char *s) {
-
- printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
-
- no_auto_ssdt = 1;
-
- return 1;
-}
-
-__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c
new file mode 100644
index 000000000000..11fde93be120
--- /dev/null
+++ b/drivers/acpi/acpica/utbuffer.c
@@ -0,0 +1,201 @@
+/******************************************************************************
+ *
+ * Module Name: utbuffer - Buffer dump routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("utbuffer")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_dump_buffer
+ *
+ * PARAMETERS: buffer - Buffer to dump
+ * count - Amount to dump, in bytes
+ * display - BYTE, WORD, DWORD, or QWORD display:
+ * DB_BYTE_DISPLAY
+ * DB_WORD_DISPLAY
+ * DB_DWORD_DISPLAY
+ * DB_QWORD_DISPLAY
+ * base_offset - Beginning buffer offset (display only)
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ******************************************************************************/
+void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
+{
+ u32 i = 0;
+ u32 j;
+ u32 temp32;
+ u8 buf_char;
+
+ if (!buffer) {
+ acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
+ return;
+ }
+
+ if ((count < 4) || (count & 0x01)) {
+ display = DB_BYTE_DISPLAY;
+ }
+
+ /* Nasty little dump buffer routine! */
+
+ while (i < count) {
+
+ /* Print current offset */
+
+ acpi_os_printf("%6.4X: ", (base_offset + i));
+
+ /* Print 16 hex chars */
+
+ for (j = 0; j < 16;) {
+ if (i + j >= count) {
+
+ /* Dump fill spaces */
+
+ acpi_os_printf("%*s", ((display * 2) + 1), " ");
+ j += display;
+ continue;
+ }
+
+ switch (display) {
+ case DB_BYTE_DISPLAY:
+ default: /* Default is BYTE display */
+
+ acpi_os_printf("%02X ",
+ buffer[(acpi_size) i + j]);
+ break;
+
+ case DB_WORD_DISPLAY:
+
+ ACPI_MOVE_16_TO_32(&temp32,
+ &buffer[(acpi_size) i + j]);
+ acpi_os_printf("%04X ", temp32);
+ break;
+
+ case DB_DWORD_DISPLAY:
+
+ ACPI_MOVE_32_TO_32(&temp32,
+ &buffer[(acpi_size) i + j]);
+ acpi_os_printf("%08X ", temp32);
+ break;
+
+ case DB_QWORD_DISPLAY:
+
+ ACPI_MOVE_32_TO_32(&temp32,
+ &buffer[(acpi_size) i + j]);
+ acpi_os_printf("%08X", temp32);
+
+ ACPI_MOVE_32_TO_32(&temp32,
+ &buffer[(acpi_size) i + j +
+ 4]);
+ acpi_os_printf("%08X ", temp32);
+ break;
+ }
+
+ j += display;
+ }
+
+ /*
+ * Print the ASCII equivalent characters but watch out for the bad
+ * unprintable ones (printable chars are 0x20 through 0x7E)
+ */
+ acpi_os_printf(" ");
+ for (j = 0; j < 16; j++) {
+ if (i + j >= count) {
+ acpi_os_printf("\n");
+ return;
+ }
+
+ buf_char = buffer[(acpi_size) i + j];
+ if (ACPI_IS_PRINT(buf_char)) {
+ acpi_os_printf("%c", buf_char);
+ } else {
+ acpi_os_printf(".");
+ }
+ }
+
+ /* Done with that line. */
+
+ acpi_os_printf("\n");
+ i += 16;
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_debug_dump_buffer
+ *
+ * PARAMETERS: buffer - Buffer to dump
+ * count - Amount to dump, in bytes
+ * display - BYTE, WORD, DWORD, or QWORD display:
+ * DB_BYTE_DISPLAY
+ * DB_WORD_DISPLAY
+ * DB_DWORD_DISPLAY
+ * DB_QWORD_DISPLAY
+ * component_ID - Caller's component ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id)
+{
+
+ /* Only dump the buffer if tracing is enabled */
+
+ if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
+ (component_id & acpi_dbg_layer))) {
+ return;
+ }
+
+ acpi_ut_dump_buffer(buffer, count, display, 0);
+}
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index e4c9291fc0a3..1731c27c36a6 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -178,7 +178,6 @@ acpi_ut_copy_isimple_to_esimple(union acpi_operand_object *internal_object,
switch (internal_object->reference.class) {
case ACPI_REFCLASS_NAME:
-
/*
* For namepath, return the object handle ("reference")
* We are referring to the namespace node
@@ -264,7 +263,6 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
switch (object_type) {
case ACPI_COPY_TYPE_SIMPLE:
-
/*
* This is a simple or null object
*/
@@ -278,7 +276,6 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
break;
case ACPI_COPY_TYPE_PACKAGE:
-
/*
* Build the package object
*/
@@ -304,6 +301,7 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
break;
default:
+
return (AE_BAD_PARAMETER);
}
@@ -481,6 +479,7 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
return_ACPI_STATUS(AE_OK);
default:
+
/* All other types are not supported */
ACPI_ERROR((AE_INFO,
@@ -544,7 +543,9 @@ acpi_ut_copy_esimple_to_isimple(union acpi_object *external_object,
break;
default:
+
/* Other types can't get here */
+
break;
}
@@ -800,7 +801,9 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
break;
default:
+
/* Nothing to do for other simple objects */
+
break;
}
@@ -868,7 +871,6 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
break;
case ACPI_COPY_TYPE_PACKAGE:
-
/*
* This object is a package - go down another nesting level
* Create and build the package object
@@ -891,6 +893,7 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
break;
default:
+
return (AE_BAD_PARAMETER);
}
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index c57d9cc07ba9..5796e11a0671 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Module Name: utdebug - Debug print routines
+ * Module Name: utdebug - Debug print/trace routines
*
*****************************************************************************/
@@ -543,149 +543,3 @@ acpi_ut_ptr_exit(u32 line_number,
}
#endif
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_dump_buffer
- *
- * PARAMETERS: buffer - Buffer to dump
- * count - Amount to dump, in bytes
- * display - BYTE, WORD, DWORD, or QWORD display
- * offset - Beginning buffer offset (display only)
- *
- * RETURN: None
- *
- * DESCRIPTION: Generic dump buffer in both hex and ascii.
- *
- ******************************************************************************/
-
-void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
-{
- u32 i = 0;
- u32 j;
- u32 temp32;
- u8 buf_char;
-
- if (!buffer) {
- acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
- return;
- }
-
- if ((count < 4) || (count & 0x01)) {
- display = DB_BYTE_DISPLAY;
- }
-
- /* Nasty little dump buffer routine! */
-
- while (i < count) {
-
- /* Print current offset */
-
- acpi_os_printf("%6.4X: ", (base_offset + i));
-
- /* Print 16 hex chars */
-
- for (j = 0; j < 16;) {
- if (i + j >= count) {
-
- /* Dump fill spaces */
-
- acpi_os_printf("%*s", ((display * 2) + 1), " ");
- j += display;
- continue;
- }
-
- switch (display) {
- case DB_BYTE_DISPLAY:
- default: /* Default is BYTE display */
-
- acpi_os_printf("%02X ",
- buffer[(acpi_size) i + j]);
- break;
-
- case DB_WORD_DISPLAY:
-
- ACPI_MOVE_16_TO_32(&temp32,
- &buffer[(acpi_size) i + j]);
- acpi_os_printf("%04X ", temp32);
- break;
-
- case DB_DWORD_DISPLAY:
-
- ACPI_MOVE_32_TO_32(&temp32,
- &buffer[(acpi_size) i + j]);
- acpi_os_printf("%08X ", temp32);
- break;
-
- case DB_QWORD_DISPLAY:
-
- ACPI_MOVE_32_TO_32(&temp32,
- &buffer[(acpi_size) i + j]);
- acpi_os_printf("%08X", temp32);
-
- ACPI_MOVE_32_TO_32(&temp32,
- &buffer[(acpi_size) i + j +
- 4]);
- acpi_os_printf("%08X ", temp32);
- break;
- }
-
- j += display;
- }
-
- /*
- * Print the ASCII equivalent characters but watch out for the bad
- * unprintable ones (printable chars are 0x20 through 0x7E)
- */
- acpi_os_printf(" ");
- for (j = 0; j < 16; j++) {
- if (i + j >= count) {
- acpi_os_printf("\n");
- return;
- }
-
- buf_char = buffer[(acpi_size) i + j];
- if (ACPI_IS_PRINT(buf_char)) {
- acpi_os_printf("%c", buf_char);
- } else {
- acpi_os_printf(".");
- }
- }
-
- /* Done with that line. */
-
- acpi_os_printf("\n");
- i += 16;
- }
-
- return;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_debug_dump_buffer
- *
- * PARAMETERS: buffer - Buffer to dump
- * count - Amount to dump, in bytes
- * display - BYTE, WORD, DWORD, or QWORD display
- * component_ID - Caller's component ID
- *
- * RETURN: None
- *
- * DESCRIPTION: Generic dump buffer in both hex and ascii.
- *
- ******************************************************************************/
-
-void
-acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id)
-{
-
- /* Only dump the buffer if tracing is enabled */
-
- if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
- (component_id & acpi_dbg_layer))) {
- return;
- }
-
- acpi_ut_dump_buffer(buffer, count, display, 0);
-}
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 29b930250b6f..d6b33f29d327 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -303,6 +303,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
break;
default:
+
break;
}
@@ -508,7 +509,6 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL:
-
/*
* Update the notify objects for these types (if present)
* Two lists, system and device notify handlers.
@@ -623,6 +623,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_REGION:
default:
+
break; /* No subobjects for all other types */
}
diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c
new file mode 100644
index 000000000000..154fdcaa5830
--- /dev/null
+++ b/drivers/acpi/acpica/uterror.c
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ *
+ * Module Name: uterror - Various internal error/warning output functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2013, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_UTILITIES
+ACPI_MODULE_NAME("uterror")
+
+/*
+ * This module contains internal error functions that may
+ * be configured out.
+ */
+#if !defined (ACPI_NO_ERROR_MESSAGES)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_warning
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Warnings for the predefined validation module. Messages are
+ * only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of error
+ * messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_warning(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...)
+{
+ va_list arg_list;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf(ACPI_MSG_WARNING "%s: ", pathname);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_info
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Info messages for the predefined validation module. Messages
+ * are only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of
+ * messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_info(const char *module_name,
+ u32 line_number,
+ char *pathname, u8 node_flags, const char *format, ...)
+{
+ va_list arg_list;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf(ACPI_MSG_INFO "%s: ", pathname);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_predefined_bios_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * pathname - Full pathname to the node
+ * node_flags - From Namespace node for the method/object
+ * format - Printf format string + additional args
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: BIOS error message for predefined names. Messages
+ * are only emitted the first time a problem with a particular
+ * method/object is detected. This prevents a flood of
+ * messages for methods that are repeatedly evaluated.
+ *
+ ******************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_predefined_bios_error(const char *module_name,
+ u32 line_number,
+ char *pathname,
+ u8 node_flags, const char *format, ...)
+{
+ va_list arg_list;
+
+ /*
+ * Warning messages for this method/object will be disabled after the
+ * first time a validation fails or an object is successfully repaired.
+ */
+ if (node_flags & ANOBJ_EVALUATED) {
+ return;
+ }
+
+ acpi_os_printf(ACPI_MSG_BIOS_ERROR "%s: ", pathname);
+
+ va_start(arg_list, format);
+ acpi_os_vprintf(format, arg_list);
+ ACPI_MSG_SUFFIX;
+ va_end(arg_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_namespace_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * internal_name - Name or path of the namespace node
+ * lookup_status - Exception code from NS lookup
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the NS node.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_namespace_error(const char *module_name,
+ u32 line_number,
+ const char *internal_name, acpi_status lookup_status)
+{
+ acpi_status status;
+ u32 bad_name;
+ char *name = NULL;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_ERROR);
+
+ if (lookup_status == AE_BAD_CHARACTER) {
+
+ /* There is a non-ascii character in the name */
+
+ ACPI_MOVE_32_TO_32(&bad_name,
+ ACPI_CAST_PTR(u32, internal_name));
+ acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name);
+ } else {
+ /* Convert path to external format */
+
+ status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
+ internal_name, NULL, &name);
+
+ /* Print target name */
+
+ if (ACPI_SUCCESS(status)) {
+ acpi_os_printf("[%s]", name);
+ } else {
+ acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
+ }
+
+ if (name) {
+ ACPI_FREE(name);
+ }
+ }
+
+ acpi_os_printf(" Namespace lookup failure, %s",
+ acpi_format_exception(lookup_status));
+
+ ACPI_MSG_SUFFIX;
+ ACPI_MSG_REDIRECT_END;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_method_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * message - Error message to use on failure
+ * prefix_node - Prefix relative to the path
+ * path - Path to the node (optional)
+ * method_status - Execution status
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message with the full pathname for the method.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_method_error(const char *module_name,
+ u32 line_number,
+ const char *message,
+ struct acpi_namespace_node *prefix_node,
+ const char *path, acpi_status method_status)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node = prefix_node;
+
+ ACPI_MSG_REDIRECT_BEGIN;
+ acpi_os_printf(ACPI_MSG_ERROR);
+
+ if (path) {
+ status =
+ acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
+ &node);
+ if (ACPI_FAILURE(status)) {
+ acpi_os_printf("[Could not get node by pathname]");
+ }
+ }
+
+ acpi_ns_print_node_pathname(node, message);
+ acpi_os_printf(", %s", acpi_format_exception(method_status));
+
+ ACPI_MSG_SUFFIX;
+ ACPI_MSG_REDIRECT_END;
+}
+
+#endif /* ACPI_NO_ERROR_MESSAGES */
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index c3f3a7e7bdc7..ee83adb97b1e 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -68,7 +68,7 @@ ACPI_MODULE_NAME("uteval")
******************************************************************************/
acpi_status
-acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
+acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node,
char *path,
u32 expected_return_btypes,
union acpi_operand_object **return_desc)
@@ -87,7 +87,7 @@ acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
}
info->prefix_node = prefix_node;
- info->pathname = path;
+ info->relative_pathname = path;
/* Evaluate the object/method */
@@ -123,22 +123,27 @@ acpi_ut_evaluate_object(struct acpi_namespace_node * prefix_node,
switch ((info->return_object)->common.type) {
case ACPI_TYPE_INTEGER:
+
return_btype = ACPI_BTYPE_INTEGER;
break;
case ACPI_TYPE_BUFFER:
+
return_btype = ACPI_BTYPE_BUFFER;
break;
case ACPI_TYPE_STRING:
+
return_btype = ACPI_BTYPE_STRING;
break;
case ACPI_TYPE_PACKAGE:
+
return_btype = ACPI_BTYPE_PACKAGE;
break;
default:
+
return_btype = 0;
break;
}
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index b543a144941a..ff6d9e8aa842 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -146,6 +146,7 @@ const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status status)
break;
default:
+
break;
}
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index 43a170a74a61..fa69071db418 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -341,14 +341,17 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
switch (cid_objects[i]->common.type) {
case ACPI_TYPE_INTEGER:
+
string_area_size += ACPI_EISAID_STRING_SIZE;
break;
case ACPI_TYPE_STRING:
+
string_area_size += cid_objects[i]->string.length + 1;
break;
default:
+
status = AE_TYPE;
goto cleanup;
}
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 785fdd07ae56..02f9101b65e4 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -382,10 +382,12 @@ acpi_ut_display_init_pathname(u8 type,
switch (type) {
case ACPI_TYPE_METHOD:
+
acpi_os_printf("Executing ");
break;
default:
+
acpi_os_printf("Initializing ");
break;
}
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index 1099f5c069f8..aa61f66ee861 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -129,6 +129,7 @@ union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char
break;
default:
+
/* All others have no secondary object */
break;
}
@@ -353,6 +354,7 @@ u8 acpi_ut_valid_internal_object(void *object)
return (TRUE);
default:
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"%p is not not an ACPI operand obj [%s]\n",
object, acpi_ut_get_descriptor_name(object)));
@@ -509,7 +511,6 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
switch (internal_object->reference.class) {
case ACPI_REFCLASS_NAME:
-
/*
* Get the actual length of the full pathname to this object.
* The reference will be converted to the pathname to the object
@@ -525,7 +526,6 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object,
break;
default:
-
/*
* No other reference opcodes are supported.
* Notably, Locals and Args are not supported, but this may be
@@ -585,7 +585,6 @@ acpi_ut_get_element_length(u8 object_type,
switch (object_type) {
case ACPI_COPY_TYPE_SIMPLE:
-
/*
* Simple object - just get the size (Null object/entry is handled
* here also) and sum it into the running package length
diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c
index 29459479148f..2b1ce4cd3207 100644
--- a/drivers/acpi/acpica/utpredef.c
+++ b/drivers/acpi/acpica/utpredef.c
@@ -147,6 +147,11 @@ void acpi_ut_get_expected_return_types(char *buffer, u32 expected_btypes)
u32 i;
u32 j;
+ if (!expected_btypes) {
+ ACPI_STRCPY(buffer, "NONE");
+ return;
+ }
+
j = 1;
buffer[0] = 0;
this_rtype = ACPI_RTYPE_INTEGER;
@@ -328,9 +333,7 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
/* First field in the types list is the count of args to follow */
- arg_count = (argument_types & METHOD_ARG_MASK);
- argument_types >>= METHOD_ARG_BIT_WIDTH;
-
+ arg_count = METHOD_GET_ARG_COUNT(argument_types);
if (arg_count > METHOD_PREDEF_ARGS_MAX) {
printf("**** Invalid argument count (%u) "
"in predefined info structure\n", arg_count);
@@ -340,7 +343,8 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
/* Get each argument from the list, convert to ascii, store to buffer */
for (i = 0; i < arg_count; i++) {
- this_argument_type = (argument_types & METHOD_ARG_MASK);
+ this_argument_type = METHOD_GET_NEXT_TYPE(argument_types);
+
if (!this_argument_type
|| (this_argument_type > METHOD_MAX_ARG_TYPE)) {
printf("**** Invalid argument type (%u) "
@@ -351,10 +355,6 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
strcat(buffer,
ut_external_type_names[this_argument_type] + sub_index);
-
- /* Shift to next argument type field */
-
- argument_types >>= METHOD_ARG_BIT_WIDTH;
sub_index = 0;
}
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index b3e36a81aa4d..c53759b76a3f 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -186,10 +186,13 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer)
switch (base) {
case ACPI_ANY_BASE:
case 16:
+
break;
default:
+
/* Invalid Base */
+
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
@@ -355,36 +358,44 @@ void acpi_ut_print_string(char *string, u8 max_length)
switch (string[i]) {
case 0x07:
+
acpi_os_printf("\\a"); /* BELL */
break;
case 0x08:
+
acpi_os_printf("\\b"); /* BACKSPACE */
break;
case 0x0C:
+
acpi_os_printf("\\f"); /* FORMFEED */
break;
case 0x0A:
+
acpi_os_printf("\\n"); /* LINEFEED */
break;
case 0x0D:
+
acpi_os_printf("\\r"); /* CARRIAGE RETURN */
break;
case 0x09:
+
acpi_os_printf("\\t"); /* HORIZONTAL TAB */
break;
case 0x0B:
+
acpi_os_printf("\\v"); /* VERTICAL TAB */
break;
case '\'': /* Single Quote */
case '\"': /* Double Quote */
case '\\': /* Backslash */
+
acpi_os_printf("\\%c", (int)string[i]);
break;
@@ -451,7 +462,8 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position)
*
* FUNCTION: acpi_ut_valid_acpi_name
*
- * PARAMETERS: name - The name to be examined
+ * PARAMETERS: name - The name to be examined. Does not have to
+ * be NULL terminated string.
*
* RETURN: TRUE if the name is valid, FALSE otherwise
*
@@ -462,15 +474,14 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position)
*
******************************************************************************/
-u8 acpi_ut_valid_acpi_name(u32 name)
+u8 acpi_ut_valid_acpi_name(char *name)
{
u32 i;
ACPI_FUNCTION_ENTRY();
for (i = 0; i < ACPI_NAME_SIZE; i++) {
- if (!acpi_ut_valid_acpi_char
- ((ACPI_CAST_PTR(char, &name))[i], i)) {
+ if (!acpi_ut_valid_acpi_char(name[i], i)) {
return (FALSE);
}
}
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index 62774c7b76a8..160f13f4aab5 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -603,6 +603,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
switch (ACPI_GET_DESCRIPTOR_TYPE
(descriptor)) {
case ACPI_DESC_TYPE_OPERAND:
+
if (element->size ==
sizeof(union
acpi_operand_object))
@@ -613,6 +614,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
break;
case ACPI_DESC_TYPE_PARSER:
+
if (element->size ==
sizeof(union
acpi_parse_object)) {
@@ -622,6 +624,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
break;
case ACPI_DESC_TYPE_NAMED:
+
if (element->size ==
sizeof(struct
acpi_namespace_node))
@@ -632,6 +635,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
break;
default:
+
break;
}
@@ -639,6 +643,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
switch (descriptor_type) {
case ACPI_DESC_TYPE_OPERAND:
+
acpi_os_printf
("%12.12s RefCount 0x%04X\n",
acpi_ut_get_type_name
@@ -649,6 +654,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
break;
case ACPI_DESC_TYPE_PARSER:
+
acpi_os_printf
("AmlOpcode 0x%04hX\n",
descriptor->op.asl.
@@ -656,6 +662,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
break;
case ACPI_DESC_TYPE_NAMED:
+
acpi_os_printf("%4.4s\n",
acpi_ut_get_node_name
(&descriptor->
@@ -663,6 +670,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
break;
default:
+
acpi_os_printf("\n");
break;
}
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index 976b6c734fce..e966a2e47b76 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -44,7 +44,6 @@
#include <linux/export.h>
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acnamesp.h"
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxferror")
@@ -52,43 +51,7 @@ ACPI_MODULE_NAME("utxferror")
/*
* This module is used for the in-kernel ACPICA as well as the ACPICA
* tools/applications.
- *
- * For the iASL compiler case, the output is redirected to stderr so that
- * any of the various ACPI errors and warnings do not appear in the output
- * files, for either the compiler or disassembler portions of the tool.
*/
-#ifdef ACPI_ASL_COMPILER
-#include <stdio.h>
-extern FILE *acpi_gbl_output_file;
-
-#define ACPI_MSG_REDIRECT_BEGIN \
- FILE *output_file = acpi_gbl_output_file; \
- acpi_os_redirect_output (stderr);
-
-#define ACPI_MSG_REDIRECT_END \
- acpi_os_redirect_output (output_file);
-
-#else
-/*
- * non-iASL case - no redirection, nothing to do
- */
-#define ACPI_MSG_REDIRECT_BEGIN
-#define ACPI_MSG_REDIRECT_END
-#endif
-/*
- * Common message prefixes
- */
-#define ACPI_MSG_ERROR "ACPI Error: "
-#define ACPI_MSG_EXCEPTION "ACPI Exception: "
-#define ACPI_MSG_WARNING "ACPI Warning: "
-#define ACPI_MSG_INFO "ACPI: "
-#define ACPI_MSG_BIOS_ERROR "ACPI BIOS Bug: Error: "
-#define ACPI_MSG_BIOS_WARNING "ACPI BIOS Bug: Warning: "
-/*
- * Common message suffix
- */
-#define ACPI_MSG_SUFFIX \
- acpi_os_printf (" (%8.8X/%s-%u)\n", ACPI_CA_VERSION, module_name, line_number)
/*******************************************************************************
*
* FUNCTION: acpi_error
@@ -285,200 +248,3 @@ acpi_bios_warning(const char *module_name,
}
ACPI_EXPORT_SYMBOL(acpi_bios_warning)
-
-/*
- * The remainder of this module contains internal error functions that may
- * be configured out.
- */
-#if !defined (ACPI_NO_ERROR_MESSAGES) && !defined (ACPI_BIN_APP)
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_predefined_warning
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * pathname - Full pathname to the node
- * node_flags - From Namespace node for the method/object
- * format - Printf format string + additional args
- *
- * RETURN: None
- *
- * DESCRIPTION: Warnings for the predefined validation module. Messages are
- * only emitted the first time a problem with a particular
- * method/object is detected. This prevents a flood of error
- * messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_warning(const char *module_name,
- u32 line_number,
- char *pathname,
- u8 node_flags, const char *format, ...)
-{
- va_list arg_list;
-
- /*
- * Warning messages for this method/object will be disabled after the
- * first time a validation fails or an object is successfully repaired.
- */
- if (node_flags & ANOBJ_EVALUATED) {
- return;
- }
-
- acpi_os_printf(ACPI_MSG_WARNING "For %s: ", pathname);
-
- va_start(arg_list, format);
- acpi_os_vprintf(format, arg_list);
- ACPI_MSG_SUFFIX;
- va_end(arg_list);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_predefined_info
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * pathname - Full pathname to the node
- * node_flags - From Namespace node for the method/object
- * format - Printf format string + additional args
- *
- * RETURN: None
- *
- * DESCRIPTION: Info messages for the predefined validation module. Messages
- * are only emitted the first time a problem with a particular
- * method/object is detected. This prevents a flood of
- * messages for methods that are repeatedly evaluated.
- *
- ******************************************************************************/
-
-void ACPI_INTERNAL_VAR_XFACE
-acpi_ut_predefined_info(const char *module_name,
- u32 line_number,
- char *pathname, u8 node_flags, const char *format, ...)
-{
- va_list arg_list;
-
- /*
- * Warning messages for this method/object will be disabled after the
- * first time a validation fails or an object is successfully repaired.
- */
- if (node_flags & ANOBJ_EVALUATED) {
- return;
- }
-
- acpi_os_printf(ACPI_MSG_INFO "For %s: ", pathname);
-
- va_start(arg_list, format);
- acpi_os_vprintf(format, arg_list);
- ACPI_MSG_SUFFIX;
- va_end(arg_list);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_namespace_error
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * internal_name - Name or path of the namespace node
- * lookup_status - Exception code from NS lookup
- *
- * RETURN: None
- *
- * DESCRIPTION: Print error message with the full pathname for the NS node.
- *
- ******************************************************************************/
-
-void
-acpi_ut_namespace_error(const char *module_name,
- u32 line_number,
- const char *internal_name, acpi_status lookup_status)
-{
- acpi_status status;
- u32 bad_name;
- char *name = NULL;
-
- ACPI_MSG_REDIRECT_BEGIN;
- acpi_os_printf(ACPI_MSG_ERROR);
-
- if (lookup_status == AE_BAD_CHARACTER) {
-
- /* There is a non-ascii character in the name */
-
- ACPI_MOVE_32_TO_32(&bad_name,
- ACPI_CAST_PTR(u32, internal_name));
- acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name);
- } else {
- /* Convert path to external format */
-
- status = acpi_ns_externalize_name(ACPI_UINT32_MAX,
- internal_name, NULL, &name);
-
- /* Print target name */
-
- if (ACPI_SUCCESS(status)) {
- acpi_os_printf("[%s]", name);
- } else {
- acpi_os_printf("[COULD NOT EXTERNALIZE NAME]");
- }
-
- if (name) {
- ACPI_FREE(name);
- }
- }
-
- acpi_os_printf(" Namespace lookup failure, %s",
- acpi_format_exception(lookup_status));
-
- ACPI_MSG_SUFFIX;
- ACPI_MSG_REDIRECT_END;
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ut_method_error
- *
- * PARAMETERS: module_name - Caller's module name (for error output)
- * line_number - Caller's line number (for error output)
- * message - Error message to use on failure
- * prefix_node - Prefix relative to the path
- * path - Path to the node (optional)
- * method_status - Execution status
- *
- * RETURN: None
- *
- * DESCRIPTION: Print error message with the full pathname for the method.
- *
- ******************************************************************************/
-
-void
-acpi_ut_method_error(const char *module_name,
- u32 line_number,
- const char *message,
- struct acpi_namespace_node *prefix_node,
- const char *path, acpi_status method_status)
-{
- acpi_status status;
- struct acpi_namespace_node *node = prefix_node;
-
- ACPI_MSG_REDIRECT_BEGIN;
- acpi_os_printf(ACPI_MSG_ERROR);
-
- if (path) {
- status =
- acpi_ns_get_node(prefix_node, path, ACPI_NS_NO_UPSEARCH,
- &node);
- if (ACPI_FAILURE(status)) {
- acpi_os_printf("[Could not get node by pathname]");
- }
- }
-
- acpi_ns_print_node_pathname(node, message);
- acpi_os_printf(", %s", acpi_format_exception(method_status));
-
- ACPI_MSG_SUFFIX;
- ACPI_MSG_REDIRECT_END;
-}
-
-#endif /* ACPI_NO_ERROR_MESSAGES */
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 6d894bfd8b8f..88d0b0f9f92b 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -935,7 +935,7 @@ static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
struct timespec *time, char **buf,
struct pstore_info *psi);
static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
- u64 *id, unsigned int part, int count,
+ u64 *id, unsigned int part, int count, size_t hsize,
size_t size, struct pstore_info *psi);
static int erst_clearer(enum pstore_type_id type, u64 id, int count,
struct timespec time, struct pstore_info *psi);
@@ -1055,7 +1055,7 @@ out:
}
static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
- u64 *id, unsigned int part, int count,
+ u64 *id, unsigned int part, int count, size_t hsize,
size_t size, struct pstore_info *psi)
{
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
@@ -1180,20 +1180,28 @@ static int __init erst_init(void)
if (!erst_erange.vaddr)
goto err_release_erange;
+ pr_info(ERST_PFX
+ "Error Record Serialization Table (ERST) support is initialized.\n");
+
buf = kmalloc(erst_erange.size, GFP_KERNEL);
spin_lock_init(&erst_info.buf_lock);
if (buf) {
erst_info.buf = buf + sizeof(struct cper_pstore_record);
erst_info.bufsize = erst_erange.size -
sizeof(struct cper_pstore_record);
- if (pstore_register(&erst_info)) {
- pr_info(ERST_PFX "Could not register with persistent store\n");
+ rc = pstore_register(&erst_info);
+ if (rc) {
+ if (rc != -EPERM)
+ pr_info(ERST_PFX
+ "Could not register with persistent store\n");
+ erst_info.buf = NULL;
+ erst_info.bufsize = 0;
kfree(buf);
}
- }
-
- pr_info(ERST_PFX
- "Error Record Serialization Table (ERST) support is initialized.\n");
+ } else
+ pr_err(ERST_PFX
+ "Failed to allocate %lld bytes for persistent store error log\n",
+ erst_erange.size);
return 0;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index fcd7d91cec34..ec9b57d428a1 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -449,9 +449,19 @@ static void ghes_do_proc(struct ghes *ghes,
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
unsigned int devfn;
int aer_severity;
+
devfn = PCI_DEVFN(pcie_err->device_id.device,
pcie_err->device_id.function);
aer_severity = cper_severity_to_aer(sev);
+
+ /*
+ * If firmware reset the component to contain
+ * the error, we must reinitialize it before
+ * use, so treat it as a fatal AER error.
+ */
+ if (gdata->flags & CPER_SEC_RESET)
+ aer_severity = AER_FATAL;
+
aer_recover_queue(pcie_err->device_id.segment,
pcie_err->device_id.bus,
devfn, aer_severity,
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index e7100459ac4a..082b4dd252a8 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -425,7 +425,7 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
{
int result = -EFAULT;
acpi_status status = 0;
- char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)?
+ char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
"_BIX" : "_BIF";
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -661,11 +661,11 @@ static void find_battery(const struct dmi_header *dm, void *private)
static void acpi_battery_quirks(struct acpi_battery *battery)
{
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
- return ;
+ return;
- if (battery->full_charge_capacity == 100 &&
- battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
- battery->capacity_now >=0 && battery->capacity_now <= 100) {
+ if (battery->full_charge_capacity == 100 &&
+ battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN &&
+ battery->capacity_now >= 0 && battery->capacity_now <= 100) {
set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags);
battery->full_charge_capacity = battery->design_capacity;
battery->capacity_now = (battery->capacity_now *
@@ -673,7 +673,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
}
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags))
- return ;
+ return;
if (battery->power_unit && dmi_name_in_vendors("LENOVO")) {
const char *s;
@@ -761,7 +761,7 @@ static int acpi_battery_print_info(struct seq_file *seq, int result)
goto end;
seq_printf(seq, "present: %s\n",
- acpi_battery_present(battery)?"yes":"no");
+ acpi_battery_present(battery) ? "yes" : "no");
if (!acpi_battery_present(battery))
goto end;
if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
@@ -817,12 +817,12 @@ static int acpi_battery_print_state(struct seq_file *seq, int result)
goto end;
seq_printf(seq, "present: %s\n",
- acpi_battery_present(battery)?"yes":"no");
+ acpi_battery_present(battery) ? "yes" : "no");
if (!acpi_battery_present(battery))
goto end;
seq_printf(seq, "capacity state: %s\n",
- (battery->state & 0x04)?"critical":"ok");
+ (battery->state & 0x04) ? "critical" : "ok");
if ((battery->state & 0x01) && (battery->state & 0x02))
seq_printf(seq,
"charging state: charging/discharging\n");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 292de3cab9cc..a5bb33bab448 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -91,8 +91,7 @@ static struct dmi_system_id dsdt_dmi_table[] __initdata = {
int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
{
- acpi_status status = AE_OK;
-
+ acpi_status status;
if (!device)
return -EINVAL;
@@ -162,7 +161,7 @@ EXPORT_SYMBOL(acpi_bus_private_data_handler);
int acpi_bus_get_private_data(acpi_handle handle, void **data)
{
- acpi_status status = AE_OK;
+ acpi_status status;
if (!*data)
return -EINVAL;
@@ -361,7 +360,7 @@ extern int event_is_open;
int acpi_bus_generate_proc_event4(const char *device_class, const char *bus_id, u8 type, int data)
{
struct acpi_bus_event *event;
- unsigned long flags = 0;
+ unsigned long flags;
/* drop event on the floor if no one's listening */
if (!event_is_open)
@@ -400,7 +399,7 @@ EXPORT_SYMBOL(acpi_bus_generate_proc_event);
int acpi_bus_receive_event(struct acpi_bus_event *event)
{
- unsigned long flags = 0;
+ unsigned long flags;
struct acpi_bus_event *entry = NULL;
DECLARE_WAITQUEUE(wait, current);
@@ -593,7 +592,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
static int __init acpi_bus_init_irq(void)
{
- acpi_status status = AE_OK;
+ acpi_status status;
union acpi_object arg = { ACPI_TYPE_INTEGER };
struct acpi_object_list arg_list = { 1, &arg };
char *message = NULL;
@@ -640,7 +639,7 @@ u8 acpi_gbl_permanent_mmap;
void __init acpi_early_init(void)
{
- acpi_status status = AE_OK;
+ acpi_status status;
if (acpi_disabled)
return;
@@ -714,8 +713,8 @@ void __init acpi_early_init(void)
static int __init acpi_bus_init(void)
{
- int result = 0;
- acpi_status status = AE_OK;
+ int result;
+ acpi_status status;
extern acpi_status acpi_os_initialize1(void);
acpi_os_initialize1();
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 31c217a42839..4ab807dc8518 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -324,14 +324,27 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
if (result)
return result;
- if (state == ACPI_STATE_UNKNOWN)
+ if (state == ACPI_STATE_UNKNOWN) {
state = ACPI_STATE_D0;
-
- result = acpi_device_set_power(device, state);
- if (!result && state_p)
+ result = acpi_device_set_power(device, state);
+ if (result)
+ return result;
+ } else {
+ if (device->power.flags.power_resources) {
+ /*
+ * We don't need to really switch the state, bu we need
+ * to update the power resources' reference counters.
+ */
+ result = acpi_power_transition(device, state);
+ if (result)
+ return result;
+ }
+ device->power.state = state;
+ }
+ if (state_p)
*state_p = state;
- return result;
+ return 0;
}
EXPORT_SYMBOL_GPL(acpi_bus_update_power);
@@ -419,62 +432,73 @@ bool acpi_bus_can_wakeup(acpi_handle handle)
EXPORT_SYMBOL(acpi_bus_can_wakeup);
/**
- * acpi_device_power_state - Get preferred power state of ACPI device.
+ * acpi_dev_pm_get_state - Get preferred power state of ACPI device.
* @dev: Device whose preferred target power state to return.
* @adev: ACPI device node corresponding to @dev.
* @target_state: System state to match the resultant device state.
- * @d_max_in: Deepest low-power state to take into consideration.
- * @d_min_p: Location to store the upper limit of the allowed states range.
- * Return value: Preferred power state of the device on success, -ENODEV
- * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
+ * @d_min_p: Location to store the highest power state available to the device.
+ * @d_max_p: Location to store the lowest power state available to the device.
*
- * Find the lowest power (highest number) ACPI device power state that the
- * device can be in while the system is in the state represented by
- * @target_state. If @d_min_p is set, the highest power (lowest number) device
- * power state that @dev can be in for the given system sleep state is stored
- * at the location pointed to by it.
+ * Find the lowest power (highest number) and highest power (lowest number) ACPI
+ * device power states that the device can be in while the system is in the
+ * state represented by @target_state. Store the integer numbers representing
+ * those stats in the memory locations pointed to by @d_max_p and @d_min_p,
+ * respectively.
*
* Callers must ensure that @dev and @adev are valid pointers and that @adev
* actually corresponds to @dev before using this function.
+ *
+ * Returns 0 on success or -ENODATA when one of the ACPI methods fails or
+ * returns a value that doesn't make sense. The memory locations pointed to by
+ * @d_max_p and @d_min_p are only modified on success.
*/
-int acpi_device_power_state(struct device *dev, struct acpi_device *adev,
- u32 target_state, int d_max_in, int *d_min_p)
+static int acpi_dev_pm_get_state(struct device *dev, struct acpi_device *adev,
+ u32 target_state, int *d_min_p, int *d_max_p)
{
- char acpi_method[] = "_SxD";
- unsigned long long d_min, d_max;
+ char method[] = { '_', 'S', '0' + target_state, 'D', '\0' };
+ acpi_handle handle = adev->handle;
+ unsigned long long ret;
+ int d_min, d_max;
bool wakeup = false;
+ acpi_status status;
- if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3)
- return -EINVAL;
-
- if (d_max_in > ACPI_STATE_D3_HOT) {
- 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;
- }
-
- acpi_method[2] = '0' + target_state;
/*
- * If the sleep state is S0, the lowest limit from ACPI is D3,
- * but if the device has _S0W, we will use the value from _S0W
- * as the lowest limit from ACPI. Finally, we will constrain
- * the lowest limit with the specified one.
+ * If the system state is S0, the lowest power state the device can be
+ * in is D3cold, unless the device has _S0W and is supposed to signal
+ * wakeup, in which case the return value of _S0W has to be used as the
+ * lowest power state available to the device.
*/
d_min = ACPI_STATE_D0;
- d_max = ACPI_STATE_D3;
+ d_max = ACPI_STATE_D3_COLD;
/*
* If present, _SxD methods return the minimum D-state (highest power
* state) we can use for the corresponding S-states. Otherwise, the
* minimum D-state is D0 (ACPI 3.x).
- *
- * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
- * provided -- that's our fault recovery, we ignore retval.
*/
if (target_state > ACPI_STATE_S0) {
- acpi_evaluate_integer(adev->handle, acpi_method, NULL, &d_min);
+ /*
+ * We rely on acpi_evaluate_integer() not clobbering the integer
+ * provided if AE_NOT_FOUND is returned.
+ */
+ ret = d_min;
+ status = acpi_evaluate_integer(handle, method, NULL, &ret);
+ if ((ACPI_FAILURE(status) && status != AE_NOT_FOUND)
+ || ret > ACPI_STATE_D3_COLD)
+ return -ENODATA;
+
+ /*
+ * We need to handle legacy systems where D3hot and D3cold are
+ * the same and 3 is returned in both cases, so fall back to
+ * D3cold if D3hot is not a valid state.
+ */
+ if (!adev->power.states[ret].flags.valid) {
+ if (ret == ACPI_STATE_D3_HOT)
+ ret = ACPI_STATE_D3_COLD;
+ else
+ return -ENODATA;
+ }
+ d_min = ret;
wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid
&& adev->wakeup.sleep_state >= target_state;
} else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) !=
@@ -490,38 +514,30 @@ int acpi_device_power_state(struct device *dev, struct acpi_device *adev,
* can wake the system. _S0W may be valid, too.
*/
if (wakeup) {
- acpi_status status;
-
- acpi_method[3] = 'W';
- status = acpi_evaluate_integer(adev->handle, acpi_method, NULL,
- &d_max);
- if (ACPI_FAILURE(status)) {
- if (target_state != ACPI_STATE_S0 ||
- status != AE_NOT_FOUND)
+ method[3] = 'W';
+ status = acpi_evaluate_integer(handle, method, NULL, &ret);
+ if (status == AE_NOT_FOUND) {
+ if (target_state > ACPI_STATE_S0)
d_max = d_min;
- } else if (d_max < d_min) {
- /* Warn the user of the broken DSDT */
- printk(KERN_WARNING "ACPI: Wrong value from %s\n",
- acpi_method);
- /* Sanitize it */
- d_min = d_max;
+ } else if (ACPI_SUCCESS(status) && ret <= ACPI_STATE_D3_COLD) {
+ /* Fall back to D3cold if ret is not a valid state. */
+ if (!adev->power.states[ret].flags.valid)
+ ret = ACPI_STATE_D3_COLD;
+
+ d_max = ret > d_min ? ret : d_min;
+ } else {
+ return -ENODATA;
}
}
- if (d_max_in < d_min)
- return -EINVAL;
if (d_min_p)
*d_min_p = d_min;
- /* constrain d_max with specified lowest limit (max number) */
- if (d_max > d_max_in) {
- for (d_max = d_max_in; d_max > d_min; d_max--) {
- if (adev->power.states[d_max].flags.valid)
- break;
- }
- }
- return d_max;
+
+ if (d_max_p)
+ *d_max_p = d_max;
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(acpi_device_power_state);
/**
* acpi_pm_device_sleep_state - Get preferred power state of ACPI device.
@@ -529,7 +545,8 @@ EXPORT_SYMBOL_GPL(acpi_device_power_state);
* @d_min_p: Location to store the upper limit of the allowed states range.
* @d_max_in: Deepest low-power state to take into consideration.
* Return value: Preferred power state of the device on success, -ENODEV
- * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure
+ * if there's no 'struct acpi_device' for @dev, -EINVAL if @d_max_in is
+ * incorrect, or -ENODATA on ACPI method failure.
*
* The caller must ensure that @dev is valid before using this function.
*/
@@ -537,14 +554,43 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
{
acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
struct acpi_device *adev;
+ int ret, d_min, d_max;
+
+ if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD)
+ return -EINVAL;
+
+ if (d_max_in > ACPI_STATE_D3_HOT) {
+ 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;
+ }
if (!handle || acpi_bus_get_device(handle, &adev)) {
dev_dbg(dev, "ACPI handle without context in %s!\n", __func__);
return -ENODEV;
}
- return acpi_device_power_state(dev, adev, acpi_target_system_state(),
- d_max_in, d_min_p);
+ ret = acpi_dev_pm_get_state(dev, adev, acpi_target_system_state(),
+ &d_min, &d_max);
+ if (ret)
+ return ret;
+
+ if (d_max_in < d_min)
+ return -EINVAL;
+
+ if (d_max > d_max_in) {
+ for (d_max = d_max_in; d_max > d_min; d_max--) {
+ if (adev->power.states[d_max].flags.valid)
+ break;
+ }
+ }
+
+ if (d_min_p)
+ *d_min_p = d_min;
+
+ return d_max;
}
EXPORT_SYMBOL(acpi_pm_device_sleep_state);
@@ -695,17 +741,13 @@ struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev,
u32 system_state)
{
- int power_state;
+ int ret, state;
if (!acpi_device_power_manageable(adev))
return 0;
- power_state = acpi_device_power_state(dev, adev, system_state,
- ACPI_STATE_D3, NULL);
- if (power_state < ACPI_STATE_D0 || power_state > ACPI_STATE_D3)
- return -EIO;
-
- return acpi_device_set_power(adev, power_state);
+ ret = acpi_dev_pm_get_state(dev, adev, system_state, NULL, &state);
+ return ret ? ret : acpi_device_set_power(adev, state);
}
/**
@@ -908,7 +950,6 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume,
- .runtime_idle = pm_generic_runtime_idle,
#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 14de9f46972e..826560753389 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -1064,10 +1064,10 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK;
}
-int __init acpi_dock_init(void)
+void __init acpi_dock_init(void)
{
if (acpi_disabled)
- return 0;
+ return;
/* look for dock stations and bays */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
@@ -1075,11 +1075,10 @@ int __init acpi_dock_init(void)
if (!dock_station_count) {
pr_info(PREFIX "No dock devices found.\n");
- return 0;
+ return;
}
register_acpi_bus_notifier(&dock_acpi_notifier);
pr_info(PREFIX "%s: %d docks/bays found\n",
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
- return 0;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index edc00818c803..80403c1a89f8 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -983,6 +983,10 @@ static struct dmi_system_id __initdata ec_dmi_table[] = {
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},
{},
};
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index 7586544fddb4..4e7b798900f2 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -12,6 +12,7 @@
#include <linux/acpi.h>
#include <linux/debugfs.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
#include "internal.h"
MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
@@ -34,7 +35,6 @@ static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
* struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private;
*/
unsigned int size = EC_SPACE_SIZE;
- u8 *data = (u8 *) buf;
loff_t init_off = *off;
int err = 0;
@@ -47,9 +47,15 @@ static ssize_t acpi_ec_read_io(struct file *f, char __user *buf,
size = count;
while (size) {
- err = ec_read(*off, &data[*off - init_off]);
+ u8 byte_read;
+ err = ec_read(*off, &byte_read);
if (err)
return err;
+ if (put_user(byte_read, buf + *off - init_off)) {
+ if (*off - init_off)
+ return *off - init_off; /* partial read */
+ return -EFAULT;
+ }
*off += 1;
size--;
}
@@ -65,7 +71,6 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
unsigned int size = count;
loff_t init_off = *off;
- u8 *data = (u8 *) buf;
int err = 0;
if (*off >= EC_SPACE_SIZE)
@@ -76,7 +81,12 @@ static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf,
}
while (size) {
- u8 byte_write = data[*off - init_off];
+ u8 byte_write;
+ if (get_user(byte_write, buf + *off - init_off)) {
+ if (*off - init_off)
+ return *off - init_off; /* partial write */
+ return -EFAULT;
+ }
err = ec_write(*off, byte_write);
if (err)
return err;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 8d1c0105e113..5b02a0aa540c 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -84,7 +84,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
{
struct acpi_device *device = cdev->devdata;
int result;
- int acpi_state;
+ int acpi_state = ACPI_STATE_D0;
if (!device)
return -EINVAL;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 40a84cc6740c..f68095756fb7 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -81,13 +81,15 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used,
void *addr_p, void **ret_p)
{
- unsigned long long addr;
+ unsigned long long addr, sta;
acpi_status status;
status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) {
*ret_p = handle;
- return AE_CTRL_TERMINATE;
+ status = acpi_bus_get_status_handle(handle, &sta);
+ if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_ENABLED))
+ return AE_CTRL_TERMINATE;
}
return AE_OK;
}
@@ -105,7 +107,7 @@ acpi_handle acpi_get_child(acpi_handle parent, u64 address)
}
EXPORT_SYMBOL(acpi_get_child);
-static int acpi_bind_one(struct device *dev, acpi_handle handle)
+int acpi_bind_one(struct device *dev, acpi_handle handle)
{
struct acpi_device *acpi_dev;
acpi_status status;
@@ -188,8 +190,9 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
kfree(physical_node);
goto err;
}
+EXPORT_SYMBOL_GPL(acpi_bind_one);
-static int acpi_unbind_one(struct device *dev)
+int acpi_unbind_one(struct device *dev)
{
struct acpi_device_physical_node *entry;
struct acpi_device *acpi_dev;
@@ -238,6 +241,7 @@ err:
dev_err(dev, "Oops, 'acpi_handle' corrupt\n");
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(acpi_unbind_one);
static int acpi_platform_notify(struct device *dev)
{
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index c610a76d92c4..3a50a34fe176 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -33,6 +33,7 @@ static inline void acpi_pci_slot_init(void) { }
void acpi_pci_root_init(void);
void acpi_pci_link_init(void);
void acpi_pci_root_hp_init(void);
+void acpi_processor_init(void);
void acpi_platform_init(void);
int acpi_sysfs_init(void);
#ifdef CONFIG_ACPI_CONTAINER
@@ -50,6 +51,13 @@ void acpi_memory_hotplug_init(void);
#else
static inline void acpi_memory_hotplug_init(void) {}
#endif
+#ifdef CONFIG_X86
+void acpi_cmos_rtc_init(void);
+#else
+static inline void acpi_cmos_rtc_init(void) {}
+#endif
+
+extern bool acpi_force_hot_remove;
void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
const char *name);
@@ -81,6 +89,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
int type, unsigned long long sta);
void acpi_device_add_finalize(struct acpi_device *device);
void acpi_free_pnp_ids(struct acpi_device_pnp *pnp);
+int acpi_bind_one(struct device *dev, acpi_handle handle);
+int acpi_unbind_one(struct device *dev);
/* --------------------------------------------------------------------------
Power Resource
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index e72186340fec..6ab2c3505520 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -835,19 +835,9 @@ void acpi_os_stall(u32 us)
*/
u64 acpi_os_get_timer(void)
{
- static u64 t;
-
-#ifdef CONFIG_HPET
- /* TBD: use HPET if available */
-#endif
-
-#ifdef CONFIG_X86_PM_TIMER
- /* TBD: default to PM timer if HPET was not available */
-#endif
- if (!t)
- printk(KERN_ERR PREFIX "acpi_os_get_timer() TBD\n");
-
- return ++t;
+ u64 time_ns = ktime_to_ns(ktime_get());
+ do_div(time_ns, 100);
+ return time_ns;
}
acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
@@ -1715,6 +1705,17 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
}
#endif
+static int __init acpi_no_auto_ssdt_setup(char *s)
+{
+ printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n");
+
+ acpi_gbl_disable_ssdt_table_load = TRUE;
+
+ return 1;
+}
+
+__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
+
acpi_status __init acpi_os_initialize(void)
{
acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index e427dc516c76..5917839321b8 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -65,10 +65,6 @@ static struct acpi_scan_handler pci_root_handler = {
.detach = acpi_pci_root_remove,
};
-/* Lock to protect both acpi_pci_roots lists */
-static DEFINE_MUTEX(acpi_pci_root_lock);
-static LIST_HEAD(acpi_pci_roots);
-
static DEFINE_MUTEX(osc_lock);
/**
@@ -100,13 +96,12 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
{
struct resource *res = data;
struct acpi_resource_address64 address;
+ acpi_status status;
- if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
- resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
+ status = acpi_resource_to_address64(resource, &address);
+ if (ACPI_FAILURE(status))
return AE_OK;
- acpi_resource_to_address64(resource, &address);
if ((address.address_length > 0) &&
(address.resource_type == ACPI_BUS_NUMBER_RANGE)) {
res->start = address.minimum;
@@ -382,23 +377,24 @@ static int acpi_pci_root_add(struct acpi_device *device,
int result;
struct acpi_pci_root *root;
u32 flags, base_flags;
+ acpi_handle handle = device->handle;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
return -ENOMEM;
segment = 0;
- status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
+ status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL,
&segment);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
+ dev_err(&device->dev, "can't evaluate _SEG\n");
result = -ENODEV;
goto end;
}
/* Check _CRS first, then _BBN. If no _BBN, default to zero. */
root->secondary.flags = IORESOURCE_BUS;
- status = try_get_root_bridge_busnr(device->handle, &root->secondary);
+ status = try_get_root_bridge_busnr(handle, &root->secondary);
if (ACPI_FAILURE(status)) {
/*
* We need both the start and end of the downstream bus range
@@ -407,33 +403,32 @@ static int acpi_pci_root_add(struct acpi_device *device,
* can do is assume [_BBN-0xFF] or [0-0xFF].
*/
root->secondary.end = 0xFF;
- printk(KERN_WARNING FW_BUG PREFIX
- "no secondary bus range in _CRS\n");
- status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN,
+ dev_warn(&device->dev,
+ FW_BUG "no secondary bus range in _CRS\n");
+ status = acpi_evaluate_integer(handle, METHOD_NAME__BBN,
NULL, &bus);
if (ACPI_SUCCESS(status))
root->secondary.start = bus;
else if (status == AE_NOT_FOUND)
root->secondary.start = 0;
else {
- printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
+ dev_err(&device->dev, "can't evaluate _BBN\n");
result = -ENODEV;
goto end;
}
}
- INIT_LIST_HEAD(&root->node);
root->device = device;
root->segment = segment & 0xFFFF;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root;
- printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
+ pr_info(PREFIX "%s [%s] (domain %04x %pR)\n",
acpi_device_name(device), acpi_device_bid(device),
root->segment, &root->secondary);
- root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle);
+ root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);
/*
* All supported architectures that use ACPI have support for
@@ -446,10 +441,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
* TBD: Need PCI interface for enumeration/configuration of roots.
*/
- mutex_lock(&acpi_pci_root_lock);
- list_add_tail(&root->node, &acpi_pci_roots);
- mutex_unlock(&acpi_pci_root_lock);
-
/*
* Scan the Root Bridge
* --------------------
@@ -459,11 +450,11 @@ static int acpi_pci_root_add(struct acpi_device *device,
*/
root->bus = pci_acpi_scan_root(root);
if (!root->bus) {
- printk(KERN_ERR PREFIX
- "Bus %04x:%02x not present in PCI namespace\n",
- root->segment, (unsigned int)root->secondary.start);
+ dev_err(&device->dev,
+ "Bus %04x:%02x not present in PCI namespace\n",
+ root->segment, (unsigned int)root->secondary.start);
result = -ENODEV;
- goto out_del_root;
+ goto end;
}
/* Indicate support for various _OSC capabilities. */
@@ -502,7 +493,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
dev_info(&device->dev,
"Requesting ACPI _OSC control (0x%02x)\n", flags);
- status = acpi_pci_osc_control_set(device->handle, &flags,
+ status = acpi_pci_osc_control_set(handle, &flags,
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
if (ACPI_SUCCESS(status)) {
dev_info(&device->dev,
@@ -519,8 +510,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
"ACPI _OSC request failed (%s), "
"returned control mask: 0x%02x\n",
acpi_format_exception(status), flags);
- pr_info("ACPI _OSC control for PCIe not granted, "
- "disabling ASPM\n");
+ dev_info(&device->dev,
+ "ACPI _OSC control for PCIe not granted, disabling ASPM\n");
pcie_no_aspm();
}
} else {
@@ -536,20 +527,14 @@ static int acpi_pci_root_add(struct acpi_device *device,
if (system_state != SYSTEM_BOOTING) {
pcibios_resource_survey_bus(root->bus);
pci_assign_unassigned_bus_resources(root->bus);
- }
- /* need to after hot-added ioapic is registered */
- if (system_state != SYSTEM_BOOTING)
+ /* need to after hot-added ioapic is registered */
pci_enable_bridges(root->bus);
+ }
pci_bus_add_devices(root->bus);
return 1;
-out_del_root:
- mutex_lock(&acpi_pci_root_lock);
- list_del(&root->node);
- mutex_unlock(&acpi_pci_root_lock);
-
end:
kfree(root);
return result;
@@ -566,9 +551,6 @@ static void acpi_pci_root_remove(struct acpi_device *device)
pci_remove_root_bus(root->bus);
- mutex_lock(&acpi_pci_root_lock);
- list_del(&root->node);
- mutex_unlock(&acpi_pci_root_lock);
kfree(root);
}
@@ -588,12 +570,13 @@ static void handle_root_bridge_insertion(acpi_handle handle)
struct acpi_device *device;
if (!acpi_bus_get_device(handle, &device)) {
- printk(KERN_DEBUG "acpi device exists...\n");
+ dev_printk(KERN_DEBUG, &device->dev,
+ "acpi device already exists; ignoring notify\n");
return;
}
if (acpi_bus_scan(handle))
- printk(KERN_ERR "cannot add bridge to acpi list\n");
+ acpi_handle_err(handle, "cannot add bridge to acpi list\n");
}
static void handle_root_bridge_removal(struct acpi_device *device)
@@ -622,7 +605,6 @@ static void handle_root_bridge_removal(struct acpi_device *device)
static void _handle_hotplug_event_root(struct work_struct *work)
{
struct acpi_pci_root *root;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
struct acpi_hp_work *hp_work;
acpi_handle handle;
u32 type;
@@ -634,13 +616,12 @@ static void _handle_hotplug_event_root(struct work_struct *work)
acpi_scan_lock_acquire();
root = acpi_pci_find_root(handle);
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* bus enumerate */
- printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
- (char *)buffer.pointer);
+ acpi_handle_printk(KERN_DEBUG, handle,
+ "Bus check notify on %s\n", __func__);
if (root)
acpiphp_check_host_bridge(handle);
else
@@ -650,28 +631,28 @@ static void _handle_hotplug_event_root(struct work_struct *work)
case ACPI_NOTIFY_DEVICE_CHECK:
/* device check */
- printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
- (char *)buffer.pointer);
+ acpi_handle_printk(KERN_DEBUG, handle,
+ "Device check notify on %s\n", __func__);
if (!root)
handle_root_bridge_insertion(handle);
break;
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
- printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
- (char *)buffer.pointer);
+ acpi_handle_printk(KERN_DEBUG, handle,
+ "Device eject notify on %s\n", __func__);
if (root)
handle_root_bridge_removal(root->device);
break;
default:
- printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
- type, (char *)buffer.pointer);
+ acpi_handle_warn(handle,
+ "notify_handler: unknown event type 0x%x\n",
+ type);
break;
}
acpi_scan_lock_release();
kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
- kfree(buffer.pointer);
}
static void handle_hotplug_event_root(acpi_handle handle, u32 type,
@@ -685,9 +666,6 @@ static acpi_status __init
find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
int *count = (int *)context;
if (!acpi_is_root_bridge(handle))
@@ -695,16 +673,15 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
(*count)++;
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_root, NULL);
if (ACPI_FAILURE(status))
- printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n",
- objname, (unsigned int)status);
+ acpi_handle_printk(KERN_DEBUG, handle,
+ "notify handler is not installed, exit status: %u\n",
+ (unsigned int)status);
else
- printk(KERN_DEBUG "acpi root: %s notify handler is installed\n",
- objname);
+ acpi_handle_printk(KERN_DEBUG, handle,
+ "notify handler is installed\n");
return AE_OK;
}
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 288bb270f8ed..5c28c894c0fc 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -279,7 +279,7 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
if (resource->ref_count++) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Power resource [%s] already on",
+ "Power resource [%s] already on\n",
resource->name));
} else {
result = __acpi_power_on(resource);
@@ -325,7 +325,7 @@ static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
if (!resource->ref_count) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Power resource [%s] already off",
+ "Power resource [%s] already off\n",
resource->name));
return 0;
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index c266cdc11784..823be116619e 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -1,11 +1,13 @@
/*
- * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $)
+ * processor_driver.c - ACPI Processor Driver
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
* Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
* Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
* - Added processor hotplug support
+ * Copyright (C) 2013, Intel Corporation
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -24,55 +26,26 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * TBD:
- * 1. Make # power states dynamic.
- * 2. Support duty_cycle values that span bit 4.
- * 3. Optimize by having scheduler determine business instead of
- * having us try to calculate it here.
- * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
#include <linux/cpufreq.h>
#include <linux/cpu.h>
-#include <linux/dmi.h>
-#include <linux/moduleparam.h>
#include <linux/cpuidle.h>
#include <linux/slab.h>
#include <linux/acpi.h>
-#include <linux/memory_hotplug.h>
-
-#include <asm/io.h>
-#include <asm/cpu.h>
-#include <asm/delay.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-#include <asm/smp.h>
-#include <asm/acpi.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+
#include <acpi/processor.h>
+#include "internal.h"
+
#define PREFIX "ACPI: "
-#define ACPI_PROCESSOR_CLASS "processor"
-#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
-#define ACPI_PROCESSOR_FILE_INFO "info"
-#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
-#define ACPI_PROCESSOR_FILE_LIMIT "limit"
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
-#define ACPI_PROCESSOR_DEVICE_HID "ACPI0007"
-
-#define ACPI_PROCESSOR_LIMIT_USER 0
-#define ACPI_PROCESSOR_LIMIT_THERMAL 1
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_driver");
@@ -81,12 +54,8 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
-static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_remove(struct acpi_device *device);
-static void acpi_processor_notify(struct acpi_device *device, u32 event);
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
-static int acpi_processor_handle_eject(struct acpi_processor *pr);
-static int acpi_processor_start(struct acpi_processor *pr);
+static int acpi_processor_start(struct device *dev);
+static int acpi_processor_stop(struct device *dev);
static const struct acpi_device_id processor_device_ids[] = {
{ACPI_PROCESSOR_OBJECT_HID, 0},
@@ -95,295 +64,24 @@ static const struct acpi_device_id processor_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, processor_device_ids);
-static struct acpi_driver acpi_processor_driver = {
+static struct device_driver acpi_processor_driver = {
.name = "processor",
- .class = ACPI_PROCESSOR_CLASS,
- .ids = processor_device_ids,
- .ops = {
- .add = acpi_processor_add,
- .remove = acpi_processor_remove,
- .notify = acpi_processor_notify,
- },
+ .bus = &cpu_subsys,
+ .acpi_match_table = processor_device_ids,
+ .probe = acpi_processor_start,
+ .remove = acpi_processor_stop,
};
-#define INSTALL_NOTIFY_HANDLER 1
-#define UNINSTALL_NOTIFY_HANDLER 2
-
-DEFINE_PER_CPU(struct acpi_processor *, processors);
-EXPORT_PER_CPU_SYMBOL(processors);
-
-struct acpi_processor_errata errata __read_mostly;
-
-/* --------------------------------------------------------------------------
- Errata Handling
- -------------------------------------------------------------------------- */
-
-static int acpi_processor_errata_piix4(struct pci_dev *dev)
-{
- u8 value1 = 0;
- u8 value2 = 0;
-
-
- if (!dev)
- return -EINVAL;
-
- /*
- * Note that 'dev' references the PIIX4 ACPI Controller.
- */
-
- switch (dev->revision) {
- case 0:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
- break;
- case 1:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
- break;
- case 2:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
- break;
- case 3:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
- break;
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
- break;
- }
-
- switch (dev->revision) {
-
- case 0: /* PIIX4 A-step */
- case 1: /* PIIX4 B-step */
- /*
- * See specification changes #13 ("Manual Throttle Duty Cycle")
- * and #14 ("Enabling and Disabling Manual Throttle"), plus
- * erratum #5 ("STPCLK# Deassertion Time") from the January
- * 2002 PIIX4 specification update. Applies to only older
- * PIIX4 models.
- */
- errata.piix4.throttle = 1;
-
- case 2: /* PIIX4E */
- case 3: /* PIIX4M */
- /*
- * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
- * Livelock") from the January 2002 PIIX4 specification update.
- * Applies to all PIIX4 models.
- */
-
- /*
- * BM-IDE
- * ------
- * Find the PIIX4 IDE Controller and get the Bus Master IDE
- * Status register address. We'll use this later to read
- * each IDE controller's DMA status to make sure we catch all
- * DMA activity.
- */
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB,
- PCI_ANY_ID, PCI_ANY_ID, NULL);
- if (dev) {
- errata.piix4.bmisx = pci_resource_start(dev, 4);
- pci_dev_put(dev);
- }
-
- /*
- * Type-F DMA
- * ----------
- * Find the PIIX4 ISA Controller and read the Motherboard
- * DMA controller's status to see if Type-F (Fast) DMA mode
- * is enabled (bit 7) on either channel. Note that we'll
- * disable C3 support if this is enabled, as some legacy
- * devices won't operate well if fast DMA is disabled.
- */
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_0,
- PCI_ANY_ID, PCI_ANY_ID, NULL);
- if (dev) {
- pci_read_config_byte(dev, 0x76, &value1);
- pci_read_config_byte(dev, 0x77, &value2);
- if ((value1 & 0x80) || (value2 & 0x80))
- errata.piix4.fdma = 1;
- pci_dev_put(dev);
- }
-
- break;
- }
-
- if (errata.piix4.bmisx)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Bus master activity detection (BM-IDE) erratum enabled\n"));
- if (errata.piix4.fdma)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Type-F DMA livelock erratum (C3 disabled)\n"));
-
- return 0;
-}
-
-static int acpi_processor_errata(struct acpi_processor *pr)
+static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
- int result = 0;
- struct pci_dev *dev = NULL;
-
-
- if (!pr)
- return -EINVAL;
-
- /*
- * PIIX4
- */
- dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
- PCI_ANY_ID, NULL);
- if (dev) {
- result = acpi_processor_errata_piix4(dev);
- pci_dev_put(dev);
- }
-
- return result;
-}
-
-/* --------------------------------------------------------------------------
- Driver Interface
- -------------------------------------------------------------------------- */
-
-static int acpi_processor_get_info(struct acpi_device *device)
-{
- acpi_status status = 0;
- union acpi_object object = { 0 };
- struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+ struct acpi_device *device = data;
struct acpi_processor *pr;
- int cpu_index, device_declaration = 0;
- static int cpu0_initialized;
-
- pr = acpi_driver_data(device);
- if (!pr)
- return -EINVAL;
-
- if (num_online_cpus() > 1)
- errata.smp = TRUE;
-
- acpi_processor_errata(pr);
-
- /*
- * Check to see if we have bus mastering arbitration control. This
- * is required for proper C3 usage (to maintain cache coherency).
- */
- if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
- pr->flags.bm_control = 1;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Bus mastering arbitration control present\n"));
- } else
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "No bus mastering arbitration control\n"));
-
- if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
- /* Declared with "Processor" statement; match ProcessorID */
- status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- dev_err(&device->dev,
- "Failed to evaluate processor object (0x%x)\n",
- status);
- return -ENODEV;
- }
-
- /*
- * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
- * >>> 'acpi_get_processor_id(acpi_id, &id)' in
- * arch/xxx/acpi.c
- */
- pr->acpi_id = object.processor.proc_id;
- } else {
- /*
- * Declared with "Device" statement; match _UID.
- * Note that we don't handle string _UIDs yet.
- */
- unsigned long long value;
- status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
- NULL, &value);
- if (ACPI_FAILURE(status)) {
- dev_err(&device->dev,
- "Failed to evaluate processor _UID (0x%x)\n",
- status);
- return -ENODEV;
- }
- device_declaration = 1;
- pr->acpi_id = value;
- }
- cpu_index = acpi_get_cpuid(pr->handle, device_declaration, pr->acpi_id);
-
- /* Handle UP system running SMP kernel, with no LAPIC in MADT */
- if (!cpu0_initialized && (cpu_index == -1) &&
- (num_online_cpus() == 1)) {
- cpu_index = 0;
- }
-
- cpu0_initialized = 1;
-
- 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 (ACPI_FAILURE(acpi_processor_hotadd_init(pr)))
- return -ENODEV;
- }
- /*
- * On some boxes several processors use the same processor bus id.
- * But they are located in different scope. For example:
- * \_SB.SCK0.CPU0
- * \_SB.SCK1.CPU0
- * Rename the processor device bus id. And the new bus id will be
- * generated as the following format:
- * CPU+CPU ID.
- */
- sprintf(acpi_device_bid(device), "CPU%X", pr->id);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
- pr->acpi_id));
-
- if (!object.processor.pblk_address)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
- else if (object.processor.pblk_length != 6)
- dev_err(&device->dev, "Invalid PBLK length [%d]\n",
- object.processor.pblk_length);
- else {
- pr->throttling.address = object.processor.pblk_address;
- pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
- pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
-
- pr->pblk = object.processor.pblk_address;
-
- /*
- * We don't care about error returns - we just try to mark
- * these reserved so that nobody else is confused into thinking
- * that this region might be unused..
- *
- * (In particular, allocating the IO range for Cardbus)
- */
- request_region(pr->throttling.address, 6, "ACPI CPU throttle");
- }
-
- /*
- * If ACPI describes a slot number for this CPU, we can use it
- * ensure we get the right value in the "physical id" field
- * of /proc/cpuinfo
- */
- status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
- if (ACPI_SUCCESS(status))
- arch_fix_phys_package_id(pr->id, object.integer.value);
-
- return 0;
-}
-
-static DEFINE_PER_CPU(void *, processor_device_array);
-
-static void acpi_processor_notify(struct acpi_device *device, u32 event)
-{
- struct acpi_processor *pr = acpi_driver_data(device);
int saved;
+ if (device->handle != handle)
+ return;
+
+ pr = acpi_driver_data(device);
if (!pr)
return;
@@ -420,55 +118,62 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event)
return;
}
-static int acpi_cpu_soft_notify(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static __cpuinit int __acpi_processor_start(struct acpi_device *device);
+
+static int __cpuinit acpi_cpu_soft_notify(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
struct acpi_processor *pr = per_cpu(processors, cpu);
+ struct acpi_device *device;
+
+ if (!pr || acpi_bus_get_device(pr->handle, &device))
+ return NOTIFY_DONE;
- if (action == CPU_ONLINE && pr) {
- /* CPU got physically hotplugged and onlined the first time:
- * Initialize missing things
+ if (action == CPU_ONLINE) {
+ /*
+ * CPU got physically hotplugged and onlined for the first time:
+ * Initialize missing things.
*/
if (pr->flags.need_hotplug_init) {
+ int ret;
+
pr_info("Will online and init hotplugged CPU: %d\n",
pr->id);
- WARN(acpi_processor_start(pr), "Failed to start CPU:"
- " %d\n", pr->id);
pr->flags.need_hotplug_init = 0;
- /* Normal CPU soft online event */
+ ret = __acpi_processor_start(device);
+ WARN(ret, "Failed to start CPU: %d\n", pr->id);
} else {
+ /* Normal CPU soft online event. */
acpi_processor_ppc_has_changed(pr, 0);
acpi_processor_hotplug(pr);
acpi_processor_reevaluate_tstate(pr, action);
acpi_processor_tstate_has_changed(pr);
}
- }
- if (action == CPU_DEAD && pr) {
- /* invalidate the flag.throttling after one CPU is offline */
+ } else if (action == CPU_DEAD) {
+ /* Invalidate flag.throttling after the CPU is offline. */
acpi_processor_reevaluate_tstate(pr, action);
}
return NOTIFY_OK;
}
-static struct notifier_block acpi_cpu_notifier =
+static struct notifier_block __refdata acpi_cpu_notifier =
{
.notifier_call = acpi_cpu_soft_notify,
};
-/*
- * acpi_processor_start() is called by the cpu_hotplug_notifier func:
- * acpi_cpu_soft_notify(). Getting it __cpuinit{data} is difficult, the
- * root cause seem to be that acpi_processor_uninstall_hotplug_notify()
- * is in the module_exit (__exit) func. Allowing acpi_processor_start()
- * to not be in __cpuinit section, but being called from __cpuinit funcs
- * via __ref looks like the right thing to do here.
- */
-static __ref int acpi_processor_start(struct acpi_processor *pr)
+static __cpuinit int __acpi_processor_start(struct acpi_device *device)
{
- struct acpi_device *device = per_cpu(processor_device_array, pr->id);
+ struct acpi_processor *pr = acpi_driver_data(device);
+ acpi_status status;
int result = 0;
+ if (!pr)
+ return -ENODEV;
+
+ if (pr->flags.need_hotplug_init)
+ return 0;
+
#ifdef CONFIG_CPU_FREQ
acpi_processor_ppc_has_changed(pr, 0);
acpi_processor_load_module(pr);
@@ -506,462 +211,95 @@ static __ref int acpi_processor_start(struct acpi_processor *pr)
goto err_remove_sysfs_thermal;
}
- return 0;
+ status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+ acpi_processor_notify, device);
+ if (ACPI_SUCCESS(status))
+ return 0;
-err_remove_sysfs_thermal:
+ sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ err_remove_sysfs_thermal:
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
-err_thermal_unregister:
+ err_thermal_unregister:
thermal_cooling_device_unregister(pr->cdev);
-err_power_exit:
+ err_power_exit:
acpi_processor_power_exit(pr);
-
return result;
}
-/*
- * Do not put anything in here which needs the core to be online.
- * For example MSR access or setting up things which check for cpuinfo_x86
- * (cpu_data(cpu)) values, like CPU feature flags, family, model, etc.
- * Such things have to be put in and set up above in acpi_processor_start()
- */
-static int __cpuinit acpi_processor_add(struct acpi_device *device)
+static int __cpuinit acpi_processor_start(struct device *dev)
{
- struct acpi_processor *pr = NULL;
- int result = 0;
- struct device *dev;
-
- pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
- if (!pr)
- return -ENOMEM;
-
- if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
- result = -ENOMEM;
- goto err_free_pr;
- }
-
- pr->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
- device->driver_data = pr;
-
- result = acpi_processor_get_info(device);
- if (result) {
- /* Processor is physically not present */
- return 0;
- }
+ struct acpi_device *device;
-#ifdef CONFIG_SMP
- if (pr->id >= setup_max_cpus && pr->id != 0)
- return 0;
-#endif
-
- BUG_ON(pr->id >= nr_cpu_ids);
-
- /*
- * Buggy BIOS check
- * ACPI id of processors can be reported wrongly by the BIOS.
- * Don't trust it blindly
- */
- if (per_cpu(processor_device_array, pr->id) != NULL &&
- per_cpu(processor_device_array, pr->id) != device) {
- dev_warn(&device->dev,
- "BIOS reported wrong ACPI id %d for the processor\n",
- pr->id);
- result = -ENODEV;
- goto err_free_cpumask;
- }
- per_cpu(processor_device_array, pr->id) = device;
+ if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
+ return -ENODEV;
- per_cpu(processors, pr->id) = pr;
-
- dev = get_cpu_device(pr->id);
- if (sysfs_create_link(&device->dev.kobj, &dev->kobj, "sysdev")) {
- result = -EFAULT;
- goto err_clear_processor;
- }
-
- /*
- * Do not start hotplugged CPUs now, but when they
- * are onlined the first time
- */
- if (pr->flags.need_hotplug_init)
- return 0;
-
- result = acpi_processor_start(pr);
- if (result)
- goto err_remove_sysfs;
-
- return 0;
-
-err_remove_sysfs:
- sysfs_remove_link(&device->dev.kobj, "sysdev");
-err_clear_processor:
- /*
- * processor_device_array is not cleared to allow checks for buggy BIOS
- */
- per_cpu(processors, pr->id) = NULL;
-err_free_cpumask:
- free_cpumask_var(pr->throttling.shared_cpu_map);
-err_free_pr:
- kfree(pr);
- return result;
+ return __acpi_processor_start(device);
}
-static int acpi_processor_remove(struct acpi_device *device)
+static int acpi_processor_stop(struct device *dev)
{
- struct acpi_processor *pr = NULL;
+ struct acpi_device *device;
+ struct acpi_processor *pr;
+ if (acpi_bus_get_device(ACPI_HANDLE(dev), &device))
+ return 0;
- if (!device || !acpi_driver_data(device))
- return -EINVAL;
+ acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+ acpi_processor_notify);
pr = acpi_driver_data(device);
-
- if (pr->id >= nr_cpu_ids)
- goto free;
-
- if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) {
- if (acpi_processor_handle_eject(pr))
- return -EINVAL;
- }
+ if (!pr)
+ return 0;
acpi_processor_power_exit(pr);
- sysfs_remove_link(&device->dev.kobj, "sysdev");
-
if (pr->cdev) {
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
thermal_cooling_device_unregister(pr->cdev);
pr->cdev = NULL;
}
-
- per_cpu(processors, pr->id) = NULL;
- per_cpu(processor_device_array, pr->id) = NULL;
- try_offline_node(cpu_to_node(pr->id));
-
-free:
- free_cpumask_var(pr->throttling.shared_cpu_map);
- kfree(pr);
-
return 0;
}
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
-/****************************************************************************
- * Acpi processor hotplug support *
- ****************************************************************************/
-
-static int is_processor_present(acpi_handle handle)
-{
- acpi_status status;
- unsigned long long sta = 0;
-
-
- status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
-
- if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
- return 1;
-
- /*
- * _STA is mandatory for a processor that supports hot plug
- */
- if (status == AE_NOT_FOUND)
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Processor does not support hot plug\n"));
- else
- ACPI_EXCEPTION((AE_INFO, status,
- "Processor Device is not present"));
- return 0;
-}
-
-static void acpi_processor_hotplug_notify(acpi_handle handle,
- u32 event, void *data)
-{
- struct acpi_device *device = NULL;
- struct acpi_eject_event *ej_event = NULL;
- u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
- acpi_status status;
- int result;
-
- acpi_scan_lock_acquire();
-
- switch (event) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Processor driver received %s event\n",
- (event == ACPI_NOTIFY_BUS_CHECK) ?
- "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
-
- if (!is_processor_present(handle))
- break;
-
- if (!acpi_bus_get_device(handle, &device))
- break;
-
- result = acpi_bus_scan(handle);
- if (result) {
- acpi_handle_err(handle, "Unable to add the device\n");
- break;
- }
- result = acpi_bus_get_device(handle, &device);
- if (result) {
- acpi_handle_err(handle, "Missing device object\n");
- break;
- }
- ost_code = ACPI_OST_SC_SUCCESS;
- break;
-
- case ACPI_NOTIFY_EJECT_REQUEST:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "received ACPI_NOTIFY_EJECT_REQUEST\n"));
-
- if (acpi_bus_get_device(handle, &device)) {
- acpi_handle_err(handle,
- "Device don't exist, dropping EJECT\n");
- break;
- }
- if (!acpi_driver_data(device)) {
- acpi_handle_err(handle,
- "Driver data is NULL, dropping EJECT\n");
- break;
- }
-
- ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
- if (!ej_event) {
- acpi_handle_err(handle, "No memory, dropping EJECT\n");
- break;
- }
-
- get_device(&device->dev);
- ej_event->device = device;
- ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- /* The eject is carried out asynchronously. */
- status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- ej_event);
- if (ACPI_FAILURE(status)) {
- put_device(&device->dev);
- kfree(ej_event);
- break;
- }
- goto out;
-
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Unsupported event [0x%x]\n", event));
-
- /* non-hotplug event; possibly handled by other handler */
- goto out;
- }
-
- /* Inform firmware that the hotplug operation has completed */
- (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
-
- out:
- acpi_scan_lock_release();
-}
-
-static acpi_status is_processor_device(acpi_handle handle)
-{
- struct acpi_device_info *info;
- char *hid;
- acpi_status status;
-
- status = acpi_get_object_info(handle, &info);
- if (ACPI_FAILURE(status))
- return status;
-
- if (info->type == ACPI_TYPE_PROCESSOR) {
- kfree(info);
- return AE_OK; /* found a processor object */
- }
-
- if (!(info->valid & ACPI_VALID_HID)) {
- kfree(info);
- return AE_ERROR;
- }
-
- hid = info->hardware_id.string;
- if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) {
- kfree(info);
- return AE_ERROR;
- }
-
- kfree(info);
- return AE_OK; /* found a processor device object */
-}
-
-static acpi_status
-processor_walk_namespace_cb(acpi_handle handle,
- u32 lvl, void *context, void **rv)
-{
- acpi_status status;
- int *action = context;
-
- status = is_processor_device(handle);
- if (ACPI_FAILURE(status))
- return AE_OK; /* not a processor; continue to walk */
-
- switch (*action) {
- case INSTALL_NOTIFY_HANDLER:
- acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_processor_hotplug_notify,
- NULL);
- break;
- case UNINSTALL_NOTIFY_HANDLER:
- acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- acpi_processor_hotplug_notify);
- break;
- default:
- break;
- }
-
- /* found a processor; skip walking underneath */
- return AE_CTRL_DEPTH;
-}
-
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
-{
- acpi_handle handle = pr->handle;
-
- if (!is_processor_present(handle)) {
- return AE_ERROR;
- }
-
- if (acpi_map_lsapic(handle, &pr->id))
- return AE_ERROR;
-
- if (arch_register_cpu(pr->id)) {
- acpi_unmap_lsapic(pr->id);
- return AE_ERROR;
- }
-
- /* CPU got hot-plugged, but cpu_data is not initialized yet
- * Set flag to delay cpu_idle/throttling initialization
- * in:
- * acpi_processor_add()
- * acpi_processor_get_info()
- * and do it when the CPU gets online the first time
- * TBD: Cleanup above functions and try to do this more elegant.
- */
- pr_info("CPU %d got hotplugged\n", pr->id);
- pr->flags.need_hotplug_init = 1;
-
- return AE_OK;
-}
-
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
-{
- if (cpu_online(pr->id))
- cpu_down(pr->id);
-
- get_online_cpus();
- /*
- * The cpu might become online again at this point. So we check whether
- * the cpu has been onlined or not. If the cpu became online, it means
- * that someone wants to use the cpu. So acpi_processor_handle_eject()
- * returns -EAGAIN.
- */
- if (unlikely(cpu_online(pr->id))) {
- put_online_cpus();
- pr_warn("Failed to remove CPU %d, because other task "
- "brought the CPU back online\n", pr->id);
- return -EAGAIN;
- }
- arch_unregister_cpu(pr->id);
- acpi_unmap_lsapic(pr->id);
- put_online_cpus();
- return (0);
-}
-#else
-static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
-{
- return AE_ERROR;
-}
-static int acpi_processor_handle_eject(struct acpi_processor *pr)
-{
- return (-EINVAL);
-}
-#endif
-
-static
-void acpi_processor_install_hotplug_notify(void)
-{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
- int action = INSTALL_NOTIFY_HANDLER;
- acpi_walk_namespace(ACPI_TYPE_ANY,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
- register_hotcpu_notifier(&acpi_cpu_notifier);
-}
-
-static
-void acpi_processor_uninstall_hotplug_notify(void)
-{
-#ifdef CONFIG_ACPI_HOTPLUG_CPU
- int action = UNINSTALL_NOTIFY_HANDLER;
- acpi_walk_namespace(ACPI_TYPE_ANY,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- processor_walk_namespace_cb, NULL, &action, NULL);
-#endif
- unregister_hotcpu_notifier(&acpi_cpu_notifier);
-}
-
/*
* We keep the driver loaded even when ACPI is not running.
* This is needed for the powernow-k8 driver, that works even without
* ACPI, but needs symbols from this driver
*/
-static int __init acpi_processor_init(void)
+static int __init acpi_processor_driver_init(void)
{
int result = 0;
if (acpi_disabled)
return 0;
- result = acpi_bus_register_driver(&acpi_processor_driver);
+ result = driver_register(&acpi_processor_driver);
if (result < 0)
return result;
acpi_processor_syscore_init();
-
- acpi_processor_install_hotplug_notify();
-
+ register_hotcpu_notifier(&acpi_cpu_notifier);
acpi_thermal_cpufreq_init();
-
acpi_processor_ppc_init();
-
acpi_processor_throttling_init();
-
return 0;
}
-static void __exit acpi_processor_exit(void)
+static void __exit acpi_processor_driver_exit(void)
{
if (acpi_disabled)
return;
acpi_processor_ppc_exit();
-
acpi_thermal_cpufreq_exit();
-
- acpi_processor_uninstall_hotplug_notify();
-
+ unregister_hotcpu_notifier(&acpi_cpu_notifier);
acpi_processor_syscore_exit();
-
- acpi_bus_unregister_driver(&acpi_processor_driver);
-
- return;
+ driver_unregister(&acpi_processor_driver);
}
-module_init(acpi_processor_init);
-module_exit(acpi_processor_exit);
+module_init(acpi_processor_driver_init);
+module_exit(acpi_processor_driver_exit);
MODULE_ALIAS("processor");
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index eb133c77aadb..0461ccc92c54 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -214,13 +214,13 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr,
#ifdef CONFIG_PM_SLEEP
static u32 saved_bm_rld;
-int acpi_processor_suspend(void)
+static int acpi_processor_suspend(void)
{
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_RLD, &saved_bm_rld);
return 0;
}
-void acpi_processor_resume(void)
+static void acpi_processor_resume(void)
{
u32 resumed_bm_rld;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index e854582f29a6..1e9732d809bf 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -639,7 +639,7 @@ end:
int acpi_processor_preregister_performance(
struct acpi_processor_performance __percpu *performance)
{
- int count, count_target;
+ int count_target;
int retval = 0;
unsigned int i, j;
cpumask_var_t covered_cpus;
@@ -711,7 +711,6 @@ int acpi_processor_preregister_performance(
/* Validate the Domain info */
count_target = pdomain->num_processors;
- count = 1;
if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
@@ -745,7 +744,6 @@ int acpi_processor_preregister_performance(
cpumask_set_cpu(j, covered_cpus);
cpumask_set_cpu(j, pr->performance->shared_cpu_map);
- count++;
}
for_each_possible_cpu(j) {
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 27da63061e11..10985573aaa7 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -27,9 +27,14 @@ extern struct acpi_device *acpi_root;
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
+/*
+ * If set, devices will be hot-removed even if they cannot be put offline
+ * gracefully (from the kernel's standpoint).
+ */
+bool acpi_force_hot_remove;
+
static const char *dummy_hid = "device";
-static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
@@ -120,12 +125,78 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
+static acpi_status acpi_bus_offline_companions(acpi_handle handle, u32 lvl,
+ void *data, void **ret_p)
+{
+ struct acpi_device *device = NULL;
+ struct acpi_device_physical_node *pn;
+ bool second_pass = (bool)data;
+ acpi_status status = AE_OK;
+
+ if (acpi_bus_get_device(handle, &device))
+ return AE_OK;
+
+ mutex_lock(&device->physical_node_lock);
+
+ list_for_each_entry(pn, &device->physical_node_list, node) {
+ int ret;
+
+ if (second_pass) {
+ /* Skip devices offlined by the first pass. */
+ if (pn->put_online)
+ continue;
+ } else {
+ pn->put_online = false;
+ }
+ ret = device_offline(pn->dev);
+ if (acpi_force_hot_remove)
+ continue;
+
+ if (ret >= 0) {
+ pn->put_online = !ret;
+ } else {
+ *ret_p = pn->dev;
+ if (second_pass) {
+ status = AE_ERROR;
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&device->physical_node_lock);
+
+ return status;
+}
+
+static acpi_status acpi_bus_online_companions(acpi_handle handle, u32 lvl,
+ void *data, void **ret_p)
+{
+ struct acpi_device *device = NULL;
+ struct acpi_device_physical_node *pn;
+
+ if (acpi_bus_get_device(handle, &device))
+ return AE_OK;
+
+ mutex_lock(&device->physical_node_lock);
+
+ list_for_each_entry(pn, &device->physical_node_list, node)
+ if (pn->put_online) {
+ device_online(pn->dev);
+ pn->put_online = false;
+ }
+
+ mutex_unlock(&device->physical_node_lock);
+
+ return AE_OK;
+}
+
static int acpi_scan_hot_remove(struct acpi_device *device)
{
acpi_handle handle = device->handle;
acpi_handle not_used;
struct acpi_object_list arg_list;
union acpi_object arg;
+ struct device *errdev;
acpi_status status;
unsigned long long sta;
@@ -136,10 +207,53 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
return -EINVAL;
}
+ lock_device_hotplug();
+
+ /*
+ * Carry out two passes here and ignore errors in the first pass,
+ * because if the devices in question are memory blocks and
+ * CONFIG_MEMCG is set, one of the blocks may hold data structures
+ * that the other blocks depend on, but it is not known in advance which
+ * block holds them.
+ *
+ * If the first pass is successful, the second one isn't needed, though.
+ */
+ errdev = NULL;
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+ NULL, acpi_bus_offline_companions,
+ (void *)false, (void **)&errdev);
+ acpi_bus_offline_companions(handle, 0, (void *)false, (void **)&errdev);
+ if (errdev) {
+ errdev = NULL;
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+ NULL, acpi_bus_offline_companions,
+ (void *)true , (void **)&errdev);
+ if (!errdev || acpi_force_hot_remove)
+ acpi_bus_offline_companions(handle, 0, (void *)true,
+ (void **)&errdev);
+
+ if (errdev && !acpi_force_hot_remove) {
+ dev_warn(errdev, "Offline failed.\n");
+ acpi_bus_online_companions(handle, 0, NULL, NULL);
+ acpi_walk_namespace(ACPI_TYPE_ANY, handle,
+ ACPI_UINT32_MAX,
+ acpi_bus_online_companions, NULL,
+ NULL, NULL);
+
+ unlock_device_hotplug();
+
+ put_device(&device->dev);
+ return -EBUSY;
+ }
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Hot-removing device %s...\n", dev_name(&device->dev)));
acpi_bus_trim(device);
+
+ unlock_device_hotplug();
+
/* Device node has been unregistered. */
put_device(&device->dev);
device = NULL;
@@ -236,6 +350,7 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
int error;
mutex_lock(&acpi_scan_lock);
+ lock_device_hotplug();
acpi_bus_get_device(handle, &device);
if (device) {
@@ -259,6 +374,7 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
out:
+ unlock_device_hotplug();
acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
mutex_unlock(&acpi_scan_lock);
}
@@ -816,32 +932,43 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
acpi_device_notify);
}
-static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
-static int acpi_device_probe(struct device * dev)
+static int acpi_device_probe(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
int ret;
- ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
- if (!ret) {
- if (acpi_drv->ops.notify) {
- ret = acpi_device_install_notify_handler(acpi_dev);
- if (ret) {
- if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev);
- acpi_dev->driver = NULL;
- acpi_dev->driver_data = NULL;
- return ret;
- }
- }
+ if (acpi_dev->handler)
+ return -EINVAL;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Found driver [%s] for device [%s]\n",
- acpi_drv->name, acpi_dev->pnp.bus_id));
- get_device(dev);
+ if (!acpi_drv->ops.add)
+ return -ENOSYS;
+
+ ret = acpi_drv->ops.add(acpi_dev);
+ if (ret)
+ return ret;
+
+ acpi_dev->driver = acpi_drv;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Driver [%s] successfully bound to device [%s]\n",
+ acpi_drv->name, acpi_dev->pnp.bus_id));
+
+ if (acpi_drv->ops.notify) {
+ ret = acpi_device_install_notify_handler(acpi_dev);
+ if (ret) {
+ if (acpi_drv->ops.remove)
+ acpi_drv->ops.remove(acpi_dev);
+
+ acpi_dev->driver = NULL;
+ acpi_dev->driver_data = NULL;
+ return ret;
+ }
}
- return ret;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
+ acpi_drv->name, acpi_dev->pnp.bus_id));
+ get_device(dev);
+ return 0;
}
static int acpi_device_remove(struct device * dev)
@@ -952,7 +1079,6 @@ int acpi_device_add(struct acpi_device *device,
printk(KERN_ERR PREFIX "Error creating sysfs interface for device %s\n",
dev_name(&device->dev));
- device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
return 0;
err:
@@ -998,41 +1124,6 @@ static void acpi_device_unregister(struct acpi_device *device)
Driver Management
-------------------------------------------------------------------------- */
/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver. Called whenever a
- * driver is bound to a device. Invokes the driver's add() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
- int result = 0;
-
- if (!device || !driver)
- return -EINVAL;
-
- if (!driver->ops.add)
- return -ENOSYS;
-
- result = driver->ops.add(device);
- if (result)
- return result;
-
- device->driver = driver;
-
- /*
- * TBD - Configuration Management: Assign resources to device based
- * upon possible configuration and currently allocated resources.
- */
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Driver successfully bound to device\n"));
- return 0;
-}
-
-/**
* acpi_bus_register_driver - register a driver with the ACPI bus
* @driver: driver being registered
*
@@ -1939,7 +2030,6 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
if (!acpi_bus_get_device(handle, &device)) {
struct acpi_scan_handler *dev_handler = device->handler;
- device->removal_type = ACPI_BUS_REMOVAL_EJECT;
if (dev_handler) {
if (dev_handler->detach)
dev_handler->detach(device);
@@ -2038,8 +2128,10 @@ int __init acpi_scan_init(void)
acpi_pci_root_init();
acpi_pci_link_init();
+ acpi_processor_init();
acpi_platform_init();
acpi_lpss_init();
+ acpi_cmos_rtc_init();
acpi_container_init();
acpi_memory_hotplug_init();
acpi_dock_init();
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 9c1a435d10e6..187ab61889e6 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -494,6 +494,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
break;
case ACPI_STATE_S3:
+ if (!acpi_suspend_lowlevel)
+ return -ENOSYS;
error = acpi_suspend_lowlevel();
if (error)
return error;
diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c
index fcae5fa2e1b3..05306a59aedc 100644
--- a/drivers/acpi/sysfs.c
+++ b/drivers/acpi/sysfs.c
@@ -677,10 +677,9 @@ void acpi_irq_stats_init(void)
else
sprintf(buffer, "bug%02X", i);
- name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
+ name = kstrdup(buffer, GFP_KERNEL);
if (name == NULL)
goto fail;
- strncpy(name, buffer, strlen(buffer) + 1);
sysfs_attr_init(&counter_attrs[i].attr);
counter_attrs[i].attr.name = name;
@@ -780,6 +779,33 @@ void acpi_sysfs_add_hotplug_profile(struct acpi_hotplug_profile *hotplug,
pr_err(PREFIX "Unable to add hotplug profile '%s'\n", name);
}
+static ssize_t force_remove_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", !!acpi_force_hot_remove);
+}
+
+static ssize_t force_remove_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t size)
+{
+ bool val;
+ int ret;
+
+ ret = strtobool(buf, &val);
+ if (ret < 0)
+ return ret;
+
+ lock_device_hotplug();
+ acpi_force_hot_remove = val;
+ unlock_device_hotplug();
+ return size;
+}
+
+static const struct kobj_attribute force_remove_attr =
+ __ATTR(force_remove, S_IRUGO | S_IWUSR, force_remove_show,
+ force_remove_store);
+
int __init acpi_sysfs_init(void)
{
int result;
@@ -789,6 +815,10 @@ int __init acpi_sysfs_init(void)
return result;
hotplug_kobj = kobject_create_and_add("hotplug", acpi_kobj);
+ result = sysfs_create_file(hotplug_kobj, &force_remove_attr.attr);
+ if (result)
+ return result;
+
result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr);
return result;
}
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 440eadf2d32c..5d7075d25700 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1722,9 +1722,6 @@ static int acpi_video_bus_add(struct acpi_device *device)
int error;
acpi_status status;
- if (device->handler)
- return -EINVAL;
-
status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
device->parent->handle, 1,
acpi_video_bus_match, NULL,
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index cdbad3a454a0..c6707278a6bb 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -284,7 +284,7 @@ static const struct dev_pm_ops amba_pm = {
SET_RUNTIME_PM_OPS(
amba_pm_runtime_suspend,
amba_pm_runtime_resume,
- pm_generic_runtime_idle
+ NULL
)
};
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index a5a3ebcbdd2c..aba6e93b0502 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -263,7 +263,6 @@ config SATA_PROMISE
config SATA_RCAR
tristate "Renesas R-Car SATA support"
- depends on ARCH_SHMOBILE && ARCH_R8A7779
help
This option enables support for Renesas R-Car Serial ATA.
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index 9d0cf019ce59..fd665d919df2 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -128,7 +128,7 @@ static struct pci_driver acard_ahci_pci_driver = {
#ifdef CONFIG_PM
static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 ctl;
@@ -156,7 +156,7 @@ static int acard_ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg
static int acard_ahci_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 2b50dfdf1cfc..5064f3ea20f1 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -291,6 +291,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x8d64), board_ahci }, /* Wellsburg RAID */
{ PCI_VDEVICE(INTEL, 0x8d66), board_ahci }, /* Wellsburg RAID */
{ PCI_VDEVICE(INTEL, 0x8d6e), board_ahci }, /* Wellsburg RAID */
+ { PCI_VDEVICE(INTEL, 0x23a3), board_ahci }, /* Coleto Creek AHCI */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -310,6 +311,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* AMD */
{ PCI_VDEVICE(AMD, 0x7800), board_ahci }, /* AMD Hudson-2 */
+ { PCI_VDEVICE(AMD, 0x7900), board_ahci }, /* AMD CZ */
/* AMD is using RAID class only for ahci controllers */
{ PCI_VENDOR_ID_AMD, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID << 8, 0xffffff, board_ahci },
@@ -585,7 +587,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
- tf.command = 0x80;
+ tf.command = ATA_BUSY;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
@@ -618,7 +620,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
#ifdef CONFIG_PM
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 ctl;
@@ -646,7 +648,7 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
static int ahci_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -1144,9 +1146,11 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis)
return rc;
for (i = 0; i < host->n_ports; i++) {
+ struct ahci_port_priv *pp = host->ports[i]->private_data;
+
rc = devm_request_threaded_irq(host->dev,
irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED,
- dev_driver_string(host->dev), host->ports[i]);
+ pp->irq_desc, host->ports[i]);
if (rc)
goto out_free_irqs;
}
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 10b14d45cfd2..11456371f29b 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -306,6 +306,7 @@ struct ahci_port_priv {
int fbs_last_dev; /* save FBS.DEV of last FIS */
/* enclosure management info per PM slot */
struct ahci_em_priv em_priv[EM_MAX_SLOTS];
+ char *irq_desc; /* desc in /proc/interrupts */
};
struct ahci_host_priv {
@@ -321,6 +322,7 @@ struct ahci_host_priv {
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
struct clk *clk; /* Only for platforms supporting clk */
+ void *plat_data; /* Other platform data */
};
extern int ahci_ignore_sss;
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 7a8a2841fe64..2daaee05cab1 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -327,6 +327,7 @@ static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "snps,spear-ahci", },
+ { .compatible = "snps,exynos5440-ahci", },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 9a8a674e8fac..b52a10c8eeb9 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -338,6 +338,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller IDE (BayTrail) */
{ 0x8086, 0x0F20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
{ 0x8086, 0x0F21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata_byt },
+ /* SATA Controller IDE (Coleto Creek) */
+ { 0x8086, 0x23a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
{ } /* terminate list */
};
@@ -993,7 +995,7 @@ static int piix_broken_suspend(void)
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
unsigned long flags;
int rc = 0;
@@ -1028,7 +1030,7 @@ static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
static int piix_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
unsigned long flags;
int rc;
@@ -1751,7 +1753,7 @@ static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
static void piix_remove_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct piix_host_priv *hpriv = host->private_data;
pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg);
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index a70ff154f586..acfd0f711069 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -173,6 +173,7 @@ struct ata_port_operations ahci_ops = {
.em_store = ahci_led_store,
.sw_activity_show = ahci_activity_show,
.sw_activity_store = ahci_activity_store,
+ .transmit_led_message = ahci_transmit_led_message,
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
@@ -774,7 +775,7 @@ static void ahci_start_port(struct ata_port *ap)
/* EM Transmit bit maybe busy during init */
for (i = 0; i < EM_MAX_RETRY; i++) {
- rc = ahci_transmit_led_message(ap,
+ rc = ap->ops->transmit_led_message(ap,
emp->led_state,
4);
if (rc == -EBUSY)
@@ -915,7 +916,7 @@ static void ahci_sw_activity_blink(unsigned long arg)
led_message |= (1 << 16);
}
spin_unlock_irqrestore(ap->lock, flags);
- ahci_transmit_led_message(ap, led_message, 4);
+ ap->ops->transmit_led_message(ap, led_message, 4);
}
static void ahci_init_sw_activity(struct ata_link *link)
@@ -1044,7 +1045,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
if (emp->blink_policy)
state &= ~EM_MSG_LED_VALUE_ACTIVITY;
- return ahci_transmit_led_message(ap, state, size);
+ return ap->ops->transmit_led_message(ap, state, size);
}
static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
@@ -1063,7 +1064,7 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
/* set the LED to OFF */
port_led_state &= EM_MSG_LED_VALUE_OFF;
port_led_state |= (ap->port_no | (link->pmp << 8));
- ahci_transmit_led_message(ap, port_led_state, 4);
+ ap->ops->transmit_led_message(ap, port_led_state, 4);
} else {
link->flags |= ATA_LFLAG_SW_ACTIVITY;
if (val == BLINK_OFF) {
@@ -1071,7 +1072,7 @@ static ssize_t ahci_activity_store(struct ata_device *dev, enum sw_activity val)
port_led_state &= EM_MSG_LED_VALUE_OFF;
port_led_state |= (ap->port_no | (link->pmp << 8));
port_led_state |= EM_MSG_LED_VALUE_ON; /* check this */
- ahci_transmit_led_message(ap, port_led_state, 4);
+ ap->ops->transmit_led_message(ap, port_led_state, 4);
}
}
emp->blink_policy = val;
@@ -1412,7 +1413,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
- tf.command = 0x80;
+ tf.command = ATA_BUSY;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_link_hardreset(link, timing, deadline, &online,
@@ -1560,8 +1561,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
u32 fbs = readl(port_mmio + PORT_FBS);
int pmp = fbs >> PORT_FBS_DWE_OFFSET;
- if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links) &&
- ata_link_online(&ap->pmp_link[pmp])) {
+ if ((fbs & PORT_FBS_SDE) && (pmp < ap->nr_pmp_links)) {
link = &ap->pmp_link[pmp];
fbs_need_dec = true;
}
@@ -2234,6 +2234,16 @@ static int ahci_port_start(struct ata_port *ap)
if (!pp)
return -ENOMEM;
+ if (ap->host->n_ports > 1) {
+ pp->irq_desc = devm_kzalloc(dev, 8, GFP_KERNEL);
+ if (!pp->irq_desc) {
+ devm_kfree(dev, pp);
+ return -ENOMEM;
+ }
+ snprintf(pp->irq_desc, 8,
+ "%s%d", dev_driver_string(dev), ap->port_no);
+ }
+
/* check FBS capability */
if ((hpriv->cap & HOST_CAP_FBS) && sata_pmp_supported(ap)) {
void __iomem *port_mmio = ahci_port_base(ap);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index adf002a3c584..c24354d44f3d 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2401,7 +2401,7 @@ int ata_dev_configure(struct ata_device *dev)
cdb_intr_string = ", CDB intr";
}
- if (atapi_dmadir || atapi_id_dmadir(dev->id)) {
+ if (atapi_dmadir || (dev->horkage & ATA_HORKAGE_ATAPI_DMADIR) || atapi_id_dmadir(dev->id)) {
dev->flags |= ATA_DFLAG_DMADIR;
dma_dir_string = ", DMADIR";
}
@@ -5436,7 +5436,7 @@ static int ata_port_runtime_idle(struct device *dev)
return -EBUSY;
}
- return pm_runtime_suspend(dev);
+ return 0;
}
static int ata_port_runtime_suspend(struct device *dev)
@@ -5642,6 +5642,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
ap->pflags |= ATA_PFLAG_INITIALIZING | ATA_PFLAG_FROZEN;
ap->lock = &host->lock;
ap->print_id = -1;
+ ap->local_port_no = -1;
ap->host = host;
ap->dev = host->dev;
@@ -6132,9 +6133,10 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
kfree(host->ports[i]);
/* give ports names and add SCSI hosts */
- for (i = 0; i < host->n_ports; i++)
+ for (i = 0; i < host->n_ports; i++) {
host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
-
+ host->ports[i]->local_port_no = i + 1;
+ }
/* Create associated sysfs transport objects */
for (i = 0; i < host->n_ports; i++) {
@@ -6502,6 +6504,7 @@ static int __init ata_parse_force_one(char **cur,
{ "nosrst", .lflags = ATA_LFLAG_NO_SRST },
{ "norst", .lflags = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
{ "rstonce", .lflags = ATA_LFLAG_RST_ONCE },
+ { "atapi_dmadir", .horkage_on = ATA_HORKAGE_ATAPI_DMADIR },
};
char *start = *cur, *p = *cur;
char *id, *val, *endp;
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 61c59ee45ce9..1c41722bb7e2 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -389,9 +389,13 @@ static void sata_pmp_quirks(struct ata_port *ap)
/* link reports offline after LPM */
link->flags |= ATA_LFLAG_NO_LPM;
- /* Class code report is unreliable. */
+ /*
+ * Class code report is unreliable and SRST times
+ * out under certain configurations.
+ */
if (link->pmp < 5)
- link->flags |= ATA_LFLAG_ASSUME_ATA;
+ link->flags |= ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
/* port 5 is for SEMB device and it doesn't like SRST */
if (link->pmp == 5)
@@ -399,20 +403,17 @@ static void sata_pmp_quirks(struct ata_port *ap)
ATA_LFLAG_ASSUME_SEMB;
}
} else if (vendor == 0x1095 && devid == 0x4723) {
- /* sil4723 quirks */
- ata_for_each_link(link, ap, EDGE) {
- /* link reports offline after LPM */
- link->flags |= ATA_LFLAG_NO_LPM;
-
- /* class code report is unreliable */
- if (link->pmp < 2)
- link->flags |= ATA_LFLAG_ASSUME_ATA;
-
- /* the config device at port 2 locks up on SRST */
- if (link->pmp == 2)
- link->flags |= ATA_LFLAG_NO_SRST |
- ATA_LFLAG_ASSUME_ATA;
- }
+ /*
+ * sil4723 quirks
+ *
+ * Link reports offline after LPM. Class code report is
+ * unreliable. SIMG PMPs never got SRST reliable and the
+ * config device at port 2 locks up on SRST.
+ */
+ ata_for_each_link(link, ap, EDGE)
+ link->flags |= ATA_LFLAG_NO_LPM |
+ ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
} else if (vendor == 0x1095 && devid == 0x4726) {
/* sil4726 quirks */
ata_for_each_link(link, ap, EDGE) {
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 0101af541436..83c08907e042 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -849,25 +849,24 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
/* Bad address mark */
{0x01, MEDIUM_ERROR, 0x13, 0x00}, // Address mark not found Address mark not found for data field
/* TRK0 */
- {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
- /* Abort & !ICRC */
- {0x04, ABORTED_COMMAND, 0x00, 0x00}, // Aborted command Aborted command
+ {0x02, HARDWARE_ERROR, 0x00, 0x00}, // Track 0 not found Hardware error
+ /* Abort: 0x04 is not translated here, see below */
/* Media change request */
{0x08, NOT_READY, 0x04, 0x00}, // Media change request FIXME: faking offline
- /* SRV */
- {0x10, ABORTED_COMMAND, 0x14, 0x00}, // ID not found Recorded entity not found
- /* Media change */
- {0x08, NOT_READY, 0x04, 0x00}, // Media change FIXME: faking offline
+ /* SRV/IDNF */
+ {0x10, ILLEGAL_REQUEST, 0x21, 0x00}, // ID not found Logical address out of range
+ /* MC */
+ {0x20, UNIT_ATTENTION, 0x28, 0x00}, // Media Changed Not ready to ready change, medium may have changed
/* ECC */
{0x40, MEDIUM_ERROR, 0x11, 0x04}, // Uncorrectable ECC error Unrecovered read error
/* BBD - block marked bad */
- {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
+ {0x80, MEDIUM_ERROR, 0x11, 0x04}, // Block marked bad Medium error, unrecovered read error
{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
};
static const unsigned char stat_table[][4] = {
/* Must be first because BUSY means no other bits valid */
{0x80, ABORTED_COMMAND, 0x47, 0x00}, // Busy, fake parity for now
- {0x20, HARDWARE_ERROR, 0x00, 0x00}, // Device fault
+ {0x20, HARDWARE_ERROR, 0x44, 0x00}, // Device fault, internal target failure
{0x08, ABORTED_COMMAND, 0x47, 0x00}, // Timed out in xfer, fake parity for now
{0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered
{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
@@ -892,13 +891,13 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
goto translate_done;
}
}
- /* No immediate match */
- if (verbose)
- printk(KERN_WARNING "ata%u: no sense translation for "
- "error 0x%02x\n", id, drv_err);
}
- /* Fall back to interpreting status bits */
+ /*
+ * Fall back to interpreting status bits. Note that if the drv_err
+ * has only the ABRT bit set, we decode drv_stat. ABRT by itself
+ * is not descriptive enough.
+ */
for (i = 0; stat_table[i][0] != 0xFF; i++) {
if (stat_table[i][0] & drv_stat) {
*sk = stat_table[i][1];
@@ -907,13 +906,11 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
goto translate_done;
}
}
- /* No error? Undecoded? */
- if (verbose)
- printk(KERN_WARNING "ata%u: no sense translation for "
- "status: 0x%02x\n", id, drv_stat);
- /* We need a sensible error return here, which is tricky, and one
- that won't cause people to do things like return a disk wrongly */
+ /*
+ * We need a sensible error return here, which is tricky, and one
+ * that won't cause people to do things like return a disk wrongly.
+ */
*sk = ABORTED_COMMAND;
*asc = 0x00;
*ascq = 0x00;
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index c04d393d20c1..077a856f5fd0 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -37,7 +37,7 @@
#include "libata.h"
#include "libata-transport.h"
-#define ATA_PORT_ATTRS 2
+#define ATA_PORT_ATTRS 3
#define ATA_LINK_ATTRS 3
#define ATA_DEV_ATTRS 9
@@ -216,6 +216,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
+ata_port_simple_attr(local_port_no, port_no, "%u\n", unsigned int);
static DECLARE_TRANSPORT_CLASS(ata_port_class,
"ata_port", NULL, NULL, NULL);
@@ -709,6 +710,7 @@ struct scsi_transport_template *ata_attach_transport(void)
count = 0;
SETUP_PORT_ATTRIBUTE(nr_pmp_links);
SETUP_PORT_ATTRIBUTE(idle_irq);
+ SETUP_PORT_ATTRIBUTE(port_no);
BUG_ON(count > ATA_PORT_ATTRS);
i->port_attrs[count] = NULL;
diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c
index 90b159b740b3..cd8daf47188b 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -32,13 +32,14 @@ struct zpodd {
static int eject_tray(struct ata_device *dev)
{
- struct ata_taskfile tf = {};
+ struct ata_taskfile tf;
const char cdb[] = { GPCMD_START_STOP_UNIT,
0, 0, 0,
0x02, /* LoEj */
0, 0, 0, 0, 0, 0, 0,
};
+ ata_tf_init(dev, &tf);
tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET;
tf.protocol = ATAPI_PROT_NODATA;
@@ -52,8 +53,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
char buf[16];
unsigned int ret;
struct rm_feature_desc *desc = (void *)(buf + 8);
- struct ata_taskfile tf = {};
-
+ struct ata_taskfile tf;
char cdb[] = { GPCMD_GET_CONFIGURATION,
2, /* only 1 feature descriptor requested */
0, 3, /* 3, removable medium feature */
@@ -62,6 +62,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev)
0, 0, 0,
};
+ ata_tf_init(dev, &tf);
tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET;
tf.protocol = ATAPI_PROT_PIO;
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 61da0694aecd..1b7b2ccabcff 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -592,7 +592,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int ali_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 82a08922afcd..d23e2b3ca0b6 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -578,7 +578,7 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int amd_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 7638121cb5d1..848ed3254ddd 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -908,7 +908,7 @@ free_clk:
static int arasan_cf_remove(struct platform_device *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
struct arasan_cf_dev *acdev = host->ports[0]->private_data;
ata_host_detach(host);
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 74b215c09b21..1581dee2967a 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -426,7 +426,7 @@ static const struct pci_device_id artop_pci_tbl[] = {
#ifdef CONFIG_PM
static int atp8xx_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index 033f3f4c20ad..5364f97b42c6 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -422,7 +422,7 @@ err_put:
static int pata_at91_remove(struct platform_device *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
struct at91_ide_info *info;
if (!host)
diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c
index 041f50d53240..2ca5026f2c15 100644
--- a/drivers/ata/pata_atp867x.c
+++ b/drivers/ata/pata_atp867x.c
@@ -534,7 +534,7 @@ err_out:
#ifdef CONFIG_PM
static int atp867x_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index 8d43510c6bec..ba0d8a29dc23 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1596,7 +1596,7 @@ static int bfin_atapi_probe(struct platform_device *pdev)
return -ENODEV;
}
- dev_set_drvdata(&pdev->dev, host);
+ platform_set_drvdata(pdev, host);
return 0;
}
@@ -1610,11 +1610,9 @@ static int bfin_atapi_probe(struct platform_device *pdev)
*/
static int bfin_atapi_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct ata_host *host = dev_get_drvdata(dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
ata_host_detach(host);
- dev_set_drvdata(&pdev->dev, NULL);
peripheral_free_list(atapi_io_port);
@@ -1624,7 +1622,7 @@ static int bfin_atapi_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
if (host)
return ata_host_suspend(host, state);
else
@@ -1633,7 +1631,7 @@ static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
static int bfin_atapi_resume(struct platform_device *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
int ret;
if (host) {
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 504b98b58e19..8fb69e5ca1b7 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -235,7 +235,7 @@ static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int cmd640_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 2949cfc2dd31..1275a8d4dedc 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -491,7 +491,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int cmd64x_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index bfcf377e8f77..f10baabbf5db 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -241,7 +241,7 @@ static int cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static int cs5520_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
u8 pcicfg;
int rc;
@@ -269,7 +269,7 @@ static int cs5520_reinit_one(struct pci_dev *pdev)
static int cs5520_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc = 0;
rc = ata_host_suspend(host, mesg);
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 48389ae0b330..f07f2296acdc 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -330,7 +330,7 @@ static int cs5530_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int cs5530_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 4be884a9f5ed..35b521348d31 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -390,7 +390,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int hpt36x_reinit_one(struct pci_dev *dev)
{
- struct ata_host *host = dev_get_drvdata(&dev->dev);
+ struct ata_host *host = pci_get_drvdata(dev);
int rc;
rc = ata_pci_device_do_resume(dev);
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 76c9314bb824..85cf2861e0b7 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -253,7 +253,7 @@ static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int hpt3x3_reinit_one(struct pci_dev *dev)
{
- struct ata_host *host = dev_get_drvdata(&dev->dev);
+ struct ata_host *host = pci_get_drvdata(dev);
int rc;
rc = ata_pci_device_do_resume(dev);
diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c
index aa3d166e02eb..4ec7c04b3f82 100644
--- a/drivers/ata/pata_imx.c
+++ b/drivers/ata/pata_imx.c
@@ -177,7 +177,7 @@ err:
static int pata_imx_remove(struct platform_device *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
struct pata_imx_priv *priv = host->private_data;
ata_host_detach(host);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 9cc05d808ad5..581e04d80367 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -939,7 +939,7 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
#ifdef CONFIG_PM
static int it821x_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index e5725edcf515..c28d0645e851 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -1311,7 +1311,7 @@ static int pata_macio_pci_attach(struct pci_dev *pdev,
static void pata_macio_pci_detach(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
ata_host_detach(host);
}
@@ -1320,14 +1320,14 @@ static void pata_macio_pci_detach(struct pci_dev *pdev)
static int pata_macio_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
return pata_macio_do_suspend(host->private_data, mesg);
}
static int pata_macio_pci_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
return pata_macio_do_resume(host->private_data);
}
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 3a8fb28b71f2..0024ced3e200 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -825,7 +825,7 @@ mpc52xx_ata_remove(struct platform_device *op)
static int
mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)
{
- struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct ata_host *host = platform_get_drvdata(op);
return ata_host_suspend(host, state);
}
@@ -833,7 +833,7 @@ mpc52xx_ata_suspend(struct platform_device *op, pm_message_t state)
static int
mpc52xx_ata_resume(struct platform_device *op)
{
- struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct ata_host *host = platform_get_drvdata(op);
struct mpc52xx_ata_priv *priv = host->private_data;
int rv;
diff --git a/drivers/ata/pata_ninja32.c b/drivers/ata/pata_ninja32.c
index 12010ed596c4..9513e071040d 100644
--- a/drivers/ata/pata_ninja32.c
+++ b/drivers/ata/pata_ninja32.c
@@ -157,7 +157,7 @@ static int ninja32_init_one(struct pci_dev *dev, const struct pci_device_id *id)
static int ninja32_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
index 6f6fa1060505..16dc3a63a23d 100644
--- a/drivers/ata/pata_ns87415.c
+++ b/drivers/ata/pata_ns87415.c
@@ -389,7 +389,7 @@ static const struct pci_device_id ns87415_pci_tbl[] = {
#ifdef CONFIG_PM
static int ns87415_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index c76e65927b0e..9d874c85d64d 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -765,7 +765,7 @@ static int pdc2027x_init_one(struct pci_dev *pdev,
#ifdef CONFIG_PM
static int pdc2027x_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
unsigned int board_idx;
int rc;
diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c
index b0ac9e0c5e01..942ef94b29e6 100644
--- a/drivers/ata/pata_pxa.c
+++ b/drivers/ata/pata_pxa.c
@@ -371,7 +371,7 @@ static int pxa_ata_probe(struct platform_device *pdev)
static int pxa_ata_remove(struct platform_device *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
struct pata_pxa_data *data = host->ports[0]->private_data;
pxa_free_dma(data->dma_channel);
diff --git a/drivers/ata/pata_rdc.c b/drivers/ata/pata_rdc.c
index 6a8665574fee..79a970f05a2e 100644
--- a/drivers/ata/pata_rdc.c
+++ b/drivers/ata/pata_rdc.c
@@ -364,7 +364,7 @@ static int rdc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
static void rdc_remove_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct rdc_host_priv *hpriv = host->private_data;
pci_write_config_dword(pdev, 0x54, hpriv->saved_iocfg);
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 60f4de2dd47d..040b093617a4 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -105,7 +105,7 @@ static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *en
#ifdef CONFIG_PM
static int rz1000_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index f3febbce6c46..96c6a79ef606 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -440,7 +440,7 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
#ifdef CONFIG_PM
static int serverworks_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 64c5f0d0f812..c4b0b073ba8e 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -407,7 +407,7 @@ use_ioports:
#ifdef CONFIG_PM
static int sil680_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int try_mmio, rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 2d5ac1361262..1e8363640bf5 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -873,7 +873,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PM
static int sis_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 738e000107d6..6816911ac422 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -341,7 +341,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
#ifdef CONFIG_PM
static int sl82c105_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index c8e589d91231..94473da68c02 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -211,7 +211,7 @@ static const struct pci_device_id triflex[] = {
#ifdef CONFIG_PM
static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc = 0;
rc = ata_host_suspend(host, mesg);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 8d2a9fdf6b8d..c3ab9a6c3965 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -673,7 +673,7 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
static int via_reinit_one(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d40e403e82dd..19720a0a4a65 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1532,7 +1532,7 @@ static int sata_fsl_probe(struct platform_device *ofdev)
ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG,
&sata_fsl_sht);
- dev_set_drvdata(&ofdev->dev, host);
+ platform_set_drvdata(ofdev, host);
host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
@@ -1558,10 +1558,8 @@ static int sata_fsl_probe(struct platform_device *ofdev)
error_exit_with_cleanup:
- if (host) {
- dev_set_drvdata(&ofdev->dev, NULL);
+ if (host)
ata_host_detach(host);
- }
if (hcr_base)
iounmap(hcr_base);
@@ -1572,7 +1570,7 @@ error_exit_with_cleanup:
static int sata_fsl_remove(struct platform_device *ofdev)
{
- struct ata_host *host = dev_get_drvdata(&ofdev->dev);
+ struct ata_host *host = platform_get_drvdata(ofdev);
struct sata_fsl_host_priv *host_priv = host->private_data;
device_remove_file(&ofdev->dev, &host_priv->intr_coalescing);
@@ -1580,8 +1578,6 @@ static int sata_fsl_remove(struct platform_device *ofdev)
ata_host_detach(host);
- dev_set_drvdata(&ofdev->dev, NULL);
-
irq_dispose_mapping(host_priv->irq);
iounmap(host_priv->hcr_base);
kfree(host_priv);
@@ -1592,13 +1588,13 @@ static int sata_fsl_remove(struct platform_device *ofdev)
#ifdef CONFIG_PM
static int sata_fsl_suspend(struct platform_device *op, pm_message_t state)
{
- struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct ata_host *host = platform_get_drvdata(op);
return ata_host_suspend(host, state);
}
static int sata_fsl_resume(struct platform_device *op)
{
- struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct ata_host *host = platform_get_drvdata(op);
struct sata_fsl_host_priv *host_priv = host->private_data;
int ret;
void __iomem *hcr_base = host_priv->hcr_base;
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index b20aa96b958d..d047d92a456f 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -33,6 +33,9 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
#include "ahci.h"
#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
@@ -66,6 +69,146 @@ struct phy_lane_info {
};
static struct phy_lane_info port_data[CPHY_PORT_COUNT];
+static DEFINE_SPINLOCK(sgpio_lock);
+#define SCLOCK 0
+#define SLOAD 1
+#define SDATA 2
+#define SGPIO_PINS 3
+#define SGPIO_PORTS 8
+
+/* can be cast as an ahci_host_priv for compatibility with most functions */
+struct ecx_plat_data {
+ u32 n_ports;
+ unsigned sgpio_gpio[SGPIO_PINS];
+ u32 sgpio_pattern;
+ u32 port_to_sgpio[SGPIO_PORTS];
+};
+
+#define SGPIO_SIGNALS 3
+#define ECX_ACTIVITY_BITS 0x300000
+#define ECX_ACTIVITY_SHIFT 2
+#define ECX_LOCATE_BITS 0x80000
+#define ECX_LOCATE_SHIFT 1
+#define ECX_FAULT_BITS 0x400000
+#define ECX_FAULT_SHIFT 0
+static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port,
+ u32 shift)
+{
+ return 1 << (3 * pdata->port_to_sgpio[port] + shift);
+}
+
+static void ecx_parse_sgpio(struct ecx_plat_data *pdata, u32 port, u32 state)
+{
+ if (state & ECX_ACTIVITY_BITS)
+ pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+ ECX_ACTIVITY_SHIFT);
+ else
+ pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+ ECX_ACTIVITY_SHIFT);
+ if (state & ECX_LOCATE_BITS)
+ pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+ ECX_LOCATE_SHIFT);
+ else
+ pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+ ECX_LOCATE_SHIFT);
+ if (state & ECX_FAULT_BITS)
+ pdata->sgpio_pattern |= sgpio_bit_shift(pdata, port,
+ ECX_FAULT_SHIFT);
+ else
+ pdata->sgpio_pattern &= ~sgpio_bit_shift(pdata, port,
+ ECX_FAULT_SHIFT);
+}
+
+/*
+ * Tell the LED controller that the signal has changed by raising the clock
+ * line for 50 uS and then lowering it for 50 uS.
+ */
+static void ecx_led_cycle_clock(struct ecx_plat_data *pdata)
+{
+ gpio_set_value(pdata->sgpio_gpio[SCLOCK], 1);
+ udelay(50);
+ gpio_set_value(pdata->sgpio_gpio[SCLOCK], 0);
+ udelay(50);
+}
+
+static ssize_t ecx_transmit_led_message(struct ata_port *ap, u32 state,
+ ssize_t size)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ecx_plat_data *pdata = (struct ecx_plat_data *) hpriv->plat_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ unsigned long flags;
+ int pmp, i;
+ struct ahci_em_priv *emp;
+ u32 sgpio_out;
+
+ /* get the slot number from the message */
+ pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
+ if (pmp < EM_MAX_SLOTS)
+ emp = &pp->em_priv[pmp];
+ else
+ return -EINVAL;
+
+ if (!(hpriv->em_msg_type & EM_MSG_TYPE_LED))
+ return size;
+
+ spin_lock_irqsave(&sgpio_lock, flags);
+ ecx_parse_sgpio(pdata, ap->port_no, state);
+ sgpio_out = pdata->sgpio_pattern;
+ gpio_set_value(pdata->sgpio_gpio[SLOAD], 1);
+ ecx_led_cycle_clock(pdata);
+ gpio_set_value(pdata->sgpio_gpio[SLOAD], 0);
+ /*
+ * bit-bang out the SGPIO pattern, by consuming a bit and then
+ * clocking it out.
+ */
+ for (i = 0; i < (SGPIO_SIGNALS * pdata->n_ports); i++) {
+ gpio_set_value(pdata->sgpio_gpio[SDATA], sgpio_out & 1);
+ sgpio_out >>= 1;
+ ecx_led_cycle_clock(pdata);
+ }
+
+ /* save off new led state for port/slot */
+ emp->led_state = state;
+
+ spin_unlock_irqrestore(&sgpio_lock, flags);
+ return size;
+}
+
+static void highbank_set_em_messages(struct device *dev,
+ struct ahci_host_priv *hpriv,
+ struct ata_port_info *pi)
+{
+ struct device_node *np = dev->of_node;
+ struct ecx_plat_data *pdata = hpriv->plat_data;
+ int i;
+ int err;
+
+ for (i = 0; i < SGPIO_PINS; i++) {
+ err = of_get_named_gpio(np, "calxeda,sgpio-gpio", i);
+ if (IS_ERR_VALUE(err))
+ return;
+
+ pdata->sgpio_gpio[i] = err;
+ err = gpio_request(pdata->sgpio_gpio[i], "CX SGPIO");
+ if (err) {
+ pr_err("sata_highbank gpio_request %d failed: %d\n",
+ i, err);
+ return;
+ }
+ gpio_direction_output(pdata->sgpio_gpio[i], 1);
+ }
+ of_property_read_u32_array(np, "calxeda,led-order",
+ pdata->port_to_sgpio,
+ pdata->n_ports);
+
+ /* store em_loc */
+ hpriv->em_loc = 0;
+ hpriv->em_buf_sz = 4;
+ hpriv->em_msg_type = EM_MSG_TYPE_LED;
+ pi->flags |= ATA_FLAG_EM | ATA_FLAG_SW_ACTIVITY;
+}
+
static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
{
u32 data;
@@ -196,10 +339,26 @@ static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
return 0;
}
+/*
+ * The Calxeda SATA phy intermittently fails to bring up a link with Gen3
+ * Retrying the phy hard reset can work around the issue, but the drive
+ * may fail again. In less than 150 out of 15000 test runs, it took more
+ * than 10 tries for the link to be established (but never more than 35).
+ * Triple the maximum observed retry count to provide plenty of margin for
+ * rare events and to guarantee that the link is established.
+ *
+ * Also, the default 2 second time-out on a failed drive is too long in
+ * this situation. The uboot implementation of the same driver function
+ * uses a much shorter time-out period and never experiences a time out
+ * issue. Reducing the time-out to 500ms improves the responsiveness.
+ * The other timing constants were kept the same as the stock AHCI driver.
+ * This change was also tested 15000 times on 24 drives and none of them
+ * experienced a time out.
+ */
static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
- const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ static const unsigned long timing[] = { 5, 100, 500};
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
@@ -207,7 +366,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
bool online;
u32 sstatus;
int rc;
- int retry = 10;
+ int retry = 100;
ahci_stop_engine(ap);
@@ -241,6 +400,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
static struct ata_port_operations ahci_highbank_ops = {
.inherits = &ahci_ops,
.hardreset = ahci_highbank_hardreset,
+ .transmit_led_message = ecx_transmit_led_message,
};
static const struct ata_port_info ahci_highbank_port_info = {
@@ -264,12 +424,13 @@ static int ahci_highbank_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
+ struct ecx_plat_data *pdata;
struct ata_host *host;
struct resource *mem;
int irq;
- int n_ports;
int i;
int rc;
+ u32 n_ports;
struct ata_port_info pi = ahci_highbank_port_info;
const struct ata_port_info *ppi[] = { &pi, NULL };
@@ -290,6 +451,11 @@ static int ahci_highbank_probe(struct platform_device *pdev)
dev_err(dev, "can't alloc ahci_host_priv\n");
return -ENOMEM;
}
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "can't alloc ecx_plat_data\n");
+ return -ENOMEM;
+ }
hpriv->flags |= (unsigned long)pi.private_data;
@@ -313,8 +479,6 @@ static int ahci_highbank_probe(struct platform_device *pdev)
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
- ahci_set_em_messages(hpriv, &pi);
-
/* CAP.NP sometimes indicate the index of the last enabled
* port, at other times, that of the last possible port, so
* determining the maximum port number requires looking at
@@ -322,6 +486,10 @@ static int ahci_highbank_probe(struct platform_device *pdev)
*/
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+ pdata->n_ports = n_ports;
+ hpriv->plat_data = pdata;
+ highbank_set_em_messages(dev, hpriv, &pi);
+
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
if (!host) {
rc = -ENOMEM;
@@ -333,9 +501,6 @@ static int ahci_highbank_probe(struct platform_device *pdev)
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
host->flags |= ATA_HOST_PARALLEL_SCAN;
- if (pi.flags & ATA_FLAG_EM)
- ahci_reset_em(host);
-
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1e6827c89429..e45131748248 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -776,7 +776,7 @@ static int init_controller(void __iomem *mmio_base, u16 hctl)
#ifdef CONFIG_PM
static int inic_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct inic_host_priv *hpriv = host->private_data;
int rc;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 85ee4993ca74..d74def823d3e 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -2435,7 +2435,7 @@ static int nv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PM
static int nv_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
struct nv_host_priv *hpriv = host->private_data;
int rc;
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 249c8a289bfd..8108eb065444 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -121,6 +121,8 @@
/* Descriptor table word 0 bit (when DTA32M = 1) */
#define SATA_RCAR_DTEND BIT(0)
+#define SATA_RCAR_DMA_BOUNDARY 0x1FFFFFFEUL
+
struct sata_rcar_priv {
void __iomem *base;
struct clk *clk;
@@ -128,41 +130,44 @@ struct sata_rcar_priv {
static void sata_rcar_phy_initialize(struct sata_rcar_priv *priv)
{
+ void __iomem *base = priv->base;
+
/* idle state */
- iowrite32(0, priv->base + SATAPHYADDR_REG);
+ iowrite32(0, base + SATAPHYADDR_REG);
/* reset */
- iowrite32(SATAPHYRESET_PHYRST, priv->base + SATAPHYRESET_REG);
+ iowrite32(SATAPHYRESET_PHYRST, base + SATAPHYRESET_REG);
udelay(10);
/* deassert reset */
- iowrite32(0, priv->base + SATAPHYRESET_REG);
+ iowrite32(0, base + SATAPHYRESET_REG);
}
static void sata_rcar_phy_write(struct sata_rcar_priv *priv, u16 reg, u32 val,
int group)
{
+ void __iomem *base = priv->base;
int timeout;
/* deassert reset */
- iowrite32(0, priv->base + SATAPHYRESET_REG);
+ iowrite32(0, base + SATAPHYRESET_REG);
/* lane 1 */
- iowrite32(SATAPHYACCEN_PHYLANE, priv->base + SATAPHYACCEN_REG);
+ iowrite32(SATAPHYACCEN_PHYLANE, base + SATAPHYACCEN_REG);
/* write phy register value */
- iowrite32(val, priv->base + SATAPHYWDATA_REG);
+ iowrite32(val, base + SATAPHYWDATA_REG);
/* set register group */
if (group)
reg |= SATAPHYADDR_PHYRATEMODE;
/* write command */
- iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, priv->base + SATAPHYADDR_REG);
+ iowrite32(SATAPHYADDR_PHYCMD_WRITE | reg, base + SATAPHYADDR_REG);
/* wait for ack */
for (timeout = 0; timeout < 100; timeout++) {
- val = ioread32(priv->base + SATAPHYACK_REG);
+ val = ioread32(base + SATAPHYACK_REG);
if (val & SATAPHYACK_PHYACK)
break;
}
if (timeout >= 100)
pr_err("%s timeout\n", __func__);
/* idle state */
- iowrite32(0, priv->base + SATAPHYADDR_REG);
+ iowrite32(0, base + SATAPHYADDR_REG);
}
static void sata_rcar_freeze(struct ata_port *ap)
@@ -178,14 +183,15 @@ static void sata_rcar_freeze(struct ata_port *ap)
static void sata_rcar_thaw(struct ata_port *ap)
{
struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
/* ack */
- iowrite32(~SATA_RCAR_INT_MASK, priv->base + SATAINTSTAT_REG);
+ iowrite32(~(u32)SATA_RCAR_INT_MASK, base + SATAINTSTAT_REG);
ata_sff_thaw(ap);
/* unmask */
- iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, priv->base + SATAINTMASK_REG);
+ iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG);
}
static void sata_rcar_ioread16_rep(void __iomem *reg, void *buffer, int count)
@@ -474,11 +480,10 @@ static void sata_rcar_bmdma_fill_sg(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
struct ata_bmdma_prd *prd = ap->bmdma_prd;
struct scatterlist *sg;
- unsigned int si, pi;
+ unsigned int si;
- pi = 0;
for_each_sg(qc->sg, sg, qc->n_elem, si) {
- u32 addr, sg_len, len;
+ u32 addr, sg_len;
/*
* Note: h/w doesn't support 64-bit, so we unconditionally
@@ -487,24 +492,13 @@ static void sata_rcar_bmdma_fill_sg(struct ata_queued_cmd *qc)
addr = (u32)sg_dma_address(sg);
sg_len = sg_dma_len(sg);
- /* H/w transfer count is only 29 bits long, let's be careful */
- while (sg_len) {
- len = sg_len;
- if (len > 0x1ffffffe)
- len = 0x1ffffffe;
-
- prd[pi].addr = cpu_to_le32(addr);
- prd[pi].flags_len = cpu_to_le32(len);
- VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", pi, addr, len);
-
- pi++;
- sg_len -= len;
- addr += len;
- }
+ prd[si].addr = cpu_to_le32(addr);
+ prd[si].flags_len = cpu_to_le32(sg_len);
+ VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", si, addr, sg_len);
}
/* end-of-table flag */
- prd[pi - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
+ prd[si - 1].addr |= cpu_to_le32(SATA_RCAR_DTEND);
}
static void sata_rcar_qc_prep(struct ata_queued_cmd *qc)
@@ -519,15 +513,16 @@ static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int rw = qc->tf.flags & ATA_TFLAG_WRITE;
- u32 dmactl;
struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
+ u32 dmactl;
/* load PRD table addr. */
mb(); /* make sure PRD table writes are visible to controller */
- iowrite32(ap->bmdma_prd_dma, priv->base + ATAPI_DTB_ADR_REG);
+ iowrite32(ap->bmdma_prd_dma, base + ATAPI_DTB_ADR_REG);
/* specify data direction, triple-check start bit is clear */
- dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl = ioread32(base + ATAPI_CONTROL1_REG);
dmactl &= ~(ATAPI_CONTROL1_RW | ATAPI_CONTROL1_STOP);
if (dmactl & ATAPI_CONTROL1_START) {
dmactl &= ~ATAPI_CONTROL1_START;
@@ -535,7 +530,7 @@ static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
}
if (!rw)
dmactl |= ATAPI_CONTROL1_RW;
- iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+ iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
/* issue r/w command */
ap->ops->sff_exec_command(ap, &qc->tf);
@@ -544,28 +539,30 @@ static void sata_rcar_bmdma_setup(struct ata_queued_cmd *qc)
static void sata_rcar_bmdma_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- u32 dmactl;
struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
+ u32 dmactl;
/* start host DMA transaction */
- dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl = ioread32(base + ATAPI_CONTROL1_REG);
dmactl &= ~ATAPI_CONTROL1_STOP;
dmactl |= ATAPI_CONTROL1_START;
- iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+ iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
}
static void sata_rcar_bmdma_stop(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct sata_rcar_priv *priv = ap->host->private_data;
+ void __iomem *base = priv->base;
u32 dmactl;
/* force termination of DMA transfer if active */
- dmactl = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ dmactl = ioread32(base + ATAPI_CONTROL1_REG);
if (dmactl & ATAPI_CONTROL1_START) {
dmactl &= ~ATAPI_CONTROL1_START;
dmactl |= ATAPI_CONTROL1_STOP;
- iowrite32(dmactl, priv->base + ATAPI_CONTROL1_REG);
+ iowrite32(dmactl, base + ATAPI_CONTROL1_REG);
}
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
@@ -575,8 +572,8 @@ static void sata_rcar_bmdma_stop(struct ata_queued_cmd *qc)
static u8 sata_rcar_bmdma_status(struct ata_port *ap)
{
struct sata_rcar_priv *priv = ap->host->private_data;
- u32 status;
u8 host_stat = 0;
+ u32 status;
status = ioread32(priv->base + ATAPI_STATUS_REG);
if (status & ATAPI_STATUS_DEVINT)
@@ -588,7 +585,14 @@ static u8 sata_rcar_bmdma_status(struct ata_port *ap)
}
static struct scsi_host_template sata_rcar_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ /*
+ * This controller allows transfer chunks up to 512MB which cross 64KB
+ * boundaries, therefore the DMA limits are more relaxed than standard
+ * ATA SFF.
+ */
+ .sg_tablesize = ATA_MAX_PRD,
+ .dma_boundary = SATA_RCAR_DMA_BOUNDARY,
};
static struct ata_port_operations sata_rcar_port_ops = {
@@ -668,19 +672,20 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct sata_rcar_priv *priv = host->private_data;
- struct ata_port *ap;
+ void __iomem *base = priv->base;
unsigned int handled = 0;
+ struct ata_port *ap;
u32 sataintstat;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
- sataintstat = ioread32(priv->base + SATAINTSTAT_REG);
+ sataintstat = ioread32(base + SATAINTSTAT_REG);
sataintstat &= SATA_RCAR_INT_MASK;
if (!sataintstat)
goto done;
/* ack */
- iowrite32(~sataintstat & 0x7ff, priv->base + SATAINTSTAT_REG);
+ iowrite32(~sataintstat & 0x7ff, base + SATAINTSTAT_REG);
ap = host->ports[0];
@@ -702,15 +707,16 @@ static void sata_rcar_setup_port(struct ata_host *host)
struct ata_port *ap = host->ports[0];
struct ata_ioports *ioaddr = &ap->ioaddr;
struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
ap->ops = &sata_rcar_port_ops;
ap->pio_mask = ATA_PIO4;
ap->udma_mask = ATA_UDMA6;
ap->flags |= ATA_FLAG_SATA;
- ioaddr->cmd_addr = priv->base + SDATA_REG;
- ioaddr->ctl_addr = priv->base + SSDEVCON_REG;
- ioaddr->scr_addr = priv->base + SCRSSTS_REG;
+ ioaddr->cmd_addr = base + SDATA_REG;
+ ioaddr->ctl_addr = base + SSDEVCON_REG;
+ ioaddr->scr_addr = base + SCRSSTS_REG;
ioaddr->altstatus_addr = ioaddr->ctl_addr;
ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << 2);
@@ -728,6 +734,7 @@ static void sata_rcar_setup_port(struct ata_host *host)
static void sata_rcar_init_controller(struct ata_host *host)
{
struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
u32 val;
/* reset and setup phy */
@@ -740,27 +747,27 @@ static void sata_rcar_init_controller(struct ata_host *host)
sata_rcar_phy_write(priv, SATAPCTLR4_REG, 0x28E80000, 0);
/* SATA-IP reset state */
- val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val = ioread32(base + ATAPI_CONTROL1_REG);
val |= ATAPI_CONTROL1_RESET;
- iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+ iowrite32(val, base + ATAPI_CONTROL1_REG);
/* ISM mode, PRD mode, DTEND flag at bit 0 */
- val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val = ioread32(base + ATAPI_CONTROL1_REG);
val |= ATAPI_CONTROL1_ISM;
val |= ATAPI_CONTROL1_DESE;
val |= ATAPI_CONTROL1_DTA32M;
- iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+ iowrite32(val, base + ATAPI_CONTROL1_REG);
/* Release the SATA-IP from the reset state */
- val = ioread32(priv->base + ATAPI_CONTROL1_REG);
+ val = ioread32(base + ATAPI_CONTROL1_REG);
val &= ~ATAPI_CONTROL1_RESET;
- iowrite32(val, priv->base + ATAPI_CONTROL1_REG);
+ iowrite32(val, base + ATAPI_CONTROL1_REG);
/* ack and mask */
- iowrite32(0, priv->base + SATAINTSTAT_REG);
- iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ iowrite32(0, base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
/* enable interrupts */
- iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
}
static int sata_rcar_probe(struct platform_device *pdev)
@@ -825,16 +832,17 @@ cleanup:
static int sata_rcar_remove(struct platform_device *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = platform_get_drvdata(pdev);
struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
ata_host_detach(host);
/* disable interrupts */
- iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+ iowrite32(0, base + ATAPI_INT_ENABLE_REG);
/* ack and mask */
- iowrite32(0, priv->base + SATAINTSTAT_REG);
- iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ iowrite32(0, base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
clk_disable(priv->clk);
@@ -846,14 +854,15 @@ static int sata_rcar_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
int ret;
ret = ata_host_suspend(host, PMSG_SUSPEND);
if (!ret) {
/* disable interrupts */
- iowrite32(0, priv->base + ATAPI_INT_ENABLE_REG);
+ iowrite32(0, base + ATAPI_INT_ENABLE_REG);
/* mask */
- iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
clk_disable(priv->clk);
}
@@ -865,14 +874,15 @@ static int sata_rcar_resume(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct sata_rcar_priv *priv = host->private_data;
+ void __iomem *base = priv->base;
clk_enable(priv->clk);
/* ack and mask */
- iowrite32(0, priv->base + SATAINTSTAT_REG);
- iowrite32(0x7ff, priv->base + SATAINTMASK_REG);
+ iowrite32(0, base + SATAINTSTAT_REG);
+ iowrite32(0x7ff, base + SATAINTMASK_REG);
/* enable interrupts */
- iowrite32(ATAPI_INT_ENABLE_SATAINT, priv->base + ATAPI_INT_ENABLE_REG);
+ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
ata_host_resume(host);
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 0ae3ca4bf5c0..d67fc351343c 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -805,7 +805,7 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PM
static int sil_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
int rc;
rc = ata_pci_device_do_resume(pdev);
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 59f0d630d634..aa1051ba6d13 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -1353,7 +1353,7 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_PM
static int sil24_pci_device_resume(struct pci_dev *pdev)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ata_host *host = pci_get_drvdata(pdev);
void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
int rc;
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 77a7480dc4d1..62a76076b548 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1403,7 +1403,7 @@ static void amb_free_rx_skb (struct atm_vcc * atm_vcc, struct sk_buff * skb) {
rx.host_address = cpu_to_be32 (virt_to_bus (skb->data));
skb->data = skb->head;
- skb->tail = skb->head;
+ skb_reset_tail_pointer(skb);
skb->len = 0;
if (!rx_give (dev, &rx, pool)) {
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 4e22ce3ed73d..48029aa477d9 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_CMA) += dma-contiguous.o
obj-y += power/
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
-obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o
+obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf.o reservation.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index d78b204e65c1..ecc1929d7f6a 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -167,7 +167,7 @@ attribute_container_add_device(struct device *dev,
ic->classdev.parent = get_device(dev);
ic->classdev.class = cont->class;
cont->class->dev_release = attribute_container_release;
- dev_set_name(&ic->classdev, dev_name(dev));
+ dev_set_name(&ic->classdev, "%s", dev_name(dev));
if (fn)
fn(cont, dev, &ic->classdev);
else
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 6fdc53d46fa0..dc3ea237f086 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -403,6 +403,36 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
static struct device_attribute uevent_attr =
__ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
+static ssize_t show_online(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ bool val;
+
+ lock_device_hotplug();
+ val = !dev->offline;
+ unlock_device_hotplug();
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t store_online(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ bool val;
+ int ret;
+
+ ret = strtobool(buf, &val);
+ if (ret < 0)
+ return ret;
+
+ lock_device_hotplug();
+ ret = val ? device_online(dev) : device_offline(dev);
+ unlock_device_hotplug();
+ return ret < 0 ? ret : count;
+}
+
+static struct device_attribute online_attr =
+ __ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
+
static int device_add_attributes(struct device *dev,
struct device_attribute *attrs)
{
@@ -516,6 +546,12 @@ static int device_add_attrs(struct device *dev)
if (error)
goto err_remove_type_groups;
+ if (device_supports_offline(dev) && !dev->offline_disabled) {
+ error = device_create_file(dev, &online_attr);
+ if (error)
+ goto err_remove_type_groups;
+ }
+
return 0;
err_remove_type_groups:
@@ -536,6 +572,7 @@ static void device_remove_attrs(struct device *dev)
struct class *class = dev->class;
const struct device_type *type = dev->type;
+ device_remove_file(dev, &online_attr);
device_remove_groups(dev, dev->groups);
if (type)
@@ -1435,6 +1472,99 @@ EXPORT_SYMBOL_GPL(put_device);
EXPORT_SYMBOL_GPL(device_create_file);
EXPORT_SYMBOL_GPL(device_remove_file);
+static DEFINE_MUTEX(device_hotplug_lock);
+
+void lock_device_hotplug(void)
+{
+ mutex_lock(&device_hotplug_lock);
+}
+
+void unlock_device_hotplug(void)
+{
+ mutex_unlock(&device_hotplug_lock);
+}
+
+static int device_check_offline(struct device *dev, void *not_used)
+{
+ int ret;
+
+ ret = device_for_each_child(dev, NULL, device_check_offline);
+ if (ret)
+ return ret;
+
+ return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0;
+}
+
+/**
+ * device_offline - Prepare the device for hot-removal.
+ * @dev: Device to be put offline.
+ *
+ * Execute the device bus type's .offline() callback, if present, to prepare
+ * the device for a subsequent hot-removal. If that succeeds, the device must
+ * not be used until either it is removed or its bus type's .online() callback
+ * is executed.
+ *
+ * Call under device_hotplug_lock.
+ */
+int device_offline(struct device *dev)
+{
+ int ret;
+
+ if (dev->offline_disabled)
+ return -EPERM;
+
+ ret = device_for_each_child(dev, NULL, device_check_offline);
+ if (ret)
+ return ret;
+
+ device_lock(dev);
+ if (device_supports_offline(dev)) {
+ if (dev->offline) {
+ ret = 1;
+ } else {
+ ret = dev->bus->offline(dev);
+ if (!ret) {
+ kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
+ dev->offline = true;
+ }
+ }
+ }
+ device_unlock(dev);
+
+ return ret;
+}
+
+/**
+ * device_online - Put the device back online after successful device_offline().
+ * @dev: Device to be put back online.
+ *
+ * If device_offline() has been successfully executed for @dev, but the device
+ * has not been removed subsequently, execute its bus type's .online() callback
+ * to indicate that the device can be used again.
+ *
+ * Call under device_hotplug_lock.
+ */
+int device_online(struct device *dev)
+{
+ int ret = 0;
+
+ device_lock(dev);
+ if (device_supports_offline(dev)) {
+ if (dev->offline) {
+ ret = dev->bus->online(dev);
+ if (!ret) {
+ kobject_uevent(&dev->kobj, KOBJ_ONLINE);
+ dev->offline = false;
+ }
+ } else {
+ ret = 1;
+ }
+ }
+ device_unlock(dev);
+
+ return ret;
+}
+
struct root_device {
struct device dev;
struct module *owner;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index c377673320ed..a16d20e389f0 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -13,17 +13,21 @@
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/percpu.h>
+#include <linux/acpi.h>
#include "base.h"
-struct bus_type cpu_subsys = {
- .name = "cpu",
- .dev_name = "cpu",
-};
-EXPORT_SYMBOL_GPL(cpu_subsys);
-
static DEFINE_PER_CPU(struct device *, cpu_sys_devices);
+static int cpu_subsys_match(struct device *dev, struct device_driver *drv)
+{
+ /* ACPI style match is the only one that may succeed. */
+ if (acpi_driver_match_device(dev, drv))
+ return 1;
+
+ return 0;
+}
+
#ifdef CONFIG_HOTPLUG_CPU
static void change_cpu_under_node(struct cpu *cpu,
unsigned int from_nid, unsigned int to_nid)
@@ -34,65 +38,38 @@ static void change_cpu_under_node(struct cpu *cpu,
cpu->node_id = to_nid;
}
-static ssize_t show_online(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int __ref cpu_subsys_online(struct device *dev)
{
struct cpu *cpu = container_of(dev, struct cpu, dev);
+ int cpuid = dev->id;
+ int from_nid, to_nid;
+ int ret;
+
+ cpu_hotplug_driver_lock();
- return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id));
+ from_nid = cpu_to_node(cpuid);
+ ret = cpu_up(cpuid);
+ /*
+ * When hot adding memory to memoryless node and enabling a cpu
+ * on the node, node number of the cpu may internally change.
+ */
+ to_nid = cpu_to_node(cpuid);
+ if (from_nid != to_nid)
+ change_cpu_under_node(cpu, from_nid, to_nid);
+
+ cpu_hotplug_driver_unlock();
+ return ret;
}
-static ssize_t __ref store_online(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int cpu_subsys_offline(struct device *dev)
{
- struct cpu *cpu = container_of(dev, struct cpu, dev);
- int cpuid = cpu->dev.id;
- int from_nid, to_nid;
- ssize_t ret;
+ int ret;
cpu_hotplug_driver_lock();
- switch (buf[0]) {
- case '0':
- ret = cpu_down(cpuid);
- if (!ret)
- kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
- break;
- case '1':
- from_nid = cpu_to_node(cpuid);
- ret = cpu_up(cpuid);
-
- /*
- * When hot adding memory to memoryless node and enabling a cpu
- * on the node, node number of the cpu may internally change.
- */
- to_nid = cpu_to_node(cpuid);
- if (from_nid != to_nid)
- change_cpu_under_node(cpu, from_nid, to_nid);
-
- if (!ret)
- kobject_uevent(&dev->kobj, KOBJ_ONLINE);
- break;
- default:
- ret = -EINVAL;
- }
+ ret = cpu_down(dev->id);
cpu_hotplug_driver_unlock();
-
- if (ret >= 0)
- ret = count;
return ret;
}
-static DEVICE_ATTR(online, 0644, show_online, store_online);
-
-static struct attribute *hotplug_cpu_attrs[] = {
- &dev_attr_online.attr,
- NULL
-};
-
-static struct attribute_group hotplug_cpu_attr_group = {
- .attrs = hotplug_cpu_attrs,
-};
void unregister_cpu(struct cpu *cpu)
{
@@ -127,6 +104,17 @@ static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store);
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
#endif /* CONFIG_HOTPLUG_CPU */
+struct bus_type cpu_subsys = {
+ .name = "cpu",
+ .dev_name = "cpu",
+ .match = cpu_subsys_match,
+#ifdef CONFIG_HOTPLUG_CPU
+ .online = cpu_subsys_online,
+ .offline = cpu_subsys_offline,
+#endif
+};
+EXPORT_SYMBOL_GPL(cpu_subsys);
+
#ifdef CONFIG_KEXEC
#include <linux/kexec.h>
@@ -185,9 +173,6 @@ static const struct attribute_group *hotplugable_cpu_attr_groups[] = {
#ifdef CONFIG_KEXEC
&crash_note_cpu_attr_group,
#endif
-#ifdef CONFIG_HOTPLUG_CPU
- &hotplug_cpu_attr_group,
-#endif
NULL
};
@@ -302,6 +287,8 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
cpu->dev.id = num;
cpu->dev.bus = &cpu_subsys;
cpu->dev.release = cpu_device_release;
+ cpu->dev.offline_disabled = !cpu->hotpluggable;
+ cpu->dev.offline = !cpu_online(num);
#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
cpu->dev.bus->uevent = arch_cpu_uevent;
#endif
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index e315051cfeeb..2b7813ec6d02 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -37,9 +37,14 @@ static inline int base_memory_block_id(int section_nr)
return section_nr / sections_per_block;
}
+static int memory_subsys_online(struct device *dev);
+static int memory_subsys_offline(struct device *dev);
+
static struct bus_type memory_subsys = {
.name = MEMORY_CLASS_NAME,
.dev_name = MEMORY_CLASS_NAME,
+ .online = memory_subsys_online,
+ .offline = memory_subsys_offline,
};
static BLOCKING_NOTIFIER_HEAD(memory_chain);
@@ -262,33 +267,64 @@ static int __memory_block_change_state(struct memory_block *mem,
{
int ret = 0;
- if (mem->state != from_state_req) {
- ret = -EINVAL;
- goto out;
- }
+ if (mem->state != from_state_req)
+ return -EINVAL;
if (to_state == MEM_OFFLINE)
mem->state = MEM_GOING_OFFLINE;
ret = memory_block_action(mem->start_section_nr, to_state, online_type);
+ mem->state = ret ? from_state_req : to_state;
+ return ret;
+}
- if (ret) {
- mem->state = from_state_req;
- goto out;
- }
+static int memory_subsys_online(struct device *dev)
+{
+ struct memory_block *mem = container_of(dev, struct memory_block, dev);
+ int ret;
- mem->state = to_state;
- switch (mem->state) {
- case MEM_OFFLINE:
- kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
- break;
- case MEM_ONLINE:
- kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
- break;
- default:
- break;
+ mutex_lock(&mem->state_mutex);
+
+ ret = mem->state == MEM_ONLINE ? 0 :
+ __memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE,
+ ONLINE_KEEP);
+
+ mutex_unlock(&mem->state_mutex);
+ return ret;
+}
+
+static int memory_subsys_offline(struct device *dev)
+{
+ struct memory_block *mem = container_of(dev, struct memory_block, dev);
+ int ret;
+
+ mutex_lock(&mem->state_mutex);
+
+ ret = mem->state == MEM_OFFLINE ? 0 :
+ __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
+
+ mutex_unlock(&mem->state_mutex);
+ return ret;
+}
+
+static int __memory_block_change_state_uevent(struct memory_block *mem,
+ unsigned long to_state, unsigned long from_state_req,
+ int online_type)
+{
+ int ret = __memory_block_change_state(mem, to_state, from_state_req,
+ online_type);
+ if (!ret) {
+ switch (mem->state) {
+ case MEM_OFFLINE:
+ kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
+ break;
+ case MEM_ONLINE:
+ kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
+ break;
+ default:
+ break;
+ }
}
-out:
return ret;
}
@@ -299,8 +335,8 @@ static int memory_block_change_state(struct memory_block *mem,
int ret;
mutex_lock(&mem->state_mutex);
- ret = __memory_block_change_state(mem, to_state, from_state_req,
- online_type);
+ ret = __memory_block_change_state_uevent(mem, to_state, from_state_req,
+ online_type);
mutex_unlock(&mem->state_mutex);
return ret;
@@ -310,22 +346,34 @@ store_mem_state(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct memory_block *mem;
+ bool offline;
int ret = -EINVAL;
mem = container_of(dev, struct memory_block, dev);
- if (!strncmp(buf, "online_kernel", min_t(int, count, 13)))
+ lock_device_hotplug();
+
+ if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) {
+ offline = false;
ret = memory_block_change_state(mem, MEM_ONLINE,
MEM_OFFLINE, ONLINE_KERNEL);
- else if (!strncmp(buf, "online_movable", min_t(int, count, 14)))
+ } else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) {
+ offline = false;
ret = memory_block_change_state(mem, MEM_ONLINE,
MEM_OFFLINE, ONLINE_MOVABLE);
- else if (!strncmp(buf, "online", min_t(int, count, 6)))
+ } else if (!strncmp(buf, "online", min_t(int, count, 6))) {
+ offline = false;
ret = memory_block_change_state(mem, MEM_ONLINE,
MEM_OFFLINE, ONLINE_KEEP);
- else if(!strncmp(buf, "offline", min_t(int, count, 7)))
+ } else if(!strncmp(buf, "offline", min_t(int, count, 7))) {
+ offline = true;
ret = memory_block_change_state(mem, MEM_OFFLINE,
MEM_ONLINE, -1);
+ }
+ if (!ret)
+ dev->offline = offline;
+
+ unlock_device_hotplug();
if (ret)
return ret;
@@ -523,6 +571,7 @@ int register_memory(struct memory_block *memory)
memory->dev.id = memory->start_section_nr / sections_per_block;
memory->dev.release = memory_block_release;
memory->dev.groups = memory_memblk_attr_groups;
+ memory->dev.offline = memory->state == MEM_OFFLINE;
error = device_register(&memory->dev);
return error;
@@ -646,21 +695,6 @@ int unregister_memory_section(struct mem_section *section)
}
#endif /* CONFIG_MEMORY_HOTREMOVE */
-/*
- * offline one memory block. If the memory block has been offlined, do nothing.
- */
-int offline_memory_block(struct memory_block *mem)
-{
- int ret = 0;
-
- mutex_lock(&mem->state_mutex);
- if (mem->state != MEM_OFFLINE)
- ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
- mutex_unlock(&mem->state_mutex);
-
- return ret;
-}
-
/* return true if the memory block is offlined, otherwise, return false */
bool is_memblock_offlined(struct memory_block *mem)
{
diff --git a/drivers/base/pinctrl.c b/drivers/base/pinctrl.c
index 67a274e86727..5fb74b43848e 100644
--- a/drivers/base/pinctrl.c
+++ b/drivers/base/pinctrl.c
@@ -48,6 +48,25 @@ int pinctrl_bind_pins(struct device *dev)
goto cleanup_get;
}
+#ifdef CONFIG_PM
+ /*
+ * If power management is enabled, we also look for the optional
+ * sleep and idle pin states, with semantics as defined in
+ * <linux/pinctrl/pinctrl-state.h>
+ */
+ dev->pins->sleep_state = pinctrl_lookup_state(dev->pins->p,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(dev->pins->sleep_state))
+ /* Not supplying this state is perfectly legal */
+ dev_dbg(dev, "no sleep pinctrl state\n");
+
+ dev->pins->idle_state = pinctrl_lookup_state(dev->pins->p,
+ PINCTRL_STATE_IDLE);
+ if (IS_ERR(dev->pins->idle_state))
+ /* Not supplying this state is perfectly legal */
+ dev_dbg(dev, "no idle pinctrl state\n");
+#endif
+
return 0;
/*
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index ed75cf6ef9c9..15789875128e 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -29,9 +29,6 @@
/* For automatically allocated device IDs */
static DEFINE_IDA(platform_devid_ida);
-#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \
- driver))
-
struct device platform_bus = {
.init_name = "platform",
};
@@ -890,7 +887,6 @@ int platform_pm_restore(struct device *dev)
static const struct dev_pm_ops platform_dev_pm_ops = {
.runtime_suspend = pm_generic_runtime_suspend,
.runtime_resume = pm_generic_runtime_resume,
- .runtime_idle = pm_generic_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS
};
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 7072404c8b6d..bfb8955c406c 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -2143,7 +2143,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->max_off_time_changed = true;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
- genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
genpd->domain.ops.prepare = pm_genpd_prepare;
genpd->domain.ops.suspend = pm_genpd_suspend;
genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index bfd898b8988e..5ee030a864f9 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -12,29 +12,6 @@
#ifdef CONFIG_PM_RUNTIME
/**
- * pm_generic_runtime_idle - Generic runtime idle callback for subsystems.
- * @dev: Device to handle.
- *
- * If PM operations are defined for the @dev's driver and they include
- * ->runtime_idle(), execute it and return its error code, if nonzero.
- * Otherwise, execute pm_runtime_suspend() for the device and return 0.
- */
-int pm_generic_runtime_idle(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm && pm->runtime_idle) {
- int ret = pm->runtime_idle(dev);
- if (ret)
- return ret;
- }
-
- pm_runtime_suspend(dev);
- return 0;
-}
-EXPORT_SYMBOL_GPL(pm_generic_runtime_idle);
-
-/**
* pm_generic_runtime_suspend - Generic runtime suspend callback for subsystems.
* @dev: Device to suspend.
*
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index f0077cb8e249..c8ec186303db 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -648,14 +648,14 @@ int opp_init_cpufreq_table(struct device *dev,
list_for_each_entry(opp, &dev_opp->opp_list, node) {
if (opp->available) {
- freq_table[i].index = i;
+ freq_table[i].driver_data = i;
freq_table[i].frequency = opp->rate / 1000;
i++;
}
}
mutex_unlock(&dev_opp_list_lock);
- freq_table[i].index = i;
+ freq_table[i].driver_data = i;
freq_table[i].frequency = CPUFREQ_TABLE_END;
*table = &freq_table[0];
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 71671c42ef45..5c1361a9e5dd 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -42,6 +42,7 @@
#include <linux/export.h>
#include <linux/pm_runtime.h>
#include <linux/err.h>
+#include <trace/events/power.h>
#include "power.h"
@@ -305,6 +306,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req,
else if (!dev->power.qos)
ret = dev_pm_qos_constraints_allocate(dev);
+ trace_dev_pm_qos_add_request(dev_name(dev), type, value);
if (!ret) {
req->dev = dev;
req->type = type;
@@ -349,6 +351,8 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
return -EINVAL;
}
+ trace_dev_pm_qos_update_request(dev_name(req->dev), req->type,
+ new_value);
if (curr_value != new_value)
ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value);
@@ -398,6 +402,8 @@ static int __dev_pm_qos_remove_request(struct dev_pm_qos_request *req)
if (IS_ERR_OR_NULL(req->dev->power.qos))
return -ENODEV;
+ trace_dev_pm_qos_remove_request(dev_name(req->dev), req->type,
+ PM_QOS_DEFAULT_VALUE);
ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
memset(req, 0, sizeof(*req));
return ret;
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index ef13ad08afb2..268a35097578 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -293,11 +293,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
/* Pending requests need to be canceled. */
dev->power.request = RPM_REQ_NONE;
- if (dev->power.no_callbacks) {
- /* Assume ->runtime_idle() callback would have suspended. */
- retval = rpm_suspend(dev, rpmflags);
+ if (dev->power.no_callbacks)
goto out;
- }
/* Carry out an asynchronous or a synchronous idle notification. */
if (rpmflags & RPM_ASYNC) {
@@ -306,7 +303,8 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.request_pending = true;
queue_work(pm_wq, &dev->power.work);
}
- goto out;
+ trace_rpm_return_int(dev, _THIS_IP_, 0);
+ return 0;
}
dev->power.idle_notification = true;
@@ -326,14 +324,14 @@ static int rpm_idle(struct device *dev, int rpmflags)
callback = dev->driver->pm->runtime_idle;
if (callback)
- __rpm_callback(callback, dev);
+ retval = __rpm_callback(callback, dev);
dev->power.idle_notification = false;
wake_up_all(&dev->power.wait_queue);
out:
trace_rpm_return_int(dev, _THIS_IP_, retval);
- return retval;
+ return retval ? retval : rpm_suspend(dev, rpmflags);
}
/**
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 79715e7fa43e..2d56f4113ae7 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -659,7 +659,7 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
}
EXPORT_SYMBOL_GPL(pm_wakeup_event);
-static void print_active_wakeup_sources(void)
+void pm_print_active_wakeup_sources(void)
{
struct wakeup_source *ws;
int active = 0;
@@ -683,6 +683,7 @@ static void print_active_wakeup_sources(void)
last_activity_ws->name);
rcu_read_unlock();
}
+EXPORT_SYMBOL_GPL(pm_print_active_wakeup_sources);
/**
* pm_wakeup_pending - Check if power transition in progress should be aborted.
@@ -707,8 +708,10 @@ bool pm_wakeup_pending(void)
}
spin_unlock_irqrestore(&events_lock, flags);
- if (ret)
- print_active_wakeup_sources();
+ if (ret) {
+ pr_info("PM: Wakeup pending, aborting suspend\n");
+ pm_print_active_wakeup_sources();
+ }
return ret;
}
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index c130536e0ab0..29c83160ca29 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -52,6 +52,7 @@ struct regmap_async {
struct regmap {
struct mutex mutex;
spinlock_t spinlock;
+ unsigned long spinlock_flags;
regmap_lock lock;
regmap_unlock unlock;
void *lock_arg; /* This is passed to lock/unlock functions */
@@ -148,6 +149,7 @@ struct regcache_ops {
int (*read)(struct regmap *map, unsigned int reg, unsigned int *value);
int (*write)(struct regmap *map, unsigned int reg, unsigned int value);
int (*sync)(struct regmap *map, unsigned int min, unsigned int max);
+ int (*drop)(struct regmap *map, unsigned int min, unsigned int max);
};
bool regmap_writeable(struct regmap *map, unsigned int reg);
@@ -174,6 +176,14 @@ struct regmap_range_node {
unsigned int window_len;
};
+struct regmap_field {
+ struct regmap *regmap;
+ unsigned int mask;
+ /* lsb */
+ unsigned int shift;
+ unsigned int reg;
+};
+
#ifdef CONFIG_DEBUG_FS
extern void regmap_debugfs_initcall(void);
extern void regmap_debugfs_init(struct regmap *map, const char *name);
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 02f490bad30f..5c1435c4e210 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -304,6 +304,48 @@ static int regcache_rbtree_insert_to_block(struct regmap *map,
return 0;
}
+static struct regcache_rbtree_node *
+regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
+{
+ struct regcache_rbtree_node *rbnode;
+ const struct regmap_range *range;
+ int i;
+
+ rbnode = kzalloc(sizeof(*rbnode), GFP_KERNEL);
+ if (!rbnode)
+ return NULL;
+
+ /* If there is a read table then use it to guess at an allocation */
+ if (map->rd_table) {
+ for (i = 0; i < map->rd_table->n_yes_ranges; i++) {
+ if (regmap_reg_in_range(reg,
+ &map->rd_table->yes_ranges[i]))
+ break;
+ }
+
+ if (i != map->rd_table->n_yes_ranges) {
+ range = &map->rd_table->yes_ranges[i];
+ rbnode->blklen = range->range_max - range->range_min
+ + 1;
+ rbnode->base_reg = range->range_min;
+ }
+ }
+
+ if (!rbnode->blklen) {
+ rbnode->blklen = sizeof(*rbnode);
+ rbnode->base_reg = reg;
+ }
+
+ rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
+ GFP_KERNEL);
+ if (!rbnode->block) {
+ kfree(rbnode);
+ return NULL;
+ }
+
+ return rbnode;
+}
+
static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
unsigned int value)
{
@@ -354,23 +396,15 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
return 0;
}
}
- /* we did not manage to find a place to insert it in an existing
- * block so create a new rbnode with a single register in its block.
- * This block will get populated further if any other adjacent
- * registers get modified in the future.
+
+ /* We did not manage to find a place to insert it in
+ * an existing block so create a new rbnode.
*/
- rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
+ rbnode = regcache_rbtree_node_alloc(map, reg);
if (!rbnode)
return -ENOMEM;
- rbnode->blklen = sizeof(*rbnode);
- rbnode->base_reg = reg;
- rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
- GFP_KERNEL);
- if (!rbnode->block) {
- kfree(rbnode);
- return -ENOMEM;
- }
- regcache_rbtree_set_register(map, rbnode, 0, value);
+ regcache_rbtree_set_register(map, rbnode,
+ reg - rbnode->base_reg, value);
regcache_rbtree_insert(map, &rbtree_ctx->root, rbnode);
rbtree_ctx->cached_rbnode = rbnode;
}
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 507ee2da0f6e..e69102696533 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -250,6 +250,38 @@ int regcache_write(struct regmap *map,
return 0;
}
+static int regcache_default_sync(struct regmap *map, unsigned int min,
+ unsigned int max)
+{
+ unsigned int reg;
+
+ for (reg = min; reg <= max; reg++) {
+ unsigned int val;
+ int ret;
+
+ if (regmap_volatile(map, reg))
+ continue;
+
+ ret = regcache_read(map, reg, &val);
+ 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)
+ continue;
+
+ map->cache_bypass = 1;
+ ret = _regmap_write(map, reg, val);
+ map->cache_bypass = 0;
+ if (ret)
+ return ret;
+ dev_dbg(map->dev, "Synced register %#x, value %#x\n", reg, val);
+ }
+
+ return 0;
+}
+
/**
* regcache_sync: Sync the register cache with the hardware.
*
@@ -268,7 +300,7 @@ int regcache_sync(struct regmap *map)
const char *name;
unsigned int bypass;
- BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+ BUG_ON(!map->cache_ops);
map->lock(map->lock_arg);
/* Remember the initial bypass state */
@@ -297,7 +329,10 @@ int regcache_sync(struct regmap *map)
}
map->cache_bypass = 0;
- ret = map->cache_ops->sync(map, 0, map->max_register);
+ if (map->cache_ops->sync)
+ ret = map->cache_ops->sync(map, 0, map->max_register);
+ else
+ ret = regcache_default_sync(map, 0, map->max_register);
if (ret == 0)
map->cache_dirty = false;
@@ -331,7 +366,7 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
const char *name;
unsigned int bypass;
- BUG_ON(!map->cache_ops || !map->cache_ops->sync);
+ BUG_ON(!map->cache_ops);
map->lock(map->lock_arg);
@@ -346,7 +381,10 @@ int regcache_sync_region(struct regmap *map, unsigned int min,
if (!map->cache_dirty)
goto out;
- ret = map->cache_ops->sync(map, min, max);
+ if (map->cache_ops->sync)
+ ret = map->cache_ops->sync(map, min, max);
+ else
+ ret = regcache_default_sync(map, min, max);
out:
trace_regcache_sync(map->dev, name, "stop region");
@@ -359,6 +397,43 @@ out:
EXPORT_SYMBOL_GPL(regcache_sync_region);
/**
+ * regcache_drop_region: Discard part of the register cache
+ *
+ * @map: map to operate on
+ * @min: first register to discard
+ * @max: last register to discard
+ *
+ * Discard part of the register cache.
+ *
+ * Return a negative value on failure, 0 on success.
+ */
+int regcache_drop_region(struct regmap *map, unsigned int min,
+ unsigned int max)
+{
+ unsigned int reg;
+ int ret = 0;
+
+ if (!map->cache_present && !(map->cache_ops && map->cache_ops->drop))
+ return -EINVAL;
+
+ map->lock(map->lock_arg);
+
+ trace_regcache_drop_region(map->dev, min, max);
+
+ if (map->cache_present)
+ for (reg = min; reg < max + 1; reg++)
+ clear_bit(reg, map->cache_present);
+
+ if (map->cache_ops && map->cache_ops->drop)
+ ret = map->cache_ops->drop(map, min, max);
+
+ map->unlock(map->lock_arg);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regcache_drop_region);
+
+/**
* regcache_cache_only: Put a register map into cache only mode
*
* @map: map to configure
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 975719bc3450..53495753fbdb 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -84,6 +84,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
unsigned int fpos_offset;
unsigned int reg_offset;
+ /* Suppress the cache if we're using a subrange */
+ if (from)
+ return from;
+
/*
* If we don't have a cache build one so we don't have to do a
* linear scan each time.
@@ -145,7 +149,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
reg_offset = fpos_offset / map->debugfs_tot_len;
*pos = c->min + (reg_offset * map->debugfs_tot_len);
mutex_unlock(&map->cache_lock);
- return c->base_reg + reg_offset;
+ return c->base_reg + (reg_offset * map->reg_stride);
}
*pos = c->max;
@@ -281,7 +285,7 @@ static ssize_t regmap_map_write_file(struct file *file,
return -EINVAL;
/* Userspace has been fiddling around behind the kernel's back */
- add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
+ add_taint(TAINT_USER, LOCKDEP_STILL_OK);
ret = regmap_write(map, reg, value);
if (ret < 0)
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index a941dcfe7590..95920583e31e 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -65,9 +65,8 @@ bool regmap_reg_in_ranges(unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_reg_in_ranges);
-static bool _regmap_check_range_table(struct regmap *map,
- unsigned int reg,
- const struct regmap_access_table *table)
+bool regmap_check_range_table(struct regmap *map, unsigned int reg,
+ const struct regmap_access_table *table)
{
/* Check "no ranges" first */
if (regmap_reg_in_ranges(reg, table->no_ranges, table->n_no_ranges))
@@ -80,6 +79,7 @@ static bool _regmap_check_range_table(struct regmap *map,
return regmap_reg_in_ranges(reg, table->yes_ranges,
table->n_yes_ranges);
}
+EXPORT_SYMBOL_GPL(regmap_check_range_table);
bool regmap_writeable(struct regmap *map, unsigned int reg)
{
@@ -90,7 +90,7 @@ bool regmap_writeable(struct regmap *map, unsigned int reg)
return map->writeable_reg(map->dev, reg);
if (map->wr_table)
- return _regmap_check_range_table(map, reg, map->wr_table);
+ return regmap_check_range_table(map, reg, map->wr_table);
return true;
}
@@ -107,7 +107,7 @@ bool regmap_readable(struct regmap *map, unsigned int reg)
return map->readable_reg(map->dev, reg);
if (map->rd_table)
- return _regmap_check_range_table(map, reg, map->rd_table);
+ return regmap_check_range_table(map, reg, map->rd_table);
return true;
}
@@ -121,9 +121,12 @@ bool regmap_volatile(struct regmap *map, unsigned int reg)
return map->volatile_reg(map->dev, reg);
if (map->volatile_table)
- return _regmap_check_range_table(map, reg, map->volatile_table);
+ return regmap_check_range_table(map, reg, map->volatile_table);
- return true;
+ if (map->cache_ops)
+ return false;
+ else
+ return true;
}
bool regmap_precious(struct regmap *map, unsigned int reg)
@@ -135,7 +138,7 @@ bool regmap_precious(struct regmap *map, unsigned int reg)
return map->precious_reg(map->dev, reg);
if (map->precious_table)
- return _regmap_check_range_table(map, reg, map->precious_table);
+ return regmap_check_range_table(map, reg, map->precious_table);
return false;
}
@@ -302,13 +305,16 @@ static void regmap_unlock_mutex(void *__map)
static void regmap_lock_spinlock(void *__map)
{
struct regmap *map = __map;
- spin_lock(&map->spinlock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&map->spinlock, flags);
+ map->spinlock_flags = flags;
}
static void regmap_unlock_spinlock(void *__map)
{
struct regmap *map = __map;
- spin_unlock(&map->spinlock);
+ spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags);
}
static void dev_get_regmap_release(struct device *dev, void *res)
@@ -801,6 +807,95 @@ struct regmap *devm_regmap_init(struct device *dev,
}
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);
+}
+
+/**
+ * devm_regmap_field_alloc(): Allocate and initialise a register field
+ * in a register map.
+ *
+ * @dev: Device that will be interacted with
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field will be automatically freed
+ * by the device management code.
+ */
+struct regmap_field *devm_regmap_field_alloc(struct device *dev,
+ struct regmap *regmap, struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = devm_kzalloc(dev,
+ sizeof(*rm_field), GFP_KERNEL);
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+
+}
+EXPORT_SYMBOL_GPL(devm_regmap_field_alloc);
+
+/**
+ * devm_regmap_field_free(): Free register field allocated using
+ * devm_regmap_field_alloc. Usally drivers need not call this function,
+ * as the memory allocated via devm will be freed as per device-driver
+ * life-cyle.
+ *
+ * @dev: Device that will be interacted with
+ * @field: regmap field which should be freed.
+ */
+void devm_regmap_field_free(struct device *dev,
+ struct regmap_field *field)
+{
+ devm_kfree(dev, field);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_field_free);
+
+/**
+ * regmap_field_alloc(): Allocate and initialise a register field
+ * in a register map.
+ *
+ * @regmap: regmap bank in which this register field is located.
+ * @reg_field: Register field with in the bank.
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap_field. The regmap_field should be freed by the
+ * user once its finished working with it using regmap_field_free().
+ */
+struct regmap_field *regmap_field_alloc(struct regmap *regmap,
+ struct reg_field reg_field)
+{
+ struct regmap_field *rm_field = kzalloc(sizeof(*rm_field), GFP_KERNEL);
+
+ if (!rm_field)
+ return ERR_PTR(-ENOMEM);
+
+ regmap_field_init(rm_field, regmap, reg_field);
+
+ return rm_field;
+}
+EXPORT_SYMBOL_GPL(regmap_field_alloc);
+
+/**
+ * regmap_field_free(): Free register field allocated using regmap_field_alloc
+ *
+ * @field: regmap field which should be freed.
+ */
+void regmap_field_free(struct regmap_field *field)
+{
+ kfree(field);
+}
+EXPORT_SYMBOL_GPL(regmap_field_free);
+
/**
* regmap_reinit_cache(): Reinitialise the current register cache
*
@@ -1249,6 +1344,22 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
}
EXPORT_SYMBOL_GPL(regmap_raw_write);
+/**
+ * regmap_field_write(): Write a value to a single register field
+ *
+ * @field: Register field to write to
+ * @val: Value to be written
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_field_write(struct regmap_field *field, unsigned int val)
+{
+ return regmap_update_bits(field->regmap, field->reg,
+ field->mask, val << field->shift);
+}
+EXPORT_SYMBOL_GPL(regmap_field_write);
+
/*
* regmap_bulk_write(): Write multiple registers to the device
*
@@ -1532,6 +1643,31 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
EXPORT_SYMBOL_GPL(regmap_raw_read);
/**
+ * regmap_field_read(): Read a value to a single register field
+ *
+ * @field: Register field to read from
+ * @val: Pointer to store read value
+ *
+ * A value of zero will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+int regmap_field_read(struct regmap_field *field, unsigned int *val)
+{
+ int ret;
+ unsigned int reg_val;
+ ret = regmap_read(field->regmap, field->reg, &reg_val);
+ if (ret != 0)
+ return ret;
+
+ reg_val &= field->mask;
+ reg_val >>= field->shift;
+ *val = reg_val;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_field_read);
+
+/**
* regmap_bulk_read(): Read multiple registers from the device
*
* @map: Register map to write to
diff --git a/drivers/base/reservation.c b/drivers/base/reservation.c
new file mode 100644
index 000000000000..a73fbf3b8e56
--- /dev/null
+++ b/drivers/base/reservation.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012-2013 Canonical Ltd
+ *
+ * Based on bo.c which bears the following copyright notice,
+ * but is dual licensed:
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include <linux/reservation.h>
+#include <linux/export.h>
+
+DEFINE_WW_CLASS(reservation_ww_class);
+EXPORT_SYMBOL(reservation_ww_class);
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
index 8b4221cfd118..380a2003231e 100644
--- a/drivers/bcma/Kconfig
+++ b/drivers/bcma/Kconfig
@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE
config BCMA_HOST_PCI
bool "Support for BCMA on PCI-host bus"
depends on BCMA_HOST_PCI_POSSIBLE
+ default y
config BCMA_DRIVER_PCI_HOSTMODE
bool "Driver for PCI core working in hostmode"
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 79595a001204..0215f9ad755c 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -22,6 +22,8 @@
struct bcma_bus;
/* main.c */
+bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
+ int timeout);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
int __init bcma_bus_early_register(struct bcma_bus *bus,
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
index 17b26ce7e051..37a5ffe673d5 100644
--- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c
@@ -9,6 +9,25 @@
#include <linux/export.h>
#include <linux/bcma/bcma.h>
+static bool bcma_core_wait_value(struct bcma_device *core, u16 reg, u32 mask,
+ u32 value, int timeout)
+{
+ unsigned long deadline = jiffies + timeout;
+ u32 val;
+
+ do {
+ val = bcma_aread32(core, reg);
+ if ((val & mask) == value)
+ return true;
+ cpu_relax();
+ udelay(10);
+ } while (!time_after_eq(jiffies, deadline));
+
+ bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg);
+
+ return false;
+}
+
bool bcma_core_is_enabled(struct bcma_device *core)
{
if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC))
@@ -25,13 +44,15 @@ void bcma_core_disable(struct bcma_device *core, u32 flags)
if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
return;
- bcma_awrite32(core, BCMA_IOCTL, flags);
- bcma_aread32(core, BCMA_IOCTL);
- udelay(10);
+ bcma_core_wait_value(core, BCMA_RESET_ST, ~0, 0, 300);
bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
bcma_aread32(core, BCMA_RESET_CTL);
udelay(1);
+
+ bcma_awrite32(core, BCMA_IOCTL, flags);
+ bcma_aread32(core, BCMA_IOCTL);
+ udelay(10);
}
EXPORT_SYMBOL_GPL(bcma_core_disable);
@@ -43,6 +64,7 @@ int bcma_core_enable(struct bcma_device *core, u32 flags)
bcma_aread32(core, BCMA_IOCTL);
bcma_awrite32(core, BCMA_RESET_CTL, 0);
+ bcma_aread32(core, BCMA_RESET_CTL);
udelay(1);
bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 036c6744b39b..b068f98920a8 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -140,8 +140,15 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
bcma_core_chipcommon_early_init(cc);
if (cc->core->id.rev >= 20) {
- bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
- bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
+ u32 pullup = 0, pulldown = 0;
+
+ if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM43142) {
+ pullup = 0x402e0;
+ pulldown = 0x20500;
+ }
+
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, pullup);
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, pulldown);
}
if (cc->capabilities & BCMA_CC_CAP_PMU)
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
index edca73af3cc0..5081a8c439cc 100644
--- a/drivers/bcma/driver_chipcommon_pmu.c
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -56,6 +56,109 @@ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
}
EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
+static u32 bcma_pmu_xtalfreq(struct bcma_drv_cc *cc)
+{
+ u32 ilp_ctl, alp_hz;
+
+ if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
+ BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
+ return 0;
+
+ bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+ BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+ usleep_range(1000, 2000);
+
+ ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+ ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
+
+ bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+
+ alp_hz = ilp_ctl * 32768 / 4;
+ return (alp_hz + 50000) / 100000 * 100;
+}
+
+static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
+{
+ struct bcma_bus *bus = cc->core->bus;
+ u32 freq_tgt_target = 0, freq_tgt_current;
+ u32 pll0, mask;
+
+ switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM43142:
+ /* pmu2_xtaltab0_adfll_485 */
+ switch (xtalfreq) {
+ case 12000:
+ freq_tgt_target = 0x50D52;
+ break;
+ case 20000:
+ freq_tgt_target = 0x307FE;
+ break;
+ case 26000:
+ freq_tgt_target = 0x254EA;
+ break;
+ case 37400:
+ freq_tgt_target = 0x19EF8;
+ break;
+ case 52000:
+ freq_tgt_target = 0x12A75;
+ break;
+ }
+ break;
+ }
+
+ if (!freq_tgt_target) {
+ bcma_err(bus, "Unknown TGT frequency for xtalfreq %d\n",
+ xtalfreq);
+ return;
+ }
+
+ pll0 = bcma_chipco_pll_read(cc, BCMA_CC_PMU15_PLL_PLLCTL0);
+ freq_tgt_current = (pll0 & BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK) >>
+ BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT;
+
+ if (freq_tgt_current == freq_tgt_target) {
+ bcma_debug(bus, "Target TGT frequency already set\n");
+ return;
+ }
+
+ /* Turn off PLL */
+ switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM43142:
+ mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
+ BCMA_RES_4314_MACPHY_CLK_AVAIL);
+
+ bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+ bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+ bcma_wait_value(cc->core, BCMA_CLKCTLST,
+ BCMA_CLKCTLST_HAVEHT, 0, 20000);
+ break;
+ }
+
+ pll0 &= ~BCMA_CC_PMU15_PLL_PC0_FREQTGT_MASK;
+ pll0 |= freq_tgt_target << BCMA_CC_PMU15_PLL_PC0_FREQTGT_SHIFT;
+ bcma_chipco_pll_write(cc, BCMA_CC_PMU15_PLL_PLLCTL0, pll0);
+
+ /* Flush */
+ if (cc->pmu.rev >= 2)
+ bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+
+ /* TODO: Do we need to update OTP? */
+}
+
+static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+ u32 xtalfreq = bcma_pmu_xtalfreq(cc);
+
+ switch (bus->chipinfo.id) {
+ case BCMA_CHIP_ID_BCM43142:
+ if (xtalfreq == 0)
+ xtalfreq = 20000;
+ bcma_pmu2_pll_init0(cc, xtalfreq);
+ break;
+ }
+}
+
static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
@@ -66,6 +169,25 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
min_msk = 0x200D;
max_msk = 0xFFFF;
break;
+ case BCMA_CHIP_ID_BCM43142:
+ min_msk = BCMA_RES_4314_LPLDO_PU |
+ BCMA_RES_4314_PMU_SLEEP_DIS |
+ BCMA_RES_4314_PMU_BG_PU |
+ BCMA_RES_4314_CBUCK_LPOM_PU |
+ BCMA_RES_4314_CBUCK_PFM_PU |
+ BCMA_RES_4314_CLDO_PU |
+ BCMA_RES_4314_LPLDO2_LVM |
+ BCMA_RES_4314_WL_PMU_PU |
+ BCMA_RES_4314_LDO3P3_PU |
+ BCMA_RES_4314_OTP_PU |
+ BCMA_RES_4314_WL_PWRSW_PU |
+ BCMA_RES_4314_LQ_AVAIL |
+ BCMA_RES_4314_LOGIC_RET |
+ BCMA_RES_4314_MEM_SLEEP |
+ BCMA_RES_4314_MACPHY_RET |
+ BCMA_RES_4314_WL_CORE_READY;
+ max_msk = 0x3FFFFFFF;
+ break;
default:
bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n",
bus->chipinfo.id);
@@ -165,6 +287,7 @@ void bcma_pmu_init(struct bcma_drv_cc *cc)
bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
BCMA_CC_PMU_CTL_NOILPONW);
+ bcma_pmu_pll_init(cc);
bcma_pmu_resources_init(cc);
bcma_pmu_workarounds(cc);
}
diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c
index e6ed4fe5dced..4d07cce9c5d9 100644
--- a/drivers/bcma/driver_chipcommon_sflash.c
+++ b/drivers/bcma/driver_chipcommon_sflash.c
@@ -30,7 +30,7 @@ struct bcma_sflash_tbl_e {
u16 numblocks;
};
-static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
+static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
{ "M25P20", 0x11, 0x10000, 4, },
{ "M25P40", 0x12, 0x10000, 8, },
@@ -41,7 +41,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
{ 0 },
};
-static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
+static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
{ "SST25WF512", 1, 0x1000, 16, },
{ "SST25VF512", 0x48, 0x1000, 16, },
{ "SST25WF010", 2, 0x1000, 32, },
@@ -59,7 +59,7 @@ static struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
{ 0 },
};
-static struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
+static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
{ "AT45DB011", 0xc, 256, 512, },
{ "AT45DB021", 0x14, 256, 1024, },
{ "AT45DB041", 0x1c, 256, 2048, },
@@ -89,7 +89,7 @@ int bcma_sflash_init(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
struct bcma_sflash *sflash = &cc->sflash;
- struct bcma_sflash_tbl_e *e;
+ const struct bcma_sflash_tbl_e *e;
u32 id, id2;
switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index fbf2759e7e4e..a355e63a3838 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -275,6 +275,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
{ 0, },
};
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index f72f52b4b1dd..0067422ec17d 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -93,6 +93,25 @@ struct bcma_device *bcma_find_core_unit(struct bcma_bus *bus, u16 coreid,
return NULL;
}
+bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
+ int timeout)
+{
+ unsigned long deadline = jiffies + timeout;
+ u32 val;
+
+ do {
+ val = bcma_read32(core, reg);
+ if ((val & mask) == value)
+ return true;
+ cpu_relax();
+ udelay(10);
+ } while (!time_after_eq(jiffies, deadline));
+
+ bcma_warn(core->bus, "Timeout waiting for register 0x%04X!\n", reg);
+
+ return false;
+}
+
static void bcma_release_core_dev(struct device *dev)
{
struct bcma_device *core = container_of(dev, struct bcma_device, dev);
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index 8934298a638d..72bf4540f565 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -72,12 +72,12 @@ fail:
* R/W ops.
**************************************************/
-static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom)
+static void bcma_sprom_read(struct bcma_bus *bus, u16 offset, u16 *sprom,
+ size_t words)
{
int i;
- for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
- sprom[i] = bcma_read16(bus->drv_cc.core,
- offset + (i * 2));
+ for (i = 0; i < words; i++)
+ sprom[i] = bcma_read16(bus->drv_cc.core, offset + (i * 2));
}
/**************************************************
@@ -124,29 +124,29 @@ static inline u8 bcma_crc8(u8 crc, u8 data)
return t[crc ^ data];
}
-static u8 bcma_sprom_crc(const u16 *sprom)
+static u8 bcma_sprom_crc(const u16 *sprom, size_t words)
{
int word;
u8 crc = 0xFF;
- for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
+ for (word = 0; word < words - 1; word++) {
crc = bcma_crc8(crc, sprom[word] & 0x00FF);
crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
}
- crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
+ crc = bcma_crc8(crc, sprom[words - 1] & 0x00FF);
crc ^= 0xFF;
return crc;
}
-static int bcma_sprom_check_crc(const u16 *sprom)
+static int bcma_sprom_check_crc(const u16 *sprom, size_t words)
{
u8 crc;
u8 expected_crc;
u16 tmp;
- crc = bcma_sprom_crc(sprom);
- tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
+ crc = bcma_sprom_crc(sprom, words);
+ tmp = sprom[words - 1] & SSB_SPROM_REVISION_CRC;
expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
if (crc != expected_crc)
return -EPROTO;
@@ -154,21 +154,25 @@ static int bcma_sprom_check_crc(const u16 *sprom)
return 0;
}
-static int bcma_sprom_valid(const u16 *sprom)
+static int bcma_sprom_valid(struct bcma_bus *bus, const u16 *sprom,
+ size_t words)
{
u16 revision;
int err;
- err = bcma_sprom_check_crc(sprom);
+ err = bcma_sprom_check_crc(sprom, words);
if (err)
return err;
- revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
- if (revision != 8 && revision != 9) {
+ revision = sprom[words - 1] & SSB_SPROM_REVISION_REV;
+ if (revision != 8 && revision != 9 && revision != 10) {
pr_err("Unsupported SPROM revision: %d\n", revision);
return -ENOENT;
}
+ bus->sprom.revision = revision;
+ bcma_debug(bus, "Found SPROM revision %d\n", revision);
+
return 0;
}
@@ -208,9 +212,6 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
BUILD_BUG_ON(ARRAY_SIZE(pwr_info_offset) !=
ARRAY_SIZE(bus->sprom.core_pwr_info));
- bus->sprom.revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] &
- SSB_SPROM_REVISION_REV;
-
for (i = 0; i < 3; i++) {
v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
*(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
@@ -502,7 +503,7 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
case BCMA_CHIP_ID_BCM4331:
present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
break;
-
+ case BCMA_CHIP_ID_BCM43142:
case BCMA_CHIP_ID_BCM43224:
case BCMA_CHIP_ID_BCM43225:
/* for these chips OTP is always available */
@@ -550,7 +551,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
{
u16 offset = BCMA_CC_SPROM;
u16 *sprom;
- int err = 0;
+ size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
+ SSB_SPROMSIZE_WORDS_R10, };
+ int i, err = 0;
if (!bus->drv_cc.core)
return -EOPNOTSUPP;
@@ -579,32 +582,37 @@ int bcma_sprom_get(struct bcma_bus *bus)
}
}
- sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
- GFP_KERNEL);
- if (!sprom)
- return -ENOMEM;
-
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
bcma_debug(bus, "SPROM offset 0x%x\n", offset);
- bcma_sprom_read(bus, offset, sprom);
+ for (i = 0; i < ARRAY_SIZE(sprom_sizes); i++) {
+ size_t words = sprom_sizes[i];
+
+ sprom = kcalloc(words, sizeof(u16), GFP_KERNEL);
+ if (!sprom)
+ return -ENOMEM;
+
+ bcma_sprom_read(bus, offset, sprom, words);
+ err = bcma_sprom_valid(bus, sprom, words);
+ if (!err)
+ break;
+
+ kfree(sprom);
+ }
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
- err = bcma_sprom_valid(sprom);
if (err) {
- bcma_warn(bus, "invalid sprom read from the PCIe card, try to use fallback sprom\n");
+ bcma_warn(bus, "Invalid SPROM read from the PCIe card, trying to use fallback SPROM\n");
err = bcma_fill_sprom_with_fallback(bus, &bus->sprom);
- goto out;
+ } else {
+ bcma_sprom_extract_r8(bus, sprom);
+ kfree(sprom);
}
- bcma_sprom_extract_r8(bus, sprom);
-
-out:
- kfree(sprom);
return err;
}
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 175649468c95..025c41d3cb33 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */
-#define VERSION "81"
+/* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */
+#define VERSION "83"
#define AOE_MAJOR 152
#define DEVICE_NAME "aoe"
@@ -196,9 +196,11 @@ struct ktstate {
struct completion rendez;
struct task_struct *task;
wait_queue_head_t *waitq;
- int (*fn) (void);
- char *name;
+ int (*fn) (int);
+ char name[12];
spinlock_t *lock;
+ int id;
+ int active;
};
int aoeblk_init(void);
@@ -222,6 +224,7 @@ int aoecmd_init(void);
struct sk_buff *aoecmd_ata_id(struct aoedev *);
void aoe_freetframe(struct frame *);
void aoe_flush_iocq(void);
+void aoe_flush_iocq_by_index(int);
void aoe_end_request(struct aoedev *, struct request *, int);
int aoe_ktstart(struct ktstate *k);
void aoe_ktstop(struct ktstate *k);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index fc803ecbbce4..99cb944a002d 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoecmd.c
* Filesystem request handling methods
@@ -35,14 +35,27 @@ module_param(aoe_maxout, int, 0644);
MODULE_PARM_DESC(aoe_maxout,
"Only aoe_maxout outstanding packets for every MAC on eX.Y.");
-static wait_queue_head_t ktiowq;
-static struct ktstate kts;
+/* The number of online cpus during module initialization gives us a
+ * convenient heuristic cap on the parallelism used for ktio threads
+ * doing I/O completion. It is not important that the cap equal the
+ * actual number of running CPUs at any given time, but because of CPU
+ * hotplug, we take care to use ncpus instead of using
+ * num_online_cpus() after module initialization.
+ */
+static int ncpus;
+
+/* mutex lock used for synchronization while thread spawning */
+static DEFINE_MUTEX(ktio_spawn_lock);
+
+static wait_queue_head_t *ktiowq;
+static struct ktstate *kts;
/* io completion queue */
-static struct {
+struct iocq_ktio {
struct list_head head;
spinlock_t lock;
-} iocq;
+};
+static struct iocq_ktio *iocq;
static struct page *empty_page;
@@ -1278,23 +1291,36 @@ out:
* Returns true iff responses needing processing remain.
*/
static int
-ktio(void)
+ktio(int id)
{
struct frame *f;
struct list_head *pos;
int i;
+ int actual_id;
for (i = 0; ; ++i) {
if (i == MAXIOC)
return 1;
- if (list_empty(&iocq.head))
+ if (list_empty(&iocq[id].head))
return 0;
- pos = iocq.head.next;
+ pos = iocq[id].head.next;
list_del(pos);
- spin_unlock_irq(&iocq.lock);
f = list_entry(pos, struct frame, head);
+ spin_unlock_irq(&iocq[id].lock);
ktiocomplete(f);
- spin_lock_irq(&iocq.lock);
+
+ /* Figure out if extra threads are required. */
+ actual_id = f->t->d->aoeminor % ncpus;
+
+ if (!kts[actual_id].active) {
+ BUG_ON(id != 0);
+ mutex_lock(&ktio_spawn_lock);
+ if (!kts[actual_id].active
+ && aoe_ktstart(&kts[actual_id]) == 0)
+ kts[actual_id].active = 1;
+ mutex_unlock(&ktio_spawn_lock);
+ }
+ spin_lock_irq(&iocq[id].lock);
}
}
@@ -1311,7 +1337,7 @@ kthread(void *vp)
complete(&k->rendez); /* tell spawner we're running */
do {
spin_lock_irq(k->lock);
- more = k->fn();
+ more = k->fn(k->id);
if (!more) {
add_wait_queue(k->waitq, &wait);
__set_current_state(TASK_INTERRUPTIBLE);
@@ -1340,7 +1366,7 @@ aoe_ktstart(struct ktstate *k)
struct task_struct *task;
init_completion(&k->rendez);
- task = kthread_run(kthread, k, k->name);
+ task = kthread_run(kthread, k, "%s", k->name);
if (task == NULL || IS_ERR(task))
return -ENOMEM;
k->task = task;
@@ -1353,13 +1379,24 @@ aoe_ktstart(struct ktstate *k)
static void
ktcomplete(struct frame *f, struct sk_buff *skb)
{
+ int id;
ulong flags;
f->r_skb = skb;
- spin_lock_irqsave(&iocq.lock, flags);
- list_add_tail(&f->head, &iocq.head);
- spin_unlock_irqrestore(&iocq.lock, flags);
- wake_up(&ktiowq);
+ id = f->t->d->aoeminor % ncpus;
+ spin_lock_irqsave(&iocq[id].lock, flags);
+ if (!kts[id].active) {
+ spin_unlock_irqrestore(&iocq[id].lock, flags);
+ /* The thread with id has not been spawned yet,
+ * so delegate the work to the main thread and
+ * try spawning a new thread.
+ */
+ id = 0;
+ spin_lock_irqsave(&iocq[id].lock, flags);
+ }
+ list_add_tail(&f->head, &iocq[id].head);
+ spin_unlock_irqrestore(&iocq[id].lock, flags);
+ wake_up(&ktiowq[id]);
}
struct sk_buff *
@@ -1706,6 +1743,17 @@ aoe_failbuf(struct aoedev *d, struct buf *buf)
void
aoe_flush_iocq(void)
{
+ int i;
+
+ for (i = 0; i < ncpus; i++) {
+ if (kts[i].active)
+ aoe_flush_iocq_by_index(i);
+ }
+}
+
+void
+aoe_flush_iocq_by_index(int id)
+{
struct frame *f;
struct aoedev *d;
LIST_HEAD(flist);
@@ -1713,9 +1761,9 @@ aoe_flush_iocq(void)
struct sk_buff *skb;
ulong flags;
- spin_lock_irqsave(&iocq.lock, flags);
- list_splice_init(&iocq.head, &flist);
- spin_unlock_irqrestore(&iocq.lock, flags);
+ spin_lock_irqsave(&iocq[id].lock, flags);
+ list_splice_init(&iocq[id].head, &flist);
+ spin_unlock_irqrestore(&iocq[id].lock, flags);
while (!list_empty(&flist)) {
pos = flist.next;
list_del(pos);
@@ -1738,6 +1786,8 @@ int __init
aoecmd_init(void)
{
void *p;
+ int i;
+ int ret;
/* get_zeroed_page returns page with ref count 1 */
p = (void *) get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
@@ -1745,22 +1795,72 @@ aoecmd_init(void)
return -ENOMEM;
empty_page = virt_to_page(p);
- INIT_LIST_HEAD(&iocq.head);
- spin_lock_init(&iocq.lock);
- init_waitqueue_head(&ktiowq);
- kts.name = "aoe_ktio";
- kts.fn = ktio;
- kts.waitq = &ktiowq;
- kts.lock = &iocq.lock;
- return aoe_ktstart(&kts);
+ ncpus = num_online_cpus();
+
+ iocq = kcalloc(ncpus, sizeof(struct iocq_ktio), GFP_KERNEL);
+ if (!iocq)
+ return -ENOMEM;
+
+ kts = kcalloc(ncpus, sizeof(struct ktstate), GFP_KERNEL);
+ if (!kts) {
+ ret = -ENOMEM;
+ goto kts_fail;
+ }
+
+ ktiowq = kcalloc(ncpus, sizeof(wait_queue_head_t), GFP_KERNEL);
+ if (!ktiowq) {
+ ret = -ENOMEM;
+ goto ktiowq_fail;
+ }
+
+ mutex_init(&ktio_spawn_lock);
+
+ for (i = 0; i < ncpus; i++) {
+ INIT_LIST_HEAD(&iocq[i].head);
+ spin_lock_init(&iocq[i].lock);
+ init_waitqueue_head(&ktiowq[i]);
+ snprintf(kts[i].name, sizeof(kts[i].name), "aoe_ktio%d", i);
+ kts[i].fn = ktio;
+ kts[i].waitq = &ktiowq[i];
+ kts[i].lock = &iocq[i].lock;
+ kts[i].id = i;
+ kts[i].active = 0;
+ }
+ kts[0].active = 1;
+ if (aoe_ktstart(&kts[0])) {
+ ret = -ENOMEM;
+ goto ktstart_fail;
+ }
+ return 0;
+
+ktstart_fail:
+ kfree(ktiowq);
+ktiowq_fail:
+ kfree(kts);
+kts_fail:
+ kfree(iocq);
+
+ return ret;
}
void
aoecmd_exit(void)
{
- aoe_ktstop(&kts);
+ int i;
+
+ for (i = 0; i < ncpus; i++)
+ if (kts[i].active)
+ aoe_ktstop(&kts[i]);
+
aoe_flush_iocq();
+ /* Free up the iocq and thread speicific configuration
+ * allocated during startup.
+ */
+ kfree(iocq);
+ kfree(kts);
+ kfree(ktiowq);
+
free_page((unsigned long) page_address(empty_page));
empty_page = NULL;
}
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 98f2965778b9..784c92e038d1 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoedev.c
* AoE device utility functions; maintains device list.
@@ -518,7 +518,6 @@ void
aoedev_exit(void)
{
flush_scheduled_work();
- aoe_flush_iocq();
flush(NULL, 0, EXITING);
}
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 71d3ea8d3006..63773a90581d 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoenet.c
* Ethernet portion of AoE driver
@@ -52,7 +52,7 @@ static struct sk_buff_head skbtxq;
/* enters with txlock held */
static int
-tx(void) __must_hold(&txlock)
+tx(int id) __must_hold(&txlock)
{
struct sk_buff *skb;
struct net_device *ifp;
@@ -205,7 +205,8 @@ aoenet_init(void)
kts.lock = &txlock;
kts.fn = tx;
kts.waitq = &txwq;
- kts.name = "aoe_tx";
+ kts.id = 0;
+ snprintf(kts.name, sizeof(kts.name), "aoe_tx%d", kts.id);
if (aoe_ktstart(&kts))
return -EAGAIN;
dev_add_pack(&aoe_pt);
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index 20dd52a2f92f..952dbfe22126 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -4087,7 +4087,8 @@ skip_create_disk:
start_service_thread:
sprintf(thd_name, "mtip_svc_thd_%02d", index);
dd->mtip_svc_handler = kthread_create_on_node(mtip_service_thread,
- dd, dd->numa_node, thd_name);
+ dd, dd->numa_node, "%s",
+ thd_name);
if (IS_ERR(dd->mtip_svc_handler)) {
dev_err(&dd->pdev->dev, "service thread failed to start\n");
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 037288e7874d..2dc3b5153f0d 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -623,8 +623,10 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
if (!nbd->sock)
return -EINVAL;
+ nbd->disconnect = 1;
+
nbd_send_req(nbd, &sreq);
- return 0;
+ return 0;
}
case NBD_CLEAR_SOCK: {
@@ -654,6 +656,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
nbd->sock = SOCKET_I(inode);
if (max_part > 0)
bdev->bd_invalidated = 1;
+ nbd->disconnect = 0; /* we're connected now */
return 0;
} else {
fput(file);
@@ -714,7 +717,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
else
blk_queue_flush(nbd->disk->queue, 0);
- thread = kthread_create(nbd_thread, nbd, nbd->disk->disk_name);
+ thread = kthread_create(nbd_thread, nbd, "%s",
+ nbd->disk->disk_name);
if (IS_ERR(thread)) {
mutex_lock(&nbd->tx_lock);
return PTR_ERR(thread);
@@ -742,6 +746,8 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
set_capacity(nbd->disk, 0);
if (max_part > 0)
ioctl_by_bdev(bdev, BLKRRPART, 0);
+ if (nbd->disconnect) /* user requested, ignore socket errors */
+ return 0;
return nbd->harderror;
}
@@ -750,7 +756,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
* This is for compatibility only. The queue is always cleared
* by NBD_DO_IT or NBD_CLEAR_SOCK.
*/
- BUG_ON(!nbd->sock && !list_empty(&nbd->queue_head));
return 0;
case NBD_PRINT_DEBUG:
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index aff789d6fccd..4ad2ad9a5bb0 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -372,7 +372,7 @@ enum rbd_dev_flags {
RBD_DEV_FLAG_REMOVING, /* this mapping is being removed */
};
-static DEFINE_MUTEX(ctl_mutex); /* Serialize open/close/setup/teardown */
+static DEFINE_MUTEX(client_mutex); /* Serialize client creation */
static LIST_HEAD(rbd_dev_list); /* devices */
static DEFINE_SPINLOCK(rbd_dev_list_lock);
@@ -489,10 +489,8 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
if (removing)
return -ENOENT;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
(void) get_device(&rbd_dev->dev);
set_device_ro(bdev, rbd_dev->mapping.read_only);
- mutex_unlock(&ctl_mutex);
return 0;
}
@@ -507,9 +505,7 @@ static void rbd_release(struct gendisk *disk, fmode_t mode)
spin_unlock_irq(&rbd_dev->lock);
rbd_assert(open_count_before > 0);
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
put_device(&rbd_dev->dev);
- mutex_unlock(&ctl_mutex);
}
static const struct block_device_operations rbd_bd_ops = {
@@ -520,7 +516,7 @@ static const struct block_device_operations rbd_bd_ops = {
/*
* Initialize an rbd client instance. Success or not, this function
- * consumes ceph_opts.
+ * consumes ceph_opts. Caller holds client_mutex.
*/
static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
{
@@ -535,30 +531,25 @@ static struct rbd_client *rbd_client_create(struct ceph_options *ceph_opts)
kref_init(&rbdc->kref);
INIT_LIST_HEAD(&rbdc->node);
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
rbdc->client = ceph_create_client(ceph_opts, rbdc, 0, 0);
if (IS_ERR(rbdc->client))
- goto out_mutex;
+ goto out_rbdc;
ceph_opts = NULL; /* Now rbdc->client is responsible for ceph_opts */
ret = ceph_open_session(rbdc->client);
if (ret < 0)
- goto out_err;
+ goto out_client;
spin_lock(&rbd_client_list_lock);
list_add_tail(&rbdc->node, &rbd_client_list);
spin_unlock(&rbd_client_list_lock);
- mutex_unlock(&ctl_mutex);
dout("%s: rbdc %p\n", __func__, rbdc);
return rbdc;
-
-out_err:
+out_client:
ceph_destroy_client(rbdc->client);
-out_mutex:
- mutex_unlock(&ctl_mutex);
+out_rbdc:
kfree(rbdc);
out_opt:
if (ceph_opts)
@@ -682,11 +673,13 @@ static struct rbd_client *rbd_get_client(struct ceph_options *ceph_opts)
{
struct rbd_client *rbdc;
+ mutex_lock_nested(&client_mutex, SINGLE_DEPTH_NESTING);
rbdc = rbd_client_find(ceph_opts);
if (rbdc) /* using an existing client */
ceph_destroy_options(ceph_opts);
else
rbdc = rbd_client_create(ceph_opts);
+ mutex_unlock(&client_mutex);
return rbdc;
}
@@ -840,7 +833,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
/* We won't fail any more, fill in the header */
- down_write(&rbd_dev->header_rwsem);
if (first_time) {
header->object_prefix = object_prefix;
header->obj_order = ondisk->options.order;
@@ -869,8 +861,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev,
if (rbd_dev->mapping.size != header->image_size)
rbd_dev->mapping.size = header->image_size;
- up_write(&rbd_dev->header_rwsem);
-
return 0;
out_2big:
ret = -EIO;
@@ -1126,6 +1116,7 @@ static void zero_bio_chain(struct bio *chain, int start_ofs)
buf = bvec_kmap_irq(bv, &flags);
memset(buf + remainder, 0,
bv->bv_len - remainder);
+ flush_dcache_page(bv->bv_page);
bvec_kunmap_irq(buf, &flags);
}
pos += bv->bv_len;
@@ -1153,11 +1144,12 @@ static void zero_pages(struct page **pages, u64 offset, u64 end)
unsigned long flags;
void *kaddr;
- page_offset = (size_t)(offset & ~PAGE_MASK);
- length = min(PAGE_SIZE - page_offset, (size_t)(end - offset));
+ page_offset = offset & ~PAGE_MASK;
+ length = min_t(size_t, PAGE_SIZE - page_offset, end - offset);
local_irq_save(flags);
kaddr = kmap_atomic(*page);
memset(kaddr + page_offset, 0, length);
+ flush_dcache_page(*page);
kunmap_atomic(kaddr);
local_irq_restore(flags);
@@ -2171,9 +2163,9 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
struct rbd_obj_request *obj_request = NULL;
struct rbd_obj_request *next_obj_request;
bool write_request = img_request_write_test(img_request);
- struct bio *bio_list;
+ struct bio *bio_list = 0;
unsigned int bio_offset = 0;
- struct page **pages;
+ struct page **pages = 0;
u64 img_offset;
u64 resid;
u16 opcode;
@@ -2535,6 +2527,7 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
*/
orig_request = obj_request->obj_request;
obj_request->obj_request = NULL;
+ rbd_obj_request_put(orig_request);
rbd_assert(orig_request);
rbd_assert(orig_request->img_request);
@@ -2555,7 +2548,6 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
if (!rbd_dev->parent_overlap) {
struct ceph_osd_client *osdc;
- rbd_obj_request_put(orig_request);
osdc = &rbd_dev->rbd_client->client->osdc;
result = rbd_obj_request_submit(osdc, orig_request);
if (!result)
@@ -2585,7 +2577,6 @@ static void rbd_img_obj_exists_callback(struct rbd_obj_request *obj_request)
out:
if (orig_request->result)
rbd_obj_request_complete(orig_request);
- rbd_obj_request_put(orig_request);
}
static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
@@ -2859,7 +2850,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
(unsigned int)opcode);
ret = rbd_dev_refresh(rbd_dev);
if (ret)
- rbd_warn(rbd_dev, ": header refresh error (%d)\n", ret);
+ rbd_warn(rbd_dev, "header refresh error (%d)\n", ret);
rbd_obj_notify_ack(rbd_dev, notify_id);
}
@@ -3339,8 +3330,8 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
int ret;
rbd_assert(rbd_image_format_valid(rbd_dev->image_format));
+ down_write(&rbd_dev->header_rwsem);
mapping_size = rbd_dev->mapping.size;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
if (rbd_dev->image_format == 1)
ret = rbd_dev_v1_header_info(rbd_dev);
else
@@ -3349,7 +3340,8 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
/* If it's a mapped snapshot, validate its EXISTS flag */
rbd_exists_validate(rbd_dev);
- mutex_unlock(&ctl_mutex);
+ up_write(&rbd_dev->header_rwsem);
+
if (mapping_size != rbd_dev->mapping.size) {
sector_t size;
@@ -3813,6 +3805,7 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
void *end;
u64 pool_id;
char *image_id;
+ u64 snap_id;
u64 overlap;
int ret;
@@ -3872,24 +3865,56 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
(unsigned long long)pool_id, U32_MAX);
goto out_err;
}
- parent_spec->pool_id = pool_id;
image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL);
if (IS_ERR(image_id)) {
ret = PTR_ERR(image_id);
goto out_err;
}
- parent_spec->image_id = image_id;
- ceph_decode_64_safe(&p, end, parent_spec->snap_id, out_err);
+ ceph_decode_64_safe(&p, end, snap_id, out_err);
ceph_decode_64_safe(&p, end, overlap, out_err);
- if (overlap) {
- rbd_spec_put(rbd_dev->parent_spec);
+ /*
+ * The parent won't change (except when the clone is
+ * flattened, already handled that). So we only need to
+ * record the parent spec we have not already done so.
+ */
+ if (!rbd_dev->parent_spec) {
+ parent_spec->pool_id = pool_id;
+ parent_spec->image_id = image_id;
+ parent_spec->snap_id = snap_id;
rbd_dev->parent_spec = parent_spec;
parent_spec = NULL; /* rbd_dev now owns this */
- rbd_dev->parent_overlap = overlap;
- } else {
- rbd_warn(rbd_dev, "ignoring parent of clone with overlap 0\n");
+ }
+
+ /*
+ * We always update the parent overlap. If it's zero we
+ * treat it specially.
+ */
+ rbd_dev->parent_overlap = overlap;
+ smp_mb();
+ if (!overlap) {
+
+ /* A null parent_spec indicates it's the initial probe */
+
+ if (parent_spec) {
+ /*
+ * The overlap has become zero, so the clone
+ * must have been resized down to 0 at some
+ * point. Treat this the same as a flatten.
+ */
+ rbd_dev_parent_put(rbd_dev);
+ pr_info("%s: clone image now standalone\n",
+ rbd_dev->disk->disk_name);
+ } else {
+ /*
+ * For the initial probe, if we find the
+ * overlap is zero we just pretend there was
+ * no parent image.
+ */
+ rbd_warn(rbd_dev, "ignoring parent of "
+ "clone with overlap 0\n");
+ }
}
out:
ret = 0;
@@ -4245,16 +4270,14 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
bool first_time = rbd_dev->header.object_prefix == NULL;
int ret;
- down_write(&rbd_dev->header_rwsem);
-
ret = rbd_dev_v2_image_size(rbd_dev);
if (ret)
- goto out;
+ return ret;
if (first_time) {
ret = rbd_dev_v2_header_onetime(rbd_dev);
if (ret)
- goto out;
+ return ret;
}
/*
@@ -4269,7 +4292,7 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
ret = rbd_dev_v2_parent_info(rbd_dev);
if (ret)
- goto out;
+ return ret;
/*
* Print a warning if this is the initial probe and
@@ -4290,8 +4313,6 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev)
ret = rbd_dev_v2_snap_context(rbd_dev);
dout("rbd_dev_v2_snap_context returned %d\n", ret);
-out:
- up_write(&rbd_dev->header_rwsem);
return ret;
}
@@ -4301,8 +4322,6 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
struct device *dev;
int ret;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
dev = &rbd_dev->dev;
dev->bus = &rbd_bus_type;
dev->type = &rbd_device_type;
@@ -4311,8 +4330,6 @@ static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
dev_set_name(dev, "%d", rbd_dev->dev_id);
ret = device_register(dev);
- mutex_unlock(&ctl_mutex);
-
return ret;
}
@@ -5059,23 +5076,6 @@ err_out_module:
return (ssize_t)rc;
}
-static struct rbd_device *__rbd_get_dev(unsigned long dev_id)
-{
- struct list_head *tmp;
- struct rbd_device *rbd_dev;
-
- spin_lock(&rbd_dev_list_lock);
- list_for_each(tmp, &rbd_dev_list) {
- rbd_dev = list_entry(tmp, struct rbd_device, node);
- if (rbd_dev->dev_id == dev_id) {
- spin_unlock(&rbd_dev_list_lock);
- return rbd_dev;
- }
- }
- spin_unlock(&rbd_dev_list_lock);
- return NULL;
-}
-
static void rbd_dev_device_release(struct device *dev)
{
struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
@@ -5120,8 +5120,10 @@ static ssize_t rbd_remove(struct bus_type *bus,
size_t count)
{
struct rbd_device *rbd_dev = NULL;
- int target_id;
+ struct list_head *tmp;
+ int dev_id;
unsigned long ul;
+ bool already = false;
int ret;
ret = strict_strtoul(buf, 10, &ul);
@@ -5129,37 +5131,40 @@ static ssize_t rbd_remove(struct bus_type *bus,
return ret;
/* convert to int; abort if we lost anything in the conversion */
- target_id = (int) ul;
- if (target_id != ul)
+ dev_id = (int)ul;
+ if (dev_id != ul)
return -EINVAL;
- mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
-
- rbd_dev = __rbd_get_dev(target_id);
- if (!rbd_dev) {
- ret = -ENOENT;
- goto done;
+ ret = -ENOENT;
+ spin_lock(&rbd_dev_list_lock);
+ list_for_each(tmp, &rbd_dev_list) {
+ rbd_dev = list_entry(tmp, struct rbd_device, node);
+ if (rbd_dev->dev_id == dev_id) {
+ ret = 0;
+ break;
+ }
+ }
+ if (!ret) {
+ spin_lock_irq(&rbd_dev->lock);
+ if (rbd_dev->open_count)
+ ret = -EBUSY;
+ else
+ already = test_and_set_bit(RBD_DEV_FLAG_REMOVING,
+ &rbd_dev->flags);
+ spin_unlock_irq(&rbd_dev->lock);
}
+ spin_unlock(&rbd_dev_list_lock);
+ if (ret < 0 || already)
+ return ret;
- spin_lock_irq(&rbd_dev->lock);
- if (rbd_dev->open_count)
- ret = -EBUSY;
- else
- set_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags);
- spin_unlock_irq(&rbd_dev->lock);
- if (ret < 0)
- goto done;
rbd_bus_del_dev(rbd_dev);
ret = rbd_dev_header_watch_sync(rbd_dev, false);
if (ret)
rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret);
rbd_dev_image_release(rbd_dev);
module_put(THIS_MODULE);
- ret = count;
-done:
- mutex_unlock(&ctl_mutex);
- return ret;
+ return count;
}
/*
@@ -5267,6 +5272,7 @@ static void __exit rbd_exit(void)
module_init(rbd_init);
module_exit(rbd_exit);
+MODULE_AUTHOR("Alex Elder <elder@inktank.com>");
MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
MODULE_DESCRIPTION("rados block device");
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 2f445b7a174e..8ed6ccb748cf 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -893,7 +893,7 @@ static int swim_probe(struct platform_device *dev)
swim_base = ioremap(res->start, resource_size(res));
if (!swim_base) {
- return -ENOMEM;
+ ret = -ENOMEM;
goto out_release_io;
}
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 64723953e1c9..5cdf88b7ad9e 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -20,7 +20,7 @@ module_param(use_bio, bool, S_IRUGO);
static int major;
static DEFINE_IDA(vd_index_ida);
-struct workqueue_struct *virtblk_wq;
+static struct workqueue_struct *virtblk_wq;
struct virtio_blk
{
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 8bfd1bcf95ec..04608a6502d7 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -93,7 +93,7 @@ static void xen_update_blkif_status(struct xen_blkif *blkif)
}
invalidate_inode_pages2(blkif->vbd.bdev->bd_inode->i_mapping);
- blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, name);
+ blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, "%s", name);
if (IS_ERR(blkif->xenblkd)) {
err = PTR_ERR(blkif->xenblkd);
blkif->xenblkd = NULL;
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 3fd130fdfbc1..1393b8871a28 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -407,7 +407,7 @@ static void ace_dump_regs(struct ace_device *ace)
ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT));
}
-void ace_fix_driveid(u16 *id)
+static void ace_fix_driveid(u16 *id)
{
#if defined(__BIG_ENDIAN)
int i;
@@ -463,7 +463,7 @@ static inline void ace_fsm_yieldirq(struct ace_device *ace)
}
/* Get the next read/write request; ending requests that we don't handle */
-struct request *ace_get_next_request(struct request_queue * q)
+static struct request *ace_get_next_request(struct request_queue *q)
{
struct request *req;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 13693b7a0d5c..75c262694632 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -554,6 +554,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
+ ret = -ENOMEM;
goto exit;
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 7a7e5f8ecadc..de4cf4daa2f4 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -57,6 +57,9 @@ static struct usb_device_id btusb_table[] = {
/* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
+ /* MediaTek MT76x0E */
+ { USB_DEVICE(0x0e8d, 0x763f) },
+
/* Broadcom SoftSailing reporting vendor specific */
{ USB_DEVICE(0x0a5c, 0x21e1) },
@@ -1616,6 +1619,7 @@ static struct usb_driver btusb_driver = {
#ifdef CONFIG_PM
.suspend = btusb_suspend,
.resume = btusb_resume,
+ .reset_resume = btusb_resume,
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d620b4495745..8a3aff724d98 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2882,7 +2882,7 @@ static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
if (lba < 0)
return -EINVAL;
- cgc->buffer = kmalloc(blocksize, GFP_KERNEL);
+ cgc->buffer = kzalloc(blocksize, GFP_KERNEL);
if (cgc->buffer == NULL)
return -ENOMEM;
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index 4afcb65cc623..5980cb9af857 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -830,9 +830,9 @@ probe_fail_cdrom_register:
del_gendisk(gd.disk);
probe_fail_no_disk:
kfree(gd.cd_info);
+probe_fail_no_mem:
unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
gdrom_major = 0;
-probe_fail_no_mem:
pr_warning("Probe failed - error is 0x%X\n", err);
return err;
}
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index dd84af4d4f7e..199b8e99f7d7 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -174,7 +174,7 @@ alpha_core_agp_setup(void)
/*
* Build a fake pci_dev struct
*/
- pdev = alloc_pci_dev();
+ pdev = pci_alloc_dev(NULL);
if (!pdev)
return -ENOMEM;
pdev->vendor = 0xffff;
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 0628d7b65c71..03c1dc1ab552 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -236,14 +236,14 @@ static int ati_configure(void)
static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
{
pci_save_state(dev);
- pci_set_power_state(dev, 3);
+ pci_set_power_state(dev, PCI_D3hot);
return 0;
}
static int agp_ati_resume(struct pci_dev *dev)
{
- pci_set_power_state(dev, 0);
+ pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
return ati_configure();
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index 2e044338753c..1b192395a90c 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -603,7 +603,8 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = kerninfo.vm_ops;
} else if (io_remap_pfn_range(vma, vma->vm_start,
(kerninfo.aper_base + offset) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
+ size,
+ pgprot_writecombine(vma->vm_page_prot))) {
goto out_again;
}
mutex_unlock(&(agp_fe.agp_mutex));
@@ -618,8 +619,9 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma)
if (kerninfo.vm_ops) {
vma->vm_ops = kerninfo.vm_ops;
} else if (io_remap_pfn_range(vma, vma->vm_start,
- kerninfo.aper_base >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
+ kerninfo.aper_base >> PAGE_SHIFT,
+ size,
+ pgprot_writecombine(vma->vm_page_prot))) {
goto out_again;
}
mutex_unlock(&(agp_fe.agp_mutex));
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 62be3ec0da4b..be42a2312dc9 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -399,8 +399,8 @@ static void agp_nvidia_remove(struct pci_dev *pdev)
#ifdef CONFIG_PM
static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state)
{
- pci_save_state (pdev);
- pci_set_power_state (pdev, 3);
+ pci_save_state(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
@@ -408,7 +408,7 @@ static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state)
static int agp_nvidia_resume(struct pci_dev *pdev)
{
/* set power state 0 and restore PCI space */
- pci_set_power_state (pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
/* reconfigure AGP hardware again */
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 94821ab01c6d..bf5d2477cb77 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -333,7 +333,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
struct agp_bridge_data *bridge;
int error = 0;
- fake_bridge_dev = alloc_pci_dev();
+ fake_bridge_dev = pci_alloc_dev(NULL);
if (!fake_bridge_dev) {
error = -ENOMEM;
goto fail;
diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
index 7c73d4aca36b..bf9fc6b79328 100644
--- a/drivers/char/hw_random/atmel-rng.c
+++ b/drivers/char/hw_random/atmel-rng.c
@@ -108,8 +108,6 @@ static int atmel_trng_remove(struct platform_device *pdev)
clk_disable(trng->clk);
clk_put(trng->clk);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c
index f343b7d0dfa1..36581ea562cb 100644
--- a/drivers/char/hw_random/bcm63xx-rng.c
+++ b/drivers/char/hw_random/bcm63xx-rng.c
@@ -137,7 +137,6 @@ static int bcm63xx_rng_probe(struct platform_device *pdev)
out_clk_disable:
clk_disable(clk);
out_free_rng:
- platform_set_drvdata(pdev, NULL);
kfree(rng);
out_free_priv:
kfree(priv);
@@ -154,7 +153,6 @@ static int bcm63xx_rng_remove(struct platform_device *pdev)
clk_disable(priv->clk);
kfree(priv);
kfree(rng);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
index 20b962e1d832..f9beed54d0c8 100644
--- a/drivers/char/hw_random/n2-drv.c
+++ b/drivers/char/hw_random/n2-drv.c
@@ -700,7 +700,7 @@ static int n2rng_probe(struct platform_device *op)
if (err)
goto out_free_units;
- dev_set_drvdata(&op->dev, np);
+ platform_set_drvdata(op, np);
schedule_delayed_work(&np->work, 0);
@@ -721,7 +721,7 @@ out:
static int n2rng_remove(struct platform_device *op)
{
- struct n2rng *np = dev_get_drvdata(&op->dev);
+ struct n2rng *np = platform_get_drvdata(op);
np->flags |= N2RNG_FLAG_SHUTDOWN;
@@ -736,8 +736,6 @@ static int n2rng_remove(struct platform_device *op)
kfree(np);
- dev_set_drvdata(&op->dev, NULL);
-
return 0;
}
diff --git a/drivers/char/hw_random/nomadik-rng.c b/drivers/char/hw_random/nomadik-rng.c
index 96de0249e595..232b87fb5fc9 100644
--- a/drivers/char/hw_random/nomadik-rng.c
+++ b/drivers/char/hw_random/nomadik-rng.c
@@ -51,7 +51,7 @@ static int nmk_rng_probe(struct amba_device *dev, const struct amba_id *id)
return ret;
}
- clk_enable(rng_clk);
+ clk_prepare_enable(rng_clk);
ret = amba_request_regions(dev, dev->dev.init_name);
if (ret)
diff --git a/drivers/char/hw_random/octeon-rng.c b/drivers/char/hw_random/octeon-rng.c
index 1eada566ca70..f2885dbe1849 100644
--- a/drivers/char/hw_random/octeon-rng.c
+++ b/drivers/char/hw_random/octeon-rng.c
@@ -96,7 +96,7 @@ static int octeon_rng_probe(struct platform_device *pdev)
rng->ops = ops;
- dev_set_drvdata(&pdev->dev, &rng->ops);
+ platform_set_drvdata(pdev, &rng->ops);
ret = hwrng_register(&rng->ops);
if (ret)
return -ENOENT;
@@ -108,7 +108,7 @@ static int octeon_rng_probe(struct platform_device *pdev)
static int __exit octeon_rng_remove(struct platform_device *pdev)
{
- struct hwrng *rng = dev_get_drvdata(&pdev->dev);
+ struct hwrng *rng = platform_get_drvdata(pdev);
hwrng_unregister(rng);
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index d2903e772270..6843ec87b98b 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -116,7 +116,7 @@ static int omap_rng_probe(struct platform_device *pdev)
};
omap_rng_ops.priv = (unsigned long)priv;
- dev_set_drvdata(&pdev->dev, priv);
+ platform_set_drvdata(pdev, priv);
priv->mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, priv->mem_res);
@@ -124,7 +124,7 @@ static int omap_rng_probe(struct platform_device *pdev)
ret = PTR_ERR(priv->base);
goto err_ioremap;
}
- dev_set_drvdata(&pdev->dev, priv);
+ platform_set_drvdata(pdev, priv);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@@ -151,7 +151,7 @@ err_ioremap:
static int __exit omap_rng_remove(struct platform_device *pdev)
{
- struct omap_rng_private_data *priv = dev_get_drvdata(&pdev->dev);
+ struct omap_rng_private_data *priv = platform_get_drvdata(pdev);
hwrng_unregister(&omap_rng_ops);
diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
index 3e75737f5fe1..d2120ba8f3f9 100644
--- a/drivers/char/hw_random/timeriomem-rng.c
+++ b/drivers/char/hw_random/timeriomem-rng.c
@@ -192,7 +192,6 @@ out_release_io:
out_timer:
del_timer_sync(&priv->timer);
out_free:
- platform_set_drvdata(pdev, NULL);
kfree(priv);
return err;
}
@@ -209,7 +208,6 @@ static int timeriomem_rng_remove(struct platform_device *pdev)
del_timer_sync(&priv->timer);
iounmap(priv->io_base);
release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;
diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c
index d34a24a0d484..00593c847cf0 100644
--- a/drivers/char/hw_random/tx4939-rng.c
+++ b/drivers/char/hw_random/tx4939-rng.c
@@ -154,7 +154,6 @@ static int __exit tx4939_rng_remove(struct platform_device *dev)
struct tx4939_rng *rngdev = platform_get_drvdata(dev);
hwrng_unregister(&rngdev->rng);
- platform_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 2ca6d7844ad9..f895a8c8a244 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -21,7 +21,6 @@
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
-#include <linux/crash_dump.h>
#include <linux/backing-dev.h>
#include <linux/bootmem.h>
#include <linux/splice.h>
@@ -357,40 +356,6 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
}
#endif
-#ifdef CONFIG_CRASH_DUMP
-/*
- * Read memory corresponding to the old kernel.
- */
-static ssize_t read_oldmem(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- unsigned long pfn, offset;
- size_t read = 0, csize;
- int rc = 0;
-
- while (count) {
- pfn = *ppos / PAGE_SIZE;
- if (pfn > saved_max_pfn)
- return read;
-
- offset = (unsigned long)(*ppos % PAGE_SIZE);
- if (count > PAGE_SIZE - offset)
- csize = PAGE_SIZE - offset;
- else
- csize = count;
-
- rc = copy_oldmem_page(pfn, buf, csize, offset, 1);
- if (rc < 0)
- return rc;
- buf += csize;
- *ppos += csize;
- read += csize;
- count -= csize;
- }
- return read;
-}
-#endif
-
#ifdef CONFIG_DEVKMEM
/*
* This function reads the *virtual* memory as seen by the kernel.
@@ -772,7 +737,6 @@ static int open_port(struct inode *inode, struct file *filp)
#define aio_write_zero aio_write_null
#define open_mem open_port
#define open_kmem open_mem
-#define open_oldmem open_mem
static const struct file_operations mem_fops = {
.llseek = memory_lseek,
@@ -837,14 +801,6 @@ static const struct file_operations full_fops = {
.write = write_full,
};
-#ifdef CONFIG_CRASH_DUMP
-static const struct file_operations oldmem_fops = {
- .read = read_oldmem,
- .open = open_oldmem,
- .llseek = default_llseek,
-};
-#endif
-
static const struct memdev {
const char *name;
umode_t mode;
@@ -866,9 +822,6 @@ static const struct memdev {
#ifdef CONFIG_PRINTK
[11] = { "kmsg", 0644, &kmsg_fops, NULL },
#endif
-#ifdef CONFIG_CRASH_DUMP
- [12] = { "oldmem", 0, &oldmem_fops, NULL },
-#endif
};
static int memory_open(struct inode *inode, struct file *filp)
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index c68969708068..04e6d6a27994 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -479,6 +479,7 @@ int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData);
+ memset(pAbilities, 0, sizeof(*pAbilities));
/* fill out standard constant fields */
pAbilities->instr_per_sec = pBDData->rDspSettings.uIps;
pAbilities->data_size = pBDData->rDspSettings.uDStoreSize;
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
index 8cafa9ccd43f..0b311fa277ef 100644
--- a/drivers/char/ps3flash.c
+++ b/drivers/char/ps3flash.c
@@ -98,32 +98,8 @@ static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
{
struct ps3_storage_device *dev = ps3flash_dev;
- loff_t res;
-
- mutex_lock(&file->f_mapping->host->i_mutex);
- switch (origin) {
- case 0:
- break;
- case 1:
- offset += file->f_pos;
- break;
- case 2:
- offset += dev->regions[dev->region_idx].size*dev->blk_size;
- break;
- default:
- offset = -1;
- }
- if (offset < 0) {
- res = -EINVAL;
- goto out;
- }
-
- file->f_pos = offset;
- res = file->f_pos;
-
-out:
- mutex_unlock(&file->f_mapping->host->i_mutex);
- return res;
+ return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
+ dev->regions[dev->region_idx].size*dev->blk_size);
}
static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
diff --git a/drivers/char/tile-srom.c b/drivers/char/tile-srom.c
index 2e2036e940fc..7faeb1cde97d 100644
--- a/drivers/char/tile-srom.c
+++ b/drivers/char/tile-srom.c
@@ -273,32 +273,10 @@ static ssize_t srom_write(struct file *filp, const char __user *buf,
}
/* Provide our own implementation so we can use srom->total_size. */
-loff_t srom_llseek(struct file *filp, loff_t offset, int origin)
+loff_t srom_llseek(struct file *file, loff_t offset, int origin)
{
- struct srom_dev *srom = filp->private_data;
-
- if (mutex_lock_interruptible(&srom->lock))
- return -ERESTARTSYS;
-
- switch (origin) {
- case SEEK_END:
- offset += srom->total_size;
- break;
- case SEEK_CUR:
- offset += filp->f_pos;
- break;
- }
-
- if (offset < 0 || offset > srom->total_size) {
- offset = -EINVAL;
- } else {
- filp->f_pos = offset;
- filp->f_version = 0;
- }
-
- mutex_unlock(&srom->lock);
-
- return offset;
+ struct srom_dev *srom = file->private_data;
+ return fixed_size_llseek(file, offset, origin, srom->total_size);
}
static ssize_t total_show(struct device *dev,
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 7c3b3dcbfbc8..e3c974a6c522 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1472,7 +1472,7 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
* Once all references to platform device are down to 0,
* release all allocated structures.
*/
-static void tpm_dev_release(struct device *dev)
+void tpm_dev_release(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 0770d1d79366..a7bfc176ed43 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -272,7 +272,6 @@ typedef union {
struct tpm_output_header out;
} tpm_cmd_header;
-#define TPM_DIGEST_SIZE 20
struct tpm_pcrread_out {
u8 pcr_result[TPM_DIGEST_SIZE];
} __packed;
@@ -333,6 +332,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
extern int tpm_release(struct inode *, struct file *);
+extern void tpm_dev_release(struct device *dev);
extern void tpm_dev_vendor_release(struct tpm_chip *);
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
loff_t *);
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 37d5dcc10ea7..b8735de8ce95 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/wait.h>
#include "tpm.h"
@@ -74,7 +73,6 @@ struct tpm_inf_dev {
};
static struct tpm_inf_dev tpm_dev;
-static struct i2c_driver tpm_tis_i2c_driver;
/*
* iic_tpm_read() - read from TPM register
@@ -744,11 +742,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
return -ENODEV;
}
- client->driver = &tpm_tis_i2c_driver;
tpm_dev.client = client;
rc = tpm_tis_i2c_init(&client->dev);
if (rc != 0) {
- client->driver = NULL;
tpm_dev.client = NULL;
rc = -ENODEV;
}
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 8a41b6be23a0..4519cb332987 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -884,12 +884,19 @@ static int __init init_tis(void)
rc = platform_driver_register(&tis_drv);
if (rc < 0)
return rc;
- if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
- return PTR_ERR(pdev);
- if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
- platform_device_unregister(pdev);
- platform_driver_unregister(&tis_drv);
+ pdev = platform_device_register_simple("tpm_tis", -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ rc = PTR_ERR(pdev);
+ goto err_dev;
}
+ rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
+ if (rc)
+ goto err_init;
+ return 0;
+err_init:
+ platform_device_unregister(pdev);
+err_dev:
+ platform_driver_unregister(&tis_drv);
return rc;
}
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 0357ac44638b..51380d655d1a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,7 +42,7 @@ config COMMON_CLK_WM831X
config COMMON_CLK_VERSATILE
bool "Clock driver for ARM Reference designs"
- depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64
---help---
Supports clocking on ARM Reference designs:
- Integrator/AP and Integrator/CP
@@ -58,7 +58,6 @@ config COMMON_CLK_MAX77686
config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
- depends on OF
select REGMAP_I2C
select RATIONAL
---help---
@@ -81,6 +80,13 @@ config COMMON_CLK_AXI_CLKGEN
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
FPGAs. It is commonly used in Analog Devices' reference designs.
+config CLK_PPC_CORENET
+ bool "Clock driver for PowerPC corenet platforms"
+ depends on PPC_E500MC && OF
+ ---help---
+ This adds the clock driver support for Freescale PowerPC corenet
+ platforms using common clock framework.
+
endmenu
source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index f9cf7085ef70..4038c2bdf334 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
+obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
@@ -24,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
+obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
@@ -39,3 +41,4 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
+obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 6d9674160430..6d55eb2cb959 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
struct clk_divider *divider = to_clk_divider(hw);
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
+ unsigned long parent_rate_saved = *best_parent_rate;
if (!rate)
rate = 1;
@@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
for (i = 1; i <= maxdiv; i++) {
if (!_is_valid_div(divider, i))
continue;
+ if (rate * i == parent_rate_saved) {
+ /*
+ * It's the most ideal case if the requested rate can be
+ * divided from parent clock without needing to change
+ * parent rate, so return the divider immediately.
+ */
+ *best_parent_rate = parent_rate_saved;
+ return i;
+ }
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = parent_rate / i;
@@ -217,8 +227,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
- val = readl(divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+ val = div_mask(divider) << (divider->shift + 16);
+ } else {
+ val = readl(divider->reg);
+ val &= ~(div_mask(divider) << divider->shift);
+ }
val |= value << divider->shift;
writel(val, divider->reg);
@@ -245,6 +259,13 @@ static struct clk *_register_divider(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
+ if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+ if (width + shift > 16) {
+ pr_warn("divider value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
/* allocate the divider */
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
if (!div) {
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 15114febfd92..790306e921c8 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -53,12 +53,18 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
- reg = readl(gate->reg);
-
- if (set)
- reg |= BIT(gate->bit_idx);
- else
- reg &= ~BIT(gate->bit_idx);
+ if (gate->flags & CLK_GATE_HIWORD_MASK) {
+ reg = BIT(gate->bit_idx + 16);
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ } else {
+ reg = readl(gate->reg);
+
+ if (set)
+ reg |= BIT(gate->bit_idx);
+ else
+ reg &= ~BIT(gate->bit_idx);
+ }
writel(reg, gate->reg);
@@ -121,6 +127,13 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
+ if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
+ if (bit_idx > 16) {
+ pr_err("gate bit exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
/* allocate the gate */
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
if (!gate) {
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 25b1734560d0..614444ca40cd 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -86,8 +86,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
- val = readl(mux->reg);
- val &= ~(mux->mask << mux->shift);
+ if (mux->flags & CLK_MUX_HIWORD_MASK) {
+ val = mux->mask << (mux->shift + 16);
+ } else {
+ val = readl(mux->reg);
+ val &= ~(mux->mask << mux->shift);
+ }
val |= index << mux->shift;
writel(val, mux->reg);
@@ -111,6 +115,15 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
struct clk_mux *mux;
struct clk *clk;
struct clk_init_data init;
+ u8 width = 0;
+
+ if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
+ width = fls(mask) - ffs(mask) + 1;
+ if (width + shift > 16) {
+ pr_err("mux value exceeds LOWORD field\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
/* allocate the mux */
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
diff --git a/drivers/clk/clk-nspire.c b/drivers/clk/clk-nspire.c
new file mode 100644
index 000000000000..a378db7b2382
--- /dev/null
+++ b/drivers/clk/clk-nspire.c
@@ -0,0 +1,153 @@
+/*
+ *
+ * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can 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/of.h>
+#include <linux/of_address.h>
+
+#define MHZ (1000 * 1000)
+
+#define BASE_CPU_SHIFT 1
+#define BASE_CPU_MASK 0x7F
+
+#define CPU_AHB_SHIFT 12
+#define CPU_AHB_MASK 0x07
+
+#define FIXED_BASE_SHIFT 8
+#define FIXED_BASE_MASK 0x01
+
+#define CLASSIC_BASE_SHIFT 16
+#define CLASSIC_BASE_MASK 0x1F
+
+#define CX_BASE_SHIFT 15
+#define CX_BASE_MASK 0x3F
+
+#define CX_UNKNOWN_SHIFT 21
+#define CX_UNKNOWN_MASK 0x03
+
+struct nspire_clk_info {
+ u32 base_clock;
+ u16 base_cpu_ratio;
+ u16 base_ahb_ratio;
+};
+
+
+#define EXTRACT(var, prop) (((var)>>prop##_SHIFT) & prop##_MASK)
+static void nspire_clkinfo_cx(u32 val, struct nspire_clk_info *clk)
+{
+ if (EXTRACT(val, FIXED_BASE))
+ clk->base_clock = 48 * MHZ;
+ else
+ clk->base_clock = 6 * EXTRACT(val, CX_BASE) * MHZ;
+
+ clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * EXTRACT(val, CX_UNKNOWN);
+ clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
+}
+
+static void nspire_clkinfo_classic(u32 val, struct nspire_clk_info *clk)
+{
+ if (EXTRACT(val, FIXED_BASE))
+ clk->base_clock = 27 * MHZ;
+ else
+ clk->base_clock = (300 - 6 * EXTRACT(val, CLASSIC_BASE)) * MHZ;
+
+ clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * 2;
+ clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
+}
+
+static void __init nspire_ahbdiv_setup(struct device_node *node,
+ void (*get_clkinfo)(u32, struct nspire_clk_info *))
+{
+ u32 val;
+ void __iomem *io;
+ struct clk *clk;
+ const char *clk_name = node->name;
+ const char *parent_name;
+ struct nspire_clk_info info;
+
+ io = of_iomap(node, 0);
+ if (!io)
+ return;
+ val = readl(io);
+ iounmap(io);
+
+ get_clkinfo(val, &info);
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent_name = of_clk_get_parent_name(node, 0);
+
+ clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
+ 1, info.base_ahb_ratio);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+
+static void __init nspire_ahbdiv_setup_cx(struct device_node *node)
+{
+ nspire_ahbdiv_setup(node, nspire_clkinfo_cx);
+}
+
+static void __init nspire_ahbdiv_setup_classic(struct device_node *node)
+{
+ nspire_ahbdiv_setup(node, nspire_clkinfo_classic);
+}
+
+CLK_OF_DECLARE(nspire_ahbdiv_cx, "lsi,nspire-cx-ahb-divider",
+ nspire_ahbdiv_setup_cx);
+CLK_OF_DECLARE(nspire_ahbdiv_classic, "lsi,nspire-classic-ahb-divider",
+ nspire_ahbdiv_setup_classic);
+
+static void __init nspire_clk_setup(struct device_node *node,
+ void (*get_clkinfo)(u32, struct nspire_clk_info *))
+{
+ u32 val;
+ void __iomem *io;
+ struct clk *clk;
+ const char *clk_name = node->name;
+ struct nspire_clk_info info;
+
+ io = of_iomap(node, 0);
+ if (!io)
+ return;
+ val = readl(io);
+ iounmap(io);
+
+ get_clkinfo(val, &info);
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT,
+ info.base_clock);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ else
+ return;
+
+ pr_info("TI-NSPIRE Base: %uMHz CPU: %uMHz AHB: %uMHz\n",
+ info.base_clock / MHZ,
+ info.base_clock / info.base_cpu_ratio / MHZ,
+ info.base_clock / info.base_ahb_ratio / MHZ);
+}
+
+static void __init nspire_clk_setup_cx(struct device_node *node)
+{
+ nspire_clk_setup(node, nspire_clkinfo_cx);
+}
+
+static void __init nspire_clk_setup_classic(struct device_node *node)
+{
+ nspire_clk_setup(node, nspire_clkinfo_classic);
+}
+
+CLK_OF_DECLARE(nspire_clk_cx, "lsi,nspire-cx-clock", nspire_clk_setup_cx);
+CLK_OF_DECLARE(nspire_clk_classic, "lsi,nspire-classic-clock",
+ nspire_clk_setup_classic);
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
new file mode 100644
index 000000000000..e9587073bd32
--- /dev/null
+++ b/drivers/clk/clk-ppc-corenet.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * clock driver for Freescale PowerPC corenet SoCs.
+ */
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct cmux_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 flags;
+};
+
+#define PLL_KILL BIT(31)
+#define CLKSEL_SHIFT 27
+#define CLKSEL_ADJUST BIT(0)
+#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
+
+static void __iomem *base;
+static unsigned int clocks_per_pll;
+
+static int cmux_set_parent(struct clk_hw *hw, u8 idx)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel += 8;
+ clksel = (clksel & 0xf) << CLKSEL_SHIFT;
+ iowrite32be(clksel, clk->reg);
+
+ return 0;
+}
+
+static u8 cmux_get_parent(struct clk_hw *hw)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ioread32be(clk->reg);
+ clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel -= 8;
+ clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
+
+ return clksel;
+}
+
+const struct clk_ops cmux_ops = {
+ .get_parent = cmux_get_parent,
+ .set_parent = cmux_set_parent,
+};
+
+static void __init core_mux_init(struct device_node *np)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+ struct cmux_clk *cmux_clk;
+ struct device_node *node;
+ int rc, count, i;
+ u32 offset;
+ const char *clk_name;
+ const char **parent_names;
+
+ rc = of_property_read_u32(np, "reg", &offset);
+ if (rc) {
+ pr_err("%s: could not get reg property\n", np->name);
+ return;
+ }
+
+ /* get the input clock source count */
+ count = of_property_count_strings(np, "clock-names");
+ if (count < 0) {
+ pr_err("%s: get clock count error\n", np->name);
+ return;
+ }
+ parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
+ if (!parent_names) {
+ pr_err("%s: could not allocate parent_names\n", __func__);
+ return;
+ }
+
+ for (i = 0; i < count; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
+ if (!cmux_clk) {
+ pr_err("%s: could not allocate cmux_clk\n", __func__);
+ goto err_name;
+ }
+ cmux_clk->reg = base + offset;
+
+ node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
+ if (node && (offset >= 0x80))
+ cmux_clk->flags = CLKSEL_ADJUST;
+
+ rc = of_property_read_string_index(np, "clock-output-names",
+ 0, &clk_name);
+ if (rc) {
+ pr_err("%s: read clock names error\n", np->name);
+ goto err_clk;
+ }
+
+ init.name = clk_name;
+ init.ops = &cmux_ops;
+ init.parent_names = parent_names;
+ init.num_parents = count;
+ init.flags = 0;
+ cmux_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &cmux_clk->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_clk;
+ }
+
+ rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (rc) {
+ pr_err("Could not register clock provider for node:%s\n",
+ np->name);
+ goto err_clk;
+ }
+ goto err_name;
+
+err_clk:
+ kfree(cmux_clk);
+err_name:
+ /* free *_names because they are reallocated when registered */
+ kfree(parent_names);
+}
+
+static void __init core_pll_init(struct device_node *np)
+{
+ u32 offset, mult;
+ int i, rc, count;
+ const char *clk_name, *parent_name;
+ struct clk_onecell_data *onecell_data;
+ struct clk **subclks;
+
+ rc = of_property_read_u32(np, "reg", &offset);
+ if (rc) {
+ pr_err("%s: could not get reg property\n", np->name);
+ return;
+ }
+
+ /* get the multiple of PLL */
+ mult = ioread32be(base + offset);
+
+ /* check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("PLL:%s is disabled\n", np->name);
+ return;
+ }
+ mult = (mult >> 1) & 0x3f;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("PLL: %s must have a parent\n", np->name);
+ return;
+ }
+
+ count = of_property_count_strings(np, "clock-output-names");
+ if (count < 0 || count > 4) {
+ pr_err("%s: clock is not supported\n", np->name);
+ return;
+ }
+
+ /* output clock number per PLL */
+ clocks_per_pll = count;
+
+ subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
+ if (!subclks) {
+ pr_err("%s: could not allocate subclks\n", __func__);
+ return;
+ }
+
+ onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!onecell_data) {
+ pr_err("%s: could not allocate onecell_data\n", __func__);
+ goto err_clks;
+ }
+
+ for (i = 0; i < count; i++) {
+ rc = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (rc) {
+ pr_err("%s: could not get clock names\n", np->name);
+ goto err_cell;
+ }
+
+ /*
+ * when count == 4, there are 4 output clocks:
+ * /1, /2, /3, /4 respectively
+ * when count < 4, there are at least 2 output clocks:
+ * /1, /2, (/4, if count == 3) respectively.
+ */
+ if (count == 4)
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ else
+
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 << i);
+
+ if (IS_ERR(subclks[i])) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_cell;
+ }
+ }
+
+ onecell_data->clks = subclks;
+ onecell_data->clk_num = count;
+
+ rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
+ if (rc) {
+ pr_err("Could not register clk provider for node:%s\n",
+ np->name);
+ goto err_cell;
+ }
+
+ return;
+err_cell:
+ kfree(onecell_data);
+err_clks:
+ kfree(subclks);
+}
+
+static const struct of_device_id clk_match[] __initconst = {
+ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+ { .compatible = "fsl,core-pll-clock", .data = core_pll_init, },
+ { .compatible = "fsl,core-mux-clock", .data = core_mux_init, },
+ {}
+};
+
+static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+
+ np = pdev->dev.of_node;
+ base = of_iomap(np, 0);
+ if (!base) {
+ dev_err(&pdev->dev, "iomap error\n");
+ return -ENOMEM;
+ }
+ of_clk_init(clk_match);
+
+ return 0;
+}
+
+static const struct of_device_id ppc_clk_ids[] __initconst = {
+ { .compatible = "fsl,qoriq-clockgen-1.0", },
+ { .compatible = "fsl,qoriq-clockgen-2.0", },
+ {}
+};
+
+static struct platform_driver ppc_corenet_clk_driver = {
+ .driver = {
+ .name = "ppc_corenet_clock",
+ .owner = THIS_MODULE,
+ .of_match_table = ppc_clk_ids,
+ },
+ .probe = ppc_corenet_clk_probe,
+};
+
+static int __init ppc_corenet_clk_init(void)
+{
+ return platform_driver_register(&ppc_corenet_clk_driver);
+}
+subsys_initcall(ppc_corenet_clk_init);
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index 24f553673b72..c50e83744b0a 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -851,6 +851,41 @@ static int _si5351_clkout_set_drive_strength(
return 0;
}
+static int _si5351_clkout_set_disable_state(
+ struct si5351_driver_data *drvdata, int num,
+ enum si5351_disable_state state)
+{
+ u8 reg = (num < 4) ? SI5351_CLK3_0_DISABLE_STATE :
+ SI5351_CLK7_4_DISABLE_STATE;
+ u8 shift = (num < 4) ? (2 * num) : (2 * (num-4));
+ u8 mask = SI5351_CLK_DISABLE_STATE_MASK << shift;
+ u8 val;
+
+ if (num > 8)
+ return -EINVAL;
+
+ switch (state) {
+ case SI5351_DISABLE_LOW:
+ val = SI5351_CLK_DISABLE_STATE_LOW;
+ break;
+ case SI5351_DISABLE_HIGH:
+ val = SI5351_CLK_DISABLE_STATE_HIGH;
+ break;
+ case SI5351_DISABLE_FLOATING:
+ val = SI5351_CLK_DISABLE_STATE_FLOAT;
+ break;
+ case SI5351_DISABLE_NEVER:
+ val = SI5351_CLK_DISABLE_STATE_NEVER;
+ break;
+ default:
+ return 0;
+ }
+
+ si5351_set_bits(drvdata, reg, mask, val << shift);
+
+ return 0;
+}
+
static int si5351_clkout_prepare(struct clk_hw *hw)
{
struct si5351_hw_data *hwdata =
@@ -1225,6 +1260,33 @@ static int si5351_dt_parse(struct i2c_client *client)
}
}
+ if (!of_property_read_u32(child, "silabs,disable-state",
+ &val)) {
+ switch (val) {
+ case 0:
+ pdata->clkout[num].disable_state =
+ SI5351_DISABLE_LOW;
+ break;
+ case 1:
+ pdata->clkout[num].disable_state =
+ SI5351_DISABLE_HIGH;
+ break;
+ case 2:
+ pdata->clkout[num].disable_state =
+ SI5351_DISABLE_FLOATING;
+ break;
+ case 3:
+ pdata->clkout[num].disable_state =
+ SI5351_DISABLE_NEVER;
+ break;
+ default:
+ dev_err(&client->dev,
+ "invalid disable state %d for clkout %d\n",
+ val, num);
+ return -EINVAL;
+ }
+ }
+
if (!of_property_read_u32(child, "clock-frequency", &val))
pdata->clkout[num].rate = val;
@@ -1281,9 +1343,6 @@ static int si5351_i2c_probe(struct i2c_client *client,
/* Disable interrupts */
si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0);
- /* Set disabled output drivers to drive low */
- si5351_reg_write(drvdata, SI5351_CLK3_0_DISABLE_STATE, 0x00);
- si5351_reg_write(drvdata, SI5351_CLK7_4_DISABLE_STATE, 0x00);
/* Ensure pll select is on XTAL for Si5351A/B */
if (drvdata->variant != SI5351_VARIANT_C)
si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
@@ -1327,6 +1386,15 @@ static int si5351_i2c_probe(struct i2c_client *client,
n, pdata->clkout[n].drive);
return ret;
}
+
+ ret = _si5351_clkout_set_disable_state(drvdata, n,
+ pdata->clkout[n].disable_state);
+ if (ret) {
+ dev_err(&client->dev,
+ "failed set disable state of clkout%d to %d\n",
+ n, pdata->clkout[n].disable_state);
+ return ret;
+ }
}
/* register xtal input clock gate */
@@ -1500,7 +1568,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
}
static const struct i2c_device_id si5351_i2c_ids[] = {
- { "silabs,si5351", 0 },
+ { "si5351a", 0 },
+ { "si5351a-msop", 0 },
+ { "si5351b", 0 },
+ { "si5351c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);
diff --git a/drivers/clk/clk-si5351.h b/drivers/clk/clk-si5351.h
index af41b5080f43..c0dbf2676872 100644
--- a/drivers/clk/clk-si5351.h
+++ b/drivers/clk/clk-si5351.h
@@ -81,6 +81,7 @@
#define SI5351_CLK3_0_DISABLE_STATE 24
#define SI5351_CLK7_4_DISABLE_STATE 25
+#define SI5351_CLK_DISABLE_STATE_MASK 3
#define SI5351_CLK_DISABLE_STATE_LOW 0
#define SI5351_CLK_DISABLE_STATE_HIGH 1
#define SI5351_CLK_DISABLE_STATE_FLOAT 2
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c
index 3af729b1b89d..1ada79a28052 100644
--- a/drivers/clk/clk-twl6040.c
+++ b/drivers/clk/clk-twl6040.c
@@ -95,14 +95,14 @@ static int twl6040_clk_probe(struct platform_device *pdev)
if (IS_ERR(clkdata->clk))
return PTR_ERR(clkdata->clk);
- dev_set_drvdata(&pdev->dev, clkdata);
+ platform_set_drvdata(pdev, clkdata);
return 0;
}
static int twl6040_clk_remove(struct platform_device *pdev)
{
- struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
+ struct twl6040_clk *clkdata = platform_get_drvdata(pdev);
clk_unregister(clkdata->clk);
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index 553ac35bcc91..82306f5fb9c2 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -42,6 +42,7 @@ struct clk_device {
#define PLL_TYPE_VT8500 0
#define PLL_TYPE_WM8650 1
#define PLL_TYPE_WM8750 2
+#define PLL_TYPE_WM8850 3
struct clk_pll {
struct clk_hw hw;
@@ -156,10 +157,6 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
divisor = parent_rate / rate;
- /* If prate / rate would be decimal, incr the divisor */
- if (rate * divisor < parent_rate)
- divisor++;
-
if (divisor == cdev->div_mask + 1)
divisor = 0;
@@ -327,6 +324,15 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
#define WM8750_BITS_TO_VAL(f, m, d1, d2) \
((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
+/* Helper macros for PLL_WM8850 */
+#define WM8850_PLL_MUL(x) ((((x >> 16) & 0x7F) + 1) * 2)
+#define WM8850_PLL_DIV(x) ((((x >> 8) & 1) + 1) * (1 << (x & 3)))
+
+#define WM8850_BITS_TO_FREQ(r, m, d1, d2) \
+ (r * ((m + 1) * 2) / ((d1+1) * (1 << d2)))
+
+#define WM8850_BITS_TO_VAL(m, d1, d2) \
+ ((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2)
static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *prediv)
@@ -466,6 +472,49 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
*divisor2 = best_div2;
}
+static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
+ u32 *multiplier, u32 *divisor1, u32 *divisor2)
+{
+ u32 mul, div1, div2;
+ u32 best_mul, best_div1, best_div2;
+ unsigned long tclk, rate_err, best_err;
+
+ best_err = (unsigned long)-1;
+
+ /* Find the closest match (lower or equal to requested) */
+ for (div1 = 1; div1 >= 0; div1--)
+ for (div2 = 3; div2 >= 0; div2--)
+ for (mul = 0; mul <= 127; mul++) {
+ tclk = parent_rate * ((mul + 1) * 2) /
+ ((div1 + 1) * (1 << div2));
+ if (tclk > rate)
+ continue;
+ /* error will always be +ve */
+ rate_err = rate - tclk;
+ if (rate_err == 0) {
+ *multiplier = mul;
+ *divisor1 = div1;
+ *divisor2 = div2;
+ return;
+ }
+
+ if (rate_err < best_err) {
+ best_err = rate_err;
+ best_mul = mul;
+ best_div1 = div1;
+ best_div2 = div2;
+ }
+ }
+
+ /* if we got here, it wasn't an exact match */
+ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
+ rate - best_err);
+
+ *multiplier = best_mul;
+ *divisor1 = best_div1;
+ *divisor2 = best_div2;
+}
+
static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -489,6 +538,10 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
break;
+ case PLL_TYPE_WM8850:
+ wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
+ pll_val = WM8850_BITS_TO_VAL(mul, div1, div2);
+ break;
default:
pr_err("%s: invalid pll type\n", __func__);
return 0;
@@ -525,6 +578,10 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
break;
+ case PLL_TYPE_WM8850:
+ wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2);
+ round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2);
+ break;
default:
round_rate = 0;
}
@@ -552,6 +609,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
pll_freq /= WM8750_PLL_DIV(pll_val);
break;
+ case PLL_TYPE_WM8850:
+ pll_freq = parent_rate * WM8850_PLL_MUL(pll_val);
+ pll_freq /= WM8850_PLL_DIV(pll_val);
+ break;
default:
pll_freq = 0;
}
@@ -628,6 +689,12 @@ static void __init wm8750_pll_init(struct device_node *node)
}
CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
+static void __init wm8850_pll_init(struct device_node *node)
+{
+ vtwm_pll_clk_init(node, PLL_TYPE_WM8850);
+}
+CLK_OF_DECLARE(wm8850_pll, "wm,wm8850-pll-clock", wm8850_pll_init);
+
void __init vtwm_clk_init(void __iomem *base)
{
if (!base)
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
index 16ed06808554..1b3f8c9b98cc 100644
--- a/drivers/clk/clk-wm831x.c
+++ b/drivers/clk/clk-wm831x.c
@@ -97,7 +97,7 @@ static int wm831x_fll_prepare(struct clk_hw *hw)
struct wm831x *wm831x = clkdata->wm831x;
int ret;
- ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2,
+ ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1,
WM831X_FLL_ENA, WM831X_FLL_ENA);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret);
@@ -114,9 +114,9 @@ static void wm831x_fll_unprepare(struct clk_hw *hw)
struct wm831x *wm831x = clkdata->wm831x;
int ret;
- ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, WM831X_FLL_ENA, 0);
+ ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0);
if (ret != 0)
- dev_crit(wm831x->dev, "Failed to disaable FLL: %d\n", ret);
+ dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret);
}
static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
@@ -299,8 +299,8 @@ static void wm831x_clkout_unprepare(struct clk_hw *hw)
}
static const char *wm831x_clkout_parents[] = {
- "xtal",
"fll",
+ "xtal",
};
static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
@@ -318,9 +318,9 @@ static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
}
if (ret & WM831X_CLKOUT_SRC)
- return 0;
- else
return 1;
+ else
+ return 0;
}
static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
@@ -384,7 +384,7 @@ static int wm831x_clk_probe(struct platform_device *pdev)
if (IS_ERR(clkdata->clkout))
return PTR_ERR(clkdata->clkout);
- dev_set_drvdata(&pdev->dev, clkdata);
+ platform_set_drvdata(pdev, clkdata);
return 0;
}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 1144e8c7579d..54a191c5bbf0 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -107,7 +107,7 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
level * 3 + 1, "",
30 - level * 3, c->name,
- c->enable_count, c->prepare_count, c->rate);
+ c->enable_count, c->prepare_count, clk_get_rate(c));
seq_printf(s, "\n");
}
@@ -166,7 +166,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "\"%s\": { ", c->name);
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
- seq_printf(s, "\"rate\": %lu", c->rate);
+ seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
}
static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
@@ -534,7 +534,7 @@ static int clk_disable_unused(void)
return 0;
}
-late_initcall(clk_disable_unused);
+late_initcall_sync(clk_disable_unused);
/*** helper functions ***/
@@ -1216,7 +1216,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
clk_prepare_lock();
/* bail early if nothing to do */
- if (rate == clk->rate)
+ if (rate == clk_get_rate(clk))
goto out;
if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
@@ -1377,23 +1377,33 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
unsigned long flags;
int ret = 0;
struct clk *old_parent = clk->parent;
- bool migrated_enable = false;
- /* migrate prepare */
- if (clk->prepare_count)
+ /*
+ * Migrate prepare state between parents and prevent race with
+ * clk_enable().
+ *
+ * If the clock is not prepared, then a race with
+ * clk_enable/disable() is impossible since we already have the
+ * prepare lock (future calls to clk_enable() need to be preceded by
+ * a clk_prepare()).
+ *
+ * If the clock is prepared, migrate the prepared state to the new
+ * parent and also protect against a race with clk_enable() by
+ * forcing the clock and the new parent on. This ensures that all
+ * future calls to clk_enable() are practically NOPs with respect to
+ * hardware and software states.
+ *
+ * See also: Comment for clk_set_parent() below.
+ */
+ if (clk->prepare_count) {
__clk_prepare(parent);
-
- flags = clk_enable_lock();
-
- /* migrate enable */
- if (clk->enable_count) {
- __clk_enable(parent);
- migrated_enable = true;
+ clk_enable(parent);
+ clk_enable(clk);
}
/* update the clk tree topology */
+ flags = clk_enable_lock();
clk_reparent(clk, parent);
-
clk_enable_unlock(flags);
/* change clock input source */
@@ -1401,43 +1411,27 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
ret = clk->ops->set_parent(clk->hw, p_index);
if (ret) {
- /*
- * The error handling is tricky due to that we need to release
- * the spinlock while issuing the .set_parent callback. This
- * means the new parent might have been enabled/disabled in
- * between, which must be considered when doing rollback.
- */
flags = clk_enable_lock();
-
clk_reparent(clk, old_parent);
-
- if (migrated_enable && clk->enable_count) {
- __clk_disable(parent);
- } else if (migrated_enable && (clk->enable_count == 0)) {
- __clk_disable(old_parent);
- } else if (!migrated_enable && clk->enable_count) {
- __clk_disable(parent);
- __clk_enable(old_parent);
- }
-
clk_enable_unlock(flags);
- if (clk->prepare_count)
+ if (clk->prepare_count) {
+ clk_disable(clk);
+ clk_disable(parent);
__clk_unprepare(parent);
-
+ }
return ret;
}
- /* clean up enable for old parent if migration was done */
- if (migrated_enable) {
- flags = clk_enable_lock();
- __clk_disable(old_parent);
- clk_enable_unlock(flags);
- }
-
- /* clean up prepare for old parent if migration was done */
- if (clk->prepare_count)
+ /*
+ * Finish the migration of prepare state and undo the changes done
+ * for preventing a race with clk_enable().
+ */
+ if (clk->prepare_count) {
+ clk_disable(clk);
+ clk_disable(old_parent);
__clk_unprepare(old_parent);
+ }
/* update debugfs with new clk tree topology */
clk_debug_reparent(clk, parent);
@@ -1449,12 +1443,17 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
* @clk: the mux clk whose input we are switching
* @parent: the new input to clk
*
- * Re-parent clk to use parent as it's new input source. If clk has the
- * CLK_SET_PARENT_GATE flag set then clk must be gated for this
- * operation to succeed. After successfully changing clk's parent
- * clk_set_parent will update the clk topology, sysfs topology and
- * propagate rate recalculation via __clk_recalc_rates. Returns 0 on
- * success, -EERROR otherwise.
+ * Re-parent clk to use parent as its new input source. If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
*/
int clk_set_parent(struct clk *clk, struct clk *parent)
{
@@ -1494,8 +1493,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
}
/* propagate PRE_RATE_CHANGE notifications */
- if (clk->notifier_count)
- ret = __clk_speculate_rates(clk, p_rate);
+ ret = __clk_speculate_rates(clk, p_rate);
/* abort if a driver objects */
if (ret & NOTIFY_STOP_MASK)
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
new file mode 100644
index 000000000000..8d3aefad2e73
--- /dev/null
+++ b/drivers/clk/rockchip/Makefile
@@ -0,0 +1,5 @@
+#
+# Rockchip Clock specific Makefile
+#
+
+obj-y += clk-rockchip.o
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
new file mode 100644
index 000000000000..967c141b1a20
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rockchip.c
@@ -0,0 +1,94 @@
+/*
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(clk_lock);
+
+/*
+ * Gate clocks
+ */
+
+static void __init rk2928_gate_clk_init(struct device_node *node,
+ void *data)
+{
+ struct clk_onecell_data *clk_data;
+ const char *clk_parent;
+ const char *clk_name;
+ void __iomem *reg;
+ void __iomem *reg_idx;
+ int flags;
+ int qty;
+ int reg_bit;
+ int clkflags = CLK_SET_RATE_PARENT;
+ int i;
+
+ qty = of_property_count_strings(node, "clock-output-names");
+ if (qty < 0) {
+ pr_err("%s: error in clock-output-names %d\n", __func__, qty);
+ return;
+ }
+
+ if (qty == 0) {
+ pr_info("%s: nothing to do\n", __func__);
+ return;
+ }
+
+ reg = of_iomap(node, 0);
+
+ clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
+
+ clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
+ if (!clk_data->clks) {
+ kfree(clk_data);
+ return;
+ }
+
+ flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
+
+ for (i = 0; i < qty; i++) {
+ of_property_read_string_index(node, "clock-output-names",
+ i, &clk_name);
+
+ /* ignore empty slots */
+ if (!strcmp("reserved", clk_name))
+ continue;
+
+ clk_parent = of_clk_get_parent_name(node, i);
+
+ /* keep all gates untouched for now */
+ clkflags |= CLK_IGNORE_UNUSED;
+
+ reg_idx = reg + (4 * (i / 16));
+ reg_bit = (i % 16);
+
+ clk_data->clks[i] = clk_register_gate(NULL, clk_name,
+ clk_parent, clkflags,
+ reg_idx, reg_bit,
+ flags,
+ &clk_lock);
+ WARN_ON(IS_ERR(clk_data->clks[i]));
+ }
+
+ clk_data->clk_num = qty;
+
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
+}
+CLK_OF_DECLARE(rk2928_gate, "rockchip,rk2928-gate-clk", rk2928_gate_clk_init);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index addc738a06fb..1bdb882c845b 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -356,8 +356,8 @@ struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {
/* list of mux clocks supported in all exynos4 soc's */
struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
- MUX_F(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
- CLK_SET_RATE_PARENT, 0),
+ MUX_FA(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
+ CLK_SET_RATE_PARENT, 0, "mout_apll"),
MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
MUX(none, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1),
MUX(none, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
@@ -385,9 +385,9 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1),
MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
- MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "sclk_mpll"),
+ MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "mout_mpll"),
MUX_A(mout_core, "mout_core", mout_core_p4210,
- SRC_CPU, 16, 1, "mout_core"),
+ SRC_CPU, 16, 1, "moutcore"),
MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210,
SRC_TOP0, 8, 1, "sclk_vpll"),
MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
@@ -424,8 +424,8 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
/* list of mux clocks supported in exynos4x12 soc */
struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
- MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
- SRC_CPU, 24, 1),
+ MUX_A(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
+ SRC_CPU, 24, 1, "mout_mpll"),
MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1),
MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1),
MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12,
@@ -449,7 +449,8 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
SRC_DMC, 12, 1, "sclk_mpll"),
MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p,
SRC_TOP0, 8, 1, "sclk_vpll"),
- MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
+ MUX_A(mout_core, "mout_core", mout_core_p4x12,
+ SRC_CPU, 16, 1, "moutcore"),
MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
@@ -537,7 +538,7 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {
DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),
DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
- DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "arm_clk"),
+ DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "armclk"),
DIV_A(sclk_apll, "sclk_apll", "mout_apll",
DIV_CPU0, 24, 3, "sclk_apll"),
DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
@@ -1070,9 +1071,9 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
- _get_rate("sclk_apll"), _get_rate("sclk_mpll"),
+ _get_rate("sclk_apll"), _get_rate("mout_mpll"),
_get_rate("sclk_epll"), _get_rate("sclk_vpll"),
- _get_rate("arm_clk"));
+ _get_rate("armclk"));
}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index e4ad6ea9aa76..2f7dba20ced8 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -144,6 +144,9 @@ struct samsung_mux_clock {
#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \
__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL)
+#define MUX_FA(_id, cname, pnames, o, s, w, f, mf, a) \
+ __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, a)
+
/**
* @id: platform specific id of the clock.
* struct samsung_div_clock: information about div clock
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 8492ad1d5360..412912bbba53 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -239,7 +239,7 @@ struct mux_data {
u8 shift;
};
-static const __initconst struct mux_data cpu_data = {
+static const __initconst struct mux_data cpu_mux_data = {
.shift = 16,
};
@@ -333,22 +333,34 @@ struct gates_data {
DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
};
-static const __initconst struct gates_data axi_gates_data = {
+static const __initconst struct gates_data sun4i_axi_gates_data = {
.mask = {1},
};
-static const __initconst struct gates_data ahb_gates_data = {
+static const __initconst struct gates_data sun4i_ahb_gates_data = {
.mask = {0x7F77FFF, 0x14FB3F},
};
-static const __initconst struct gates_data apb0_gates_data = {
+static const __initconst struct gates_data sun5i_a13_ahb_gates_data = {
+ .mask = {0x107067e7, 0x185111},
+};
+
+static const __initconst struct gates_data sun4i_apb0_gates_data = {
.mask = {0x4EF},
};
-static const __initconst struct gates_data apb1_gates_data = {
+static const __initconst struct gates_data sun5i_a13_apb0_gates_data = {
+ .mask = {0x61},
+};
+
+static const __initconst struct gates_data sun4i_apb1_gates_data = {
.mask = {0xFF00F7},
};
+static const __initconst struct gates_data sun5i_a13_apb1_gates_data = {
+ .mask = {0xa0007},
+};
+
static void __init sunxi_gates_clk_setup(struct device_node *node,
struct gates_data *data)
{
@@ -421,17 +433,20 @@ static const __initconst struct of_device_id clk_div_match[] = {
/* Matches for mux clocks */
static const __initconst struct of_device_id clk_mux_match[] = {
- {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,},
+ {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_mux_data,},
{.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
{}
};
/* Matches for gate clocks */
static const __initconst struct of_device_id clk_gates_match[] = {
- {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,},
- {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,},
- {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,},
- {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,},
+ {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
+ {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
+ {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
+ {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
+ {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
+ {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
+ {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
{}
};
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 17c2cc086eb4..197074a57754 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -117,10 +117,6 @@
#define PLLCX_MISC2_DEFAULT 0x30211200
#define PLLCX_MISC3_DEFAULT 0x200
-#define PMC_PLLM_WB0_OVERRIDE 0x1dc
-#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
-#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27)
-
#define PMC_SATA_PWRGT 0x1ac
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
@@ -128,38 +124,31 @@
#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
+#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
+#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
#define mask(w) ((1 << (w)) - 1)
-#define divm_mask(p) mask(p->divm_width)
-#define divn_mask(p) mask(p->divn_width)
+#define divm_mask(p) mask(p->params->div_nmp->divm_width)
+#define divn_mask(p) mask(p->params->div_nmp->divn_width)
#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \
- mask(p->divp_width))
+ mask(p->params->div_nmp->divp_width))
#define divm_max(p) (divm_mask(p))
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))
-
-#ifdef CONFIG_ARCH_TEGRA_114_SOC
-/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */
-#define PLLXC_PDIV_MAX 14
-
-/* non-monotonic mapping below is not a typo */
-static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = {
- /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */
- /* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32
-};
-
-#define PLLCX_PDIV_MAX 7
-static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = {
- /* PDIV: 0, 1, 2, 3, 4, 5, 6, 7 */
- /* p: */ 1, 2, 3, 4, 6, 8, 12, 16
+static struct div_nmp default_nmp = {
+ .divn_shift = PLL_BASE_DIVN_SHIFT,
+ .divn_width = PLL_BASE_DIVN_WIDTH,
+ .divm_shift = PLL_BASE_DIVM_SHIFT,
+ .divm_width = PLL_BASE_DIVM_WIDTH,
+ .divp_shift = PLL_BASE_DIVP_SHIFT,
+ .divp_width = PLL_BASE_DIVP_WIDTH,
};
-#endif
static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
{
@@ -297,6 +286,39 @@ static void clk_pll_disable(struct clk_hw *hw)
spin_unlock_irqrestore(pll->lock, flags);
}
+static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+
+ if (p_tohw) {
+ while (p_tohw->pdiv) {
+ if (p_div <= p_tohw->pdiv)
+ return p_tohw->hw_val;
+ p_tohw++;
+ }
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+
+static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw)
+{
+ struct tegra_clk_pll *pll = to_clk_pll(hw);
+ struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
+
+ if (p_tohw) {
+ while (p_tohw->pdiv) {
+ if (p_div_hw == p_tohw->hw_val)
+ return p_tohw->pdiv;
+ p_tohw++;
+ }
+ return -EINVAL;
+ }
+
+ return 1 << p_div_hw;
+}
+
static int _get_table_rate(struct clk_hw *hw,
struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
@@ -326,9 +348,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
unsigned long cfreq;
u32 p_div = 0;
+ int ret;
switch (parent_rate) {
case 12000000:
@@ -369,20 +391,16 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
|| cfg->output_rate > pll->params->vco_max) {
pr_err("%s: Failed to set %s rate %lu\n",
__func__, __clk_get_name(hw->clk), rate);
+ WARN_ON(1);
return -EINVAL;
}
- if (p_tohw) {
- p_div = 1 << p_div;
- while (p_tohw->pdiv) {
- if (p_div <= p_tohw->pdiv) {
- cfg->p = p_tohw->hw_val;
- break;
- }
- p_tohw++;
- }
- if (!p_tohw->pdiv)
- return -EINVAL;
+ if (pll->params->pdiv_tohw) {
+ ret = _p_div_to_hw(hw, 1 << p_div);
+ if (ret < 0)
+ return ret;
+ else
+ cfg->p = ret;
} else
cfg->p = p_div;
@@ -393,29 +411,61 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
u32 val;
+ struct tegra_clk_pll_params *params = pll->params;
+ struct div_nmp *div_nmp = params->div_nmp;
+
+ if ((pll->flags & TEGRA_PLLM) &&
+ (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
+ PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
+ val = pll_override_readl(params->pmc_divp_reg, pll);
+ val &= ~(divp_mask(pll) << div_nmp->override_divp_shift);
+ val |= cfg->p << div_nmp->override_divp_shift;
+ pll_override_writel(val, params->pmc_divp_reg, pll);
+
+ val = pll_override_readl(params->pmc_divnm_reg, pll);
+ val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |
+ ~(divn_mask(pll) << div_nmp->override_divn_shift);
+ val |= (cfg->m << div_nmp->override_divm_shift) |
+ (cfg->n << div_nmp->override_divn_shift);
+ pll_override_writel(val, params->pmc_divnm_reg, pll);
+ } else {
+ val = pll_readl_base(pll);
- val = pll_readl_base(pll);
+ val &= ~((divm_mask(pll) << div_nmp->divm_shift) |
+ (divn_mask(pll) << div_nmp->divn_shift) |
+ (divp_mask(pll) << div_nmp->divp_shift));
- val &= ~((divm_mask(pll) << pll->divm_shift) |
- (divn_mask(pll) << pll->divn_shift) |
- (divp_mask(pll) << pll->divp_shift));
- val |= ((cfg->m << pll->divm_shift) |
- (cfg->n << pll->divn_shift) |
- (cfg->p << pll->divp_shift));
+ val |= ((cfg->m << div_nmp->divm_shift) |
+ (cfg->n << div_nmp->divn_shift) |
+ (cfg->p << div_nmp->divp_shift));
- pll_writel_base(val, pll);
+ pll_writel_base(val, pll);
+ }
}
static void _get_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
u32 val;
+ struct tegra_clk_pll_params *params = pll->params;
+ struct div_nmp *div_nmp = params->div_nmp;
+
+ if ((pll->flags & TEGRA_PLLM) &&
+ (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
+ PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
+ val = pll_override_readl(params->pmc_divp_reg, pll);
+ cfg->p = (val >> div_nmp->override_divp_shift) & divp_mask(pll);
+
+ val = pll_override_readl(params->pmc_divnm_reg, pll);
+ cfg->m = (val >> div_nmp->override_divm_shift) & divm_mask(pll);
+ cfg->n = (val >> div_nmp->override_divn_shift) & divn_mask(pll);
+ } else {
+ val = pll_readl_base(pll);
- val = pll_readl_base(pll);
-
- cfg->m = (val >> pll->divm_shift) & (divm_mask(pll));
- cfg->n = (val >> pll->divn_shift) & (divn_mask(pll));
- cfg->p = (val >> pll->divp_shift) & (divp_mask(pll));
+ cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
+ cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
+ cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
+ }
}
static void _update_pll_cpcon(struct tegra_clk_pll *pll,
@@ -485,9 +535,10 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}
if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
- _calc_rate(hw, &cfg, rate, parent_rate))
+ _calc_rate(hw, &cfg, rate, parent_rate)) {
+ WARN_ON(1);
return -EINVAL;
-
+ }
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@@ -507,7 +558,6 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
- u64 output_rate = *prate;
if (pll->flags & TEGRA_PLL_FIXED)
return pll->fixed_rate;
@@ -517,13 +567,12 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
return __clk_get_rate(hw->clk);
if (_get_table_rate(hw, &cfg, rate, *prate) &&
- _calc_rate(hw, &cfg, rate, *prate))
+ _calc_rate(hw, &cfg, rate, *prate)) {
+ WARN_ON(1);
return -EINVAL;
+ }
- output_rate *= cfg.n;
- do_div(output_rate, cfg.m * (1 << cfg.p));
-
- return output_rate;
+ return cfg.output_rate;
}
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
@@ -531,7 +580,6 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
- struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
u32 val;
u64 rate = parent_rate;
int pdiv;
@@ -553,21 +601,11 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
_get_pll_mnp(pll, &cfg);
- if (p_tohw) {
- while (p_tohw->pdiv) {
- if (cfg.p == p_tohw->hw_val) {
- pdiv = p_tohw->pdiv;
- break;
- }
- p_tohw++;
- }
-
- if (!p_tohw->pdiv) {
- WARN_ON(1);
- pdiv = 1;
- }
- } else
- pdiv = 1 << cfg.p;
+ pdiv = _hw_to_p_div(hw, cfg.p);
+ if (pdiv < 0) {
+ WARN_ON(1);
+ pdiv = 1;
+ }
cfg.m *= pdiv;
@@ -647,9 +685,9 @@ static int clk_plle_enable(struct clk_hw *hw)
val = pll_readl_base(pll);
val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
- val |= sel.m << pll->divm_shift;
- val |= sel.n << pll->divn_shift;
- val |= sel.p << pll->divp_shift;
+ val |= sel.m << pll->params->div_nmp->divm_shift;
+ val |= sel.n << pll->params->div_nmp->divn_shift;
+ val |= sel.p << pll->params->div_nmp->divp_shift;
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
}
@@ -680,9 +718,9 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
u32 divn = 0, divm = 0, divp = 0;
u64 rate = parent_rate;
- divp = (val >> pll->divp_shift) & (divp_mask(pll));
- divn = (val >> pll->divn_shift) & (divn_mask(pll));
- divm = (val >> pll->divm_shift) & (divm_mask(pll));
+ divp = (val >> pll->params->div_nmp->divp_shift) & (divp_mask(pll));
+ divn = (val >> pll->params->div_nmp->divn_shift) & (divn_mask(pll));
+ divm = (val >> pll->params->div_nmp->divm_shift) & (divm_mask(pll));
divm *= divp;
rate *= divn;
@@ -769,16 +807,22 @@ static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned int p;
+ int p_div;
if (!rate)
return -EINVAL;
p = DIV_ROUND_UP(pll->params->vco_min, rate);
cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
- cfg->p = p;
- cfg->output_rate = rate * cfg->p;
+ cfg->output_rate = rate * p;
cfg->n = cfg->output_rate * cfg->m / parent_rate;
+ p_div = _p_div_to_hw(hw, p);
+ if (p_div < 0)
+ return p_div;
+ else
+ cfg->p = p_div;
+
if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
return -EINVAL;
@@ -790,18 +834,25 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
- int err = 0;
+ int err = 0, p_div;
err = _get_table_rate(hw, cfg, rate, parent_rate);
if (err < 0)
err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate);
- else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
+ else {
+ if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
WARN_ON(1);
err = -EINVAL;
goto out;
+ }
+ p_div = _p_div_to_hw(hw, cfg->p);
+ if (p_div < 0)
+ return p_div;
+ else
+ cfg->p = p_div;
}
- if (!cfg->p || (cfg->p > pll->params->max_p))
+ if (cfg->p > pll->params->max_p)
err = -EINVAL;
out:
@@ -815,7 +866,6 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
struct tegra_clk_pll_freq_table cfg, old_cfg;
unsigned long flags = 0;
int ret = 0;
- u8 old_p;
ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
if (ret < 0)
@@ -826,11 +876,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
_get_pll_mnp(pll, &old_cfg);
- old_p = pllxc_p[old_cfg.p];
- if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) {
- cfg.p -= 1;
+ if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
ret = _program_pll(hw, &cfg, rate);
- }
if (pll->lock)
spin_unlock_irqrestore(pll->lock, flags);
@@ -842,15 +889,19 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct tegra_clk_pll_freq_table cfg;
- int ret = 0;
+ int ret = 0, p_div;
u64 output_rate = *prate;
ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate);
if (ret < 0)
return ret;
+ p_div = _hw_to_p_div(hw, cfg.p);
+ if (p_div < 0)
+ return p_div;
+
output_rate *= cfg.n;
- do_div(output_rate, cfg.m * cfg.p);
+ do_div(output_rate, cfg.m * p_div);
return output_rate;
}
@@ -862,7 +913,6 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long flags = 0;
int state, ret = 0;
- u32 val;
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@@ -881,22 +931,7 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
if (ret < 0)
goto out;
- cfg.p -= 1;
-
- val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
- if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) {
- val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
- val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) :
- (val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK);
- writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
-
- val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
- val &= ~(divn_mask(pll) | divm_mask(pll));
- val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift);
- writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE);
- } else
- _update_pll_mnp(pll, &cfg);
-
+ _update_pll_mnp(pll, &cfg);
out:
if (pll->lock)
@@ -1010,13 +1045,10 @@ static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll,
static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
- struct tegra_clk_pll_freq_table cfg;
+ struct tegra_clk_pll_freq_table cfg, old_cfg;
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long flags = 0;
int state, ret = 0;
- u32 val;
- u16 old_m, old_n;
- u8 old_p;
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@@ -1025,21 +1057,16 @@ static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
if (ret < 0)
goto out;
- val = pll_readl_base(pll);
- old_m = (val >> pll->divm_shift) & (divm_mask(pll));
- old_n = (val >> pll->divn_shift) & (divn_mask(pll));
- old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))];
+ _get_pll_mnp(pll, &old_cfg);
- if (cfg.m != old_m) {
+ if (cfg.m != old_cfg.m) {
WARN_ON(1);
goto out;
}
- if (old_n == cfg.n && old_p == cfg.p)
+ if (old_cfg.n == cfg.n && old_cfg.p == cfg.p)
goto out;
- cfg.p -= 1;
-
state = clk_pll_is_enabled(hw);
if (state)
_clk_pllc_disable(hw);
@@ -1178,8 +1205,8 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
val = pll_readl_base(pll);
val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
- val |= sel.m << pll->divm_shift;
- val |= sel.n << pll->divn_shift;
+ val |= sel.m << pll->params->div_nmp->divm_shift;
+ val |= sel.n << pll->params->div_nmp->divn_shift;
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
udelay(1);
@@ -1240,12 +1267,8 @@ static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
pll->flags = pll_flags;
pll->lock = lock;
- pll->divp_shift = PLL_BASE_DIVP_SHIFT;
- pll->divp_width = PLL_BASE_DIVP_WIDTH;
- pll->divn_shift = PLL_BASE_DIVN_SHIFT;
- pll->divn_width = PLL_BASE_DIVN_WIDTH;
- pll->divm_shift = PLL_BASE_DIVM_SHIFT;
- pll->divm_width = PLL_BASE_DIVM_WIDTH;
+ if (!pll_params->div_nmp)
+ pll_params->div_nmp = &default_nmp;
return pll;
}
@@ -1401,7 +1424,7 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk;
- pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;
pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
freq_table, lock);
if (IS_ERR(pll))
@@ -1428,7 +1451,6 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
val &= ~BIT(29);
pll_writel_misc(val, pll);
- pll_flags |= TEGRA_PLL_LOCK_MISC;
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
&tegra_clk_pllre_ops);
if (IS_ERR(clk))
@@ -1453,6 +1475,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
pll_flags |= TEGRA_PLL_BYPASS;
pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
+ pll_flags |= TEGRA_PLLM;
pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
freq_table, lock);
if (IS_ERR(pll))
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 40d939d091bf..b6015cb4fc01 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/clk/tegra.h>
#include "clk.h"
@@ -28,6 +29,7 @@
#define RST_DEVICES_L 0x004
#define RST_DEVICES_H 0x008
#define RST_DEVICES_U 0x00C
+#define RST_DFLL_DVCO 0x2F4
#define RST_DEVICES_V 0x358
#define RST_DEVICES_W 0x35C
#define RST_DEVICES_X 0x28C
@@ -41,8 +43,36 @@
#define RST_DEVICES_CLR_V 0x434
#define RST_DEVICES_SET_W 0x438
#define RST_DEVICES_CLR_W 0x43c
+#define CPU_FINETRIM_SELECT 0x4d4 /* override default prop dlys */
+#define CPU_FINETRIM_DR 0x4d8 /* rise->rise prop dly A */
+#define CPU_FINETRIM_R 0x4e4 /* rise->rise prop dly inc A */
#define RST_DEVICES_NUM 5
+/* RST_DFLL_DVCO bitfields */
+#define DVFS_DFLL_RESET_SHIFT 0
+
+/* CPU_FINETRIM_SELECT and CPU_FINETRIM_DR bitfields */
+#define CPU_FINETRIM_1_FCPU_1 BIT(0) /* fcpu0 */
+#define CPU_FINETRIM_1_FCPU_2 BIT(1) /* fcpu1 */
+#define CPU_FINETRIM_1_FCPU_3 BIT(2) /* fcpu2 */
+#define CPU_FINETRIM_1_FCPU_4 BIT(3) /* fcpu3 */
+#define CPU_FINETRIM_1_FCPU_5 BIT(4) /* fl2 */
+#define CPU_FINETRIM_1_FCPU_6 BIT(5) /* ftop */
+
+/* CPU_FINETRIM_R bitfields */
+#define CPU_FINETRIM_R_FCPU_1_SHIFT 0 /* fcpu0 */
+#define CPU_FINETRIM_R_FCPU_1_MASK (0x3 << CPU_FINETRIM_R_FCPU_1_SHIFT)
+#define CPU_FINETRIM_R_FCPU_2_SHIFT 2 /* fcpu1 */
+#define CPU_FINETRIM_R_FCPU_2_MASK (0x3 << CPU_FINETRIM_R_FCPU_2_SHIFT)
+#define CPU_FINETRIM_R_FCPU_3_SHIFT 4 /* fcpu2 */
+#define CPU_FINETRIM_R_FCPU_3_MASK (0x3 << CPU_FINETRIM_R_FCPU_3_SHIFT)
+#define CPU_FINETRIM_R_FCPU_4_SHIFT 6 /* fcpu3 */
+#define CPU_FINETRIM_R_FCPU_4_MASK (0x3 << CPU_FINETRIM_R_FCPU_4_SHIFT)
+#define CPU_FINETRIM_R_FCPU_5_SHIFT 8 /* fl2 */
+#define CPU_FINETRIM_R_FCPU_5_MASK (0x3 << CPU_FINETRIM_R_FCPU_5_SHIFT)
+#define CPU_FINETRIM_R_FCPU_6_SHIFT 10 /* ftop */
+#define CPU_FINETRIM_R_FCPU_6_MASK (0x3 << CPU_FINETRIM_R_FCPU_6_SHIFT)
+
#define CLK_OUT_ENB_L 0x010
#define CLK_OUT_ENB_H 0x014
#define CLK_OUT_ENB_U 0x018
@@ -127,6 +157,7 @@
#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
#define PMC_CTRL 0
#define PMC_CTRL_BLINK_ENB 7
+#define PMC_BLINK_TIMER 0x40
#define OSC_CTRL 0x50
#define OSC_CTRL_OSC_FREQ_SHIFT 28
@@ -242,6 +273,8 @@
#define CLK_SOURCE_I2CSLOW 0x3fc
#define CLK_SOURCE_SE 0x42c
#define CLK_SOURCE_MSELECT 0x3b4
+#define CLK_SOURCE_DFLL_REF 0x62c
+#define CLK_SOURCE_DFLL_SOC 0x630
#define CLK_SOURCE_SOC_THERM 0x644
#define CLK_SOURCE_XUSB_HOST_SRC 0x600
#define CLK_SOURCE_XUSB_FALCON_SRC 0x604
@@ -250,6 +283,10 @@
#define CLK_SOURCE_XUSB_DEV_SRC 0x60c
#define CLK_SOURCE_EMC 0x19c
+/* PLLM override registers */
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
+
/* Tegra CPU clock and reset control regs */
#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
@@ -267,6 +304,15 @@ static DEFINE_SPINLOCK(clk_doubler_lock);
static DEFINE_SPINLOCK(clk_out_lock);
static DEFINE_SPINLOCK(sysrate_lock);
+static struct div_nmp pllxc_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 4,
+};
+
static struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
@@ -315,6 +361,16 @@ static struct tegra_clk_pll_params pll_c_params = {
.stepa_shift = 17,
.stepb_shift = 9,
.pdiv_tohw = pllxc_p,
+ .div_nmp = &pllxc_nmp,
+};
+
+static struct div_nmp pllcx_nmp = {
+ .divm_shift = 0,
+ .divm_width = 2,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 20,
+ .divp_width = 3,
};
static struct pdiv_map pllc_p[] = {
@@ -348,6 +404,8 @@ static struct tegra_clk_pll_params pll_c2_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = pllc_p,
+ .div_nmp = &pllcx_nmp,
+ .max_p = 7,
.ext_misc_reg[0] = 0x4f0,
.ext_misc_reg[1] = 0x4f4,
.ext_misc_reg[2] = 0x4f8,
@@ -366,11 +424,25 @@ static struct tegra_clk_pll_params pll_c3_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = pllc_p,
+ .div_nmp = &pllcx_nmp,
+ .max_p = 7,
.ext_misc_reg[0] = 0x504,
.ext_misc_reg[1] = 0x508,
.ext_misc_reg[2] = 0x50c,
};
+static struct div_nmp pllm_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .override_divm_shift = 0,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .override_divn_shift = 8,
+ .divp_shift = 20,
+ .divp_width = 1,
+ .override_divp_shift = 27,
+};
+
static struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
@@ -400,6 +472,18 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_delay = 300,
.max_p = 2,
.pdiv_tohw = pllm_p,
+ .div_nmp = &pllm_nmp,
+ .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+ .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
+};
+
+static struct div_nmp pllp_nmp = {
+ .divm_shift = 0,
+ .divm_width = 5,
+ .divn_shift = 8,
+ .divn_width = 10,
+ .divp_shift = 20,
+ .divp_width = 3,
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
@@ -423,6 +507,7 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
@@ -449,6 +534,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
@@ -484,6 +570,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
+ .div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_params pll_d2_params = {
@@ -498,6 +585,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
+ .div_nmp = &pllp_nmp,
};
static struct pdiv_map pllu_p[] = {
@@ -506,6 +594,15 @@ static struct pdiv_map pllu_p[] = {
{ .pdiv = 0, .hw_val = 0 },
};
+static struct div_nmp pllu_nmp = {
+ .divm_shift = 0,
+ .divm_width = 5,
+ .divn_shift = 8,
+ .divn_width = 10,
+ .divp_shift = 20,
+ .divp_width = 1,
+};
+
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{12000000, 480000000, 960, 12, 0, 12},
{13000000, 480000000, 960, 13, 0, 12},
@@ -528,6 +625,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
+ .div_nmp = &pllu_nmp,
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
@@ -560,6 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.stepa_shift = 16,
.stepb_shift = 24,
.pdiv_tohw = pllxc_p,
+ .div_nmp = &pllxc_nmp,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
@@ -569,6 +668,15 @@ static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
{0, 0, 0, 0, 0, 0},
};
+static struct div_nmp plle_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 24,
+ .divp_width = 4,
+};
+
static struct tegra_clk_pll_params pll_e_params = {
.input_min = 12000000,
.input_max = 1000000000,
@@ -582,6 +690,16 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &plle_nmp,
+};
+
+static struct div_nmp pllre_nmp = {
+ .divm_shift = 0,
+ .divm_width = 8,
+ .divn_shift = 8,
+ .divn_width = 8,
+ .divp_shift = 16,
+ .divp_width = 4,
};
static struct tegra_clk_pll_params pll_re_vco_params = {
@@ -598,6 +716,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.lock_delay = 300,
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
+ .div_nmp = &pllre_nmp,
};
/* Peripheral clock registers */
@@ -765,6 +884,7 @@ enum tegra114_clk {
audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3,
blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src,
xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp,
+ dfll_ref = 264, dfll_soc,
/* Mux clocks */
@@ -1202,8 +1322,8 @@ static void __init tegra114_pll_init(void __iomem *clk_base,
/* PLLP_OUT2 */
clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",
clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
- TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
- &pll_div_lock);
+ TEGRA_DIVIDER_ROUND_UP | TEGRA_DIVIDER_INT, 24,
+ 8, 1, &pll_div_lock);
clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",
clk_base + PLLP_OUTA, 17, 16,
CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
@@ -1605,7 +1725,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
/* clk_out_2 */
clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out2_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
&clk_out_lock);
clks[clk_out_2_mux] = clk;
@@ -1617,7 +1737,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
/* clk_out_3 */
clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out3_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
&clk_out_lock);
clks[clk_out_3_mux] = clk;
@@ -1628,6 +1748,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
clks[clk_out_3] = clk;
/* blink */
+ /* clear the blink timer register to directly output clk_32k */
+ writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
pmc_base + PMC_DPD_PADS_ORIDE,
PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
@@ -1640,7 +1762,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
}
static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
- "pll_p_out3", "pll_p_out2", "unused",
+ "pll_p", "pll_p_out2", "unused",
"clk_32k", "pll_m_out1" };
static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
@@ -1750,7 +1872,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),
TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),
TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp),
- TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc),
+ TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_u_regs, TEGRA_PERIPH_WAR_1005168, msenc),
TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec),
TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),
TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi),
@@ -1767,6 +1889,8 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow),
TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se),
TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED),
+ TEGRA_INIT_DATA_MUX("dfll_ref", "ref", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_ref),
+ TEGRA_INIT_DATA_MUX("dfll_soc", "soc", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_soc),
TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm),
TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src),
TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src),
@@ -2028,6 +2152,10 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
+/*
+ * dfll_soc/dfll_ref apparently must be kept enabled, otherwise I2C5
+ * breaks
+ */
static __initdata struct tegra_clk_init_table init_table[] = {
{uarta, pll_p, 408000000, 0},
{uartb, pll_p, 408000000, 0},
@@ -2043,6 +2171,8 @@ static __initdata struct tegra_clk_init_table init_table[] = {
{i2s2, pll_a_out0, 11289600, 0},
{i2s3, pll_a_out0, 11289600, 0},
{i2s4, pll_a_out0, 11289600, 0},
+ {dfll_soc, pll_p, 51000000, 1},
+ {dfll_ref, pll_p, 51000000, 1},
{clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
};
@@ -2051,7 +2181,132 @@ static void __init tegra114_clock_apply_init_table(void)
tegra_init_from_table(init_table, clks, clk_max);
}
-void __init tegra114_clock_init(struct device_node *np)
+
+/**
+ * tegra114_car_barrier - wait for pending writes to the CAR to complete
+ *
+ * Wait for any outstanding writes to the CAR MMIO space from this CPU
+ * to complete before continuing execution. No return value.
+ */
+static void tegra114_car_barrier(void)
+{
+ wmb(); /* probably unnecessary */
+ readl_relaxed(clk_base + CPU_FINETRIM_SELECT);
+}
+
+/**
+ * tegra114_clock_tune_cpu_trimmers_high - use high-voltage propagation delays
+ *
+ * When the CPU rail voltage is in the high-voltage range, use the
+ * built-in hardwired clock propagation delays in the CPU clock
+ * shaper. No return value.
+ */
+void tegra114_clock_tune_cpu_trimmers_high(void)
+{
+ u32 select = 0;
+
+ /* Use hardwired rise->rise & fall->fall clock propagation delays */
+ select |= ~(CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
+ CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
+ CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
+ writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT);
+
+ tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_high);
+
+/**
+ * tegra114_clock_tune_cpu_trimmers_low - use low-voltage propagation delays
+ *
+ * When the CPU rail voltage is in the low-voltage range, use the
+ * extended clock propagation delays set by
+ * tegra114_clock_tune_cpu_trimmers_init(). The intention is to
+ * maintain the input clock duty cycle that the FCPU subsystem
+ * expects. No return value.
+ */
+void tegra114_clock_tune_cpu_trimmers_low(void)
+{
+ u32 select = 0;
+
+ /*
+ * Use software-specified rise->rise & fall->fall clock
+ * propagation delays (from
+ * tegra114_clock_tune_cpu_trimmers_init()
+ */
+ select |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
+ CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
+ CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
+ writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT);
+
+ tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_low);
+
+/**
+ * tegra114_clock_tune_cpu_trimmers_init - set up and enable clk prop delays
+ *
+ * Program extended clock propagation delays into the FCPU clock
+ * shaper and enable them. XXX Define the purpose - peak current
+ * reduction? No return value.
+ */
+/* XXX Initial voltage rail state assumption issues? */
+void tegra114_clock_tune_cpu_trimmers_init(void)
+{
+ u32 dr = 0, r = 0;
+
+ /* Increment the rise->rise clock delay by four steps */
+ r |= (CPU_FINETRIM_R_FCPU_1_MASK | CPU_FINETRIM_R_FCPU_2_MASK |
+ CPU_FINETRIM_R_FCPU_3_MASK | CPU_FINETRIM_R_FCPU_4_MASK |
+ CPU_FINETRIM_R_FCPU_5_MASK | CPU_FINETRIM_R_FCPU_6_MASK);
+ writel_relaxed(r, clk_base + CPU_FINETRIM_R);
+
+ /*
+ * Use the rise->rise clock propagation delay specified in the
+ * r field
+ */
+ dr |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
+ CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
+ CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
+ writel_relaxed(dr, clk_base + CPU_FINETRIM_DR);
+
+ tegra114_clock_tune_cpu_trimmers_low();
+}
+EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_init);
+
+/**
+ * tegra114_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset
+ *
+ * Assert the reset line of the DFLL's DVCO. No return value.
+ */
+void tegra114_clock_assert_dfll_dvco_reset(void)
+{
+ u32 v;
+
+ v = readl_relaxed(clk_base + RST_DFLL_DVCO);
+ v |= (1 << DVFS_DFLL_RESET_SHIFT);
+ writel_relaxed(v, clk_base + RST_DFLL_DVCO);
+ tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset);
+
+/**
+ * tegra114_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset
+ *
+ * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to
+ * operate. No return value.
+ */
+void tegra114_clock_deassert_dfll_dvco_reset(void)
+{
+ u32 v;
+
+ v = readl_relaxed(clk_base + RST_DFLL_DVCO);
+ v &= ~(1 << DVFS_DFLL_RESET_SHIFT);
+ writel_relaxed(v, clk_base + RST_DFLL_DVCO);
+ tegra114_car_barrier();
+}
+EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset);
+
+static void __init tegra114_clock_init(struct device_node *np)
{
struct device_node *node;
int i;
@@ -2104,3 +2359,4 @@ void __init tegra114_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra114_cpu_car_ops;
}
+CLK_OF_DECLARE(tegra114, "nvidia,tegra114-car", tegra114_clock_init);
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 075db0c99edb..759ca47be753 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -1287,7 +1287,7 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
-void __init tegra20_clock_init(struct device_node *np)
+static void __init tegra20_clock_init(struct device_node *np)
{
int i;
struct device_node *node;
@@ -1339,3 +1339,4 @@ void __init tegra20_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra20_cpu_car_ops;
}
+CLK_OF_DECLARE(tegra20, "nvidia,tegra20-car", tegra20_clock_init);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index ba99e3844106..e2c6ca0431d6 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -252,6 +252,9 @@
#define CLK_RESET_CCLK_RUN_POLICY 2
#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8
+/* PLLM override registers */
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+
#ifdef CONFIG_PM_SLEEP
static struct cpu_clk_suspend_context {
u32 pllx_misc;
@@ -563,6 +566,18 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_delay = 300,
};
+static struct div_nmp pllm_nmp = {
+ .divn_shift = 8,
+ .divn_width = 10,
+ .override_divn_shift = 5,
+ .divm_shift = 0,
+ .divm_width = 5,
+ .override_divm_shift = 0,
+ .divp_shift = 20,
+ .divp_width = 3,
+ .override_divp_shift = 15,
+};
+
static struct tegra_clk_pll_params pll_m_params = {
.input_min = 2000000,
.input_max = 31000000,
@@ -575,6 +590,9 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
+ .div_nmp = &pllm_nmp,
+ .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
+ .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
};
static struct tegra_clk_pll_params pll_p_params = {
@@ -1223,7 +1241,7 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_2 */
clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out2_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
&clk_out_lock);
clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
@@ -1234,7 +1252,7 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_3 */
clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
- ARRAY_SIZE(clk_out1_parents), 0,
+ ARRAY_SIZE(clk_out3_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
&clk_out_lock);
clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
@@ -1954,7 +1972,7 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
-void __init tegra30_clock_init(struct device_node *np)
+static void __init tegra30_clock_init(struct device_node *np)
{
struct device_node *node;
int i;
@@ -2005,3 +2023,4 @@ void __init tegra30_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra30_cpu_car_ops;
}
+CLK_OF_DECLARE(tegra30, "nvidia,tegra30-car", tegra30_clock_init);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 923ca7ee4694..86581ac1fd69 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -74,18 +74,6 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
}
}
-static const struct of_device_id tegra_dt_clk_match[] = {
- { .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init },
- { .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init },
- { .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init },
- { }
-};
-
-void __init tegra_clocks_init(void)
-{
- of_clk_init(tegra_dt_clk_match);
-}
-
tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
void __init tegra_clocks_apply_init_table(void)
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index e0565620d68e..07cfacd91686 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -128,6 +128,31 @@ struct pdiv_map {
};
/**
+ * struct div_nmp - offset and width of m,n and p fields
+ *
+ * @divn_shift: shift to the feedback divider bit field
+ * @divn_width: width of the feedback divider bit field
+ * @divm_shift: shift to the input divider bit field
+ * @divm_width: width of the input divider bit field
+ * @divp_shift: shift to the post divider bit field
+ * @divp_width: width of the post divider bit field
+ * @override_divn_shift: shift to the feedback divider bitfield in override reg
+ * @override_divm_shift: shift to the input divider bitfield in override reg
+ * @override_divp_shift: shift to the post divider bitfield in override reg
+ */
+struct div_nmp {
+ u8 divn_shift;
+ u8 divn_width;
+ u8 divm_shift;
+ u8 divm_width;
+ u8 divp_shift;
+ u8 divp_width;
+ u8 override_divn_shift;
+ u8 override_divm_shift;
+ u8 override_divp_shift;
+};
+
+/**
* struct clk_pll_params - PLL parameters
*
* @input_min: Minimum input frequency
@@ -161,11 +186,14 @@ struct tegra_clk_pll_params {
u32 aux_reg;
u32 dyn_ramp_reg;
u32 ext_misc_reg[3];
+ u32 pmc_divnm_reg;
+ u32 pmc_divp_reg;
int stepa_shift;
int stepb_shift;
int lock_delay;
int max_p;
struct pdiv_map *pdiv_tohw;
+ struct div_nmp *div_nmp;
};
/**
@@ -179,12 +207,6 @@ struct tegra_clk_pll_params {
* @flags: PLL flags
* @fixed_rate: PLL rate if it is fixed
* @lock: register lock
- * @divn_shift: shift to the feedback divider bit field
- * @divn_width: width of the feedback divider bit field
- * @divm_shift: shift to the input divider bit field
- * @divm_width: width of the input divider bit field
- * @divp_shift: shift to the post divider bit field
- * @divp_width: width of the post divider bit field
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@@ -214,12 +236,6 @@ struct tegra_clk_pll {
u32 flags;
unsigned long fixed_rate;
spinlock_t *lock;
- u8 divn_shift;
- u8 divn_width;
- u8 divm_shift;
- u8 divm_width;
- u8 divp_shift;
- u8 divp_width;
struct tegra_clk_pll_freq_table *freq_table;
struct tegra_clk_pll_params *params;
};
@@ -571,23 +587,11 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl,
void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
struct clk *clks[], int clk_max);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-void tegra20_clock_init(struct device_node *np);
-#else
-static inline void tegra20_clock_init(struct device_node *np) {}
-#endif /* CONFIG_ARCH_TEGRA_2x_SOC */
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-void tegra30_clock_init(struct device_node *np);
-#else
-static inline void tegra30_clock_init(struct device_node *np) {}
-#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
-
-#ifdef CONFIG_ARCH_TEGRA_114_SOC
-void tegra114_clock_init(struct device_node *np);
-#else
-static inline void tegra114_clock_init(struct device_node *np) {}
-#endif /* CONFIG_ARCH_TEGRA114_SOC */
+void tegra114_clock_tune_cpu_trimmers_high(void);
+void tegra114_clock_tune_cpu_trimmers_low(void);
+void tegra114_clock_tune_cpu_trimmers_init(void);
+void tegra114_clock_assert_dfll_dvco_reset(void);
+void tegra114_clock_deassert_dfll_dvco_reset(void);
typedef void (*tegra_clk_apply_init_table_func)(void);
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c
index a0fca004abc1..e7bd62cf60b3 100644
--- a/drivers/clk/ux500/abx500-clk.c
+++ b/drivers/clk/ux500/abx500-clk.c
@@ -45,7 +45,7 @@ static int ab8500_reg_clks(struct device *dev)
CLK_IS_ROOT);
clk_register_clkdev(clk, "sysclk", "ab8500-usb.0");
clk_register_clkdev(clk, "sysclk", "ab-iddet.0");
- clk_register_clkdev(clk, "sysclk", "ab85xx-codec.0");
+ clk_register_clkdev(clk, "sysclk", "snd-soc-mop500.0");
clk_register_clkdev(clk, "sysclk", "shrm_bus");
/* ab8500_sysclk2 */
@@ -70,19 +70,19 @@ static int ab8500_reg_clks(struct device *dev)
AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
38400000, 9000, CLK_IS_ROOT);
- clk_register_clkdev(clk, "ulpclk", "ab85xx-codec.0");
+ clk_register_clkdev(clk, "ulpclk", "snd-soc-mop500.0");
/* ab8500_intclk */
clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,
intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0);
- clk_register_clkdev(clk, "intclk", "ab85xx-codec.0");
+ clk_register_clkdev(clk, "intclk", "snd-soc-mop500.0");
clk_register_clkdev(clk, NULL, "ab8500-pwm.1");
/* ab8500_audioclk */
clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",
AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,
AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0);
- clk_register_clkdev(clk, "audioclk", "ab85xx-codec.0");
+ clk_register_clkdev(clk, "audioclk", "ab8500-codec.0");
return 0;
}
diff --git a/drivers/clk/ux500/u8540_clk.c b/drivers/clk/ux500/u8540_clk.c
index 10adfd2ead21..f26258869deb 100644
--- a/drivers/clk/ux500/u8540_clk.c
+++ b/drivers/clk/ux500/u8540_clk.c
@@ -12,10 +12,568 @@
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
-
#include "clk.h"
-void u8540_clk_init(void)
+void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
+ u32 clkrst5_base, u32 clkrst6_base)
{
- /* register clocks here */
+ struct clk *clk;
+
+ /* Clock sources. */
+ /* Fixed ClockGen */
+ clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "soc0_pll", NULL);
+
+ clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "soc1_pll", NULL);
+
+ clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "ddr_pll", NULL);
+
+ clk = clk_register_fixed_rate(NULL, "rtc32k", NULL,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED,
+ 32768);
+ clk_register_clkdev(clk, "clk32k", NULL);
+ clk_register_clkdev(clk, "apb_pclk", "rtc-pl031");
+
+ clk = clk_register_fixed_rate(NULL, "ulp38m4", NULL,
+ CLK_IS_ROOT|CLK_IGNORE_UNUSED,
+ 38400000);
+
+ clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "UART");
+
+ /* msp02clk needs a abx500 clk as parent. Handle by abx500 clk driver */
+ clk = clk_reg_prcmu_gate("msp02clk", "ab9540_sysclk12_b1",
+ PRCMU_MSP02CLK, 0);
+ clk_register_clkdev(clk, NULL, "MSP02");
+
+ clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "MSP1");
+
+ clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "I2C");
+
+ clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "slim");
+
+ clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH1");
+
+ clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH2");
+
+ clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH3");
+
+ clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH5");
+
+ clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH6");
+
+ clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "PERIPH7");
+
+ clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "lcd");
+ clk_register_clkdev(clk, "lcd", "mcde");
+
+ clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BML8580CLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "bml");
+
+ clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+
+ clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "hdmi");
+ clk_register_clkdev(clk, "hdmi", "mcde");
+
+ clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "apeat");
+
+ clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "apetrace");
+
+ clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "mcde");
+ clk_register_clkdev(clk, "mcde", "mcde");
+ clk_register_clkdev(clk, NULL, "dsilink.0");
+ clk_register_clkdev(clk, NULL, "dsilink.1");
+ clk_register_clkdev(clk, NULL, "dsilink.2");
+
+ clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "ipi2");
+
+ clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
+ CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "dsialt");
+
+ clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "dma40.0");
+
+ clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "b2r2");
+ clk_register_clkdev(clk, NULL, "b2r2_core");
+ clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
+ clk_register_clkdev(clk, NULL, "b2r2_1_core");
+
+ clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "tv");
+ clk_register_clkdev(clk, "tv", "mcde");
+
+ clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "SSP");
+
+ clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "rngclk");
+
+ clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "uicc");
+
+ clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "mtu0");
+ clk_register_clkdev(clk, NULL, "mtu1");
+
+ clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL,
+ PRCMU_SDMMCCLK, 100000000,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdmmc");
+
+ clk = clk_reg_prcmu_opp_volt_scalable("sdmmchclk", NULL,
+ PRCMU_SDMMCHCLK, 400000000,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdmmchclk");
+
+ clk = clk_reg_prcmu_gate("hvaclk", NULL, PRCMU_HVACLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "hva");
+
+ clk = clk_reg_prcmu_gate("g1clk", NULL, PRCMU_G1CLK, CLK_IS_ROOT);
+ clk_register_clkdev(clk, NULL, "g1");
+
+ clk = clk_reg_prcmu_scalable("spare1clk", NULL, PRCMU_SPARE1CLK, 0,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsilcd", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
+ PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs2", "mcde");
+ clk_register_clkdev(clk, "hs_clk", "dsilink.2");
+
+ clk = clk_reg_prcmu_scalable("dsilcd_pll", "spare1clk",
+ PRCMU_PLLDSI_LCD, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsilcd_pll", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
+ PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs0", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi0lcdclk", "dsilcd_pll",
+ PRCMU_DSI0CLK_LCD, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs0", "mcde");
+ clk_register_clkdev(clk, "hs_clk", "dsilink.0");
+
+ clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
+ PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs1", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi1lcdclk", "dsilcd_pll",
+ PRCMU_DSI1CLK_LCD, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "dsihs1", "mcde");
+ clk_register_clkdev(clk, "hs_clk", "dsilink.1");
+
+ clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
+ PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "lp_clk", "dsilink.0");
+ clk_register_clkdev(clk, "dsilp0", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
+ PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "lp_clk", "dsilink.1");
+ clk_register_clkdev(clk, "dsilp1", "mcde");
+
+ clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
+ PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, "lp_clk", "dsilink.2");
+ clk_register_clkdev(clk, "dsilp2", "mcde");
+
+ clk = clk_reg_prcmu_scalable_rate("armss", NULL,
+ PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "armss", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
+ CLK_IGNORE_UNUSED, 1, 2);
+ clk_register_clkdev(clk, NULL, "smp_twd");
+
+ /* PRCC P-clocks */
+ /* Peripheral 1 : PRCC P-clocks */
+ clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base,
+ BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base,
+ BIT(1), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart1");
+
+ clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base,
+ BIT(2), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1");
+
+ clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base,
+ BIT(3), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp0");
+ clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base,
+ BIT(4), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp1");
+ clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.1");
+
+ clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base,
+ BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base,
+ BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2");
+
+ clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base,
+ BIT(7), 0);
+ clk_register_clkdev(clk, NULL, "spi3");
+
+ clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base,
+ BIT(8), 0);
+ clk_register_clkdev(clk, "apb_pclk", "slimbus0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base,
+ BIT(9), 0);
+ clk_register_clkdev(clk, NULL, "gpio.0");
+ clk_register_clkdev(clk, NULL, "gpio.1");
+ clk_register_clkdev(clk, NULL, "gpioblock0");
+ clk_register_clkdev(clk, "apb_pclk", "ab85xx-codec.0");
+
+ clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base,
+ BIT(10), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4");
+
+ clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base,
+ BIT(11), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp3");
+ clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.3");
+
+ /* Peripheral 2 : PRCC P-clocks */
+ clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base,
+ BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3");
+
+ clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base,
+ BIT(1), 0);
+ clk_register_clkdev(clk, NULL, "spi2");
+
+ clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base,
+ BIT(2), 0);
+ clk_register_clkdev(clk, NULL, "spi1");
+
+ clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base,
+ BIT(3), 0);
+ clk_register_clkdev(clk, NULL, "pwl");
+
+ clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base,
+ BIT(4), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi4");
+
+ clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base,
+ BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp2");
+ clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.2");
+
+ clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base,
+ BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi1");
+
+ clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base,
+ BIT(7), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi3");
+
+ clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base,
+ BIT(8), 0);
+ clk_register_clkdev(clk, NULL, "spi0");
+
+ clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base,
+ BIT(9), 0);
+ clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
+
+ clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base,
+ BIT(10), 0);
+ clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
+
+ clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base,
+ BIT(11), 0);
+ clk_register_clkdev(clk, NULL, "gpio.6");
+ clk_register_clkdev(clk, NULL, "gpio.7");
+ clk_register_clkdev(clk, NULL, "gpioblock1");
+
+ clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base,
+ BIT(12), 0);
+ clk_register_clkdev(clk, "msp4-pclk", "ab85xx-codec.0");
+
+ /* Peripheral 3 : PRCC P-clocks */
+ clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
+ BIT(0), 0);
+ clk_register_clkdev(clk, NULL, "fsmc");
+
+ clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
+ BIT(1), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ssp0");
+
+ clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base,
+ BIT(2), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ssp1");
+
+ clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base,
+ BIT(3), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0");
+
+ clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base,
+ BIT(4), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi2");
+
+ clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base,
+ BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ske");
+ clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
+
+ clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base,
+ BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart2");
+
+ clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base,
+ BIT(7), 0);
+ clk_register_clkdev(clk, "apb_pclk", "sdi5");
+
+ clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base,
+ BIT(8), 0);
+ clk_register_clkdev(clk, NULL, "gpio.2");
+ clk_register_clkdev(clk, NULL, "gpio.3");
+ clk_register_clkdev(clk, NULL, "gpio.4");
+ clk_register_clkdev(clk, NULL, "gpio.5");
+ clk_register_clkdev(clk, NULL, "gpioblock2");
+
+ clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", clkrst3_base,
+ BIT(9), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.5");
+
+ clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", clkrst3_base,
+ BIT(10), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.6");
+
+ clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", clkrst3_base,
+ BIT(11), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart3");
+
+ clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", clkrst3_base,
+ BIT(12), 0);
+ clk_register_clkdev(clk, "apb_pclk", "uart4");
+
+ /* Peripheral 5 : PRCC P-clocks */
+ clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base,
+ BIT(0), 0);
+ clk_register_clkdev(clk, "usb", "musb-ux500.0");
+ clk_register_clkdev(clk, "usbclk", "ab-iddet.0");
+
+ clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base,
+ BIT(1), 0);
+ clk_register_clkdev(clk, NULL, "gpio.8");
+ clk_register_clkdev(clk, NULL, "gpioblock3");
+
+ /* Peripheral 6 : PRCC P-clocks */
+ clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base,
+ BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "rng");
+
+ clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base,
+ BIT(1), 0);
+ clk_register_clkdev(clk, NULL, "cryp0");
+ clk_register_clkdev(clk, NULL, "cryp1");
+
+ clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base,
+ BIT(2), 0);
+ clk_register_clkdev(clk, NULL, "hash0");
+
+ clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base,
+ BIT(3), 0);
+ clk_register_clkdev(clk, NULL, "pka");
+
+ clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base,
+ BIT(4), 0);
+ clk_register_clkdev(clk, NULL, "db8540-hash1");
+
+ clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base,
+ BIT(5), 0);
+ clk_register_clkdev(clk, NULL, "cfgreg");
+
+ clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base,
+ BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "mtu0");
+
+ clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base,
+ BIT(7), 0);
+ clk_register_clkdev(clk, "apb_pclk", "mtu1");
+
+ /*
+ * PRCC K-clocks ==> see table PRCC_PCKEN/PRCC_KCKEN
+ * This differs from the internal implementation:
+ * We don't use the PERPIH[n| clock as parent, since those _should_
+ * only be used as parents for the P-clocks.
+ * TODO: "parentjoin" with corresponding P-clocks for all K-clocks.
+ */
+
+ /* Peripheral 1 : PRCC K-clocks */
+ clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
+ clkrst1_base, BIT(0), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart0");
+
+ clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
+ clkrst1_base, BIT(1), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart1");
+
+ clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
+ clkrst1_base, BIT(2), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.1");
+
+ clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
+ clkrst1_base, BIT(3), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp0");
+ clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.0");
+
+ clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
+ clkrst1_base, BIT(4), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp1");
+ clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.1");
+
+ clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmchclk",
+ clkrst1_base, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi0");
+
+ clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
+ clkrst1_base, BIT(6), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.2");
+
+ clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
+ clkrst1_base, BIT(8), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "slimbus0");
+
+ clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
+ clkrst1_base, BIT(9), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.4");
+
+ clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
+ clkrst1_base, BIT(10), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp3");
+ clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.3");
+
+ /* Peripheral 2 : PRCC K-clocks */
+ clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
+ clkrst2_base, BIT(0), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.3");
+
+ clk = clk_reg_prcc_kclk("p2_pwl_kclk", "rtc32k",
+ clkrst2_base, BIT(1), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "pwl");
+
+ clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmchclk",
+ clkrst2_base, BIT(2), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi4");
+
+ clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
+ clkrst2_base, BIT(3), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp2");
+ clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.2");
+
+ clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmchclk",
+ clkrst2_base, BIT(4), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi1");
+
+ clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
+ clkrst2_base, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi3");
+
+ clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
+ clkrst2_base, BIT(6),
+ CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+ clk_register_clkdev(clk, "hsir_hsirxclk", "ste_hsi.0");
+
+ clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
+ clkrst2_base, BIT(7),
+ CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
+ clk_register_clkdev(clk, "hsit_hsitxclk", "ste_hsi.0");
+
+ /* Should only be 9540, but might be added for 85xx as well */
+ clk = clk_reg_prcc_kclk("p2_msp4_kclk", "msp02clk",
+ clkrst2_base, BIT(9), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp4");
+ clk_register_clkdev(clk, "msp4", "ab85xx-codec.0");
+
+ /* Peripheral 3 : PRCC K-clocks */
+ clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
+ clkrst3_base, BIT(1), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ssp0");
+
+ clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
+ clkrst3_base, BIT(2), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ssp1");
+
+ clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
+ clkrst3_base, BIT(3), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.0");
+
+ clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmchclk",
+ clkrst3_base, BIT(4), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi2");
+
+ clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
+ clkrst3_base, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ske");
+ clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
+
+ clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
+ clkrst3_base, BIT(6), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart2");
+
+ clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
+ clkrst3_base, BIT(7), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "sdi5");
+
+ clk = clk_reg_prcc_kclk("p3_i2c5_kclk", "i2cclk",
+ clkrst3_base, BIT(8), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.5");
+
+ clk = clk_reg_prcc_kclk("p3_i2c6_kclk", "i2cclk",
+ clkrst3_base, BIT(9), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.6");
+
+ clk = clk_reg_prcc_kclk("p3_uart3_kclk", "uartclk",
+ clkrst3_base, BIT(10), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart3");
+
+ clk = clk_reg_prcc_kclk("p3_uart4_kclk", "uartclk",
+ clkrst3_base, BIT(11), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "uart4");
+
+ /* Peripheral 6 : PRCC K-clocks */
+ clk = clk_reg_prcc_kclk("p6_rng_kclk", "rngclk",
+ clkrst6_base, BIT(0), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "rng");
}
diff --git a/drivers/clk/ux500/u9540_clk.c b/drivers/clk/ux500/u9540_clk.c
index dbc0191e16c8..44794782e7e0 100644
--- a/drivers/clk/ux500/u9540_clk.c
+++ b/drivers/clk/ux500/u9540_clk.c
@@ -12,10 +12,10 @@
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
-
#include "clk.h"
-void u9540_clk_init(void)
+void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
+ u32 clkrst5_base, u32 clkrst6_base)
{
/* register clocks here */
}
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index 256c8be74df8..2dc8b41a339d 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -107,7 +107,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)
osc->func = vexpress_config_func_get_by_node(node);
if (!osc->func) {
pr_err("Failed to obtain config func for node '%s'!\n",
- node->name);
+ node->full_name);
goto error;
}
@@ -119,7 +119,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &init.name);
if (!init.name)
- init.name = node->name;
+ init.name = node->full_name;
init.ops = &vexpress_osc_ops;
init.flags = CLK_IS_ROOT;
diff --git a/drivers/clk/x86/clk-lpt.c b/drivers/clk/x86/clk-lpt.c
index 4f45eee9e33b..812f83f8b0c6 100644
--- a/drivers/clk/x86/clk-lpt.c
+++ b/drivers/clk/x86/clk-lpt.c
@@ -1,5 +1,5 @@
/*
- * Intel Lynxpoint LPSS clocks.
+ * Intel Low Power Subsystem clocks.
*
* Copyright (C) 2013, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
@@ -18,8 +18,6 @@
#include <linux/platform_data/clk-lpss.h>
#include <linux/platform_device.h>
-#define PRV_CLOCK_PARAMS 0x800
-
static int lpt_clk_probe(struct platform_device *pdev)
{
struct lpss_clk_data *drvdata;
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 5871933c4e51..81465c21f873 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -87,3 +87,8 @@ config CLKSRC_SAMSUNG_PWM
Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver
for all devicetree enabled platforms. This driver will be
needed only on systems that do not have the Exynos MCT available.
+
+config VF_PIT_TIMER
+ bool
+ help
+ Support for Period Interrupt Timer on Freescale Vybrid Family SoCs.
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d979c72aa94..9ba8b4d867e3 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -22,10 +22,13 @@ obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
+obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
obj-$(CONFIG_ARCH_BCM) += bcm_kona_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o
obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o
+obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
+obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index a2b254189782..053d846ab5b1 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -186,27 +186,19 @@ u32 arch_timer_get_rate(void)
return arch_timer_rate;
}
-/*
- * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to
- * call it before it has been initialised. Rather than incur a performance
- * penalty checking for initialisation, provide a default implementation that
- * won't lead to time appearing to jump backwards.
- */
-static u64 arch_timer_read_zero(void)
+u64 arch_timer_read_counter(void)
{
- return 0;
+ return arch_counter_get_cntvct();
}
-u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero;
-
static cycle_t arch_counter_read(struct clocksource *cs)
{
- return arch_timer_read_counter();
+ return arch_counter_get_cntvct();
}
static cycle_t arch_counter_read_cc(const struct cyclecounter *cc)
{
- return arch_timer_read_counter();
+ return arch_counter_get_cntvct();
}
static struct clocksource clocksource_counter = {
@@ -287,7 +279,7 @@ static int __init arch_timer_register(void)
cyclecounter.mult = clocksource_counter.mult;
cyclecounter.shift = clocksource_counter.shift;
timecounter_init(&timecounter, &cyclecounter,
- arch_counter_get_cntpct());
+ arch_counter_get_cntvct());
if (arch_timer_use_virtual) {
ppi = arch_timer_ppi[VIRT_PPI];
@@ -376,11 +368,6 @@ static void __init arch_timer_init(struct device_node *np)
}
}
- if (arch_timer_use_virtual)
- arch_timer_read_counter = arch_counter_get_cntvct;
- else
- arch_timer_read_counter = arch_counter_get_cntpct;
-
arch_timer_register();
arch_timer_arch_init();
}
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c
index 766611d29945..07ea7ce900dc 100644
--- a/drivers/clocksource/bcm2835_timer.c
+++ b/drivers/clocksource/bcm2835_timer.c
@@ -28,8 +28,8 @@
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <asm/irq.h>
#define REG_CONTROL 0x00
diff --git a/drivers/clocksource/clksrc-dbx500-prcmu.c b/drivers/clocksource/clksrc-dbx500-prcmu.c
index 77398f8c19a0..a9fd4ad25674 100644
--- a/drivers/clocksource/clksrc-dbx500-prcmu.c
+++ b/drivers/clocksource/clksrc-dbx500-prcmu.c
@@ -14,8 +14,7 @@
*/
#include <linux/clockchips.h>
#include <linux/clksrc-dbx500-prcmu.h>
-
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
#define RATE_32K 32768
diff --git a/drivers/clocksource/dummy_timer.c b/drivers/clocksource/dummy_timer.c
new file mode 100644
index 000000000000..1f55f9620338
--- /dev/null
+++ b/drivers/clocksource/dummy_timer.c
@@ -0,0 +1,69 @@
+/*
+ * linux/drivers/clocksource/dummy_timer.c
+ *
+ * Copyright (C) 2013 ARM Ltd.
+ * 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/clockchips.h>
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/cpumask.h>
+
+static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt);
+
+static void dummy_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /*
+ * Core clockevents code will call this when exchanging timer devices.
+ * We don't need to do anything here.
+ */
+}
+
+static void __cpuinit dummy_timer_setup(void)
+{
+ int cpu = smp_processor_id();
+ struct clock_event_device *evt = __this_cpu_ptr(&dummy_timer_evt);
+
+ evt->name = "dummy_timer";
+ evt->features = CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_ONESHOT |
+ CLOCK_EVT_FEAT_DUMMY;
+ evt->rating = 100;
+ evt->set_mode = dummy_timer_set_mode;
+ evt->cpumask = cpumask_of(cpu);
+
+ clockevents_register_device(evt);
+}
+
+static int __cpuinit dummy_timer_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
+ dummy_timer_setup();
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block dummy_timer_cpu_nb __cpuinitdata = {
+ .notifier_call = dummy_timer_cpu_notify,
+};
+
+static int __init dummy_timer_register(void)
+{
+ int err = register_cpu_notifier(&dummy_timer_cpu_nb);
+ if (err)
+ return err;
+
+ /* We won't get a call on the boot CPU, so register immediately */
+ if (num_possible_cpus() > 1)
+ dummy_timer_setup();
+
+ return 0;
+}
+early_initcall(dummy_timer_register);
diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c
index 8c2a35f26d9b..e54ca1062d8e 100644
--- a/drivers/clocksource/dw_apb_timer.c
+++ b/drivers/clocksource/dw_apb_timer.c
@@ -387,15 +387,3 @@ cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs)
{
return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
}
-
-/**
- * dw_apb_clocksource_unregister() - unregister and free a clocksource.
- *
- * @dw_cs: The clocksource to unregister/free.
- */
-void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs)
-{
- clocksource_unregister(&dw_cs->cs);
-
- kfree(dw_cs);
-}
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index cef554432a33..4cbae4f762b1 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -21,9 +21,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
-
-#include <asm/mach/time.h>
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
static void timer_get_base_and_rate(struct device_node *np,
void __iomem **base, u32 *rate)
@@ -68,7 +66,7 @@ static void add_clockevent(struct device_node *event_timer)
u32 irq, rate;
irq = irq_of_parse_and_map(event_timer, 0);
- if (irq == NO_IRQ)
+ if (irq == 0)
panic("No IRQ for clock event timer");
timer_get_base_and_rate(event_timer, &iobase, &rate);
diff --git a/drivers/clocksource/metag_generic.c b/drivers/clocksource/metag_generic.c
index ade7513a11d1..6722f0e2fe40 100644
--- a/drivers/clocksource/metag_generic.c
+++ b/drivers/clocksource/metag_generic.c
@@ -184,6 +184,8 @@ int __init metag_generic_timer_init(void)
#ifdef CONFIG_METAG_META21
hwtimer_freq = get_coreclock() / (metag_in32(EXPAND_TIMER_DIV) + 1);
#endif
+ pr_info("Timer frequency: %u Hz\n", hwtimer_freq);
+
clocksource_register_hz(&clocksource_metag, hwtimer_freq);
setup_irq(tbisig_map(TBID_SIGNUM_TRT), &metag_timer_irq);
diff --git a/drivers/clocksource/mxs_timer.c b/drivers/clocksource/mxs_timer.c
index 02af4204af86..0f5e65f74dc3 100644
--- a/drivers/clocksource/mxs_timer.c
+++ b/drivers/clocksource/mxs_timer.c
@@ -29,9 +29,9 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/stmp_device.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
-#include <asm/sched_clock.h>
/*
* There are 2 versions of the timrot on Freescale MXS-based SoCs.
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c
index b9415b622f55..7d2c2c56f73c 100644
--- a/drivers/clocksource/nomadik-mtu.c
+++ b/drivers/clocksource/nomadik-mtu.c
@@ -21,8 +21,8 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/platform_data/clocksource-nomadik-mtu.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
-#include <asm/sched_clock.h>
/*
* The MTU device hosts four different counters, with 4 set of
diff --git a/drivers/clocksource/samsung_pwm_timer.c b/drivers/clocksource/samsung_pwm_timer.c
index 0234c8d2c8f2..584b5472eea3 100644
--- a/drivers/clocksource/samsung_pwm_timer.c
+++ b/drivers/clocksource/samsung_pwm_timer.c
@@ -21,10 +21,10 @@
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/sched_clock.h>
#include <clocksource/samsung_pwm.h>
-#include <asm/sched_clock.h>
/*
* Clocksource driver
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c
index ae877b021b54..93961703b887 100644
--- a/drivers/clocksource/tegra20_timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -26,10 +26,10 @@
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
#include <asm/smp_twd.h>
-#include <asm/sched_clock.h>
#define RTC_SECONDS 0x08
#define RTC_SHADOW_SECONDS 0x0c
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 47a673070d70..efdca3263afe 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -27,8 +27,8 @@
#include <linux/of_address.h>
#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/sched_clock.h>
-#include <asm/sched_clock.h>
#include <asm/localtimer.h>
#include <linux/percpu.h>
/*
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c
index 97738dbf3e3b..e5dc9129ca26 100644
--- a/drivers/clocksource/timer-marco.c
+++ b/drivers/clocksource/timer-marco.c
@@ -17,7 +17,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
#include <asm/localtimer.h>
#include <asm/mach/time.h>
diff --git a/drivers/clocksource/timer-prima2.c b/drivers/clocksource/timer-prima2.c
index 760882665d7a..ef3cfb269d8b 100644
--- a/drivers/clocksource/timer-prima2.c
+++ b/drivers/clocksource/timer-prima2.c
@@ -18,7 +18,7 @@
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
-#include <asm/sched_clock.h>
+#include <linux/sched_clock.h>
#include <asm/mach/time.h>
#define SIRFSOC_TIMER_COUNTER_LO 0x0000
diff --git a/drivers/clocksource/vf_pit_timer.c b/drivers/clocksource/vf_pit_timer.c
new file mode 100644
index 000000000000..587e0202a70b
--- /dev/null
+++ b/drivers/clocksource/vf_pit_timer.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sched_clock.h>
+
+/*
+ * Each pit takes 0x10 Bytes register space
+ */
+#define PITMCR 0x00
+#define PIT0_OFFSET 0x100
+#define PITn_OFFSET(n) (PIT0_OFFSET + 0x10 * (n))
+#define PITLDVAL 0x00
+#define PITCVAL 0x04
+#define PITTCTRL 0x08
+#define PITTFLG 0x0c
+
+#define PITMCR_MDIS (0x1 << 1)
+
+#define PITTCTRL_TEN (0x1 << 0)
+#define PITTCTRL_TIE (0x1 << 1)
+#define PITCTRL_CHN (0x1 << 2)
+
+#define PITTFLG_TIF 0x1
+
+static void __iomem *clksrc_base;
+static void __iomem *clkevt_base;
+static unsigned long cycle_per_jiffy;
+
+static inline void pit_timer_enable(void)
+{
+ __raw_writel(PITTCTRL_TEN | PITTCTRL_TIE, clkevt_base + PITTCTRL);
+}
+
+static inline void pit_timer_disable(void)
+{
+ __raw_writel(0, clkevt_base + PITTCTRL);
+}
+
+static inline void pit_irq_acknowledge(void)
+{
+ __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG);
+}
+
+static unsigned int pit_read_sched_clock(void)
+{
+ return __raw_readl(clksrc_base + PITCVAL);
+}
+
+static int __init pit_clocksource_init(unsigned long rate)
+{
+ /* set the max load value and start the clock source counter */
+ __raw_writel(0, clksrc_base + PITTCTRL);
+ __raw_writel(~0UL, clksrc_base + PITLDVAL);
+ __raw_writel(PITTCTRL_TEN, clksrc_base + PITTCTRL);
+
+ setup_sched_clock(pit_read_sched_clock, 32, rate);
+ return clocksource_mmio_init(clksrc_base + PITCVAL, "vf-pit", rate,
+ 300, 32, clocksource_mmio_readl_down);
+}
+
+static int pit_set_next_event(unsigned long delta,
+ struct clock_event_device *unused)
+{
+ /*
+ * set a new value to PITLDVAL register will not restart the timer,
+ * to abort the current cycle and start a timer period with the new
+ * value, the timer must be disabled and enabled again.
+ * and the PITLAVAL should be set to delta minus one according to pit
+ * hardware requirement.
+ */
+ pit_timer_disable();
+ __raw_writel(delta - 1, clkevt_base + PITLDVAL);
+ pit_timer_enable();
+
+ return 0;
+}
+
+static void pit_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ pit_set_next_event(cycle_per_jiffy, evt);
+ break;
+ default:
+ break;
+ }
+}
+
+static irqreturn_t pit_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ pit_irq_acknowledge();
+
+ /*
+ * pit hardware doesn't support oneshot, it will generate an interrupt
+ * and reload the counter value from PITLDVAL when PITCVAL reach zero,
+ * and start the counter again. So software need to disable the timer
+ * to stop the counter loop in ONESHOT mode.
+ */
+ if (likely(evt->mode == CLOCK_EVT_MODE_ONESHOT))
+ pit_timer_disable();
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct clock_event_device clockevent_pit = {
+ .name = "VF pit timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = pit_set_mode,
+ .set_next_event = pit_set_next_event,
+ .rating = 300,
+};
+
+static struct irqaction pit_timer_irq = {
+ .name = "VF pit timer",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = pit_timer_interrupt,
+ .dev_id = &clockevent_pit,
+};
+
+static int __init pit_clockevent_init(unsigned long rate, int irq)
+{
+ __raw_writel(0, clkevt_base + PITTCTRL);
+ __raw_writel(PITTFLG_TIF, clkevt_base + PITTFLG);
+
+ BUG_ON(setup_irq(irq, &pit_timer_irq));
+
+ clockevent_pit.cpumask = cpumask_of(0);
+ clockevent_pit.irq = irq;
+ /*
+ * The value for the LDVAL register trigger is calculated as:
+ * LDVAL trigger = (period / clock period) - 1
+ * The pit is a 32-bit down count timer, when the conter value
+ * reaches 0, it will generate an interrupt, thus the minimal
+ * LDVAL trigger value is 1. And then the min_delta is
+ * minimal LDVAL trigger value + 1, and the max_delta is full 32-bit.
+ */
+ clockevents_config_and_register(&clockevent_pit, rate, 2, 0xffffffff);
+
+ return 0;
+}
+
+static void __init pit_timer_init(struct device_node *np)
+{
+ struct clk *pit_clk;
+ void __iomem *timer_base;
+ unsigned long clk_rate;
+ int irq;
+
+ timer_base = of_iomap(np, 0);
+ BUG_ON(!timer_base);
+
+ /*
+ * PIT0 and PIT1 can be chained to build a 64-bit timer,
+ * so choose PIT2 as clocksource, PIT3 as clockevent device,
+ * and leave PIT0 and PIT1 unused for anyone else who needs them.
+ */
+ clksrc_base = timer_base + PITn_OFFSET(2);
+ clkevt_base = timer_base + PITn_OFFSET(3);
+
+ irq = irq_of_parse_and_map(np, 0);
+ BUG_ON(irq <= 0);
+
+ pit_clk = of_clk_get(np, 0);
+ BUG_ON(IS_ERR(pit_clk));
+
+ BUG_ON(clk_prepare_enable(pit_clk));
+
+ clk_rate = clk_get_rate(pit_clk);
+ cycle_per_jiffy = clk_rate / (HZ);
+
+ /* enable the pit module */
+ __raw_writel(~PITMCR_MDIS, timer_base + PITMCR);
+
+ BUG_ON(pit_clocksource_init(clk_rate));
+
+ pit_clockevent_init(clk_rate, irq);
+}
+CLOCKSOURCE_OF_DECLARE(vf610, "fsl,vf610-pit", pit_timer_init);
diff --git a/drivers/clocksource/zevio-timer.c b/drivers/clocksource/zevio-timer.c
new file mode 100644
index 000000000000..ca81809d159d
--- /dev/null
+++ b/drivers/clocksource/zevio-timer.c
@@ -0,0 +1,215 @@
+/*
+ * linux/drivers/clocksource/zevio-timer.c
+ *
+ * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#define IO_CURRENT_VAL 0x00
+#define IO_DIVIDER 0x04
+#define IO_CONTROL 0x08
+
+#define IO_TIMER1 0x00
+#define IO_TIMER2 0x0C
+
+#define IO_MATCH_BEGIN 0x18
+#define IO_MATCH(x) (IO_MATCH_BEGIN + ((x) << 2))
+
+#define IO_INTR_STS 0x00
+#define IO_INTR_ACK 0x00
+#define IO_INTR_MSK 0x04
+
+#define CNTL_STOP_TIMER (1 << 4)
+#define CNTL_RUN_TIMER (0 << 4)
+
+#define CNTL_INC (1 << 3)
+#define CNTL_DEC (0 << 3)
+
+#define CNTL_TOZERO 0
+#define CNTL_MATCH(x) ((x) + 1)
+#define CNTL_FOREVER 7
+
+/* There are 6 match registers but we only use one. */
+#define TIMER_MATCH 0
+
+#define TIMER_INTR_MSK (1 << (TIMER_MATCH))
+#define TIMER_INTR_ALL 0x3F
+
+struct zevio_timer {
+ void __iomem *base;
+ void __iomem *timer1, *timer2;
+ void __iomem *interrupt_regs;
+
+ struct clk *clk;
+ struct clock_event_device clkevt;
+ struct irqaction clkevt_irq;
+
+ char clocksource_name[64];
+ char clockevent_name[64];
+};
+
+static int zevio_timer_set_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ struct zevio_timer *timer = container_of(dev, struct zevio_timer,
+ clkevt);
+
+ writel(delta, timer->timer1 + IO_CURRENT_VAL);
+ writel(CNTL_RUN_TIMER | CNTL_DEC | CNTL_MATCH(TIMER_MATCH),
+ timer->timer1 + IO_CONTROL);
+
+ return 0;
+}
+
+static void zevio_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ struct zevio_timer *timer = container_of(dev, struct zevio_timer,
+ clkevt);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_RESUME:
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* Enable timer interrupts */
+ writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_MSK);
+ writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ /* Disable timer interrupts */
+ writel(0, timer->interrupt_regs + IO_INTR_MSK);
+ writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
+ /* Stop timer */
+ writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL);
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ default:
+ /* Unsupported */
+ break;
+ }
+}
+
+static irqreturn_t zevio_timer_interrupt(int irq, void *dev_id)
+{
+ struct zevio_timer *timer = dev_id;
+ u32 intr;
+
+ intr = readl(timer->interrupt_regs + IO_INTR_ACK);
+ if (!(intr & TIMER_INTR_MSK))
+ return IRQ_NONE;
+
+ writel(TIMER_INTR_MSK, timer->interrupt_regs + IO_INTR_ACK);
+ writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL);
+
+ if (timer->clkevt.event_handler)
+ timer->clkevt.event_handler(&timer->clkevt);
+
+ return IRQ_HANDLED;
+}
+
+static int __init zevio_timer_add(struct device_node *node)
+{
+ struct zevio_timer *timer;
+ struct resource res;
+ int irqnr, ret;
+
+ timer = kzalloc(sizeof(*timer), GFP_KERNEL);
+ if (!timer)
+ return -ENOMEM;
+
+ timer->base = of_iomap(node, 0);
+ if (!timer->base) {
+ ret = -EINVAL;
+ goto error_free;
+ }
+ timer->timer1 = timer->base + IO_TIMER1;
+ timer->timer2 = timer->base + IO_TIMER2;
+
+ timer->clk = of_clk_get(node, 0);
+ if (IS_ERR(timer->clk)) {
+ ret = PTR_ERR(timer->clk);
+ pr_err("Timer clock not found! (error %d)\n", ret);
+ goto error_unmap;
+ }
+
+ timer->interrupt_regs = of_iomap(node, 1);
+ irqnr = irq_of_parse_and_map(node, 0);
+
+ of_address_to_resource(node, 0, &res);
+ scnprintf(timer->clocksource_name, sizeof(timer->clocksource_name),
+ "%llx.%s_clocksource",
+ (unsigned long long)res.start, node->name);
+
+ scnprintf(timer->clockevent_name, sizeof(timer->clockevent_name),
+ "%llx.%s_clockevent",
+ (unsigned long long)res.start, node->name);
+
+ if (timer->interrupt_regs && irqnr) {
+ timer->clkevt.name = timer->clockevent_name;
+ timer->clkevt.set_next_event = zevio_timer_set_event;
+ timer->clkevt.set_mode = zevio_timer_set_mode;
+ timer->clkevt.rating = 200;
+ timer->clkevt.cpumask = cpu_all_mask;
+ timer->clkevt.features = CLOCK_EVT_FEAT_ONESHOT;
+ timer->clkevt.irq = irqnr;
+
+ writel(CNTL_STOP_TIMER, timer->timer1 + IO_CONTROL);
+ writel(0, timer->timer1 + IO_DIVIDER);
+
+ /* Start with timer interrupts disabled */
+ writel(0, timer->interrupt_regs + IO_INTR_MSK);
+ writel(TIMER_INTR_ALL, timer->interrupt_regs + IO_INTR_ACK);
+
+ /* Interrupt to occur when timer value matches 0 */
+ writel(0, timer->base + IO_MATCH(TIMER_MATCH));
+
+ timer->clkevt_irq.name = timer->clockevent_name;
+ timer->clkevt_irq.handler = zevio_timer_interrupt;
+ timer->clkevt_irq.dev_id = timer;
+ timer->clkevt_irq.flags = IRQF_TIMER | IRQF_IRQPOLL;
+
+ setup_irq(irqnr, &timer->clkevt_irq);
+
+ clockevents_config_and_register(&timer->clkevt,
+ clk_get_rate(timer->clk), 0x0001, 0xffff);
+ pr_info("Added %s as clockevent\n", timer->clockevent_name);
+ }
+
+ writel(CNTL_STOP_TIMER, timer->timer2 + IO_CONTROL);
+ writel(0, timer->timer2 + IO_CURRENT_VAL);
+ writel(0, timer->timer2 + IO_DIVIDER);
+ writel(CNTL_RUN_TIMER | CNTL_FOREVER | CNTL_INC,
+ timer->timer2 + IO_CONTROL);
+
+ clocksource_mmio_init(timer->timer2 + IO_CURRENT_VAL,
+ timer->clocksource_name,
+ clk_get_rate(timer->clk),
+ 200, 16,
+ clocksource_mmio_readw_up);
+
+ pr_info("Added %s as clocksource\n", timer->clocksource_name);
+
+ return 0;
+error_unmap:
+ iounmap(timer->base);
+error_free:
+ kfree(timer);
+ return ret;
+}
+
+CLOCKSOURCE_OF_DECLARE(zevio_timer, "lsi,zevio-timer", zevio_timer_add);
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index a92440896868..de4d5d93c3fd 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -5,6 +5,7 @@
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
depends on ARM_CPU_TOPOLOGY && PM_OPP && HAVE_CLK
+ select CPU_FREQ_TABLE
help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
@@ -18,6 +19,7 @@ config ARM_DT_BL_CPUFREQ
config ARM_EXYNOS_CPUFREQ
bool "SAMSUNG EXYNOS SoCs"
depends on ARCH_EXYNOS
+ select CPU_FREQ_TABLE
default y
help
This adds the CPUFreq driver common part for Samsung
@@ -46,6 +48,7 @@ config ARM_EXYNOS5250_CPUFREQ
config ARM_EXYNOS5440_CPUFREQ
def_bool SOC_EXYNOS5440
depends on HAVE_CLK && PM_OPP && OF
+ select CPU_FREQ_TABLE
help
This adds the CPUFreq driver for Samsung EXYNOS5440
SoC. The nature of exynos5440 clock controller is
@@ -55,7 +58,6 @@ config ARM_EXYNOS5440_CPUFREQ
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK
- select CPU_FREQ_TABLE
select GENERIC_CPUFREQ_CPU0
select PM_OPP
select REGULATOR
@@ -71,6 +73,7 @@ config ARM_IMX6Q_CPUFREQ
tristate "Freescale i.MX6Q cpufreq support"
depends on SOC_IMX6Q
depends on REGULATOR_ANATOP
+ select CPU_FREQ_TABLE
help
This adds cpufreq driver support for Freescale i.MX6Q SOC.
@@ -86,6 +89,7 @@ config ARM_INTEGRATOR
config ARM_KIRKWOOD_CPUFREQ
def_bool ARCH_KIRKWOOD && OF
+ select CPU_FREQ_TABLE
help
This adds the CPUFreq driver for Marvell Kirkwood
SoCs.
@@ -149,6 +153,7 @@ config ARM_S3C2412_CPUFREQ
config ARM_S3C2416_CPUFREQ
bool "S3C2416 CPU Frequency scaling support"
depends on CPU_S3C2416
+ select CPU_FREQ_TABLE
help
This adds the CPUFreq driver for the Samsung S3C2416 and
S3C2450 SoC. The S3C2416 supports changing the rate of the
@@ -179,6 +184,7 @@ config ARM_S3C2440_CPUFREQ
config ARM_S3C64XX_CPUFREQ
bool "Samsung S3C64XX"
depends on CPU_S3C6410
+ select CPU_FREQ_TABLE
default y
help
This adds the CPUFreq driver for Samsung S3C6410 SoC.
@@ -205,6 +211,15 @@ config ARM_SA1110_CPUFREQ
config ARM_SPEAR_CPUFREQ
bool "SPEAr CPUFreq support"
depends on PLAT_SPEAR
+ select CPU_FREQ_TABLE
default y
help
This adds the CPUFreq driver support for SPEAr SOCs.
+
+config ARM_TEGRA_CPUFREQ
+ bool "TEGRA CPUFreq support"
+ depends on ARCH_TEGRA
+ select CPU_FREQ_TABLE
+ default y
+ help
+ This adds the CPUFreq driver support for TEGRA SOCs.
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index 9c926ca0d718..25ca9db62e09 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -1,6 +1,7 @@
config CPU_FREQ_CBE
tristate "CBE frequency scaling"
depends on CBE_RAS && PPC_CELL
+ select CPU_FREQ_TABLE
default m
help
This adds the cpufreq driver for Cell BE processors.
@@ -23,3 +24,39 @@ config CPU_FREQ_MAPLE
help
This adds support for frequency switching on Maple 970FX
Evaluation Board and compatible boards (IBM JS2x blades).
+
+config PPC_CORENET_CPUFREQ
+ tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
+ depends on PPC_E500MC && OF && COMMON_CLK
+ select CPU_FREQ_TABLE
+ select CLK_PPC_CORENET
+ help
+ This adds the CPUFreq driver support for Freescale e500mc,
+ e5500 and e6500 series SoCs which are capable of changing
+ the CPU's frequency dynamically.
+
+config CPU_FREQ_PMAC
+ bool "Support for Apple PowerBooks"
+ depends on ADB_PMU && PPC32
+ select CPU_FREQ_TABLE
+ help
+ This adds support for frequency switching on Apple PowerBooks,
+ this currently includes some models of iBook & Titanium
+ PowerBook.
+
+config CPU_FREQ_PMAC64
+ bool "Support for some Apple G5s"
+ depends on PPC_PMAC && PPC64
+ select CPU_FREQ_TABLE
+ help
+ This adds support for frequency switching on Apple iMac G5,
+ and some of the more recent desktop G5 machines as well.
+
+config PPC_PASEMI_CPUFREQ
+ bool "Support for PA Semi PWRficient"
+ depends on PPC_PASEMI
+ select CPU_FREQ_TABLE
+ default y
+ help
+ This adds the support for frequency switching on PA Semi
+ PWRficient processors.
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 6bd63d63d356..e2b6eabef221 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -132,6 +132,7 @@ config X86_POWERNOW_K8
config X86_AMD_FREQ_SENSITIVITY
tristate "AMD frequency sensitivity feedback powersave bias"
depends on CPU_FREQ_GOV_ONDEMAND && X86_ACPI_CPUFREQ && CPU_SUP_AMD
+ select CPU_FREQ_TABLE
help
This adds AMD-specific powersave bias function to the ondemand
governor, which allows it to make more power-conscious frequency
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 6ad0b913ca17..d345b5a7aa71 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -76,7 +76,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
-obj-$(CONFIG_ARCH_TEGRA) += tegra-cpufreq.o
+obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
##################################################################################
# PowerPC platform drivers
@@ -84,11 +84,15 @@ obj-$(CONFIG_CPU_FREQ_CBE) += ppc-cbe-cpufreq.o
ppc-cbe-cpufreq-y += ppc_cbe_cpufreq_pervasive.o ppc_cbe_cpufreq.o
obj-$(CONFIG_CPU_FREQ_CBE_PMI) += ppc_cbe_cpufreq_pmi.o
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
+obj-$(CONFIG_PPC_CORENET_CPUFREQ) += ppc-corenet-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_PMAC) += pmac32-cpufreq.o
+obj-$(CONFIG_CPU_FREQ_PMAC64) += pmac64-cpufreq.o
+obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += pasemi-cpufreq.o
##################################################################################
# Other platform drivers
obj-$(CONFIG_AVR32_AT32AP_CPUFREQ) += at32ap-cpufreq.o
-obj-$(CONFIG_BLACKFIN) += blackfin-cpufreq.o
+obj-$(CONFIG_BFIN_CPU_FREQ) += blackfin-cpufreq.o
obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o
obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o
obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index edc089e9d0c4..39264020b88a 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -70,6 +70,7 @@ struct acpi_cpufreq_data {
struct cpufreq_frequency_table *freq_table;
unsigned int resume;
unsigned int cpu_feature;
+ cpumask_var_t freqdomain_cpus;
};
static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data);
@@ -176,6 +177,15 @@ static struct global_attr global_boost = __ATTR(boost, 0644,
show_global_boost,
store_global_boost);
+static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf)
+{
+ struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
+
+ return cpufreq_show_cpus(data->freqdomain_cpus, buf);
+}
+
+cpufreq_freq_attr_ro(freqdomain_cpus);
+
#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB
static ssize_t store_cpb(struct cpufreq_policy *policy, const char *buf,
size_t count)
@@ -232,7 +242,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
perf = data->acpi_data;
for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
- if (msr == perf->states[data->freq_table[i].index].status)
+ if (msr == perf->states[data->freq_table[i].driver_data].status)
return data->freq_table[i].frequency;
}
return data->freq_table[0].frequency;
@@ -442,7 +452,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
goto out;
}
- next_perf_state = data->freq_table[next_state].index;
+ next_perf_state = data->freq_table[next_state].driver_data;
if (perf->state == next_perf_state) {
if (unlikely(data->resume)) {
pr_debug("Called after resume, resetting to P%d\n",
@@ -494,12 +504,14 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
pr_debug("acpi_cpufreq_target failed (%d)\n",
policy->cpu);
result = -EAGAIN;
- goto out;
+ freqs.new = freqs.old;
}
}
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- perf->state = next_perf_state;
+
+ if (!result)
+ perf->state = next_perf_state;
out:
return result;
@@ -702,6 +714,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (!data)
return -ENOMEM;
+ if (!zalloc_cpumask_var(&data->freqdomain_cpus, GFP_KERNEL)) {
+ result = -ENOMEM;
+ goto err_free;
+ }
+
data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu);
per_cpu(acfreq_data, cpu) = data;
@@ -710,7 +727,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
result = acpi_processor_register_performance(data->acpi_data, cpu);
if (result)
- goto err_free;
+ goto err_free_mask;
perf = data->acpi_data;
policy->shared_type = perf->shared_type;
@@ -723,6 +740,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
cpumask_copy(policy->cpus, perf->shared_cpu_map);
}
+ cpumask_copy(data->freqdomain_cpus, perf->shared_cpu_map);
#ifdef CONFIG_SMP
dmi_check_system(sw_any_bug_dmi_table);
@@ -734,6 +752,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
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));
policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
pr_info_once(PFX "overriding BIOS provided _PSD data\n");
}
@@ -811,7 +830,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
data->freq_table[valid_states-1].frequency / 1000)
continue;
- data->freq_table[valid_states].index = i;
+ data->freq_table[valid_states].driver_data = i;
data->freq_table[valid_states].frequency =
perf->states[i].core_frequency * 1000;
valid_states++;
@@ -868,6 +887,8 @@ err_freqfree:
kfree(data->freq_table);
err_unreg:
acpi_processor_unregister_performance(perf, cpu);
+err_free_mask:
+ free_cpumask_var(data->freqdomain_cpus);
err_free:
kfree(data);
per_cpu(acfreq_data, cpu) = NULL;
@@ -886,6 +907,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
per_cpu(acfreq_data, policy->cpu) = NULL;
acpi_processor_unregister_performance(data->acpi_data,
policy->cpu);
+ free_cpumask_var(data->freqdomain_cpus);
kfree(data->freq_table);
kfree(data);
}
@@ -906,6 +928,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
static struct freq_attr *acpi_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
+ &freqdomain_cpus,
NULL, /* this is a placeholder for cpb, do not remove */
NULL,
};
@@ -947,7 +970,7 @@ static void __init acpi_cpufreq_boost_init(void)
/* We create the boost file in any case, though for systems without
* hardware support it will be read-only and hardwired to return 0.
*/
- if (sysfs_create_file(cpufreq_global_kobject, &(global_boost.attr)))
+ if (cpufreq_sysfs_create_file(&(global_boost.attr)))
pr_warn(PFX "could not register global boost sysfs file\n");
else
pr_debug("registered global boost sysfs file\n");
@@ -955,7 +978,7 @@ static void __init acpi_cpufreq_boost_init(void)
static void __exit acpi_cpufreq_boost_exit(void)
{
- sysfs_remove_file(cpufreq_global_kobject, &(global_boost.attr));
+ cpufreq_sysfs_remove_file(&(global_boost.attr));
if (msrs) {
unregister_cpu_notifier(&boost_nb);
@@ -1034,4 +1057,11 @@ static const struct x86_cpu_id acpi_cpufreq_ids[] = {
};
MODULE_DEVICE_TABLE(x86cpu, acpi_cpufreq_ids);
+static const struct acpi_device_id processor_device_ids[] = {
+ {ACPI_PROCESSOR_OBJECT_HID, },
+ {ACPI_PROCESSOR_DEVICE_HID, },
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, processor_device_ids);
+
MODULE_ALIAS("acpi");
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index 5d7f53fcd6f5..3549f0784af1 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -84,11 +84,9 @@ static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000);
if (ret) {
pr_err("clk_set_rate failed: %d\n", ret);
- return ret;
+ freqs.new = freqs.old;
}
- policy->cur = freqs.new;
-
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c
index 995511e80bef..9cdbbd278a80 100644
--- a/drivers/cpufreq/blackfin-cpufreq.c
+++ b/drivers/cpufreq/blackfin-cpufreq.c
@@ -20,23 +20,23 @@
/* this is the table of CCLK frequencies, in Hz */
-/* .index is the entry in the auxiliary dpm_state_table[] */
+/* .driver_data is the entry in the auxiliary dpm_state_table[] */
static struct cpufreq_frequency_table bfin_freq_table[] = {
{
.frequency = CPUFREQ_TABLE_END,
- .index = 0,
+ .driver_data = 0,
},
{
.frequency = CPUFREQ_TABLE_END,
- .index = 1,
+ .driver_data = 1,
},
{
.frequency = CPUFREQ_TABLE_END,
- .index = 2,
+ .driver_data = 2,
},
{
.frequency = CPUFREQ_TABLE_END,
- .index = 0,
+ .driver_data = 0,
},
};
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2d53f47d1747..0937b8d6c2a4 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2001 Russell King
* (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ * (C) 2013 Viresh Kumar <viresh.kumar@linaro.org>
*
* Oct 2005 - Ashok Raj <ashok.raj@intel.com>
* Added handling for CPU hotplug
@@ -12,12 +13,13 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <asm/cputime.h>
#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/notifier.h>
@@ -25,6 +27,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/tick.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/cpu.h>
@@ -41,11 +44,13 @@
*/
static struct cpufreq_driver *cpufreq_driver;
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
+static DEFINE_RWLOCK(cpufreq_driver_lock);
+static DEFINE_MUTEX(cpufreq_governor_lock);
+
#ifdef CONFIG_HOTPLUG_CPU
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
#endif
-static DEFINE_RWLOCK(cpufreq_driver_lock);
/*
* cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure
@@ -132,6 +137,51 @@ bool have_governor_per_policy(void)
{
return cpufreq_driver->have_governor_per_policy;
}
+EXPORT_SYMBOL_GPL(have_governor_per_policy);
+
+struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
+{
+ if (have_governor_per_policy())
+ return &policy->kobj;
+ else
+ return cpufreq_global_kobject;
+}
+EXPORT_SYMBOL_GPL(get_governor_parent_kobj);
+
+static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
+{
+ u64 idle_time;
+ u64 cur_wall_time;
+ u64 busy_time;
+
+ cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+ busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+ busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+ idle_time = cur_wall_time - busy_time;
+ if (wall)
+ *wall = cputime_to_usecs(cur_wall_time);
+
+ return cputime_to_usecs(idle_time);
+}
+
+u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
+{
+ u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
+
+ if (idle_time == -1ULL)
+ return get_cpu_idle_time_jiffy(cpu, wall);
+ else if (!io_busy)
+ idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+ return idle_time;
+}
+EXPORT_SYMBOL_GPL(get_cpu_idle_time);
static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
{
@@ -150,7 +200,6 @@ static struct cpufreq_policy *__cpufreq_cpu_get(unsigned int cpu, bool sysfs)
if (!try_module_get(cpufreq_driver->owner))
goto err_out_unlock;
-
/* get the CPU */
data = per_cpu(cpufreq_cpu_data, cpu);
@@ -220,7 +269,7 @@ static void cpufreq_cpu_put_sysfs(struct cpufreq_policy *data)
*/
#ifndef CONFIG_SMP
static unsigned long l_p_j_ref;
-static unsigned int l_p_j_ref_freq;
+static unsigned int l_p_j_ref_freq;
static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{
@@ -233,7 +282,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
pr_debug("saving %lu as reference value for loops_per_jiffy; "
"freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
}
- if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
+ if ((val == CPUFREQ_POSTCHANGE && ci->old != ci->new) ||
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
ci->new);
@@ -248,8 +297,7 @@ static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
}
#endif
-
-void __cpufreq_notify_transition(struct cpufreq_policy *policy,
+static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, unsigned int state)
{
BUG_ON(irqs_disabled());
@@ -264,6 +312,13 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
switch (state) {
case CPUFREQ_PRECHANGE:
+ if (WARN(policy->transition_ongoing ==
+ cpumask_weight(policy->cpus),
+ "In middle of another frequency transition\n"))
+ return;
+
+ policy->transition_ongoing++;
+
/* detect if the driver reported a value as "old frequency"
* which is not equal to what the cpufreq core thinks is
* "old frequency".
@@ -283,6 +338,12 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
break;
case CPUFREQ_POSTCHANGE:
+ if (WARN(!policy->transition_ongoing,
+ "No frequency transition in progress\n"))
+ return;
+
+ policy->transition_ongoing--;
+
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
(unsigned long)freqs->cpu);
@@ -294,6 +355,7 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy,
break;
}
}
+
/**
* cpufreq_notify_transition - call notifier chain and adjust_jiffies
* on frequency transition.
@@ -311,7 +373,6 @@ void cpufreq_notify_transition(struct cpufreq_policy *policy,
EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
-
/*********************************************************************
* SYSFS INTERFACE *
*********************************************************************/
@@ -376,7 +437,6 @@ out:
return err;
}
-
/**
* cpufreq_per_cpu_attr_read() / show_##file_name() -
* print out cpufreq information
@@ -441,7 +501,6 @@ static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
return sprintf(buf, "%u\n", cur_freq);
}
-
/**
* show_scaling_governor - show the current policy for the specified CPU
*/
@@ -457,7 +516,6 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
return -EINVAL;
}
-
/**
* store_scaling_governor - store policy for the specified CPU
*/
@@ -480,8 +538,10 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
&new_policy.governor))
return -EINVAL;
- /* Do not use cpufreq_set_policy here or the user_policy.max
- will be wrongly overridden */
+ /*
+ * Do not use cpufreq_set_policy here or the user_policy.max
+ * will be wrongly overridden
+ */
ret = __cpufreq_set_policy(policy, &new_policy);
policy->user_policy.policy = policy->policy;
@@ -526,7 +586,7 @@ out:
return i;
}
-static ssize_t show_cpus(const struct cpumask *mask, char *buf)
+ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf)
{
ssize_t i = 0;
unsigned int cpu;
@@ -541,6 +601,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
i += sprintf(&buf[i], "\n");
return i;
}
+EXPORT_SYMBOL_GPL(cpufreq_show_cpus);
/**
* show_related_cpus - show the CPUs affected by each transition even if
@@ -548,7 +609,7 @@ static ssize_t show_cpus(const struct cpumask *mask, char *buf)
*/
static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
{
- return show_cpus(policy->related_cpus, buf);
+ return cpufreq_show_cpus(policy->related_cpus, buf);
}
/**
@@ -556,7 +617,7 @@ static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
*/
static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
{
- return show_cpus(policy->cpus, buf);
+ return cpufreq_show_cpus(policy->cpus, buf);
}
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
@@ -630,9 +691,6 @@ static struct attribute *default_attrs[] = {
NULL
};
-struct kobject *cpufreq_global_kobject;
-EXPORT_SYMBOL(cpufreq_global_kobject);
-
#define to_policy(k) container_of(k, struct cpufreq_policy, kobj)
#define to_attr(a) container_of(a, struct freq_attr, attr)
@@ -703,6 +761,49 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release,
};
+struct kobject *cpufreq_global_kobject;
+EXPORT_SYMBOL(cpufreq_global_kobject);
+
+static int cpufreq_global_kobject_usage;
+
+int cpufreq_get_global_kobject(void)
+{
+ if (!cpufreq_global_kobject_usage++)
+ return kobject_add(cpufreq_global_kobject,
+ &cpu_subsys.dev_root->kobj, "%s", "cpufreq");
+
+ return 0;
+}
+EXPORT_SYMBOL(cpufreq_get_global_kobject);
+
+void cpufreq_put_global_kobject(void)
+{
+ if (!--cpufreq_global_kobject_usage)
+ kobject_del(cpufreq_global_kobject);
+}
+EXPORT_SYMBOL(cpufreq_put_global_kobject);
+
+int cpufreq_sysfs_create_file(const struct attribute *attr)
+{
+ int ret = cpufreq_get_global_kobject();
+
+ if (!ret) {
+ ret = sysfs_create_file(cpufreq_global_kobject, attr);
+ if (ret)
+ cpufreq_put_global_kobject();
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(cpufreq_sysfs_create_file);
+
+void cpufreq_sysfs_remove_file(const struct attribute *attr)
+{
+ sysfs_remove_file(cpufreq_global_kobject, attr);
+ cpufreq_put_global_kobject();
+}
+EXPORT_SYMBOL(cpufreq_sysfs_remove_file);
+
/* symlink affected CPUs */
static int cpufreq_add_dev_symlink(unsigned int cpu,
struct cpufreq_policy *policy)
@@ -1005,7 +1106,8 @@ static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
* Caller should already have policy_rwsem in write mode for this CPU.
* This routine frees the rwsem before returning.
*/
-static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
+static int __cpufreq_remove_dev(struct device *dev,
+ struct subsys_interface *sif)
{
unsigned int cpu = dev->id, ret, cpus;
unsigned long flags;
@@ -1112,7 +1214,6 @@ static int __cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif
return 0;
}
-
static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
{
unsigned int cpu = dev->id;
@@ -1125,7 +1226,6 @@ static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
return retval;
}
-
static void handle_update(struct work_struct *work)
{
struct cpufreq_policy *policy =
@@ -1136,7 +1236,8 @@ static void handle_update(struct work_struct *work)
}
/**
- * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're in deep trouble.
+ * cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
+ * in deep trouble.
* @cpu: cpu number
* @old_freq: CPU frequency the kernel thinks the CPU runs at
* @new_freq: CPU frequency the CPU actually runs at
@@ -1151,7 +1252,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
struct cpufreq_freqs freqs;
unsigned long flags;
-
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
@@ -1166,7 +1266,6 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
}
-
/**
* cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur
* @cpu: CPU number
@@ -1212,7 +1311,6 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_quick_get_max);
-
static unsigned int __cpufreq_get(unsigned int cpu)
{
struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
@@ -1271,7 +1369,6 @@ static struct subsys_interface cpufreq_interface = {
.remove_dev = cpufreq_remove_dev,
};
-
/**
* cpufreq_bp_suspend - Prepare the boot CPU for system suspend.
*
@@ -1408,11 +1505,10 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
}
EXPORT_SYMBOL(cpufreq_register_notifier);
-
/**
* cpufreq_unregister_notifier - unregister a driver with cpufreq
* @nb: notifier block to be unregistered
- * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
+ * @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
*
* Remove a driver from the CPU frequency notifier list.
*
@@ -1448,7 +1544,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS *
*********************************************************************/
-
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
@@ -1458,6 +1553,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
if (cpufreq_disabled())
return -ENODEV;
+ if (policy->transition_ongoing)
+ return -EBUSY;
/* Make sure that target_freq is within supported range */
if (target_freq > policy->max)
@@ -1484,10 +1581,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
{
int ret = -EINVAL;
- policy = cpufreq_cpu_get(policy->cpu);
- if (!policy)
- goto no_policy;
-
if (unlikely(lock_policy_rwsem_write(policy->cpu)))
goto fail;
@@ -1496,30 +1589,19 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
unlock_policy_rwsem_write(policy->cpu);
fail:
- cpufreq_cpu_put(policy);
-no_policy:
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu)
{
- int ret = 0;
-
if (cpufreq_disabled())
- return ret;
+ return 0;
if (!cpufreq_driver->getavg)
return 0;
- policy = cpufreq_cpu_get(policy->cpu);
- if (!policy)
- return -EINVAL;
-
- ret = cpufreq_driver->getavg(policy, cpu);
-
- cpufreq_cpu_put(policy);
- return ret;
+ return cpufreq_driver->getavg(policy, cpu);
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg);
@@ -1562,6 +1644,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
pr_debug("__cpufreq_governor for CPU %u, event %u\n",
policy->cpu, event);
+
+ mutex_lock(&cpufreq_governor_lock);
+ if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
+ (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
+ mutex_unlock(&cpufreq_governor_lock);
+ return -EBUSY;
+ }
+
+ if (event == CPUFREQ_GOV_STOP)
+ policy->governor_enabled = false;
+ else if (event == CPUFREQ_GOV_START)
+ policy->governor_enabled = true;
+
+ mutex_unlock(&cpufreq_governor_lock);
+
ret = policy->governor->governor(policy, event);
if (!ret) {
@@ -1569,6 +1666,14 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
policy->governor->initialized++;
else if (event == CPUFREQ_GOV_POLICY_EXIT)
policy->governor->initialized--;
+ } else {
+ /* Restore original values */
+ mutex_lock(&cpufreq_governor_lock);
+ if (event == CPUFREQ_GOV_STOP)
+ policy->governor_enabled = true;
+ else if (event == CPUFREQ_GOV_START)
+ policy->governor_enabled = false;
+ mutex_unlock(&cpufreq_governor_lock);
}
/* we keep one module reference alive for
@@ -1581,7 +1686,6 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
return ret;
}
-
int cpufreq_register_governor(struct cpufreq_governor *governor)
{
int err;
@@ -1606,7 +1710,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
}
EXPORT_SYMBOL_GPL(cpufreq_register_governor);
-
void cpufreq_unregister_governor(struct cpufreq_governor *governor)
{
#ifdef CONFIG_HOTPLUG_CPU
@@ -1636,7 +1739,6 @@ void cpufreq_unregister_governor(struct cpufreq_governor *governor)
EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
-
/*********************************************************************
* POLICY INTERFACE *
*********************************************************************/
@@ -1665,7 +1767,6 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_get_policy);
-
/*
* data : current policy.
* policy : policy to be set.
@@ -1699,8 +1800,10 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_INCOMPATIBLE, policy);
- /* verify the cpu speed can be set within this limit,
- which might be different to the first one */
+ /*
+ * verify the cpu speed can be set within this limit, which might be
+ * different to the first one
+ */
ret = cpufreq_driver->verify(policy);
if (ret)
goto error_out;
@@ -1802,8 +1905,10 @@ int cpufreq_update_policy(unsigned int cpu)
policy.policy = data->user_policy.policy;
policy.governor = data->user_policy.governor;
- /* BIOS might change freq behind our back
- -> ask driver for current freq and notify governors about a change */
+ /*
+ * BIOS might change freq behind our back
+ * -> ask driver for current freq and notify governors about a change
+ */
if (cpufreq_driver->get) {
policy.cur = cpufreq_driver->get(cpu);
if (!data->cur) {
@@ -1852,7 +1957,7 @@ static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
}
static struct notifier_block __refdata cpufreq_cpu_notifier = {
- .notifier_call = cpufreq_cpu_callback,
+ .notifier_call = cpufreq_cpu_callback,
};
/*********************************************************************
@@ -1864,7 +1969,7 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = {
* @driver_data: A struct cpufreq_driver containing the values#
* submitted by the CPU Frequency driver.
*
- * Registers a CPU Frequency driver to this core code. This code
+ * Registers a CPU Frequency driver to this core code. This code
* returns zero on success, -EBUSY when another driver got here first
* (and isn't unregistered in the meantime).
*
@@ -1931,11 +2036,10 @@ err_null_driver:
}
EXPORT_SYMBOL_GPL(cpufreq_register_driver);
-
/**
* cpufreq_unregister_driver - unregister the current CPUFreq driver
*
- * Unregister the current CPUFreq driver. Only call this if you have
+ * Unregister the current CPUFreq driver. Only call this if you have
* the right to do so, i.e. if you have succeeded in initialising before!
* Returns zero if successful, and -EINVAL if the cpufreq_driver is
* currently not initialised.
@@ -1972,7 +2076,7 @@ static int __init cpufreq_core_init(void)
init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
}
- cpufreq_global_kobject = kobject_create_and_add("cpufreq", &cpu_subsys.dev_root->kobj);
+ cpufreq_global_kobject = kobject_create();
BUG_ON(!cpufreq_global_kobject);
register_syscore_ops(&cpufreq_syscore_ops);
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index dc9b72e25c1a..464587697561 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -23,21 +23,12 @@
#include <linux/kernel_stat.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/tick.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/cpu.h>
#include "cpufreq_governor.h"
-static struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy)
-{
- if (have_governor_per_policy())
- return &policy->kobj;
- else
- return cpufreq_global_kobject;
-}
-
static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
{
if (have_governor_per_policy())
@@ -46,41 +37,6 @@ static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data)
return dbs_data->cdata->attr_group_gov_sys;
}
-static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
-{
- u64 idle_time;
- u64 cur_wall_time;
- u64 busy_time;
-
- cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
-
- busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
- busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
- busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
- busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
- busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
- busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
-
- idle_time = cur_wall_time - busy_time;
- if (wall)
- *wall = cputime_to_usecs(cur_wall_time);
-
- return cputime_to_usecs(idle_time);
-}
-
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
-{
- u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
-
- if (idle_time == -1ULL)
- return get_cpu_idle_time_jiffy(cpu, wall);
- else if (!io_busy)
- idle_time += get_cpu_iowait_time_us(cpu, wall);
-
- return idle_time;
-}
-EXPORT_SYMBOL_GPL(get_cpu_idle_time);
-
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
{
struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu);
@@ -278,6 +234,9 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
return rc;
}
+ if (!have_governor_per_policy())
+ WARN_ON(cpufreq_get_global_kobject());
+
rc = sysfs_create_group(get_governor_parent_kobj(policy),
get_sysfs_attr(dbs_data));
if (rc) {
@@ -316,6 +275,9 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
sysfs_remove_group(get_governor_parent_kobj(policy),
get_sysfs_attr(dbs_data));
+ if (!have_governor_per_policy())
+ cpufreq_put_global_kobject();
+
if ((dbs_data->cdata->governor == GOV_CONSERVATIVE) &&
(policy->governor->initialized == 1)) {
struct cs_ops *cs_ops = dbs_data->cdata->gov_ops;
@@ -404,6 +366,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
mutex_lock(&dbs_data->mutex);
mutex_destroy(&cpu_cdbs->timer_mutex);
+ cpu_cdbs->cur_policy = NULL;
mutex_unlock(&dbs_data->mutex);
diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h
index e16a96130cb3..6663ec3b3056 100644
--- a/drivers/cpufreq/cpufreq_governor.h
+++ b/drivers/cpufreq/cpufreq_governor.h
@@ -81,7 +81,7 @@ static ssize_t show_##file_name##_gov_sys \
return sprintf(buf, "%u\n", tuners->file_name); \
} \
\
-static ssize_t show_##file_name##_gov_pol \
+static ssize_t show_##file_name##_gov_pol \
(struct cpufreq_policy *policy, char *buf) \
{ \
struct dbs_data *dbs_data = policy->governor_data; \
@@ -91,7 +91,7 @@ static ssize_t show_##file_name##_gov_pol \
#define store_one(_gov, file_name) \
static ssize_t store_##file_name##_gov_sys \
-(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
+(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count) \
{ \
struct dbs_data *dbs_data = _gov##_dbs_cdata.gdbs_data; \
return store_##file_name(dbs_data, buf, count); \
@@ -256,7 +256,6 @@ static ssize_t show_sampling_rate_min_gov_pol \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
}
-u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
bool need_load_eval(struct cpu_dbs_common_info *cdbs,
unsigned int sampling_rate);
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index ceee06849b91..9fef7d6e4e6a 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -17,7 +17,6 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
-
static int cpufreq_governor_performance(struct cpufreq_policy *policy,
unsigned int event)
{
@@ -44,19 +43,16 @@ struct cpufreq_governor cpufreq_gov_performance = {
.owner = THIS_MODULE,
};
-
static int __init cpufreq_gov_performance_init(void)
{
return cpufreq_register_governor(&cpufreq_gov_performance);
}
-
static void __exit cpufreq_gov_performance_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_performance);
}
-
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION("CPUfreq policy governor 'performance'");
MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 2d948a171155..32109a14f5dc 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/cpufreq/cpufreq_powersave.c
+ * linux/drivers/cpufreq/cpufreq_powersave.c
*
- * Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -48,13 +48,11 @@ static int __init cpufreq_gov_powersave_init(void)
return cpufreq_register_governor(&cpufreq_gov_powersave);
}
-
static void __exit cpufreq_gov_powersave_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_powersave);
}
-
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'");
MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index fb65decffa28..cd9e81713a71 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -27,7 +27,7 @@ static spinlock_t cpufreq_stats_lock;
struct cpufreq_stats {
unsigned int cpu;
unsigned int total_trans;
- unsigned long long last_time;
+ unsigned long long last_time;
unsigned int max_state;
unsigned int state_num;
unsigned int last_index;
@@ -116,7 +116,7 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
stat->freq_table[i]);
- for (j = 0; j < stat->state_num; j++) {
+ for (j = 0; j < stat->state_num; j++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
@@ -349,6 +349,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
case CPU_DOWN_PREPARE:
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index bbeb9c0720a6..03078090b5f7 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -13,55 +13,13 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
#include <linux/cpufreq.h>
-#include <linux/cpu.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
#include <linux/mutex.h>
-/**
- * A few values needed by the userspace governor
- */
-static DEFINE_PER_CPU(unsigned int, cpu_max_freq);
-static DEFINE_PER_CPU(unsigned int, cpu_min_freq);
-static DEFINE_PER_CPU(unsigned int, cpu_cur_freq); /* current CPU freq */
-static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by
- userspace */
static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
-
static DEFINE_MUTEX(userspace_mutex);
-static int cpus_using_userspace_governor;
-
-/* keep track of frequency transitions */
-static int
-userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- struct cpufreq_freqs *freq = data;
-
- if (!per_cpu(cpu_is_managed, freq->cpu))
- return 0;
-
- if (val == CPUFREQ_POSTCHANGE) {
- pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
- freq->cpu, freq->new);
- per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
- }
-
- return 0;
-}
-
-static struct notifier_block userspace_cpufreq_notifier_block = {
- .notifier_call = userspace_cpufreq_notifier
-};
-
/**
* cpufreq_set - set the CPU frequency
@@ -80,13 +38,6 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
if (!per_cpu(cpu_is_managed, policy->cpu))
goto err;
- per_cpu(cpu_set_freq, policy->cpu) = freq;
-
- if (freq < per_cpu(cpu_min_freq, policy->cpu))
- freq = per_cpu(cpu_min_freq, policy->cpu);
- if (freq > per_cpu(cpu_max_freq, policy->cpu))
- freq = per_cpu(cpu_max_freq, policy->cpu);
-
/*
* We're safe from concurrent calls to ->target() here
* as we hold the userspace_mutex lock. If we were calling
@@ -104,10 +55,9 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
return ret;
}
-
static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
{
- return sprintf(buf, "%u\n", per_cpu(cpu_cur_freq, policy->cpu));
+ return sprintf(buf, "%u\n", policy->cur);
}
static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
@@ -119,73 +69,37 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
BUG_ON(!policy->cur);
- mutex_lock(&userspace_mutex);
-
- if (cpus_using_userspace_governor == 0) {
- cpufreq_register_notifier(
- &userspace_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- }
- cpus_using_userspace_governor++;
+ pr_debug("started managing cpu %u\n", cpu);
+ mutex_lock(&userspace_mutex);
per_cpu(cpu_is_managed, cpu) = 1;
- per_cpu(cpu_min_freq, cpu) = policy->min;
- per_cpu(cpu_max_freq, cpu) = policy->max;
- per_cpu(cpu_cur_freq, cpu) = policy->cur;
- per_cpu(cpu_set_freq, cpu) = policy->cur;
- pr_debug("managing cpu %u started "
- "(%u - %u kHz, currently %u kHz)\n",
- cpu,
- per_cpu(cpu_min_freq, cpu),
- per_cpu(cpu_max_freq, cpu),
- per_cpu(cpu_cur_freq, cpu));
-
mutex_unlock(&userspace_mutex);
break;
case CPUFREQ_GOV_STOP:
- mutex_lock(&userspace_mutex);
- cpus_using_userspace_governor--;
- if (cpus_using_userspace_governor == 0) {
- cpufreq_unregister_notifier(
- &userspace_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER);
- }
+ pr_debug("managing cpu %u stopped\n", cpu);
+ mutex_lock(&userspace_mutex);
per_cpu(cpu_is_managed, cpu) = 0;
- per_cpu(cpu_min_freq, cpu) = 0;
- per_cpu(cpu_max_freq, cpu) = 0;
- per_cpu(cpu_set_freq, cpu) = 0;
- pr_debug("managing cpu %u stopped\n", cpu);
mutex_unlock(&userspace_mutex);
break;
case CPUFREQ_GOV_LIMITS:
mutex_lock(&userspace_mutex);
- pr_debug("limit event for cpu %u: %u - %u kHz, "
- "currently %u kHz, last set to %u kHz\n",
+ pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
cpu, policy->min, policy->max,
- per_cpu(cpu_cur_freq, cpu),
- per_cpu(cpu_set_freq, cpu));
- if (policy->max < per_cpu(cpu_set_freq, cpu)) {
+ policy->cur);
+
+ if (policy->max < policy->cur)
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
- } else if (policy->min > per_cpu(cpu_set_freq, cpu)) {
+ else if (policy->min > policy->cur)
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
- } else {
- __cpufreq_driver_target(policy,
- per_cpu(cpu_set_freq, cpu),
- CPUFREQ_RELATION_L);
- }
- per_cpu(cpu_min_freq, cpu) = policy->min;
- per_cpu(cpu_max_freq, cpu) = policy->max;
- per_cpu(cpu_cur_freq, cpu) = policy->cur;
mutex_unlock(&userspace_mutex);
break;
}
return rc;
}
-
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
static
#endif
@@ -202,13 +116,11 @@ static int __init cpufreq_gov_userspace_init(void)
return cpufreq_register_governor(&cpufreq_gov_userspace);
}
-
static void __exit cpufreq_gov_userspace_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_userspace);
}
-
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
"Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c
index c33c76c360fa..551dd655c6f2 100644
--- a/drivers/cpufreq/davinci-cpufreq.c
+++ b/drivers/cpufreq/davinci-cpufreq.c
@@ -114,6 +114,9 @@ static int davinci_target(struct cpufreq_policy *policy,
pdata->set_voltage(idx);
out:
+ if (ret)
+ freqs.new = freqs.old;
+
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return ret;
diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c
index 6ec6539ae041..1fdb02b9f1ec 100644
--- a/drivers/cpufreq/dbx500-cpufreq.c
+++ b/drivers/cpufreq/dbx500-cpufreq.c
@@ -57,13 +57,13 @@ static int dbx500_cpufreq_target(struct cpufreq_policy *policy,
if (ret) {
pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n",
freqs.new * 1000, ret);
- return ret;
+ freqs.new = freqs.old;
}
/* post change notification */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- return 0;
+ return ret;
}
static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu)
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 37380fb92621..a60efaeb4cf8 100644
--- a/drivers/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
@@ -161,6 +161,9 @@ postchange:
current_multiplier);
}
#endif
+ if (err)
+ freqs.new = freqs.old;
+
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return err;
}
@@ -188,7 +191,7 @@ static int eps_target(struct cpufreq_policy *policy,
}
/* Make frequency transition */
- dest_state = centaur->freq_table[newstate].index & 0xffff;
+ dest_state = centaur->freq_table[newstate].driver_data & 0xffff;
ret = eps_set_state(centaur, policy, dest_state);
if (ret)
printk(KERN_ERR "eps: Timeout!\n");
@@ -380,9 +383,9 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
f_table = &centaur->freq_table[0];
if (brand != EPS_BRAND_C7M) {
f_table[0].frequency = fsb * min_multiplier;
- f_table[0].index = (min_multiplier << 8) | min_voltage;
+ f_table[0].driver_data = (min_multiplier << 8) | min_voltage;
f_table[1].frequency = fsb * max_multiplier;
- f_table[1].index = (max_multiplier << 8) | max_voltage;
+ f_table[1].driver_data = (max_multiplier << 8) | max_voltage;
f_table[2].frequency = CPUFREQ_TABLE_END;
} else {
k = 0;
@@ -391,7 +394,7 @@ static int eps_cpu_init(struct cpufreq_policy *policy)
for (i = min_multiplier; i <= max_multiplier; i++) {
voltage = (k * step) / 256 + min_voltage;
f_table[k].frequency = fsb * i;
- f_table[k].index = (i << 8) | voltage;
+ f_table[k].driver_data = (i << 8) | voltage;
k++;
}
f_table[k].frequency = CPUFREQ_TABLE_END;
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 475b4f607f0d..0d32f02ef4d6 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -113,7 +113,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n",
__func__, arm_volt);
- goto out;
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
@@ -123,14 +124,19 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
if (ret) {
pr_err("%s: failed to set cpu voltage to %d\n",
__func__, safe_arm_volt);
- goto out;
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
exynos_info->set_freq(old_index, index);
+post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ if (ret)
+ goto out;
+
/* When the new frequency is lower than current frequency */
if ((freqs.new < freqs.old) ||
((freqs.new > freqs.old) && safe_arm_volt)) {
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index d7a79662e24c..f0d87412cc91 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -34,8 +34,8 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
continue;
}
- pr_debug("table entry %u: %u kHz, %u index\n",
- i, freq, table[i].index);
+ pr_debug("table entry %u: %u kHz, %u driver_data\n",
+ i, freq, table[i].driver_data);
if (freq < min_freq)
min_freq = freq;
if (freq > max_freq)
@@ -97,11 +97,11 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
unsigned int *index)
{
struct cpufreq_frequency_table optimal = {
- .index = ~0,
+ .driver_data = ~0,
.frequency = 0,
};
struct cpufreq_frequency_table suboptimal = {
- .index = ~0,
+ .driver_data = ~0,
.frequency = 0,
};
unsigned int i;
@@ -129,12 +129,12 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
if (freq <= target_freq) {
if (freq >= optimal.frequency) {
optimal.frequency = freq;
- optimal.index = i;
+ optimal.driver_data = i;
}
} else {
if (freq <= suboptimal.frequency) {
suboptimal.frequency = freq;
- suboptimal.index = i;
+ suboptimal.driver_data = i;
}
}
break;
@@ -142,26 +142,26 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
if (freq >= target_freq) {
if (freq <= optimal.frequency) {
optimal.frequency = freq;
- optimal.index = i;
+ optimal.driver_data = i;
}
} else {
if (freq >= suboptimal.frequency) {
suboptimal.frequency = freq;
- suboptimal.index = i;
+ suboptimal.driver_data = i;
}
}
break;
}
}
- if (optimal.index > i) {
- if (suboptimal.index > i)
+ if (optimal.driver_data > i) {
+ if (suboptimal.driver_data > i)
return -EINVAL;
- *index = suboptimal.index;
+ *index = suboptimal.driver_data;
} else
- *index = optimal.index;
+ *index = optimal.driver_data;
pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
- table[*index].index);
+ table[*index].driver_data);
return 0;
}
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c
index c0075dbaa633..573c14ea802d 100644
--- a/drivers/cpufreq/ia64-acpi-cpufreq.c
+++ b/drivers/cpufreq/ia64-acpi-cpufreq.c
@@ -326,7 +326,7 @@ acpi_cpufreq_cpu_init (
/* table init */
for (i = 0; i <= data->acpi_data.state_count; i++)
{
- data->freq_table[i].index = i;
+ data->freq_table[i].driver_data = i;
if (i < data->acpi_data.state_count) {
data->freq_table[i].frequency =
data->acpi_data.states[i].core_frequency * 1000;
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index b78bc35973ba..e37cdaedbb5b 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -68,8 +68,6 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new)
return 0;
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
-
rcu_read_lock();
opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) {
@@ -86,13 +84,16 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
freqs.old / 1000, volt_old / 1000,
freqs.new / 1000, volt / 1000);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
/* scaling up? scale voltage before frequency */
if (freqs.new > freqs.old) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
if (ret) {
dev_err(cpu_dev,
"failed to scale vddarm up: %d\n", ret);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
/*
@@ -145,15 +146,18 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
if (ret) {
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
regulator_set_voltage_tol(arm_reg, volt_old, 0);
- return ret;
+ freqs.new = freqs.old;
+ goto post_notify;
}
/* scaling down? scale voltage after frequency */
if (freqs.new < freqs.old) {
ret = regulator_set_voltage_tol(arm_reg, volt, 0);
- if (ret)
+ if (ret) {
dev_warn(cpu_dev,
"failed to scale vddarm down: %d\n", ret);
+ ret = 0;
+ }
if (freqs.old == FREQ_1P2_GHZ / 1000) {
regulator_set_voltage_tol(pu_reg,
@@ -163,9 +167,10 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
}
}
+post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- return 0;
+ return ret;
}
static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c
index b2644af985ec..c233ea617366 100644
--- a/drivers/cpufreq/kirkwood-cpufreq.c
+++ b/drivers/cpufreq/kirkwood-cpufreq.c
@@ -59,7 +59,7 @@ static void kirkwood_cpufreq_set_cpu_state(struct cpufreq_policy *policy,
unsigned int index)
{
struct cpufreq_freqs freqs;
- unsigned int state = kirkwood_freq_table[index].index;
+ unsigned int state = kirkwood_freq_table[index].driver_data;
unsigned long reg;
freqs.old = kirkwood_cpufreq_get_cpu_frequency(0);
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index b448638e34de..b6a0a7a406b0 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -254,7 +254,7 @@ static void longhaul_setstate(struct cpufreq_policy *policy,
u32 bm_timeout = 1000;
unsigned int dir = 0;
- mults_index = longhaul_table[table_index].index;
+ mults_index = longhaul_table[table_index].driver_data;
/* Safety precautions */
mult = mults[mults_index & 0x1f];
if (mult == -1)
@@ -487,7 +487,7 @@ static int __cpuinit longhaul_get_ranges(void)
if (ratio > maxmult || ratio < minmult)
continue;
longhaul_table[k].frequency = calc_speed(ratio);
- longhaul_table[k].index = j;
+ longhaul_table[k].driver_data = j;
k++;
}
if (k <= 1) {
@@ -508,8 +508,8 @@ static int __cpuinit longhaul_get_ranges(void)
if (min_i != j) {
swap(longhaul_table[j].frequency,
longhaul_table[min_i].frequency);
- swap(longhaul_table[j].index,
- longhaul_table[min_i].index);
+ swap(longhaul_table[j].driver_data,
+ longhaul_table[min_i].driver_data);
}
}
@@ -517,7 +517,7 @@ static int __cpuinit longhaul_get_ranges(void)
/* Find index we are running on */
for (j = 0; j < k; j++) {
- if (mults[longhaul_table[j].index & 0x1f] == mult) {
+ if (mults[longhaul_table[j].driver_data & 0x1f] == mult) {
longhaul_index = j;
break;
}
@@ -613,7 +613,7 @@ static void __cpuinit longhaul_setup_voltagescaling(void)
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
else
pos = minvid.pos;
- longhaul_table[j].index |= mV_vrm_table[pos] << 8;
+ longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
speed, j, vid.mV);
@@ -656,12 +656,12 @@ static int longhaul_target(struct cpufreq_policy *policy,
* this in hardware, C3 is old and we need to do this
* in software. */
i = longhaul_index;
- current_vid = (longhaul_table[longhaul_index].index >> 8);
+ current_vid = (longhaul_table[longhaul_index].driver_data >> 8);
current_vid &= 0x1f;
if (table_index > longhaul_index)
dir = 1;
while (i != table_index) {
- vid = (longhaul_table[i].index >> 8) & 0x1f;
+ vid = (longhaul_table[i].driver_data >> 8) & 0x1f;
if (vid != current_vid) {
longhaul_setstate(policy, i);
current_vid = vid;
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c
index d53912768946..bb838b985077 100644
--- a/drivers/cpufreq/loongson2_cpufreq.c
+++ b/drivers/cpufreq/loongson2_cpufreq.c
@@ -72,7 +72,7 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
freq =
((cpu_clock_freq / 1000) *
- loongson2_clockmod_table[newstate].index) / 8;
+ loongson2_clockmod_table[newstate].driver_data) / 8;
if (freq < policy->min || freq > policy->max)
return -EINVAL;
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c
index 0279d18a57f9..29468a522ee9 100644
--- a/drivers/cpufreq/omap-cpufreq.c
+++ b/drivers/cpufreq/omap-cpufreq.c
@@ -93,9 +93,6 @@ static int omap_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new && policy->cur == freqs.new)
return ret;
- /* notifiers */
- cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
-
freq = freqs.new * 1000;
ret = clk_round_rate(mpu_clk, freq);
if (IS_ERR_VALUE(ret)) {
@@ -125,6 +122,9 @@ static int omap_target(struct cpufreq_policy *policy,
freqs.old / 1000, volt_old ? volt_old / 1000 : -1,
freqs.new / 1000, volt ? volt / 1000 : -1);
+ /* notifiers */
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
/* scaling up? scale voltage before frequency */
if (mpu_reg && (freqs.new > freqs.old)) {
r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol);
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 421ef37d0bb3..9ee78170ff86 100644
--- a/drivers/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -118,7 +118,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
return -EINVAL;
freqs.old = cpufreq_p4_get(policy->cpu);
- freqs.new = stock_freq * p4clockmod_table[newstate].index / 8;
+ freqs.new = stock_freq * p4clockmod_table[newstate].driver_data / 8;
if (freqs.new == freqs.old)
return 0;
@@ -131,7 +131,7 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
* Developer's Manual, Volume 3
*/
for_each_cpu(i, policy->cpus)
- cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
+ cpufreq_p4_setdc(i, p4clockmod_table[newstate].driver_data);
/* notifiers */
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index be1e7958909e..b704da404067 100644
--- a/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -204,7 +204,8 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* initialize frequency table */
for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000;
+ pas_freqs[i].frequency =
+ get_astate_freq(pas_freqs[i].driver_data) * 100000;
pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
}
@@ -280,7 +281,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy,
pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
policy->cpu,
pas_freqs[pas_astate_new].frequency,
- pas_freqs[pas_astate_new].index);
+ pas_freqs[pas_astate_new].driver_data);
current_astate = pas_astate_new;
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 0de00081a81e..1581fcc4cf4a 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -243,6 +243,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
return 0;
cmd_incomplete:
+ freqs.new = freqs.old;
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
iowrite16(0, &pcch_hdr->status);
spin_unlock(&pcc_lock);
return -EINVAL;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/drivers/cpufreq/pmac32-cpufreq.c
index 3104fad82480..3104fad82480 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/drivers/cpufreq/pmac32-cpufreq.c
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/drivers/cpufreq/pmac64-cpufreq.c
index 7ba423431cfe..7ba423431cfe 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/drivers/cpufreq/pmac64-cpufreq.c
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index ea0222a45b7b..ea8e10382ec5 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -58,7 +58,7 @@ static int powernow_k6_get_cpu_multiplier(void)
msrval = POWERNOW_IOPORT + 0x0;
wrmsr(MSR_K6_EPMR, msrval, 0); /* disable it again */
- return clock_ratio[(invalue >> 5)&7].index;
+ return clock_ratio[(invalue >> 5)&7].driver_data;
}
@@ -75,13 +75,13 @@ static void powernow_k6_set_state(struct cpufreq_policy *policy,
unsigned long msrval;
struct cpufreq_freqs freqs;
- if (clock_ratio[best_i].index > max_multiplier) {
+ if (clock_ratio[best_i].driver_data > max_multiplier) {
printk(KERN_ERR PFX "invalid target frequency\n");
return;
}
freqs.old = busfreq * powernow_k6_get_cpu_multiplier();
- freqs.new = busfreq * clock_ratio[best_i].index;
+ freqs.new = busfreq * clock_ratio[best_i].driver_data;
cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
@@ -156,7 +156,7 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
/* table init */
for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
- f = clock_ratio[i].index;
+ f = clock_ratio[i].driver_data;
if (f > max_multiplier)
clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
else
diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 53888dacbe58..b9f80b713fda 100644
--- a/drivers/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -186,7 +186,7 @@ static int get_ranges(unsigned char *pst)
fid = *pst++;
powernow_table[j].frequency = (fsb * fid_codes[fid]) / 10;
- powernow_table[j].index = fid; /* lower 8 bits */
+ powernow_table[j].driver_data = fid; /* lower 8 bits */
speed = powernow_table[j].frequency;
@@ -203,7 +203,7 @@ static int get_ranges(unsigned char *pst)
maximum_speed = speed;
vid = *pst++;
- powernow_table[j].index |= (vid << 8); /* upper 8 bits */
+ powernow_table[j].driver_data |= (vid << 8); /* upper 8 bits */
pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
"VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
@@ -212,7 +212,7 @@ static int get_ranges(unsigned char *pst)
mobile_vid_table[vid]%1000);
}
powernow_table[number_scales].frequency = CPUFREQ_TABLE_END;
- powernow_table[number_scales].index = 0;
+ powernow_table[number_scales].driver_data = 0;
return 0;
}
@@ -260,8 +260,8 @@ static void change_speed(struct cpufreq_policy *policy, unsigned int index)
* vid are the upper 8 bits.
*/
- fid = powernow_table[index].index & 0xFF;
- vid = (powernow_table[index].index & 0xFF00) >> 8;
+ fid = powernow_table[index].driver_data & 0xFF;
+ vid = (powernow_table[index].driver_data & 0xFF00) >> 8;
rdmsrl(MSR_K7_FID_VID_STATUS, fidvidstatus.val);
cfid = fidvidstatus.bits.CFID;
@@ -373,8 +373,8 @@ static int powernow_acpi_init(void)
fid = pc.bits.fid;
powernow_table[i].frequency = fsb * fid_codes[fid] / 10;
- powernow_table[i].index = fid; /* lower 8 bits */
- powernow_table[i].index |= (vid << 8); /* upper 8 bits */
+ powernow_table[i].driver_data = fid; /* lower 8 bits */
+ powernow_table[i].driver_data |= (vid << 8); /* upper 8 bits */
speed = powernow_table[i].frequency;
speed_mhz = speed / 1000;
@@ -417,7 +417,7 @@ static int powernow_acpi_init(void)
}
powernow_table[i].frequency = CPUFREQ_TABLE_END;
- powernow_table[i].index = 0;
+ powernow_table[i].driver_data = 0;
/* notify BIOS that we exist */
acpi_processor_notify_smm(THIS_MODULE);
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index b828efe4b2f8..78f018f2a5de 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -584,9 +584,9 @@ static void print_basics(struct powernow_k8_data *data)
CPUFREQ_ENTRY_INVALID) {
printk(KERN_INFO PFX
"fid 0x%x (%d MHz), vid 0x%x\n",
- data->powernow_table[j].index & 0xff,
+ data->powernow_table[j].driver_data & 0xff,
data->powernow_table[j].frequency/1000,
- data->powernow_table[j].index >> 8);
+ data->powernow_table[j].driver_data >> 8);
}
}
if (data->batps)
@@ -632,13 +632,13 @@ static int fill_powernow_table(struct powernow_k8_data *data,
for (j = 0; j < data->numps; j++) {
int freq;
- powernow_table[j].index = pst[j].fid; /* lower 8 bits */
- powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
+ powernow_table[j].driver_data = pst[j].fid; /* lower 8 bits */
+ powernow_table[j].driver_data |= (pst[j].vid << 8); /* upper 8 bits */
freq = find_khz_freq_from_fid(pst[j].fid);
powernow_table[j].frequency = freq;
}
powernow_table[data->numps].frequency = CPUFREQ_TABLE_END;
- powernow_table[data->numps].index = 0;
+ powernow_table[data->numps].driver_data = 0;
if (query_current_values_with_pending_wait(data)) {
kfree(powernow_table);
@@ -810,7 +810,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
powernow_table[data->acpi_data.state_count].frequency =
CPUFREQ_TABLE_END;
- powernow_table[data->acpi_data.state_count].index = 0;
+ powernow_table[data->acpi_data.state_count].driver_data = 0;
data->powernow_table = powernow_table;
if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
@@ -865,7 +865,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
pr_debug(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
index = fid | (vid<<8);
- powernow_table[i].index = index;
+ powernow_table[i].driver_data = index;
freq = find_khz_freq_from_fid(fid);
powernow_table[i].frequency = freq;
@@ -941,8 +941,8 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
* the cpufreq frequency table in find_psb_table, vid
* are the upper 8 bits.
*/
- fid = data->powernow_table[index].index & 0xFF;
- vid = (data->powernow_table[index].index & 0xFF00) >> 8;
+ fid = data->powernow_table[index].driver_data & 0xFF;
+ vid = (data->powernow_table[index].driver_data & 0xFF00) >> 8;
pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
@@ -967,9 +967,9 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
res = transition_fid_vid(data, fid, vid);
if (res)
- return res;
-
- freqs.new = find_khz_freq_from_fid(data->currfid);
+ freqs.new = freqs.old;
+ else
+ freqs.new = find_khz_freq_from_fid(data->currfid);
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
return res;
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
new file mode 100644
index 000000000000..3cae4529f959
--- /dev/null
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/errno.h>
+#include <sysdev/fsl_soc.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+/**
+ * struct cpu_data - per CPU data struct
+ * @clk: the clk of CPU
+ * @parent: the parent node of cpu clock
+ * @table: frequency table
+ */
+struct cpu_data {
+ struct clk *clk;
+ struct device_node *parent;
+ struct cpufreq_frequency_table *table;
+};
+
+/**
+ * struct soc_data - SoC specific data
+ * @freq_mask: mask the disallowed frequencies
+ * @flag: unique flags
+ */
+struct soc_data {
+ u32 freq_mask[4];
+ u32 flag;
+};
+
+#define FREQ_MASK 1
+/* see hardware specification for the allowed frqeuencies */
+static const struct soc_data sdata[] = {
+ { /* used by p2041 and p3041 */
+ .freq_mask = {0x8, 0x8, 0x2, 0x2},
+ .flag = FREQ_MASK,
+ },
+ { /* used by p5020 */
+ .freq_mask = {0x8, 0x2},
+ .flag = FREQ_MASK,
+ },
+ { /* used by p4080, p5040 */
+ .freq_mask = {0},
+ .flag = 0,
+ },
+};
+
+/*
+ * the minimum allowed core frequency, in Hz
+ * for chassis v1.0, >= platform frequency
+ * for chassis v2.0, >= platform frequency / 2
+ */
+static u32 min_cpufreq;
+static const u32 *fmask;
+
+/* serialize frequency changes */
+static DEFINE_MUTEX(cpufreq_lock);
+static DEFINE_PER_CPU(struct cpu_data *, cpu_data);
+
+/* cpumask in a cluster */
+static DEFINE_PER_CPU(cpumask_var_t, cpu_mask);
+
+#ifndef CONFIG_SMP
+static inline const struct cpumask *cpu_core_mask(int cpu)
+{
+ return cpumask_of(0);
+}
+#endif
+
+static unsigned int corenet_cpufreq_get_speed(unsigned int cpu)
+{
+ struct cpu_data *data = per_cpu(cpu_data, cpu);
+
+ return clk_get_rate(data->clk) / 1000;
+}
+
+/* reduce the duplicated frequencies in frequency table */
+static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
+ int count)
+{
+ int i, j;
+
+ for (i = 1; i < count; i++) {
+ for (j = 0; j < i; j++) {
+ if (freq_table[j].frequency == CPUFREQ_ENTRY_INVALID ||
+ freq_table[j].frequency !=
+ freq_table[i].frequency)
+ continue;
+
+ freq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
+ break;
+ }
+ }
+}
+
+/* sort the frequencies in frequency table in descenting order */
+static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
+ int count)
+{
+ int i, j, ind;
+ unsigned int freq, max_freq;
+ struct cpufreq_frequency_table table;
+ for (i = 0; i < count - 1; i++) {
+ max_freq = freq_table[i].frequency;
+ ind = i;
+ for (j = i + 1; j < count; j++) {
+ freq = freq_table[j].frequency;
+ if (freq == CPUFREQ_ENTRY_INVALID ||
+ freq <= max_freq)
+ continue;
+ ind = j;
+ max_freq = freq;
+ }
+
+ if (ind != i) {
+ /* exchange the frequencies */
+ table.driver_data = freq_table[i].driver_data;
+ table.frequency = freq_table[i].frequency;
+ freq_table[i].driver_data = freq_table[ind].driver_data;
+ freq_table[i].frequency = freq_table[ind].frequency;
+ freq_table[ind].driver_data = table.driver_data;
+ freq_table[ind].frequency = table.frequency;
+ }
+ }
+}
+
+static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ struct device_node *np;
+ int i, count, ret;
+ u32 freq, mask;
+ struct clk *clk;
+ struct cpufreq_frequency_table *table;
+ struct cpu_data *data;
+ unsigned int cpu = policy->cpu;
+
+ np = of_get_cpu_node(cpu, NULL);
+ if (!np)
+ return -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ pr_err("%s: no memory\n", __func__);
+ goto err_np;
+ }
+
+ data->clk = of_clk_get(np, 0);
+ if (IS_ERR(data->clk)) {
+ pr_err("%s: no clock information\n", __func__);
+ goto err_nomem2;
+ }
+
+ data->parent = of_parse_phandle(np, "clocks", 0);
+ if (!data->parent) {
+ pr_err("%s: could not get clock information\n", __func__);
+ goto err_nomem2;
+ }
+
+ count = of_property_count_strings(data->parent, "clock-names");
+ table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
+ if (!table) {
+ pr_err("%s: no memory\n", __func__);
+ goto err_node;
+ }
+
+ if (fmask)
+ mask = fmask[get_hard_smp_processor_id(cpu)];
+ else
+ mask = 0x0;
+
+ for (i = 0; i < count; i++) {
+ clk = of_clk_get(data->parent, i);
+ freq = clk_get_rate(clk);
+ /*
+ * the clock is valid if its frequency is not masked
+ * and large than minimum allowed frequency.
+ */
+ if (freq < min_cpufreq || (mask & (1 << i)))
+ table[i].frequency = CPUFREQ_ENTRY_INVALID;
+ else
+ table[i].frequency = freq / 1000;
+ table[i].driver_data = i;
+ }
+ freq_table_redup(table, count);
+ freq_table_sort(table, count);
+ table[i].frequency = CPUFREQ_TABLE_END;
+
+ /* set the min and max frequency properly */
+ ret = cpufreq_frequency_table_cpuinfo(policy, table);
+ if (ret) {
+ pr_err("invalid frequency table: %d\n", ret);
+ goto err_nomem1;
+ }
+
+ data->table = table;
+ per_cpu(cpu_data, cpu) = data;
+
+ /* update ->cpus if we have cluster, no harm if not */
+ cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu));
+ for_each_cpu(i, per_cpu(cpu_mask, cpu))
+ per_cpu(cpu_data, i) = data;
+
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ policy->cur = corenet_cpufreq_get_speed(policy->cpu);
+
+ cpufreq_frequency_table_get_attr(table, cpu);
+ of_node_put(np);
+
+ return 0;
+
+err_nomem1:
+ kfree(table);
+err_node:
+ of_node_put(data->parent);
+err_nomem2:
+ per_cpu(cpu_data, cpu) = NULL;
+ kfree(data);
+err_np:
+ of_node_put(np);
+
+ return -ENODEV;
+}
+
+static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
+ unsigned int cpu;
+
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ of_node_put(data->parent);
+ kfree(data->table);
+ kfree(data);
+
+ for_each_cpu(cpu, per_cpu(cpu_mask, policy->cpu))
+ per_cpu(cpu_data, cpu) = NULL;
+
+ return 0;
+}
+
+static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ struct cpufreq_frequency_table *table =
+ per_cpu(cpu_data, policy->cpu)->table;
+
+ return cpufreq_frequency_table_verify(policy, table);
+}
+
+static int corenet_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ unsigned int new;
+ struct clk *parent;
+ int ret;
+ struct cpu_data *data = per_cpu(cpu_data, policy->cpu);
+
+ cpufreq_frequency_table_target(policy, data->table,
+ target_freq, relation, &new);
+
+ if (policy->cur == data->table[new].frequency)
+ return 0;
+
+ freqs.old = policy->cur;
+ freqs.new = data->table[new].frequency;
+
+ mutex_lock(&cpufreq_lock);
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
+
+ parent = of_clk_get(data->parent, data->table[new].driver_data);
+ ret = clk_set_parent(data->clk, parent);
+ if (ret)
+ freqs.new = freqs.old;
+
+ cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&cpufreq_lock);
+
+ return ret;
+}
+
+static struct freq_attr *corenet_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
+ .name = "ppc_cpufreq",
+ .owner = THIS_MODULE,
+ .flags = CPUFREQ_CONST_LOOPS,
+ .init = corenet_cpufreq_cpu_init,
+ .exit = __exit_p(corenet_cpufreq_cpu_exit),
+ .verify = corenet_cpufreq_verify,
+ .target = corenet_cpufreq_target,
+ .get = corenet_cpufreq_get_speed,
+ .attr = corenet_cpufreq_attr,
+};
+
+static const struct of_device_id node_matches[] __initdata = {
+ { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
+ { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
+ { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
+ { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], },
+ { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], },
+ { .compatible = "fsl,qoriq-clockgen-2.0", },
+ {}
+};
+
+static int __init ppc_corenet_cpufreq_init(void)
+{
+ int ret;
+ struct device_node *np;
+ const struct of_device_id *match;
+ const struct soc_data *data;
+ unsigned int cpu;
+
+ np = of_find_matching_node(NULL, node_matches);
+ if (!np)
+ return -ENODEV;
+
+ for_each_possible_cpu(cpu) {
+ if (!alloc_cpumask_var(&per_cpu(cpu_mask, cpu), GFP_KERNEL))
+ goto err_mask;
+ cpumask_copy(per_cpu(cpu_mask, cpu), cpu_core_mask(cpu));
+ }
+
+ match = of_match_node(node_matches, np);
+ data = match->data;
+ if (data) {
+ if (data->flag)
+ fmask = data->freq_mask;
+ min_cpufreq = fsl_get_sys_freq();
+ } else {
+ min_cpufreq = fsl_get_sys_freq() / 2;
+ }
+
+ of_node_put(np);
+
+ ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
+ if (!ret)
+ pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
+
+ return ret;
+
+err_mask:
+ for_each_possible_cpu(cpu)
+ free_cpumask_var(per_cpu(cpu_mask, cpu));
+
+ return -ENOMEM;
+}
+module_init(ppc_corenet_cpufreq_init);
+
+static void __exit ppc_corenet_cpufreq_exit(void)
+{
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu)
+ free_cpumask_var(per_cpu(cpu_mask, cpu));
+
+ cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
+}
+module_exit(ppc_corenet_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
+MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SoCs");
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index e577a1dbbfcd..5936f8d6f2cc 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -106,7 +106,7 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* initialize frequency table */
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
+ cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
}
@@ -165,7 +165,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy,
"1/%d of max frequency\n",
policy->cpu,
cbe_freqs[cbe_pmode_new].frequency,
- cbe_freqs[cbe_pmode_new].index);
+ cbe_freqs[cbe_pmode_new].driver_data);
rc = set_pmode(policy->cpu, cbe_pmode_new);
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c
index 9e5bc8e388a0..fb3981ac829f 100644
--- a/drivers/cpufreq/pxa2xx-cpufreq.c
+++ b/drivers/cpufreq/pxa2xx-cpufreq.c
@@ -420,7 +420,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
/* Generate pxa25x the run cpufreq_frequency_table struct */
for (i = 0; i < NUM_PXA25x_RUN_FREQS; i++) {
pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
- pxa255_run_freq_table[i].index = i;
+ pxa255_run_freq_table[i].driver_data = i;
}
pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
@@ -428,7 +428,7 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
for (i = 0; i < NUM_PXA25x_TURBO_FREQS; i++) {
pxa255_turbo_freq_table[i].frequency =
pxa255_turbo_freqs[i].khz;
- pxa255_turbo_freq_table[i].index = i;
+ pxa255_turbo_freq_table[i].driver_data = i;
}
pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
@@ -440,9 +440,9 @@ static int pxa_cpufreq_init(struct cpufreq_policy *policy)
if (freq > pxa27x_maxfreq)
break;
pxa27x_freq_table[i].frequency = freq;
- pxa27x_freq_table[i].index = i;
+ pxa27x_freq_table[i].driver_data = i;
}
- pxa27x_freq_table[i].index = i;
+ pxa27x_freq_table[i].driver_data = i;
pxa27x_freq_table[i].frequency = CPUFREQ_TABLE_END;
/*
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c
index 15d60f857ad5..9c92ef032a9e 100644
--- a/drivers/cpufreq/pxa3xx-cpufreq.c
+++ b/drivers/cpufreq/pxa3xx-cpufreq.c
@@ -98,10 +98,10 @@ static int setup_freqs_table(struct cpufreq_policy *policy,
return -ENOMEM;
for (i = 0; i < num; i++) {
- table[i].index = i;
+ table[i].driver_data = i;
table[i].frequency = freqs[i].cpufreq_mhz * 1000;
}
- table[num].index = i;
+ table[num].driver_data = i;
table[num].frequency = CPUFREQ_TABLE_END;
pxa3xx_freqs = freqs;
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index 4f1881eee3f1..ce5b9fca9c18 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -205,7 +205,7 @@ static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx)
ret = s3c2416_cpufreq_set_armdiv(s3c_freq,
clk_get_rate(s3c_freq->hclk) / 1000);
if (ret < 0) {
- pr_err("cpufreq: Failed to to set the armdiv to %lukHz: %d\n",
+ pr_err("cpufreq: Failed to set the armdiv to %lukHz: %d\n",
clk_get_rate(s3c_freq->hclk) / 1000, ret);
return ret;
}
@@ -244,7 +244,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
if (ret != 0)
goto out;
- idx = s3c_freq->freq_table[i].index;
+ idx = s3c_freq->freq_table[i].driver_data;
if (idx == SOURCE_HCLK)
to_dvs = 1;
@@ -312,7 +312,7 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
if (freq->frequency == CPUFREQ_ENTRY_INVALID)
continue;
- dvfs = &s3c2416_dvfs_table[freq->index];
+ dvfs = &s3c2416_dvfs_table[freq->driver_data];
found = 0;
/* Check only the min-voltage, more is always ok on S3C2416 */
@@ -462,7 +462,7 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
freq = s3c_freq->freq_table;
while (freq->frequency != CPUFREQ_TABLE_END) {
/* special handling for dvs mode */
- if (freq->index == 0) {
+ if (freq->driver_data == 0) {
if (!s3c_freq->hclk) {
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
freq->frequency);
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 3c0e78ede0da..3513e7477160 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -70,7 +70,7 @@ static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg)
cfg->freq.pclk = pclk = clk_get_rate(clk_pclk);
cfg->freq.armclk = armclk = clk_get_rate(clk_arm);
- cfg->pll.index = __raw_readl(S3C2410_MPLLCON);
+ cfg->pll.driver_data = __raw_readl(S3C2410_MPLLCON);
cfg->pll.frequency = fclk;
cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10);
@@ -431,7 +431,7 @@ static unsigned int suspend_freq;
static int s3c_cpufreq_suspend(struct cpufreq_policy *policy)
{
suspend_pll.frequency = clk_get_rate(_clk_mpll);
- suspend_pll.index = __raw_readl(S3C2410_MPLLCON);
+ suspend_pll.driver_data = __raw_readl(S3C2410_MPLLCON);
suspend_freq = s3c_cpufreq_get(0) * 1000;
return 0;
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index 27cacb524796..13bb4bae64ee 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -87,7 +87,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
freqs.old = clk_get_rate(armclk) / 1000;
freqs.new = s3c64xx_freq_table[i].frequency;
freqs.flags = 0;
- dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[i].index];
+ dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[i].driver_data];
if (freqs.old == freqs.new)
return 0;
@@ -104,7 +104,8 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
if (ret != 0) {
pr_err("Failed to set VDDARM for %dkHz: %d\n",
freqs.new, ret);
- goto err;
+ freqs.new = freqs.old;
+ goto post_notify;
}
}
#endif
@@ -113,10 +114,13 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy,
if (ret < 0) {
pr_err("Failed to set rate %dkHz: %d\n",
freqs.new, ret);
- goto err;
+ freqs.new = freqs.old;
}
+post_notify:
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
+ if (ret)
+ goto err;
#ifdef CONFIG_REGULATOR
if (vddarm && freqs.new < freqs.old) {
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index f740b134d27b..77a210975fc4 100644
--- a/drivers/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -71,7 +71,7 @@ static void sc520_freq_set_cpu_state(struct cpufreq_policy *policy,
local_irq_disable();
clockspeed_reg = *cpuctl & ~0x03;
- *cpuctl = clockspeed_reg | sc520_freq_table[state].index;
+ *cpuctl = clockspeed_reg | sc520_freq_table[state].driver_data;
local_irq_enable();
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c
index 306ae462bba6..93061a408773 100644
--- a/drivers/cpufreq/sparc-us2e-cpufreq.c
+++ b/drivers/cpufreq/sparc-us2e-cpufreq.c
@@ -308,17 +308,17 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
struct cpufreq_frequency_table *table =
&us2e_freq_table[cpu].table[0];
- table[0].index = 0;
+ table[0].driver_data = 0;
table[0].frequency = clock_tick / 1;
- table[1].index = 1;
+ table[1].driver_data = 1;
table[1].frequency = clock_tick / 2;
- table[2].index = 2;
+ table[2].driver_data = 2;
table[2].frequency = clock_tick / 4;
- table[2].index = 3;
+ table[2].driver_data = 3;
table[2].frequency = clock_tick / 6;
- table[2].index = 4;
+ table[2].driver_data = 4;
table[2].frequency = clock_tick / 8;
- table[2].index = 5;
+ table[2].driver_data = 5;
table[3].frequency = CPUFREQ_TABLE_END;
policy->cpuinfo.transition_latency = 0;
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c
index c71ee142347a..880ee293d61e 100644
--- a/drivers/cpufreq/sparc-us3-cpufreq.c
+++ b/drivers/cpufreq/sparc-us3-cpufreq.c
@@ -169,13 +169,13 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
struct cpufreq_frequency_table *table =
&us3_freq_table[cpu].table[0];
- table[0].index = 0;
+ table[0].driver_data = 0;
table[0].frequency = clock_tick / 1;
- table[1].index = 1;
+ table[1].driver_data = 1;
table[1].frequency = clock_tick / 2;
- table[2].index = 2;
+ table[2].driver_data = 2;
table[2].frequency = clock_tick / 32;
- table[3].index = 0;
+ table[3].driver_data = 0;
table[3].frequency = CPUFREQ_TABLE_END;
policy->cpuinfo.transition_latency = 0;
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c
index 156829f4576d..c3efa7f2a908 100644
--- a/drivers/cpufreq/spear-cpufreq.c
+++ b/drivers/cpufreq/spear-cpufreq.c
@@ -250,11 +250,11 @@ static int spear_cpufreq_driver_init(void)
}
for (i = 0; i < cnt; i++) {
- freq_tbl[i].index = i;
+ freq_tbl[i].driver_data = i;
freq_tbl[i].frequency = be32_to_cpup(val++);
}
- freq_tbl[i].index = i;
+ freq_tbl[i].driver_data = i;
freq_tbl[i].frequency = CPUFREQ_TABLE_END;
spear_cpufreq.freq_tbl = freq_tbl;
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 618e6f417b1c..0915e712fbdc 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -79,11 +79,11 @@ static struct cpufreq_driver centrino_driver;
/* Computes the correct form for IA32_PERF_CTL MSR for a particular
frequency/voltage operating point; frequency in MHz, volts in mV.
- This is stored as "index" in the structure. */
+ This is stored as "driver_data" in the structure. */
#define OP(mhz, mv) \
{ \
.frequency = (mhz) * 1000, \
- .index = (((mhz)/100) << 8) | ((mv - 700) / 16) \
+ .driver_data = (((mhz)/100) << 8) | ((mv - 700) / 16) \
}
/*
@@ -307,7 +307,7 @@ static unsigned extract_clock(unsigned msr, unsigned int cpu, int failsafe)
per_cpu(centrino_model, cpu)->op_points[i].frequency
!= CPUFREQ_TABLE_END;
i++) {
- if (msr == per_cpu(centrino_model, cpu)->op_points[i].index)
+ if (msr == per_cpu(centrino_model, cpu)->op_points[i].driver_data)
return per_cpu(centrino_model, cpu)->
op_points[i].frequency;
}
@@ -501,7 +501,7 @@ static int centrino_target (struct cpufreq_policy *policy,
break;
}
- msr = per_cpu(centrino_model, cpu)->op_points[newstate].index;
+ msr = per_cpu(centrino_model, cpu)->op_points[newstate].driver_data;
if (first_cpu) {
rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h);
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index c74c0e130ef4..cd66b85d927c 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -28,17 +28,16 @@
#include <linux/io.h>
#include <linux/suspend.h>
-/* Frequency table index must be sequential starting at 0 */
static struct cpufreq_frequency_table freq_table[] = {
- { 0, 216000 },
- { 1, 312000 },
- { 2, 456000 },
- { 3, 608000 },
- { 4, 760000 },
- { 5, 816000 },
- { 6, 912000 },
- { 7, 1000000 },
- { 8, CPUFREQ_TABLE_END },
+ { .frequency = 216000 },
+ { .frequency = 312000 },
+ { .frequency = 456000 },
+ { .frequency = 608000 },
+ { .frequency = 760000 },
+ { .frequency = 816000 },
+ { .frequency = 912000 },
+ { .frequency = 1000000 },
+ { .frequency = CPUFREQ_TABLE_END },
};
#define NUM_CPUS 2
@@ -138,12 +137,12 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
if (ret) {
pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
freqs.new);
- return ret;
+ freqs.new = freqs.old;
}
cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
- return 0;
+ return ret;
}
static unsigned long tegra_cpu_highest_speed(void)
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index e21cdfa4002a..0e2cd5cab4d0 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -1,7 +1,9 @@
-config CPU_IDLE
+menuconfig CPU_IDLE
bool "CPU idle PM support"
default y if ACPI || PPC_PSERIES
+ select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE)
+ select CPU_IDLE_GOV_MENU if (NO_HZ || NO_HZ_IDLE)
help
CPU idle is a generic framework for supporting software-controlled
idle processor power management. It includes modular cross-platform
@@ -9,9 +11,10 @@ config CPU_IDLE
If you're using an ACPI-enabled platform, you should say Y here.
+if CPU_IDLE
+
config CPU_IDLE_MULTIPLE_DRIVERS
bool "Support multiple cpuidle drivers"
- depends on CPU_IDLE
default n
help
Allows the cpuidle framework to use different drivers for each CPU.
@@ -19,20 +22,13 @@ config CPU_IDLE_MULTIPLE_DRIVERS
states. If unsure say N.
config CPU_IDLE_GOV_LADDER
- bool
- depends on CPU_IDLE
+ bool "Ladder governor (for periodic timer tick)"
default y
config CPU_IDLE_GOV_MENU
- bool
- depends on CPU_IDLE && NO_HZ
+ bool "Menu governor (for tickless system)"
default y
-config ARCH_NEEDS_CPU_IDLE_COUPLED
- def_bool n
-
-if CPU_IDLE
-
config CPU_IDLE_CALXEDA
bool "CPU Idle Driver for Calxeda processors"
depends on ARCH_HIGHBANK
@@ -40,4 +36,13 @@ config CPU_IDLE_CALXEDA
help
Select this to enable cpuidle on Calxeda processors.
+config CPU_IDLE_ZYNQ
+ bool "CPU Idle Driver for Xilinx Zynq processors"
+ depends on ARCH_ZYNQ
+ help
+ Select this to enable cpuidle on Xilinx Zynq processors.
+
endif
+
+config ARCH_NEEDS_CPU_IDLE_COUPLED
+ def_bool n
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 0d8bd55e776f..8767a7b3eb91 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
obj-$(CONFIG_CPU_IDLE_CALXEDA) += cpuidle-calxeda.o
obj-$(CONFIG_ARCH_KIRKWOOD) += cpuidle-kirkwood.o
+obj-$(CONFIG_CPU_IDLE_ZYNQ) += cpuidle-zynq.o
diff --git a/drivers/cpuidle/cpuidle-zynq.c b/drivers/cpuidle/cpuidle-zynq.c
new file mode 100644
index 000000000000..38e03a183591
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-zynq.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012-2013 Xilinx
+ *
+ * CPU idle support for Xilinx Zynq
+ *
+ * based on arch/arm/mach-at91/cpuidle.c
+ *
+ * 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/>.
+ *
+ * The cpu idle uses wait-for-interrupt and RAM self refresh in order
+ * to implement two idle states -
+ * #1 wait-for-interrupt
+ * #2 wait-for-interrupt and RAM self refresh
+ *
+ * Maintainer: Michal Simek <michal.simek@xilinx.com>
+ */
+
+#include <linux/init.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpuidle.h>
+#include <linux/of.h>
+#include <asm/proc-fns.h>
+#include <asm/cpuidle.h>
+
+#define ZYNQ_MAX_STATES 2
+
+/* Actual code that puts the SoC in different idle states */
+static int zynq_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ /* Devices must be stopped here */
+ cpu_pm_enter();
+
+ /* Add code for DDR self refresh start */
+ cpu_do_idle();
+
+ /* Add code for DDR self refresh stop */
+ cpu_pm_exit();
+
+ return index;
+}
+
+static struct cpuidle_driver zynq_idle_driver = {
+ .name = "zynq_idle",
+ .owner = THIS_MODULE,
+ .states = {
+ ARM_CPUIDLE_WFI_STATE,
+ {
+ .enter = zynq_enter_idle,
+ .exit_latency = 10,
+ .target_residency = 10000,
+ .flags = CPUIDLE_FLAG_TIME_VALID |
+ CPUIDLE_FLAG_TIMER_STOP,
+ .name = "RAM_SR",
+ .desc = "WFI and RAM Self Refresh",
+ },
+ },
+ .safe_state_index = 0,
+ .state_count = ZYNQ_MAX_STATES,
+};
+
+/* Initialize CPU idle by registering the idle states */
+static int __init zynq_cpuidle_init(void)
+{
+ if (!of_machine_is_compatible("xlnx,zynq-7000"))
+ return -ENODEV;
+
+ pr_info("Xilinx Zynq CpuIdle Driver started\n");
+
+ return cpuidle_register(&zynq_idle_driver, NULL);
+}
+
+device_initcall(zynq_cpuidle_init);
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index c3a93fece819..fdc432f18022 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -466,7 +466,7 @@ void cpuidle_unregister(struct cpuidle_driver *drv)
int cpu;
struct cpuidle_device *device;
- for_each_possible_cpu(cpu) {
+ for_each_cpu(cpu, drv->cpumask) {
device = &per_cpu(cpuidle_dev, cpu);
cpuidle_unregister_device(device);
}
@@ -498,7 +498,7 @@ int cpuidle_register(struct cpuidle_driver *drv,
return ret;
}
- for_each_possible_cpu(cpu) {
+ for_each_cpu(cpu, drv->cpumask) {
device = &per_cpu(cpuidle_dev, cpu);
device->cpu = cpu;
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index 8dfaaae94444..3ac499d5a207 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -18,182 +18,249 @@
DEFINE_SPINLOCK(cpuidle_driver_lock);
-static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
-static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
+#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
-static void cpuidle_setup_broadcast_timer(void *arg)
+static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
+
+/**
+ * __cpuidle_get_cpu_driver - return the cpuidle driver tied to a CPU.
+ * @cpu: the CPU handled by the driver
+ *
+ * Returns a pointer to struct cpuidle_driver or NULL if no driver has been
+ * registered for @cpu.
+ */
+static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
{
- int cpu = smp_processor_id();
- clockevents_notify((long)(arg), &cpu);
+ return per_cpu(cpuidle_drivers, cpu);
}
-static void __cpuidle_driver_init(struct cpuidle_driver *drv, int cpu)
+/**
+ * __cpuidle_unset_driver - unset per CPU driver variables.
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * For each CPU in the driver's CPU mask, unset the registered driver per CPU
+ * variable. If @drv is different from the registered driver, the corresponding
+ * variable is not cleared.
+ */
+static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
{
- int i;
-
- drv->refcnt = 0;
+ int cpu;
- for (i = drv->state_count - 1; i >= 0 ; i--) {
+ for_each_cpu(cpu, drv->cpumask) {
- if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP))
+ if (drv != __cpuidle_get_cpu_driver(cpu))
continue;
- drv->bctimer = 1;
- on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
- (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
- break;
+ per_cpu(cpuidle_drivers, cpu) = NULL;
}
}
-static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
+/**
+ * __cpuidle_set_driver - set per CPU driver variables the the given driver.
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * For each CPU in the driver's cpumask, unset the registered driver per CPU
+ * to @drv.
+ *
+ * Returns 0 on success, -EBUSY if the CPUs have driver(s) already.
+ */
+static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
{
- if (!drv || !drv->state_count)
- return -EINVAL;
-
- if (cpuidle_disabled())
- return -ENODEV;
+ int cpu;
- if (__cpuidle_get_cpu_driver(cpu))
- return -EBUSY;
+ for_each_cpu(cpu, drv->cpumask) {
- __cpuidle_driver_init(drv, cpu);
+ if (__cpuidle_get_cpu_driver(cpu)) {
+ __cpuidle_unset_driver(drv);
+ return -EBUSY;
+ }
- __cpuidle_set_cpu_driver(drv, cpu);
+ per_cpu(cpuidle_drivers, cpu) = drv;
+ }
return 0;
}
-static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
-{
- if (drv != __cpuidle_get_cpu_driver(cpu))
- return;
+#else
- if (!WARN_ON(drv->refcnt > 0))
- __cpuidle_set_cpu_driver(NULL, cpu);
+static struct cpuidle_driver *cpuidle_curr_driver;
- if (drv->bctimer) {
- drv->bctimer = 0;
- on_each_cpu_mask(get_cpu_mask(cpu), cpuidle_setup_broadcast_timer,
- (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
- }
+/**
+ * __cpuidle_get_cpu_driver - return the global cpuidle driver pointer.
+ * @cpu: ignored without the multiple driver support
+ *
+ * Return a pointer to a struct cpuidle_driver object or NULL if no driver was
+ * previously registered.
+ */
+static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
+{
+ return cpuidle_curr_driver;
}
-#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
+/**
+ * __cpuidle_set_driver - assign the global cpuidle driver variable.
+ * @drv: pointer to a struct cpuidle_driver object
+ *
+ * Returns 0 on success, -EBUSY if the driver is already registered.
+ */
+static inline int __cpuidle_set_driver(struct cpuidle_driver *drv)
+{
+ if (cpuidle_curr_driver)
+ return -EBUSY;
-static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
+ cpuidle_curr_driver = drv;
-static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
-{
- per_cpu(cpuidle_drivers, cpu) = drv;
+ return 0;
}
-static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
+/**
+ * __cpuidle_unset_driver - unset the global cpuidle driver variable.
+ * @drv: a pointer to a struct cpuidle_driver
+ *
+ * Reset the global cpuidle variable to NULL. If @drv does not match the
+ * registered driver, do nothing.
+ */
+static inline void __cpuidle_unset_driver(struct cpuidle_driver *drv)
{
- return per_cpu(cpuidle_drivers, cpu);
+ if (drv == cpuidle_curr_driver)
+ cpuidle_curr_driver = NULL;
}
-static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
+#endif
+
+/**
+ * cpuidle_setup_broadcast_timer - enable/disable the broadcast timer
+ * @arg: a void pointer used to match the SMP cross call API
+ *
+ * @arg is used as a value of type 'long' with on of the two values:
+ * - CLOCK_EVT_NOTIFY_BROADCAST_ON
+ * - CLOCK_EVT_NOTIFY_BROADCAST_OFF
+ *
+ * Set the broadcast timer notification for the current CPU. This function
+ * is executed per CPU by an SMP cross call. It not supposed to be called
+ * directly.
+ */
+static void cpuidle_setup_broadcast_timer(void *arg)
{
- int cpu;
- for_each_present_cpu(cpu)
- __cpuidle_unregister_driver(drv, cpu);
+ int cpu = smp_processor_id();
+ clockevents_notify((long)(arg), &cpu);
}
-static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
+/**
+ * __cpuidle_driver_init - initialize the driver's internal data
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+static int __cpuidle_driver_init(struct cpuidle_driver *drv)
{
- int ret = 0;
- int i, cpu;
+ int i;
- for_each_present_cpu(cpu) {
- ret = __cpuidle_register_driver(drv, cpu);
- if (ret)
- break;
- }
+ drv->refcnt = 0;
- if (ret)
- for_each_present_cpu(i) {
- if (i == cpu)
- break;
- __cpuidle_unregister_driver(drv, i);
- }
+ /*
+ * Use all possible CPUs as the default, because if the kernel boots
+ * with some CPUs offline and then we online one of them, the CPU
+ * notifier has to know which driver to assign.
+ */
+ if (!drv->cpumask)
+ drv->cpumask = (struct cpumask *)cpu_possible_mask;
+
+ /*
+ * Look for the timer stop flag in the different states, so that we know
+ * if the broadcast timer has to be set up. The loop is in the reverse
+ * order, because usually on of the the deeper states has this flag set.
+ */
+ for (i = drv->state_count - 1; i >= 0 ; i--) {
+ if (!(drv->states[i].flags & CPUIDLE_FLAG_TIMER_STOP))
+ continue;
- return ret;
+ drv->bctimer = 1;
+ break;
+ }
+
+ return 0;
}
-int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
+/**
+ * __cpuidle_register_driver: register the driver
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * Do some sanity checks, initialize the driver, assign the driver to the
+ * global cpuidle driver variable(s) and set up the broadcast timer if the
+ * cpuidle driver has some states that shut down the local timer.
+ *
+ * Returns 0 on success, a negative error code otherwise:
+ * * -EINVAL if the driver pointer is NULL or no idle states are available
+ * * -ENODEV if the cpuidle framework is disabled
+ * * -EBUSY if the driver is already assigned to the global variable(s)
+ */
+static int __cpuidle_register_driver(struct cpuidle_driver *drv)
{
int ret;
- spin_lock(&cpuidle_driver_lock);
- ret = __cpuidle_register_driver(drv, cpu);
- spin_unlock(&cpuidle_driver_lock);
+ if (!drv || !drv->state_count)
+ return -EINVAL;
- return ret;
-}
+ if (cpuidle_disabled())
+ return -ENODEV;
-void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
-{
- spin_lock(&cpuidle_driver_lock);
- __cpuidle_unregister_driver(drv, cpu);
- spin_unlock(&cpuidle_driver_lock);
-}
+ ret = __cpuidle_driver_init(drv);
+ if (ret)
+ return ret;
-/**
- * cpuidle_register_driver - registers a driver
- * @drv: the driver
- */
-int cpuidle_register_driver(struct cpuidle_driver *drv)
-{
- int ret;
+ ret = __cpuidle_set_driver(drv);
+ if (ret)
+ return ret;
- spin_lock(&cpuidle_driver_lock);
- ret = __cpuidle_register_all_cpu_driver(drv);
- spin_unlock(&cpuidle_driver_lock);
+ if (drv->bctimer)
+ on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
+ (void *)CLOCK_EVT_NOTIFY_BROADCAST_ON, 1);
- return ret;
+ return 0;
}
-EXPORT_SYMBOL_GPL(cpuidle_register_driver);
/**
- * cpuidle_unregister_driver - unregisters a driver
- * @drv: the driver
+ * __cpuidle_unregister_driver - unregister the driver
+ * @drv: a valid pointer to a struct cpuidle_driver
+ *
+ * Check if the driver is no longer in use, reset the global cpuidle driver
+ * variable(s) and disable the timer broadcast notification mechanism if it was
+ * in use.
+ *
*/
-void cpuidle_unregister_driver(struct cpuidle_driver *drv)
+static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
{
- spin_lock(&cpuidle_driver_lock);
- __cpuidle_unregister_all_cpu_driver(drv);
- spin_unlock(&cpuidle_driver_lock);
-}
-EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
-
-#else
-
-static struct cpuidle_driver *cpuidle_curr_driver;
+ if (WARN_ON(drv->refcnt > 0))
+ return;
-static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
-{
- cpuidle_curr_driver = drv;
-}
+ if (drv->bctimer) {
+ drv->bctimer = 0;
+ on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
+ (void *)CLOCK_EVT_NOTIFY_BROADCAST_OFF, 1);
+ }
-static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
-{
- return cpuidle_curr_driver;
+ __cpuidle_unset_driver(drv);
}
/**
* cpuidle_register_driver - registers a driver
- * @drv: the driver
+ * @drv: a pointer to a valid struct cpuidle_driver
+ *
+ * Register the driver under a lock to prevent concurrent attempts to
+ * [un]register the driver from occuring at the same time.
+ *
+ * Returns 0 on success, a negative error code (returned by
+ * __cpuidle_register_driver()) otherwise.
*/
int cpuidle_register_driver(struct cpuidle_driver *drv)
{
- int ret, cpu;
+ int ret;
- cpu = get_cpu();
spin_lock(&cpuidle_driver_lock);
- ret = __cpuidle_register_driver(drv, cpu);
+ ret = __cpuidle_register_driver(drv);
spin_unlock(&cpuidle_driver_lock);
- put_cpu();
return ret;
}
@@ -201,23 +268,24 @@ EXPORT_SYMBOL_GPL(cpuidle_register_driver);
/**
* cpuidle_unregister_driver - unregisters a driver
- * @drv: the driver
+ * @drv: a pointer to a valid struct cpuidle_driver
+ *
+ * Unregisters the cpuidle driver under a lock to prevent concurrent attempts
+ * to [un]register the driver from occuring at the same time. @drv has to
+ * match the currently registered driver.
*/
void cpuidle_unregister_driver(struct cpuidle_driver *drv)
{
- int cpu;
-
- cpu = get_cpu();
spin_lock(&cpuidle_driver_lock);
- __cpuidle_unregister_driver(drv, cpu);
+ __cpuidle_unregister_driver(drv);
spin_unlock(&cpuidle_driver_lock);
- put_cpu();
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
-#endif
/**
- * cpuidle_get_driver - return the current driver
+ * cpuidle_get_driver - return the driver tied to the current CPU.
+ *
+ * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered.
*/
struct cpuidle_driver *cpuidle_get_driver(void)
{
@@ -233,7 +301,11 @@ struct cpuidle_driver *cpuidle_get_driver(void)
EXPORT_SYMBOL_GPL(cpuidle_get_driver);
/**
- * cpuidle_get_cpu_driver - return the driver tied with a cpu
+ * cpuidle_get_cpu_driver - return the driver registered for a CPU.
+ * @dev: a valid pointer to a struct cpuidle_device
+ *
+ * Returns a struct cpuidle_driver pointer, or NULL if no driver is registered
+ * for the CPU associated with @dev.
*/
struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
{
@@ -244,6 +316,14 @@ struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
}
EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
+/**
+ * cpuidle_driver_ref - get a reference to the driver.
+ *
+ * Increment the reference counter of the cpuidle driver associated with
+ * the current CPU.
+ *
+ * Returns a pointer to the driver, or NULL if the current CPU has no driver.
+ */
struct cpuidle_driver *cpuidle_driver_ref(void)
{
struct cpuidle_driver *drv;
@@ -257,6 +337,12 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
return drv;
}
+/**
+ * cpuidle_driver_unref - puts down the refcount for the driver
+ *
+ * Decrement the reference counter of the cpuidle driver associated with
+ * the current CPU.
+ */
void cpuidle_driver_unref(void)
{
struct cpuidle_driver *drv = cpuidle_get_driver();
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index dffb85525368..8ff7c230d82e 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -278,7 +278,7 @@ config CRYPTO_DEV_PICOXCELL
config CRYPTO_DEV_SAHARA
tristate "Support for SAHARA crypto accelerator"
- depends on ARCH_MXC && EXPERIMENTAL && OF
+ depends on ARCH_MXC && OF
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
@@ -286,6 +286,16 @@ config CRYPTO_DEV_SAHARA
This option enables support for the SAHARA HW crypto accelerator
found in some Freescale i.MX chips.
+config CRYPTO_DEV_DCP
+ tristate "Support for the DCP engine"
+ depends on ARCH_MXS && OF
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_AES
+ select CRYPTO_CBC
+ help
+ This options enables support for the hardware crypto-acceleration
+ capabilities of the DCP co-processor
+
config CRYPTO_DEV_S5P
tristate "Support for Samsung S5PV210 crypto accelerator"
depends on ARCH_S5PV210
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 38ce13d3b79b..b4946ddd2550 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
+obj-$(CONFIG_CRYPTO_DEV_DCP) += dcp.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 6e94bcd94678..f5d6deced1cb 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -202,6 +202,7 @@ static int caam_probe(struct platform_device *pdev)
#ifdef CONFIG_DEBUG_FS
struct caam_perfmon *perfmon;
#endif
+ u64 cha_vid;
ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL);
if (!ctrlpriv)
@@ -293,11 +294,14 @@ static int caam_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ cha_vid = rd_reg64(&topregs->ctrl.perfmon.cha_id);
+
/*
- * RNG4 based SECs (v5+) need special initialization prior
- * to executing any descriptors
+ * If SEC has RNG version >= 4 and RNG state handle has not been
+ * already instantiated ,do RNG instantiation
*/
- if (of_device_is_compatible(nprop, "fsl,sec-v5.0")) {
+ if ((cha_vid & CHA_ID_RNG_MASK) >> CHA_ID_RNG_SHIFT >= 4 &&
+ !(rd_reg32(&topregs->ctrl.r4tst[0].rdsta) & RDSTA_IF0)) {
kick_trng(pdev);
ret = instantiate_rng(ctrlpriv->jrdev[0]);
if (ret) {
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
index f7f833be8c67..53b296f78b0d 100644
--- a/drivers/crypto/caam/desc.h
+++ b/drivers/crypto/caam/desc.h
@@ -231,7 +231,12 @@ struct sec4_sg_entry {
#define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT)
#define LDST_SRCDST_WORD_PKHA_N_SZ (0x12 << LDST_SRCDST_SHIFT)
#define LDST_SRCDST_WORD_PKHA_E_SZ (0x13 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_CLASS_CTX (0x20 << LDST_SRCDST_SHIFT)
#define LDST_SRCDST_WORD_DESCBUF (0x40 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DESCBUF_JOB (0x41 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DESCBUF_SHARED (0x42 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DESCBUF_JOB_WE (0x45 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DESCBUF_SHARED_WE (0x46 << LDST_SRCDST_SHIFT)
#define LDST_SRCDST_WORD_INFO_FIFO (0x7a << LDST_SRCDST_SHIFT)
/* Offset in source/destination */
@@ -366,6 +371,7 @@ struct sec4_sg_entry {
#define FIFOLD_TYPE_LAST2FLUSH1 (0x05 << FIFOLD_TYPE_SHIFT)
#define FIFOLD_TYPE_LASTBOTH (0x06 << FIFOLD_TYPE_SHIFT)
#define FIFOLD_TYPE_LASTBOTHFL (0x07 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_NOINFOFIFO (0x0F << FIFOLD_TYPE_SHIFT)
#define FIFOLDST_LEN_MASK 0xffff
#define FIFOLDST_EXT_LEN_MASK 0xffffffff
@@ -1294,10 +1300,10 @@ struct sec4_sg_entry {
#define SQOUT_SGF 0x01000000
/* Appends to a previous pointer */
-#define SQOUT_PRE 0x00800000
+#define SQOUT_PRE SQIN_PRE
/* Restore sequence with pointer/length */
-#define SQOUT_RTO 0x00200000
+#define SQOUT_RTO SQIN_RTO
/* Use extended length following pointer */
#define SQOUT_EXT 0x00400000
@@ -1359,6 +1365,7 @@ struct sec4_sg_entry {
#define MOVE_DEST_MATH3 (0x07 << MOVE_DEST_SHIFT)
#define MOVE_DEST_CLASS1INFIFO (0x08 << MOVE_DEST_SHIFT)
#define MOVE_DEST_CLASS2INFIFO (0x09 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_INFIFO_NOINFO (0x0a << MOVE_DEST_SHIFT)
#define MOVE_DEST_PK_A (0x0c << MOVE_DEST_SHIFT)
#define MOVE_DEST_CLASS1KEY (0x0d << MOVE_DEST_SHIFT)
#define MOVE_DEST_CLASS2KEY (0x0e << MOVE_DEST_SHIFT)
@@ -1411,6 +1418,7 @@ struct sec4_sg_entry {
#define MATH_SRC0_REG2 (0x02 << MATH_SRC0_SHIFT)
#define MATH_SRC0_REG3 (0x03 << MATH_SRC0_SHIFT)
#define MATH_SRC0_IMM (0x04 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_DPOVRD (0x07 << MATH_SRC0_SHIFT)
#define MATH_SRC0_SEQINLEN (0x08 << MATH_SRC0_SHIFT)
#define MATH_SRC0_SEQOUTLEN (0x09 << MATH_SRC0_SHIFT)
#define MATH_SRC0_VARSEQINLEN (0x0a << MATH_SRC0_SHIFT)
@@ -1425,6 +1433,7 @@ struct sec4_sg_entry {
#define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT)
#define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT)
#define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_DPOVRD (0x07 << MATH_SRC0_SHIFT)
#define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT)
#define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT)
#define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT)
@@ -1600,4 +1609,13 @@ struct sec4_sg_entry {
#define NFIFOENTRY_PLEN_SHIFT 0
#define NFIFOENTRY_PLEN_MASK (0xFF << NFIFOENTRY_PLEN_SHIFT)
+/* Append Load Immediate Command */
+#define FD_CMD_APPEND_LOAD_IMMEDIATE 0x80000000
+
+/* Set SEQ LIODN equal to the Non-SEQ LIODN for the job */
+#define FD_CMD_SET_SEQ_LIODN_EQUAL_NONSEQ_LIODN 0x40000000
+
+/* Frame Descriptor Command for Replacement Job Descriptor */
+#define FD_CMD_REPLACE_JOB_DESC 0x20000000
+
#endif /* DESC_H */
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index c85c1f058401..fe3bfd1b08ca 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -110,6 +110,26 @@ static inline void append_cmd(u32 *desc, u32 command)
(*desc)++;
}
+#define append_u32 append_cmd
+
+static inline void append_u64(u32 *desc, u64 data)
+{
+ u32 *offset = desc_end(desc);
+
+ *offset = upper_32_bits(data);
+ *(++offset) = lower_32_bits(data);
+
+ (*desc) += 2;
+}
+
+/* Write command without affecting header, and return pointer to next word */
+static inline u32 *write_cmd(u32 *desc, u32 command)
+{
+ *desc = command;
+
+ return desc + 1;
+}
+
static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
u32 command)
{
@@ -122,7 +142,8 @@ static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr,
unsigned int len, u32 command)
{
append_cmd(desc, command);
- append_ptr(desc, ptr);
+ if (!(command & (SQIN_RTO | SQIN_PRE)))
+ append_ptr(desc, ptr);
append_cmd(desc, len);
}
@@ -176,17 +197,36 @@ static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \
}
APPEND_CMD_PTR(key, KEY)
APPEND_CMD_PTR(load, LOAD)
-APPEND_CMD_PTR(store, STORE)
APPEND_CMD_PTR(fifo_load, FIFO_LOAD)
APPEND_CMD_PTR(fifo_store, FIFO_STORE)
+static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len,
+ u32 options)
+{
+ u32 cmd_src;
+
+ cmd_src = options & LDST_SRCDST_MASK;
+
+ append_cmd(desc, CMD_STORE | options | len);
+
+ /* The following options do not require pointer */
+ if (!(cmd_src == LDST_SRCDST_WORD_DESCBUF_SHARED ||
+ cmd_src == LDST_SRCDST_WORD_DESCBUF_JOB ||
+ cmd_src == LDST_SRCDST_WORD_DESCBUF_JOB_WE ||
+ cmd_src == LDST_SRCDST_WORD_DESCBUF_SHARED_WE))
+ append_ptr(desc, ptr);
+}
+
#define APPEND_SEQ_PTR_INTLEN(cmd, op) \
static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \
unsigned int len, \
u32 options) \
{ \
PRINT_POS; \
- append_cmd_ptr(desc, ptr, len, CMD_SEQ_##op##_PTR | options); \
+ if (options & (SQIN_RTO | SQIN_PRE)) \
+ append_cmd(desc, CMD_SEQ_##op##_PTR | len | options); \
+ else \
+ append_cmd_ptr(desc, ptr, len, CMD_SEQ_##op##_PTR | options); \
}
APPEND_SEQ_PTR_INTLEN(in, IN)
APPEND_SEQ_PTR_INTLEN(out, OUT)
@@ -259,7 +299,7 @@ APPEND_CMD_RAW_IMM(load, LOAD, u32);
*/
#define APPEND_MATH(op, desc, dest, src_0, src_1, len) \
append_cmd(desc, CMD_MATH | MATH_FUN_##op | MATH_DEST_##dest | \
- MATH_SRC0_##src_0 | MATH_SRC1_##src_1 | (u32) (len & MATH_LEN_MASK));
+ MATH_SRC0_##src_0 | MATH_SRC1_##src_1 | (u32)len);
#define append_math_add(desc, dest, src0, src1, len) \
APPEND_MATH(ADD, desc, dest, src0, src1, len)
@@ -279,6 +319,8 @@ append_cmd(desc, CMD_MATH | MATH_FUN_##op | MATH_DEST_##dest | \
APPEND_MATH(LSHIFT, desc, dest, src0, src1, len)
#define append_math_rshift(desc, dest, src0, src1, len) \
APPEND_MATH(RSHIFT, desc, dest, src0, src1, len)
+#define append_math_ldshift(desc, dest, src0, src1, len) \
+ APPEND_MATH(SHLD, desc, dest, src0, src1, len)
/* Exactly one source is IMM. Data is passed in as u32 value */
#define APPEND_MATH_IMM_u32(op, desc, dest, src_0, src_1, data) \
@@ -305,3 +347,34 @@ do { \
APPEND_MATH_IMM_u32(LSHIFT, desc, dest, src0, src1, data)
#define append_math_rshift_imm_u32(desc, dest, src0, src1, data) \
APPEND_MATH_IMM_u32(RSHIFT, desc, dest, src0, src1, data)
+
+/* Exactly one source is IMM. Data is passed in as u64 value */
+#define APPEND_MATH_IMM_u64(op, desc, dest, src_0, src_1, data) \
+do { \
+ u32 upper = (data >> 16) >> 16; \
+ APPEND_MATH(op, desc, dest, src_0, src_1, CAAM_CMD_SZ * 2 | \
+ (upper ? 0 : MATH_IFB)); \
+ if (upper) \
+ append_u64(desc, data); \
+ else \
+ append_u32(desc, data); \
+} while (0)
+
+#define append_math_add_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(ADD, desc, dest, src0, src1, data)
+#define append_math_sub_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(SUB, desc, dest, src0, src1, data)
+#define append_math_add_c_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(ADDC, desc, dest, src0, src1, data)
+#define append_math_sub_b_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(SUBB, desc, dest, src0, src1, data)
+#define append_math_and_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(AND, desc, dest, src0, src1, data)
+#define append_math_or_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(OR, desc, dest, src0, src1, data)
+#define append_math_xor_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(XOR, desc, dest, src0, src1, data)
+#define append_math_lshift_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(LSHIFT, desc, dest, src0, src1, data)
+#define append_math_rshift_imm_u64(desc, dest, src0, src1, data) \
+ APPEND_MATH_IMM_u64(RSHIFT, desc, dest, src0, src1, data)
diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h
index 62950d22ac13..3a87c0cf879a 100644
--- a/drivers/crypto/caam/pdb.h
+++ b/drivers/crypto/caam/pdb.h
@@ -44,6 +44,7 @@
#define PDBOPTS_ESP_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */
#define PDBOPTS_ESP_INCIPHDR 0x04 /* Prepend IP header to output frame */
#define PDBOPTS_ESP_IPVSN 0x02 /* process IPv6 header */
+#define PDBOPTS_ESP_AOFL 0x04 /* adjust out frame len (decap, SEC>=5.3)*/
#define PDBOPTS_ESP_TUNNEL 0x01 /* tunnel mode next-header byte */
#define PDBOPTS_ESP_IPV6 0x02 /* ip header version is V6 */
#define PDBOPTS_ESP_DIFFSERV 0x40 /* copy TOS/TC from inner iphdr */
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
index cd6fedad9935..c09142fc13e3 100644
--- a/drivers/crypto/caam/regs.h
+++ b/drivers/crypto/caam/regs.h
@@ -117,6 +117,43 @@ struct jr_outentry {
#define CHA_NUM_DECONUM_SHIFT 56
#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT)
+/* CHA Version IDs */
+#define CHA_ID_AES_SHIFT 0
+#define CHA_ID_AES_MASK (0xfull << CHA_ID_AES_SHIFT)
+
+#define CHA_ID_DES_SHIFT 4
+#define CHA_ID_DES_MASK (0xfull << CHA_ID_DES_SHIFT)
+
+#define CHA_ID_ARC4_SHIFT 8
+#define CHA_ID_ARC4_MASK (0xfull << CHA_ID_ARC4_SHIFT)
+
+#define CHA_ID_MD_SHIFT 12
+#define CHA_ID_MD_MASK (0xfull << CHA_ID_MD_SHIFT)
+
+#define CHA_ID_RNG_SHIFT 16
+#define CHA_ID_RNG_MASK (0xfull << CHA_ID_RNG_SHIFT)
+
+#define CHA_ID_SNW8_SHIFT 20
+#define CHA_ID_SNW8_MASK (0xfull << CHA_ID_SNW8_SHIFT)
+
+#define CHA_ID_KAS_SHIFT 24
+#define CHA_ID_KAS_MASK (0xfull << CHA_ID_KAS_SHIFT)
+
+#define CHA_ID_PK_SHIFT 28
+#define CHA_ID_PK_MASK (0xfull << CHA_ID_PK_SHIFT)
+
+#define CHA_ID_CRC_SHIFT 32
+#define CHA_ID_CRC_MASK (0xfull << CHA_ID_CRC_SHIFT)
+
+#define CHA_ID_SNW9_SHIFT 36
+#define CHA_ID_SNW9_MASK (0xfull << CHA_ID_SNW9_SHIFT)
+
+#define CHA_ID_DECO_SHIFT 56
+#define CHA_ID_DECO_MASK (0xfull << CHA_ID_DECO_SHIFT)
+
+#define CHA_ID_JR_SHIFT 60
+#define CHA_ID_JR_MASK (0xfull << CHA_ID_JR_SHIFT)
+
struct sec_vid {
u16 ip_id;
u8 maj_rev;
@@ -228,7 +265,10 @@ struct rng4tst {
u32 rtfrqmax; /* PRGM=1: freq. count max. limit register */
u32 rtfrqcnt; /* PRGM=0: freq. count register */
};
- u32 rsvd1[56];
+ u32 rsvd1[40];
+#define RDSTA_IF0 0x00000001
+ u32 rdsta;
+ u32 rsvd2[15];
};
/*
diff --git a/drivers/crypto/dcp.c b/drivers/crypto/dcp.c
new file mode 100644
index 000000000000..a8a7dd4b0d25
--- /dev/null
+++ b/drivers/crypto/dcp.c
@@ -0,0 +1,912 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for DCP cryptographic accelerator.
+ *
+ * Copyright (c) 2013
+ * Author: Tobias Rauter <tobias.rauter@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.
+ *
+ * Based on tegra-aes.c, dcp.c (from freescale SDK) and sahara.c
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/crypto.h>
+#include <linux/miscdevice.h>
+
+#include <crypto/scatterwalk.h>
+#include <crypto/aes.h>
+
+
+/* IOCTL for DCP OTP Key AES - taken from Freescale's SDK*/
+#define DBS_IOCTL_BASE 'd'
+#define DBS_ENC _IOW(DBS_IOCTL_BASE, 0x00, uint8_t[16])
+#define DBS_DEC _IOW(DBS_IOCTL_BASE, 0x01, uint8_t[16])
+
+/* DCP channel used for AES */
+#define USED_CHANNEL 1
+/* Ring Buffers' maximum size */
+#define DCP_MAX_PKG 20
+
+/* Control Register */
+#define DCP_REG_CTRL 0x000
+#define DCP_CTRL_SFRST (1<<31)
+#define DCP_CTRL_CLKGATE (1<<30)
+#define DCP_CTRL_CRYPTO_PRESENT (1<<29)
+#define DCP_CTRL_SHA_PRESENT (1<<28)
+#define DCP_CTRL_GATHER_RES_WRITE (1<<23)
+#define DCP_CTRL_ENABLE_CONTEXT_CACHE (1<<22)
+#define DCP_CTRL_ENABLE_CONTEXT_SWITCH (1<<21)
+#define DCP_CTRL_CH_IRQ_E_0 0x01
+#define DCP_CTRL_CH_IRQ_E_1 0x02
+#define DCP_CTRL_CH_IRQ_E_2 0x04
+#define DCP_CTRL_CH_IRQ_E_3 0x08
+
+/* Status register */
+#define DCP_REG_STAT 0x010
+#define DCP_STAT_OTP_KEY_READY (1<<28)
+#define DCP_STAT_CUR_CHANNEL(stat) ((stat>>24)&0x0F)
+#define DCP_STAT_READY_CHANNEL(stat) ((stat>>16)&0x0F)
+#define DCP_STAT_IRQ(stat) (stat&0x0F)
+#define DCP_STAT_CHAN_0 (0x01)
+#define DCP_STAT_CHAN_1 (0x02)
+#define DCP_STAT_CHAN_2 (0x04)
+#define DCP_STAT_CHAN_3 (0x08)
+
+/* Channel Control Register */
+#define DCP_REG_CHAN_CTRL 0x020
+#define DCP_CHAN_CTRL_CH0_IRQ_MERGED (1<<16)
+#define DCP_CHAN_CTRL_HIGH_PRIO_0 (0x0100)
+#define DCP_CHAN_CTRL_HIGH_PRIO_1 (0x0200)
+#define DCP_CHAN_CTRL_HIGH_PRIO_2 (0x0400)
+#define DCP_CHAN_CTRL_HIGH_PRIO_3 (0x0800)
+#define DCP_CHAN_CTRL_ENABLE_0 (0x01)
+#define DCP_CHAN_CTRL_ENABLE_1 (0x02)
+#define DCP_CHAN_CTRL_ENABLE_2 (0x04)
+#define DCP_CHAN_CTRL_ENABLE_3 (0x08)
+
+/*
+ * Channel Registers:
+ * The DCP has 4 channels. Each of this channels
+ * has 4 registers (command pointer, semaphore, status and options).
+ * The address of register REG of channel CHAN is obtained by
+ * dcp_chan_reg(REG, CHAN)
+ */
+#define DCP_REG_CHAN_PTR 0x00000100
+#define DCP_REG_CHAN_SEMA 0x00000110
+#define DCP_REG_CHAN_STAT 0x00000120
+#define DCP_REG_CHAN_OPT 0x00000130
+
+#define DCP_CHAN_STAT_NEXT_CHAIN_IS_0 0x010000
+#define DCP_CHAN_STAT_NO_CHAIN 0x020000
+#define DCP_CHAN_STAT_CONTEXT_ERROR 0x030000
+#define DCP_CHAN_STAT_PAYLOAD_ERROR 0x040000
+#define DCP_CHAN_STAT_INVALID_MODE 0x050000
+#define DCP_CHAN_STAT_PAGEFAULT 0x40
+#define DCP_CHAN_STAT_DST 0x20
+#define DCP_CHAN_STAT_SRC 0x10
+#define DCP_CHAN_STAT_PACKET 0x08
+#define DCP_CHAN_STAT_SETUP 0x04
+#define DCP_CHAN_STAT_MISMATCH 0x02
+
+/* hw packet control*/
+
+#define DCP_PKT_PAYLOAD_KEY (1<<11)
+#define DCP_PKT_OTP_KEY (1<<10)
+#define DCP_PKT_CIPHER_INIT (1<<9)
+#define DCP_PKG_CIPHER_ENCRYPT (1<<8)
+#define DCP_PKT_CIPHER_ENABLE (1<<5)
+#define DCP_PKT_DECR_SEM (1<<1)
+#define DCP_PKT_CHAIN (1<<2)
+#define DCP_PKT_IRQ 1
+
+#define DCP_PKT_MODE_CBC (1<<4)
+#define DCP_PKT_KEYSELECT_OTP (0xFF<<8)
+
+/* cipher flags */
+#define DCP_ENC 0x0001
+#define DCP_DEC 0x0002
+#define DCP_ECB 0x0004
+#define DCP_CBC 0x0008
+#define DCP_CBC_INIT 0x0010
+#define DCP_NEW_KEY 0x0040
+#define DCP_OTP_KEY 0x0080
+#define DCP_AES 0x1000
+
+/* DCP Flags */
+#define DCP_FLAG_BUSY 0x01
+#define DCP_FLAG_PRODUCING 0x02
+
+/* clock defines */
+#define CLOCK_ON 1
+#define CLOCK_OFF 0
+
+struct dcp_dev_req_ctx {
+ int mode;
+};
+
+struct dcp_op {
+ unsigned int flags;
+ u8 key[AES_KEYSIZE_128];
+ int keylen;
+
+ struct ablkcipher_request *req;
+ struct crypto_ablkcipher *fallback;
+
+ uint32_t stat;
+ uint32_t pkt1;
+ uint32_t pkt2;
+ struct ablkcipher_walk walk;
+};
+
+struct dcp_dev {
+ struct device *dev;
+ void __iomem *dcp_regs_base;
+
+ int dcp_vmi_irq;
+ int dcp_irq;
+
+ spinlock_t queue_lock;
+ struct crypto_queue queue;
+
+ uint32_t pkt_produced;
+ uint32_t pkt_consumed;
+
+ struct dcp_hw_packet *hw_pkg[DCP_MAX_PKG];
+ dma_addr_t hw_phys_pkg;
+
+ /* [KEY][IV] Both with 16 Bytes */
+ u8 *payload_base;
+ dma_addr_t payload_base_dma;
+
+
+ struct tasklet_struct done_task;
+ struct tasklet_struct queue_task;
+ struct timer_list watchdog;
+
+ unsigned long flags;
+
+ struct dcp_op *ctx;
+
+ struct miscdevice dcp_bootstream_misc;
+};
+
+struct dcp_hw_packet {
+ uint32_t next;
+ uint32_t pkt1;
+ uint32_t pkt2;
+ uint32_t src;
+ uint32_t dst;
+ uint32_t size;
+ uint32_t payload;
+ uint32_t stat;
+};
+
+static struct dcp_dev *global_dev;
+
+static inline u32 dcp_chan_reg(u32 reg, int chan)
+{
+ return reg + (chan) * 0x40;
+}
+
+static inline void dcp_write(struct dcp_dev *dev, u32 data, u32 reg)
+{
+ writel(data, dev->dcp_regs_base + reg);
+}
+
+static inline void dcp_set(struct dcp_dev *dev, u32 data, u32 reg)
+{
+ writel(data, dev->dcp_regs_base + (reg | 0x04));
+}
+
+static inline void dcp_clear(struct dcp_dev *dev, u32 data, u32 reg)
+{
+ writel(data, dev->dcp_regs_base + (reg | 0x08));
+}
+
+static inline void dcp_toggle(struct dcp_dev *dev, u32 data, u32 reg)
+{
+ writel(data, dev->dcp_regs_base + (reg | 0x0C));
+}
+
+static inline unsigned int dcp_read(struct dcp_dev *dev, u32 reg)
+{
+ return readl(dev->dcp_regs_base + reg);
+}
+
+static void dcp_dma_unmap(struct dcp_dev *dev, struct dcp_hw_packet *pkt)
+{
+ dma_unmap_page(dev->dev, pkt->src, pkt->size, DMA_TO_DEVICE);
+ dma_unmap_page(dev->dev, pkt->dst, pkt->size, DMA_FROM_DEVICE);
+ dev_dbg(dev->dev, "unmap packet %x", (unsigned int) pkt);
+}
+
+static int dcp_dma_map(struct dcp_dev *dev,
+ struct ablkcipher_walk *walk, struct dcp_hw_packet *pkt)
+{
+ dev_dbg(dev->dev, "map packet %x", (unsigned int) pkt);
+ /* align to length = 16 */
+ pkt->size = walk->nbytes - (walk->nbytes % 16);
+
+ pkt->src = dma_map_page(dev->dev, walk->src.page, walk->src.offset,
+ pkt->size, DMA_TO_DEVICE);
+
+ if (pkt->src == 0) {
+ dev_err(dev->dev, "Unable to map src");
+ return -ENOMEM;
+ }
+
+ pkt->dst = dma_map_page(dev->dev, walk->dst.page, walk->dst.offset,
+ pkt->size, DMA_FROM_DEVICE);
+
+ if (pkt->dst == 0) {
+ dev_err(dev->dev, "Unable to map dst");
+ dma_unmap_page(dev->dev, pkt->src, pkt->size, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void dcp_op_one(struct dcp_dev *dev, struct dcp_hw_packet *pkt,
+ uint8_t last)
+{
+ struct dcp_op *ctx = dev->ctx;
+ pkt->pkt1 = ctx->pkt1;
+ pkt->pkt2 = ctx->pkt2;
+
+ pkt->payload = (u32) dev->payload_base_dma;
+ pkt->stat = 0;
+
+ if (ctx->flags & DCP_CBC_INIT) {
+ pkt->pkt1 |= DCP_PKT_CIPHER_INIT;
+ ctx->flags &= ~DCP_CBC_INIT;
+ }
+
+ mod_timer(&dev->watchdog, jiffies + msecs_to_jiffies(500));
+ pkt->pkt1 |= DCP_PKT_IRQ;
+ if (!last)
+ pkt->pkt1 |= DCP_PKT_CHAIN;
+
+ dev->pkt_produced++;
+
+ dcp_write(dev, 1,
+ dcp_chan_reg(DCP_REG_CHAN_SEMA, USED_CHANNEL));
+}
+
+static void dcp_op_proceed(struct dcp_dev *dev)
+{
+ struct dcp_op *ctx = dev->ctx;
+ struct dcp_hw_packet *pkt;
+
+ while (ctx->walk.nbytes) {
+ int err = 0;
+
+ pkt = dev->hw_pkg[dev->pkt_produced % DCP_MAX_PKG];
+ err = dcp_dma_map(dev, &ctx->walk, pkt);
+ if (err) {
+ dev->ctx->stat |= err;
+ /* start timer to wait for already set up calls */
+ mod_timer(&dev->watchdog,
+ jiffies + msecs_to_jiffies(500));
+ break;
+ }
+
+
+ err = ctx->walk.nbytes - pkt->size;
+ ablkcipher_walk_done(dev->ctx->req, &dev->ctx->walk, err);
+
+ dcp_op_one(dev, pkt, ctx->walk.nbytes == 0);
+ /* we have to wait if no space is left in buffer */
+ if (dev->pkt_produced - dev->pkt_consumed == DCP_MAX_PKG)
+ break;
+ }
+ clear_bit(DCP_FLAG_PRODUCING, &dev->flags);
+}
+
+static void dcp_op_start(struct dcp_dev *dev, uint8_t use_walk)
+{
+ struct dcp_op *ctx = dev->ctx;
+
+ if (ctx->flags & DCP_NEW_KEY) {
+ memcpy(dev->payload_base, ctx->key, ctx->keylen);
+ ctx->flags &= ~DCP_NEW_KEY;
+ }
+
+ ctx->pkt1 = 0;
+ ctx->pkt1 |= DCP_PKT_CIPHER_ENABLE;
+ ctx->pkt1 |= DCP_PKT_DECR_SEM;
+
+ if (ctx->flags & DCP_OTP_KEY)
+ ctx->pkt1 |= DCP_PKT_OTP_KEY;
+ else
+ ctx->pkt1 |= DCP_PKT_PAYLOAD_KEY;
+
+ if (ctx->flags & DCP_ENC)
+ ctx->pkt1 |= DCP_PKG_CIPHER_ENCRYPT;
+
+ ctx->pkt2 = 0;
+ if (ctx->flags & DCP_CBC)
+ ctx->pkt2 |= DCP_PKT_MODE_CBC;
+
+ dev->pkt_produced = 0;
+ dev->pkt_consumed = 0;
+
+ ctx->stat = 0;
+ dcp_clear(dev, -1, dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL));
+ dcp_write(dev, (u32) dev->hw_phys_pkg,
+ dcp_chan_reg(DCP_REG_CHAN_PTR, USED_CHANNEL));
+
+ set_bit(DCP_FLAG_PRODUCING, &dev->flags);
+
+ if (use_walk) {
+ ablkcipher_walk_init(&ctx->walk, ctx->req->dst,
+ ctx->req->src, ctx->req->nbytes);
+ ablkcipher_walk_phys(ctx->req, &ctx->walk);
+ dcp_op_proceed(dev);
+ } else {
+ dcp_op_one(dev, dev->hw_pkg[0], 1);
+ clear_bit(DCP_FLAG_PRODUCING, &dev->flags);
+ }
+}
+
+static void dcp_done_task(unsigned long data)
+{
+ struct dcp_dev *dev = (struct dcp_dev *)data;
+ struct dcp_hw_packet *last_packet;
+ int fin;
+ fin = 0;
+
+ for (last_packet = dev->hw_pkg[(dev->pkt_consumed) % DCP_MAX_PKG];
+ last_packet->stat == 1;
+ last_packet =
+ dev->hw_pkg[++(dev->pkt_consumed) % DCP_MAX_PKG]) {
+
+ dcp_dma_unmap(dev, last_packet);
+ last_packet->stat = 0;
+ fin++;
+ }
+ /* the last call of this function already consumed this IRQ's packet */
+ if (fin == 0)
+ return;
+
+ dev_dbg(dev->dev,
+ "Packet(s) done with status %x; finished: %d, produced:%d, complete consumed: %d",
+ dev->ctx->stat, fin, dev->pkt_produced, dev->pkt_consumed);
+
+ last_packet = dev->hw_pkg[(dev->pkt_consumed - 1) % DCP_MAX_PKG];
+ if (!dev->ctx->stat && last_packet->pkt1 & DCP_PKT_CHAIN) {
+ if (!test_and_set_bit(DCP_FLAG_PRODUCING, &dev->flags))
+ dcp_op_proceed(dev);
+ return;
+ }
+
+ while (unlikely(dev->pkt_consumed < dev->pkt_produced)) {
+ dcp_dma_unmap(dev,
+ dev->hw_pkg[dev->pkt_consumed++ % DCP_MAX_PKG]);
+ }
+
+ if (dev->ctx->flags & DCP_OTP_KEY) {
+ /* we used the miscdevice, no walk to finish */
+ clear_bit(DCP_FLAG_BUSY, &dev->flags);
+ return;
+ }
+
+ ablkcipher_walk_complete(&dev->ctx->walk);
+ dev->ctx->req->base.complete(&dev->ctx->req->base,
+ dev->ctx->stat);
+ dev->ctx->req = NULL;
+ /* in case there are other requests in the queue */
+ tasklet_schedule(&dev->queue_task);
+}
+
+static void dcp_watchdog(unsigned long data)
+{
+ struct dcp_dev *dev = (struct dcp_dev *)data;
+ dev->ctx->stat |= dcp_read(dev,
+ dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL));
+
+ dev_err(dev->dev, "Timeout, Channel status: %x", dev->ctx->stat);
+
+ if (!dev->ctx->stat)
+ dev->ctx->stat = -ETIMEDOUT;
+
+ dcp_done_task(data);
+}
+
+
+static irqreturn_t dcp_common_irq(int irq, void *context)
+{
+ u32 msk;
+ struct dcp_dev *dev = (struct dcp_dev *) context;
+
+ del_timer(&dev->watchdog);
+
+ msk = DCP_STAT_IRQ(dcp_read(dev, DCP_REG_STAT));
+ dcp_clear(dev, msk, DCP_REG_STAT);
+ if (msk == 0)
+ return IRQ_NONE;
+
+ dev->ctx->stat |= dcp_read(dev,
+ dcp_chan_reg(DCP_REG_CHAN_STAT, USED_CHANNEL));
+
+ if (msk & DCP_STAT_CHAN_1)
+ tasklet_schedule(&dev->done_task);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dcp_vmi_irq(int irq, void *context)
+{
+ return dcp_common_irq(irq, context);
+}
+
+static irqreturn_t dcp_irq(int irq, void *context)
+{
+ return dcp_common_irq(irq, context);
+}
+
+static void dcp_crypt(struct dcp_dev *dev, struct dcp_op *ctx)
+{
+ dev->ctx = ctx;
+
+ if ((ctx->flags & DCP_CBC) && ctx->req->info) {
+ ctx->flags |= DCP_CBC_INIT;
+ memcpy(dev->payload_base + AES_KEYSIZE_128,
+ ctx->req->info, AES_KEYSIZE_128);
+ }
+
+ dcp_op_start(dev, 1);
+}
+
+static void dcp_queue_task(unsigned long data)
+{
+ struct dcp_dev *dev = (struct dcp_dev *) data;
+ struct crypto_async_request *async_req, *backlog;
+ struct crypto_ablkcipher *tfm;
+ struct dcp_op *ctx;
+ struct dcp_dev_req_ctx *rctx;
+ struct ablkcipher_request *req;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->queue_lock, flags);
+
+ backlog = crypto_get_backlog(&dev->queue);
+ async_req = crypto_dequeue_request(&dev->queue);
+
+ spin_unlock_irqrestore(&dev->queue_lock, flags);
+
+ if (!async_req)
+ goto ret_nothing_done;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ req = ablkcipher_request_cast(async_req);
+ tfm = crypto_ablkcipher_reqtfm(req);
+ rctx = ablkcipher_request_ctx(req);
+ ctx = crypto_ablkcipher_ctx(tfm);
+
+ if (!req->src || !req->dst)
+ goto ret_nothing_done;
+
+ ctx->flags |= rctx->mode;
+ ctx->req = req;
+
+ dcp_crypt(dev, ctx);
+
+ return;
+
+ret_nothing_done:
+ clear_bit(DCP_FLAG_BUSY, &dev->flags);
+}
+
+
+static int dcp_cra_init(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct dcp_op *ctx = crypto_tfm_ctx(tfm);
+
+ tfm->crt_ablkcipher.reqsize = sizeof(struct dcp_dev_req_ctx);
+
+ ctx->fallback = crypto_alloc_ablkcipher(name, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(ctx->fallback)) {
+ dev_err(global_dev->dev, "Error allocating fallback algo %s\n",
+ name);
+ return PTR_ERR(ctx->fallback);
+ }
+
+ return 0;
+}
+
+static void dcp_cra_exit(struct crypto_tfm *tfm)
+{
+ struct dcp_op *ctx = crypto_tfm_ctx(tfm);
+
+ if (ctx->fallback)
+ crypto_free_ablkcipher(ctx->fallback);
+
+ ctx->fallback = NULL;
+}
+
+/* async interface */
+static int dcp_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int len)
+{
+ struct dcp_op *ctx = crypto_ablkcipher_ctx(tfm);
+ unsigned int ret = 0;
+ ctx->keylen = len;
+ ctx->flags = 0;
+ if (len == AES_KEYSIZE_128) {
+ if (memcmp(ctx->key, key, AES_KEYSIZE_128)) {
+ memcpy(ctx->key, key, len);
+ ctx->flags |= DCP_NEW_KEY;
+ }
+ return 0;
+ }
+
+ ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ ctx->fallback->base.crt_flags |=
+ (tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_ablkcipher_setkey(ctx->fallback, key, len);
+ if (ret) {
+ struct crypto_tfm *tfm_aux = crypto_ablkcipher_tfm(tfm);
+
+ tfm_aux->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ tfm_aux->crt_flags |=
+ (ctx->fallback->base.crt_flags & CRYPTO_TFM_RES_MASK);
+ }
+ return ret;
+}
+
+static int dcp_aes_cbc_crypt(struct ablkcipher_request *req, int mode)
+{
+ struct dcp_dev_req_ctx *rctx = ablkcipher_request_ctx(req);
+ struct dcp_dev *dev = global_dev;
+ unsigned long flags;
+ int err = 0;
+
+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE))
+ return -EINVAL;
+
+ rctx->mode = mode;
+
+ spin_lock_irqsave(&dev->queue_lock, flags);
+ err = ablkcipher_enqueue_request(&dev->queue, req);
+ spin_unlock_irqrestore(&dev->queue_lock, flags);
+
+ flags = test_and_set_bit(DCP_FLAG_BUSY, &dev->flags);
+
+ if (!(flags & DCP_FLAG_BUSY))
+ tasklet_schedule(&dev->queue_task);
+
+ return err;
+}
+
+static int dcp_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+ struct crypto_tfm *tfm =
+ crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
+ struct dcp_op *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+
+ if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
+ int err = 0;
+ ablkcipher_request_set_tfm(req, ctx->fallback);
+ err = crypto_ablkcipher_encrypt(req);
+ ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm));
+ return err;
+ }
+
+ return dcp_aes_cbc_crypt(req, DCP_AES | DCP_ENC | DCP_CBC);
+}
+
+static int dcp_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+ struct crypto_tfm *tfm =
+ crypto_ablkcipher_tfm(crypto_ablkcipher_reqtfm(req));
+ struct dcp_op *ctx = crypto_ablkcipher_ctx(
+ crypto_ablkcipher_reqtfm(req));
+
+ if (unlikely(ctx->keylen != AES_KEYSIZE_128)) {
+ int err = 0;
+ ablkcipher_request_set_tfm(req, ctx->fallback);
+ err = crypto_ablkcipher_decrypt(req);
+ ablkcipher_request_set_tfm(req, __crypto_ablkcipher_cast(tfm));
+ return err;
+ }
+ return dcp_aes_cbc_crypt(req, DCP_AES | DCP_DEC | DCP_CBC);
+}
+
+static struct crypto_alg algs[] = {
+ {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "dcp-cbc-aes",
+ .cra_alignmask = 3,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = AES_KEYSIZE_128,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_priority = 300,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_KEYSIZE_128,
+ .max_keysize = AES_KEYSIZE_128,
+ .setkey = dcp_aes_setkey,
+ .encrypt = dcp_aes_cbc_encrypt,
+ .decrypt = dcp_aes_cbc_decrypt,
+ .ivsize = AES_KEYSIZE_128,
+ }
+
+ },
+};
+
+/* DCP bootstream verification interface: uses OTP key for crypto */
+static int dcp_bootstream_open(struct inode *inode, struct file *file)
+{
+ file->private_data = container_of((file->private_data),
+ struct dcp_dev, dcp_bootstream_misc);
+ return 0;
+}
+
+static long dcp_bootstream_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct dcp_dev *dev = (struct dcp_dev *) file->private_data;
+ void __user *argp = (void __user *)arg;
+ int ret;
+
+ if (dev == NULL)
+ return -EBADF;
+
+ if (cmd != DBS_ENC && cmd != DBS_DEC)
+ return -EINVAL;
+
+ if (copy_from_user(dev->payload_base, argp, 16))
+ return -EFAULT;
+
+ if (test_and_set_bit(DCP_FLAG_BUSY, &dev->flags))
+ return -EAGAIN;
+
+ dev->ctx = kzalloc(sizeof(struct dcp_op), GFP_KERNEL);
+ if (!dev->ctx) {
+ dev_err(dev->dev,
+ "cannot allocate context for OTP crypto");
+ clear_bit(DCP_FLAG_BUSY, &dev->flags);
+ return -ENOMEM;
+ }
+
+ dev->ctx->flags = DCP_AES | DCP_ECB | DCP_OTP_KEY | DCP_CBC_INIT;
+ dev->ctx->flags |= (cmd == DBS_ENC) ? DCP_ENC : DCP_DEC;
+ dev->hw_pkg[0]->src = dev->payload_base_dma;
+ dev->hw_pkg[0]->dst = dev->payload_base_dma;
+ dev->hw_pkg[0]->size = 16;
+
+ dcp_op_start(dev, 0);
+
+ while (test_bit(DCP_FLAG_BUSY, &dev->flags))
+ cpu_relax();
+
+ ret = dev->ctx->stat;
+ if (!ret && copy_to_user(argp, dev->payload_base, 16))
+ ret = -EFAULT;
+
+ kfree(dev->ctx);
+
+ return ret;
+}
+
+static const struct file_operations dcp_bootstream_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = dcp_bootstream_ioctl,
+ .open = dcp_bootstream_open,
+};
+
+static int dcp_probe(struct platform_device *pdev)
+{
+ struct dcp_dev *dev = NULL;
+ struct resource *r;
+ int i, ret, j;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ global_dev = dev;
+ dev->dev = &pdev->dev;
+
+ platform_set_drvdata(pdev, dev);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "failed to get IORESOURCE_MEM\n");
+ return -ENXIO;
+ }
+ dev->dcp_regs_base = devm_ioremap(&pdev->dev, r->start,
+ resource_size(r));
+
+ dcp_set(dev, DCP_CTRL_SFRST, DCP_REG_CTRL);
+ udelay(10);
+ dcp_clear(dev, DCP_CTRL_SFRST | DCP_CTRL_CLKGATE, DCP_REG_CTRL);
+
+ dcp_write(dev, DCP_CTRL_GATHER_RES_WRITE |
+ DCP_CTRL_ENABLE_CONTEXT_CACHE | DCP_CTRL_CH_IRQ_E_1,
+ DCP_REG_CTRL);
+
+ dcp_write(dev, DCP_CHAN_CTRL_ENABLE_1, DCP_REG_CHAN_CTRL);
+
+ for (i = 0; i < 4; i++)
+ dcp_clear(dev, -1, dcp_chan_reg(DCP_REG_CHAN_STAT, i));
+
+ dcp_clear(dev, -1, DCP_REG_STAT);
+
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!r) {
+ dev_err(&pdev->dev, "can't get IRQ resource (0)\n");
+ return -EIO;
+ }
+ dev->dcp_vmi_irq = r->start;
+ ret = request_irq(dev->dcp_vmi_irq, dcp_vmi_irq, 0, "dcp", dev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "can't request_irq (0)\n");
+ return -EIO;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (!r) {
+ dev_err(&pdev->dev, "can't get IRQ resource (1)\n");
+ ret = -EIO;
+ goto err_free_irq0;
+ }
+ dev->dcp_irq = r->start;
+ ret = request_irq(dev->dcp_irq, dcp_irq, 0, "dcp", dev);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "can't request_irq (1)\n");
+ ret = -EIO;
+ goto err_free_irq0;
+ }
+
+ dev->hw_pkg[0] = dma_alloc_coherent(&pdev->dev,
+ DCP_MAX_PKG * sizeof(struct dcp_hw_packet),
+ &dev->hw_phys_pkg,
+ GFP_KERNEL);
+ if (!dev->hw_pkg[0]) {
+ dev_err(&pdev->dev, "Could not allocate hw descriptors\n");
+ ret = -ENOMEM;
+ goto err_free_irq1;
+ }
+
+ for (i = 1; i < DCP_MAX_PKG; i++) {
+ dev->hw_pkg[i - 1]->next = dev->hw_phys_pkg
+ + i * sizeof(struct dcp_hw_packet);
+ dev->hw_pkg[i] = dev->hw_pkg[i - 1] + 1;
+ }
+ dev->hw_pkg[i - 1]->next = dev->hw_phys_pkg;
+
+
+ dev->payload_base = dma_alloc_coherent(&pdev->dev, 2 * AES_KEYSIZE_128,
+ &dev->payload_base_dma, GFP_KERNEL);
+ if (!dev->payload_base) {
+ dev_err(&pdev->dev, "Could not allocate memory for key\n");
+ ret = -ENOMEM;
+ goto err_free_hw_packet;
+ }
+ tasklet_init(&dev->queue_task, dcp_queue_task,
+ (unsigned long) dev);
+ tasklet_init(&dev->done_task, dcp_done_task,
+ (unsigned long) dev);
+ spin_lock_init(&dev->queue_lock);
+
+ crypto_init_queue(&dev->queue, 10);
+
+ init_timer(&dev->watchdog);
+ dev->watchdog.function = &dcp_watchdog;
+ dev->watchdog.data = (unsigned long)dev;
+
+ dev->dcp_bootstream_misc.minor = MISC_DYNAMIC_MINOR,
+ dev->dcp_bootstream_misc.name = "dcpboot",
+ dev->dcp_bootstream_misc.fops = &dcp_bootstream_fops,
+ ret = misc_register(&dev->dcp_bootstream_misc);
+ if (ret != 0) {
+ dev_err(dev->dev, "Unable to register misc device\n");
+ goto err_free_key_iv;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++) {
+ algs[i].cra_priority = 300;
+ algs[i].cra_ctxsize = sizeof(struct dcp_op);
+ algs[i].cra_module = THIS_MODULE;
+ algs[i].cra_init = dcp_cra_init;
+ algs[i].cra_exit = dcp_cra_exit;
+ if (crypto_register_alg(&algs[i])) {
+ dev_err(&pdev->dev, "register algorithm failed\n");
+ ret = -ENOMEM;
+ goto err_unregister;
+ }
+ }
+ dev_notice(&pdev->dev, "DCP crypto enabled.!\n");
+
+ return 0;
+
+err_unregister:
+ for (j = 0; j < i; j++)
+ crypto_unregister_alg(&algs[j]);
+err_free_key_iv:
+ dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base,
+ dev->payload_base_dma);
+err_free_hw_packet:
+ dma_free_coherent(&pdev->dev, DCP_MAX_PKG *
+ sizeof(struct dcp_hw_packet), dev->hw_pkg[0],
+ dev->hw_phys_pkg);
+err_free_irq1:
+ free_irq(dev->dcp_irq, dev);
+err_free_irq0:
+ free_irq(dev->dcp_vmi_irq, dev);
+
+ return ret;
+}
+
+static int dcp_remove(struct platform_device *pdev)
+{
+ struct dcp_dev *dev;
+ int j;
+ dev = platform_get_drvdata(pdev);
+
+ dma_free_coherent(&pdev->dev,
+ DCP_MAX_PKG * sizeof(struct dcp_hw_packet),
+ dev->hw_pkg[0], dev->hw_phys_pkg);
+
+ dma_free_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, dev->payload_base,
+ dev->payload_base_dma);
+
+ free_irq(dev->dcp_irq, dev);
+ free_irq(dev->dcp_vmi_irq, dev);
+
+ tasklet_kill(&dev->done_task);
+ tasklet_kill(&dev->queue_task);
+
+ for (j = 0; j < ARRAY_SIZE(algs); j++)
+ crypto_unregister_alg(&algs[j]);
+
+ misc_deregister(&dev->dcp_bootstream_misc);
+
+ return 0;
+}
+
+static struct of_device_id fs_dcp_of_match[] = {
+ { .compatible = "fsl-dcp"},
+ {},
+};
+
+static struct platform_driver fs_dcp_driver = {
+ .probe = dcp_probe,
+ .remove = dcp_remove,
+ .driver = {
+ .name = "fsl-dcp",
+ .owner = THIS_MODULE,
+ .of_match_table = fs_dcp_of_match
+ }
+};
+
+module_platform_driver(fs_dcp_driver);
+
+
+MODULE_AUTHOR("Tobias Rauter <tobias.rauter@gmail.com>");
+MODULE_DESCRIPTION("Freescale DCP Crypto Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c
index ebf130e894b5..12fea3e22348 100644
--- a/drivers/crypto/hifn_795x.c
+++ b/drivers/crypto/hifn_795x.c
@@ -2676,7 +2676,7 @@ err_out_stop_device:
hifn_reset_dma(dev, 1);
hifn_stop_device(dev);
err_out_free_irq:
- free_irq(dev->irq, dev->name);
+ free_irq(dev->irq, dev);
tasklet_kill(&dev->tasklet);
err_out_free_desc:
pci_free_consistent(pdev, sizeof(struct hifn_dma),
@@ -2711,7 +2711,7 @@ static void hifn_remove(struct pci_dev *pdev)
hifn_reset_dma(dev, 1);
hifn_stop_device(dev);
- free_irq(dev->irq, dev->name);
+ free_irq(dev->irq, dev);
tasklet_kill(&dev->tasklet);
hifn_flush(dev);
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index ce6290e5471a..3374a3ebe4c7 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -1146,7 +1146,6 @@ err_unmap_reg:
err:
kfree(cp);
cpg = NULL;
- platform_set_drvdata(pdev, NULL);
return ret;
}
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index ee15b0f7849a..5f7980586850 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -203,13 +203,6 @@ static void omap_aes_write_n(struct omap_aes_dev *dd, u32 offset,
static int omap_aes_hw_init(struct omap_aes_dev *dd)
{
- /*
- * clocks are enabled when request starts and disabled when finished.
- * It may be long delays between requests.
- * Device might go to off mode to save power.
- */
- pm_runtime_get_sync(dd->dev);
-
if (!(dd->flags & FLAGS_INIT)) {
dd->flags |= FLAGS_INIT;
dd->err = 0;
@@ -636,7 +629,6 @@ static void omap_aes_finish_req(struct omap_aes_dev *dd, int err)
pr_debug("err: %d\n", err);
- pm_runtime_put(dd->dev);
dd->flags &= ~FLAGS_BUSY;
req->base.complete(&req->base, err);
@@ -837,8 +829,16 @@ static int omap_aes_ctr_decrypt(struct ablkcipher_request *req)
static int omap_aes_cra_init(struct crypto_tfm *tfm)
{
- pr_debug("enter\n");
+ struct omap_aes_dev *dd = NULL;
+
+ /* Find AES device, currently picks the first device */
+ spin_lock_bh(&list_lock);
+ list_for_each_entry(dd, &dev_list, list) {
+ break;
+ }
+ spin_unlock_bh(&list_lock);
+ pm_runtime_get_sync(dd->dev);
tfm->crt_ablkcipher.reqsize = sizeof(struct omap_aes_reqctx);
return 0;
@@ -846,7 +846,16 @@ static int omap_aes_cra_init(struct crypto_tfm *tfm)
static void omap_aes_cra_exit(struct crypto_tfm *tfm)
{
- pr_debug("enter\n");
+ struct omap_aes_dev *dd = NULL;
+
+ /* Find AES device, currently picks the first device */
+ spin_lock_bh(&list_lock);
+ list_for_each_entry(dd, &dev_list, list) {
+ break;
+ }
+ spin_unlock_bh(&list_lock);
+
+ pm_runtime_put_sync(dd->dev);
}
/* ********************** ALGS ************************************ */
@@ -1125,10 +1134,9 @@ static int omap_aes_probe(struct platform_device *pdev)
if (err)
goto err_res;
- dd->io_base = devm_request_and_ioremap(dev, &res);
- if (!dd->io_base) {
- dev_err(dev, "can't ioremap\n");
- err = -ENOMEM;
+ dd->io_base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(dd->io_base)) {
+ err = PTR_ERR(dd->io_base);
goto err_res;
}
dd->phys_base = res.start;
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index a1e1b4756ee5..4bb67652c200 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1686,10 +1686,9 @@ static int omap_sham_probe(struct platform_device *pdev)
if (err)
goto res_err;
- dd->io_base = devm_request_and_ioremap(dev, &res);
- if (!dd->io_base) {
- dev_err(dev, "can't ioremap\n");
- err = -ENOMEM;
+ dd->io_base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(dd->io_base)) {
+ err = PTR_ERR(dd->io_base);
goto res_err;
}
dd->phys_base = res.start;
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index ac30724d923d..888f7f4a6d3f 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -1298,7 +1298,7 @@ static ssize_t spacc_stat_irq_thresh_store(struct device *dev,
struct spacc_engine *engine = spacc_dev_to_engine(dev);
unsigned long thresh;
- if (strict_strtoul(buf, 0, &thresh))
+ if (kstrtoul(buf, 0, &thresh))
return -EINVAL;
thresh = clamp(thresh, 1UL, engine->fifo_sz - 1);
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
index 4b314326f48a..cf149b19ff47 100644
--- a/drivers/crypto/s5p-sss.c
+++ b/drivers/crypto/s5p-sss.c
@@ -647,7 +647,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
clk_disable(pdata->clk);
s5p_dev = NULL;
- platform_set_drvdata(pdev, NULL);
return err;
}
@@ -668,7 +667,6 @@ static int s5p_aes_remove(struct platform_device *pdev)
clk_disable(pdata->clk);
s5p_dev = NULL;
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 5b2b5e61e4f9..661dc3eb1d66 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -1112,64 +1112,6 @@ static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained)
return sg_nents;
}
-/**
- * sg_copy_end_to_buffer - Copy end data from SG list to a linear buffer
- * @sgl: The SG list
- * @nents: Number of SG entries
- * @buf: Where to copy to
- * @buflen: The number of bytes to copy
- * @skip: The number of bytes to skip before copying.
- * Note: skip + buflen should equal SG total size.
- *
- * Returns the number of copied bytes.
- *
- **/
-static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents,
- void *buf, size_t buflen, unsigned int skip)
-{
- unsigned int offset = 0;
- unsigned int boffset = 0;
- struct sg_mapping_iter miter;
- unsigned long flags;
- unsigned int sg_flags = SG_MITER_ATOMIC;
- size_t total_buffer = buflen + skip;
-
- sg_flags |= SG_MITER_FROM_SG;
-
- sg_miter_start(&miter, sgl, nents, sg_flags);
-
- local_irq_save(flags);
-
- while (sg_miter_next(&miter) && offset < total_buffer) {
- unsigned int len;
- unsigned int ignore;
-
- if ((offset + miter.length) > skip) {
- if (offset < skip) {
- /* Copy part of this segment */
- ignore = skip - offset;
- len = miter.length - ignore;
- if (boffset + len > buflen)
- len = buflen - boffset;
- memcpy(buf + boffset, miter.addr + ignore, len);
- } else {
- /* Copy all of this segment (up to buflen) */
- len = miter.length;
- if (boffset + len > buflen)
- len = buflen - boffset;
- memcpy(buf + boffset, miter.addr, len);
- }
- boffset += len;
- }
- offset += miter.length;
- }
-
- sg_miter_stop(&miter);
-
- local_irq_restore(flags);
- return boffset;
-}
-
/*
* allocate and map the extended descriptor
*/
@@ -1800,7 +1742,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
if (to_hash_later) {
int nents = sg_count(areq->src, nbytes, &chained);
- sg_copy_end_to_buffer(areq->src, nents,
+ sg_pcopy_to_buffer(areq->src, nents,
req_ctx->bufnext,
to_hash_later,
nbytes - to_hash_later);
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index 83d79b964d12..a999f537228f 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -1629,7 +1629,7 @@ static int ux500_cryp_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
- release_mem_region(res->start, res->end - res->start + 1);
+ release_mem_region(res->start, resource_size(res));
kfree(device_data);
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 0f079be13305..31f3adba4cf3 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -67,7 +67,7 @@ comment "DEVFREQ Drivers"
config ARM_EXYNOS4_BUS_DEVFREQ
bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
- depends on CPU_EXYNOS4210 || CPU_EXYNOS4212 || CPU_EXYNOS4412
+ depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412
select ARCH_HAS_OPP
select DEVFREQ_GOV_SIMPLE_ONDEMAND
help
@@ -78,4 +78,14 @@ config ARM_EXYNOS4_BUS_DEVFREQ
To operate with optimal voltages, ASV support is required
(CONFIG_EXYNOS_ASV).
+config ARM_EXYNOS5_BUS_DEVFREQ
+ bool "ARM Exynos5250 Bus DEVFREQ Driver"
+ depends on SOC_EXYNOS5250
+ select ARCH_HAS_OPP
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ help
+ This adds the DEVFREQ driver for Exynos5250 bus interface (vdd_int).
+ It reads PPMU counters of memory controllers and adjusts the
+ operating frequencies and voltages with OPP support.
+
endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 8c464234f7e7..16138c9e0d58 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
# DEVFREQ Drivers
-obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
+obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/
+obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 3b367973a802..e94e619fe050 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -271,6 +271,7 @@ void devfreq_monitor_suspend(struct devfreq *devfreq)
return;
}
+ devfreq_update_status(devfreq, devfreq->previous_freq);
devfreq->stop_polling = true;
mutex_unlock(&devfreq->lock);
cancel_delayed_work_sync(&devfreq->work);
@@ -287,6 +288,8 @@ EXPORT_SYMBOL(devfreq_monitor_suspend);
*/
void devfreq_monitor_resume(struct devfreq *devfreq)
{
+ unsigned long freq;
+
mutex_lock(&devfreq->lock);
if (!devfreq->stop_polling)
goto out;
@@ -295,8 +298,14 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
devfreq->profile->polling_ms)
queue_delayed_work(devfreq_wq, &devfreq->work,
msecs_to_jiffies(devfreq->profile->polling_ms));
+
+ devfreq->last_stat_updated = jiffies;
devfreq->stop_polling = false;
+ if (devfreq->profile->get_cur_freq &&
+ !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq))
+ devfreq->previous_freq = freq;
+
out:
mutex_unlock(&devfreq->lock);
}
@@ -477,7 +486,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
GFP_KERNEL);
devfreq->last_stat_updated = jiffies;
- dev_set_name(&devfreq->dev, dev_name(dev));
+ dev_set_name(&devfreq->dev, "%s", dev_name(dev));
err = device_register(&devfreq->dev);
if (err) {
put_device(&devfreq->dev);
@@ -518,6 +527,8 @@ EXPORT_SYMBOL(devfreq_add_device);
/**
* devfreq_remove_device() - Remove devfreq feature from a device.
* @devfreq: the devfreq instance to be removed
+ *
+ * The opposite of devfreq_add_device().
*/
int devfreq_remove_device(struct devfreq *devfreq)
{
@@ -533,6 +544,10 @@ EXPORT_SYMBOL(devfreq_remove_device);
/**
* devfreq_suspend_device() - Suspend devfreq of a device.
* @devfreq: the devfreq instance to be suspended
+ *
+ * This function is intended to be called by the pm callbacks
+ * (e.g., runtime_suspend, suspend) of the device driver that
+ * holds the devfreq.
*/
int devfreq_suspend_device(struct devfreq *devfreq)
{
@@ -550,6 +565,10 @@ EXPORT_SYMBOL(devfreq_suspend_device);
/**
* devfreq_resume_device() - Resume devfreq of a device.
* @devfreq: the devfreq instance to be resumed
+ *
+ * This function is intended to be called by the pm callbacks
+ * (e.g., runtime_resume, resume) of the device driver that
+ * holds the devfreq.
*/
int devfreq_resume_device(struct devfreq *devfreq)
{
@@ -905,11 +924,11 @@ static ssize_t show_trans_table(struct device *dev, struct device_attribute *att
{
struct devfreq *devfreq = to_devfreq(dev);
ssize_t len;
- int i, j, err;
+ int i, j;
unsigned int max_state = devfreq->profile->max_state;
- err = devfreq_update_status(devfreq, devfreq->previous_freq);
- if (err)
+ if (!devfreq->stop_polling &&
+ devfreq_update_status(devfreq, devfreq->previous_freq))
return 0;
len = sprintf(buf, " From : To\n");
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
new file mode 100644
index 000000000000..bfaaf5b0d61d
--- /dev/null
+++ b/drivers/devfreq/exynos/Makefile
@@ -0,0 +1,3 @@
+# Exynos DEVFREQ Drivers
+obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
+obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos_ppmu.o exynos5_bus.o
diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos/exynos4_bus.c
index 3f37f3b3f268..c5f86d8caca3 100644
--- a/drivers/devfreq/exynos4_bus.c
+++ b/drivers/devfreq/exynos/exynos4_bus.c
@@ -974,6 +974,7 @@ static int exynos4_busfreq_pm_notifier_event(struct notifier_block *this,
rcu_read_unlock();
dev_err(data->dev, "%s: unable to find a min freq\n",
__func__);
+ mutex_unlock(&data->lock);
return PTR_ERR(opp);
}
new_oppinfo.rate = opp_get_freq(opp);
diff --git a/drivers/devfreq/exynos/exynos5_bus.c b/drivers/devfreq/exynos/exynos5_bus.c
new file mode 100644
index 000000000000..574b16b59be5
--- /dev/null
+++ b/drivers/devfreq/exynos/exynos5_bus.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS5 INT clock frequency scaling support using DEVFREQ framework
+ * Based on work done by Jonghwan Choi <jhbird.choi@samsung.com>
+ * Support for only EXYNOS5250 is present.
+ *
+ * This program is free software; you can 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/devfreq.h>
+#include <linux/io.h>
+#include <linux/opp.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/opp.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#include "exynos_ppmu.h"
+
+#define MAX_SAFEVOLT 1100000 /* 1.10V */
+/* Assume that the bus is saturated if the utilization is 25% */
+#define INT_BUS_SATURATION_RATIO 25
+
+enum int_level_idx {
+ LV_0,
+ LV_1,
+ LV_2,
+ LV_3,
+ LV_4,
+ _LV_END
+};
+
+enum exynos_ppmu_list {
+ PPMU_RIGHT,
+ PPMU_END,
+};
+
+struct busfreq_data_int {
+ struct device *dev;
+ struct devfreq *devfreq;
+ struct regulator *vdd_int;
+ struct exynos_ppmu ppmu[PPMU_END];
+ unsigned long curr_freq;
+ bool disabled;
+
+ struct notifier_block pm_notifier;
+ struct mutex lock;
+ struct pm_qos_request int_req;
+ struct clk *int_clk;
+};
+
+struct int_bus_opp_table {
+ unsigned int idx;
+ unsigned long clk;
+ unsigned long volt;
+};
+
+static struct int_bus_opp_table exynos5_int_opp_table[] = {
+ {LV_0, 266000, 1025000},
+ {LV_1, 200000, 1025000},
+ {LV_2, 160000, 1025000},
+ {LV_3, 133000, 1025000},
+ {LV_4, 100000, 1025000},
+ {0, 0, 0},
+};
+
+static void busfreq_mon_reset(struct busfreq_data_int *data)
+{
+ unsigned int i;
+
+ for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+ void __iomem *ppmu_base = data->ppmu[i].hw_base;
+
+ /* Reset the performance and cycle counters */
+ exynos_ppmu_reset(ppmu_base);
+
+ /* Setup count registers to monitor read/write transactions */
+ data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
+ exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
+ data->ppmu[i].event[PPMU_PMNCNT3]);
+
+ exynos_ppmu_start(ppmu_base);
+ }
+}
+
+static void exynos5_read_ppmu(struct busfreq_data_int *data)
+{
+ int i, j;
+
+ for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+ void __iomem *ppmu_base = data->ppmu[i].hw_base;
+
+ exynos_ppmu_stop(ppmu_base);
+
+ /* Update local data from PPMU */
+ data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
+
+ for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+ if (data->ppmu[i].event[j] == 0)
+ data->ppmu[i].count[j] = 0;
+ else
+ data->ppmu[i].count[j] =
+ exynos_ppmu_read(ppmu_base, j);
+ }
+ }
+
+ busfreq_mon_reset(data);
+}
+
+static int exynos5_int_setvolt(struct busfreq_data_int *data,
+ unsigned long volt)
+{
+ return regulator_set_voltage(data->vdd_int, volt, MAX_SAFEVOLT);
+}
+
+static int exynos5_busfreq_int_target(struct device *dev, unsigned long *_freq,
+ u32 flags)
+{
+ int err = 0;
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+ struct opp *opp;
+ unsigned long old_freq, freq;
+ unsigned long volt;
+
+ rcu_read_lock();
+ opp = devfreq_recommended_opp(dev, _freq, flags);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "%s: Invalid OPP.\n", __func__);
+ return PTR_ERR(opp);
+ }
+
+ freq = opp_get_freq(opp);
+ volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ old_freq = data->curr_freq;
+
+ if (old_freq == freq)
+ return 0;
+
+ dev_dbg(dev, "targetting %lukHz %luuV\n", freq, volt);
+
+ mutex_lock(&data->lock);
+
+ if (data->disabled)
+ goto out;
+
+ if (freq > exynos5_int_opp_table[0].clk)
+ pm_qos_update_request(&data->int_req, freq * 16 / 1000);
+ else
+ pm_qos_update_request(&data->int_req, -1);
+
+ if (old_freq < freq)
+ err = exynos5_int_setvolt(data, volt);
+ if (err)
+ goto out;
+
+ err = clk_set_rate(data->int_clk, freq * 1000);
+
+ if (err)
+ goto out;
+
+ if (old_freq > freq)
+ err = exynos5_int_setvolt(data, volt);
+ if (err)
+ goto out;
+
+ data->curr_freq = freq;
+out:
+ mutex_unlock(&data->lock);
+ return err;
+}
+
+static int exynos5_get_busier_dmc(struct busfreq_data_int *data)
+{
+ int i, j;
+ int busy = 0;
+ unsigned int temp = 0;
+
+ for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+ for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+ if (data->ppmu[i].count[j] > temp) {
+ temp = data->ppmu[i].count[j];
+ busy = i;
+ }
+ }
+ }
+
+ return busy;
+}
+
+static int exynos5_int_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+ int busier_dmc;
+
+ exynos5_read_ppmu(data);
+ busier_dmc = exynos5_get_busier_dmc(data);
+
+ stat->current_frequency = data->curr_freq;
+
+ /* Number of cycles spent on memory access */
+ stat->busy_time = data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
+ stat->busy_time *= 100 / INT_BUS_SATURATION_RATIO;
+ stat->total_time = data->ppmu[busier_dmc].ccnt;
+
+ return 0;
+}
+static void exynos5_int_exit(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ devfreq_unregister_opp_notifier(dev, data->devfreq);
+}
+
+static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
+ .initial_freq = 160000,
+ .polling_ms = 100,
+ .target = exynos5_busfreq_int_target,
+ .get_dev_status = exynos5_int_get_dev_status,
+ .exit = exynos5_int_exit,
+};
+
+static int exynos5250_init_int_tables(struct busfreq_data_int *data)
+{
+ int i, err = 0;
+
+ for (i = LV_0; i < _LV_END; i++) {
+ err = opp_add(data->dev, exynos5_int_opp_table[i].clk,
+ exynos5_int_opp_table[i].volt);
+ if (err) {
+ dev_err(data->dev, "Cannot add opp entries.\n");
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int exynos5_busfreq_int_pm_notifier_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct busfreq_data_int *data = container_of(this,
+ struct busfreq_data_int, pm_notifier);
+ struct opp *opp;
+ unsigned long maxfreq = ULONG_MAX;
+ unsigned long freq;
+ unsigned long volt;
+ int err = 0;
+
+ switch (event) {
+ case PM_SUSPEND_PREPARE:
+ /* Set Fastest and Deactivate DVFS */
+ mutex_lock(&data->lock);
+
+ data->disabled = true;
+
+ rcu_read_lock();
+ opp = opp_find_freq_floor(data->dev, &maxfreq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ err = PTR_ERR(opp);
+ goto unlock;
+ }
+ freq = opp_get_freq(opp);
+ volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+
+ err = exynos5_int_setvolt(data, volt);
+ if (err)
+ goto unlock;
+
+ err = clk_set_rate(data->int_clk, freq * 1000);
+
+ if (err)
+ goto unlock;
+
+ data->curr_freq = freq;
+unlock:
+ mutex_unlock(&data->lock);
+ if (err)
+ return NOTIFY_BAD;
+ return NOTIFY_OK;
+ case PM_POST_RESTORE:
+ case PM_POST_SUSPEND:
+ /* Reactivate */
+ mutex_lock(&data->lock);
+ data->disabled = false;
+ mutex_unlock(&data->lock);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int exynos5_busfreq_int_probe(struct platform_device *pdev)
+{
+ struct busfreq_data_int *data;
+ struct opp *opp;
+ struct device *dev = &pdev->dev;
+ struct device_node *np;
+ unsigned long initial_freq;
+ unsigned long initial_volt;
+ int err = 0;
+ int i;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data_int),
+ GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
+ }
+
+ np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu");
+ if (np == NULL) {
+ pr_err("Unable to find PPMU node\n");
+ return -ENOENT;
+ }
+
+ for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+ /* map PPMU memory region */
+ data->ppmu[i].hw_base = of_iomap(np, i);
+ if (data->ppmu[i].hw_base == NULL) {
+ dev_err(&pdev->dev, "failed to map memory region\n");
+ return -ENOMEM;
+ }
+ }
+ data->pm_notifier.notifier_call = exynos5_busfreq_int_pm_notifier_event;
+ data->dev = dev;
+ mutex_init(&data->lock);
+
+ err = exynos5250_init_int_tables(data);
+ if (err)
+ goto err_regulator;
+
+ data->vdd_int = regulator_get(dev, "vdd_int");
+ if (IS_ERR(data->vdd_int)) {
+ dev_err(dev, "Cannot get the regulator \"vdd_int\"\n");
+ err = PTR_ERR(data->vdd_int);
+ goto err_regulator;
+ }
+
+ data->int_clk = clk_get(dev, "int_clk");
+ if (IS_ERR(data->int_clk)) {
+ dev_err(dev, "Cannot get clock \"int_clk\"\n");
+ err = PTR_ERR(data->int_clk);
+ goto err_clock;
+ }
+
+ rcu_read_lock();
+ opp = opp_find_freq_floor(dev,
+ &exynos5_devfreq_int_profile.initial_freq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "Invalid initial frequency %lu kHz.\n",
+ exynos5_devfreq_int_profile.initial_freq);
+ err = PTR_ERR(opp);
+ goto err_opp_add;
+ }
+ initial_freq = opp_get_freq(opp);
+ initial_volt = opp_get_voltage(opp);
+ rcu_read_unlock();
+ data->curr_freq = initial_freq;
+
+ err = clk_set_rate(data->int_clk, initial_freq * 1000);
+ if (err) {
+ dev_err(dev, "Failed to set initial frequency\n");
+ goto err_opp_add;
+ }
+
+ err = exynos5_int_setvolt(data, initial_volt);
+ if (err)
+ goto err_opp_add;
+
+ platform_set_drvdata(pdev, data);
+
+ busfreq_mon_reset(data);
+
+ data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_int_profile,
+ "simple_ondemand", NULL);
+
+ if (IS_ERR(data->devfreq)) {
+ err = PTR_ERR(data->devfreq);
+ goto err_devfreq_add;
+ }
+
+ devfreq_register_opp_notifier(dev, data->devfreq);
+
+ err = register_pm_notifier(&data->pm_notifier);
+ if (err) {
+ dev_err(dev, "Failed to setup pm notifier\n");
+ goto err_devfreq_add;
+ }
+
+ /* TODO: Add a new QOS class for int/mif bus */
+ pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1);
+
+ return 0;
+
+err_devfreq_add:
+ devfreq_remove_device(data->devfreq);
+ platform_set_drvdata(pdev, NULL);
+err_opp_add:
+ clk_put(data->int_clk);
+err_clock:
+ regulator_put(data->vdd_int);
+err_regulator:
+ return err;
+}
+
+static int exynos5_busfreq_int_remove(struct platform_device *pdev)
+{
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ pm_qos_remove_request(&data->int_req);
+ unregister_pm_notifier(&data->pm_notifier);
+ devfreq_remove_device(data->devfreq);
+ regulator_put(data->vdd_int);
+ clk_put(data->int_clk);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static int exynos5_busfreq_int_resume(struct device *dev)
+{
+ struct platform_device *pdev = container_of(dev, struct platform_device,
+ dev);
+ struct busfreq_data_int *data = platform_get_drvdata(pdev);
+
+ busfreq_mon_reset(data);
+ return 0;
+}
+
+static const struct dev_pm_ops exynos5_busfreq_int_pm = {
+ .resume = exynos5_busfreq_int_resume,
+};
+
+/* platform device pointer for exynos5 devfreq device. */
+static struct platform_device *exynos5_devfreq_pdev;
+
+static struct platform_driver exynos5_busfreq_int_driver = {
+ .probe = exynos5_busfreq_int_probe,
+ .remove = exynos5_busfreq_int_remove,
+ .driver = {
+ .name = "exynos5-bus-int",
+ .owner = THIS_MODULE,
+ .pm = &exynos5_busfreq_int_pm,
+ },
+};
+
+static int __init exynos5_busfreq_int_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&exynos5_busfreq_int_driver);
+ if (ret < 0)
+ goto out;
+
+ exynos5_devfreq_pdev =
+ platform_device_register_simple("exynos5-bus-int", -1, NULL, 0);
+ if (IS_ERR_OR_NULL(exynos5_devfreq_pdev)) {
+ ret = PTR_ERR(exynos5_devfreq_pdev);
+ goto out1;
+ }
+
+ return 0;
+out1:
+ platform_driver_unregister(&exynos5_busfreq_int_driver);
+out:
+ return ret;
+}
+late_initcall(exynos5_busfreq_int_init);
+
+static void __exit exynos5_busfreq_int_exit(void)
+{
+ platform_device_unregister(exynos5_devfreq_pdev);
+ platform_driver_unregister(&exynos5_busfreq_int_driver);
+}
+module_exit(exynos5_busfreq_int_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EXYNOS5 busfreq driver with devfreq framework");
diff --git a/drivers/devfreq/exynos/exynos_ppmu.c b/drivers/devfreq/exynos/exynos_ppmu.c
new file mode 100644
index 000000000000..85fc5ac1036a
--- /dev/null
+++ b/drivers/devfreq/exynos/exynos_ppmu.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS - PPMU support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+
+#include "exynos_ppmu.h"
+
+void exynos_ppmu_reset(void __iomem *ppmu_base)
+{
+ __raw_writel(PPMU_CYCLE_RESET | PPMU_COUNTER_RESET, ppmu_base);
+ __raw_writel(PPMU_ENABLE_CYCLE |
+ PPMU_ENABLE_COUNT0 |
+ PPMU_ENABLE_COUNT1 |
+ PPMU_ENABLE_COUNT2 |
+ PPMU_ENABLE_COUNT3,
+ ppmu_base + PPMU_CNTENS);
+}
+
+void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
+ unsigned int evt)
+{
+ __raw_writel(evt, ppmu_base + PPMU_BEVTSEL(ch));
+}
+
+void exynos_ppmu_start(void __iomem *ppmu_base)
+{
+ __raw_writel(PPMU_ENABLE, ppmu_base);
+}
+
+void exynos_ppmu_stop(void __iomem *ppmu_base)
+{
+ __raw_writel(PPMU_DISABLE, ppmu_base);
+}
+
+unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch)
+{
+ unsigned int total;
+
+ if (ch == PPMU_PMNCNT3)
+ total = ((__raw_readl(ppmu_base + PMCNT_OFFSET(ch)) << 8) |
+ __raw_readl(ppmu_base + PMCNT_OFFSET(ch + 1)));
+ else
+ total = __raw_readl(ppmu_base + PMCNT_OFFSET(ch));
+
+ return total;
+}
diff --git a/drivers/devfreq/exynos/exynos_ppmu.h b/drivers/devfreq/exynos/exynos_ppmu.h
new file mode 100644
index 000000000000..7dfb221eaccd
--- /dev/null
+++ b/drivers/devfreq/exynos/exynos_ppmu.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com/
+ *
+ * EXYNOS PPMU header
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __DEVFREQ_EXYNOS_PPMU_H
+#define __DEVFREQ_EXYNOS_PPMU_H __FILE__
+
+#include <linux/ktime.h>
+
+/* For PPMU Control */
+#define PPMU_ENABLE BIT(0)
+#define PPMU_DISABLE 0x0
+#define PPMU_CYCLE_RESET BIT(1)
+#define PPMU_COUNTER_RESET BIT(2)
+
+#define PPMU_ENABLE_COUNT0 BIT(0)
+#define PPMU_ENABLE_COUNT1 BIT(1)
+#define PPMU_ENABLE_COUNT2 BIT(2)
+#define PPMU_ENABLE_COUNT3 BIT(3)
+#define PPMU_ENABLE_CYCLE BIT(31)
+
+#define PPMU_CNTENS 0x10
+#define PPMU_FLAG 0x50
+#define PPMU_CCNT_OVERFLOW BIT(31)
+#define PPMU_CCNT 0x100
+
+#define PPMU_PMCNT0 0x110
+#define PPMU_PMCNT_OFFSET 0x10
+#define PMCNT_OFFSET(x) (PPMU_PMCNT0 + (PPMU_PMCNT_OFFSET * x))
+
+#define PPMU_BEVT0SEL 0x1000
+#define PPMU_BEVTSEL_OFFSET 0x100
+#define PPMU_BEVTSEL(x) (PPMU_BEVT0SEL + (ch * PPMU_BEVTSEL_OFFSET))
+
+/* For Event Selection */
+#define RD_DATA_COUNT 0x5
+#define WR_DATA_COUNT 0x6
+#define RDWR_DATA_COUNT 0x7
+
+enum ppmu_counter {
+ PPMU_PMNCNT0,
+ PPMU_PMCCNT1,
+ PPMU_PMNCNT2,
+ PPMU_PMNCNT3,
+ PPMU_PMNCNT_MAX,
+};
+
+struct bus_opp_table {
+ unsigned int idx;
+ unsigned long clk;
+ unsigned long volt;
+};
+
+struct exynos_ppmu {
+ void __iomem *hw_base;
+ unsigned int ccnt;
+ unsigned int event[PPMU_PMNCNT_MAX];
+ unsigned int count[PPMU_PMNCNT_MAX];
+ unsigned long long ns;
+ ktime_t reset_time;
+ bool ccnt_overflow;
+ bool count_overflow[PPMU_PMNCNT_MAX];
+};
+
+void exynos_ppmu_reset(void __iomem *ppmu_base);
+void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
+ unsigned int evt);
+void exynos_ppmu_start(void __iomem *ppmu_base);
+void exynos_ppmu_stop(void __iomem *ppmu_base);
+unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch);
+#endif /* __DEVFREQ_EXYNOS_PPMU_H */
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 3215a3cb3de8..6825957c97fb 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -79,25 +79,7 @@ config INTEL_IOP_ADMA
help
Enable support for the Intel(R) IOP Series RAID engines.
-config DW_DMAC
- tristate "Synopsys DesignWare AHB DMA support"
- depends on GENERIC_HARDIRQS
- select DMA_ENGINE
- default y if CPU_AT32AP7000
- help
- Support the Synopsys DesignWare AHB DMA controller. This
- can be integrated in chips such as the Atmel AT32ap7000.
-
-config DW_DMAC_BIG_ENDIAN_IO
- bool "Use big endian I/O register access"
- default y if AVR32
- depends on DW_DMAC
- help
- Say yes here to use big endian I/O access when reading and writing
- to the DMA controller registers. This is needed on some platforms,
- like the Atmel AVR32 architecture.
-
- If unsure, use the default setting.
+source "drivers/dma/dw/Kconfig"
config AT_HDMAC
tristate "Atmel AHB DMA support"
@@ -312,6 +294,12 @@ config MMP_PDMA
help
Support the MMP PDMA engine for PXA and MMP platfrom.
+config DMA_JZ4740
+ tristate "JZ4740 DMA support"
+ depends on MACH_JZ4740
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a2b0df591f95..5e0f2ef85614 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_FSL_DMA) += fsldma.o
obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_MV_XOR) += mv_xor.o
-obj-$(CONFIG_DW_DMAC) += dw_dmac.o
+obj-$(CONFIG_DW_DMAC_CORE) += dw/
obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
@@ -38,3 +38,4 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
+obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 8bad254a498d..06fe45c74de5 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -299,8 +299,8 @@ static int pl08x_request_mux(struct pl08x_dma_chan *plchan)
const struct pl08x_platform_data *pd = plchan->host->pd;
int ret;
- if (plchan->mux_use++ == 0 && pd->get_signal) {
- ret = pd->get_signal(plchan->cd);
+ if (plchan->mux_use++ == 0 && pd->get_xfer_signal) {
+ ret = pd->get_xfer_signal(plchan->cd);
if (ret < 0) {
plchan->mux_use = 0;
return ret;
@@ -318,8 +318,8 @@ static void pl08x_release_mux(struct pl08x_dma_chan *plchan)
if (plchan->signal >= 0) {
WARN_ON(plchan->mux_use == 0);
- if (--plchan->mux_use == 0 && pd->put_signal) {
- pd->put_signal(plchan->cd, plchan->signal);
+ if (--plchan->mux_use == 0 && pd->put_xfer_signal) {
+ pd->put_xfer_signal(plchan->cd, plchan->signal);
plchan->signal = -1;
}
}
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e923cda930f9..c787f38a186a 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -14,6 +14,7 @@
* found on AT91SAM9263.
*/
+#include <dt-bindings/dma/at91.h>
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
@@ -54,6 +55,7 @@ MODULE_PARM_DESC(init_nr_desc_per_channel,
/* prototypes */
static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx);
+static void atc_issue_pending(struct dma_chan *chan);
/*----------------------------------------------------------------------*/
@@ -230,6 +232,95 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
vdbg_dump_regs(atchan);
}
+/*
+ * atc_get_current_descriptors -
+ * locate the descriptor which equal to physical address in DSCR
+ * @atchan: the channel we want to start
+ * @dscr_addr: physical descriptor address in DSCR
+ */
+static struct at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
+ u32 dscr_addr)
+{
+ struct at_desc *desc, *_desc, *child, *desc_cur = NULL;
+
+ list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
+ if (desc->lli.dscr == dscr_addr) {
+ desc_cur = desc;
+ break;
+ }
+
+ list_for_each_entry(child, &desc->tx_list, desc_node) {
+ if (child->lli.dscr == dscr_addr) {
+ desc_cur = child;
+ break;
+ }
+ }
+ }
+
+ return desc_cur;
+}
+
+/*
+ * atc_get_bytes_left -
+ * Get the number of bytes residue in dma buffer,
+ * @chan: the channel we want to start
+ */
+static int atc_get_bytes_left(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ int chan_id = atchan->chan_common.chan_id;
+ struct at_desc *desc_first = atc_first_active(atchan);
+ struct at_desc *desc_cur;
+ int ret = 0, count = 0;
+
+ /*
+ * Initialize necessary values in the first time.
+ * remain_desc record remain desc length.
+ */
+ if (atchan->remain_desc == 0)
+ /* First descriptor embedds the transaction length */
+ atchan->remain_desc = desc_first->len;
+
+ /*
+ * This happens when current descriptor transfer complete.
+ * The residual buffer size should reduce current descriptor length.
+ */
+ if (unlikely(test_bit(ATC_IS_BTC, &atchan->status))) {
+ clear_bit(ATC_IS_BTC, &atchan->status);
+ desc_cur = atc_get_current_descriptors(atchan,
+ channel_readl(atchan, DSCR));
+ if (!desc_cur) {
+ ret = -EINVAL;
+ goto out;
+ }
+ atchan->remain_desc -= (desc_cur->lli.ctrla & ATC_BTSIZE_MAX)
+ << (desc_first->tx_width);
+ if (atchan->remain_desc < 0) {
+ ret = -EINVAL;
+ goto out;
+ } else {
+ ret = atchan->remain_desc;
+ }
+ } else {
+ /*
+ * Get residual bytes when current
+ * descriptor transfer in progress.
+ */
+ count = (channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX)
+ << (desc_first->tx_width);
+ ret = atchan->remain_desc - count;
+ }
+ /*
+ * Check fifo empty.
+ */
+ if (!(dma_readl(atdma, CHSR) & AT_DMA_EMPT(chan_id)))
+ atc_issue_pending(chan);
+
+out:
+ return ret;
+}
+
/**
* atc_chain_complete - finish work for one transaction chain
* @atchan: channel we work on
@@ -327,37 +418,6 @@ static void atc_complete_all(struct at_dma_chan *atchan)
}
/**
- * atc_cleanup_descriptors - cleanup up finished descriptors in active_list
- * @atchan: channel to be cleaned up
- *
- * Called with atchan->lock held and bh disabled
- */
-static void atc_cleanup_descriptors(struct at_dma_chan *atchan)
-{
- struct at_desc *desc, *_desc;
- struct at_desc *child;
-
- dev_vdbg(chan2dev(&atchan->chan_common), "cleanup descriptors\n");
-
- list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node) {
- if (!(desc->lli.ctrla & ATC_DONE))
- /* This one is currently in progress */
- return;
-
- list_for_each_entry(child, &desc->tx_list, desc_node)
- if (!(child->lli.ctrla & ATC_DONE))
- /* Currently in progress */
- return;
-
- /*
- * No descriptors so far seem to be in progress, i.e.
- * this chain must be done.
- */
- atc_chain_complete(atchan, desc);
- }
-}
-
-/**
* atc_advance_work - at the end of a transaction, move forward
* @atchan: channel where the transaction ended
*
@@ -496,6 +556,8 @@ static irqreturn_t at_dma_interrupt(int irq, void *dev_id)
/* Give information to tasklet */
set_bit(ATC_IS_ERROR, &atchan->status);
}
+ if (pending & AT_DMA_BTC(i))
+ set_bit(ATC_IS_BTC, &atchan->status);
tasklet_schedule(&atchan->tasklet);
ret = IRQ_HANDLED;
}
@@ -615,6 +677,7 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
/* First descriptor of the chain embedds additional information */
first->txd.cookie = -EBUSY;
first->len = len;
+ first->tx_width = src_width;
/* set end-of-link to the last link descriptor of list*/
set_desc_eol(desc);
@@ -761,6 +824,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* First descriptor of the chain embedds additional information */
first->txd.cookie = -EBUSY;
first->len = total_len;
+ first->tx_width = reg_width;
/* first link descriptor of list is responsible of flags */
first->txd.flags = flags; /* client is in control of this ack */
@@ -919,6 +983,7 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
/* First descriptor of the chain embedds additional information */
first->txd.cookie = -EBUSY;
first->len = buf_len;
+ first->tx_width = reg_width;
return &first->txd;
@@ -1032,34 +1097,36 @@ atc_tx_status(struct dma_chan *chan,
struct dma_tx_state *txstate)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
- dma_cookie_t last_used;
- dma_cookie_t last_complete;
unsigned long flags;
enum dma_status ret;
-
- spin_lock_irqsave(&atchan->lock, flags);
+ int bytes = 0;
ret = dma_cookie_status(chan, cookie, txstate);
- if (ret != DMA_SUCCESS) {
- atc_cleanup_descriptors(atchan);
+ if (ret == DMA_SUCCESS)
+ return ret;
+ /*
+ * There's no point calculating the residue if there's
+ * no txstate to store the value.
+ */
+ if (!txstate)
+ return DMA_ERROR;
- ret = dma_cookie_status(chan, cookie, txstate);
- }
+ spin_lock_irqsave(&atchan->lock, flags);
- last_complete = chan->completed_cookie;
- last_used = chan->cookie;
+ /* Get number of bytes left in the active transactions */
+ bytes = atc_get_bytes_left(chan);
spin_unlock_irqrestore(&atchan->lock, flags);
- if (ret != DMA_SUCCESS)
- dma_set_residue(txstate, atc_first_active(atchan)->len);
-
- if (atc_chan_is_paused(atchan))
- ret = DMA_PAUSED;
+ if (unlikely(bytes < 0)) {
+ dev_vdbg(chan2dev(chan), "get residual bytes error\n");
+ return DMA_ERROR;
+ } else {
+ dma_set_residue(txstate, bytes);
+ }
- dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d (d%d, u%d)\n",
- ret, cookie, last_complete ? last_complete : 0,
- last_used ? last_used : 0);
+ dev_vdbg(chan2dev(chan), "tx_status %d: cookie = %d residue = %d\n",
+ ret, cookie, bytes);
return ret;
}
@@ -1120,7 +1187,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
*/
BUG_ON(!atslave->dma_dev || atslave->dma_dev != atdma->dma_common.dev);
- /* if cfg configuration specified take it instad of default */
+ /* if cfg configuration specified take it instead of default */
if (atslave->cfg)
cfg = atslave->cfg;
}
@@ -1143,6 +1210,7 @@ static int atc_alloc_chan_resources(struct dma_chan *chan)
spin_lock_irqsave(&atchan->lock, flags);
atchan->descs_allocated = i;
+ atchan->remain_desc = 0;
list_splice(&tmp_list, &atchan->free_list);
dma_cookie_init(chan);
spin_unlock_irqrestore(&atchan->lock, flags);
@@ -1185,6 +1253,7 @@ static void atc_free_chan_resources(struct dma_chan *chan)
list_splice_init(&atchan->free_list, &list);
atchan->descs_allocated = 0;
atchan->status = 0;
+ atchan->remain_desc = 0;
dev_vdbg(chan2dev(chan), "free_chan_resources: done\n");
}
@@ -1223,14 +1292,31 @@ static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec,
atslave = devm_kzalloc(&dmac_pdev->dev, sizeof(*atslave), GFP_KERNEL);
if (!atslave)
return NULL;
+
+ atslave->cfg = ATC_DST_H2SEL_HW | ATC_SRC_H2SEL_HW;
/*
* We can fill both SRC_PER and DST_PER, one of these fields will be
* ignored depending on DMA transfer direction.
*/
- per_id = dma_spec->args[1];
- atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_DST_H2SEL_HW
- | ATC_SRC_H2SEL_HW | ATC_DST_PER(per_id)
- | ATC_SRC_PER(per_id);
+ per_id = dma_spec->args[1] & AT91_DMA_CFG_PER_ID_MASK;
+ atslave->cfg |= ATC_DST_PER_MSB(per_id) | ATC_DST_PER(per_id)
+ | ATC_SRC_PER_MSB(per_id) | ATC_SRC_PER(per_id);
+ /*
+ * We have to translate the value we get from the device tree since
+ * the half FIFO configuration value had to be 0 to keep backward
+ * compatibility.
+ */
+ switch (dma_spec->args[1] & AT91_DMA_CFG_FIFOCFG_MASK) {
+ case AT91_DMA_CFG_FIFOCFG_ALAP:
+ atslave->cfg |= ATC_FIFOCFG_LARGESTBURST;
+ break;
+ case AT91_DMA_CFG_FIFOCFG_ASAP:
+ atslave->cfg |= ATC_FIFOCFG_ENOUGHSPACE;
+ break;
+ case AT91_DMA_CFG_FIFOCFG_HALF:
+ default:
+ atslave->cfg |= ATC_FIFOCFG_HALFFIFO;
+ }
atslave->dma_dev = &dmac_pdev->dev;
chan = dma_request_channel(mask, at_dma_filter, atslave);
@@ -1374,7 +1460,9 @@ static int __init at_dma_probe(struct platform_device *pdev)
err = PTR_ERR(atdma->clk);
goto err_clk;
}
- clk_enable(atdma->clk);
+ err = clk_prepare_enable(atdma->clk);
+ if (err)
+ goto err_clk_prepare;
/* force dma off, just in case */
at_dma_off(atdma);
@@ -1472,10 +1560,10 @@ err_of_dma_controller_register:
dma_async_device_unregister(&atdma->dma_common);
dma_pool_destroy(atdma->dma_desc_pool);
err_pool_create:
- platform_set_drvdata(pdev, NULL);
free_irq(platform_get_irq(pdev, 0), atdma);
err_irq:
- clk_disable(atdma->clk);
+ clk_disable_unprepare(atdma->clk);
+err_clk_prepare:
clk_put(atdma->clk);
err_clk:
iounmap(atdma->regs);
@@ -1497,7 +1585,6 @@ static int at_dma_remove(struct platform_device *pdev)
dma_async_device_unregister(&atdma->dma_common);
dma_pool_destroy(atdma->dma_desc_pool);
- platform_set_drvdata(pdev, NULL);
free_irq(platform_get_irq(pdev, 0), atdma);
list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels,
@@ -1512,7 +1599,7 @@ static int at_dma_remove(struct platform_device *pdev)
list_del(&chan->device_node);
}
- clk_disable(atdma->clk);
+ clk_disable_unprepare(atdma->clk);
clk_put(atdma->clk);
iounmap(atdma->regs);
@@ -1531,7 +1618,7 @@ static void at_dma_shutdown(struct platform_device *pdev)
struct at_dma *atdma = platform_get_drvdata(pdev);
at_dma_off(platform_get_drvdata(pdev));
- clk_disable(atdma->clk);
+ clk_disable_unprepare(atdma->clk);
}
static int at_dma_prepare(struct device *dev)
@@ -1588,7 +1675,7 @@ static int at_dma_suspend_noirq(struct device *dev)
/* disable DMA controller */
at_dma_off(atdma);
- clk_disable(atdma->clk);
+ clk_disable_unprepare(atdma->clk);
return 0;
}
@@ -1618,7 +1705,7 @@ static int at_dma_resume_noirq(struct device *dev)
struct dma_chan *chan, *_chan;
/* bring back DMA controller */
- clk_enable(atdma->clk);
+ clk_prepare_enable(atdma->clk);
dma_writel(atdma, EN, AT_DMA_ENABLE);
/* clear any pending interrupt */
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index c604d26fd4d3..f31d647acdfa 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -182,6 +182,7 @@ struct at_lli {
* @txd: support for the async_tx api
* @desc_node: node on the channed descriptors list
* @len: total transaction bytecount
+ * @tx_width: transfer width
*/
struct at_desc {
/* FIRST values the hardware uses */
@@ -192,6 +193,7 @@ struct at_desc {
struct dma_async_tx_descriptor txd;
struct list_head desc_node;
size_t len;
+ u32 tx_width;
};
static inline struct at_desc *
@@ -211,6 +213,7 @@ txd_to_at_desc(struct dma_async_tx_descriptor *txd)
enum atc_status {
ATC_IS_ERROR = 0,
ATC_IS_PAUSED = 1,
+ ATC_IS_BTC = 2,
ATC_IS_CYCLIC = 24,
};
@@ -228,6 +231,7 @@ enum atc_status {
* @save_cfg: configuration register that is saved on suspend/resume cycle
* @save_dscr: for cyclic operations, preserve next descriptor address in
* the cyclic list on suspend/resume cycle
+ * @remain_desc: to save remain desc length
* @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
* @lock: serializes enqueue/dequeue operations to descriptors lists
* @active_list: list of descriptors dmaengine is being running on
@@ -246,6 +250,7 @@ struct at_dma_chan {
struct tasklet_struct tasklet;
u32 save_cfg;
u32 save_dscr;
+ u32 remain_desc;
struct dma_slave_config dma_sconfig;
spinlock_t lock;
diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c
new file mode 100644
index 000000000000..b0c0c8268d42
--- /dev/null
+++ b/drivers/dma/dma-jz4740.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (C) 2013, Lars-Peter Clausen <lars@metafoo.de>
+ * JZ4740 DMAC support
+ *
+ * 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.
+ *
+ * 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.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+
+#include <asm/mach-jz4740/dma.h>
+
+#include "virt-dma.h"
+
+#define JZ_DMA_NR_CHANS 6
+
+#define JZ_REG_DMA_SRC_ADDR(x) (0x00 + (x) * 0x20)
+#define JZ_REG_DMA_DST_ADDR(x) (0x04 + (x) * 0x20)
+#define JZ_REG_DMA_TRANSFER_COUNT(x) (0x08 + (x) * 0x20)
+#define JZ_REG_DMA_REQ_TYPE(x) (0x0C + (x) * 0x20)
+#define JZ_REG_DMA_STATUS_CTRL(x) (0x10 + (x) * 0x20)
+#define JZ_REG_DMA_CMD(x) (0x14 + (x) * 0x20)
+#define JZ_REG_DMA_DESC_ADDR(x) (0x18 + (x) * 0x20)
+
+#define JZ_REG_DMA_CTRL 0x300
+#define JZ_REG_DMA_IRQ 0x304
+#define JZ_REG_DMA_DOORBELL 0x308
+#define JZ_REG_DMA_DOORBELL_SET 0x30C
+
+#define JZ_DMA_STATUS_CTRL_NO_DESC BIT(31)
+#define JZ_DMA_STATUS_CTRL_DESC_INV BIT(6)
+#define JZ_DMA_STATUS_CTRL_ADDR_ERR BIT(4)
+#define JZ_DMA_STATUS_CTRL_TRANSFER_DONE BIT(3)
+#define JZ_DMA_STATUS_CTRL_HALT BIT(2)
+#define JZ_DMA_STATUS_CTRL_COUNT_TERMINATE BIT(1)
+#define JZ_DMA_STATUS_CTRL_ENABLE BIT(0)
+
+#define JZ_DMA_CMD_SRC_INC BIT(23)
+#define JZ_DMA_CMD_DST_INC BIT(22)
+#define JZ_DMA_CMD_RDIL_MASK (0xf << 16)
+#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14)
+#define JZ_DMA_CMD_DST_WIDTH_MASK (0x3 << 12)
+#define JZ_DMA_CMD_INTERVAL_LENGTH_MASK (0x7 << 8)
+#define JZ_DMA_CMD_BLOCK_MODE BIT(7)
+#define JZ_DMA_CMD_DESC_VALID BIT(4)
+#define JZ_DMA_CMD_DESC_VALID_MODE BIT(3)
+#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2)
+#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1)
+#define JZ_DMA_CMD_LINK_ENABLE BIT(0)
+
+#define JZ_DMA_CMD_FLAGS_OFFSET 22
+#define JZ_DMA_CMD_RDIL_OFFSET 16
+#define JZ_DMA_CMD_SRC_WIDTH_OFFSET 14
+#define JZ_DMA_CMD_DST_WIDTH_OFFSET 12
+#define JZ_DMA_CMD_TRANSFER_SIZE_OFFSET 8
+#define JZ_DMA_CMD_MODE_OFFSET 7
+
+#define JZ_DMA_CTRL_PRIORITY_MASK (0x3 << 8)
+#define JZ_DMA_CTRL_HALT BIT(3)
+#define JZ_DMA_CTRL_ADDRESS_ERROR BIT(2)
+#define JZ_DMA_CTRL_ENABLE BIT(0)
+
+enum jz4740_dma_width {
+ JZ4740_DMA_WIDTH_32BIT = 0,
+ JZ4740_DMA_WIDTH_8BIT = 1,
+ JZ4740_DMA_WIDTH_16BIT = 2,
+};
+
+enum jz4740_dma_transfer_size {
+ JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0,
+ JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1,
+ JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2,
+ JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3,
+ JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4,
+};
+
+enum jz4740_dma_flags {
+ JZ4740_DMA_SRC_AUTOINC = 0x2,
+ JZ4740_DMA_DST_AUTOINC = 0x1,
+};
+
+enum jz4740_dma_mode {
+ JZ4740_DMA_MODE_SINGLE = 0,
+ JZ4740_DMA_MODE_BLOCK = 1,
+};
+
+struct jz4740_dma_sg {
+ dma_addr_t addr;
+ unsigned int len;
+};
+
+struct jz4740_dma_desc {
+ struct virt_dma_desc vdesc;
+
+ enum dma_transfer_direction direction;
+ bool cyclic;
+
+ unsigned int num_sgs;
+ struct jz4740_dma_sg sg[];
+};
+
+struct jz4740_dmaengine_chan {
+ struct virt_dma_chan vchan;
+ unsigned int id;
+
+ dma_addr_t fifo_addr;
+ unsigned int transfer_shift;
+
+ struct jz4740_dma_desc *desc;
+ unsigned int next_sg;
+};
+
+struct jz4740_dma_dev {
+ struct dma_device ddev;
+ void __iomem *base;
+ struct clk *clk;
+
+ struct jz4740_dmaengine_chan chan[JZ_DMA_NR_CHANS];
+};
+
+static struct jz4740_dma_dev *jz4740_dma_chan_get_dev(
+ struct jz4740_dmaengine_chan *chan)
+{
+ return container_of(chan->vchan.chan.device, struct jz4740_dma_dev,
+ ddev);
+}
+
+static struct jz4740_dmaengine_chan *to_jz4740_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct jz4740_dmaengine_chan, vchan.chan);
+}
+
+static struct jz4740_dma_desc *to_jz4740_dma_desc(struct virt_dma_desc *vdesc)
+{
+ return container_of(vdesc, struct jz4740_dma_desc, vdesc);
+}
+
+static inline uint32_t jz4740_dma_read(struct jz4740_dma_dev *dmadev,
+ unsigned int reg)
+{
+ return readl(dmadev->base + reg);
+}
+
+static inline void jz4740_dma_write(struct jz4740_dma_dev *dmadev,
+ unsigned reg, uint32_t val)
+{
+ writel(val, dmadev->base + reg);
+}
+
+static inline void jz4740_dma_write_mask(struct jz4740_dma_dev *dmadev,
+ unsigned int reg, uint32_t val, uint32_t mask)
+{
+ uint32_t tmp;
+
+ tmp = jz4740_dma_read(dmadev, reg);
+ tmp &= ~mask;
+ tmp |= val;
+ jz4740_dma_write(dmadev, reg, tmp);
+}
+
+static struct jz4740_dma_desc *jz4740_dma_alloc_desc(unsigned int num_sgs)
+{
+ return kzalloc(sizeof(struct jz4740_dma_desc) +
+ sizeof(struct jz4740_dma_sg) * num_sgs, GFP_ATOMIC);
+}
+
+static enum jz4740_dma_width jz4740_dma_width(enum dma_slave_buswidth width)
+{
+ switch (width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ return JZ4740_DMA_WIDTH_8BIT;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ return JZ4740_DMA_WIDTH_16BIT;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ return JZ4740_DMA_WIDTH_32BIT;
+ default:
+ return JZ4740_DMA_WIDTH_32BIT;
+ }
+}
+
+static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst)
+{
+ if (maxburst <= 1)
+ return JZ4740_DMA_TRANSFER_SIZE_1BYTE;
+ else if (maxburst <= 3)
+ return JZ4740_DMA_TRANSFER_SIZE_2BYTE;
+ else if (maxburst <= 15)
+ return JZ4740_DMA_TRANSFER_SIZE_4BYTE;
+ else if (maxburst <= 31)
+ return JZ4740_DMA_TRANSFER_SIZE_16BYTE;
+
+ return JZ4740_DMA_TRANSFER_SIZE_32BYTE;
+}
+
+static int jz4740_dma_slave_config(struct dma_chan *c,
+ const struct dma_slave_config *config)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
+ enum jz4740_dma_width src_width;
+ enum jz4740_dma_width dst_width;
+ enum jz4740_dma_transfer_size transfer_size;
+ enum jz4740_dma_flags flags;
+ uint32_t cmd;
+
+ switch (config->direction) {
+ case DMA_MEM_TO_DEV:
+ flags = JZ4740_DMA_SRC_AUTOINC;
+ transfer_size = jz4740_dma_maxburst(config->dst_maxburst);
+ chan->fifo_addr = config->dst_addr;
+ break;
+ case DMA_DEV_TO_MEM:
+ flags = JZ4740_DMA_DST_AUTOINC;
+ transfer_size = jz4740_dma_maxburst(config->src_maxburst);
+ chan->fifo_addr = config->src_addr;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ src_width = jz4740_dma_width(config->src_addr_width);
+ dst_width = jz4740_dma_width(config->dst_addr_width);
+
+ switch (transfer_size) {
+ case JZ4740_DMA_TRANSFER_SIZE_2BYTE:
+ chan->transfer_shift = 1;
+ break;
+ case JZ4740_DMA_TRANSFER_SIZE_4BYTE:
+ chan->transfer_shift = 2;
+ break;
+ case JZ4740_DMA_TRANSFER_SIZE_16BYTE:
+ chan->transfer_shift = 4;
+ break;
+ case JZ4740_DMA_TRANSFER_SIZE_32BYTE:
+ chan->transfer_shift = 5;
+ break;
+ default:
+ chan->transfer_shift = 0;
+ break;
+ }
+
+ cmd = flags << JZ_DMA_CMD_FLAGS_OFFSET;
+ cmd |= src_width << JZ_DMA_CMD_SRC_WIDTH_OFFSET;
+ cmd |= dst_width << JZ_DMA_CMD_DST_WIDTH_OFFSET;
+ cmd |= transfer_size << JZ_DMA_CMD_TRANSFER_SIZE_OFFSET;
+ cmd |= JZ4740_DMA_MODE_SINGLE << JZ_DMA_CMD_MODE_OFFSET;
+ cmd |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE;
+
+ jz4740_dma_write(dmadev, JZ_REG_DMA_CMD(chan->id), cmd);
+ jz4740_dma_write(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0);
+ jz4740_dma_write(dmadev, JZ_REG_DMA_REQ_TYPE(chan->id),
+ config->slave_id);
+
+ return 0;
+}
+
+static int jz4740_dma_terminate_all(struct dma_chan *c)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0,
+ JZ_DMA_STATUS_CTRL_ENABLE);
+ chan->desc = NULL;
+ vchan_get_all_descriptors(&chan->vchan, &head);
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+ vchan_dma_desc_free_list(&chan->vchan, &head);
+
+ return 0;
+}
+
+static int jz4740_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct dma_slave_config *config = (struct dma_slave_config *)arg;
+
+ switch (cmd) {
+ case DMA_SLAVE_CONFIG:
+ return jz4740_dma_slave_config(chan, config);
+ case DMA_TERMINATE_ALL:
+ return jz4740_dma_terminate_all(chan);
+ default:
+ return -ENOSYS;
+ }
+}
+
+static int jz4740_dma_start_transfer(struct jz4740_dmaengine_chan *chan)
+{
+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
+ dma_addr_t src_addr, dst_addr;
+ struct virt_dma_desc *vdesc;
+ struct jz4740_dma_sg *sg;
+
+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id), 0,
+ JZ_DMA_STATUS_CTRL_ENABLE);
+
+ if (!chan->desc) {
+ vdesc = vchan_next_desc(&chan->vchan);
+ if (!vdesc)
+ return 0;
+ chan->desc = to_jz4740_dma_desc(vdesc);
+ chan->next_sg = 0;
+ }
+
+ if (chan->next_sg == chan->desc->num_sgs)
+ chan->next_sg = 0;
+
+ sg = &chan->desc->sg[chan->next_sg];
+
+ if (chan->desc->direction == DMA_MEM_TO_DEV) {
+ src_addr = sg->addr;
+ dst_addr = chan->fifo_addr;
+ } else {
+ src_addr = chan->fifo_addr;
+ dst_addr = sg->addr;
+ }
+ jz4740_dma_write(dmadev, JZ_REG_DMA_SRC_ADDR(chan->id), src_addr);
+ jz4740_dma_write(dmadev, JZ_REG_DMA_DST_ADDR(chan->id), dst_addr);
+ jz4740_dma_write(dmadev, JZ_REG_DMA_TRANSFER_COUNT(chan->id),
+ sg->len >> chan->transfer_shift);
+
+ chan->next_sg++;
+
+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_STATUS_CTRL(chan->id),
+ JZ_DMA_STATUS_CTRL_NO_DESC | JZ_DMA_STATUS_CTRL_ENABLE,
+ JZ_DMA_STATUS_CTRL_HALT | JZ_DMA_STATUS_CTRL_NO_DESC |
+ JZ_DMA_STATUS_CTRL_ENABLE);
+
+ jz4740_dma_write_mask(dmadev, JZ_REG_DMA_CTRL,
+ JZ_DMA_CTRL_ENABLE,
+ JZ_DMA_CTRL_HALT | JZ_DMA_CTRL_ENABLE);
+
+ return 0;
+}
+
+static void jz4740_dma_chan_irq(struct jz4740_dmaengine_chan *chan)
+{
+ spin_lock(&chan->vchan.lock);
+ if (chan->desc) {
+ if (chan->desc && chan->desc->cyclic) {
+ vchan_cyclic_callback(&chan->desc->vdesc);
+ } else {
+ if (chan->next_sg == chan->desc->num_sgs) {
+ chan->desc = NULL;
+ vchan_cookie_complete(&chan->desc->vdesc);
+ }
+ }
+ }
+ jz4740_dma_start_transfer(chan);
+ spin_unlock(&chan->vchan.lock);
+}
+
+static irqreturn_t jz4740_dma_irq(int irq, void *devid)
+{
+ struct jz4740_dma_dev *dmadev = devid;
+ uint32_t irq_status;
+ unsigned int i;
+
+ irq_status = readl(dmadev->base + JZ_REG_DMA_IRQ);
+
+ for (i = 0; i < 6; ++i) {
+ if (irq_status & (1 << i)) {
+ jz4740_dma_write_mask(dmadev,
+ JZ_REG_DMA_STATUS_CTRL(i), 0,
+ JZ_DMA_STATUS_CTRL_ENABLE |
+ JZ_DMA_STATUS_CTRL_TRANSFER_DONE);
+
+ jz4740_dma_chan_irq(&dmadev->chan[i]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void jz4740_dma_issue_pending(struct dma_chan *c)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ if (vchan_issue_pending(&chan->vchan) && !chan->desc)
+ jz4740_dma_start_transfer(chan);
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+}
+
+static struct dma_async_tx_descriptor *jz4740_dma_prep_slave_sg(
+ struct dma_chan *c, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+ struct jz4740_dma_desc *desc;
+ struct scatterlist *sg;
+ unsigned int i;
+
+ desc = jz4740_dma_alloc_desc(sg_len);
+ if (!desc)
+ return NULL;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ desc->sg[i].addr = sg_dma_address(sg);
+ desc->sg[i].len = sg_dma_len(sg);
+ }
+
+ desc->num_sgs = sg_len;
+ desc->direction = direction;
+ desc->cyclic = false;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *jz4740_dma_prep_dma_cyclic(
+ struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+ struct jz4740_dma_desc *desc;
+ unsigned int num_periods, i;
+
+ if (buf_len % period_len)
+ return NULL;
+
+ num_periods = buf_len / period_len;
+
+ desc = jz4740_dma_alloc_desc(num_periods);
+ if (!desc)
+ return NULL;
+
+ for (i = 0; i < num_periods; i++) {
+ desc->sg[i].addr = buf_addr;
+ desc->sg[i].len = period_len;
+ buf_addr += period_len;
+ }
+
+ desc->num_sgs = num_periods;
+ desc->direction = direction;
+ desc->cyclic = true;
+
+ return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
+}
+
+static size_t jz4740_dma_desc_residue(struct jz4740_dmaengine_chan *chan,
+ struct jz4740_dma_desc *desc, unsigned int next_sg)
+{
+ struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
+ unsigned int residue, count;
+ unsigned int i;
+
+ residue = 0;
+
+ for (i = next_sg; i < desc->num_sgs; i++)
+ residue += desc->sg[i].len;
+
+ if (next_sg != 0) {
+ count = jz4740_dma_read(dmadev,
+ JZ_REG_DMA_TRANSFER_COUNT(chan->id));
+ residue += count << chan->transfer_shift;
+ }
+
+ return residue;
+}
+
+static enum dma_status jz4740_dma_tx_status(struct dma_chan *c,
+ dma_cookie_t cookie, struct dma_tx_state *state)
+{
+ struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
+ struct virt_dma_desc *vdesc;
+ enum dma_status status;
+ unsigned long flags;
+
+ status = dma_cookie_status(c, cookie, state);
+ if (status == DMA_SUCCESS || !state)
+ return status;
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ vdesc = vchan_find_desc(&chan->vchan, cookie);
+ if (cookie == chan->desc->vdesc.tx.cookie) {
+ state->residue = jz4740_dma_desc_residue(chan, chan->desc,
+ chan->next_sg);
+ } else if (vdesc) {
+ state->residue = jz4740_dma_desc_residue(chan,
+ to_jz4740_dma_desc(vdesc), 0);
+ } else {
+ state->residue = 0;
+ }
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
+
+ return status;
+}
+
+static int jz4740_dma_alloc_chan_resources(struct dma_chan *c)
+{
+ return 0;
+}
+
+static void jz4740_dma_free_chan_resources(struct dma_chan *c)
+{
+ vchan_free_chan_resources(to_virt_chan(c));
+}
+
+static void jz4740_dma_desc_free(struct virt_dma_desc *vdesc)
+{
+ kfree(container_of(vdesc, struct jz4740_dma_desc, vdesc));
+}
+
+static int jz4740_dma_probe(struct platform_device *pdev)
+{
+ struct jz4740_dmaengine_chan *chan;
+ struct jz4740_dma_dev *dmadev;
+ struct dma_device *dd;
+ unsigned int i;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ dmadev = devm_kzalloc(&pdev->dev, sizeof(*dmadev), GFP_KERNEL);
+ if (!dmadev)
+ return -EINVAL;
+
+ dd = &dmadev->ddev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dmadev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dmadev->base))
+ return PTR_ERR(dmadev->base);
+
+ dmadev->clk = clk_get(&pdev->dev, "dma");
+ if (IS_ERR(dmadev->clk))
+ return PTR_ERR(dmadev->clk);
+
+ clk_prepare_enable(dmadev->clk);
+
+ dma_cap_set(DMA_SLAVE, dd->cap_mask);
+ dma_cap_set(DMA_CYCLIC, dd->cap_mask);
+ dd->device_alloc_chan_resources = jz4740_dma_alloc_chan_resources;
+ dd->device_free_chan_resources = jz4740_dma_free_chan_resources;
+ dd->device_tx_status = jz4740_dma_tx_status;
+ dd->device_issue_pending = jz4740_dma_issue_pending;
+ dd->device_prep_slave_sg = jz4740_dma_prep_slave_sg;
+ dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic;
+ dd->device_control = jz4740_dma_control;
+ dd->dev = &pdev->dev;
+ dd->chancnt = JZ_DMA_NR_CHANS;
+ INIT_LIST_HEAD(&dd->channels);
+
+ for (i = 0; i < dd->chancnt; i++) {
+ chan = &dmadev->chan[i];
+ chan->id = i;
+ chan->vchan.desc_free = jz4740_dma_desc_free;
+ vchan_init(&chan->vchan, dd);
+ }
+
+ ret = dma_async_device_register(dd);
+ if (ret)
+ return ret;
+
+ irq = platform_get_irq(pdev, 0);
+ ret = request_irq(irq, jz4740_dma_irq, 0, dev_name(&pdev->dev), dmadev);
+ if (ret)
+ goto err_unregister;
+
+ platform_set_drvdata(pdev, dmadev);
+
+ return 0;
+
+err_unregister:
+ dma_async_device_unregister(dd);
+ return ret;
+}
+
+static int jz4740_dma_remove(struct platform_device *pdev)
+{
+ struct jz4740_dma_dev *dmadev = platform_get_drvdata(pdev);
+ int irq = platform_get_irq(pdev, 0);
+
+ free_irq(irq, dmadev);
+ dma_async_device_unregister(&dmadev->ddev);
+ clk_disable_unprepare(dmadev->clk);
+
+ return 0;
+}
+
+static struct platform_driver jz4740_dma_driver = {
+ .probe = jz4740_dma_probe,
+ .remove = jz4740_dma_remove,
+ .driver = {
+ .name = "jz4740-dma",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(jz4740_dma_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("JZ4740 DMA driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 93f7992bee5c..9e56745f87bf 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -663,11 +663,6 @@ static bool device_has_all_tx_types(struct dma_device *device)
return false;
#endif
- #if defined(CONFIG_ASYNC_MEMSET) || defined(CONFIG_ASYNC_MEMSET_MODULE)
- if (!dma_has_cap(DMA_MEMSET, device->cap_mask))
- return false;
- #endif
-
#if defined(CONFIG_ASYNC_XOR) || defined(CONFIG_ASYNC_XOR_MODULE)
if (!dma_has_cap(DMA_XOR, device->cap_mask))
return false;
@@ -729,8 +724,6 @@ int dma_async_device_register(struct dma_device *device)
!device->device_prep_dma_pq);
BUG_ON(dma_has_cap(DMA_PQ_VAL, device->cap_mask) &&
!device->device_prep_dma_pq_val);
- BUG_ON(dma_has_cap(DMA_MEMSET, device->cap_mask) &&
- !device->device_prep_dma_memset);
BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
!device->device_prep_dma_interrupt);
BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig
new file mode 100644
index 000000000000..dde13248b681
--- /dev/null
+++ b/drivers/dma/dw/Kconfig
@@ -0,0 +1,29 @@
+#
+# DMA engine configuration for dw
+#
+
+config DW_DMAC_CORE
+ tristate "Synopsys DesignWare AHB DMA support"
+ depends on GENERIC_HARDIRQS
+ select DMA_ENGINE
+
+config DW_DMAC
+ tristate "Synopsys DesignWare AHB DMA platform driver"
+ select DW_DMAC_CORE
+ select DW_DMAC_BIG_ENDIAN_IO if AVR32
+ default y if CPU_AT32AP7000
+ help
+ Support the Synopsys DesignWare AHB DMA controller. This
+ can be integrated in chips such as the Atmel AT32ap7000.
+
+config DW_DMAC_PCI
+ tristate "Synopsys DesignWare AHB DMA PCI driver"
+ depends on PCI
+ select DW_DMAC_CORE
+ help
+ Support the Synopsys DesignWare AHB DMA controller on the
+ platfroms that enumerate it as a PCI device. For example,
+ Intel Medfield has integrated this GPDMA controller.
+
+config DW_DMAC_BIG_ENDIAN_IO
+ bool
diff --git a/drivers/dma/dw/Makefile b/drivers/dma/dw/Makefile
new file mode 100644
index 000000000000..3eebd1ce2c6b
--- /dev/null
+++ b/drivers/dma/dw/Makefile
@@ -0,0 +1,8 @@
+obj-$(CONFIG_DW_DMAC_CORE) += dw_dmac_core.o
+dw_dmac_core-objs := core.o
+
+obj-$(CONFIG_DW_DMAC) += dw_dmac.o
+dw_dmac-objs := platform.o
+
+obj-$(CONFIG_DW_DMAC_PCI) += dw_dmac_pci.o
+dw_dmac_pci-objs := pci.o
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw/core.c
index 2e5deaa82b60..eea479c12173 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw/core.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2007-2008 Atmel Corporation
* Copyright (C) 2010-2011 ST Microelectronics
+ * Copyright (C) 2013 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,17 +20,12 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_dma.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/acpi.h>
-#include <linux/acpi_dma.h>
-#include "dw_dmac_regs.h"
-#include "dmaengine.h"
+#include "../dmaengine.h"
+#include "internal.h"
/*
* This supports the Synopsys "DesignWare AHB Central DMA Controller",
@@ -41,16 +37,6 @@
* which does not support descriptor writeback.
*/
-static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
-{
- return slave ? slave->dst_master : 0;
-}
-
-static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
-{
- return slave ? slave->src_master : 1;
-}
-
static inline void dwc_set_masters(struct dw_dma_chan *dwc)
{
struct dw_dma *dw = to_dw_dma(dwc->chan.device);
@@ -556,14 +542,14 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc)
/* --------------------- Cyclic DMA API extensions -------------------- */
-inline dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan)
+dma_addr_t dw_dma_get_src_addr(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
return channel_readl(dwc, SAR);
}
EXPORT_SYMBOL(dw_dma_get_src_addr);
-inline dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan)
+dma_addr_t dw_dma_get_dst_addr(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
return channel_readl(dwc, DAR);
@@ -1225,99 +1211,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
dev_vdbg(chan2dev(chan), "%s: done\n", __func__);
}
-/*----------------------------------------------------------------------*/
-
-struct dw_dma_of_filter_args {
- struct dw_dma *dw;
- unsigned int req;
- unsigned int src;
- unsigned int dst;
-};
-
-static bool dw_dma_of_filter(struct dma_chan *chan, void *param)
-{
- struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
- struct dw_dma_of_filter_args *fargs = param;
-
- /* Ensure the device matches our channel */
- if (chan->device != &fargs->dw->dma)
- return false;
-
- dwc->request_line = fargs->req;
- dwc->src_master = fargs->src;
- dwc->dst_master = fargs->dst;
-
- return true;
-}
-
-static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
- struct of_dma *ofdma)
-{
- struct dw_dma *dw = ofdma->of_dma_data;
- struct dw_dma_of_filter_args fargs = {
- .dw = dw,
- };
- dma_cap_mask_t cap;
-
- if (dma_spec->args_count != 3)
- return NULL;
-
- fargs.req = dma_spec->args[0];
- fargs.src = dma_spec->args[1];
- fargs.dst = dma_spec->args[2];
-
- if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
- fargs.src >= dw->nr_masters ||
- fargs.dst >= dw->nr_masters))
- return NULL;
-
- dma_cap_zero(cap);
- dma_cap_set(DMA_SLAVE, cap);
-
- /* TODO: there should be a simpler way to do this */
- return dma_request_channel(cap, dw_dma_of_filter, &fargs);
-}
-
-#ifdef CONFIG_ACPI
-static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
-{
- struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
- struct acpi_dma_spec *dma_spec = param;
-
- if (chan->device->dev != dma_spec->dev ||
- chan->chan_id != dma_spec->chan_id)
- return false;
-
- dwc->request_line = dma_spec->slave_id;
- dwc->src_master = dwc_get_sms(NULL);
- dwc->dst_master = dwc_get_dms(NULL);
-
- return true;
-}
-
-static void dw_dma_acpi_controller_register(struct dw_dma *dw)
-{
- struct device *dev = dw->dma.dev;
- struct acpi_dma_filter_info *info;
- int ret;
-
- info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
- if (!info)
- return;
-
- dma_cap_zero(info->dma_cap);
- dma_cap_set(DMA_SLAVE, info->dma_cap);
- info->filter_fn = dw_dma_acpi_filter;
-
- ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
- info);
- if (ret)
- dev_err(dev, "could not register acpi_dma_controller\n");
-}
-#else /* !CONFIG_ACPI */
-static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
-#endif /* !CONFIG_ACPI */
-
/* --------------------- Cyclic DMA API extensions -------------------- */
/**
@@ -1598,104 +1491,24 @@ static void dw_dma_off(struct dw_dma *dw)
dw->chan[i].initialized = false;
}
-#ifdef CONFIG_OF
-static struct dw_dma_platform_data *
-dw_dma_parse_dt(struct platform_device *pdev)
+int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
{
- struct device_node *np = pdev->dev.of_node;
- struct dw_dma_platform_data *pdata;
- u32 tmp, arr[4];
-
- if (!np) {
- dev_err(&pdev->dev, "Missing DT data\n");
- return NULL;
- }
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
- return NULL;
-
- if (of_property_read_bool(np, "is_private"))
- pdata->is_private = true;
-
- if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
- pdata->chan_allocation_order = (unsigned char)tmp;
-
- if (!of_property_read_u32(np, "chan_priority", &tmp))
- pdata->chan_priority = tmp;
-
- if (!of_property_read_u32(np, "block_size", &tmp))
- pdata->block_size = tmp;
-
- if (!of_property_read_u32(np, "dma-masters", &tmp)) {
- if (tmp > 4)
- return NULL;
-
- pdata->nr_masters = tmp;
- }
-
- if (!of_property_read_u32_array(np, "data_width", arr,
- pdata->nr_masters))
- for (tmp = 0; tmp < pdata->nr_masters; tmp++)
- pdata->data_width[tmp] = arr[tmp];
-
- return pdata;
-}
-#else
-static inline struct dw_dma_platform_data *
-dw_dma_parse_dt(struct platform_device *pdev)
-{
- return NULL;
-}
-#endif
-
-static int dw_probe(struct platform_device *pdev)
-{
- struct dw_dma_platform_data *pdata;
- struct resource *io;
struct dw_dma *dw;
size_t size;
- void __iomem *regs;
bool autocfg;
unsigned int dw_params;
unsigned int nr_channels;
unsigned int max_blk_size = 0;
- int irq;
int err;
int i;
- io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!io)
- return -EINVAL;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- regs = devm_ioremap_resource(&pdev->dev, io);
- if (IS_ERR(regs))
- return PTR_ERR(regs);
-
- /* Apply default dma_mask if needed */
- if (!pdev->dev.dma_mask) {
- pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
- pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- }
-
- dw_params = dma_read_byaddr(regs, DW_PARAMS);
+ dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
autocfg = dw_params >> DW_PARAMS_EN & 0x1;
- dev_dbg(&pdev->dev, "DW_PARAMS: 0x%08x\n", dw_params);
-
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata)
- pdata = dw_dma_parse_dt(pdev);
+ dev_dbg(chip->dev, "DW_PARAMS: 0x%08x\n", dw_params);
if (!pdata && autocfg) {
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -1712,16 +1525,17 @@ static int dw_probe(struct platform_device *pdev)
nr_channels = pdata->nr_channels;
size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
- dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ dw = devm_kzalloc(chip->dev, size, GFP_KERNEL);
if (!dw)
return -ENOMEM;
- dw->clk = devm_clk_get(&pdev->dev, "hclk");
+ dw->clk = devm_clk_get(chip->dev, "hclk");
if (IS_ERR(dw->clk))
return PTR_ERR(dw->clk);
clk_prepare_enable(dw->clk);
- dw->regs = regs;
+ dw->regs = chip->regs;
+ chip->dw = dw;
/* Get hardware configuration parameters */
if (autocfg) {
@@ -1746,18 +1560,16 @@ static int dw_probe(struct platform_device *pdev)
/* Disable BLOCK interrupts as well */
channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
- err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0,
+ err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt, 0,
"dw_dmac", dw);
if (err)
return err;
- platform_set_drvdata(pdev, dw);
-
/* Create a pool of consistent memory blocks for hardware descriptors */
- dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", &pdev->dev,
+ dw->desc_pool = dmam_pool_create("dw_dmac_desc_pool", chip->dev,
sizeof(struct dw_desc), 4, 0);
if (!dw->desc_pool) {
- dev_err(&pdev->dev, "No memory for descriptors dma pool\n");
+ dev_err(chip->dev, "No memory for descriptors dma pool\n");
return -ENOMEM;
}
@@ -1798,12 +1610,12 @@ static int dw_probe(struct platform_device *pdev)
/* Hardware configuration */
if (autocfg) {
unsigned int dwc_params;
+ void __iomem *addr = chip->regs + r * sizeof(u32);
- dwc_params = dma_read_byaddr(regs + r * sizeof(u32),
- DWC_PARAMS);
+ dwc_params = dma_read_byaddr(addr, DWC_PARAMS);
- dev_dbg(&pdev->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
- dwc_params);
+ dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
+ dwc_params);
/* Decode maximum block size for given channel. The
* stored 4 bit value represents blocks from 0x00 for 3
@@ -1834,7 +1646,7 @@ static int dw_probe(struct platform_device *pdev)
dma_cap_set(DMA_SLAVE, dw->dma.cap_mask);
if (pdata->is_private)
dma_cap_set(DMA_PRIVATE, dw->dma.cap_mask);
- dw->dma.dev = &pdev->dev;
+ dw->dma.dev = chip->dev;
dw->dma.device_alloc_chan_resources = dwc_alloc_chan_resources;
dw->dma.device_free_chan_resources = dwc_free_chan_resources;
@@ -1848,32 +1660,20 @@ static int dw_probe(struct platform_device *pdev)
dma_writel(dw, CFG, DW_CFG_DMA_EN);
- dev_info(&pdev->dev, "DesignWare DMA Controller, %d channels\n",
+ dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
nr_channels);
dma_async_device_register(&dw->dma);
- if (pdev->dev.of_node) {
- err = of_dma_controller_register(pdev->dev.of_node,
- dw_dma_of_xlate, dw);
- if (err)
- dev_err(&pdev->dev,
- "could not register of_dma_controller\n");
- }
-
- if (ACPI_HANDLE(&pdev->dev))
- dw_dma_acpi_controller_register(dw);
-
return 0;
}
+EXPORT_SYMBOL_GPL(dw_dma_probe);
-static int dw_remove(struct platform_device *pdev)
+int dw_dma_remove(struct dw_dma_chip *chip)
{
- struct dw_dma *dw = platform_get_drvdata(pdev);
+ struct dw_dma *dw = chip->dw;
struct dw_dma_chan *dwc, *_dwc;
- if (pdev->dev.of_node)
- of_dma_controller_free(pdev->dev.of_node);
dw_dma_off(dw);
dma_async_device_unregister(&dw->dma);
@@ -1887,86 +1687,44 @@ static int dw_remove(struct platform_device *pdev)
return 0;
}
+EXPORT_SYMBOL_GPL(dw_dma_remove);
-static void dw_shutdown(struct platform_device *pdev)
+void dw_dma_shutdown(struct dw_dma_chip *chip)
{
- struct dw_dma *dw = platform_get_drvdata(pdev);
+ struct dw_dma *dw = chip->dw;
dw_dma_off(dw);
clk_disable_unprepare(dw->clk);
}
+EXPORT_SYMBOL_GPL(dw_dma_shutdown);
+
+#ifdef CONFIG_PM_SLEEP
-static int dw_suspend_noirq(struct device *dev)
+int dw_dma_suspend(struct dw_dma_chip *chip)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct dw_dma *dw = platform_get_drvdata(pdev);
+ struct dw_dma *dw = chip->dw;
dw_dma_off(dw);
clk_disable_unprepare(dw->clk);
return 0;
}
+EXPORT_SYMBOL_GPL(dw_dma_suspend);
-static int dw_resume_noirq(struct device *dev)
+int dw_dma_resume(struct dw_dma_chip *chip)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct dw_dma *dw = platform_get_drvdata(pdev);
+ struct dw_dma *dw = chip->dw;
clk_prepare_enable(dw->clk);
dma_writel(dw, CFG, DW_CFG_DMA_EN);
return 0;
}
+EXPORT_SYMBOL_GPL(dw_dma_resume);
-static const struct dev_pm_ops dw_dev_pm_ops = {
- .suspend_noirq = dw_suspend_noirq,
- .resume_noirq = dw_resume_noirq,
- .freeze_noirq = dw_suspend_noirq,
- .thaw_noirq = dw_resume_noirq,
- .restore_noirq = dw_resume_noirq,
- .poweroff_noirq = dw_suspend_noirq,
-};
-
-#ifdef CONFIG_OF
-static const struct of_device_id dw_dma_of_id_table[] = {
- { .compatible = "snps,dma-spear1340" },
- {}
-};
-MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
-#endif
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id dw_dma_acpi_id_table[] = {
- { "INTL9C60", 0 },
- { }
-};
-#endif
-
-static struct platform_driver dw_driver = {
- .probe = dw_probe,
- .remove = dw_remove,
- .shutdown = dw_shutdown,
- .driver = {
- .name = "dw_dmac",
- .pm = &dw_dev_pm_ops,
- .of_match_table = of_match_ptr(dw_dma_of_id_table),
- .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
- },
-};
-
-static int __init dw_init(void)
-{
- return platform_driver_register(&dw_driver);
-}
-subsys_initcall(dw_init);
-
-static void __exit dw_exit(void)
-{
- platform_driver_unregister(&dw_driver);
-}
-module_exit(dw_exit);
+#endif /* CONFIG_PM_SLEEP */
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller core driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_AUTHOR("Viresh Kumar <viresh.linux@gmail.com>");
diff --git a/drivers/dma/dw/internal.h b/drivers/dma/dw/internal.h
new file mode 100644
index 000000000000..32667f9e0dda
--- /dev/null
+++ b/drivers/dma/dw/internal.h
@@ -0,0 +1,70 @@
+/*
+ * Driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _DW_DMAC_INTERNAL_H
+#define _DW_DMAC_INTERNAL_H
+
+#include <linux/device.h>
+#include <linux/dw_dmac.h>
+
+#include "regs.h"
+
+/**
+ * struct dw_dma_chip - representation of DesignWare DMA controller hardware
+ * @dev: struct device of the DMA controller
+ * @irq: irq line
+ * @regs: memory mapped I/O space
+ * @dw: struct dw_dma that is filed by dw_dma_probe()
+ */
+struct dw_dma_chip {
+ struct device *dev;
+ int irq;
+ void __iomem *regs;
+ struct dw_dma *dw;
+};
+
+/* Export to the platform drivers */
+int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata);
+int dw_dma_remove(struct dw_dma_chip *chip);
+
+void dw_dma_shutdown(struct dw_dma_chip *chip);
+
+#ifdef CONFIG_PM_SLEEP
+
+int dw_dma_suspend(struct dw_dma_chip *chip);
+int dw_dma_resume(struct dw_dma_chip *chip);
+
+#endif /* CONFIG_PM_SLEEP */
+
+/**
+ * dwc_get_dms - get destination master
+ * @slave: pointer to the custom slave configuration
+ *
+ * Returns destination master in the custom slave configuration if defined, or
+ * default value otherwise.
+ */
+static inline unsigned int dwc_get_dms(struct dw_dma_slave *slave)
+{
+ return slave ? slave->dst_master : 0;
+}
+
+/**
+ * dwc_get_sms - get source master
+ * @slave: pointer to the custom slave configuration
+ *
+ * Returns source master in the custom slave configuration if defined, or
+ * default value otherwise.
+ */
+static inline unsigned int dwc_get_sms(struct dw_dma_slave *slave)
+{
+ return slave ? slave->src_master : 1;
+}
+
+#endif /* _DW_DMAC_INTERNAL_H */
diff --git a/drivers/dma/dw/pci.c b/drivers/dma/dw/pci.c
new file mode 100644
index 000000000000..e89fc24b8293
--- /dev/null
+++ b/drivers/dma/dw/pci.c
@@ -0,0 +1,101 @@
+/*
+ * PCI driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2013 Intel Corporation
+ * Author: Andy Shevchenko <andriy.shevchenko@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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+
+#include "internal.h"
+
+static struct dw_dma_platform_data dw_pci_pdata = {
+ .is_private = 1,
+ .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+ .chan_priority = CHAN_PRIORITY_ASCENDING,
+};
+
+static int dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+ struct dw_dma_chip *chip;
+ struct dw_dma_platform_data *pdata = (void *)pid->driver_data;
+ int ret;
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ ret = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
+ if (ret) {
+ dev_err(&pdev->dev, "I/O memory remapping failed\n");
+ return ret;
+ }
+
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
+
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = &pdev->dev;
+ chip->regs = pcim_iomap_table(pdev)[0];
+ chip->irq = pdev->irq;
+
+ ret = dw_dma_probe(chip, pdata);
+ if (ret)
+ return ret;
+
+ pci_set_drvdata(pdev, chip);
+
+ return 0;
+}
+
+static void dw_pci_remove(struct pci_dev *pdev)
+{
+ struct dw_dma_chip *chip = pci_get_drvdata(pdev);
+ int ret;
+
+ ret = dw_dma_remove(chip);
+ if (ret)
+ dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(dw_pci_id_table) = {
+ /* Medfield */
+ { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_pdata },
+ { PCI_VDEVICE(INTEL, 0x0830), (kernel_ulong_t)&dw_pci_pdata },
+
+ /* BayTrail */
+ { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_pdata },
+ { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_pdata },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
+
+static struct pci_driver dw_pci_driver = {
+ .name = "dw_dmac_pci",
+ .id_table = dw_pci_id_table,
+ .probe = dw_pci_probe,
+ .remove = dw_pci_remove,
+};
+
+module_pci_driver(dw_pci_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller PCI driver");
+MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
new file mode 100644
index 000000000000..6c9449cffae8
--- /dev/null
+++ b/drivers/dma/dw/platform.c
@@ -0,0 +1,317 @@
+/*
+ * Platform driver for the Synopsys DesignWare DMA Controller
+ *
+ * Copyright (C) 2007-2008 Atmel Corporation
+ * Copyright (C) 2010-2011 ST Microelectronics
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Some parts of this driver are derived from the original dw_dmac.
+ *
+ * This program is free software; you can 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/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/acpi.h>
+#include <linux/acpi_dma.h>
+
+#include "internal.h"
+
+struct dw_dma_of_filter_args {
+ struct dw_dma *dw;
+ unsigned int req;
+ unsigned int src;
+ unsigned int dst;
+};
+
+static bool dw_dma_of_filter(struct dma_chan *chan, void *param)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dw_dma_of_filter_args *fargs = param;
+
+ /* Ensure the device matches our channel */
+ if (chan->device != &fargs->dw->dma)
+ return false;
+
+ dwc->request_line = fargs->req;
+ dwc->src_master = fargs->src;
+ dwc->dst_master = fargs->dst;
+
+ return true;
+}
+
+static struct dma_chan *dw_dma_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct dw_dma *dw = ofdma->of_dma_data;
+ struct dw_dma_of_filter_args fargs = {
+ .dw = dw,
+ };
+ dma_cap_mask_t cap;
+
+ if (dma_spec->args_count != 3)
+ return NULL;
+
+ fargs.req = dma_spec->args[0];
+ fargs.src = dma_spec->args[1];
+ fargs.dst = dma_spec->args[2];
+
+ if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
+ fargs.src >= dw->nr_masters ||
+ fargs.dst >= dw->nr_masters))
+ return NULL;
+
+ dma_cap_zero(cap);
+ dma_cap_set(DMA_SLAVE, cap);
+
+ /* TODO: there should be a simpler way to do this */
+ return dma_request_channel(cap, dw_dma_of_filter, &fargs);
+}
+
+#ifdef CONFIG_ACPI
+static bool dw_dma_acpi_filter(struct dma_chan *chan, void *param)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct acpi_dma_spec *dma_spec = param;
+
+ if (chan->device->dev != dma_spec->dev ||
+ chan->chan_id != dma_spec->chan_id)
+ return false;
+
+ dwc->request_line = dma_spec->slave_id;
+ dwc->src_master = dwc_get_sms(NULL);
+ dwc->dst_master = dwc_get_dms(NULL);
+
+ return true;
+}
+
+static void dw_dma_acpi_controller_register(struct dw_dma *dw)
+{
+ struct device *dev = dw->dma.dev;
+ struct acpi_dma_filter_info *info;
+ int ret;
+
+ info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return;
+
+ dma_cap_zero(info->dma_cap);
+ dma_cap_set(DMA_SLAVE, info->dma_cap);
+ info->filter_fn = dw_dma_acpi_filter;
+
+ ret = devm_acpi_dma_controller_register(dev, acpi_dma_simple_xlate,
+ info);
+ if (ret)
+ dev_err(dev, "could not register acpi_dma_controller\n");
+}
+#else /* !CONFIG_ACPI */
+static inline void dw_dma_acpi_controller_register(struct dw_dma *dw) {}
+#endif /* !CONFIG_ACPI */
+
+#ifdef CONFIG_OF
+static struct dw_dma_platform_data *
+dw_dma_parse_dt(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct dw_dma_platform_data *pdata;
+ u32 tmp, arr[4];
+
+ if (!np) {
+ dev_err(&pdev->dev, "Missing DT data\n");
+ return NULL;
+ }
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ if (of_property_read_u32(np, "dma-channels", &pdata->nr_channels))
+ return NULL;
+
+ if (of_property_read_bool(np, "is_private"))
+ pdata->is_private = true;
+
+ if (!of_property_read_u32(np, "chan_allocation_order", &tmp))
+ pdata->chan_allocation_order = (unsigned char)tmp;
+
+ if (!of_property_read_u32(np, "chan_priority", &tmp))
+ pdata->chan_priority = tmp;
+
+ if (!of_property_read_u32(np, "block_size", &tmp))
+ pdata->block_size = tmp;
+
+ if (!of_property_read_u32(np, "dma-masters", &tmp)) {
+ if (tmp > 4)
+ return NULL;
+
+ pdata->nr_masters = tmp;
+ }
+
+ if (!of_property_read_u32_array(np, "data_width", arr,
+ pdata->nr_masters))
+ for (tmp = 0; tmp < pdata->nr_masters; tmp++)
+ pdata->data_width[tmp] = arr[tmp];
+
+ return pdata;
+}
+#else
+static inline struct dw_dma_platform_data *
+dw_dma_parse_dt(struct platform_device *pdev)
+{
+ return NULL;
+}
+#endif
+
+static int dw_probe(struct platform_device *pdev)
+{
+ struct dw_dma_chip *chip;
+ struct device *dev = &pdev->dev;
+ struct resource *mem;
+ struct dw_dma_platform_data *pdata;
+ int err;
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->irq = platform_get_irq(pdev, 0);
+ if (chip->irq < 0)
+ return chip->irq;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ chip->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(chip->regs))
+ return PTR_ERR(chip->regs);
+
+ /* Apply default dma_mask if needed */
+ if (!dev->dma_mask) {
+ dev->dma_mask = &dev->coherent_dma_mask;
+ dev->coherent_dma_mask = DMA_BIT_MASK(32);
+ }
+
+ pdata = dev_get_platdata(dev);
+ if (!pdata)
+ pdata = dw_dma_parse_dt(pdev);
+
+ chip->dev = dev;
+
+ err = dw_dma_probe(chip, pdata);
+ if (err)
+ return err;
+
+ platform_set_drvdata(pdev, chip);
+
+ if (pdev->dev.of_node) {
+ err = of_dma_controller_register(pdev->dev.of_node,
+ dw_dma_of_xlate, chip->dw);
+ if (err)
+ dev_err(&pdev->dev,
+ "could not register of_dma_controller\n");
+ }
+
+ if (ACPI_HANDLE(&pdev->dev))
+ dw_dma_acpi_controller_register(chip->dw);
+
+ return 0;
+}
+
+static int dw_remove(struct platform_device *pdev)
+{
+ struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+ if (pdev->dev.of_node)
+ of_dma_controller_free(pdev->dev.of_node);
+
+ return dw_dma_remove(chip);
+}
+
+static void dw_shutdown(struct platform_device *pdev)
+{
+ struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+ dw_dma_shutdown(chip);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id dw_dma_of_id_table[] = {
+ { .compatible = "snps,dma-spear1340" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
+#endif
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id dw_dma_acpi_id_table[] = {
+ { "INTL9C60", 0 },
+ { }
+};
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+
+static int dw_suspend_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+ return dw_dma_suspend(chip);
+}
+
+static int dw_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_dma_chip *chip = platform_get_drvdata(pdev);
+
+ return dw_dma_resume(chip);
+}
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define dw_suspend_noirq NULL
+#define dw_resume_noirq NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dw_dev_pm_ops = {
+ .suspend_noirq = dw_suspend_noirq,
+ .resume_noirq = dw_resume_noirq,
+ .freeze_noirq = dw_suspend_noirq,
+ .thaw_noirq = dw_resume_noirq,
+ .restore_noirq = dw_resume_noirq,
+ .poweroff_noirq = dw_suspend_noirq,
+};
+
+static struct platform_driver dw_driver = {
+ .probe = dw_probe,
+ .remove = dw_remove,
+ .shutdown = dw_shutdown,
+ .driver = {
+ .name = "dw_dmac",
+ .pm = &dw_dev_pm_ops,
+ .of_match_table = of_match_ptr(dw_dma_of_id_table),
+ .acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
+ },
+};
+
+static int __init dw_init(void)
+{
+ return platform_driver_register(&dw_driver);
+}
+subsys_initcall(dw_init);
+
+static void __exit dw_exit(void)
+{
+ platform_driver_unregister(&dw_driver);
+}
+module_exit(dw_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
diff --git a/drivers/dma/dw_dmac_regs.h b/drivers/dma/dw/regs.h
index 9d417200bd57..deb4274f80f4 100644
--- a/drivers/dma/dw_dmac_regs.h
+++ b/drivers/dma/dw/regs.h
@@ -9,6 +9,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/dw_dmac.h>
@@ -100,6 +101,12 @@ struct dw_dma_regs {
u32 DW_PARAMS;
};
+/*
+ * Big endian I/O access when reading and writing to the DMA controller
+ * registers. This is needed on some platforms, like the Atmel AVR32
+ * architecture.
+ */
+
#ifdef CONFIG_DW_DMAC_BIG_ENDIAN_IO
#define dma_readl_native ioread32be
#define dma_writel_native iowrite32be
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 4fc2980556ad..49e8fbdb8983 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -1368,7 +1368,7 @@ static int fsldma_of_probe(struct platform_device *op)
dma_set_mask(&(op->dev), DMA_BIT_MASK(36));
- dev_set_drvdata(&op->dev, fdev);
+ platform_set_drvdata(op, fdev);
/*
* We cannot use of_platform_bus_probe() because there is no
@@ -1417,7 +1417,7 @@ static int fsldma_of_remove(struct platform_device *op)
struct fsldma_device *fdev;
unsigned int i;
- fdev = dev_get_drvdata(&op->dev);
+ fdev = platform_get_drvdata(op);
dma_async_device_unregister(&fdev->common);
fsldma_free_irqs(fdev);
@@ -1428,7 +1428,6 @@ static int fsldma_of_remove(struct platform_device *op)
}
iounmap(fdev->regs);
- dev_set_drvdata(&op->dev, NULL);
kfree(fdev);
return 0;
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index f28583370d00..ff2aab973b45 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -27,6 +27,8 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
#include <asm/irq.h>
#include <linux/platform_data/dma-imx.h>
@@ -186,6 +188,11 @@ struct imxdma_engine {
enum imx_dma_type devtype;
};
+struct imxdma_filter_data {
+ struct imxdma_engine *imxdma;
+ int request;
+};
+
static struct platform_device_id imx_dma_devtype[] = {
{
.name = "imx1-dma",
@@ -202,6 +209,22 @@ static struct platform_device_id imx_dma_devtype[] = {
};
MODULE_DEVICE_TABLE(platform, imx_dma_devtype);
+static const struct of_device_id imx_dma_of_dev_id[] = {
+ {
+ .compatible = "fsl,imx1-dma",
+ .data = &imx_dma_devtype[IMX1_DMA],
+ }, {
+ .compatible = "fsl,imx21-dma",
+ .data = &imx_dma_devtype[IMX21_DMA],
+ }, {
+ .compatible = "fsl,imx27-dma",
+ .data = &imx_dma_devtype[IMX27_DMA],
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, imx_dma_of_dev_id);
+
static inline int is_imx1_dma(struct imxdma_engine *imxdma)
{
return imxdma->devtype == IMX1_DMA;
@@ -996,17 +1019,55 @@ static void imxdma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&imxdma->lock, flags);
}
+static bool imxdma_filter_fn(struct dma_chan *chan, void *param)
+{
+ struct imxdma_filter_data *fdata = param;
+ struct imxdma_channel *imxdma_chan = to_imxdma_chan(chan);
+
+ if (chan->device->dev != fdata->imxdma->dev)
+ return false;
+
+ imxdma_chan->dma_request = fdata->request;
+ chan->private = NULL;
+
+ return true;
+}
+
+static struct dma_chan *imxdma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ int count = dma_spec->args_count;
+ struct imxdma_engine *imxdma = ofdma->of_dma_data;
+ struct imxdma_filter_data fdata = {
+ .imxdma = imxdma,
+ };
+
+ if (count != 1)
+ return NULL;
+
+ fdata.request = dma_spec->args[0];
+
+ return dma_request_channel(imxdma->dma_device.cap_mask,
+ imxdma_filter_fn, &fdata);
+}
+
static int __init imxdma_probe(struct platform_device *pdev)
{
struct imxdma_engine *imxdma;
struct resource *res;
+ const struct of_device_id *of_id;
int ret, i;
int irq, irq_err;
+ of_id = of_match_device(imx_dma_of_dev_id, &pdev->dev);
+ if (of_id)
+ pdev->id_entry = of_id->data;
+
imxdma = devm_kzalloc(&pdev->dev, sizeof(*imxdma), GFP_KERNEL);
if (!imxdma)
return -ENOMEM;
+ imxdma->dev = &pdev->dev;
imxdma->devtype = pdev->id_entry->driver_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1111,7 +1172,6 @@ static int __init imxdma_probe(struct platform_device *pdev)
&imxdma->dma_device.channels);
}
- imxdma->dev = &pdev->dev;
imxdma->dma_device.dev = &pdev->dev;
imxdma->dma_device.device_alloc_chan_resources = imxdma_alloc_chan_resources;
@@ -1136,8 +1196,19 @@ static int __init imxdma_probe(struct platform_device *pdev)
goto err;
}
+ if (pdev->dev.of_node) {
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ imxdma_xlate, imxdma);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to register of_dma_controller\n");
+ goto err_of_dma_controller;
+ }
+ }
+
return 0;
+err_of_dma_controller:
+ dma_async_device_unregister(&imxdma->dma_device);
err:
clk_disable_unprepare(imxdma->dma_ipg);
clk_disable_unprepare(imxdma->dma_ahb);
@@ -1150,6 +1221,9 @@ static int imxdma_remove(struct platform_device *pdev)
dma_async_device_unregister(&imxdma->dma_device);
+ if (pdev->dev.of_node)
+ of_dma_controller_free(pdev->dev.of_node);
+
clk_disable_unprepare(imxdma->dma_ipg);
clk_disable_unprepare(imxdma->dma_ahb);
@@ -1159,6 +1233,7 @@ static int imxdma_remove(struct platform_device *pdev)
static struct platform_driver imxdma_driver = {
.driver = {
.name = "imx-dma",
+ .of_match_table = imx_dma_of_dev_id,
},
.id_table = imx_dma_devtype,
.remove = imxdma_remove,
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 092867bf795c..1e44b8cf95da 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -36,6 +36,7 @@
#include <linux/dmaengine.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/of_dma.h>
#include <asm/irq.h>
#include <linux/platform_data/dma-imx-sdma.h>
@@ -1296,6 +1297,35 @@ err_dma_alloc:
return ret;
}
+static bool sdma_filter_fn(struct dma_chan *chan, void *fn_param)
+{
+ struct imx_dma_data *data = fn_param;
+
+ if (!imx_dma_is_general_purpose(chan))
+ return false;
+
+ chan->private = data;
+
+ return true;
+}
+
+static struct dma_chan *sdma_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct sdma_engine *sdma = ofdma->of_dma_data;
+ dma_cap_mask_t mask = sdma->dma_device.cap_mask;
+ struct imx_dma_data data;
+
+ if (dma_spec->args_count != 3)
+ return NULL;
+
+ data.dma_request = dma_spec->args[0];
+ data.peripheral_type = dma_spec->args[1];
+ data.priority = dma_spec->args[2];
+
+ return dma_request_channel(mask, sdma_filter_fn, &data);
+}
+
static int __init sdma_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -1443,10 +1473,20 @@ static int __init sdma_probe(struct platform_device *pdev)
goto err_init;
}
+ if (np) {
+ ret = of_dma_controller_register(np, sdma_xlate, sdma);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register controller\n");
+ goto err_register;
+ }
+ }
+
dev_info(sdma->dev, "initialized\n");
return 0;
+err_register:
+ dma_async_device_unregister(&sdma->dma_device);
err_init:
kfree(sdma->script_addrs);
err_alloc:
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index a0de82e21a7c..a975ebebea8a 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -1405,7 +1405,7 @@ static int dma_runtime_idle(struct device *dev)
return -EAGAIN;
}
- return pm_schedule_suspend(dev, 0);
+ return 0;
}
/******************************************************************************
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index 17a2393b3e25..5ff6fc1819dc 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -1105,12 +1105,11 @@ static ssize_t cap_show(struct dma_chan *c, char *page)
{
struct dma_device *dma = c->device;
- return sprintf(page, "copy%s%s%s%s%s%s\n",
+ return sprintf(page, "copy%s%s%s%s%s\n",
dma_has_cap(DMA_PQ, dma->cap_mask) ? " pq" : "",
dma_has_cap(DMA_PQ_VAL, dma->cap_mask) ? " pq_val" : "",
dma_has_cap(DMA_XOR, dma->cap_mask) ? " xor" : "",
dma_has_cap(DMA_XOR_VAL, dma->cap_mask) ? " xor_val" : "",
- dma_has_cap(DMA_MEMSET, dma->cap_mask) ? " fill" : "",
dma_has_cap(DMA_INTERRUPT, dma->cap_mask) ? " intr" : "");
}
diff --git a/drivers/dma/ioat/dma_v2.h b/drivers/dma/ioat/dma_v2.h
index 29bf9448035d..212d584fe427 100644
--- a/drivers/dma/ioat/dma_v2.h
+++ b/drivers/dma/ioat/dma_v2.h
@@ -123,7 +123,6 @@ static inline u16 ioat2_xferlen_to_descs(struct ioat2_dma_chan *ioat, size_t len
struct ioat_ring_ent {
union {
struct ioat_dma_descriptor *hw;
- struct ioat_fill_descriptor *fill;
struct ioat_xor_descriptor *xor;
struct ioat_xor_ext_descriptor *xor_ex;
struct ioat_pq_descriptor *pq;
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index ca6ea9b3551b..b642e035579b 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -311,14 +311,6 @@ static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat,
if (!desc->hw->ctl_f.null) /* skip 'interrupt' ops */
ioat_dma_unmap(chan, flags, len, desc->hw);
break;
- case IOAT_OP_FILL: {
- struct ioat_fill_descriptor *hw = desc->fill;
-
- if (!(flags & DMA_COMPL_SKIP_DEST_UNMAP))
- ioat_unmap(pdev, hw->dst_addr - offset, len,
- PCI_DMA_FROMDEVICE, flags, 1);
- break;
- }
case IOAT_OP_XOR_VAL:
case IOAT_OP_XOR: {
struct ioat_xor_descriptor *xor = desc->xor;
@@ -824,51 +816,6 @@ ioat3_tx_status(struct dma_chan *c, dma_cookie_t cookie,
}
static struct dma_async_tx_descriptor *
-ioat3_prep_memset_lock(struct dma_chan *c, dma_addr_t dest, int value,
- size_t len, unsigned long flags)
-{
- struct ioat2_dma_chan *ioat = to_ioat2_chan(c);
- struct ioat_ring_ent *desc;
- size_t total_len = len;
- struct ioat_fill_descriptor *fill;
- u64 src_data = (0x0101010101010101ULL) * (value & 0xff);
- int num_descs, idx, i;
-
- num_descs = ioat2_xferlen_to_descs(ioat, len);
- if (likely(num_descs) && ioat2_check_space_lock(ioat, num_descs) == 0)
- idx = ioat->head;
- else
- return NULL;
- i = 0;
- do {
- size_t xfer_size = min_t(size_t, len, 1 << ioat->xfercap_log);
-
- desc = ioat2_get_ring_ent(ioat, idx + i);
- fill = desc->fill;
-
- fill->size = xfer_size;
- fill->src_data = src_data;
- fill->dst_addr = dest;
- fill->ctl = 0;
- fill->ctl_f.op = IOAT_OP_FILL;
-
- len -= xfer_size;
- dest += xfer_size;
- dump_desc_dbg(ioat, desc);
- } while (++i < num_descs);
-
- desc->txd.flags = flags;
- desc->len = total_len;
- fill->ctl_f.int_en = !!(flags & DMA_PREP_INTERRUPT);
- fill->ctl_f.fence = !!(flags & DMA_PREP_FENCE);
- fill->ctl_f.compl_write = 1;
- dump_desc_dbg(ioat, desc);
-
- /* we leave the channel locked to ensure in order submission */
- return &desc->txd;
-}
-
-static struct dma_async_tx_descriptor *
__ioat3_prep_xor_lock(struct dma_chan *c, enum sum_check_flags *result,
dma_addr_t dest, dma_addr_t *src, unsigned int src_cnt,
size_t len, unsigned long flags)
@@ -1431,7 +1378,7 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
struct page *xor_srcs[IOAT_NUM_SRC_TEST];
struct page *xor_val_srcs[IOAT_NUM_SRC_TEST + 1];
dma_addr_t dma_srcs[IOAT_NUM_SRC_TEST + 1];
- dma_addr_t dma_addr, dest_dma;
+ dma_addr_t dest_dma;
struct dma_async_tx_descriptor *tx;
struct dma_chan *dma_chan;
dma_cookie_t cookie;
@@ -1598,56 +1545,6 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
goto free_resources;
}
- /* skip memset if the capability is not present */
- if (!dma_has_cap(DMA_MEMSET, dma_chan->device->cap_mask))
- goto free_resources;
-
- /* test memset */
- op = IOAT_OP_FILL;
-
- dma_addr = dma_map_page(dev, dest, 0,
- PAGE_SIZE, DMA_FROM_DEVICE);
- tx = dma->device_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE,
- DMA_PREP_INTERRUPT |
- DMA_COMPL_SKIP_SRC_UNMAP |
- DMA_COMPL_SKIP_DEST_UNMAP);
- if (!tx) {
- dev_err(dev, "Self-test memset prep failed\n");
- err = -ENODEV;
- goto dma_unmap;
- }
-
- async_tx_ack(tx);
- init_completion(&cmp);
- tx->callback = ioat3_dma_test_callback;
- tx->callback_param = &cmp;
- cookie = tx->tx_submit(tx);
- if (cookie < 0) {
- dev_err(dev, "Self-test memset setup failed\n");
- err = -ENODEV;
- goto dma_unmap;
- }
- dma->device_issue_pending(dma_chan);
-
- tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
-
- if (dma->device_tx_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
- dev_err(dev, "Self-test memset timed out\n");
- err = -ENODEV;
- goto dma_unmap;
- }
-
- dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
-
- for (i = 0; i < PAGE_SIZE/sizeof(u32); i++) {
- u32 *ptr = page_address(dest);
- if (ptr[i]) {
- dev_err(dev, "Self-test memset failed compare\n");
- err = -ENODEV;
- goto free_resources;
- }
- }
-
/* test for non-zero parity sum */
op = IOAT_OP_XOR_VAL;
@@ -1706,8 +1603,7 @@ dma_unmap:
for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++)
dma_unmap_page(dev, dma_srcs[i], PAGE_SIZE,
DMA_TO_DEVICE);
- } else if (op == IOAT_OP_FILL)
- dma_unmap_page(dev, dma_addr, PAGE_SIZE, DMA_FROM_DEVICE);
+ }
free_resources:
dma->device_free_chan_resources(dma_chan);
out:
@@ -1944,12 +1840,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
}
}
- if (is_raid_device && (device->cap & IOAT_CAP_FILL_BLOCK)) {
- dma_cap_set(DMA_MEMSET, dma->cap_mask);
- dma->device_prep_dma_memset = ioat3_prep_memset_lock;
- }
-
-
dma->device_tx_status = ioat3_tx_status;
device->cleanup_fn = ioat3_cleanup_event;
device->timer_fn = ioat3_timer_event;
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
index 5ee57d402a6e..62f83e983d8d 100644
--- a/drivers/dma/ioat/hw.h
+++ b/drivers/dma/ioat/hw.h
@@ -100,33 +100,6 @@ struct ioat_dma_descriptor {
uint64_t user2;
};
-struct ioat_fill_descriptor {
- uint32_t size;
- union {
- uint32_t ctl;
- struct {
- unsigned int int_en:1;
- unsigned int rsvd:1;
- unsigned int dest_snoop_dis:1;
- unsigned int compl_write:1;
- unsigned int fence:1;
- unsigned int rsvd2:2;
- unsigned int dest_brk:1;
- unsigned int bundle:1;
- unsigned int rsvd4:15;
- #define IOAT_OP_FILL 0x01
- unsigned int op:8;
- } ctl_f;
- };
- uint64_t src_data;
- uint64_t dst_addr;
- uint64_t next;
- uint64_t rsv1;
- uint64_t next_dst_addr;
- uint64_t user1;
- uint64_t user2;
-};
-
struct ioat_xor_descriptor {
uint32_t size;
union {
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
index 7dafb9f3785f..cc727ec78c4e 100644
--- a/drivers/dma/iop-adma.c
+++ b/drivers/dma/iop-adma.c
@@ -633,39 +633,6 @@ iop_adma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
}
static struct dma_async_tx_descriptor *
-iop_adma_prep_dma_memset(struct dma_chan *chan, dma_addr_t dma_dest,
- int value, size_t len, unsigned long flags)
-{
- struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
- struct iop_adma_desc_slot *sw_desc, *grp_start;
- int slot_cnt, slots_per_op;
-
- if (unlikely(!len))
- return NULL;
- BUG_ON(len > IOP_ADMA_MAX_BYTE_COUNT);
-
- dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
- __func__, len);
-
- spin_lock_bh(&iop_chan->lock);
- slot_cnt = iop_chan_memset_slot_count(len, &slots_per_op);
- sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
- if (sw_desc) {
- grp_start = sw_desc->group_head;
- iop_desc_init_memset(grp_start, flags);
- iop_desc_set_byte_count(grp_start, iop_chan, len);
- iop_desc_set_block_fill_val(grp_start, value);
- iop_desc_set_dest_addr(grp_start, iop_chan, dma_dest);
- sw_desc->unmap_src_cnt = 1;
- sw_desc->unmap_len = len;
- sw_desc->async_tx.flags = flags;
- }
- spin_unlock_bh(&iop_chan->lock);
-
- return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
-static struct dma_async_tx_descriptor *
iop_adma_prep_dma_xor(struct dma_chan *chan, dma_addr_t dma_dest,
dma_addr_t *dma_src, unsigned int src_cnt, size_t len,
unsigned long flags)
@@ -1050,7 +1017,7 @@ iop_adma_xor_val_self_test(struct iop_adma_device *device)
struct page *xor_srcs[IOP_ADMA_NUM_SRC_TEST];
struct page *zero_sum_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
dma_addr_t dma_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
- dma_addr_t dma_addr, dest_dma;
+ dma_addr_t dest_dma;
struct dma_async_tx_descriptor *tx;
struct dma_chan *dma_chan;
dma_cookie_t cookie;
@@ -1176,33 +1143,6 @@ iop_adma_xor_val_self_test(struct iop_adma_device *device)
goto free_resources;
}
- /* test memset */
- dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
- PAGE_SIZE, DMA_FROM_DEVICE);
- tx = iop_adma_prep_dma_memset(dma_chan, dma_addr, 0, PAGE_SIZE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
- cookie = iop_adma_tx_submit(tx);
- iop_adma_issue_pending(dma_chan);
- msleep(8);
-
- if (iop_adma_status(dma_chan, cookie, NULL) != DMA_SUCCESS) {
- dev_err(dma_chan->device->dev,
- "Self-test memset timed out, disabling\n");
- err = -ENODEV;
- goto free_resources;
- }
-
- for (i = 0; i < PAGE_SIZE/sizeof(u32); i++) {
- u32 *ptr = page_address(dest);
- if (ptr[i]) {
- dev_err(dma_chan->device->dev,
- "Self-test memset failed compare, disabling\n");
- err = -ENODEV;
- goto free_resources;
- }
- }
-
/* test for non-zero parity sum */
zero_sum_result = 0;
for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++)
@@ -1487,8 +1427,6 @@ static int iop_adma_probe(struct platform_device *pdev)
/* set prep routines based on capability */
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask))
dma_dev->device_prep_dma_memcpy = iop_adma_prep_dma_memcpy;
- if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
- dma_dev->device_prep_dma_memset = iop_adma_prep_dma_memset;
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
dma_dev->max_xor = iop_adma_get_max_xor();
dma_dev->device_prep_dma_xor = iop_adma_prep_dma_xor;
@@ -1556,8 +1494,7 @@ static int iop_adma_probe(struct platform_device *pdev)
goto err_free_iop_chan;
}
- if (dma_has_cap(DMA_XOR, dma_dev->cap_mask) ||
- dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) {
+ if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
ret = iop_adma_xor_val_self_test(adev);
dev_dbg(&pdev->dev, "xor self test returned %d\n", ret);
if (ret)
@@ -1579,12 +1516,11 @@ static int iop_adma_probe(struct platform_device *pdev)
goto err_free_iop_chan;
}
- dev_info(&pdev->dev, "Intel(R) IOP: ( %s%s%s%s%s%s%s)\n",
+ dev_info(&pdev->dev, "Intel(R) IOP: ( %s%s%s%s%s%s)\n",
dma_has_cap(DMA_PQ, dma_dev->cap_mask) ? "pq " : "",
dma_has_cap(DMA_PQ_VAL, dma_dev->cap_mask) ? "pq_val " : "",
dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
dma_has_cap(DMA_XOR_VAL, dma_dev->cap_mask) ? "xor_val " : "",
- dma_has_cap(DMA_MEMSET, dma_dev->cap_mask) ? "fill " : "",
dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index 43d5a6c33297..9b9366537d73 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -154,6 +154,10 @@ static void mmp_tdma_disable_chan(struct mmp_tdma_chan *tdmac)
{
writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
tdmac->reg_base + TDCR);
+
+ /* disable irq */
+ writel(0, tdmac->reg_base + TDIMR);
+
tdmac->status = DMA_SUCCESS;
}
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index d64ae14f2706..200f1a3c9a44 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -89,11 +89,6 @@ static void mv_desc_clear_next_desc(struct mv_xor_desc_slot *desc)
hw_desc->phy_next_desc = 0;
}
-static void mv_desc_set_block_fill_val(struct mv_xor_desc_slot *desc, u32 val)
-{
- desc->value = val;
-}
-
static void mv_desc_set_dest_addr(struct mv_xor_desc_slot *desc,
dma_addr_t addr)
{
@@ -128,22 +123,6 @@ static void mv_chan_set_next_descriptor(struct mv_xor_chan *chan,
__raw_writel(next_desc_addr, XOR_NEXT_DESC(chan));
}
-static void mv_chan_set_dest_pointer(struct mv_xor_chan *chan, u32 desc_addr)
-{
- __raw_writel(desc_addr, XOR_DEST_POINTER(chan));
-}
-
-static void mv_chan_set_block_size(struct mv_xor_chan *chan, u32 block_size)
-{
- __raw_writel(block_size, XOR_BLOCK_SIZE(chan));
-}
-
-static void mv_chan_set_value(struct mv_xor_chan *chan, u32 value)
-{
- __raw_writel(value, XOR_INIT_VALUE_LOW(chan));
- __raw_writel(value, XOR_INIT_VALUE_HIGH(chan));
-}
-
static void mv_chan_unmask_interrupts(struct mv_xor_chan *chan)
{
u32 val = __raw_readl(XOR_INTR_MASK(chan));
@@ -186,8 +165,6 @@ static int mv_can_chain(struct mv_xor_desc_slot *desc)
if (chain_old_tail->type != desc->type)
return 0;
- if (desc->type == DMA_MEMSET)
- return 0;
return 1;
}
@@ -205,9 +182,6 @@ static void mv_set_mode(struct mv_xor_chan *chan,
case DMA_MEMCPY:
op_mode = XOR_OPERATION_MODE_MEMCPY;
break;
- case DMA_MEMSET:
- op_mode = XOR_OPERATION_MODE_MEMSET;
- break;
default:
dev_err(mv_chan_to_devp(chan),
"error: unsupported operation %d\n",
@@ -274,18 +248,9 @@ static void mv_xor_start_new_chain(struct mv_xor_chan *mv_chan,
if (sw_desc->type != mv_chan->current_type)
mv_set_mode(mv_chan, sw_desc->type);
- if (sw_desc->type == DMA_MEMSET) {
- /* for memset requests we need to program the engine, no
- * descriptors used.
- */
- struct mv_xor_desc *hw_desc = sw_desc->hw_desc;
- mv_chan_set_dest_pointer(mv_chan, hw_desc->phy_dest_addr);
- mv_chan_set_block_size(mv_chan, sw_desc->unmap_len);
- mv_chan_set_value(mv_chan, sw_desc->value);
- } else {
- /* set the hardware chain */
- mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys);
- }
+ /* set the hardware chain */
+ mv_chan_set_next_descriptor(mv_chan, sw_desc->async_tx.phys);
+
mv_chan->pending += sw_desc->slot_cnt;
mv_xor_issue_pending(&mv_chan->dmachan);
}
@@ -688,43 +653,6 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
}
static struct dma_async_tx_descriptor *
-mv_xor_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
- size_t len, unsigned long flags)
-{
- struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan);
- struct mv_xor_desc_slot *sw_desc, *grp_start;
- int slot_cnt;
-
- dev_dbg(mv_chan_to_devp(mv_chan),
- "%s dest: %x len: %u flags: %ld\n",
- __func__, dest, len, flags);
- if (unlikely(len < MV_XOR_MIN_BYTE_COUNT))
- return NULL;
-
- BUG_ON(len > MV_XOR_MAX_BYTE_COUNT);
-
- spin_lock_bh(&mv_chan->lock);
- slot_cnt = mv_chan_memset_slot_count(len);
- sw_desc = mv_xor_alloc_slots(mv_chan, slot_cnt, 1);
- if (sw_desc) {
- sw_desc->type = DMA_MEMSET;
- sw_desc->async_tx.flags = flags;
- grp_start = sw_desc->group_head;
- mv_desc_init(grp_start, flags);
- mv_desc_set_byte_count(grp_start, len);
- mv_desc_set_dest_addr(sw_desc->group_head, dest);
- mv_desc_set_block_fill_val(grp_start, value);
- sw_desc->unmap_src_cnt = 1;
- sw_desc->unmap_len = len;
- }
- spin_unlock_bh(&mv_chan->lock);
- dev_dbg(mv_chan_to_devp(mv_chan),
- "%s sw_desc %p async_tx %p \n",
- __func__, sw_desc, &sw_desc->async_tx);
- return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
-static struct dma_async_tx_descriptor *
mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src,
unsigned int src_cnt, size_t len, unsigned long flags)
{
@@ -1137,8 +1065,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
/* set prep routines based on capability */
if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask))
dma_dev->device_prep_dma_memcpy = mv_xor_prep_dma_memcpy;
- if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
- dma_dev->device_prep_dma_memset = mv_xor_prep_dma_memset;
if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
dma_dev->max_xor = 8;
dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor;
@@ -1187,9 +1113,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
goto err_free_irq;
}
- dev_info(&pdev->dev, "Marvell XOR: ( %s%s%s%s)\n",
+ dev_info(&pdev->dev, "Marvell XOR: ( %s%s%s)\n",
dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
- dma_has_cap(DMA_MEMSET, dma_dev->cap_mask) ? "fill " : "",
dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
@@ -1298,8 +1223,6 @@ static int mv_xor_probe(struct platform_device *pdev)
dma_cap_set(DMA_MEMCPY, cap_mask);
if (of_property_read_bool(np, "dmacap,xor"))
dma_cap_set(DMA_XOR, cap_mask);
- if (of_property_read_bool(np, "dmacap,memset"))
- dma_cap_set(DMA_MEMSET, cap_mask);
if (of_property_read_bool(np, "dmacap,interrupt"))
dma_cap_set(DMA_INTERRUPT, cap_mask);
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index c632a4761fcf..c619359cb7fe 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -31,7 +31,6 @@
#define XOR_OPERATION_MODE_XOR 0
#define XOR_OPERATION_MODE_MEMCPY 2
-#define XOR_OPERATION_MODE_MEMSET 4
#define XOR_CURR_DESC(chan) (chan->mmr_base + 0x210 + (chan->idx * 4))
#define XOR_NEXT_DESC(chan) (chan->mmr_base + 0x200 + (chan->idx * 4))
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index b48a79c28845..719593002ab7 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -693,7 +693,7 @@ static bool mxs_dma_filter_fn(struct dma_chan *chan, void *fn_param)
return true;
}
-struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
+static struct dma_chan *mxs_dma_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
struct mxs_dma_engine *mxs_dma = ofdma->of_dma_data;
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index 7aa0864cd487..75334bdd2c56 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -35,8 +35,7 @@ static struct of_dma *of_dma_find_controller(struct of_phandle_args *dma_spec)
struct of_dma *ofdma;
list_for_each_entry(ofdma, &of_dma_list, of_dma_controllers)
- if ((ofdma->of_node == dma_spec->np) &&
- (ofdma->of_dma_nbcells == dma_spec->args_count))
+ if (ofdma->of_node == dma_spec->np)
return ofdma;
pr_debug("%s: can't find DMA controller %s\n", __func__,
@@ -64,8 +63,6 @@ int of_dma_controller_register(struct device_node *np,
void *data)
{
struct of_dma *ofdma;
- int nbcells;
- const __be32 *prop;
if (!np || !of_dma_xlate) {
pr_err("%s: not enough information provided\n", __func__);
@@ -76,19 +73,7 @@ int of_dma_controller_register(struct device_node *np,
if (!ofdma)
return -ENOMEM;
- prop = of_get_property(np, "#dma-cells", NULL);
- if (prop)
- nbcells = be32_to_cpup(prop);
-
- if (!prop || !nbcells) {
- pr_err("%s: #dma-cells property is missing or invalid\n",
- __func__);
- kfree(ofdma);
- return -EINVAL;
- }
-
ofdma->of_node = np;
- ofdma->of_dma_nbcells = nbcells;
ofdma->of_dma_xlate = of_dma_xlate;
ofdma->of_dma_data = data;
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index a17553f7c028..593827b3fdd4 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -157,7 +157,6 @@ enum pl330_reqtype {
#define PERIPH_REV_R0P0 0
#define PERIPH_REV_R1P0 1
#define PERIPH_REV_R1P1 2
-#define PCELL_ID 0xff0
#define CR0_PERIPH_REQ_SET (1 << 0)
#define CR0_BOOT_EN_SET (1 << 1)
@@ -193,8 +192,6 @@ enum pl330_reqtype {
#define INTEG_CFG 0x0
#define PERIPH_ID_VAL ((PART << 0) | (DESIGNER << 12))
-#define PCELL_ID_VAL 0xb105f00d
-
#define PL330_STATE_STOPPED (1 << 0)
#define PL330_STATE_EXECUTING (1 << 1)
#define PL330_STATE_WFE (1 << 2)
@@ -292,7 +289,6 @@ static unsigned cmd_line;
/* Populated by the PL330 core driver for DMA API driver's info */
struct pl330_config {
u32 periph_id;
- u32 pcell_id;
#define DMAC_MODE_NS (1 << 0)
unsigned int mode;
unsigned int data_bus_width:10; /* In number of bits */
@@ -505,7 +501,7 @@ struct pl330_dmac {
/* Maximum possible events/irqs */
int events[32];
/* BUS address of MicroCode buffer */
- u32 mcode_bus;
+ dma_addr_t mcode_bus;
/* CPU address of MicroCode buffer */
void *mcode_cpu;
/* List of all Channel threads */
@@ -650,19 +646,6 @@ static inline bool _manager_ns(struct pl330_thread *thrd)
return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false;
}
-static inline u32 get_id(struct pl330_info *pi, u32 off)
-{
- void __iomem *regs = pi->base;
- u32 id = 0;
-
- id |= (readb(regs + off + 0x0) << 0);
- id |= (readb(regs + off + 0x4) << 8);
- id |= (readb(regs + off + 0x8) << 16);
- id |= (readb(regs + off + 0xc) << 24);
-
- return id;
-}
-
static inline u32 get_revision(u32 periph_id)
{
return (periph_id >> PERIPH_REV_SHIFT) & PERIPH_REV_MASK;
@@ -1986,9 +1969,6 @@ static void read_dmac_config(struct pl330_info *pi)
pi->pcfg.num_events = val;
pi->pcfg.irq_ns = readl(regs + CR3);
-
- pi->pcfg.periph_id = get_id(pi, PERIPH_ID);
- pi->pcfg.pcell_id = get_id(pi, PCELL_ID);
}
static inline void _reset_thread(struct pl330_thread *thrd)
@@ -2098,10 +2078,8 @@ static int pl330_add(struct pl330_info *pi)
regs = pi->base;
/* Check if we can handle this DMAC */
- if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
- || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
- dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
- get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
+ if ((pi->pcfg.periph_id & 0xfffff) != PERIPH_ID_VAL) {
+ dev_err(pi->dev, "PERIPH_ID 0x%x !\n", pi->pcfg.periph_id);
return -EINVAL;
}
@@ -2485,10 +2463,10 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
struct dma_pl330_chan *pch = to_pchan(chan);
unsigned long flags;
- spin_lock_irqsave(&pch->lock, flags);
-
tasklet_kill(&pch->task);
+ spin_lock_irqsave(&pch->lock, flags);
+
pl330_release_channel(pch->pl330_chid);
pch->pl330_chid = NULL;
@@ -2916,6 +2894,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
if (ret)
return ret;
+ pi->pcfg.periph_id = adev->periphid;
ret = pl330_add(pi);
if (ret)
goto probe_err1;
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 5d3d95569a1e..370ff8265630 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -2323,47 +2323,6 @@ static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memcpy(
}
/**
- * ppc440spe_adma_prep_dma_memset - prepare CDB for a MEMSET operation
- */
-static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_memset(
- struct dma_chan *chan, dma_addr_t dma_dest, int value,
- size_t len, unsigned long flags)
-{
- struct ppc440spe_adma_chan *ppc440spe_chan;
- struct ppc440spe_adma_desc_slot *sw_desc, *group_start;
- int slot_cnt, slots_per_op;
-
- ppc440spe_chan = to_ppc440spe_adma_chan(chan);
-
- if (unlikely(!len))
- return NULL;
-
- BUG_ON(len > PPC440SPE_ADMA_DMA_MAX_BYTE_COUNT);
-
- spin_lock_bh(&ppc440spe_chan->lock);
-
- dev_dbg(ppc440spe_chan->device->common.dev,
- "ppc440spe adma%d: %s cal: %u len: %u int_en %d\n",
- ppc440spe_chan->device->id, __func__, value, len,
- flags & DMA_PREP_INTERRUPT ? 1 : 0);
-
- slot_cnt = slots_per_op = 1;
- sw_desc = ppc440spe_adma_alloc_slots(ppc440spe_chan, slot_cnt,
- slots_per_op);
- if (sw_desc) {
- group_start = sw_desc->group_head;
- ppc440spe_desc_init_memset(group_start, value, flags);
- ppc440spe_adma_set_dest(group_start, dma_dest, 0);
- ppc440spe_desc_set_byte_count(group_start, ppc440spe_chan, len);
- sw_desc->unmap_len = len;
- sw_desc->async_tx.flags = flags;
- }
- spin_unlock_bh(&ppc440spe_chan->lock);
-
- return sw_desc ? &sw_desc->async_tx : NULL;
-}
-
-/**
* ppc440spe_adma_prep_dma_xor - prepare CDB for a XOR operation
*/
static struct dma_async_tx_descriptor *ppc440spe_adma_prep_dma_xor(
@@ -4125,7 +4084,6 @@ static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
case PPC440SPE_DMA1_ID:
dma_cap_set(DMA_MEMCPY, adev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, adev->common.cap_mask);
- dma_cap_set(DMA_MEMSET, adev->common.cap_mask);
dma_cap_set(DMA_PQ, adev->common.cap_mask);
dma_cap_set(DMA_PQ_VAL, adev->common.cap_mask);
dma_cap_set(DMA_XOR_VAL, adev->common.cap_mask);
@@ -4151,10 +4109,6 @@ static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
adev->common.device_prep_dma_memcpy =
ppc440spe_adma_prep_dma_memcpy;
}
- if (dma_has_cap(DMA_MEMSET, adev->common.cap_mask)) {
- adev->common.device_prep_dma_memset =
- ppc440spe_adma_prep_dma_memset;
- }
if (dma_has_cap(DMA_XOR, adev->common.cap_mask)) {
adev->common.max_xor = XOR_MAX_OPS;
adev->common.device_prep_dma_xor =
@@ -4217,7 +4171,6 @@ static void ppc440spe_adma_init_capabilities(struct ppc440spe_adma_device *adev)
dma_has_cap(DMA_XOR, adev->common.cap_mask) ? "xor " : "",
dma_has_cap(DMA_XOR_VAL, adev->common.cap_mask) ? "xor_val " : "",
dma_has_cap(DMA_MEMCPY, adev->common.cap_mask) ? "memcpy " : "",
- dma_has_cap(DMA_MEMSET, adev->common.cap_mask) ? "memset " : "",
dma_has_cap(DMA_INTERRUPT, adev->common.cap_mask) ? "intr " : "");
}
@@ -4481,7 +4434,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
adev->dev = &ofdev->dev;
adev->common.dev = &ofdev->dev;
INIT_LIST_HEAD(&adev->common.channels);
- dev_set_drvdata(&ofdev->dev, adev);
+ platform_set_drvdata(ofdev, adev);
/* create a channel */
chan = kzalloc(sizeof(*chan), GFP_KERNEL);
@@ -4594,14 +4547,13 @@ out:
*/
static int ppc440spe_adma_remove(struct platform_device *ofdev)
{
- struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev);
+ struct ppc440spe_adma_device *adev = platform_get_drvdata(ofdev);
struct device_node *np = ofdev->dev.of_node;
struct resource res;
struct dma_chan *chan, *_chan;
struct ppc_dma_chan_ref *ref, *_ref;
struct ppc440spe_adma_chan *ppc440spe_chan;
- dev_set_drvdata(&ofdev->dev, NULL);
if (adev->id < PPC440SPE_ADMA_ENGINES_NUM)
ppc440spe_adma_devices[adev->id] = -1;
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index c07ca4612e46..c962138dde96 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o
+obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
obj-$(CONFIG_SH_DMAE) += shdma.o
obj-$(CONFIG_SUDMAC) += sudmac.o
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 4acb85a10250..28ca36121631 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -175,7 +175,18 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
{
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops;
- int ret;
+ int ret, match;
+
+ if (schan->dev->of_node) {
+ match = schan->hw_req;
+ ret = ops->set_slave(schan, match, true);
+ if (ret < 0)
+ return ret;
+
+ slave_id = schan->slave_id;
+ } else {
+ match = slave_id;
+ }
if (slave_id < 0 || slave_id >= slave_num)
return -EINVAL;
@@ -183,7 +194,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
if (test_and_set_bit(slave_id, shdma_slave_used))
return -EBUSY;
- ret = ops->set_slave(schan, slave_id, false);
+ ret = ops->set_slave(schan, match, false);
if (ret < 0) {
clear_bit(slave_id, shdma_slave_used);
return ret;
@@ -206,23 +217,26 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
* services would have to provide their own filters, which first would check
* the device driver, similar to how other DMAC drivers, e.g., sa11x0-dma.c, do
* this, and only then, in case of a match, call this common filter.
+ * NOTE 2: This filter function is also used in the DT case by shdma_of_xlate().
+ * In that case the MID-RID value is used for slave channel filtering and is
+ * passed to this function in the "arg" parameter.
*/
bool shdma_chan_filter(struct dma_chan *chan, void *arg)
{
struct shdma_chan *schan = to_shdma_chan(chan);
struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
const struct shdma_ops *ops = sdev->ops;
- int slave_id = (int)arg;
+ int match = (int)arg;
int ret;
- if (slave_id < 0)
+ if (match < 0)
/* No slave requested - arbitrary channel */
return true;
- if (slave_id >= slave_num)
+ if (!schan->dev->of_node && match >= slave_num)
return false;
- ret = ops->set_slave(schan, slave_id, true);
+ ret = ops->set_slave(schan, match, true);
if (ret < 0)
return false;
diff --git a/drivers/dma/sh/shdma-of.c b/drivers/dma/sh/shdma-of.c
new file mode 100644
index 000000000000..11bcb05cd79c
--- /dev/null
+++ b/drivers/dma/sh/shdma-of.c
@@ -0,0 +1,82 @@
+/*
+ * SHDMA Device Tree glue
+ *
+ * Copyright (C) 2013 Renesas Electronics Inc.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/shdma-base.h>
+
+#define to_shdma_chan(c) container_of(c, struct shdma_chan, dma_chan)
+
+static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ u32 id = dma_spec->args[0];
+ dma_cap_mask_t mask;
+ struct dma_chan *chan;
+
+ if (dma_spec->args_count != 1)
+ return NULL;
+
+ dma_cap_zero(mask);
+ /* Only slave DMA channels can be allocated via DT */
+ dma_cap_set(DMA_SLAVE, mask);
+
+ chan = dma_request_channel(mask, shdma_chan_filter, (void *)id);
+ if (chan)
+ to_shdma_chan(chan)->hw_req = id;
+
+ return chan;
+}
+
+static int shdma_of_probe(struct platform_device *pdev)
+{
+ const struct of_dev_auxdata *lookup = pdev->dev.platform_data;
+ int ret;
+
+ if (!lookup)
+ return -EINVAL;
+
+ ret = of_dma_controller_register(pdev->dev.of_node,
+ shdma_of_xlate, pdev);
+ if (ret < 0)
+ return ret;
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, lookup, &pdev->dev);
+ if (ret < 0)
+ of_dma_controller_free(pdev->dev.of_node);
+
+ return ret;
+}
+
+static const struct of_device_id shdma_of_match[] = {
+ { .compatible = "renesas,shdma-mux", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
+
+static struct platform_driver shdma_of = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "shdma-of",
+ .of_match_table = shdma_of_match,
+ },
+ .probe = shdma_of_probe,
+};
+
+module_platform_driver(shdma_of);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("SH-DMA driver DT glue");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c
index b70709b030d8..b67f45f5c271 100644
--- a/drivers/dma/sh/shdma.c
+++ b/drivers/dma/sh/shdma.c
@@ -301,20 +301,32 @@ static void sh_dmae_setup_xfer(struct shdma_chan *schan,
}
}
+/*
+ * Find a slave channel configuration from the contoller list by either a slave
+ * ID in the non-DT case, or by a MID/RID value in the DT case
+ */
static const struct sh_dmae_slave_config *dmae_find_slave(
- struct sh_dmae_chan *sh_chan, int slave_id)
+ struct sh_dmae_chan *sh_chan, int match)
{
struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
struct sh_dmae_pdata *pdata = shdev->pdata;
const struct sh_dmae_slave_config *cfg;
int i;
- if (slave_id >= SH_DMA_SLAVE_NUMBER)
- return NULL;
+ if (!sh_chan->shdma_chan.dev->of_node) {
+ if (match >= SH_DMA_SLAVE_NUMBER)
+ return NULL;
- for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
- if (cfg->slave_id == slave_id)
- return cfg;
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->slave_id == match)
+ return cfg;
+ } else {
+ for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+ if (cfg->mid_rid == match) {
+ sh_chan->shdma_chan.slave_id = cfg->slave_id;
+ return cfg;
+ }
+ }
return NULL;
}
@@ -729,7 +741,7 @@ static int sh_dmae_probe(struct platform_device *pdev)
goto eshdma;
/* platform data */
- shdev->pdata = pdev->dev.platform_data;
+ shdev->pdata = pdata;
if (pdata->chcr_offset)
shdev->chcr_offset = pdata->chcr_offset;
@@ -920,11 +932,18 @@ static int sh_dmae_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id sh_dmae_of_match[] = {
+ { .compatible = "renesas,shdma", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
+
static struct platform_driver sh_dmae_driver = {
.driver = {
.owner = THIS_MODULE,
.pm = &sh_dmae_pm,
.name = SH_DMAE_DRV_NAME,
+ .of_match_table = sh_dmae_of_match,
},
.remove = sh_dmae_remove,
.shutdown = sh_dmae_shutdown,
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 1765a0a2736d..716b23e4f327 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -466,12 +466,29 @@ static enum dma_status
sirfsoc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
+ struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
unsigned long flags;
enum dma_status ret;
+ struct sirfsoc_dma_desc *sdesc;
+ int cid = schan->chan.chan_id;
+ unsigned long dma_pos;
+ unsigned long dma_request_bytes;
+ unsigned long residue;
spin_lock_irqsave(&schan->lock, flags);
+
+ sdesc = list_first_entry(&schan->active, struct sirfsoc_dma_desc,
+ node);
+ dma_request_bytes = (sdesc->xlen + 1) * (sdesc->ylen + 1) *
+ (sdesc->width * SIRFSOC_DMA_WORD_LEN);
+
ret = dma_cookie_status(chan, cookie, txstate);
+ dma_pos = readl_relaxed(sdma->base + cid * 0x10 + SIRFSOC_DMA_CH_ADDR)
+ << 2;
+ residue = dma_request_bytes - (dma_pos - sdesc->addr);
+ dma_set_residue(txstate, residue);
+
spin_unlock_irqrestore(&schan->lock, flags);
return ret;
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 33f59ecd256e..f137914d7b16 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1191,6 +1191,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
list_splice_init(&tdc->free_dma_desc, &dma_desc_list);
INIT_LIST_HEAD(&tdc->cb_desc);
tdc->config_init = false;
+ tdc->isr_handler = NULL;
spin_unlock_irqrestore(&tdc->lock, flags);
while (!list_empty(&dma_desc_list)) {
@@ -1334,7 +1335,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"request_irq failed with err %d channel %d\n",
- i, ret);
+ ret, i);
goto err_irq;
}
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index 26107ba6edb3..0ef43c136aa7 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -811,8 +811,6 @@ static int td_remove(struct platform_device *pdev)
kfree(td);
release_mem_region(iomem->start, resource_size(iomem));
- platform_set_drvdata(pdev, NULL);
-
dev_dbg(&pdev->dev, "Removed...\n");
return 0;
}
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index 845f04786c2d..0d66ae68d468 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -24,7 +24,7 @@ static ssize_t amd64_inject_section_store(struct device *dev,
unsigned long value;
int ret;
- ret = strict_strtoul(data, 10, &value);
+ ret = kstrtoul(data, 10, &value);
if (ret < 0)
return ret;
@@ -61,7 +61,7 @@ static ssize_t amd64_inject_word_store(struct device *dev,
unsigned long value;
int ret;
- ret = strict_strtoul(data, 10, &value);
+ ret = kstrtoul(data, 10, &value);
if (ret < 0)
return ret;
@@ -97,7 +97,7 @@ static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
unsigned long value;
int ret;
- ret = strict_strtoul(data, 16, &value);
+ ret = kstrtoul(data, 16, &value);
if (ret < 0)
return ret;
@@ -124,7 +124,7 @@ static ssize_t amd64_inject_read_store(struct device *dev,
u32 section, word_bits;
int ret;
- ret = strict_strtoul(data, 10, &value);
+ ret = kstrtoul(data, 10, &value);
if (ret < 0)
return ret;
@@ -157,7 +157,7 @@ static ssize_t amd64_inject_write_store(struct device *dev,
unsigned long value;
int ret;
- ret = strict_strtoul(data, 10, &value);
+ ret = kstrtoul(data, 10, &value);
if (ret < 0)
return ret;
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 67610a6ebf87..ef15a7e613bc 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -678,7 +678,7 @@ static ssize_t mci_sdram_scrub_rate_store(struct device *dev,
unsigned long bandwidth = 0;
int new_bw = 0;
- if (strict_strtoul(data, 10, &bandwidth) < 0)
+ if (kstrtoul(data, 10, &bandwidth) < 0)
return -EINVAL;
new_bw = mci->set_sdram_scrub_rate(mci, bandwidth);
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 0ec3e95a12cd..80a963d64e58 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -704,7 +704,7 @@ static ssize_t i7core_inject_section_store(struct device *dev,
if (pvt->inject.enable)
disable_inject(mci);
- rc = strict_strtoul(data, 10, &value);
+ rc = kstrtoul(data, 10, &value);
if ((rc < 0) || (value > 3))
return -EIO;
@@ -741,7 +741,7 @@ struct i7core_pvt *pvt = mci->pvt_info;
if (pvt->inject.enable)
disable_inject(mci);
- rc = strict_strtoul(data, 10, &value);
+ rc = kstrtoul(data, 10, &value);
if ((rc < 0) || (value > 7))
return -EIO;
@@ -781,7 +781,7 @@ static ssize_t i7core_inject_eccmask_store(struct device *dev,
if (pvt->inject.enable)
disable_inject(mci);
- rc = strict_strtoul(data, 10, &value);
+ rc = kstrtoul(data, 10, &value);
if (rc < 0)
return -EIO;
@@ -830,7 +830,7 @@ static ssize_t i7core_inject_store_##param( \
if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\
value = -1; \
else { \
- rc = strict_strtoul(data, 10, &value); \
+ rc = kstrtoul(data, 10, &value); \
if ((rc < 0) || (value >= limit)) \
return -EIO; \
} \
@@ -934,7 +934,7 @@ static ssize_t i7core_inject_enable_store(struct device *dev,
if (!pvt->pci_ch[pvt->inject.channel][0])
return 0;
- rc = strict_strtoul(data, 10, &enable);
+ rc = kstrtoul(data, 10, &enable);
if ((rc < 0))
return 0;
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index f3f0c930d550..30f7309446a6 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -134,7 +134,8 @@ static const char * const mc5_mce_desc[] = {
"Physical register file AG0 port",
"Physical register file AG1 port",
"Flag register file",
- "DE error occurred"
+ "DE error occurred",
+ "Retire status queue"
};
static bool f12h_mc0_mce(u16 ec, u8 xec)
@@ -624,7 +625,7 @@ static void decode_mc5_mce(struct mce *m)
if (xec == 0x0 || xec == 0xc)
pr_cont("%s.\n", mc5_mce_desc[xec]);
- else if (xec < 0xd)
+ else if (xec <= 0xd)
pr_cont("%s parity error.\n", mc5_mce_desc[xec]);
else
goto wrong_mc5_mce;
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 2ae78f20cc28..5e46a9fea31b 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -43,7 +43,7 @@ static ssize_t edac_inject_##reg##_store(struct kobject *kobj, \
int ret = 0; \
unsigned long value; \
\
- ret = strict_strtoul(data, 16, &value); \
+ ret = kstrtoul(data, 16, &value); \
if (ret < 0) \
printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \
\
@@ -83,7 +83,7 @@ static ssize_t edac_inject_bank_store(struct kobject *kobj,
int ret = 0;
unsigned long value;
- ret = strict_strtoul(data, 10, &value);
+ ret = kstrtoul(data, 10, &value);
if (ret < 0) {
printk(KERN_ERR "Invalid bank value!\n");
return -EINVAL;
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 8c69803558fe..18ccadef43fd 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -602,7 +602,7 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
edev->dev->class = extcon_class;
edev->dev->release = extcon_dev_release;
- dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+ dev_set_name(edev->dev, "%s", edev->name ? edev->name : dev_name(dev));
if (edev->max_supported) {
char buf[10];
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 664a6ff0a823..de4aa409abe2 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -165,25 +165,44 @@ static bool match_ids(const struct ieee1394_device_id *id_table, int *id)
return (match & id_table->match_flags) == id_table->match_flags;
}
-static bool is_fw_unit(struct device *dev);
-
-static int fw_unit_match(struct device *dev, struct device_driver *drv)
+static const struct ieee1394_device_id *unit_match(struct device *dev,
+ struct device_driver *drv)
{
const struct ieee1394_device_id *id_table =
container_of(drv, struct fw_driver, driver)->id_table;
int id[] = {0, 0, 0, 0};
- /* We only allow binding to fw_units. */
- if (!is_fw_unit(dev))
- return 0;
-
get_modalias_ids(fw_unit(dev), id);
for (; id_table->match_flags != 0; id_table++)
if (match_ids(id_table, id))
- return 1;
+ return id_table;
- return 0;
+ return NULL;
+}
+
+static bool is_fw_unit(struct device *dev);
+
+static int fw_unit_match(struct device *dev, struct device_driver *drv)
+{
+ /* We only allow binding to fw_units. */
+ return is_fw_unit(dev) && unit_match(dev, drv) != NULL;
+}
+
+static int fw_unit_probe(struct device *dev)
+{
+ struct fw_driver *driver =
+ container_of(dev->driver, struct fw_driver, driver);
+
+ return driver->probe(fw_unit(dev), unit_match(dev, dev->driver));
+}
+
+static int fw_unit_remove(struct device *dev)
+{
+ struct fw_driver *driver =
+ container_of(dev->driver, struct fw_driver, driver);
+
+ return driver->remove(fw_unit(dev)), 0;
}
static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
@@ -213,6 +232,8 @@ static int fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
struct bus_type fw_bus_type = {
.name = "firewire",
.match = fw_unit_match,
+ .probe = fw_unit_probe,
+ .remove = fw_unit_remove,
};
EXPORT_SYMBOL(fw_bus_type);
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 815b0fcbe918..6b895986dc22 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -1440,9 +1440,9 @@ static int fwnet_add_peer(struct fwnet_device *dev,
return 0;
}
-static int fwnet_probe(struct device *_dev)
+static int fwnet_probe(struct fw_unit *unit,
+ const struct ieee1394_device_id *id)
{
- struct fw_unit *unit = fw_unit(_dev);
struct fw_device *device = fw_parent_device(unit);
struct fw_card *card = device->card;
struct net_device *net;
@@ -1526,6 +1526,24 @@ static int fwnet_probe(struct device *_dev)
return ret;
}
+/*
+ * FIXME abort partially sent fragmented datagrams,
+ * discard partially received fragmented datagrams
+ */
+static void fwnet_update(struct fw_unit *unit)
+{
+ struct fw_device *device = fw_parent_device(unit);
+ struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
+ int generation;
+
+ generation = device->generation;
+
+ spin_lock_irq(&peer->dev->lock);
+ peer->node_id = device->node_id;
+ peer->generation = generation;
+ spin_unlock_irq(&peer->dev->lock);
+}
+
static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
{
struct fwnet_partial_datagram *pd, *pd_next;
@@ -1542,9 +1560,9 @@ static void fwnet_remove_peer(struct fwnet_peer *peer, struct fwnet_device *dev)
kfree(peer);
}
-static int fwnet_remove(struct device *_dev)
+static void fwnet_remove(struct fw_unit *unit)
{
- struct fwnet_peer *peer = dev_get_drvdata(_dev);
+ struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
struct fwnet_device *dev = peer->dev;
struct net_device *net;
int i;
@@ -1569,26 +1587,6 @@ static int fwnet_remove(struct device *_dev)
}
mutex_unlock(&fwnet_device_mutex);
-
- return 0;
-}
-
-/*
- * FIXME abort partially sent fragmented datagrams,
- * discard partially received fragmented datagrams
- */
-static void fwnet_update(struct fw_unit *unit)
-{
- struct fw_device *device = fw_parent_device(unit);
- struct fwnet_peer *peer = dev_get_drvdata(&unit->device);
- int generation;
-
- generation = device->generation;
-
- spin_lock_irq(&peer->dev->lock);
- peer->node_id = device->node_id;
- peer->generation = generation;
- spin_unlock_irq(&peer->dev->lock);
}
static const struct ieee1394_device_id fwnet_id_table[] = {
@@ -1614,10 +1612,10 @@ static struct fw_driver fwnet_driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.bus = &fw_bus_type,
- .probe = fwnet_probe,
- .remove = fwnet_remove,
},
+ .probe = fwnet_probe,
.update = fwnet_update,
+ .remove = fwnet_remove,
.id_table = fwnet_id_table,
};
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 47674b913843..281029daf98c 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1128,11 +1128,10 @@ static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
}
static struct scsi_host_template scsi_driver_template;
-static int sbp2_remove(struct device *dev);
+static void sbp2_remove(struct fw_unit *unit);
-static int sbp2_probe(struct device *dev)
+static int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
{
- struct fw_unit *unit = fw_unit(dev);
struct fw_device *device = fw_parent_device(unit);
struct sbp2_target *tgt;
struct sbp2_logical_unit *lu;
@@ -1196,7 +1195,7 @@ static int sbp2_probe(struct device *dev)
return 0;
fail_remove:
- sbp2_remove(dev);
+ sbp2_remove(unit);
return -ENOMEM;
fail_shost_put:
@@ -1222,9 +1221,8 @@ static void sbp2_update(struct fw_unit *unit)
}
}
-static int sbp2_remove(struct device *dev)
+static void sbp2_remove(struct fw_unit *unit)
{
- struct fw_unit *unit = fw_unit(dev);
struct fw_device *device = fw_parent_device(unit);
struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
struct sbp2_logical_unit *lu, *next;
@@ -1261,10 +1259,9 @@ static int sbp2_remove(struct device *dev)
kfree(lu);
}
scsi_remove_host(shost);
- dev_notice(dev, "released target %d:0:0\n", shost->host_no);
+ dev_notice(&unit->device, "released target %d:0:0\n", shost->host_no);
scsi_host_put(shost);
- return 0;
}
#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
@@ -1285,10 +1282,10 @@ static struct fw_driver sbp2_driver = {
.owner = THIS_MODULE,
.name = KBUILD_MODNAME,
.bus = &fw_bus_type,
- .probe = sbp2_probe,
- .remove = sbp2_remove,
},
+ .probe = sbp2_probe,
.update = sbp2_update,
+ .remove = sbp2_remove,
.id_table = sbp2_id_table,
};
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index b95159b33c39..eb760a218da4 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -551,9 +551,15 @@ static bool dmi_matches(const struct dmi_system_id *dmi)
int s = dmi->matches[i].slot;
if (s == DMI_NONE)
break;
- if (dmi_ident[s]
- && strstr(dmi_ident[s], dmi->matches[i].substr))
- continue;
+ if (dmi_ident[s]) {
+ if (!dmi->matches[i].exact_match &&
+ strstr(dmi_ident[s], dmi->matches[i].substr))
+ continue;
+ else if (dmi->matches[i].exact_match &&
+ !strcmp(dmi_ident[s], dmi->matches[i].substr))
+ continue;
+ }
+
/* No match */
return false;
}
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index 202d2c85ba2e..73de5a9c2247 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -79,10 +79,9 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
&entry->var.DataSize, entry->var.Data);
size = entry->var.DataSize;
- *cb_data->buf = kmalloc(size, GFP_KERNEL);
+ *cb_data->buf = kmemdup(entry->var.Data, size, GFP_KERNEL);
if (*cb_data->buf == NULL)
return -ENOMEM;
- memcpy(*cb_data->buf, entry->var.Data, size);
return size;
}
@@ -104,7 +103,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
static int efi_pstore_write(enum pstore_type_id type,
enum kmsg_dump_reason reason, u64 *id,
- unsigned int part, int count, size_t size,
+ unsigned int part, int count, size_t hsize, size_t size,
struct pstore_info *psi)
{
char name[DUMP_NAME_LEN];
@@ -236,7 +235,11 @@ static __init int efivars_pstore_init(void)
efi_pstore_info.bufsize = 1024;
spin_lock_init(&efi_pstore_info.buf_lock);
- pstore_register(&efi_pstore_info);
+ if (pstore_register(&efi_pstore_info)) {
+ kfree(efi_pstore_info.buf);
+ efi_pstore_info.buf = NULL;
+ efi_pstore_info.bufsize = 0;
+ }
return 0;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 94624370caad..b2450ba14138 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -244,7 +244,7 @@ config GPIO_TS5500
config GPIO_XILINX
bool "Xilinx GPIO support"
- depends on PPC_OF || MICROBLAZE
+ depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
help
Say yes here to support the Xilinx FPGA GPIO device
@@ -340,7 +340,7 @@ config GPIO_MAX7300
depends on I2C
select GPIO_MAX730X
help
- GPIO driver for Maxim MAX7301 I2C-based GPIO expander.
+ GPIO driver for Maxim MAX7300 I2C-based GPIO expander.
config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 1077754f8289..3e7812f0405e 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -34,10 +34,10 @@ static int devm_gpio_match(struct device *dev, void *res, void *data)
}
/**
- * devm_gpio_request - request a gpio for a managed device
- * @dev: device to request the gpio for
- * @gpio: gpio to allocate
- * @label: the name of the requested gpio
+ * devm_gpio_request - request a GPIO for a managed device
+ * @dev: device to request the GPIO for
+ * @gpio: GPIO to allocate
+ * @label: the name of the requested GPIO
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as
@@ -101,9 +101,9 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio,
EXPORT_SYMBOL(devm_gpio_request_one);
/**
- * devm_gpio_free - free an interrupt
- * @dev: device to free gpio for
- * @gpio: gpio to free
+ * devm_gpio_free - free a GPIO
+ * @dev: device to free GPIO for
+ * @gpio: GPIO to free
*
* Except for the extra @dev argument, this function takes the
* same arguments and performs the same function as gpio_free().
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index 7d9d7cb35f28..8369e71ebe4f 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -286,7 +286,7 @@ static int bt8xxgpio_resume(struct pci_dev *pdev)
unsigned long flags;
int err;
- pci_set_power_state(pdev, 0);
+ pci_set_power_state(pdev, PCI_D0);
err = pci_enable_device(pdev);
if (err)
return err;
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 8e08b8647655..84d2478ec294 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -235,8 +235,8 @@ static irqreturn_t grgpio_irq_handler(int irq, void *dev)
* This function will be called as a consequence of the call to
* irq_create_mapping in grgpio_to_irq
*/
-int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct grgpio_priv *priv = d->host_data;
struct grgpio_lirq *lirq;
@@ -291,7 +291,7 @@ int grgpio_irq_map(struct irq_domain *d, unsigned int irq,
return ret;
}
-void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
+static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq)
{
struct grgpio_priv *priv = d->host_data;
int index;
diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c
index e16d932fd444..2729e3d2d5bb 100644
--- a/drivers/gpio/gpio-ich.c
+++ b/drivers/gpio/gpio-ich.c
@@ -41,12 +41,14 @@ enum GPIO_REG {
GPIO_USE_SEL = 0,
GPIO_IO_SEL,
GPIO_LVL,
+ GPO_BLINK
};
-static const u8 ichx_regs[3][3] = {
+static const u8 ichx_regs[4][3] = {
{0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */
{0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
+ {0x18, 0x18, 0x18}, /* BLINK offset */
};
static const u8 ichx_reglen[3] = {
@@ -148,6 +150,10 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
+ /* Disable blink hardware which is available for GPIOs from 0 to 31. */
+ if (nr < 32)
+ ichx_write_bit(GPO_BLINK, nr, 0, 0);
+
/* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0);
diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c
index 62ef10a641c4..bfa1af1b519f 100644
--- a/drivers/gpio/gpio-langwell.c
+++ b/drivers/gpio/gpio-langwell.c
@@ -1,7 +1,7 @@
/*
* Moorestown platform Langwell chip GPIO driver
*
- * Copyright (c) 2008 - 2009, Intel Corporation.
+ * Copyright (c) 2008, 2009, 2013, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,7 +20,6 @@
/* Supports:
* Moorestown platform Langwell chip.
* Medfield platform Penwell chip.
- * Whitney point.
*/
#include <linux/module.h>
@@ -65,7 +64,7 @@ enum GPIO_REG {
struct lnw_gpio {
struct gpio_chip chip;
- void *reg_base;
+ void __iomem *reg_base;
spinlock_t lock;
struct pci_dev *pdev;
struct irq_domain *domain;
@@ -74,15 +73,13 @@ struct lnw_gpio {
#define to_lnw_priv(chip) container_of(chip, struct lnw_gpio, chip)
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
- enum GPIO_REG reg_type)
+ enum GPIO_REG reg_type)
{
struct lnw_gpio *lnw = to_lnw_priv(chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 32;
- void __iomem *ptr;
- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
- return ptr;
+ return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
}
static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
@@ -91,10 +88,8 @@ static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
struct lnw_gpio *lnw = to_lnw_priv(chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 16;
- void __iomem *ptr;
- ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
- return ptr;
+ return lnw->reg_base + reg_type * nreg * 4 + reg * 4;
}
static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -305,11 +300,7 @@ static const struct irq_domain_ops lnw_gpio_irq_ops = {
static int lnw_gpio_runtime_idle(struct device *dev)
{
- int err = pm_schedule_suspend(dev, 500);
-
- if (!err)
- return 0;
-
+ pm_schedule_suspend(dev, 500);
return -EBUSY;
}
@@ -318,56 +309,40 @@ static const struct dev_pm_ops lnw_gpio_pm_ops = {
};
static int lnw_gpio_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
+ const struct pci_device_id *id)
{
- void *base;
- resource_size_t start, len;
+ void __iomem *base;
struct lnw_gpio *lnw;
u32 gpio_base;
u32 irq_base;
int retval;
int ngpio = id->driver_data;
- retval = pci_enable_device(pdev);
+ retval = pcim_enable_device(pdev);
if (retval)
return retval;
- retval = pci_request_regions(pdev, "langwell_gpio");
+ retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev));
if (retval) {
- dev_err(&pdev->dev, "error requesting resources\n");
- goto err_pci_req_region;
- }
- /* get the gpio_base from bar1 */
- start = pci_resource_start(pdev, 1);
- len = pci_resource_len(pdev, 1);
- base = ioremap_nocache(start, len);
- if (!base) {
- dev_err(&pdev->dev, "error mapping bar1\n");
- retval = -EFAULT;
- goto err_ioremap;
+ dev_err(&pdev->dev, "I/O memory mapping error\n");
+ return retval;
}
- irq_base = *(u32 *)base;
- gpio_base = *((u32 *)base + 1);
+
+ base = pcim_iomap_table(pdev)[1];
+
+ irq_base = readl(base);
+ gpio_base = readl(sizeof(u32) + base);
+
/* release the IO mapping, since we already get the info from bar1 */
- iounmap(base);
- /* get the register base from bar0 */
- start = pci_resource_start(pdev, 0);
- len = pci_resource_len(pdev, 0);
- base = devm_ioremap_nocache(&pdev->dev, start, len);
- if (!base) {
- dev_err(&pdev->dev, "error mapping bar0\n");
- retval = -EFAULT;
- goto err_ioremap;
- }
+ pcim_iounmap_regions(pdev, 1 << 1);
lnw = devm_kzalloc(&pdev->dev, sizeof(*lnw), GFP_KERNEL);
if (!lnw) {
- dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
- retval = -ENOMEM;
- goto err_ioremap;
+ dev_err(&pdev->dev, "can't allocate chip data\n");
+ return -ENOMEM;
}
- lnw->reg_base = base;
+ lnw->reg_base = pcim_iomap_table(pdev)[0];
lnw->chip.label = dev_name(&pdev->dev);
lnw->chip.request = lnw_gpio_request;
lnw->chip.direction_input = lnw_gpio_direction_input;
@@ -380,18 +355,18 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.can_sleep = 0;
lnw->pdev = pdev;
+ spin_lock_init(&lnw->lock);
+
lnw->domain = irq_domain_add_simple(pdev->dev.of_node, ngpio, irq_base,
&lnw_gpio_irq_ops, lnw);
- if (!lnw->domain) {
- retval = -ENOMEM;
- goto err_ioremap;
- }
+ if (!lnw->domain)
+ return -ENOMEM;
pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip);
if (retval) {
- dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
- goto err_ioremap;
+ dev_err(&pdev->dev, "gpiochip_add error %d\n", retval);
+ return retval;
}
lnw_irq_init_hw(lnw);
@@ -399,18 +374,10 @@ static int lnw_gpio_probe(struct pci_dev *pdev,
irq_set_handler_data(pdev->irq, lnw);
irq_set_chained_handler(pdev->irq, lnw_irq_handler);
- spin_lock_init(&lnw->lock);
-
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
return 0;
-
-err_ioremap:
- pci_release_regions(pdev);
-err_pci_req_region:
- pci_disable_device(pdev);
- return retval;
}
static struct pci_driver lnw_gpio_driver = {
@@ -422,88 +389,9 @@ static struct pci_driver lnw_gpio_driver = {
},
};
-
-static int wp_gpio_probe(struct platform_device *pdev)
-{
- struct lnw_gpio *lnw;
- struct gpio_chip *gc;
- struct resource *rc;
- int retval = 0;
-
- rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!rc)
- return -EINVAL;
-
- lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
- if (!lnw) {
- dev_err(&pdev->dev,
- "can't allocate whitneypoint_gpio chip data\n");
- return -ENOMEM;
- }
- lnw->reg_base = ioremap_nocache(rc->start, resource_size(rc));
- if (lnw->reg_base == NULL) {
- retval = -EINVAL;
- goto err_kmalloc;
- }
- spin_lock_init(&lnw->lock);
- gc = &lnw->chip;
- gc->label = dev_name(&pdev->dev);
- gc->owner = THIS_MODULE;
- gc->direction_input = lnw_gpio_direction_input;
- gc->direction_output = lnw_gpio_direction_output;
- gc->get = lnw_gpio_get;
- gc->set = lnw_gpio_set;
- gc->to_irq = NULL;
- gc->base = 0;
- gc->ngpio = 64;
- gc->can_sleep = 0;
- retval = gpiochip_add(gc);
- if (retval) {
- dev_err(&pdev->dev, "whitneypoint gpiochip_add error %d\n",
- retval);
- goto err_ioremap;
- }
- platform_set_drvdata(pdev, lnw);
- return 0;
-err_ioremap:
- iounmap(lnw->reg_base);
-err_kmalloc:
- kfree(lnw);
- return retval;
-}
-
-static int wp_gpio_remove(struct platform_device *pdev)
-{
- struct lnw_gpio *lnw = platform_get_drvdata(pdev);
- int err;
- err = gpiochip_remove(&lnw->chip);
- if (err)
- dev_err(&pdev->dev, "failed to remove gpio_chip.\n");
- iounmap(lnw->reg_base);
- kfree(lnw);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-static struct platform_driver wp_gpio_driver = {
- .probe = wp_gpio_probe,
- .remove = wp_gpio_remove,
- .driver = {
- .name = "wp_gpio",
- .owner = THIS_MODULE,
- },
-};
-
static int __init lnw_gpio_init(void)
{
- int ret;
- ret = pci_register_driver(&lnw_gpio_driver);
- if (ret < 0)
- return ret;
- ret = platform_driver_register(&wp_gpio_driver);
- if (ret < 0)
- pci_unregister_driver(&lnw_gpio_driver);
- return ret;
+ return pci_register_driver(&lnw_gpio_driver);
}
device_initcall(lnw_gpio_init);
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index 86c17de87692..761c4705dfbb 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -447,7 +447,6 @@ static int lp_gpio_remove(struct platform_device *pdev)
err = gpiochip_remove(&lg->chip);
if (err)
dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index 0966f2637ad2..6da6d7667c6d 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -465,6 +465,7 @@ static int ioh_gpio_probe(struct pci_dev *pdev,
dev_warn(&pdev->dev,
"ml_ioh_gpio: Failed to get IRQ base num\n");
chip->irq_base = -1;
+ ret = irq_base;
goto err_irq_alloc_descs;
}
chip->irq_base = irq_base;
diff --git a/drivers/gpio/gpio-msm-v1.c b/drivers/gpio/gpio-msm-v1.c
index fb2cc90d0134..e3ceaacde45c 100644
--- a/drivers/gpio/gpio-msm-v1.c
+++ b/drivers/gpio/gpio-msm-v1.c
@@ -652,14 +652,14 @@ static int gpio_msm_v1_probe(struct platform_device *pdev)
return irq2;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base1 = devm_request_and_ioremap(&pdev->dev, res);
- if (!base1)
- return -EADDRNOTAVAIL;
+ base1 = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base1))
+ return PTR_ERR(base1);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- base2 = devm_request_and_ioremap(&pdev->dev, res);
- if (!base2)
- return -EADDRNOTAVAIL;
+ base2 = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base2))
+ return PTR_ERR(base2);
for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
if (i - FIRST_GPIO_IRQ >=
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 4a430360af5a..dfeb3a3a8f20 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1482,7 +1482,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
-static void omap_gpio_init_context(struct gpio_bank *p) {}
+static inline void omap_gpio_init_context(struct gpio_bank *p) {}
#endif
static const struct dev_pm_ops gpio_pm_ops = {
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 6ec82f76f019..e8198dd68615 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -232,7 +232,14 @@ static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)
static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)
{
- return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & BIT(offset));
+ u32 bit = BIT(offset);
+
+ /* testing on r8a7790 shows that INDT does not show correct pin state
+ * when configured as output, so use OUTDT in case of output pins */
+ if (gpio_rcar_read(gpio_to_priv(chip), INOUTSEL) & bit)
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), OUTDT) & bit);
+ else
+ return (int)(gpio_rcar_read(gpio_to_priv(chip), INDT) & bit);
}
static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)
diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c
index 1bf55f67f7a5..368c3c00fca5 100644
--- a/drivers/gpio/gpio-rdc321x.c
+++ b/drivers/gpio/gpio-rdc321x.c
@@ -187,20 +187,18 @@ static int rdc321x_gpio_probe(struct platform_device *pdev)
rdc321x_gpio_dev->reg1_data_base,
&rdc321x_gpio_dev->data_reg[0]);
if (err)
- goto out_drvdata;
+ goto out_free;
err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev,
rdc321x_gpio_dev->reg2_data_base,
&rdc321x_gpio_dev->data_reg[1]);
if (err)
- goto out_drvdata;
+ goto out_free;
dev_info(&pdev->dev, "registering %d GPIOs\n",
rdc321x_gpio_dev->chip.ngpio);
return gpiochip_add(&rdc321x_gpio_dev->chip);
-out_drvdata:
- platform_set_drvdata(pdev, NULL);
out_free:
kfree(rdc321x_gpio_dev);
return err;
@@ -216,7 +214,6 @@ static int rdc321x_gpio_remove(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to unregister chip\n");
kfree(rdc321x_gpio_dev);
- platform_set_drvdata(pdev, NULL);
return ret;
}
diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c
index 558542552aae..f43ab6aea281 100644
--- a/drivers/gpio/gpio-sta2x11.c
+++ b/drivers/gpio/gpio-sta2x11.c
@@ -371,8 +371,12 @@ static int gsta_probe(struct platform_device *dev)
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
chip->dev = &dev->dev;
- chip->reg_base = devm_request_and_ioremap(&dev->dev, res);
+ chip->reg_base = devm_ioremap_resource(&dev->dev, res);
+ if (IS_ERR(chip->reg_base))
+ return PTR_ERR(chip->reg_base);
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
chip->regs[i] = chip->reg_base + i * 4096;
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 3ce5bc38ac31..b33bad1bb4df 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -271,8 +271,8 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
return IRQ_HANDLED;
}
-int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
- irq_hw_number_t hwirq)
+static int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hwirq)
{
struct stmpe_gpio *stmpe_gpio = d->host_data;
@@ -292,7 +292,7 @@ int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq,
return 0;
}
-void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
+static void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq)
{
#ifdef CONFIG_ARM
set_irq_flags(virq, 0);
@@ -431,7 +431,6 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
if (irq >= 0)
free_irq(irq, stmpe_gpio);
- platform_set_drvdata(pdev, NULL);
kfree(stmpe_gpio);
return 0;
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index 796b6c42fa70..f371732591d2 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -548,7 +548,8 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
#endif
}
- err = request_threaded_irq(irq_summary,
+ err = devm_request_threaded_irq(&chip->client->dev,
+ irq_summary,
NULL,
sx150x_irq_thread_fn,
IRQF_SHARED | IRQF_TRIGGER_FALLING,
@@ -567,8 +568,6 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
unsigned n;
unsigned irq;
- free_irq(chip->irq_summary, chip);
-
for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
irq = chip->irq_base + n;
irq_set_chip_and_handler(irq, NULL, NULL);
@@ -591,18 +590,19 @@ static int sx150x_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, i2c_funcs))
return -ENOSYS;
- chip = kzalloc(sizeof(struct sx150x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct sx150x_chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
sx150x_init_chip(chip, client, id->driver_data, pdata);
rc = sx150x_init_hw(chip, pdata);
if (rc < 0)
- goto probe_fail_pre_gpiochip_add;
+ return rc;
rc = gpiochip_add(&chip->gpio_chip);
- if (rc < 0)
- goto probe_fail_pre_gpiochip_add;
+ if (rc)
+ return rc;
if (pdata->irq_summary >= 0) {
rc = sx150x_install_irq_chip(chip,
@@ -617,8 +617,6 @@ static int sx150x_probe(struct i2c_client *client,
return 0;
probe_fail_post_gpiochip_add:
WARN_ON(gpiochip_remove(&chip->gpio_chip) < 0);
-probe_fail_pre_gpiochip_add:
- kfree(chip);
return rc;
}
@@ -635,8 +633,6 @@ static int sx150x_remove(struct i2c_client *client)
if (chip->irq_summary >= 0)
sx150x_remove_irq_chip(chip);
- kfree(chip);
-
return 0;
}
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index d34d80dfb083..4a5de273c230 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -407,7 +407,6 @@ static int tc3589x_gpio_remove(struct platform_device *pdev)
free_irq(irq, tc3589x_gpio);
- platform_set_drvdata(pdev, NULL);
kfree(tc3589x_gpio);
return 0;
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 43774058b693..4c65f8883204 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -342,8 +342,6 @@ static int timbgpio_remove(struct platform_device *pdev)
release_mem_region(iomem->start, resource_size(iomem));
kfree(tgpio);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 2b7252cb2427..cddfa22edb41 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -279,7 +279,6 @@ out_release:
release_region(res_gpi->start, resource_size(res_gpi));
if (vg->gpo_reserved)
release_region(res_gpi->start, resource_size(res_gpo));
- platform_set_drvdata(pdev, NULL);
kfree(vg);
return ret;
}
@@ -301,7 +300,6 @@ static int vx855gpio_remove(struct platform_device *pdev)
release_region(res->start, resource_size(res));
}
- platform_set_drvdata(pdev, NULL);
kfree(vg);
return 0;
}
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 9ae7aa8ca48a..792a05ad4649 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -1,7 +1,7 @@
/*
- * Xilinx gpio driver
+ * Xilinx gpio driver for xps/axi_gpio IP.
*
- * Copyright 2008 Xilinx, Inc.
+ * Copyright 2008 - 2013 Xilinx, 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
@@ -12,6 +12,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -26,11 +27,31 @@
#define XGPIO_DATA_OFFSET (0x0) /* Data register */
#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */
+#define XGPIO_CHANNEL_OFFSET 0x8
+
+/* Read/Write access to the GPIO registers */
+#ifdef CONFIG_ARCH_ZYNQ
+# define xgpio_readreg(offset) readl(offset)
+# define xgpio_writereg(offset, val) writel(val, offset)
+#else
+# define xgpio_readreg(offset) __raw_readl(offset)
+# define xgpio_writereg(offset, val) __raw_writel(val, offset)
+#endif
+
+/**
+ * struct xgpio_instance - Stores information about GPIO device
+ * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks
+ * gpio_state: GPIO state shadow register
+ * gpio_dir: GPIO direction shadow register
+ * offset: GPIO channel offset
+ * gpio_lock: Lock used for synchronization
+ */
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
- u32 gpio_state; /* GPIO state shadow register */
- u32 gpio_dir; /* GPIO direction shadow register */
- spinlock_t gpio_lock; /* Lock used for synchronization */
+ u32 gpio_state;
+ u32 gpio_dir;
+ u32 offset;
+ spinlock_t gpio_lock;
};
/**
@@ -44,8 +65,12 @@ struct xgpio_instance {
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct xgpio_instance *chip =
+ container_of(mm_gc, struct xgpio_instance, mmchip);
- return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
+ void __iomem *regs = mm_gc->regs + chip->offset;
+
+ return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio));
}
/**
@@ -63,15 +88,18 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write to GPIO signal and set its direction to output */
if (val)
- chip->gpio_state |= 1 << gpio;
+ chip->gpio_state |= BIT(gpio);
else
- chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+ chip->gpio_state &= ~BIT(gpio);
+
+ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
}
@@ -91,12 +119,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */
- chip->gpio_dir |= (1 << gpio);
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir |= BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -119,19 +148,21 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Write state of GPIO signal */
if (val)
- chip->gpio_state |= 1 << gpio;
+ chip->gpio_state |= BIT(gpio);
else
- chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
+ chip->gpio_state &= ~BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
/* Clear the GPIO bit in shadow register and set direction as output */
- chip->gpio_dir &= (~(1 << gpio));
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir &= ~BIT(gpio);
+ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
spin_unlock_irqrestore(&chip->gpio_lock, flags);
@@ -147,8 +178,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
+ chip->gpio_state);
+ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET,
+ chip->gpio_dir);
}
/**
@@ -170,24 +203,20 @@ static int xgpio_of_probe(struct device_node *np)
return -ENOMEM;
/* Update GPIO state shadow register with default value */
- tree_info = of_get_property(np, "xlnx,dout-default", NULL);
- if (tree_info)
- chip->gpio_state = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
+
+ /* By default, all pins are inputs */
+ chip->gpio_dir = 0xFFFFFFFF;
/* Update GPIO direction shadow register with default value */
- chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
- tree_info = of_get_property(np, "xlnx,tri-default", NULL);
- if (tree_info)
- chip->gpio_dir = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
+
+ /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32;
/* Check device node and parent device node for device width */
- chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
- tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
- if (!tree_info)
- tree_info = of_get_property(np->parent,
- "xlnx,gpio-width", NULL);
- if (tree_info)
- chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
+ of_property_read_u32(np, "xlnx,gpio-width",
+ (u32 *)&chip->mmchip.gc.ngpio);
spin_lock_init(&chip->gpio_lock);
@@ -206,6 +235,57 @@ static int xgpio_of_probe(struct device_node *np)
np->full_name, status);
return status;
}
+
+ pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
+ chip->mmchip.gc.base);
+
+ tree_info = of_get_property(np, "xlnx,is-dual", NULL);
+ if (tree_info && be32_to_cpup(tree_info)) {
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ /* Add dual channel offset */
+ chip->offset = XGPIO_CHANNEL_OFFSET;
+
+ /* Update GPIO state shadow register with default value */
+ of_property_read_u32(np, "xlnx,dout-default-2",
+ &chip->gpio_state);
+
+ /* By default, all pins are inputs */
+ chip->gpio_dir = 0xFFFFFFFF;
+
+ /* Update GPIO direction shadow register with default value */
+ of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
+
+ /* By default assume full GPIO controller */
+ chip->mmchip.gc.ngpio = 32;
+
+ /* Check device node and parent device node for device width */
+ of_property_read_u32(np, "xlnx,gpio2-width",
+ (u32 *)&chip->mmchip.gc.ngpio);
+
+ spin_lock_init(&chip->gpio_lock);
+
+ chip->mmchip.gc.direction_input = xgpio_dir_in;
+ chip->mmchip.gc.direction_output = xgpio_dir_out;
+ chip->mmchip.gc.get = xgpio_get;
+ chip->mmchip.gc.set = xgpio_set;
+
+ chip->mmchip.save_regs = xgpio_save_regs;
+
+ /* Call the OF gpio helper to setup and register the GPIO dev */
+ status = of_mm_gpiochip_add(np, &chip->mmchip);
+ if (status) {
+ kfree(chip);
+ pr_err("%s: error in probe function with status %d\n",
+ np->full_name, status);
+ return status;
+ }
+ pr_info("XGpio: %s: dual channel registered, base is %d\n",
+ np->full_name, chip->mmchip.gc.base);
+ }
+
return 0;
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index c2534d62911c..ff0fd655729f 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+ spin_unlock_irqrestore(&gpio_lock, flags);
+
#ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&chip->pin_ranges);
#endif
of_gpiochip_add(chip);
-unlock:
- spin_unlock_irqrestore(&gpio_lock, flags);
-
if (status)
goto fail;
@@ -1235,6 +1234,9 @@ unlock:
chip->label ? : "generic");
return 0;
+
+unlock:
+ spin_unlock_irqrestore(&gpio_lock, flags);
fail:
/* failures here can mean systems won't boot... */
pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b16c50ee769c..a7c54c843291 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -139,6 +139,7 @@ config DRM_I915
select BACKLIGHT_CLASS_DEVICE if ACPI
select VIDEO_OUTPUT_CONTROL if ACPI
select INPUT if ACPI
+ select THERMAL if ACPI
select ACPI_VIDEO if ACPI
select ACPI_BUTTON if ACPI
help
@@ -213,6 +214,8 @@ source "drivers/gpu/drm/mgag200/Kconfig"
source "drivers/gpu/drm/cirrus/Kconfig"
+source "drivers/gpu/drm/rcar-du/Kconfig"
+
source "drivers/gpu/drm/shmobile/Kconfig"
source "drivers/gpu/drm/omapdrm/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1c9f24396002..801bcafa3028 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -12,7 +12,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \
drm_crtc.o drm_modes.o drm_edid.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
- drm_trace_points.o drm_global.o drm_prime.o
+ drm_trace_points.o drm_global.o drm_prime.o \
+ drm_rect.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -48,6 +49,7 @@ obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_GMA500) += gma500/
obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/
+obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_DRM_TILCDC) += tilcdc/
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 02e52d543e4b..622d4ae7eb9e 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -348,8 +348,24 @@ int ast_gem_create(struct drm_device *dev,
int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr);
int ast_bo_unpin(struct ast_bo *bo);
-int ast_bo_reserve(struct ast_bo *bo, bool no_wait);
-void ast_bo_unreserve(struct ast_bo *bo);
+static inline int ast_bo_reserve(struct ast_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+static inline void ast_bo_unreserve(struct ast_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
void ast_ttm_placement(struct ast_bo *bo, int domain);
int ast_bo_push_sysram(struct ast_bo *bo);
int ast_mmap(struct file *filp, struct vm_area_struct *vma);
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index fbc0823cfa18..7b33e14e44aa 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -51,7 +51,7 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
struct ast_bo *bo;
int src_offset, dst_offset;
int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8;
- int ret;
+ int ret = -EBUSY;
bool unmap = false;
bool store_for_later = false;
int x2, y2;
@@ -65,7 +65,8 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
* then the BO is being moved and we should
* store up the damage until later.
*/
- ret = ast_bo_reserve(bo, true);
+ if (!in_interrupt())
+ ret = ast_bo_reserve(bo, true);
if (ret) {
if (ret != -EBUSY)
return;
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
index 09da3393c527..98d670825a1a 100644
--- a/drivers/gpu/drm/ast/ast_ttm.c
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -271,26 +271,19 @@ int ast_mm_init(struct ast_private *ast)
return ret;
}
- ast->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0),
- DRM_MTRR_WC);
+ ast->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
return 0;
}
void ast_mm_fini(struct ast_private *ast)
{
- struct drm_device *dev = ast->dev;
ttm_bo_device_release(&ast->ttm.bdev);
ast_ttm_global_release(ast);
- if (ast->fb_mtrr >= 0) {
- drm_mtrr_del(ast->fb_mtrr,
- pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
- ast->fb_mtrr = -1;
- }
+ arch_phys_wc_del(ast->fb_mtrr);
}
void ast_ttm_placement(struct ast_bo *bo, int domain)
@@ -310,24 +303,6 @@ void ast_ttm_placement(struct ast_bo *bo, int domain)
bo->placement.num_busy_placement = c;
}
-int ast_bo_reserve(struct ast_bo *bo, bool no_wait)
-{
- int ret;
-
- ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
- if (ret) {
- if (ret != -ERESTARTSYS && ret != -EBUSY)
- DRM_ERROR("reserve failed %p\n", bo);
- return ret;
- }
- return 0;
-}
-
-void ast_bo_unreserve(struct ast_bo *bo)
-{
- ttm_bo_unreserve(&bo->bo);
-}
-
int ast_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct ast_bo **pastbo)
{
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 7ca059596887..bae55609e6c3 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -240,8 +240,25 @@ void cirrus_ttm_placement(struct cirrus_bo *bo, int domain);
int cirrus_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct cirrus_bo **pcirrusbo);
int cirrus_mmap(struct file *filp, struct vm_area_struct *vma);
-int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait);
-void cirrus_bo_unreserve(struct cirrus_bo *bo);
+
+static inline int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+static inline void cirrus_bo_unreserve(struct cirrus_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
int cirrus_bo_push_sysram(struct cirrus_bo *bo);
int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr);
#endif /* __CIRRUS_DRV_H__ */
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 3541b567bbd8..b27e95666fab 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -25,7 +25,7 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
struct cirrus_bo *bo;
int src_offset, dst_offset;
int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8;
- int ret;
+ int ret = -EBUSY;
bool unmap = false;
bool store_for_later = false;
int x2, y2;
@@ -39,7 +39,8 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
* then the BO is being moved and we should
* store up the damage until later.
*/
- ret = cirrus_bo_reserve(bo, true);
+ if (!in_interrupt())
+ ret = cirrus_bo_reserve(bo, true);
if (ret) {
if (ret != -EBUSY)
return;
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
index 2ed8cfc740c9..0047012045c2 100644
--- a/drivers/gpu/drm/cirrus/cirrus_ttm.c
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -271,9 +271,8 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
return ret;
}
- cirrus->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0),
- DRM_MTRR_WC);
+ cirrus->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
cirrus->mm_inited = true;
return 0;
@@ -281,8 +280,6 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
void cirrus_mm_fini(struct cirrus_device *cirrus)
{
- struct drm_device *dev = cirrus->dev;
-
if (!cirrus->mm_inited)
return;
@@ -290,12 +287,8 @@ void cirrus_mm_fini(struct cirrus_device *cirrus)
cirrus_ttm_global_release(cirrus);
- if (cirrus->fb_mtrr >= 0) {
- drm_mtrr_del(cirrus->fb_mtrr,
- pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
- cirrus->fb_mtrr = -1;
- }
+ arch_phys_wc_del(cirrus->fb_mtrr);
+ cirrus->fb_mtrr = 0;
}
void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
@@ -315,24 +308,6 @@ void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
bo->placement.num_busy_placement = c;
}
-int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
-{
- int ret;
-
- ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
- if (ret) {
- if (ret != -ERESTARTSYS && ret != -EBUSY)
- DRM_ERROR("reserve failed %p\n", bo);
- return ret;
- }
- return 0;
-}
-
-void cirrus_bo_unreserve(struct cirrus_bo *bo)
-{
- ttm_bo_unreserve(&bo->bo);
-}
-
int cirrus_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct cirrus_bo **pcirrusbo)
{
diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c
index 0128147265f3..5a4dbb410b71 100644
--- a/drivers/gpu/drm/drm_bufs.c
+++ b/drivers/gpu/drm/drm_bufs.c
@@ -210,12 +210,16 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
if (drm_core_has_MTRR(dev)) {
if (map->type == _DRM_FRAME_BUFFER ||
(map->flags & _DRM_WRITE_COMBINING)) {
- map->mtrr = mtrr_add(map->offset, map->size,
- MTRR_TYPE_WRCOMB, 1);
+ map->mtrr =
+ arch_phys_wc_add(map->offset, map->size);
}
}
if (map->type == _DRM_REGISTERS) {
- map->handle = ioremap(map->offset, map->size);
+ if (map->flags & _DRM_WRITE_COMBINING)
+ map->handle = ioremap_wc(map->offset,
+ map->size);
+ else
+ map->handle = ioremap(map->offset, map->size);
if (!map->handle) {
kfree(map);
return -ENOMEM;
@@ -410,6 +414,15 @@ int drm_addmap_ioctl(struct drm_device *dev, void *data,
/* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */
map->handle = (void *)(unsigned long)maplist->user_token;
+
+ /*
+ * It appears that there are no users of this value whatsoever --
+ * drmAddMap just discards it. Let's not encourage its use.
+ * (Keeping drm_addmap_core's returned mtrr value would be wrong --
+ * it's not a real mtrr index anymore.)
+ */
+ map->mtrr = -1;
+
return 0;
}
@@ -451,11 +464,8 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
iounmap(map->handle);
/* FALLTHROUGH */
case _DRM_FRAME_BUFFER:
- if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
- int retcode;
- retcode = mtrr_del(map->mtrr, map->offset, map->size);
- DRM_DEBUG("mtrr_del=%d\n", retcode);
- }
+ if (drm_core_has_MTRR(dev))
+ arch_phys_wc_del(map->mtrr);
break;
case _DRM_SHM:
vfree(map->handle);
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e7e92429d10f..fc83bb9eb514 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -29,6 +29,7 @@
* Dave Airlie <airlied@linux.ie>
* Jesse Barnes <jesse.barnes@intel.com>
*/
+#include <linux/ctype.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/export.h>
@@ -91,7 +92,7 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
/* Avoid boilerplate. I'm tired of typing. */
#define DRM_ENUM_NAME_FN(fnname, list) \
- char *fnname(int val) \
+ const char *fnname(int val) \
{ \
int i; \
for (i = 0; i < ARRAY_SIZE(list); i++) { \
@@ -104,7 +105,7 @@ EXPORT_SYMBOL(drm_warn_on_modeset_not_all_locked);
/*
* Global properties
*/
-static struct drm_prop_enum_list drm_dpms_enum_list[] =
+static const struct drm_prop_enum_list drm_dpms_enum_list[] =
{ { DRM_MODE_DPMS_ON, "On" },
{ DRM_MODE_DPMS_STANDBY, "Standby" },
{ DRM_MODE_DPMS_SUSPEND, "Suspend" },
@@ -116,7 +117,7 @@ DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
/*
* Optional properties
*/
-static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
+static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
{
{ DRM_MODE_SCALE_NONE, "None" },
{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
@@ -124,7 +125,7 @@ static struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
{ DRM_MODE_SCALE_ASPECT, "Full aspect" },
};
-static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
+static const struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
{
{ DRM_MODE_DITHERING_OFF, "Off" },
{ DRM_MODE_DITHERING_ON, "On" },
@@ -134,7 +135,7 @@ static struct drm_prop_enum_list drm_dithering_mode_enum_list[] =
/*
* Non-global properties, but "required" for certain connectors.
*/
-static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
+static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
{
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
@@ -143,7 +144,7 @@ static struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
-static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
+static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
{
{ DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
@@ -153,7 +154,7 @@ static struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
drm_dvi_i_subconnector_enum_list)
-static struct drm_prop_enum_list drm_tv_select_enum_list[] =
+static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
{
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
@@ -164,7 +165,7 @@ static struct drm_prop_enum_list drm_tv_select_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
-static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
+static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
{
{ DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
@@ -176,7 +177,7 @@ static struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_tv_subconnector_name,
drm_tv_subconnector_enum_list)
-static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
+static const struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
{ DRM_MODE_DIRTY_OFF, "Off" },
{ DRM_MODE_DIRTY_ON, "On" },
{ DRM_MODE_DIRTY_ANNOTATE, "Annotate" },
@@ -184,7 +185,7 @@ static struct drm_prop_enum_list drm_dirty_info_enum_list[] = {
struct drm_conn_prop_enum_list {
int type;
- char *name;
+ const char *name;
int count;
};
@@ -210,7 +211,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
{ DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0},
};
-static struct drm_prop_enum_list drm_encoder_enum_list[] =
+static const struct drm_prop_enum_list drm_encoder_enum_list[] =
{ { DRM_MODE_ENCODER_NONE, "None" },
{ DRM_MODE_ENCODER_DAC, "DAC" },
{ DRM_MODE_ENCODER_TMDS, "TMDS" },
@@ -219,7 +220,7 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] =
{ DRM_MODE_ENCODER_VIRTUAL, "Virtual" },
};
-char *drm_get_encoder_name(struct drm_encoder *encoder)
+const char *drm_get_encoder_name(const struct drm_encoder *encoder)
{
static char buf[32];
@@ -230,7 +231,7 @@ char *drm_get_encoder_name(struct drm_encoder *encoder)
}
EXPORT_SYMBOL(drm_get_encoder_name);
-char *drm_get_connector_name(struct drm_connector *connector)
+const char *drm_get_connector_name(const struct drm_connector *connector)
{
static char buf[32];
@@ -241,7 +242,7 @@ char *drm_get_connector_name(struct drm_connector *connector)
}
EXPORT_SYMBOL(drm_get_connector_name);
-char *drm_get_connector_status_name(enum drm_connector_status status)
+const char *drm_get_connector_status_name(enum drm_connector_status status)
{
if (status == connector_status_connected)
return "connected";
@@ -252,6 +253,28 @@ char *drm_get_connector_status_name(enum drm_connector_status status)
}
EXPORT_SYMBOL(drm_get_connector_status_name);
+static char printable_char(int c)
+{
+ return isascii(c) && isprint(c) ? c : '?';
+}
+
+const char *drm_get_format_name(uint32_t format)
+{
+ static char buf[32];
+
+ snprintf(buf, sizeof(buf),
+ "%c%c%c%c %s-endian (0x%08x)",
+ printable_char(format & 0xff),
+ printable_char((format >> 8) & 0xff),
+ printable_char((format >> 16) & 0xff),
+ printable_char((format >> 24) & 0x7f),
+ format & DRM_FORMAT_BIG_ENDIAN ? "big" : "little",
+ format);
+
+ return buf;
+}
+EXPORT_SYMBOL(drm_get_format_name);
+
/**
* drm_mode_object_get - allocate a new modeset identifier
* @dev: DRM device
@@ -569,16 +592,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
}
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
- if (plane->fb == fb) {
- /* should turn off the crtc */
- ret = plane->funcs->disable_plane(plane);
- if (ret)
- DRM_ERROR("failed to disable plane with busy fb\n");
- /* disconnect the plane from the fb and crtc: */
- __drm_framebuffer_unreference(plane->fb);
- plane->fb = NULL;
- plane->crtc = NULL;
- }
+ if (plane->fb == fb)
+ drm_plane_force_disable(plane);
}
drm_modeset_unlock_all(dev);
}
@@ -593,7 +608,7 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
* @crtc: CRTC object to init
* @funcs: callbacks for the new CRTC
*
- * Inits a new object created as base part of an driver crtc object.
+ * Inits a new object created as base part of a driver crtc object.
*
* RETURNS:
* Zero on success, error code on failure.
@@ -628,11 +643,12 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
EXPORT_SYMBOL(drm_crtc_init);
/**
- * drm_crtc_cleanup - Cleans up the core crtc usage.
+ * drm_crtc_cleanup - Clean up the core crtc usage
* @crtc: CRTC to cleanup
*
- * Cleanup @crtc. Removes from drm modesetting space
- * does NOT free object, caller does that.
+ * This function cleans up @crtc and removes it from the DRM mode setting
+ * core. Note that the function does *not* free the crtc structure itself,
+ * this is the responsibility of the caller.
*/
void drm_crtc_cleanup(struct drm_crtc *crtc)
{
@@ -657,7 +673,7 @@ EXPORT_SYMBOL(drm_crtc_cleanup);
void drm_mode_probed_add(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- list_add(&mode->head, &connector->probed_modes);
+ list_add_tail(&mode->head, &connector->probed_modes);
}
EXPORT_SYMBOL(drm_mode_probed_add);
@@ -803,6 +819,21 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
}
EXPORT_SYMBOL(drm_encoder_cleanup);
+/**
+ * drm_plane_init - Initialise a new plane object
+ * @dev: DRM device
+ * @plane: plane object to init
+ * @possible_crtcs: bitmask of possible CRTCs
+ * @funcs: callbacks for the new plane
+ * @formats: array of supported formats (%DRM_FORMAT_*)
+ * @format_count: number of elements in @formats
+ * @priv: plane is private (hidden from userspace)?
+ *
+ * Inits a new object created as base part of a driver plane object.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure.
+ */
int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
@@ -851,6 +882,14 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
}
EXPORT_SYMBOL(drm_plane_init);
+/**
+ * drm_plane_cleanup - Clean up the core plane usage
+ * @plane: plane to cleanup
+ *
+ * This function cleans up @plane and removes it from the DRM mode setting
+ * core. Note that the function does *not* free the plane structure itself,
+ * this is the responsibility of the caller.
+ */
void drm_plane_cleanup(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
@@ -868,6 +907,32 @@ void drm_plane_cleanup(struct drm_plane *plane)
EXPORT_SYMBOL(drm_plane_cleanup);
/**
+ * drm_plane_force_disable - Forcibly disable a plane
+ * @plane: plane to disable
+ *
+ * Forces the plane to be disabled.
+ *
+ * Used when the plane's current framebuffer is destroyed,
+ * and when restoring fbdev mode.
+ */
+void drm_plane_force_disable(struct drm_plane *plane)
+{
+ int ret;
+
+ if (!plane->fb)
+ return;
+
+ ret = plane->funcs->disable_plane(plane);
+ if (ret)
+ DRM_ERROR("failed to disable plane with busy fb\n");
+ /* disconnect the plane from the fb and crtc: */
+ __drm_framebuffer_unreference(plane->fb);
+ plane->fb = NULL;
+ plane->crtc = NULL;
+}
+EXPORT_SYMBOL(drm_plane_force_disable);
+
+/**
* drm_mode_create - create a new display mode
* @dev: DRM device
*
@@ -1740,7 +1805,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
plane_resp->plane_id = plane->base.id;
plane_resp->possible_crtcs = plane->possible_crtcs;
- plane_resp->gamma_size = plane->gamma_size;
+ plane_resp->gamma_size = 0;
/*
* This ioctl is called twice, once to determine how much space is
@@ -1834,7 +1899,8 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
if (fb->pixel_format == plane->format_types[i])
break;
if (i == plane->format_count) {
- DRM_DEBUG_KMS("Invalid pixel format 0x%08x\n", fb->pixel_format);
+ DRM_DEBUG_KMS("Invalid pixel format %s\n",
+ drm_get_format_name(fb->pixel_format));
ret = -EINVAL;
goto out;
}
@@ -1906,18 +1972,31 @@ out:
int drm_mode_set_config_internal(struct drm_mode_set *set)
{
struct drm_crtc *crtc = set->crtc;
- struct drm_framebuffer *fb, *old_fb;
+ struct drm_framebuffer *fb;
+ struct drm_crtc *tmp;
int ret;
- old_fb = crtc->fb;
+ /*
+ * NOTE: ->set_config can also disable other crtcs (if we steal all
+ * connectors from it), hence we need to refcount the fbs across all
+ * crtcs. Atomic modeset will have saner semantics ...
+ */
+ list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
+ tmp->old_fb = tmp->fb;
+
fb = set->fb;
ret = crtc->funcs->set_config(set);
if (ret == 0) {
- if (old_fb)
- drm_framebuffer_unreference(old_fb);
- if (fb)
- drm_framebuffer_reference(fb);
+ /* crtc->fb must be updated by ->set_config, enforces this. */
+ WARN_ON(fb != crtc->fb);
+ }
+
+ list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
+ if (tmp->fb)
+ drm_framebuffer_reference(tmp->fb);
+ if (tmp->old_fb)
+ drm_framebuffer_unreference(tmp->old_fb);
}
return ret;
@@ -2099,10 +2178,10 @@ out:
return ret;
}
-int drm_mode_cursor_ioctl(struct drm_device *dev,
- void *data, struct drm_file *file_priv)
+static int drm_mode_cursor_common(struct drm_device *dev,
+ struct drm_mode_cursor2 *req,
+ struct drm_file *file_priv)
{
- struct drm_mode_cursor *req = data;
struct drm_mode_object *obj;
struct drm_crtc *crtc;
int ret = 0;
@@ -2122,13 +2201,17 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
mutex_lock(&crtc->mutex);
if (req->flags & DRM_MODE_CURSOR_BO) {
- if (!crtc->funcs->cursor_set) {
+ if (!crtc->funcs->cursor_set && !crtc->funcs->cursor_set2) {
ret = -ENXIO;
goto out;
}
/* Turns off the cursor if handle is 0 */
- ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
- req->width, req->height);
+ if (crtc->funcs->cursor_set2)
+ ret = crtc->funcs->cursor_set2(crtc, file_priv, req->handle,
+ req->width, req->height, req->hot_x, req->hot_y);
+ else
+ ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
+ req->width, req->height);
}
if (req->flags & DRM_MODE_CURSOR_MOVE) {
@@ -2143,6 +2226,25 @@ out:
mutex_unlock(&crtc->mutex);
return ret;
+
+}
+int drm_mode_cursor_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_cursor *req = data;
+ struct drm_mode_cursor2 new_req;
+
+ memcpy(&new_req, req, sizeof(struct drm_mode_cursor));
+ new_req.hot_x = new_req.hot_y = 0;
+
+ return drm_mode_cursor_common(dev, &new_req, file_priv);
+}
+
+int drm_mode_cursor2_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_cursor2 *req = data;
+ return drm_mode_cursor_common(dev, req, file_priv);
}
/* Original addfb only supported RGB formats, so figure out which one */
@@ -2312,7 +2414,8 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
ret = format_check(r);
if (ret) {
- DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);
+ DRM_DEBUG_KMS("bad framebuffer format %s\n",
+ drm_get_format_name(r->pixel_format));
return ret;
}
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index ed1334e27c33..738a4294d820 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -189,13 +189,14 @@ prune:
if (list_empty(&connector->modes))
return 0;
+ list_for_each_entry(mode, &connector->modes, head)
+ mode->vrefresh = drm_mode_vrefresh(mode);
+
drm_mode_sort(&connector->modes);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,
drm_get_connector_name(connector));
list_for_each_entry(mode, &connector->modes, head) {
- mode->vrefresh = drm_mode_vrefresh(mode);
-
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
drm_mode_debug_printmodeline(mode);
}
@@ -564,14 +565,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
DRM_DEBUG_KMS("\n");
- if (!set)
- return -EINVAL;
-
- if (!set->crtc)
- return -EINVAL;
+ BUG_ON(!set);
+ BUG_ON(!set->crtc);
+ BUG_ON(!set->crtc->helper_private);
- if (!set->crtc->helper_private)
- return -EINVAL;
+ /* Enforce sane interface api - has been abused by the fb helper. */
+ BUG_ON(!set->mode && set->fb);
+ BUG_ON(set->fb && set->num_connectors == 0);
crtc_funcs = set->crtc->helper_private;
@@ -645,11 +645,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
mode_changed = true;
} else if (set->fb == NULL) {
mode_changed = true;
- } else if (set->fb->depth != set->crtc->fb->depth) {
- mode_changed = true;
- } else if (set->fb->bits_per_pixel !=
- set->crtc->fb->bits_per_pixel) {
- mode_changed = true;
} else if (set->fb->pixel_format !=
set->crtc->fb->pixel_format) {
mode_changed = true;
@@ -759,12 +754,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
ret = -EINVAL;
goto fail;
}
- DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
- for (i = 0; i < set->num_connectors; i++) {
- DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
- drm_get_connector_name(set->connectors[i]));
- set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
- }
}
drm_helper_disable_unused_functions(dev);
} else if (fb_changed) {
@@ -782,6 +771,22 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
}
}
+ /*
+ * crtc set_config helpers implicit set the crtc and all connected
+ * encoders to DPMS on for a full mode set. But for just an fb update it
+ * doesn't do that. To not confuse userspace, do an explicit DPMS_ON
+ * unconditionally. This will also ensure driver internal dpms state is
+ * consistent again.
+ */
+ if (set->crtc->enabled) {
+ DRM_DEBUG_KMS("Setting connector DPMS state to on\n");
+ for (i = 0; i < set->num_connectors; i++) {
+ DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,
+ drm_get_connector_name(set->connectors[i]));
+ set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
+ }
+ }
+
kfree(save_connectors);
kfree(save_encoders);
kfree(save_crtcs);
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 9cc247f55502..99fcd7c32ea2 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -166,6 +166,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 9e62bbedb5ad..95d6f4b6967c 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -968,6 +968,9 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
u8 csum = 0;
struct edid *edid = (struct edid *)raw_edid;
+ if (WARN_ON(!raw_edid))
+ return false;
+
if (edid_fixup > 8 || edid_fixup < 0)
edid_fixup = 6;
@@ -1010,15 +1013,15 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
break;
}
- return 1;
+ return true;
bad:
- if (raw_edid && print_bad_edid) {
+ if (print_bad_edid) {
printk(KERN_ERR "Raw EDID:\n");
print_hex_dump(KERN_ERR, " \t", DUMP_PREFIX_NONE, 16, 1,
raw_edid, EDID_LENGTH, false);
}
- return 0;
+ return false;
}
EXPORT_SYMBOL(drm_edid_block_valid);
@@ -1706,11 +1709,11 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
return NULL;
if (pt->misc & DRM_EDID_PT_STEREO) {
- printk(KERN_WARNING "stereo mode not supported\n");
+ DRM_DEBUG_KMS("stereo mode not supported\n");
return NULL;
}
if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
- printk(KERN_WARNING "composite sync not supported\n");
+ DRM_DEBUG_KMS("composite sync not supported\n");
}
/* it is incorrect if hsync/vsync width is zero */
@@ -2321,6 +2324,31 @@ u8 *drm_find_cea_extension(struct edid *edid)
}
EXPORT_SYMBOL(drm_find_cea_extension);
+/*
+ * Calculate the alternate clock for the CEA mode
+ * (60Hz vs. 59.94Hz etc.)
+ */
+static unsigned int
+cea_mode_alternate_clock(const struct drm_display_mode *cea_mode)
+{
+ unsigned int clock = cea_mode->clock;
+
+ if (cea_mode->vrefresh % 6 != 0)
+ return clock;
+
+ /*
+ * edid_cea_modes contains the 59.94Hz
+ * variant for 240 and 480 line modes,
+ * and the 60Hz variant otherwise.
+ */
+ if (cea_mode->vdisplay == 240 || cea_mode->vdisplay == 480)
+ clock = clock * 1001 / 1000;
+ else
+ clock = DIV_ROUND_UP(clock * 1000, 1001);
+
+ return clock;
+}
+
/**
* drm_match_cea_mode - look for a CEA mode matching given mode
* @to_match: display mode
@@ -2339,21 +2367,9 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
const struct drm_display_mode *cea_mode = &edid_cea_modes[mode];
unsigned int clock1, clock2;
- clock1 = clock2 = cea_mode->clock;
-
/* Check both 60Hz and 59.94Hz */
- if (cea_mode->vrefresh % 6 == 0) {
- /*
- * edid_cea_modes contains the 59.94Hz
- * variant for 240 and 480 line modes,
- * and the 60Hz variant otherwise.
- */
- if (cea_mode->vdisplay == 240 ||
- cea_mode->vdisplay == 480)
- clock1 = clock1 * 1001 / 1000;
- else
- clock2 = DIV_ROUND_UP(clock2 * 1000, 1001);
- }
+ clock1 = cea_mode->clock;
+ clock2 = cea_mode_alternate_clock(cea_mode);
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) ||
KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) &&
@@ -2364,6 +2380,66 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
}
EXPORT_SYMBOL(drm_match_cea_mode);
+static int
+add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_display_mode *mode, *tmp;
+ LIST_HEAD(list);
+ int modes = 0;
+
+ /* Don't add CEA modes if the CEA extension block is missing */
+ if (!drm_find_cea_extension(edid))
+ return 0;
+
+ /*
+ * Go through all probed modes and create a new mode
+ * with the alternate clock for certain CEA modes.
+ */
+ list_for_each_entry(mode, &connector->probed_modes, head) {
+ const struct drm_display_mode *cea_mode;
+ struct drm_display_mode *newmode;
+ u8 cea_mode_idx = drm_match_cea_mode(mode) - 1;
+ unsigned int clock1, clock2;
+
+ if (cea_mode_idx >= ARRAY_SIZE(edid_cea_modes))
+ continue;
+
+ cea_mode = &edid_cea_modes[cea_mode_idx];
+
+ clock1 = cea_mode->clock;
+ clock2 = cea_mode_alternate_clock(cea_mode);
+
+ if (clock1 == clock2)
+ continue;
+
+ if (mode->clock != clock1 && mode->clock != clock2)
+ continue;
+
+ newmode = drm_mode_duplicate(dev, cea_mode);
+ if (!newmode)
+ continue;
+
+ /*
+ * The current mode could be either variant. Make
+ * sure to pick the "other" clock for the new mode.
+ */
+ if (mode->clock != clock1)
+ newmode->clock = clock1;
+ else
+ newmode->clock = clock2;
+
+ list_add_tail(&newmode->head, &list);
+ }
+
+ list_for_each_entry_safe(mode, tmp, &list, head) {
+ list_del(&mode->head);
+ drm_mode_probed_add(connector, mode);
+ modes++;
+ }
+
+ return modes;
+}
static int
do_cea_modes (struct drm_connector *connector, u8 *db, u8 len)
@@ -2946,6 +3022,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF)
num_modes += add_inferred_modes(connector, edid);
num_modes += add_cea_modes(connector, edid);
+ num_modes += add_alternate_cea_modes(connector, edid);
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks);
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index fa445dd4dc00..271b42bbfb72 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -133,8 +133,8 @@ static u8 generic_edid[GENERIC_EDIDS][128] = {
},
};
-static u8 *edid_load(struct drm_connector *connector, char *name,
- char *connector_name)
+static u8 *edid_load(struct drm_connector *connector, const char *name,
+ const char *connector_name)
{
const struct firmware *fw;
struct platform_device *pdev;
@@ -186,12 +186,11 @@ static u8 *edid_load(struct drm_connector *connector, char *name,
goto relfw_out;
}
- edid = kmalloc(fwsize, GFP_KERNEL);
+ edid = kmemdup(fwdata, fwsize, GFP_KERNEL);
if (edid == NULL) {
err = -ENOMEM;
goto relfw_out;
}
- memcpy(edid, fwdata, fwsize);
if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
connector->bad_edid_counter++;
@@ -243,7 +242,7 @@ out:
int drm_load_edid_firmware(struct drm_connector *connector)
{
- char *connector_name = drm_get_connector_name(connector);
+ const char *connector_name = drm_get_connector_name(connector);
char *edidname = edid_firmware, *last, *colon;
int ret;
struct edid *edid;
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index 0b5af7d0edb1..c385cc5e730e 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -92,7 +92,7 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
if (ret) {
- dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
+ dev_err(dev->dev, "Failed to initialize framebuffer: %d\n", ret);
kfree(fb_cma);
return ERR_PTR(ret);
}
@@ -376,7 +376,7 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
ret = drm_fb_helper_initial_config(helper, preferred_bpp);
if (ret < 0) {
- dev_err(dev->dev, "Failed to set inital hw configuration.\n");
+ dev_err(dev->dev, "Failed to set initial hw configuration.\n");
goto err_drm_fb_helper_fini;
}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b78cbe74dadf..3d13ca6e257f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -168,6 +168,9 @@ static void drm_fb_helper_save_lut_atomic(struct drm_crtc *crtc, struct drm_fb_h
uint16_t *r_base, *g_base, *b_base;
int i;
+ if (helper->funcs->gamma_get == NULL)
+ return;
+
r_base = crtc->gamma_store;
g_base = r_base + crtc->gamma_size;
b_base = g_base + crtc->gamma_size;
@@ -284,13 +287,27 @@ EXPORT_SYMBOL(drm_fb_helper_debug_leave);
*/
bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
{
+ struct drm_device *dev = fb_helper->dev;
+ struct drm_plane *plane;
bool error = false;
- int i, ret;
+ int i;
+
+ drm_warn_on_modeset_not_all_locked(dev);
- drm_warn_on_modeset_not_all_locked(fb_helper->dev);
+ list_for_each_entry(plane, &dev->mode_config.plane_list, head)
+ drm_plane_force_disable(plane);
for (i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
+ struct drm_crtc *crtc = mode_set->crtc;
+ int ret;
+
+ if (crtc->funcs->cursor_set) {
+ ret = crtc->funcs->cursor_set(crtc, NULL, 0, 0, 0);
+ if (ret)
+ error = true;
+ }
+
ret = drm_mode_set_config_internal(mode_set);
if (ret)
error = true;
@@ -583,6 +600,14 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
return 0;
}
+ /*
+ * The driver really shouldn't advertise pseudo/directcolor
+ * visuals if it can't deal with the palette.
+ */
+ if (WARN_ON(!fb_helper->funcs->gamma_set ||
+ !fb_helper->funcs->gamma_get))
+ return -EINVAL;
+
pindex = regno;
if (fb->bits_per_pixel == 16) {
@@ -626,12 +651,19 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
{
struct drm_fb_helper *fb_helper = info->par;
+ struct drm_device *dev = fb_helper->dev;
struct drm_crtc_helper_funcs *crtc_funcs;
u16 *red, *green, *blue, *transp;
struct drm_crtc *crtc;
int i, j, rc = 0;
int start;
+ drm_modeset_lock_all(dev);
+ if (!drm_fb_helper_is_bound(fb_helper)) {
+ drm_modeset_unlock_all(dev);
+ return -EBUSY;
+ }
+
for (i = 0; i < fb_helper->crtc_count; i++) {
crtc = fb_helper->crtc_info[i].mode_set.crtc;
crtc_funcs = crtc->helper_private;
@@ -654,10 +686,13 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
rc = setcolreg(crtc, hred, hgreen, hblue, start++, info);
if (rc)
- return rc;
+ goto out;
}
- crtc_funcs->load_lut(crtc);
+ if (crtc_funcs->load_lut)
+ crtc_funcs->load_lut(crtc);
}
+ out:
+ drm_modeset_unlock_all(dev);
return rc;
}
EXPORT_SYMBOL(drm_fb_helper_setcmap);
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 429e07d0b0f1..3a24385e0368 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -271,6 +271,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
priv->uid = current_euid();
priv->pid = get_pid(task_pid(current));
priv->minor = idr_find(&drm_minors_idr, minor_id);
+ if (!priv->minor) {
+ ret = -ENODEV;
+ goto out_put_pid;
+ }
+
priv->ioctl_count = 0;
/* for compatibility root is always authenticated */
priv->authenticated = capable(CAP_SYS_ADMIN);
@@ -292,7 +297,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
if (dev->driver->open) {
ret = dev->driver->open(dev, priv);
if (ret < 0)
- goto out_free;
+ goto out_prime_destroy;
}
@@ -304,7 +309,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
if (!priv->minor->master) {
mutex_unlock(&dev->struct_mutex);
ret = -ENOMEM;
- goto out_free;
+ goto out_close;
}
priv->is_master = 1;
@@ -322,7 +327,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
drm_master_put(&priv->minor->master);
drm_master_put(&priv->master);
mutex_unlock(&dev->struct_mutex);
- goto out_free;
+ goto out_close;
}
}
mutex_lock(&dev->struct_mutex);
@@ -333,7 +338,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
drm_master_put(&priv->minor->master);
drm_master_put(&priv->master);
mutex_unlock(&dev->struct_mutex);
- goto out_free;
+ goto out_close;
}
}
mutex_unlock(&dev->struct_mutex);
@@ -367,7 +372,17 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
#endif
return 0;
- out_free:
+
+out_close:
+ if (dev->driver->postclose)
+ dev->driver->postclose(dev, priv);
+out_prime_destroy:
+ if (drm_core_check_feature(dev, DRIVER_PRIME))
+ drm_prime_destroy_file_private(&priv->prime);
+ if (dev->driver->driver_features & DRIVER_GEM)
+ drm_gem_release(dev, priv);
+out_put_pid:
+ put_pid(priv->pid);
kfree(priv);
filp->private_data = NULL;
return ret;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index cf919e36e8ae..603f256152ef 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -108,12 +108,8 @@ drm_gem_init(struct drm_device *dev)
return -ENOMEM;
}
- if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
- DRM_FILE_PAGE_OFFSET_SIZE)) {
- drm_ht_remove(&mm->offset_hash);
- kfree(mm);
- return -ENOMEM;
- }
+ drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
+ DRM_FILE_PAGE_OFFSET_SIZE);
return 0;
}
@@ -453,25 +449,21 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
spin_lock(&dev->object_name_lock);
if (!obj->name) {
ret = idr_alloc(&dev->object_name_idr, obj, 1, 0, GFP_NOWAIT);
- obj->name = ret;
- args->name = (uint64_t) obj->name;
- spin_unlock(&dev->object_name_lock);
- idr_preload_end();
-
if (ret < 0)
goto err;
- ret = 0;
+
+ obj->name = ret;
/* Allocate a reference for the name table. */
drm_gem_object_reference(obj);
- } else {
- args->name = (uint64_t) obj->name;
- spin_unlock(&dev->object_name_lock);
- idr_preload_end();
- ret = 0;
}
+ args->name = (uint64_t) obj->name;
+ ret = 0;
+
err:
+ spin_unlock(&dev->object_name_lock);
+ idr_preload_end();
drm_gem_object_unreference_unlocked(obj);
return ret;
}
@@ -644,6 +636,59 @@ void drm_gem_vm_close(struct vm_area_struct *vma)
}
EXPORT_SYMBOL(drm_gem_vm_close);
+/**
+ * drm_gem_mmap_obj - memory map a GEM object
+ * @obj: the GEM object to map
+ * @obj_size: the object size to be mapped, in bytes
+ * @vma: VMA for the area to be mapped
+ *
+ * Set up the VMA to prepare mapping of the GEM object using the gem_vm_ops
+ * provided by the driver. Depending on their requirements, drivers can either
+ * provide a fault handler in their gem_vm_ops (in which case any accesses to
+ * the object will be trapped, to perform migration, GTT binding, surface
+ * register allocation, or performance monitoring), or mmap the buffer memory
+ * synchronously after calling drm_gem_mmap_obj.
+ *
+ * This function is mainly intended to implement the DMABUF mmap operation, when
+ * the GEM object is not looked up based on its fake offset. To implement the
+ * DRM mmap operation, drivers should use the drm_gem_mmap() function.
+ *
+ * NOTE: This function has to be protected with dev->struct_mutex
+ *
+ * Return 0 or success or -EINVAL if the object size is smaller than the VMA
+ * size, or if no gem_vm_ops are provided.
+ */
+int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
+ struct vm_area_struct *vma)
+{
+ struct drm_device *dev = obj->dev;
+
+ lockdep_assert_held(&dev->struct_mutex);
+
+ /* Check for valid size. */
+ if (obj_size < vma->vm_end - vma->vm_start)
+ return -EINVAL;
+
+ if (!dev->driver->gem_vm_ops)
+ return -EINVAL;
+
+ vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_ops = dev->driver->gem_vm_ops;
+ vma->vm_private_data = obj;
+ vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+ /* Take a ref for this mapping of the object, so that the fault
+ * handler can dereference the mmap offset's pointer to the object.
+ * This reference is cleaned up by the corresponding vm_close
+ * (which should happen whether the vma was created by this call, or
+ * by a vm_open due to mremap or partial unmap or whatever).
+ */
+ drm_gem_object_reference(obj);
+
+ drm_vm_open_locked(dev, vma);
+ return 0;
+}
+EXPORT_SYMBOL(drm_gem_mmap_obj);
/**
* drm_gem_mmap - memory map routine for GEM objects
@@ -653,11 +698,9 @@ EXPORT_SYMBOL(drm_gem_vm_close);
* If a driver supports GEM object mapping, mmap calls on the DRM file
* descriptor will end up here.
*
- * If we find the object based on the offset passed in (vma->vm_pgoff will
+ * Look up the GEM object based on the offset passed in (vma->vm_pgoff will
* contain the fake offset we created when the GTT map ioctl was called on
- * the object), we set up the driver fault handler so that any accesses
- * to the object can be trapped, to perform migration, GTT binding, surface
- * register allocation, or performance monitoring.
+ * the object) and map it with a call to drm_gem_mmap_obj().
*/
int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
{
@@ -665,7 +708,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_device *dev = priv->minor->dev;
struct drm_gem_mm *mm = dev->mm_private;
struct drm_local_map *map = NULL;
- struct drm_gem_object *obj;
struct drm_hash_item *hash;
int ret = 0;
@@ -686,32 +728,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
goto out_unlock;
}
- /* Check for valid size. */
- if (map->size < vma->vm_end - vma->vm_start) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- obj = map->handle;
- if (!obj->dev->driver->gem_vm_ops) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_ops = obj->dev->driver->gem_vm_ops;
- vma->vm_private_data = map->handle;
- vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
-
- /* Take a ref for this mapping of the object, so that the fault
- * handler can dereference the mmap offset's pointer to the object.
- * This reference is cleaned up by the corresponding vm_close
- * (which should happen whether the vma was created by this call, or
- * by a vm_open due to mremap or partial unmap or whatever).
- */
- drm_gem_object_reference(obj);
-
- drm_vm_open_locked(dev, vma);
+ ret = drm_gem_mmap_obj(map->handle, map->size, vma);
out_unlock:
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c
index 0a7e011509bd..ece72a8ac245 100644
--- a/drivers/gpu/drm/drm_gem_cma_helper.c
+++ b/drivers/gpu/drm/drm_gem_cma_helper.c
@@ -21,6 +21,7 @@
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/export.h>
+#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
#include <drm/drmP.h>
@@ -32,11 +33,44 @@ static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
}
-static void drm_gem_cma_buf_destroy(struct drm_device *drm,
- struct drm_gem_cma_object *cma_obj)
+/*
+ * __drm_gem_cma_create - Create a GEM CMA object without allocating memory
+ * @drm: The drm device
+ * @size: The GEM object size
+ *
+ * This function creates and initializes a GEM CMA object of the given size, but
+ * doesn't allocate any memory to back the object.
+ *
+ * Return a struct drm_gem_cma_object* on success or ERR_PTR values on failure.
+ */
+static struct drm_gem_cma_object *
+__drm_gem_cma_create(struct drm_device *drm, unsigned int size)
{
- dma_free_writecombine(drm->dev, cma_obj->base.size, cma_obj->vaddr,
- cma_obj->paddr);
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_gem_object *gem_obj;
+ int ret;
+
+ cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
+ if (!cma_obj)
+ return ERR_PTR(-ENOMEM);
+
+ gem_obj = &cma_obj->base;
+
+ ret = drm_gem_object_init(drm, gem_obj, size);
+ if (ret)
+ goto error;
+
+ ret = drm_gem_create_mmap_offset(gem_obj);
+ if (ret) {
+ drm_gem_object_release(gem_obj);
+ goto error;
+ }
+
+ return cma_obj;
+
+error:
+ kfree(cma_obj);
+ return ERR_PTR(ret);
}
/*
@@ -49,44 +83,42 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
unsigned int size)
{
struct drm_gem_cma_object *cma_obj;
- struct drm_gem_object *gem_obj;
+ struct sg_table *sgt = NULL;
int ret;
size = round_up(size, PAGE_SIZE);
- cma_obj = kzalloc(sizeof(*cma_obj), GFP_KERNEL);
- if (!cma_obj)
- return ERR_PTR(-ENOMEM);
+ cma_obj = __drm_gem_cma_create(drm, size);
+ if (IS_ERR(cma_obj))
+ return cma_obj;
cma_obj->vaddr = dma_alloc_writecombine(drm->dev, size,
&cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN);
if (!cma_obj->vaddr) {
- dev_err(drm->dev, "failed to allocate buffer with size %d\n", size);
+ dev_err(drm->dev, "failed to allocate buffer with size %d\n",
+ size);
ret = -ENOMEM;
- goto err_dma_alloc;
+ goto error;
}
- gem_obj = &cma_obj->base;
+ sgt = kzalloc(sizeof(*cma_obj->sgt), GFP_KERNEL);
+ if (sgt == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
- ret = drm_gem_object_init(drm, gem_obj, size);
- if (ret)
- goto err_obj_init;
+ ret = dma_get_sgtable(drm->dev, sgt, cma_obj->vaddr,
+ cma_obj->paddr, size);
+ if (ret < 0)
+ goto error;
- ret = drm_gem_create_mmap_offset(gem_obj);
- if (ret)
- goto err_create_mmap_offset;
+ cma_obj->sgt = sgt;
return cma_obj;
-err_create_mmap_offset:
- drm_gem_object_release(gem_obj);
-
-err_obj_init:
- drm_gem_cma_buf_destroy(drm, cma_obj);
-
-err_dma_alloc:
- kfree(cma_obj);
-
+error:
+ kfree(sgt);
+ drm_gem_cma_free_object(&cma_obj->base);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_create);
@@ -143,11 +175,20 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
if (gem_obj->map_list.map)
drm_gem_free_mmap_offset(gem_obj);
- drm_gem_object_release(gem_obj);
-
cma_obj = to_drm_gem_cma_obj(gem_obj);
- drm_gem_cma_buf_destroy(gem_obj->dev, cma_obj);
+ if (cma_obj->vaddr) {
+ dma_free_writecombine(gem_obj->dev->dev, cma_obj->base.size,
+ cma_obj->vaddr, cma_obj->paddr);
+ if (cma_obj->sgt) {
+ sg_free_table(cma_obj->sgt);
+ kfree(cma_obj->sgt);
+ }
+ } else if (gem_obj->import_attach) {
+ drm_prime_gem_destroy(gem_obj, cma_obj->sgt);
+ }
+
+ drm_gem_object_release(gem_obj);
kfree(cma_obj);
}
@@ -174,10 +215,7 @@ int drm_gem_cma_dumb_create(struct drm_file *file_priv,
cma_obj = drm_gem_cma_create_with_handle(file_priv, dev,
args->size, &args->handle);
- if (IS_ERR(cma_obj))
- return PTR_ERR(cma_obj);
-
- return 0;
+ return PTR_RET(cma_obj);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_dumb_create);
@@ -215,13 +253,26 @@ const struct vm_operations_struct drm_gem_cma_vm_ops = {
};
EXPORT_SYMBOL_GPL(drm_gem_cma_vm_ops);
+static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj,
+ struct vm_area_struct *vma)
+{
+ int ret;
+
+ ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+ if (ret)
+ drm_gem_vm_close(vma);
+
+ return ret;
+}
+
/*
* drm_gem_cma_mmap - (struct file_operation)->mmap callback function
*/
int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
{
- struct drm_gem_object *gem_obj;
struct drm_gem_cma_object *cma_obj;
+ struct drm_gem_object *gem_obj;
int ret;
ret = drm_gem_mmap(filp, vma);
@@ -231,12 +282,7 @@ int drm_gem_cma_mmap(struct file *filp, struct vm_area_struct *vma)
gem_obj = vma->vm_private_data;
cma_obj = to_drm_gem_cma_obj(gem_obj);
- ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
- if (ret)
- drm_gem_vm_close(vma);
-
- return ret;
+ return drm_gem_cma_mmap_obj(cma_obj, vma);
}
EXPORT_SYMBOL_GPL(drm_gem_cma_mmap);
@@ -270,3 +316,82 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m
}
EXPORT_SYMBOL_GPL(drm_gem_cma_describe);
#endif
+
+/* low-level interface prime helpers */
+struct sg_table *drm_gem_cma_prime_get_sg_table(struct drm_gem_object *obj)
+{
+ struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
+ struct sg_table *sgt;
+ int ret;
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt)
+ return NULL;
+
+ ret = dma_get_sgtable(obj->dev->dev, sgt, cma_obj->vaddr,
+ cma_obj->paddr, obj->size);
+ if (ret < 0)
+ goto out;
+
+ return sgt;
+
+out:
+ kfree(sgt);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_get_sg_table);
+
+struct drm_gem_object *
+drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size,
+ struct sg_table *sgt)
+{
+ struct drm_gem_cma_object *cma_obj;
+
+ if (sgt->nents != 1)
+ return ERR_PTR(-EINVAL);
+
+ /* Create a CMA GEM buffer. */
+ cma_obj = __drm_gem_cma_create(dev, size);
+ if (IS_ERR(cma_obj))
+ return ERR_PTR(PTR_ERR(cma_obj));
+
+ cma_obj->paddr = sg_dma_address(sgt->sgl);
+ cma_obj->sgt = sgt;
+
+ DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, size);
+
+ return &cma_obj->base;
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_import_sg_table);
+
+int drm_gem_cma_prime_mmap(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
+{
+ struct drm_gem_cma_object *cma_obj;
+ struct drm_device *dev = obj->dev;
+ int ret;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_gem_mmap_obj(obj, obj->size, vma);
+ mutex_unlock(&dev->struct_mutex);
+ if (ret < 0)
+ return ret;
+
+ cma_obj = to_drm_gem_cma_obj(obj);
+ return drm_gem_cma_mmap_obj(cma_obj, vma);
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_mmap);
+
+void *drm_gem_cma_prime_vmap(struct drm_gem_object *obj)
+{
+ struct drm_gem_cma_object *cma_obj = to_drm_gem_cma_obj(obj);
+
+ return cma_obj->vaddr;
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vmap);
+
+void drm_gem_cma_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+ /* Nothing to do */
+}
+EXPORT_SYMBOL_GPL(drm_gem_cma_prime_vunmap);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index e77bd8b57df2..ffd7a7ba70d4 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -38,6 +38,9 @@
#include <linux/pci.h>
#include <linux/export.h>
+#ifdef CONFIG_X86
+#include <asm/mtrr.h>
+#endif
/**
* Get the bus id.
@@ -181,7 +184,17 @@ int drm_getmap(struct drm_device *dev, void *data,
map->type = r_list->map->type;
map->flags = r_list->map->flags;
map->handle = (void *)(unsigned long) r_list->user_token;
- map->mtrr = r_list->map->mtrr;
+
+#ifdef CONFIG_X86
+ /*
+ * There appears to be exactly one user of the mtrr index: dritest.
+ * It's easy enough to keep it working on non-PAT systems.
+ */
+ map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr);
+#else
+ map->mtrr = -1;
+#endif
+
mutex_unlock(&dev->struct_mutex);
return 0;
diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c
index 07cf99cc8862..543b9b3171d3 100644
--- a/drivers/gpu/drm/drm_mm.c
+++ b/drivers/gpu/drm/drm_mm.c
@@ -669,7 +669,7 @@ int drm_mm_clean(struct drm_mm * mm)
}
EXPORT_SYMBOL(drm_mm_clean);
-int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
+void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{
INIT_LIST_HEAD(&mm->hole_stack);
INIT_LIST_HEAD(&mm->unused_nodes);
@@ -690,8 +690,6 @@ int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
list_add_tail(&mm->head_node.hole_stack, &mm->hole_stack);
mm->color_adjust = NULL;
-
- return 0;
}
EXPORT_SYMBOL(drm_mm_init);
@@ -699,8 +697,8 @@ void drm_mm_takedown(struct drm_mm * mm)
{
struct drm_mm_node *entry, *next;
- if (!list_empty(&mm->head_node.node_list)) {
- DRM_ERROR("Memory manager not clean. Delaying takedown\n");
+ if (WARN(!list_empty(&mm->head_node.node_list),
+ "Memory manager not clean. Delaying takedown\n")) {
return;
}
@@ -716,36 +714,37 @@ void drm_mm_takedown(struct drm_mm * mm)
}
EXPORT_SYMBOL(drm_mm_takedown);
-void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
+static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
+ const char *prefix)
{
- struct drm_mm_node *entry;
- unsigned long total_used = 0, total_free = 0, total = 0;
unsigned long hole_start, hole_end, hole_size;
- hole_start = drm_mm_hole_node_start(&mm->head_node);
- hole_end = drm_mm_hole_node_end(&mm->head_node);
- hole_size = hole_end - hole_start;
- if (hole_size)
+ if (entry->hole_follows) {
+ hole_start = drm_mm_hole_node_start(entry);
+ hole_end = drm_mm_hole_node_end(entry);
+ hole_size = hole_end - hole_start;
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
prefix, hole_start, hole_end,
hole_size);
- total_free += hole_size;
+ return hole_size;
+ }
+
+ return 0;
+}
+
+void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
+{
+ struct drm_mm_node *entry;
+ unsigned long total_used = 0, total_free = 0, total = 0;
+
+ total_free += drm_mm_debug_hole(&mm->head_node, prefix);
drm_mm_for_each_node(entry, mm) {
printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: used\n",
prefix, entry->start, entry->start + entry->size,
entry->size);
total_used += entry->size;
-
- if (entry->hole_follows) {
- hole_start = drm_mm_hole_node_start(entry);
- hole_end = drm_mm_hole_node_end(entry);
- hole_size = hole_end - hole_start;
- printk(KERN_DEBUG "%s 0x%08lx-0x%08lx: %8lu: free\n",
- prefix, hole_start, hole_end,
- hole_size);
- total_free += hole_size;
- }
+ total_free += drm_mm_debug_hole(entry, prefix);
}
total = total_free + total_used;
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index a371ff865a88..a6729bfe6860 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -535,6 +535,8 @@ int drm_display_mode_from_videomode(const struct videomode *vm,
dmode->flags |= DRM_MODE_FLAG_INTERLACE;
if (vm->flags & DISPLAY_FLAGS_DOUBLESCAN)
dmode->flags |= DRM_MODE_FLAG_DBLSCAN;
+ if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
+ dmode->flags |= DRM_MODE_FLAG_DBLCLK;
drm_mode_set_name(dmode);
return 0;
@@ -787,16 +789,17 @@ EXPORT_SYMBOL(drm_mode_set_crtcinfo);
* LOCKING:
* None.
*
- * Copy an existing mode into another mode, preserving the object id
- * of the destination mode.
+ * Copy an existing mode into another mode, preserving the object id and
+ * list head of the destination mode.
*/
void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src)
{
int id = dst->base.id;
+ struct list_head head = dst->head;
*dst = *src;
dst->base.id = id;
- INIT_LIST_HEAD(&dst->head);
+ dst->head = head;
}
EXPORT_SYMBOL(drm_mode_copy);
@@ -1017,6 +1020,11 @@ static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head
diff = b->hdisplay * b->vdisplay - a->hdisplay * a->vdisplay;
if (diff)
return diff;
+
+ diff = b->vrefresh - a->vrefresh;
+ if (diff)
+ return diff;
+
diff = b->clock - a->clock;
return diff;
}
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c
index 14194b6ef644..80c0b2b29801 100644
--- a/drivers/gpu/drm/drm_pci.c
+++ b/drivers/gpu/drm/drm_pci.c
@@ -278,10 +278,10 @@ static int drm_pci_agp_init(struct drm_device *dev)
}
if (drm_core_has_MTRR(dev)) {
if (dev->agp)
- dev->agp->agp_mtrr =
- mtrr_add(dev->agp->agp_info.aper_base,
- dev->agp->agp_info.aper_size *
- 1024 * 1024, MTRR_TYPE_WRCOMB, 1);
+ dev->agp->agp_mtrr = arch_phys_wc_add(
+ dev->agp->agp_info.aper_base,
+ dev->agp->agp_info.aper_size *
+ 1024 * 1024);
}
}
return 0;
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 5b7b9110254b..85e450e3241c 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -62,20 +62,125 @@ struct drm_prime_member {
struct dma_buf *dma_buf;
uint32_t handle;
};
-static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle);
+
+struct drm_prime_attachment {
+ struct sg_table *sgt;
+ enum dma_data_direction dir;
+};
+
+static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
+{
+ struct drm_prime_member *member;
+
+ member = kmalloc(sizeof(*member), GFP_KERNEL);
+ if (!member)
+ return -ENOMEM;
+
+ get_dma_buf(dma_buf);
+ member->dma_buf = dma_buf;
+ member->handle = handle;
+ list_add(&member->entry, &prime_fpriv->head);
+ return 0;
+}
+
+static int drm_gem_map_attach(struct dma_buf *dma_buf,
+ struct device *target_dev,
+ struct dma_buf_attachment *attach)
+{
+ struct drm_prime_attachment *prime_attach;
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+
+ prime_attach = kzalloc(sizeof(*prime_attach), GFP_KERNEL);
+ if (!prime_attach)
+ return -ENOMEM;
+
+ prime_attach->dir = DMA_NONE;
+ attach->priv = prime_attach;
+
+ if (!dev->driver->gem_prime_pin)
+ return 0;
+
+ return dev->driver->gem_prime_pin(obj);
+}
+
+static void drm_gem_map_detach(struct dma_buf *dma_buf,
+ struct dma_buf_attachment *attach)
+{
+ struct drm_prime_attachment *prime_attach = attach->priv;
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+ struct sg_table *sgt;
+
+ if (dev->driver->gem_prime_unpin)
+ dev->driver->gem_prime_unpin(obj);
+
+ if (!prime_attach)
+ return;
+
+ sgt = prime_attach->sgt;
+ if (sgt) {
+ if (prime_attach->dir != DMA_NONE)
+ dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
+ prime_attach->dir);
+ sg_free_table(sgt);
+ }
+
+ kfree(sgt);
+ kfree(prime_attach);
+ attach->priv = NULL;
+}
+
+static void drm_prime_remove_buf_handle_locked(
+ struct drm_prime_file_private *prime_fpriv,
+ struct dma_buf *dma_buf)
+{
+ struct drm_prime_member *member, *safe;
+
+ list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
+ if (member->dma_buf == dma_buf) {
+ dma_buf_put(dma_buf);
+ list_del(&member->entry);
+ kfree(member);
+ }
+ }
+}
static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction dir)
{
+ struct drm_prime_attachment *prime_attach = attach->priv;
struct drm_gem_object *obj = attach->dmabuf->priv;
struct sg_table *sgt;
+ if (WARN_ON(dir == DMA_NONE || !prime_attach))
+ return ERR_PTR(-EINVAL);
+
+ /* return the cached mapping when possible */
+ if (prime_attach->dir == dir)
+ return prime_attach->sgt;
+
+ /*
+ * two mappings with different directions for the same attachment are
+ * not allowed
+ */
+ if (WARN_ON(prime_attach->dir != DMA_NONE))
+ return ERR_PTR(-EBUSY);
+
mutex_lock(&obj->dev->struct_mutex);
sgt = obj->dev->driver->gem_prime_get_sg_table(obj);
- if (!IS_ERR_OR_NULL(sgt))
- dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+ if (!IS_ERR(sgt)) {
+ if (!dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir)) {
+ sg_free_table(sgt);
+ kfree(sgt);
+ sgt = ERR_PTR(-ENOMEM);
+ } else {
+ prime_attach->sgt = sgt;
+ prime_attach->dir = dir;
+ }
+ }
mutex_unlock(&obj->dev->struct_mutex);
return sgt;
@@ -84,9 +189,7 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
struct sg_table *sgt, enum dma_data_direction dir)
{
- dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
- sg_free_table(sgt);
- kfree(sgt);
+ /* nothing to be done here */
}
static void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
@@ -142,10 +245,18 @@ static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf,
struct vm_area_struct *vma)
{
- return -EINVAL;
+ struct drm_gem_object *obj = dma_buf->priv;
+ struct drm_device *dev = obj->dev;
+
+ if (!dev->driver->gem_prime_mmap)
+ return -ENOSYS;
+
+ return dev->driver->gem_prime_mmap(obj, vma);
}
static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
+ .attach = drm_gem_map_attach,
+ .detach = drm_gem_map_detach,
.map_dma_buf = drm_gem_map_dma_buf,
.unmap_dma_buf = drm_gem_unmap_dma_buf,
.release = drm_gem_dmabuf_release,
@@ -185,11 +296,6 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops = {
struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
struct drm_gem_object *obj, int flags)
{
- if (dev->driver->gem_prime_pin) {
- int ret = dev->driver->gem_prime_pin(obj);
- if (ret)
- return ERR_PTR(ret);
- }
return dma_buf_export(obj, &drm_gem_prime_dmabuf_ops, obj->size, flags);
}
EXPORT_SYMBOL(drm_gem_prime_export);
@@ -235,15 +341,34 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
ret = drm_prime_add_buf_handle(&file_priv->prime,
obj->export_dma_buf, handle);
if (ret)
- goto out;
+ goto fail_put_dmabuf;
+
+ ret = dma_buf_fd(buf, flags);
+ if (ret < 0)
+ goto fail_rm_handle;
- *prime_fd = dma_buf_fd(buf, flags);
+ *prime_fd = ret;
mutex_unlock(&file_priv->prime.lock);
return 0;
out_have_obj:
get_dma_buf(dmabuf);
- *prime_fd = dma_buf_fd(dmabuf, flags);
+ ret = dma_buf_fd(dmabuf, flags);
+ if (ret < 0) {
+ dma_buf_put(dmabuf);
+ } else {
+ *prime_fd = ret;
+ ret = 0;
+ }
+
+ goto out;
+
+fail_rm_handle:
+ drm_prime_remove_buf_handle_locked(&file_priv->prime, buf);
+fail_put_dmabuf:
+ /* clear NOT to be checked when releasing dma_buf */
+ obj->export_dma_buf = NULL;
+ dma_buf_put(buf);
out:
drm_gem_object_unreference_unlocked(obj);
mutex_unlock(&file_priv->prime.lock);
@@ -276,7 +401,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
attach = dma_buf_attach(dma_buf, dev->dev);
if (IS_ERR(attach))
- return ERR_PTR(PTR_ERR(attach));
+ return ERR_CAST(attach);
get_dma_buf(dma_buf);
@@ -412,8 +537,10 @@ struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
int ret;
sg = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!sg)
+ if (!sg) {
+ ret = -ENOMEM;
goto out;
+ }
ret = sg_alloc_table_from_pages(sg, pages, nr_pages, 0,
nr_pages << PAGE_SHIFT, GFP_KERNEL);
@@ -423,7 +550,7 @@ struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
return sg;
out:
kfree(sg);
- return NULL;
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL(drm_prime_pages_to_sg);
@@ -492,21 +619,6 @@ void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
}
EXPORT_SYMBOL(drm_prime_destroy_file_private);
-static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
-{
- struct drm_prime_member *member;
-
- member = kmalloc(sizeof(*member), GFP_KERNEL);
- if (!member)
- return -ENOMEM;
-
- get_dma_buf(dma_buf);
- member->dma_buf = dma_buf;
- member->handle = handle;
- list_add(&member->entry, &prime_fpriv->head);
- return 0;
-}
-
int drm_prime_lookup_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t *handle)
{
struct drm_prime_member *member;
@@ -523,16 +635,8 @@ EXPORT_SYMBOL(drm_prime_lookup_buf_handle);
void drm_prime_remove_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf)
{
- struct drm_prime_member *member, *safe;
-
mutex_lock(&prime_fpriv->lock);
- list_for_each_entry_safe(member, safe, &prime_fpriv->head, entry) {
- if (member->dma_buf == dma_buf) {
- dma_buf_put(dma_buf);
- list_del(&member->entry);
- kfree(member);
- }
- }
+ drm_prime_remove_buf_handle_locked(prime_fpriv, dma_buf);
mutex_unlock(&prime_fpriv->lock);
}
EXPORT_SYMBOL(drm_prime_remove_buf_handle);
diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c
new file mode 100644
index 000000000000..7047ca025787
--- /dev/null
+++ b/drivers/gpu/drm/drm_rect.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011-2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <drm/drmP.h>
+#include <drm/drm_rect.h>
+
+/**
+ * drm_rect_intersect - intersect two rectangles
+ * @r1: first rectangle
+ * @r2: second rectangle
+ *
+ * Calculate the intersection of rectangles @r1 and @r2.
+ * @r1 will be overwritten with the intersection.
+ *
+ * RETURNS:
+ * %true if rectangle @r1 is still visible after the operation,
+ * %false otherwise.
+ */
+bool drm_rect_intersect(struct drm_rect *r1, const struct drm_rect *r2)
+{
+ r1->x1 = max(r1->x1, r2->x1);
+ r1->y1 = max(r1->y1, r2->y1);
+ r1->x2 = min(r1->x2, r2->x2);
+ r1->y2 = min(r1->y2, r2->y2);
+
+ return drm_rect_visible(r1);
+}
+EXPORT_SYMBOL(drm_rect_intersect);
+
+/**
+ * drm_rect_clip_scaled - perform a scaled clip operation
+ * @src: source window rectangle
+ * @dst: destination window rectangle
+ * @clip: clip rectangle
+ * @hscale: horizontal scaling factor
+ * @vscale: vertical scaling factor
+ *
+ * Clip rectangle @dst by rectangle @clip. Clip rectangle @src by the
+ * same amounts multiplied by @hscale and @vscale.
+ *
+ * RETURNS:
+ * %true if rectangle @dst is still visible after being clipped,
+ * %false otherwise
+ */
+bool drm_rect_clip_scaled(struct drm_rect *src, struct drm_rect *dst,
+ const struct drm_rect *clip,
+ int hscale, int vscale)
+{
+ int diff;
+
+ diff = clip->x1 - dst->x1;
+ if (diff > 0) {
+ int64_t tmp = src->x1 + (int64_t) diff * hscale;
+ src->x1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+ }
+ diff = clip->y1 - dst->y1;
+ if (diff > 0) {
+ int64_t tmp = src->y1 + (int64_t) diff * vscale;
+ src->y1 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+ }
+ diff = dst->x2 - clip->x2;
+ if (diff > 0) {
+ int64_t tmp = src->x2 - (int64_t) diff * hscale;
+ src->x2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+ }
+ diff = dst->y2 - clip->y2;
+ if (diff > 0) {
+ int64_t tmp = src->y2 - (int64_t) diff * vscale;
+ src->y2 = clamp_t(int64_t, tmp, INT_MIN, INT_MAX);
+ }
+
+ return drm_rect_intersect(dst, clip);
+}
+EXPORT_SYMBOL(drm_rect_clip_scaled);
+
+static int drm_calc_scale(int src, int dst)
+{
+ int scale = 0;
+
+ if (src < 0 || dst < 0)
+ return -EINVAL;
+
+ if (dst == 0)
+ return 0;
+
+ scale = src / dst;
+
+ return scale;
+}
+
+/**
+ * drm_rect_calc_hscale - calculate the horizontal scaling factor
+ * @src: source window rectangle
+ * @dst: destination window rectangle
+ * @min_hscale: minimum allowed horizontal scaling factor
+ * @max_hscale: maximum allowed horizontal scaling factor
+ *
+ * Calculate the horizontal scaling factor as
+ * (@src width) / (@dst width).
+ *
+ * RETURNS:
+ * The horizontal scaling factor, or errno of out of limits.
+ */
+int drm_rect_calc_hscale(const struct drm_rect *src,
+ const struct drm_rect *dst,
+ int min_hscale, int max_hscale)
+{
+ int src_w = drm_rect_width(src);
+ int dst_w = drm_rect_width(dst);
+ int hscale = drm_calc_scale(src_w, dst_w);
+
+ if (hscale < 0 || dst_w == 0)
+ return hscale;
+
+ if (hscale < min_hscale || hscale > max_hscale)
+ return -ERANGE;
+
+ return hscale;
+}
+EXPORT_SYMBOL(drm_rect_calc_hscale);
+
+/**
+ * drm_rect_calc_vscale - calculate the vertical scaling factor
+ * @src: source window rectangle
+ * @dst: destination window rectangle
+ * @min_vscale: minimum allowed vertical scaling factor
+ * @max_vscale: maximum allowed vertical scaling factor
+ *
+ * Calculate the vertical scaling factor as
+ * (@src height) / (@dst height).
+ *
+ * RETURNS:
+ * The vertical scaling factor, or errno of out of limits.
+ */
+int drm_rect_calc_vscale(const struct drm_rect *src,
+ const struct drm_rect *dst,
+ int min_vscale, int max_vscale)
+{
+ int src_h = drm_rect_height(src);
+ int dst_h = drm_rect_height(dst);
+ int vscale = drm_calc_scale(src_h, dst_h);
+
+ if (vscale < 0 || dst_h == 0)
+ return vscale;
+
+ if (vscale < min_vscale || vscale > max_vscale)
+ return -ERANGE;
+
+ return vscale;
+}
+EXPORT_SYMBOL(drm_rect_calc_vscale);
+
+/**
+ * drm_calc_hscale_relaxed - calculate the horizontal scaling factor
+ * @src: source window rectangle
+ * @dst: destination window rectangle
+ * @min_hscale: minimum allowed horizontal scaling factor
+ * @max_hscale: maximum allowed horizontal scaling factor
+ *
+ * Calculate the horizontal scaling factor as
+ * (@src width) / (@dst width).
+ *
+ * If the calculated scaling factor is below @min_vscale,
+ * decrease the height of rectangle @dst to compensate.
+ *
+ * If the calculated scaling factor is above @max_vscale,
+ * decrease the height of rectangle @src to compensate.
+ *
+ * RETURNS:
+ * The horizontal scaling factor.
+ */
+int drm_rect_calc_hscale_relaxed(struct drm_rect *src,
+ struct drm_rect *dst,
+ int min_hscale, int max_hscale)
+{
+ int src_w = drm_rect_width(src);
+ int dst_w = drm_rect_width(dst);
+ int hscale = drm_calc_scale(src_w, dst_w);
+
+ if (hscale < 0 || dst_w == 0)
+ return hscale;
+
+ if (hscale < min_hscale) {
+ int max_dst_w = src_w / min_hscale;
+
+ drm_rect_adjust_size(dst, max_dst_w - dst_w, 0);
+
+ return min_hscale;
+ }
+
+ if (hscale > max_hscale) {
+ int max_src_w = dst_w * max_hscale;
+
+ drm_rect_adjust_size(src, max_src_w - src_w, 0);
+
+ return max_hscale;
+ }
+
+ return hscale;
+}
+EXPORT_SYMBOL(drm_rect_calc_hscale_relaxed);
+
+/**
+ * drm_rect_calc_vscale_relaxed - calculate the vertical scaling factor
+ * @src: source window rectangle
+ * @dst: destination window rectangle
+ * @min_vscale: minimum allowed vertical scaling factor
+ * @max_vscale: maximum allowed vertical scaling factor
+ *
+ * Calculate the vertical scaling factor as
+ * (@src height) / (@dst height).
+ *
+ * If the calculated scaling factor is below @min_vscale,
+ * decrease the height of rectangle @dst to compensate.
+ *
+ * If the calculated scaling factor is above @max_vscale,
+ * decrease the height of rectangle @src to compensate.
+ *
+ * RETURNS:
+ * The vertical scaling factor.
+ */
+int drm_rect_calc_vscale_relaxed(struct drm_rect *src,
+ struct drm_rect *dst,
+ int min_vscale, int max_vscale)
+{
+ int src_h = drm_rect_height(src);
+ int dst_h = drm_rect_height(dst);
+ int vscale = drm_calc_scale(src_h, dst_h);
+
+ if (vscale < 0 || dst_h == 0)
+ return vscale;
+
+ if (vscale < min_vscale) {
+ int max_dst_h = src_h / min_vscale;
+
+ drm_rect_adjust_size(dst, 0, max_dst_h - dst_h);
+
+ return min_vscale;
+ }
+
+ if (vscale > max_vscale) {
+ int max_src_h = dst_h * max_vscale;
+
+ drm_rect_adjust_size(src, 0, max_src_h - src_h);
+
+ return max_vscale;
+ }
+
+ return vscale;
+}
+EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed);
+
+/**
+ * drm_rect_debug_print - print the rectangle information
+ * @r: rectangle to print
+ * @fixed_point: rectangle is in 16.16 fixed point format
+ */
+void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point)
+{
+ int w = drm_rect_width(r);
+ int h = drm_rect_height(r);
+
+ if (fixed_point)
+ DRM_DEBUG_KMS("%d.%06ux%d.%06u%+d.%06u%+d.%06u\n",
+ w >> 16, ((w & 0xffff) * 15625) >> 10,
+ h >> 16, ((h & 0xffff) * 15625) >> 10,
+ r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10,
+ r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10);
+ else
+ DRM_DEBUG_KMS("%dx%d%+d%+d\n", w, h, r->x1, r->y1);
+}
+EXPORT_SYMBOL(drm_rect_debug_print);
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 16f3ec579b3b..327ca19cda85 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -203,7 +203,7 @@ EXPORT_SYMBOL(drm_master_put);
int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- int ret;
+ int ret = 0;
if (file_priv->is_master)
return 0;
@@ -229,7 +229,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
}
mutex_unlock(&dev->struct_mutex);
- return 0;
+ return ret;
}
int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
@@ -451,14 +451,8 @@ void drm_put_dev(struct drm_device *dev)
drm_lastclose(dev);
- if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
- dev->agp && dev->agp->agp_mtrr >= 0) {
- int retval;
- retval = mtrr_del(dev->agp->agp_mtrr,
- dev->agp->agp_info.aper_base,
- dev->agp->agp_info.aper_size * 1024 * 1024);
- DRM_DEBUG("mtrr_del=%d\n", retval);
- }
+ if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) && dev->agp)
+ arch_phys_wc_del(dev->agp->agp_mtrr);
if (dev->driver->unload)
dev->driver->unload(dev);
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 02296653a058..2290b3b73832 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -30,14 +30,14 @@ static struct device_type drm_sysfs_device_minor = {
};
/**
- * drm_class_suspend - DRM class suspend hook
+ * __drm_class_suspend - internal DRM class suspend routine
* @dev: Linux device to suspend
* @state: power state to enter
*
* Just figures out what the actual struct drm_device associated with
* @dev is and calls its suspend hook, if present.
*/
-static int drm_class_suspend(struct device *dev, pm_message_t state)
+static int __drm_class_suspend(struct device *dev, pm_message_t state)
{
if (dev->type == &drm_sysfs_device_minor) {
struct drm_minor *drm_minor = to_drm_minor(dev);
@@ -52,6 +52,26 @@ static int drm_class_suspend(struct device *dev, pm_message_t state)
}
/**
+ * drm_class_suspend - internal DRM class suspend hook. Simply calls
+ * __drm_class_suspend() with the correct pm state.
+ * @dev: Linux device to suspend
+ */
+static int drm_class_suspend(struct device *dev)
+{
+ return __drm_class_suspend(dev, PMSG_SUSPEND);
+}
+
+/**
+ * drm_class_freeze - internal DRM class freeze hook. Simply calls
+ * __drm_class_suspend() with the correct pm state.
+ * @dev: Linux device to freeze
+ */
+static int drm_class_freeze(struct device *dev)
+{
+ return __drm_class_suspend(dev, PMSG_FREEZE);
+}
+
+/**
* drm_class_resume - DRM class resume hook
* @dev: Linux device to resume
*
@@ -72,6 +92,12 @@ static int drm_class_resume(struct device *dev)
return 0;
}
+static const struct dev_pm_ops drm_class_dev_pm_ops = {
+ .suspend = drm_class_suspend,
+ .resume = drm_class_resume,
+ .freeze = drm_class_freeze,
+};
+
static char *drm_devnode(struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
@@ -106,8 +132,7 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
goto err_out;
}
- class->suspend = drm_class_suspend;
- class->resume = drm_class_resume;
+ class->pm = &drm_class_dev_pm_ops;
err = class_create_file(class, &class_attr_version.attr);
if (err)
diff --git a/drivers/gpu/drm/drm_trace.h b/drivers/gpu/drm/drm_trace.h
index 03ea964aa604..27cc95f36381 100644
--- a/drivers/gpu/drm/drm_trace.h
+++ b/drivers/gpu/drm/drm_trace.h
@@ -21,7 +21,7 @@ TRACE_EVENT(drm_vblank_event,
__entry->crtc = crtc;
__entry->seq = seq;
),
- TP_printk("crtc=%d, seq=%d", __entry->crtc, __entry->seq)
+ TP_printk("crtc=%d, seq=%u", __entry->crtc, __entry->seq)
);
TRACE_EVENT(drm_vblank_event_queued,
@@ -37,7 +37,7 @@ TRACE_EVENT(drm_vblank_event_queued,
__entry->crtc = crtc;
__entry->seq = seq;
),
- TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
+ TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \
__entry->seq)
);
@@ -54,7 +54,7 @@ TRACE_EVENT(drm_vblank_event_delivered,
__entry->crtc = crtc;
__entry->seq = seq;
),
- TP_printk("pid=%d, crtc=%d, seq=%d", __entry->pid, __entry->crtc, \
+ TP_printk("pid=%d, crtc=%d, seq=%u", __entry->pid, __entry->crtc, \
__entry->seq)
);
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 67969e25d60f..feb20035b2c4 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -43,18 +43,19 @@
static void drm_vm_open(struct vm_area_struct *vma);
static void drm_vm_close(struct vm_area_struct *vma);
-static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
+static pgprot_t drm_io_prot(struct drm_local_map *map,
+ struct vm_area_struct *vma)
{
pgprot_t tmp = vm_get_page_prot(vma->vm_flags);
#if defined(__i386__) || defined(__x86_64__)
- if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) {
- pgprot_val(tmp) |= _PAGE_PCD;
- pgprot_val(tmp) &= ~_PAGE_PWT;
- }
+ if (map->type == _DRM_REGISTERS && !(map->flags & _DRM_WRITE_COMBINING))
+ tmp = pgprot_noncached(tmp);
+ else
+ tmp = pgprot_writecombine(tmp);
#elif defined(__powerpc__)
pgprot_val(tmp) |= _PAGE_NO_CACHE;
- if (map_type == _DRM_REGISTERS)
+ if (map->type == _DRM_REGISTERS)
pgprot_val(tmp) |= _PAGE_GUARDED;
#elif defined(__ia64__)
if (efi_range_is_wc(vma->vm_start, vma->vm_end -
@@ -250,13 +251,8 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
switch (map->type) {
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
- if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
- int retcode;
- retcode = mtrr_del(map->mtrr,
- map->offset,
- map->size);
- DRM_DEBUG("mtrr_del = %d\n", retcode);
- }
+ if (drm_core_has_MTRR(dev))
+ arch_phys_wc_del(map->mtrr);
iounmap(map->handle);
break;
case _DRM_SHM:
@@ -617,7 +613,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
offset = drm_core_get_reg_ofs(dev);
- vma->vm_page_prot = drm_io_prot(map->type, vma);
+ vma->vm_page_prot = drm_io_prot(map, vma);
if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
index 4e9b5ba8edff..95c75edef01a 100644
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ b/drivers/gpu/drm/exynos/exynos_ddc.c
@@ -53,6 +53,8 @@ static struct of_device_id hdmiddc_match_types[] = {
{
.compatible = "samsung,exynos5-hdmiddc",
}, {
+ .compatible = "samsung,exynos4210-hdmiddc",
+ }, {
/* end node */
}
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 57affae9568b..b8ac06d92fbf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -24,8 +24,6 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
enum dma_attr attr;
unsigned int nr_pages;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (buf->dma_addr) {
DRM_DEBUG_KMS("already allocated.\n");
return 0;
@@ -59,8 +57,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
dma_addr_t start_addr;
unsigned int i = 0;
- buf->pages = kzalloc(sizeof(struct page) * nr_pages,
- GFP_KERNEL);
+ buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
if (!buf->pages) {
DRM_ERROR("failed to allocate pages.\n");
return -ENOMEM;
@@ -71,8 +68,8 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
&buf->dma_attrs);
if (!buf->kvaddr) {
DRM_ERROR("failed to allocate buffer.\n");
- kfree(buf->pages);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_free;
}
start_addr = buf->dma_addr;
@@ -109,9 +106,9 @@ err_free_attrs:
dma_free_attrs(dev->dev, buf->size, buf->pages,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
buf->dma_addr = (dma_addr_t)NULL;
-
+err_free:
if (!is_drm_iommu_supported(dev))
- kfree(buf->pages);
+ drm_free_large(buf->pages);
return ret;
}
@@ -119,8 +116,6 @@ err_free_attrs:
static void lowlevel_buffer_deallocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
- DRM_DEBUG_KMS("%s.\n", __FILE__);
-
if (!buf->dma_addr) {
DRM_DEBUG_KMS("dma_addr is invalid.\n");
return;
@@ -138,7 +133,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
if (!is_drm_iommu_supported(dev)) {
dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
- kfree(buf->pages);
+ drm_free_large(buf->pages);
} else
dma_free_attrs(dev->dev, buf->size, buf->pages,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
@@ -151,7 +146,6 @@ struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
{
struct exynos_drm_gem_buf *buffer;
- DRM_DEBUG_KMS("%s.\n", __FILE__);
DRM_DEBUG_KMS("desired size = 0x%x\n", size);
buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
@@ -167,8 +161,6 @@ struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
void exynos_drm_fini_buf(struct drm_device *dev,
struct exynos_drm_gem_buf *buffer)
{
- DRM_DEBUG_KMS("%s.\n", __FILE__);
-
if (!buffer) {
DRM_DEBUG_KMS("buffer is null.\n");
return;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 8bcc13ac9f73..02a8bc5226ca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -34,7 +34,6 @@ convert_to_display_mode(struct drm_display_mode *mode,
struct exynos_drm_panel_info *panel)
{
struct fb_videomode *timing = &panel->timing;
- DRM_DEBUG_KMS("%s\n", __FILE__);
mode->clock = timing->pixclock / 1000;
mode->vrefresh = timing->refresh;
@@ -58,37 +57,6 @@ convert_to_display_mode(struct drm_display_mode *mode,
mode->flags |= DRM_MODE_FLAG_DBLSCAN;
}
-/* convert drm_display_mode to exynos_video_timings */
-static inline void
-convert_to_video_timing(struct fb_videomode *timing,
- struct drm_display_mode *mode)
-{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- memset(timing, 0, sizeof(*timing));
-
- timing->pixclock = mode->clock * 1000;
- timing->refresh = drm_mode_vrefresh(mode);
-
- timing->xres = mode->hdisplay;
- timing->right_margin = mode->hsync_start - mode->hdisplay;
- timing->hsync_len = mode->hsync_end - mode->hsync_start;
- timing->left_margin = mode->htotal - mode->hsync_end;
-
- timing->yres = mode->vdisplay;
- timing->lower_margin = mode->vsync_start - mode->vdisplay;
- timing->vsync_len = mode->vsync_end - mode->vsync_start;
- timing->upper_margin = mode->vtotal - mode->vsync_end;
-
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- timing->vmode = FB_VMODE_INTERLACED;
- else
- timing->vmode = FB_VMODE_NONINTERLACED;
-
- if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
- timing->vmode |= FB_VMODE_DOUBLE;
-}
-
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
{
struct exynos_drm_connector *exynos_connector =
@@ -99,8 +67,6 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
unsigned int count = 0;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!display_ops) {
DRM_DEBUG_KMS("display_ops is null.\n");
return 0;
@@ -168,15 +134,12 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
to_exynos_connector(connector);
struct exynos_drm_manager *manager = exynos_connector->manager;
struct exynos_drm_display_ops *display_ops = manager->display_ops;
- struct fb_videomode timing;
int ret = MODE_BAD;
DRM_DEBUG_KMS("%s\n", __FILE__);
- convert_to_video_timing(&timing, mode);
-
- if (display_ops && display_ops->check_timing)
- if (!display_ops->check_timing(manager->dev, (void *)&timing))
+ if (display_ops && display_ops->check_mode)
+ if (!display_ops->check_mode(manager->dev, mode))
ret = MODE_OK;
return ret;
@@ -190,8 +153,6 @@ struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
struct drm_mode_object *obj;
struct drm_encoder *encoder;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
obj = drm_mode_object_find(dev, exynos_connector->encoder_id,
DRM_MODE_OBJECT_ENCODER);
if (!obj) {
@@ -234,8 +195,6 @@ void exynos_drm_display_power(struct drm_connector *connector, int mode)
static void exynos_drm_connector_dpms(struct drm_connector *connector,
int mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* in case that drm_crtc_helper_set_mode() is called,
* encoder/crtc->funcs->dpms() will be just returned
@@ -282,8 +241,6 @@ exynos_drm_connector_detect(struct drm_connector *connector, bool force)
manager->display_ops;
enum drm_connector_status status = connector_status_disconnected;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (display_ops && display_ops->is_connected) {
if (display_ops->is_connected(manager->dev))
status = connector_status_connected;
@@ -299,8 +256,6 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
struct exynos_drm_connector *exynos_connector =
to_exynos_connector(connector);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
drm_sysfs_connector_remove(connector);
drm_connector_cleanup(connector);
kfree(exynos_connector);
@@ -322,8 +277,6 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
int type;
int err;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
if (!exynos_connector) {
DRM_ERROR("failed to allocate connector\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 4667c9f67acd..1bef6dc77478 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -27,8 +27,6 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev,
struct drm_connector *connector;
int ret;
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
subdrv->manager->dev = subdrv->dev;
/* create and initialize a encoder for this sub driver. */
@@ -102,8 +100,6 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev,
static void exynos_drm_subdrv_remove(struct drm_device *dev,
struct exynos_drm_subdrv *subdrv)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
if (subdrv->remove)
subdrv->remove(dev, subdrv->dev);
}
@@ -114,8 +110,6 @@ int exynos_drm_device_register(struct drm_device *dev)
unsigned int fine_cnt = 0;
int err;
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
if (!dev)
return -EINVAL;
@@ -158,8 +152,6 @@ int exynos_drm_device_unregister(struct drm_device *dev)
{
struct exynos_drm_subdrv *subdrv;
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
if (!dev) {
WARN(1, "Unexpected drm device unregister!\n");
return -EINVAL;
@@ -176,8 +168,6 @@ EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
if (!subdrv)
return -EINVAL;
@@ -189,8 +179,6 @@ EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
if (!subdrv)
return -EINVAL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index c200e4d71e3d..9a35d171a6d3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -76,8 +76,6 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* drm framework doesn't check NULL. */
}
@@ -85,8 +83,6 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
exynos_plane_commit(exynos_crtc->plane);
exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
@@ -97,8 +93,6 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* drm framework doesn't check NULL */
return true;
}
@@ -115,8 +109,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
int pipe = exynos_crtc->pipe;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* copy the mode data adjusted by mode_fixup() into crtc->mode
* so that hardware can be seet to proper mode.
@@ -139,7 +131,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
return 0;
}
-static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
@@ -148,8 +140,6 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
unsigned int crtc_h;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* when framebuffer changing is requested, crtc's dpms should be on */
if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
DRM_ERROR("failed framebuffer changing request.\n");
@@ -169,18 +159,16 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
-static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
+static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
- /* drm framework doesn't check NULL */
+ return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
}
static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
}
@@ -192,7 +180,6 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
.mode_fixup = exynos_drm_crtc_mode_fixup,
.mode_set = exynos_drm_crtc_mode_set,
.mode_set_base = exynos_drm_crtc_mode_set_base,
- .load_lut = exynos_drm_crtc_load_lut,
.disable = exynos_drm_crtc_disable,
};
@@ -206,8 +193,6 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb = crtc->fb;
int ret = -EINVAL;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* when the page flip is requested, crtc's dpms should be on */
if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
DRM_ERROR("failed page flip request.\n");
@@ -237,7 +222,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
spin_unlock_irq(&dev->event_lock);
crtc->fb = fb;
- ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
+ ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
NULL);
if (ret) {
crtc->fb = old_fb;
@@ -260,8 +245,6 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct exynos_drm_private *private = crtc->dev->dev_private;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
private->crtc[exynos_crtc->pipe] = NULL;
drm_crtc_cleanup(crtc);
@@ -276,8 +259,6 @@ static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
struct exynos_drm_private *dev_priv = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (property == dev_priv->crtc_mode_property) {
enum exynos_crtc_mode mode = val;
@@ -322,8 +303,6 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_property *prop;
- DRM_DEBUG_KMS("%s\n", __func__);
-
prop = dev_priv->crtc_mode_property;
if (!prop) {
prop = drm_property_create_enum(dev, 0, "mode", mode_names,
@@ -343,8 +322,6 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
struct exynos_drm_private *private = dev->dev_private;
struct drm_crtc *crtc;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
if (!exynos_crtc) {
DRM_ERROR("failed to allocate exynos crtc\n");
@@ -379,8 +356,6 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[crtc]);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM;
@@ -396,8 +371,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[crtc]);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return;
@@ -413,8 +386,6 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
unsigned long flags;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
spin_lock_irqsave(&dev->event_lock, flags);
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index ff7f2a886a34..a0f997e0cbdf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -71,8 +71,6 @@ static struct sg_table *
unsigned int i;
int nents, ret;
- DRM_DEBUG_PRIME("%s\n", __FILE__);
-
/* just return current sgt if already requested. */
if (exynos_attach->dir == dir && exynos_attach->is_mapped)
return &exynos_attach->sgt;
@@ -133,8 +131,6 @@ static void exynos_dmabuf_release(struct dma_buf *dmabuf)
{
struct exynos_drm_gem_obj *exynos_gem_obj = dmabuf->priv;
- DRM_DEBUG_PRIME("%s\n", __FILE__);
-
/*
* exynos_dmabuf_release() call means that file object's
* f_count is 0 and it calls drm_gem_object_handle_unreference()
@@ -219,8 +215,6 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct exynos_drm_gem_buf *buffer;
int ret;
- DRM_DEBUG_PRIME("%s\n", __FILE__);
-
/* is this one of own objects? */
if (dma_buf->ops == &exynos_dmabuf_ops) {
struct drm_gem_object *obj;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index ba6d995e4375..ca2729a85129 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -46,8 +46,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
int ret;
int nr;
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
if (!private) {
DRM_ERROR("failed to allocate private\n");
@@ -140,8 +138,6 @@ err_crtc:
static int exynos_drm_unload(struct drm_device *dev)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
exynos_drm_fbdev_fini(dev);
exynos_drm_device_unregister(dev);
drm_vblank_cleanup(dev);
@@ -159,8 +155,7 @@ static int exynos_drm_unload(struct drm_device *dev)
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
struct drm_exynos_file_private *file_priv;
-
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
+ int ret;
file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
@@ -168,7 +163,13 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
file->driver_priv = file_priv;
- return exynos_drm_subdrv_open(dev, file);
+ ret = exynos_drm_subdrv_open(dev, file);
+ if (ret) {
+ kfree(file_priv);
+ file->driver_priv = NULL;
+ }
+
+ return ret;
}
static void exynos_drm_preclose(struct drm_device *dev,
@@ -178,8 +179,6 @@ static void exynos_drm_preclose(struct drm_device *dev,
struct drm_pending_vblank_event *e, *t;
unsigned long flags;
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
/* release events of current file */
spin_lock_irqsave(&dev->event_lock, flags);
list_for_each_entry_safe(e, t, &private->pageflip_event_list,
@@ -196,8 +195,6 @@ static void exynos_drm_preclose(struct drm_device *dev,
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
if (!file->driver_priv)
return;
@@ -207,8 +204,6 @@ static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
static void exynos_drm_lastclose(struct drm_device *dev)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
exynos_drm_fbdev_restore_mode(dev);
}
@@ -292,8 +287,6 @@ static struct drm_driver exynos_drm_driver = {
static int exynos_drm_platform_probe(struct platform_device *pdev)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
@@ -302,8 +295,6 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
static int exynos_drm_platform_remove(struct platform_device *pdev)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
drm_platform_exit(&exynos_drm_driver, pdev);
return 0;
@@ -322,8 +313,6 @@ static int __init exynos_drm_init(void)
{
int ret;
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
#ifdef CONFIG_DRM_EXYNOS_FIMD
ret = platform_driver_register(&fimd_driver);
if (ret < 0)
@@ -455,8 +444,6 @@ out_fimd:
static void __exit exynos_drm_exit(void)
{
- DRM_DEBUG_DRIVER("%s\n", __FILE__);
-
platform_device_unregister(exynos_drm_pdev);
platform_driver_unregister(&exynos_drm_platform_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 680a7c1b9dea..eaa19668bf00 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -142,7 +142,7 @@ struct exynos_drm_overlay {
* @is_connected: check for that display is connected or not.
* @get_edid: get edid modes from display driver.
* @get_panel: get panel object from display driver.
- * @check_timing: check if timing is valid or not.
+ * @check_mode: check if mode is valid or not.
* @power_on: display device on or off.
*/
struct exynos_drm_display_ops {
@@ -151,7 +151,7 @@ struct exynos_drm_display_ops {
struct edid *(*get_edid)(struct device *dev,
struct drm_connector *connector);
void *(*get_panel)(struct device *dev);
- int (*check_timing)(struct device *dev, void *timing);
+ int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
int (*power_on)(struct device *dev, int mode);
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index c63721f64aec..a99a033793bc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -61,7 +61,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
struct exynos_drm_manager_ops *manager_ops = manager->ops;
struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
- DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode);
+ DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
if (exynos_encoder->dpms == mode) {
DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
@@ -104,8 +104,6 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
struct exynos_drm_manager_ops *manager_ops = manager->ops;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder)
if (manager_ops && manager_ops->mode_fixup)
@@ -155,8 +153,6 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
struct exynos_drm_manager *manager;
struct exynos_drm_manager_ops *manager_ops;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->encoder == encoder) {
struct exynos_drm_encoder *exynos_encoder;
@@ -189,8 +185,6 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* drm framework doesn't check NULL. */
}
@@ -200,8 +194,6 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
struct exynos_drm_manager *manager = exynos_encoder->manager;
struct exynos_drm_manager_ops *manager_ops = manager->ops;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (manager_ops && manager_ops->commit)
manager_ops->commit(manager->dev);
@@ -274,8 +266,6 @@ static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
struct exynos_drm_encoder *exynos_encoder =
to_exynos_encoder(encoder);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_encoder->manager->pipe = -1;
drm_encoder_cleanup(encoder);
@@ -315,8 +305,6 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
{
struct drm_encoder *encoder;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
encoder->possible_clones = exynos_drm_encoder_clones(encoder);
}
@@ -329,8 +317,6 @@ exynos_drm_encoder_create(struct drm_device *dev,
struct drm_encoder *encoder;
struct exynos_drm_encoder *exynos_encoder;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!manager || !possible_crtcs)
return NULL;
@@ -427,8 +413,6 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
struct exynos_drm_manager_ops *manager_ops = manager->ops;
int mode = *(int *)data;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (manager_ops && manager_ops->dpms)
manager_ops->dpms(manager->dev, mode);
@@ -449,8 +433,6 @@ void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
to_exynos_encoder(encoder)->manager;
int pipe = *(int *)data;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* when crtc is detached from encoder, this pipe is used
* to select manager operation
@@ -465,8 +447,6 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
struct exynos_drm_overlay *overlay = data;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (overlay_ops && overlay_ops->mode_set)
overlay_ops->mode_set(manager->dev, overlay);
}
@@ -478,8 +458,6 @@ void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
int zpos = DEFAULT_ZPOS;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (data)
zpos = *(int *)data;
@@ -494,8 +472,6 @@ void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
int zpos = DEFAULT_ZPOS;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (data)
zpos = *(int *)data;
@@ -510,8 +486,6 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
int zpos = DEFAULT_ZPOS;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (data)
zpos = *(int *)data;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 0e04f4ea441f..c2d149f0408a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -70,8 +70,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
unsigned int i;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* make sure that overlay data are updated before relesing fb. */
exynos_drm_encoder_complete_scanout(fb);
@@ -97,8 +95,6 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
{
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* This fb should have only one gem object. */
if (WARN_ON(exynos_fb->buf_cnt != 1))
return -EINVAL;
@@ -112,8 +108,6 @@ static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
unsigned color, struct drm_clip_rect *clips,
unsigned num_clips)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO */
return 0;
@@ -225,8 +219,6 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
struct exynos_drm_fb *exynos_fb;
int i, ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL);
if (!exynos_fb) {
DRM_ERROR("failed to allocate exynos drm framebuffer\n");
@@ -293,8 +285,6 @@ struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
struct exynos_drm_gem_buf *buffer;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (index >= MAX_FB_BUFFER)
return NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 8f007aaeffc3..8e60bd61137f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -43,8 +43,6 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
unsigned long vm_size;
int ret;
- DRM_DEBUG_KMS("%s\n", __func__);
-
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vm_size = vma->vm_end - vma->vm_start;
@@ -84,8 +82,6 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
unsigned long offset;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
@@ -148,8 +144,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
unsigned long size;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
sizes->surface_width, sizes->surface_height,
sizes->surface_bpp);
@@ -238,8 +232,6 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
unsigned int num_crtc;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 4a1616a18ab7..61b094f689a7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -175,8 +175,6 @@ static void fimc_sw_reset(struct fimc_context *ctx)
{
u32 cfg;
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* stop dma operation */
cfg = fimc_read(EXYNOS_CISTATUS);
if (EXYNOS_CISTATUS_GET_ENVID_STATUS(cfg)) {
@@ -210,8 +208,6 @@ static void fimc_sw_reset(struct fimc_context *ctx)
static int fimc_set_camblk_fimd0_wb(struct fimc_context *ctx)
{
- DRM_DEBUG_KMS("%s\n", __func__);
-
return regmap_update_bits(ctx->sysreg, SYSREG_CAMERA_BLK,
SYSREG_FIMD0WB_DEST_MASK,
ctx->id << SYSREG_FIMD0WB_DEST_SHIFT);
@@ -221,7 +217,7 @@ static void fimc_set_type_ctrl(struct fimc_context *ctx, enum fimc_wb wb)
{
u32 cfg;
- DRM_DEBUG_KMS("%s:wb[%d]\n", __func__, wb);
+ DRM_DEBUG_KMS("wb[%d]\n", wb);
cfg = fimc_read(EXYNOS_CIGCTRL);
cfg &= ~(EXYNOS_CIGCTRL_TESTPATTERN_MASK |
@@ -257,10 +253,10 @@ static void fimc_set_polarity(struct fimc_context *ctx,
{
u32 cfg;
- DRM_DEBUG_KMS("%s:inv_pclk[%d]inv_vsync[%d]\n",
- __func__, pol->inv_pclk, pol->inv_vsync);
- DRM_DEBUG_KMS("%s:inv_href[%d]inv_hsync[%d]\n",
- __func__, pol->inv_href, pol->inv_hsync);
+ DRM_DEBUG_KMS("inv_pclk[%d]inv_vsync[%d]\n",
+ pol->inv_pclk, pol->inv_vsync);
+ DRM_DEBUG_KMS("inv_href[%d]inv_hsync[%d]\n",
+ pol->inv_href, pol->inv_hsync);
cfg = fimc_read(EXYNOS_CIGCTRL);
cfg &= ~(EXYNOS_CIGCTRL_INVPOLPCLK | EXYNOS_CIGCTRL_INVPOLVSYNC |
@@ -282,7 +278,7 @@ static void fimc_handle_jpeg(struct fimc_context *ctx, bool enable)
{
u32 cfg;
- DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+ DRM_DEBUG_KMS("enable[%d]\n", enable);
cfg = fimc_read(EXYNOS_CIGCTRL);
if (enable)
@@ -298,7 +294,7 @@ static void fimc_handle_irq(struct fimc_context *ctx, bool enable,
{
u32 cfg;
- DRM_DEBUG_KMS("%s:enable[%d]overflow[%d]level[%d]\n", __func__,
+ DRM_DEBUG_KMS("enable[%d]overflow[%d]level[%d]\n",
enable, overflow, level);
cfg = fimc_read(EXYNOS_CIGCTRL);
@@ -319,8 +315,6 @@ static void fimc_clear_irq(struct fimc_context *ctx)
{
u32 cfg;
- DRM_DEBUG_KMS("%s\n", __func__);
-
cfg = fimc_read(EXYNOS_CIGCTRL);
cfg |= EXYNOS_CIGCTRL_IRQ_CLR;
fimc_write(cfg, EXYNOS_CIGCTRL);
@@ -335,7 +329,7 @@ static bool fimc_check_ovf(struct fimc_context *ctx)
flag = EXYNOS_CISTATUS_OVFIY | EXYNOS_CISTATUS_OVFICB |
EXYNOS_CISTATUS_OVFICR;
- DRM_DEBUG_KMS("%s:flag[0x%x]\n", __func__, flag);
+ DRM_DEBUG_KMS("flag[0x%x]\n", flag);
if (status & flag) {
cfg = fimc_read(EXYNOS_CIWDOFST);
@@ -364,7 +358,7 @@ static bool fimc_check_frame_end(struct fimc_context *ctx)
cfg = fimc_read(EXYNOS_CISTATUS);
- DRM_DEBUG_KMS("%s:cfg[0x%x]\n", __func__, cfg);
+ DRM_DEBUG_KMS("cfg[0x%x]\n", cfg);
if (!(cfg & EXYNOS_CISTATUS_FRAMEEND))
return false;
@@ -380,15 +374,13 @@ static int fimc_get_buf_id(struct fimc_context *ctx)
u32 cfg;
int frame_cnt, buf_id;
- DRM_DEBUG_KMS("%s\n", __func__);
-
cfg = fimc_read(EXYNOS_CISTATUS2);
frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg);
if (frame_cnt == 0)
frame_cnt = EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg);
- DRM_DEBUG_KMS("%s:present[%d]before[%d]\n", __func__,
+ DRM_DEBUG_KMS("present[%d]before[%d]\n",
EXYNOS_CISTATUS2_GET_FRAMECOUNT_PRESENT(cfg),
EXYNOS_CISTATUS2_GET_FRAMECOUNT_BEFORE(cfg));
@@ -398,7 +390,7 @@ static int fimc_get_buf_id(struct fimc_context *ctx)
}
buf_id = frame_cnt - 1;
- DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id);
+ DRM_DEBUG_KMS("buf_id[%d]\n", buf_id);
return buf_id;
}
@@ -407,7 +399,7 @@ static void fimc_handle_lastend(struct fimc_context *ctx, bool enable)
{
u32 cfg;
- DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+ DRM_DEBUG_KMS("enable[%d]\n", enable);
cfg = fimc_read(EXYNOS_CIOCTRL);
if (enable)
@@ -424,7 +416,7 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+ DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
/* RGB */
cfg = fimc_read(EXYNOS_CISCCTRL);
@@ -497,7 +489,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt)
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+ DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
cfg = fimc_read(EXYNOS_MSCTRL);
cfg &= ~EXYNOS_MSCTRL_INFORMAT_RGB;
@@ -557,8 +549,7 @@ static int fimc_src_set_transf(struct device *dev,
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg1, cfg2;
- DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
- degree, flip);
+ DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
cfg1 = fimc_read(EXYNOS_MSCTRL);
cfg1 &= ~(EXYNOS_MSCTRL_FLIP_X_MIRROR |
@@ -621,10 +612,9 @@ static int fimc_set_window(struct fimc_context *ctx,
v1 = pos->y;
v2 = sz->vsize - pos->h - pos->y;
- DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
- __func__, pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize);
- DRM_DEBUG_KMS("%s:h1[%d]h2[%d]v1[%d]v2[%d]\n", __func__,
- h1, h2, v1, v2);
+ DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]hsize[%d]vsize[%d]\n",
+ pos->x, pos->y, pos->w, pos->h, sz->hsize, sz->vsize);
+ DRM_DEBUG_KMS("h1[%d]h2[%d]v1[%d]v2[%d]\n", h1, h2, v1, v2);
/*
* set window offset 1, 2 size
@@ -653,8 +643,8 @@ static int fimc_src_set_size(struct device *dev, int swap,
struct drm_exynos_sz img_sz = *sz;
u32 cfg;
- DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n",
- __func__, swap, sz->hsize, sz->vsize);
+ DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
+ swap, sz->hsize, sz->vsize);
/* original size */
cfg = (EXYNOS_ORGISIZE_HORIZONTAL(img_sz.hsize) |
@@ -662,8 +652,7 @@ static int fimc_src_set_size(struct device *dev, int swap,
fimc_write(cfg, EXYNOS_ORGISIZE);
- DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n", __func__,
- pos->x, pos->y, pos->w, pos->h);
+ DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h);
if (swap) {
img_pos.w = pos->h;
@@ -720,7 +709,7 @@ static int fimc_src_set_addr(struct device *dev,
property = &c_node->property;
- DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+ DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
property->prop_id, buf_id, buf_type);
if (buf_id > FIMC_MAX_SRC) {
@@ -772,7 +761,7 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+ DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
/* RGB */
cfg = fimc_read(EXYNOS_CISCCTRL);
@@ -851,7 +840,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+ DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
cfg = fimc_read(EXYNOS_CIEXTEN);
@@ -919,8 +908,7 @@ static int fimc_dst_set_transf(struct device *dev,
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
- degree, flip);
+ DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
cfg = fimc_read(EXYNOS_CITRGFMT);
cfg &= ~EXYNOS_CITRGFMT_FLIP_MASK;
@@ -970,7 +958,7 @@ static int fimc_dst_set_transf(struct device *dev,
static int fimc_get_ratio_shift(u32 src, u32 dst, u32 *ratio, u32 *shift)
{
- DRM_DEBUG_KMS("%s:src[%d]dst[%d]\n", __func__, src, dst);
+ DRM_DEBUG_KMS("src[%d]dst[%d]\n", src, dst);
if (src >= dst * 64) {
DRM_ERROR("failed to make ratio and shift.\n");
@@ -1039,20 +1027,20 @@ static int fimc_set_prescaler(struct fimc_context *ctx, struct fimc_scaler *sc,
pre_dst_width = src_w / pre_hratio;
pre_dst_height = src_h / pre_vratio;
- DRM_DEBUG_KMS("%s:pre_dst_width[%d]pre_dst_height[%d]\n", __func__,
+ DRM_DEBUG_KMS("pre_dst_width[%d]pre_dst_height[%d]\n",
pre_dst_width, pre_dst_height);
- DRM_DEBUG_KMS("%s:pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n",
- __func__, pre_hratio, hfactor, pre_vratio, vfactor);
+ DRM_DEBUG_KMS("pre_hratio[%d]hfactor[%d]pre_vratio[%d]vfactor[%d]\n",
+ pre_hratio, hfactor, pre_vratio, vfactor);
sc->hratio = (src_w << 14) / (dst_w << hfactor);
sc->vratio = (src_h << 14) / (dst_h << vfactor);
sc->up_h = (dst_w >= src_w) ? true : false;
sc->up_v = (dst_h >= src_h) ? true : false;
- DRM_DEBUG_KMS("%s:hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
- __func__, sc->hratio, sc->vratio, sc->up_h, sc->up_v);
+ DRM_DEBUG_KMS("hratio[%d]vratio[%d]up_h[%d]up_v[%d]\n",
+ sc->hratio, sc->vratio, sc->up_h, sc->up_v);
shfactor = FIMC_SHFACTOR - (hfactor + vfactor);
- DRM_DEBUG_KMS("%s:shfactor[%d]\n", __func__, shfactor);
+ DRM_DEBUG_KMS("shfactor[%d]\n", shfactor);
cfg = (EXYNOS_CISCPRERATIO_SHFACTOR(shfactor) |
EXYNOS_CISCPRERATIO_PREHORRATIO(pre_hratio) |
@@ -1070,10 +1058,10 @@ static void fimc_set_scaler(struct fimc_context *ctx, struct fimc_scaler *sc)
{
u32 cfg, cfg_ext;
- DRM_DEBUG_KMS("%s:range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
- __func__, sc->range, sc->bypass, sc->up_h, sc->up_v);
- DRM_DEBUG_KMS("%s:hratio[%d]vratio[%d]\n",
- __func__, sc->hratio, sc->vratio);
+ DRM_DEBUG_KMS("range[%d]bypass[%d]up_h[%d]up_v[%d]\n",
+ sc->range, sc->bypass, sc->up_h, sc->up_v);
+ DRM_DEBUG_KMS("hratio[%d]vratio[%d]\n",
+ sc->hratio, sc->vratio);
cfg = fimc_read(EXYNOS_CISCCTRL);
cfg &= ~(EXYNOS_CISCCTRL_SCALERBYPASS |
@@ -1113,8 +1101,8 @@ static int fimc_dst_set_size(struct device *dev, int swap,
struct drm_exynos_sz img_sz = *sz;
u32 cfg;
- DRM_DEBUG_KMS("%s:swap[%d]hsize[%d]vsize[%d]\n",
- __func__, swap, sz->hsize, sz->vsize);
+ DRM_DEBUG_KMS("swap[%d]hsize[%d]vsize[%d]\n",
+ swap, sz->hsize, sz->vsize);
/* original size */
cfg = (EXYNOS_ORGOSIZE_HORIZONTAL(img_sz.hsize) |
@@ -1122,8 +1110,7 @@ static int fimc_dst_set_size(struct device *dev, int swap,
fimc_write(cfg, EXYNOS_ORGOSIZE);
- DRM_DEBUG_KMS("%s:x[%d]y[%d]w[%d]h[%d]\n",
- __func__, pos->x, pos->y, pos->w, pos->h);
+ DRM_DEBUG_KMS("x[%d]y[%d]w[%d]h[%d]\n", pos->x, pos->y, pos->w, pos->h);
/* CSC ITU */
cfg = fimc_read(EXYNOS_CIGCTRL);
@@ -1180,7 +1167,7 @@ static int fimc_dst_get_buf_seq(struct fimc_context *ctx)
if (cfg & (mask << i))
buf_num++;
- DRM_DEBUG_KMS("%s:buf_num[%d]\n", __func__, buf_num);
+ DRM_DEBUG_KMS("buf_num[%d]\n", buf_num);
return buf_num;
}
@@ -1194,8 +1181,7 @@ static int fimc_dst_set_buf_seq(struct fimc_context *ctx, u32 buf_id,
u32 mask = 0x00000001 << buf_id;
int ret = 0;
- DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
- buf_id, buf_type);
+ DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
mutex_lock(&ctx->lock);
@@ -1252,7 +1238,7 @@ static int fimc_dst_set_addr(struct device *dev,
property = &c_node->property;
- DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+ DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
property->prop_id, buf_id, buf_type);
if (buf_id > FIMC_MAX_DST) {
@@ -1302,7 +1288,7 @@ static struct exynos_drm_ipp_ops fimc_dst_ops = {
static int fimc_clk_ctrl(struct fimc_context *ctx, bool enable)
{
- DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+ DRM_DEBUG_KMS("enable[%d]\n", enable);
if (enable) {
clk_prepare_enable(ctx->clocks[FIMC_CLK_GATE]);
@@ -1326,7 +1312,7 @@ static irqreturn_t fimc_irq_handler(int irq, void *dev_id)
c_node->event_work;
int buf_id;
- DRM_DEBUG_KMS("%s:fimc id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("fimc id[%d]\n", ctx->id);
fimc_clear_irq(ctx);
if (fimc_check_ovf(ctx))
@@ -1339,7 +1325,7 @@ static irqreturn_t fimc_irq_handler(int irq, void *dev_id)
if (buf_id < 0)
return IRQ_HANDLED;
- DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, buf_id);
+ DRM_DEBUG_KMS("buf_id[%d]\n", buf_id);
if (fimc_dst_set_buf_seq(ctx, buf_id, IPP_BUF_DEQUEUE) < 0) {
DRM_ERROR("failed to dequeue.\n");
@@ -1357,8 +1343,6 @@ static int fimc_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
{
struct drm_exynos_ipp_prop_list *prop_list;
- DRM_DEBUG_KMS("%s\n", __func__);
-
prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
if (!prop_list) {
DRM_ERROR("failed to alloc property list.\n");
@@ -1402,7 +1386,7 @@ static inline bool fimc_check_drm_flip(enum drm_exynos_flip flip)
case EXYNOS_DRM_FLIP_BOTH:
return true;
default:
- DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+ DRM_DEBUG_KMS("invalid flip\n");
return false;
}
}
@@ -1419,8 +1403,6 @@ static int fimc_ippdrv_check_property(struct device *dev,
bool swap;
int i;
- DRM_DEBUG_KMS("%s\n", __func__);
-
for_each_ipp_ops(i) {
if ((i == EXYNOS_DRM_OPS_SRC) &&
(property->cmd == IPP_CMD_WB))
@@ -1526,8 +1508,6 @@ static void fimc_clear_addr(struct fimc_context *ctx)
{
int i;
- DRM_DEBUG_KMS("%s:\n", __func__);
-
for (i = 0; i < FIMC_MAX_SRC; i++) {
fimc_write(0, EXYNOS_CIIYSA(i));
fimc_write(0, EXYNOS_CIICBSA(i));
@@ -1545,8 +1525,6 @@ static int fimc_ippdrv_reset(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* reset h/w block */
fimc_sw_reset(ctx);
@@ -1570,7 +1548,7 @@ static int fimc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
int ret, i;
u32 cfg0, cfg1;
- DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+ DRM_DEBUG_KMS("cmd[%d]\n", cmd);
if (!c_node) {
DRM_ERROR("failed to get c_node.\n");
@@ -1679,7 +1657,7 @@ static void fimc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
struct drm_exynos_ipp_set_wb set_wb = {0, 0};
u32 cfg;
- DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+ DRM_DEBUG_KMS("cmd[%d]\n", cmd);
switch (cmd) {
case IPP_CMD_M2M:
@@ -1869,8 +1847,7 @@ static int fimc_probe(struct platform_device *pdev)
goto err_put_clk;
}
- DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
- (int)ippdrv);
+ DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
@@ -1917,7 +1894,7 @@ static int fimc_suspend(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
if (pm_runtime_suspended(dev))
return 0;
@@ -1929,7 +1906,7 @@ static int fimc_resume(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
if (!pm_runtime_suspended(dev))
return fimc_clk_ctrl(ctx, true);
@@ -1943,7 +1920,7 @@ static int fimc_runtime_suspend(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
return fimc_clk_ctrl(ctx, false);
}
@@ -1952,7 +1929,7 @@ static int fimc_runtime_resume(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
return fimc_clk_ctrl(ctx, true);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 97c61dbffd82..3e106beca5b6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -63,14 +63,24 @@
struct fimd_driver_data {
unsigned int timing_base;
+
+ unsigned int has_shadowcon:1;
+ unsigned int has_clksel:1;
+};
+
+static struct fimd_driver_data s3c64xx_fimd_driver_data = {
+ .timing_base = 0x0,
+ .has_clksel = 1,
};
static struct fimd_driver_data exynos4_fimd_driver_data = {
.timing_base = 0x0,
+ .has_shadowcon = 1,
};
static struct fimd_driver_data exynos5_fimd_driver_data = {
.timing_base = 0x20000,
+ .has_shadowcon = 1,
};
struct fimd_win_data {
@@ -107,10 +117,13 @@ struct fimd_context {
atomic_t wait_vsync_event;
struct exynos_drm_panel_info *panel;
+ struct fimd_driver_data *driver_data;
};
#ifdef CONFIG_OF
static const struct of_device_id fimd_driver_dt_match[] = {
+ { .compatible = "samsung,s3c6400-fimd",
+ .data = &s3c64xx_fimd_driver_data },
{ .compatible = "samsung,exynos4210-fimd",
.data = &exynos4_fimd_driver_data },
{ .compatible = "samsung,exynos5250-fimd",
@@ -137,8 +150,6 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
static bool fimd_display_is_connected(struct device *dev)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO. */
return true;
@@ -148,15 +159,11 @@ static void *fimd_get_panel(struct device *dev)
{
struct fimd_context *ctx = get_fimd_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
return ctx->panel;
}
-static int fimd_check_timing(struct device *dev, void *timing)
+static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO. */
return 0;
@@ -164,8 +171,6 @@ static int fimd_check_timing(struct device *dev, void *timing)
static int fimd_display_power_on(struct device *dev, int mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO */
return 0;
@@ -175,7 +180,7 @@ static struct exynos_drm_display_ops fimd_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_LCD,
.is_connected = fimd_display_is_connected,
.get_panel = fimd_get_panel,
- .check_timing = fimd_check_timing,
+ .check_mode = fimd_check_mode,
.power_on = fimd_display_power_on,
};
@@ -183,7 +188,7 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
{
struct fimd_context *ctx = get_fimd_context(subdrv_dev);
- DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+ DRM_DEBUG_KMS("%d\n", mode);
mutex_lock(&ctx->lock);
@@ -221,8 +226,6 @@ static void fimd_apply(struct device *subdrv_dev)
struct fimd_win_data *win_data;
int i;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled && (ovl_ops && ovl_ops->commit))
@@ -239,15 +242,12 @@ static void fimd_commit(struct device *dev)
struct exynos_drm_panel_info *panel = ctx->panel;
struct fb_videomode *timing = &panel->timing;
struct fimd_driver_data *driver_data;
- struct platform_device *pdev = to_platform_device(dev);
u32 val;
- driver_data = drm_fimd_get_driver_data(pdev);
+ driver_data = ctx->driver_data;
if (ctx->suspended)
return;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* setup polarity values from machine code. */
writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
@@ -274,6 +274,11 @@ static void fimd_commit(struct device *dev)
val = ctx->vidcon0;
val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+ if (ctx->driver_data->has_clksel) {
+ val &= ~VIDCON0_CLKSEL_MASK;
+ val |= VIDCON0_CLKSEL_LCD;
+ }
+
if (ctx->clkdiv > 1)
val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
else
@@ -292,8 +297,6 @@ static int fimd_enable_vblank(struct device *dev)
struct fimd_context *ctx = get_fimd_context(dev);
u32 val;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return -EPERM;
@@ -319,8 +322,6 @@ static void fimd_disable_vblank(struct device *dev)
struct fimd_context *ctx = get_fimd_context(dev);
u32 val;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return;
@@ -370,8 +371,6 @@ static void fimd_win_mode_set(struct device *dev,
int win;
unsigned long offset;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!overlay) {
dev_err(dev, "overlay is NULL\n");
return;
@@ -381,7 +380,7 @@ static void fimd_win_mode_set(struct device *dev,
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
- if (win < 0 || win > WINDOWS_NR)
+ if (win < 0 || win >= WINDOWS_NR)
return;
offset = overlay->fb_x * (overlay->bpp >> 3);
@@ -418,8 +417,6 @@ static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
struct fimd_win_data *win_data = &ctx->win_data[win];
unsigned long val;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
val = WINCONx_ENWIN;
switch (win_data->bpp) {
@@ -478,8 +475,6 @@ static void fimd_win_set_colkey(struct device *dev, unsigned int win)
struct fimd_context *ctx = get_fimd_context(dev);
unsigned int keycon0 = 0, keycon1 = 0;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
@@ -489,6 +484,33 @@ static void fimd_win_set_colkey(struct device *dev, unsigned int win)
writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
}
+/**
+ * shadow_protect_win() - disable updating values from shadow registers at vsync
+ *
+ * @win: window to protect registers for
+ * @protect: 1 to protect (disable updates)
+ */
+static void fimd_shadow_protect_win(struct fimd_context *ctx,
+ int win, bool protect)
+{
+ u32 reg, bits, val;
+
+ if (ctx->driver_data->has_shadowcon) {
+ reg = SHADOWCON;
+ bits = SHADOWCON_WINx_PROTECT(win);
+ } else {
+ reg = PRTCON;
+ bits = PRTCON_PROTECT;
+ }
+
+ val = readl(ctx->regs + reg);
+ if (protect)
+ val |= bits;
+ else
+ val &= ~bits;
+ writel(val, ctx->regs + reg);
+}
+
static void fimd_win_commit(struct device *dev, int zpos)
{
struct fimd_context *ctx = get_fimd_context(dev);
@@ -498,21 +520,19 @@ static void fimd_win_commit(struct device *dev, int zpos)
unsigned int last_x;
unsigned int last_y;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
- if (win < 0 || win > WINDOWS_NR)
+ if (win < 0 || win >= WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
/*
- * SHADOWCON register is used for enabling timing.
+ * SHADOWCON/PRTCON register is used for enabling timing.
*
* for example, once only width value of a register is set,
* if the dma is started then fimd hardware could malfunction so
@@ -522,9 +542,7 @@ static void fimd_win_commit(struct device *dev, int zpos)
*/
/* protect windows */
- val = readl(ctx->regs + SHADOWCON);
- val |= SHADOWCON_WINx_PROTECT(win);
- writel(val, ctx->regs + SHADOWCON);
+ fimd_shadow_protect_win(ctx, win, true);
/* buffer start address */
val = (unsigned long)win_data->dma_addr;
@@ -602,10 +620,13 @@ static void fimd_win_commit(struct device *dev, int zpos)
writel(val, ctx->regs + WINCON(win));
/* Enable DMA channel and unprotect windows */
- val = readl(ctx->regs + SHADOWCON);
- val |= SHADOWCON_CHx_ENABLE(win);
- val &= ~SHADOWCON_WINx_PROTECT(win);
- writel(val, ctx->regs + SHADOWCON);
+ fimd_shadow_protect_win(ctx, win, false);
+
+ if (ctx->driver_data->has_shadowcon) {
+ val = readl(ctx->regs + SHADOWCON);
+ val |= SHADOWCON_CHx_ENABLE(win);
+ writel(val, ctx->regs + SHADOWCON);
+ }
win_data->enabled = true;
}
@@ -617,12 +638,10 @@ static void fimd_win_disable(struct device *dev, int zpos)
int win = zpos;
u32 val;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
- if (win < 0 || win > WINDOWS_NR)
+ if (win < 0 || win >= WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
@@ -634,9 +653,7 @@ static void fimd_win_disable(struct device *dev, int zpos)
}
/* protect windows */
- val = readl(ctx->regs + SHADOWCON);
- val |= SHADOWCON_WINx_PROTECT(win);
- writel(val, ctx->regs + SHADOWCON);
+ fimd_shadow_protect_win(ctx, win, true);
/* wincon */
val = readl(ctx->regs + WINCON(win));
@@ -644,10 +661,13 @@ static void fimd_win_disable(struct device *dev, int zpos)
writel(val, ctx->regs + WINCON(win));
/* unprotect windows */
- val = readl(ctx->regs + SHADOWCON);
- val &= ~SHADOWCON_CHx_ENABLE(win);
- val &= ~SHADOWCON_WINx_PROTECT(win);
- writel(val, ctx->regs + SHADOWCON);
+ if (ctx->driver_data->has_shadowcon) {
+ val = readl(ctx->regs + SHADOWCON);
+ val &= ~SHADOWCON_CHx_ENABLE(win);
+ writel(val, ctx->regs + SHADOWCON);
+ }
+
+ fimd_shadow_protect_win(ctx, win, false);
win_data->enabled = false;
}
@@ -697,8 +717,6 @@ out:
static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* enable drm irq mode.
* - with irq_enabled = 1, we can use the vblank feature.
@@ -725,8 +743,6 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(drm_dev))
drm_iommu_detach_device(drm_dev, dev);
@@ -741,8 +757,6 @@ static int fimd_calc_clkdiv(struct fimd_context *ctx,
u32 best_framerate = 0;
u32 framerate;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
retrace = timing->left_margin + timing->hsync_len +
timing->right_margin + timing->xres;
retrace *= timing->upper_margin + timing->vsync_len +
@@ -777,10 +791,6 @@ static int fimd_calc_clkdiv(struct fimd_context *ctx,
static void fimd_clear_win(struct fimd_context *ctx, int win)
{
- u32 val;
-
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
writel(0, ctx->regs + WINCON(win));
writel(0, ctx->regs + VIDOSD_A(win));
writel(0, ctx->regs + VIDOSD_B(win));
@@ -789,15 +799,11 @@ static void fimd_clear_win(struct fimd_context *ctx, int win)
if (win == 1 || win == 2)
writel(0, ctx->regs + VIDOSD_D(win));
- val = readl(ctx->regs + SHADOWCON);
- val &= ~SHADOWCON_WINx_PROTECT(win);
- writel(val, ctx->regs + SHADOWCON);
+ fimd_shadow_protect_win(ctx, win, false);
}
static int fimd_clock(struct fimd_context *ctx, bool enable)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (enable) {
int ret;
@@ -883,8 +889,6 @@ static int fimd_probe(struct platform_device *pdev)
int win;
int ret = -EINVAL;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (dev->of_node) {
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -949,6 +953,7 @@ static int fimd_probe(struct platform_device *pdev)
return ret;
}
+ ctx->driver_data = drm_fimd_get_driver_data(pdev);
ctx->vidcon0 = pdata->vidcon0;
ctx->vidcon1 = pdata->vidcon1;
ctx->default_win = pdata->default_win;
@@ -989,8 +994,6 @@ static int fimd_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct fimd_context *ctx = platform_get_drvdata(pdev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_drm_subdrv_unregister(&ctx->subdrv);
if (ctx->suspended)
@@ -1055,8 +1058,6 @@ static int fimd_runtime_suspend(struct device *dev)
{
struct fimd_context *ctx = get_fimd_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
return fimd_activate(ctx, false);
}
@@ -1064,14 +1065,15 @@ static int fimd_runtime_resume(struct device *dev)
{
struct fimd_context *ctx = get_fimd_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
return fimd_activate(ctx, true);
}
#endif
static struct platform_device_id fimd_driver_ids[] = {
{
+ .name = "s3c64xx-fb",
+ .driver_data = (unsigned long)&s3c64xx_fimd_driver_data,
+ }, {
.name = "exynos4-fb",
.driver_data = (unsigned long)&exynos4_fimd_driver_data,
}, {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index af75434ee4d7..42a5a5466075 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -388,12 +388,9 @@ out:
sg_free_table(g2d_userptr->sgt);
kfree(g2d_userptr->sgt);
- g2d_userptr->sgt = NULL;
- kfree(g2d_userptr->pages);
- g2d_userptr->pages = NULL;
+ drm_free_large(g2d_userptr->pages);
kfree(g2d_userptr);
- g2d_userptr = NULL;
}
static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
@@ -463,11 +460,11 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
npages = (end - start) >> PAGE_SHIFT;
g2d_userptr->npages = npages;
- pages = kzalloc(npages * sizeof(struct page *), GFP_KERNEL);
+ pages = drm_calloc_large(npages, sizeof(struct page *));
if (!pages) {
DRM_ERROR("failed to allocate pages.\n");
- kfree(g2d_userptr);
- return ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
+ goto err_free;
}
vma = find_vma(current->mm, userptr);
@@ -543,7 +540,6 @@ err_sg_free_table:
err_free_sgt:
kfree(sgt);
- sgt = NULL;
err_free_userptr:
exynos_gem_put_pages_to_userptr(g2d_userptr->pages,
@@ -554,10 +550,10 @@ err_put_vma:
exynos_gem_put_vma(g2d_userptr->vma);
err_free_pages:
- kfree(pages);
+ drm_free_large(pages);
+
+err_free:
kfree(g2d_userptr);
- pages = NULL;
- g2d_userptr = NULL;
return ERR_PTR(ret);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index cf4543ffa079..24c22a8c3364 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -132,8 +132,6 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
struct drm_gem_object *obj;
struct exynos_drm_gem_buf *buf;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
obj = &exynos_gem_obj->base;
buf = exynos_gem_obj->buffer;
@@ -227,7 +225,6 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
}
size = roundup_gem_size(size, flags);
- DRM_DEBUG_KMS("%s\n", __FILE__);
ret = check_gem_flags(flags);
if (ret)
@@ -249,13 +246,14 @@ struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
exynos_gem_obj->flags = flags;
ret = exynos_drm_alloc_buf(dev, buf, flags);
- if (ret < 0) {
- drm_gem_object_release(&exynos_gem_obj->base);
- goto err_fini_buf;
- }
+ if (ret < 0)
+ goto err_gem_fini;
return exynos_gem_obj;
+err_gem_fini:
+ drm_gem_object_release(&exynos_gem_obj->base);
+ kfree(exynos_gem_obj);
err_fini_buf:
exynos_drm_fini_buf(dev, buf);
return ERR_PTR(ret);
@@ -268,8 +266,6 @@ int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data,
struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
if (IS_ERR(exynos_gem_obj))
return PTR_ERR(exynos_gem_obj);
@@ -331,8 +327,6 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
{
struct drm_exynos_gem_map_off *args = data;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
args->handle, (unsigned long)args->offset);
@@ -371,8 +365,6 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
unsigned long vm_size;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
vma->vm_private_data = obj;
vma->vm_ops = drm_dev->driver->gem_vm_ops;
@@ -429,9 +421,7 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
{
struct drm_exynos_gem_mmap *args = data;
struct drm_gem_object *obj;
- unsigned int addr;
-
- DRM_DEBUG_KMS("%s\n", __FILE__);
+ unsigned long addr;
if (!(dev->driver->driver_features & DRIVER_GEM)) {
DRM_ERROR("does not support GEM.\n");
@@ -473,14 +463,14 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
drm_gem_object_unreference(obj);
- if (IS_ERR((void *)addr)) {
+ if (IS_ERR_VALUE(addr)) {
/* check filp->f_op, filp->private_data are restored */
if (file_priv->filp->f_op == &exynos_drm_gem_fops) {
file_priv->filp->f_op = fops_get(dev->driver->fops);
file_priv->filp->private_data = file_priv;
}
mutex_unlock(&dev->struct_mutex);
- return PTR_ERR((void *)addr);
+ return (int)addr;
}
mutex_unlock(&dev->struct_mutex);
@@ -643,8 +633,6 @@ void exynos_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
int exynos_drm_gem_init_object(struct drm_gem_object *obj)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
return 0;
}
@@ -653,8 +641,6 @@ void exynos_drm_gem_free_object(struct drm_gem_object *obj)
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_gem_buf *buf;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_gem_obj = to_exynos_gem_obj(obj);
buf = exynos_gem_obj->buffer;
@@ -671,8 +657,6 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv,
struct exynos_drm_gem_obj *exynos_gem_obj;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* alocate memory to be used for framebuffer.
* - this callback would be called by user application
@@ -704,8 +688,6 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
struct drm_gem_object *obj;
int ret = 0;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
mutex_lock(&dev->struct_mutex);
/*
@@ -743,8 +725,6 @@ int exynos_drm_gem_dumb_destroy(struct drm_file *file_priv,
{
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* obj->refcount and obj->handle_count are decreased and
* if both them are 0 then exynos_drm_gem_free_object()
@@ -788,8 +768,6 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
struct drm_gem_object *obj;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* set vm_area_struct. */
ret = drm_gem_mmap(filp, vma);
if (ret < 0) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 762f40d548b7..472e3b25e7f2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -400,8 +400,6 @@ static int gsc_sw_reset(struct gsc_context *ctx)
u32 cfg;
int count = GSC_RESET_TIMEOUT;
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* s/w reset */
cfg = (GSC_SW_RESET_SRESET);
gsc_write(cfg, GSC_SW_RESET);
@@ -441,8 +439,6 @@ static void gsc_set_gscblk_fimd_wb(struct gsc_context *ctx, bool enable)
{
u32 gscblk_cfg;
- DRM_DEBUG_KMS("%s\n", __func__);
-
gscblk_cfg = readl(SYSREG_GSCBLK_CFG1);
if (enable)
@@ -460,7 +456,7 @@ static void gsc_handle_irq(struct gsc_context *ctx, bool enable,
{
u32 cfg;
- DRM_DEBUG_KMS("%s:enable[%d]overflow[%d]level[%d]\n", __func__,
+ DRM_DEBUG_KMS("enable[%d]overflow[%d]level[%d]\n",
enable, overflow, done);
cfg = gsc_read(GSC_IRQ);
@@ -491,7 +487,7 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+ DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
cfg = gsc_read(GSC_IN_CON);
cfg &= ~(GSC_IN_RGB_TYPE_MASK | GSC_IN_YUV422_1P_ORDER_MASK |
@@ -567,8 +563,7 @@ static int gsc_src_set_transf(struct device *dev,
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
- degree, flip);
+ DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
cfg = gsc_read(GSC_IN_CON);
cfg &= ~GSC_IN_ROT_MASK;
@@ -616,8 +611,8 @@ static int gsc_src_set_size(struct device *dev, int swap,
struct gsc_scaler *sc = &ctx->sc;
u32 cfg;
- DRM_DEBUG_KMS("%s:swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
- __func__, swap, pos->x, pos->y, pos->w, pos->h);
+ DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
+ swap, pos->x, pos->y, pos->w, pos->h);
if (swap) {
img_pos.w = pos->h;
@@ -634,8 +629,7 @@ static int gsc_src_set_size(struct device *dev, int swap,
GSC_CROPPED_HEIGHT(img_pos.h));
gsc_write(cfg, GSC_CROPPED_SIZE);
- DRM_DEBUG_KMS("%s:hsize[%d]vsize[%d]\n",
- __func__, sz->hsize, sz->vsize);
+ DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);
/* original size */
cfg = gsc_read(GSC_SRCIMG_SIZE);
@@ -650,8 +644,7 @@ static int gsc_src_set_size(struct device *dev, int swap,
cfg = gsc_read(GSC_IN_CON);
cfg &= ~GSC_IN_RGB_TYPE_MASK;
- DRM_DEBUG_KMS("%s:width[%d]range[%d]\n",
- __func__, pos->w, sc->range);
+ DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);
if (pos->w >= GSC_WIDTH_ITU_709)
if (sc->range)
@@ -677,8 +670,7 @@ static int gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
u32 cfg;
u32 mask = 0x00000001 << buf_id;
- DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
- buf_id, buf_type);
+ DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
/* mask register set */
cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
@@ -721,7 +713,7 @@ static int gsc_src_set_addr(struct device *dev,
property = &c_node->property;
- DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+ DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
property->prop_id, buf_id, buf_type);
if (buf_id > GSC_MAX_SRC) {
@@ -765,7 +757,7 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:fmt[0x%x]\n", __func__, fmt);
+ DRM_DEBUG_KMS("fmt[0x%x]\n", fmt);
cfg = gsc_read(GSC_OUT_CON);
cfg &= ~(GSC_OUT_RGB_TYPE_MASK | GSC_OUT_YUV422_1P_ORDER_MASK |
@@ -838,8 +830,7 @@ static int gsc_dst_set_transf(struct device *dev,
struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;
u32 cfg;
- DRM_DEBUG_KMS("%s:degree[%d]flip[0x%x]\n", __func__,
- degree, flip);
+ DRM_DEBUG_KMS("degree[%d]flip[0x%x]\n", degree, flip);
cfg = gsc_read(GSC_IN_CON);
cfg &= ~GSC_IN_ROT_MASK;
@@ -881,7 +872,7 @@ static int gsc_dst_set_transf(struct device *dev,
static int gsc_get_ratio_shift(u32 src, u32 dst, u32 *ratio)
{
- DRM_DEBUG_KMS("%s:src[%d]dst[%d]\n", __func__, src, dst);
+ DRM_DEBUG_KMS("src[%d]dst[%d]\n", src, dst);
if (src >= dst * 8) {
DRM_ERROR("failed to make ratio and shift.\n");
@@ -944,20 +935,19 @@ static int gsc_set_prescaler(struct gsc_context *ctx, struct gsc_scaler *sc,
return ret;
}
- DRM_DEBUG_KMS("%s:pre_hratio[%d]pre_vratio[%d]\n",
- __func__, sc->pre_hratio, sc->pre_vratio);
+ DRM_DEBUG_KMS("pre_hratio[%d]pre_vratio[%d]\n",
+ sc->pre_hratio, sc->pre_vratio);
sc->main_hratio = (src_w << 16) / dst_w;
sc->main_vratio = (src_h << 16) / dst_h;
- DRM_DEBUG_KMS("%s:main_hratio[%ld]main_vratio[%ld]\n",
- __func__, sc->main_hratio, sc->main_vratio);
+ DRM_DEBUG_KMS("main_hratio[%ld]main_vratio[%ld]\n",
+ sc->main_hratio, sc->main_vratio);
gsc_get_prescaler_shfactor(sc->pre_hratio, sc->pre_vratio,
&sc->pre_shfactor);
- DRM_DEBUG_KMS("%s:pre_shfactor[%d]\n", __func__,
- sc->pre_shfactor);
+ DRM_DEBUG_KMS("pre_shfactor[%d]\n", sc->pre_shfactor);
cfg = (GSC_PRESC_SHFACTOR(sc->pre_shfactor) |
GSC_PRESC_H_RATIO(sc->pre_hratio) |
@@ -1023,8 +1013,8 @@ static void gsc_set_scaler(struct gsc_context *ctx, struct gsc_scaler *sc)
{
u32 cfg;
- DRM_DEBUG_KMS("%s:main_hratio[%ld]main_vratio[%ld]\n",
- __func__, sc->main_hratio, sc->main_vratio);
+ DRM_DEBUG_KMS("main_hratio[%ld]main_vratio[%ld]\n",
+ sc->main_hratio, sc->main_vratio);
gsc_set_h_coef(ctx, sc->main_hratio);
cfg = GSC_MAIN_H_RATIO_VALUE(sc->main_hratio);
@@ -1043,8 +1033,8 @@ static int gsc_dst_set_size(struct device *dev, int swap,
struct gsc_scaler *sc = &ctx->sc;
u32 cfg;
- DRM_DEBUG_KMS("%s:swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
- __func__, swap, pos->x, pos->y, pos->w, pos->h);
+ DRM_DEBUG_KMS("swap[%d]x[%d]y[%d]w[%d]h[%d]\n",
+ swap, pos->x, pos->y, pos->w, pos->h);
if (swap) {
img_pos.w = pos->h;
@@ -1060,8 +1050,7 @@ static int gsc_dst_set_size(struct device *dev, int swap,
cfg = (GSC_SCALED_WIDTH(img_pos.w) | GSC_SCALED_HEIGHT(img_pos.h));
gsc_write(cfg, GSC_SCALED_SIZE);
- DRM_DEBUG_KMS("%s:hsize[%d]vsize[%d]\n",
- __func__, sz->hsize, sz->vsize);
+ DRM_DEBUG_KMS("hsize[%d]vsize[%d]\n", sz->hsize, sz->vsize);
/* original size */
cfg = gsc_read(GSC_DSTIMG_SIZE);
@@ -1074,8 +1063,7 @@ static int gsc_dst_set_size(struct device *dev, int swap,
cfg = gsc_read(GSC_OUT_CON);
cfg &= ~GSC_OUT_RGB_TYPE_MASK;
- DRM_DEBUG_KMS("%s:width[%d]range[%d]\n",
- __func__, pos->w, sc->range);
+ DRM_DEBUG_KMS("width[%d]range[%d]\n", pos->w, sc->range);
if (pos->w >= GSC_WIDTH_ITU_709)
if (sc->range)
@@ -1104,7 +1092,7 @@ static int gsc_dst_get_buf_seq(struct gsc_context *ctx)
if (cfg & (mask << i))
buf_num--;
- DRM_DEBUG_KMS("%s:buf_num[%d]\n", __func__, buf_num);
+ DRM_DEBUG_KMS("buf_num[%d]\n", buf_num);
return buf_num;
}
@@ -1118,8 +1106,7 @@ static int gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id,
u32 mask = 0x00000001 << buf_id;
int ret = 0;
- DRM_DEBUG_KMS("%s:buf_id[%d]buf_type[%d]\n", __func__,
- buf_id, buf_type);
+ DRM_DEBUG_KMS("buf_id[%d]buf_type[%d]\n", buf_id, buf_type);
mutex_lock(&ctx->lock);
@@ -1177,7 +1164,7 @@ static int gsc_dst_set_addr(struct device *dev,
property = &c_node->property;
- DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]buf_type[%d]\n", __func__,
+ DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]buf_type[%d]\n",
property->prop_id, buf_id, buf_type);
if (buf_id > GSC_MAX_DST) {
@@ -1217,7 +1204,7 @@ static struct exynos_drm_ipp_ops gsc_dst_ops = {
static int gsc_clk_ctrl(struct gsc_context *ctx, bool enable)
{
- DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+ DRM_DEBUG_KMS("enable[%d]\n", enable);
if (enable) {
clk_enable(ctx->gsc_clk);
@@ -1236,7 +1223,7 @@ static int gsc_get_src_buf_index(struct gsc_context *ctx)
u32 buf_id = GSC_MAX_SRC;
int ret;
- DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
cfg = gsc_read(GSC_IN_BASE_ADDR_Y_MASK);
curr_index = GSC_IN_CURR_GET_INDEX(cfg);
@@ -1259,7 +1246,7 @@ static int gsc_get_src_buf_index(struct gsc_context *ctx)
return ret;
}
- DRM_DEBUG_KMS("%s:cfg[0x%x]curr_index[%d]buf_id[%d]\n", __func__, cfg,
+ DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
curr_index, buf_id);
return buf_id;
@@ -1271,7 +1258,7 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx)
u32 buf_id = GSC_MAX_DST;
int ret;
- DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
cfg = gsc_read(GSC_OUT_BASE_ADDR_Y_MASK);
curr_index = GSC_OUT_CURR_GET_INDEX(cfg);
@@ -1294,7 +1281,7 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx)
return ret;
}
- DRM_DEBUG_KMS("%s:cfg[0x%x]curr_index[%d]buf_id[%d]\n", __func__, cfg,
+ DRM_DEBUG_KMS("cfg[0x%x]curr_index[%d]buf_id[%d]\n", cfg,
curr_index, buf_id);
return buf_id;
@@ -1310,7 +1297,7 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id)
u32 status;
int buf_id[EXYNOS_DRM_OPS_MAX];
- DRM_DEBUG_KMS("%s:gsc id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("gsc id[%d]\n", ctx->id);
status = gsc_read(GSC_IRQ);
if (status & GSC_IRQ_STATUS_OR_IRQ) {
@@ -1331,7 +1318,7 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id)
if (buf_id[EXYNOS_DRM_OPS_DST] < 0)
return IRQ_HANDLED;
- DRM_DEBUG_KMS("%s:buf_id_src[%d]buf_id_dst[%d]\n", __func__,
+ DRM_DEBUG_KMS("buf_id_src[%d]buf_id_dst[%d]\n",
buf_id[EXYNOS_DRM_OPS_SRC], buf_id[EXYNOS_DRM_OPS_DST]);
event_work->ippdrv = ippdrv;
@@ -1350,8 +1337,6 @@ static int gsc_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
{
struct drm_exynos_ipp_prop_list *prop_list;
- DRM_DEBUG_KMS("%s\n", __func__);
-
prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
if (!prop_list) {
DRM_ERROR("failed to alloc property list.\n");
@@ -1394,7 +1379,7 @@ static inline bool gsc_check_drm_flip(enum drm_exynos_flip flip)
case EXYNOS_DRM_FLIP_BOTH:
return true;
default:
- DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+ DRM_DEBUG_KMS("invalid flip\n");
return false;
}
}
@@ -1411,8 +1396,6 @@ static int gsc_ippdrv_check_property(struct device *dev,
bool swap;
int i;
- DRM_DEBUG_KMS("%s\n", __func__);
-
for_each_ipp_ops(i) {
if ((i == EXYNOS_DRM_OPS_SRC) &&
(property->cmd == IPP_CMD_WB))
@@ -1521,8 +1504,6 @@ static int gsc_ippdrv_reset(struct device *dev)
struct gsc_scaler *sc = &ctx->sc;
int ret;
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* reset h/w block */
ret = gsc_sw_reset(ctx);
if (ret < 0) {
@@ -1549,7 +1530,7 @@ static int gsc_ippdrv_start(struct device *dev, enum drm_exynos_ipp_cmd cmd)
u32 cfg;
int ret, i;
- DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+ DRM_DEBUG_KMS("cmd[%d]\n", cmd);
if (!c_node) {
DRM_ERROR("failed to get c_node.\n");
@@ -1643,7 +1624,7 @@ static void gsc_ippdrv_stop(struct device *dev, enum drm_exynos_ipp_cmd cmd)
struct drm_exynos_ipp_set_wb set_wb = {0, 0};
u32 cfg;
- DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, cmd);
+ DRM_DEBUG_KMS("cmd[%d]\n", cmd);
switch (cmd) {
case IPP_CMD_M2M:
@@ -1728,8 +1709,7 @@ static int gsc_probe(struct platform_device *pdev)
return ret;
}
- DRM_DEBUG_KMS("%s:id[%d]ippdrv[0x%x]\n", __func__, ctx->id,
- (int)ippdrv);
+ DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
mutex_init(&ctx->lock);
platform_set_drvdata(pdev, ctx);
@@ -1772,7 +1752,7 @@ static int gsc_suspend(struct device *dev)
{
struct gsc_context *ctx = get_gsc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
if (pm_runtime_suspended(dev))
return 0;
@@ -1784,7 +1764,7 @@ static int gsc_resume(struct device *dev)
{
struct gsc_context *ctx = get_gsc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
if (!pm_runtime_suspended(dev))
return gsc_clk_ctrl(ctx, true);
@@ -1798,7 +1778,7 @@ static int gsc_runtime_suspend(struct device *dev)
{
struct gsc_context *ctx = get_gsc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
return gsc_clk_ctrl(ctx, false);
}
@@ -1807,7 +1787,7 @@ static int gsc_runtime_resume(struct device *dev)
{
struct gsc_context *ctx = get_gsc_context(dev);
- DRM_DEBUG_KMS("%s:id[%d]\n", __FILE__, ctx->id);
+ DRM_DEBUG_KMS("id[%d]\n", ctx->id);
return gsc_clk_ctrl(ctx, true);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 437fb947e46d..aaa550d622f0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -88,16 +88,12 @@ void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ops)
hdmi_ops = ops;
}
void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ops)
mixer_ops = ops;
}
@@ -106,8 +102,6 @@ static bool drm_hdmi_is_connected(struct device *dev)
{
struct drm_hdmi_context *ctx = to_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (hdmi_ops && hdmi_ops->is_connected)
return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
@@ -119,34 +113,31 @@ static struct edid *drm_hdmi_get_edid(struct device *dev,
{
struct drm_hdmi_context *ctx = to_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (hdmi_ops && hdmi_ops->get_edid)
return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
return NULL;
}
-static int drm_hdmi_check_timing(struct device *dev, void *timing)
+static int drm_hdmi_check_mode(struct device *dev,
+ struct drm_display_mode *mode)
{
struct drm_hdmi_context *ctx = to_context(dev);
int ret = 0;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* Both, mixer and hdmi should be able to handle the requested mode.
* If any of the two fails, return mode as BAD.
*/
- if (mixer_ops && mixer_ops->check_timing)
- ret = mixer_ops->check_timing(ctx->mixer_ctx->ctx, timing);
+ if (mixer_ops && mixer_ops->check_mode)
+ ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode);
if (ret)
return ret;
- if (hdmi_ops && hdmi_ops->check_timing)
- return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
+ if (hdmi_ops && hdmi_ops->check_mode)
+ return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
return 0;
}
@@ -155,8 +146,6 @@ static int drm_hdmi_power_on(struct device *dev, int mode)
{
struct drm_hdmi_context *ctx = to_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (hdmi_ops && hdmi_ops->power_on)
return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
@@ -167,7 +156,7 @@ static struct exynos_drm_display_ops drm_hdmi_display_ops = {
.type = EXYNOS_DISPLAY_TYPE_HDMI,
.is_connected = drm_hdmi_is_connected,
.get_edid = drm_hdmi_get_edid,
- .check_timing = drm_hdmi_check_timing,
+ .check_mode = drm_hdmi_check_mode,
.power_on = drm_hdmi_power_on,
};
@@ -177,8 +166,6 @@ static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
struct exynos_drm_manager *manager = subdrv->manager;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (mixer_ops && mixer_ops->enable_vblank)
return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
manager->pipe);
@@ -190,8 +177,6 @@ static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (mixer_ops && mixer_ops->disable_vblank)
return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
}
@@ -200,8 +185,6 @@ static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (mixer_ops && mixer_ops->wait_for_vblank)
mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
}
@@ -214,11 +197,9 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
struct drm_display_mode *m;
int mode_ok;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
drm_mode_set_crtcinfo(adjusted_mode, 0);
- mode_ok = drm_hdmi_check_timing(subdrv_dev, adjusted_mode);
+ mode_ok = drm_hdmi_check_mode(subdrv_dev, adjusted_mode);
/* just return if user desired mode exists. */
if (mode_ok == 0)
@@ -229,7 +210,7 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
* to adjusted_mode.
*/
list_for_each_entry(m, &connector->modes, head) {
- mode_ok = drm_hdmi_check_timing(subdrv_dev, m);
+ mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
if (mode_ok == 0) {
struct drm_mode_object base;
@@ -256,8 +237,6 @@ static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (hdmi_ops && hdmi_ops->mode_set)
hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
}
@@ -267,8 +246,6 @@ static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (hdmi_ops && hdmi_ops->get_max_resol)
hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
}
@@ -277,8 +254,6 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (hdmi_ops && hdmi_ops->commit)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
@@ -287,8 +262,6 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (mixer_ops && mixer_ops->dpms)
mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
@@ -301,8 +274,6 @@ static void drm_hdmi_apply(struct device *subdrv_dev)
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int i;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
for (i = 0; i < MIXER_WIN_NR; i++) {
if (!ctx->enabled[i])
continue;
@@ -331,8 +302,6 @@ static void drm_mixer_mode_set(struct device *subdrv_dev,
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (mixer_ops && mixer_ops->win_mode_set)
mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
}
@@ -342,9 +311,7 @@ static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (win < 0 || win > MIXER_WIN_NR) {
+ if (win < 0 || win >= MIXER_WIN_NR) {
DRM_ERROR("mixer window[%d] is wrong\n", win);
return;
}
@@ -360,9 +327,7 @@ static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (win < 0 || win > MIXER_WIN_NR) {
+ if (win < 0 || win >= MIXER_WIN_NR) {
DRM_ERROR("mixer window[%d] is wrong\n", win);
return;
}
@@ -392,8 +357,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
struct drm_hdmi_context *ctx;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!hdmi_ctx) {
DRM_ERROR("hdmi context not initialized.\n");
return -EFAULT;
@@ -440,8 +403,6 @@ static int exynos_drm_hdmi_probe(struct platform_device *pdev)
struct exynos_drm_subdrv *subdrv;
struct drm_hdmi_context *ctx;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
DRM_LOG_KMS("failed to alloc common hdmi context.\n");
@@ -466,8 +427,6 @@ static int exynos_drm_hdmi_remove(struct platform_device *pdev)
{
struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_drm_subdrv_unregister(&ctx->subdrv);
return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 6b709440df4c..724cab181976 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -32,11 +32,11 @@ struct exynos_hdmi_ops {
bool (*is_connected)(void *ctx);
struct edid *(*get_edid)(void *ctx,
struct drm_connector *connector);
- int (*check_timing)(void *ctx, struct fb_videomode *timing);
+ int (*check_mode)(void *ctx, struct drm_display_mode *mode);
int (*power_on)(void *ctx, int mode);
/* manager */
- void (*mode_set)(void *ctx, void *mode);
+ void (*mode_set)(void *ctx, struct drm_display_mode *mode);
void (*get_max_resol)(void *ctx, unsigned int *width,
unsigned int *height);
void (*commit)(void *ctx);
@@ -57,7 +57,7 @@ struct exynos_mixer_ops {
void (*win_disable)(void *ctx, int zpos);
/* display */
- int (*check_timing)(void *ctx, struct fb_videomode *timing);
+ int (*check_mode)(void *ctx, struct drm_display_mode *mode);
};
void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index be1e88463466..b1ef8e7ff9c9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -131,8 +131,6 @@ void exynos_platform_device_ipp_unregister(void)
int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
{
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!ippdrv)
return -EINVAL;
@@ -145,8 +143,6 @@ int exynos_drm_ippdrv_register(struct exynos_drm_ippdrv *ippdrv)
int exynos_drm_ippdrv_unregister(struct exynos_drm_ippdrv *ippdrv)
{
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!ippdrv)
return -EINVAL;
@@ -162,8 +158,6 @@ static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj,
{
int ret;
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* do the allocation under our mutexlock */
mutex_lock(lock);
ret = idr_alloc(id_idr, obj, 1, 0, GFP_KERNEL);
@@ -179,7 +173,7 @@ static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id)
{
void *obj;
- DRM_DEBUG_KMS("%s:id[%d]\n", __func__, id);
+ DRM_DEBUG_KMS("id[%d]\n", id);
mutex_lock(lock);
@@ -216,7 +210,7 @@ static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx,
struct exynos_drm_ippdrv *ippdrv;
u32 ipp_id = property->ipp_id;
- DRM_DEBUG_KMS("%s:ipp_id[%d]\n", __func__, ipp_id);
+ DRM_DEBUG_KMS("ipp_id[%d]\n", ipp_id);
if (ipp_id) {
/* find ipp driver using idr */
@@ -257,14 +251,13 @@ static struct exynos_drm_ippdrv *ipp_find_driver(struct ipp_context *ctx,
*/
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
if (ipp_check_dedicated(ippdrv, property->cmd)) {
- DRM_DEBUG_KMS("%s:used device.\n", __func__);
+ DRM_DEBUG_KMS("used device.\n");
continue;
}
if (ippdrv->check_property &&
ippdrv->check_property(ippdrv->dev, property)) {
- DRM_DEBUG_KMS("%s:not support property.\n",
- __func__);
+ DRM_DEBUG_KMS("not support property.\n");
continue;
}
@@ -283,10 +276,10 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
struct drm_exynos_ipp_cmd_node *c_node;
int count = 0;
- DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, prop_id);
+ DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
if (list_empty(&exynos_drm_ippdrv_list)) {
- DRM_DEBUG_KMS("%s:ippdrv_list is empty.\n", __func__);
+ DRM_DEBUG_KMS("ippdrv_list is empty.\n");
return ERR_PTR(-ENODEV);
}
@@ -296,8 +289,7 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
* e.g PAUSE state, queue buf, command contro.
*/
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
- DRM_DEBUG_KMS("%s:count[%d]ippdrv[0x%x]\n", __func__,
- count++, (int)ippdrv);
+ DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv);
if (!list_empty(&ippdrv->cmd_list)) {
list_for_each_entry(c_node, &ippdrv->cmd_list, list)
@@ -320,8 +312,6 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
struct exynos_drm_ippdrv *ippdrv;
int count = 0;
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!ctx) {
DRM_ERROR("invalid context.\n");
return -EINVAL;
@@ -332,7 +322,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
return -EINVAL;
}
- DRM_DEBUG_KMS("%s:ipp_id[%d]\n", __func__, prop_list->ipp_id);
+ DRM_DEBUG_KMS("ipp_id[%d]\n", prop_list->ipp_id);
if (!prop_list->ipp_id) {
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list)
@@ -371,11 +361,11 @@ static void ipp_print_property(struct drm_exynos_ipp_property *property,
struct drm_exynos_pos *pos = &config->pos;
struct drm_exynos_sz *sz = &config->sz;
- DRM_DEBUG_KMS("%s:prop_id[%d]ops[%s]fmt[0x%x]\n",
- __func__, property->prop_id, idx ? "dst" : "src", config->fmt);
+ DRM_DEBUG_KMS("prop_id[%d]ops[%s]fmt[0x%x]\n",
+ property->prop_id, idx ? "dst" : "src", config->fmt);
- DRM_DEBUG_KMS("%s:pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n",
- __func__, pos->x, pos->y, pos->w, pos->h,
+ DRM_DEBUG_KMS("pos[%d %d %d %d]sz[%d %d]f[%d]r[%d]\n",
+ pos->x, pos->y, pos->w, pos->h,
sz->hsize, sz->vsize, config->flip, config->degree);
}
@@ -385,7 +375,7 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)
struct drm_exynos_ipp_cmd_node *c_node;
u32 prop_id = property->prop_id;
- DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, prop_id);
+ DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
ippdrv = ipp_find_drv_by_handle(prop_id);
if (IS_ERR(ippdrv)) {
@@ -401,8 +391,8 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)
list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
if ((c_node->property.prop_id == prop_id) &&
(c_node->state == IPP_STATE_STOP)) {
- DRM_DEBUG_KMS("%s:found cmd[%d]ippdrv[0x%x]\n",
- __func__, property->cmd, (int)ippdrv);
+ DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n",
+ property->cmd, (int)ippdrv);
c_node->property = *property;
return 0;
@@ -418,8 +408,6 @@ static struct drm_exynos_ipp_cmd_work *ipp_create_cmd_work(void)
{
struct drm_exynos_ipp_cmd_work *cmd_work;
- DRM_DEBUG_KMS("%s\n", __func__);
-
cmd_work = kzalloc(sizeof(*cmd_work), GFP_KERNEL);
if (!cmd_work) {
DRM_ERROR("failed to alloc cmd_work.\n");
@@ -435,8 +423,6 @@ static struct drm_exynos_ipp_event_work *ipp_create_event_work(void)
{
struct drm_exynos_ipp_event_work *event_work;
- DRM_DEBUG_KMS("%s\n", __func__);
-
event_work = kzalloc(sizeof(*event_work), GFP_KERNEL);
if (!event_work) {
DRM_ERROR("failed to alloc event_work.\n");
@@ -460,8 +446,6 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
struct drm_exynos_ipp_cmd_node *c_node;
int ret, i;
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!ctx) {
DRM_ERROR("invalid context.\n");
return -EINVAL;
@@ -486,7 +470,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
* instead of allocation.
*/
if (property->prop_id) {
- DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+ DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
return ipp_find_and_set_property(property);
}
@@ -512,8 +496,8 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
goto err_clear;
}
- DRM_DEBUG_KMS("%s:created prop_id[%d]cmd[%d]ippdrv[0x%x]\n",
- __func__, property->prop_id, property->cmd, (int)ippdrv);
+ DRM_DEBUG_KMS("created prop_id[%d]cmd[%d]ippdrv[0x%x]\n",
+ property->prop_id, property->cmd, (int)ippdrv);
/* stored property information and ippdrv in private data */
c_node->priv = priv;
@@ -569,8 +553,6 @@ err_clear:
static void ipp_clean_cmd_node(struct drm_exynos_ipp_cmd_node *c_node)
{
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* delete list */
list_del(&c_node->list);
@@ -593,8 +575,6 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
struct list_head *head;
int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, };
- DRM_DEBUG_KMS("%s\n", __func__);
-
mutex_lock(&c_node->mem_lock);
for_each_ipp_ops(i) {
@@ -602,20 +582,19 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
head = &c_node->mem_list[i];
if (list_empty(head)) {
- DRM_DEBUG_KMS("%s:%s memory empty.\n", __func__,
- i ? "dst" : "src");
+ DRM_DEBUG_KMS("%s memory empty.\n", i ? "dst" : "src");
continue;
}
/* find memory node entry */
list_for_each_entry(m_node, head, list) {
- DRM_DEBUG_KMS("%s:%s,count[%d]m_node[0x%x]\n", __func__,
+ DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n",
i ? "dst" : "src", count[i], (int)m_node);
count[i]++;
}
}
- DRM_DEBUG_KMS("%s:min[%d]max[%d]\n", __func__,
+ DRM_DEBUG_KMS("min[%d]max[%d]\n",
min(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST]),
max(count[EXYNOS_DRM_OPS_SRC], count[EXYNOS_DRM_OPS_DST]));
@@ -644,15 +623,14 @@ static struct drm_exynos_ipp_mem_node
struct list_head *head;
int count = 0;
- DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__, qbuf->buf_id);
+ DRM_DEBUG_KMS("buf_id[%d]\n", qbuf->buf_id);
/* source/destination memory list */
head = &c_node->mem_list[qbuf->ops_id];
/* find memory node from memory list */
list_for_each_entry(m_node, head, list) {
- DRM_DEBUG_KMS("%s:count[%d]m_node[0x%x]\n",
- __func__, count++, (int)m_node);
+ DRM_DEBUG_KMS("count[%d]m_node[0x%x]\n", count++, (int)m_node);
/* compare buffer id */
if (m_node->buf_id == qbuf->buf_id)
@@ -669,7 +647,7 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
struct exynos_drm_ipp_ops *ops = NULL;
int ret = 0;
- DRM_DEBUG_KMS("%s:node[0x%x]\n", __func__, (int)m_node);
+ DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
if (!m_node) {
DRM_ERROR("invalid queue node.\n");
@@ -678,7 +656,7 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
mutex_lock(&c_node->mem_lock);
- DRM_DEBUG_KMS("%s:ops_id[%d]\n", __func__, m_node->ops_id);
+ DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
/* get operations callback */
ops = ippdrv->ops[m_node->ops_id];
@@ -714,8 +692,6 @@ static struct drm_exynos_ipp_mem_node
void *addr;
int i;
- DRM_DEBUG_KMS("%s\n", __func__);
-
mutex_lock(&c_node->mem_lock);
m_node = kzalloc(sizeof(*m_node), GFP_KERNEL);
@@ -732,14 +708,11 @@ static struct drm_exynos_ipp_mem_node
m_node->prop_id = qbuf->prop_id;
m_node->buf_id = qbuf->buf_id;
- DRM_DEBUG_KMS("%s:m_node[0x%x]ops_id[%d]\n", __func__,
- (int)m_node, qbuf->ops_id);
- DRM_DEBUG_KMS("%s:prop_id[%d]buf_id[%d]\n", __func__,
- qbuf->prop_id, m_node->buf_id);
+ DRM_DEBUG_KMS("m_node[0x%x]ops_id[%d]\n", (int)m_node, qbuf->ops_id);
+ DRM_DEBUG_KMS("prop_id[%d]buf_id[%d]\n", qbuf->prop_id, m_node->buf_id);
for_each_ipp_planar(i) {
- DRM_DEBUG_KMS("%s:i[%d]handle[0x%x]\n", __func__,
- i, qbuf->handle[i]);
+ DRM_DEBUG_KMS("i[%d]handle[0x%x]\n", i, qbuf->handle[i]);
/* get dma address by handle */
if (qbuf->handle[i]) {
@@ -752,9 +725,8 @@ static struct drm_exynos_ipp_mem_node
buf_info.handles[i] = qbuf->handle[i];
buf_info.base[i] = *(dma_addr_t *) addr;
- DRM_DEBUG_KMS("%s:i[%d]base[0x%x]hd[0x%x]\n",
- __func__, i, buf_info.base[i],
- (int)buf_info.handles[i]);
+ DRM_DEBUG_KMS("i[%d]base[0x%x]hd[0x%x]\n",
+ i, buf_info.base[i], (int)buf_info.handles[i]);
}
}
@@ -778,7 +750,7 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,
{
int i;
- DRM_DEBUG_KMS("%s:node[0x%x]\n", __func__, (int)m_node);
+ DRM_DEBUG_KMS("node[0x%x]\n", (int)m_node);
if (!m_node) {
DRM_ERROR("invalid dequeue node.\n");
@@ -792,7 +764,7 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,
mutex_lock(&c_node->mem_lock);
- DRM_DEBUG_KMS("%s:ops_id[%d]\n", __func__, m_node->ops_id);
+ DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
/* put gem buffer */
for_each_ipp_planar(i) {
@@ -824,8 +796,7 @@ static int ipp_get_event(struct drm_device *drm_dev,
struct drm_exynos_ipp_send_event *e;
unsigned long flags;
- DRM_DEBUG_KMS("%s:ops_id[%d]buf_id[%d]\n", __func__,
- qbuf->ops_id, qbuf->buf_id);
+ DRM_DEBUG_KMS("ops_id[%d]buf_id[%d]\n", qbuf->ops_id, qbuf->buf_id);
e = kzalloc(sizeof(*e), GFP_KERNEL);
@@ -857,16 +828,13 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
struct drm_exynos_ipp_send_event *e, *te;
int count = 0;
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (list_empty(&c_node->event_list)) {
- DRM_DEBUG_KMS("%s:event_list is empty.\n", __func__);
+ DRM_DEBUG_KMS("event_list is empty.\n");
return;
}
list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {
- DRM_DEBUG_KMS("%s:count[%d]e[0x%x]\n",
- __func__, count++, (int)e);
+ DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
/*
* quf == NULL condition means all event deletion.
@@ -912,8 +880,6 @@ static int ipp_queue_buf_with_run(struct device *dev,
struct exynos_drm_ipp_ops *ops;
int ret;
- DRM_DEBUG_KMS("%s\n", __func__);
-
ippdrv = ipp_find_drv_by_handle(qbuf->prop_id);
if (IS_ERR(ippdrv)) {
DRM_ERROR("failed to get ipp driver.\n");
@@ -929,12 +895,12 @@ static int ipp_queue_buf_with_run(struct device *dev,
property = &c_node->property;
if (c_node->state != IPP_STATE_START) {
- DRM_DEBUG_KMS("%s:bypass for invalid state.\n" , __func__);
+ DRM_DEBUG_KMS("bypass for invalid state.\n");
return 0;
}
if (!ipp_check_mem_list(c_node)) {
- DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
+ DRM_DEBUG_KMS("empty memory.\n");
return 0;
}
@@ -964,8 +930,6 @@ static void ipp_clean_queue_buf(struct drm_device *drm_dev,
{
struct drm_exynos_ipp_mem_node *m_node, *tm_node;
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!list_empty(&c_node->mem_list[qbuf->ops_id])) {
/* delete list */
list_for_each_entry_safe(m_node, tm_node,
@@ -989,8 +953,6 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
struct drm_exynos_ipp_mem_node *m_node;
int ret;
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!qbuf) {
DRM_ERROR("invalid buf parameter.\n");
return -EINVAL;
@@ -1001,8 +963,8 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
return -EINVAL;
}
- DRM_DEBUG_KMS("%s:prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n",
- __func__, qbuf->prop_id, qbuf->ops_id ? "dst" : "src",
+ DRM_DEBUG_KMS("prop_id[%d]ops_id[%s]buf_id[%d]buf_type[%d]\n",
+ qbuf->prop_id, qbuf->ops_id ? "dst" : "src",
qbuf->buf_id, qbuf->buf_type);
/* find command node */
@@ -1075,8 +1037,6 @@ err_clean_node:
static bool exynos_drm_ipp_check_valid(struct device *dev,
enum drm_exynos_ipp_ctrl ctrl, enum drm_exynos_ipp_state state)
{
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (ctrl != IPP_CTRL_PLAY) {
if (pm_runtime_suspended(dev)) {
DRM_ERROR("pm:runtime_suspended.\n");
@@ -1104,7 +1064,6 @@ static bool exynos_drm_ipp_check_valid(struct device *dev,
default:
DRM_ERROR("invalid state.\n");
goto err_status;
- break;
}
return true;
@@ -1126,8 +1085,6 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
struct drm_exynos_ipp_cmd_work *cmd_work;
struct drm_exynos_ipp_cmd_node *c_node;
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!ctx) {
DRM_ERROR("invalid context.\n");
return -EINVAL;
@@ -1138,7 +1095,7 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
return -EINVAL;
}
- DRM_DEBUG_KMS("%s:ctrl[%d]prop_id[%d]\n", __func__,
+ DRM_DEBUG_KMS("ctrl[%d]prop_id[%d]\n",
cmd_ctrl->ctrl, cmd_ctrl->prop_id);
ippdrv = ipp_find_drv_by_handle(cmd_ctrl->prop_id);
@@ -1213,7 +1170,7 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
return -EINVAL;
}
- DRM_DEBUG_KMS("%s:done ctrl[%d]prop_id[%d]\n", __func__,
+ DRM_DEBUG_KMS("done ctrl[%d]prop_id[%d]\n",
cmd_ctrl->ctrl, cmd_ctrl->prop_id);
return 0;
@@ -1249,7 +1206,7 @@ static int ipp_set_property(struct exynos_drm_ippdrv *ippdrv,
return -EINVAL;
}
- DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+ DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
/* reset h/w block */
if (ippdrv->reset &&
@@ -1310,13 +1267,13 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
struct list_head *head;
int ret, i;
- DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+ DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
/* store command info in ippdrv */
ippdrv->c_node = c_node;
if (!ipp_check_mem_list(c_node)) {
- DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
+ DRM_DEBUG_KMS("empty memory.\n");
return -ENOMEM;
}
@@ -1343,8 +1300,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
return ret;
}
- DRM_DEBUG_KMS("%s:m_node[0x%x]\n",
- __func__, (int)m_node);
+ DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node);
ret = ipp_set_mem_node(ippdrv, c_node, m_node);
if (ret) {
@@ -1382,7 +1338,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
return -EINVAL;
}
- DRM_DEBUG_KMS("%s:cmd[%d]\n", __func__, property->cmd);
+ DRM_DEBUG_KMS("cmd[%d]\n", property->cmd);
/* start operations */
if (ippdrv->start) {
@@ -1405,7 +1361,7 @@ static int ipp_stop_property(struct drm_device *drm_dev,
struct list_head *head;
int ret = 0, i;
- DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id);
+ DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
/* put event */
ipp_put_event(c_node, NULL);
@@ -1418,8 +1374,7 @@ static int ipp_stop_property(struct drm_device *drm_dev,
head = &c_node->mem_list[i];
if (list_empty(head)) {
- DRM_DEBUG_KMS("%s:mem_list is empty.\n",
- __func__);
+ DRM_DEBUG_KMS("mem_list is empty.\n");
break;
}
@@ -1439,7 +1394,7 @@ static int ipp_stop_property(struct drm_device *drm_dev,
head = &c_node->mem_list[EXYNOS_DRM_OPS_DST];
if (list_empty(head)) {
- DRM_DEBUG_KMS("%s:mem_list is empty.\n", __func__);
+ DRM_DEBUG_KMS("mem_list is empty.\n");
break;
}
@@ -1456,7 +1411,7 @@ static int ipp_stop_property(struct drm_device *drm_dev,
head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC];
if (list_empty(head)) {
- DRM_DEBUG_KMS("%s:mem_list is empty.\n", __func__);
+ DRM_DEBUG_KMS("mem_list is empty.\n");
break;
}
@@ -1491,8 +1446,6 @@ void ipp_sched_cmd(struct work_struct *work)
struct drm_exynos_ipp_property *property;
int ret;
- DRM_DEBUG_KMS("%s\n", __func__);
-
ippdrv = cmd_work->ippdrv;
if (!ippdrv) {
DRM_ERROR("invalid ippdrv list.\n");
@@ -1550,7 +1503,7 @@ void ipp_sched_cmd(struct work_struct *work)
break;
}
- DRM_DEBUG_KMS("%s:ctrl[%d] done.\n", __func__, cmd_work->ctrl);
+ DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl);
err_unlock:
mutex_unlock(&c_node->cmd_lock);
@@ -1571,8 +1524,7 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
int ret, i;
for_each_ipp_ops(i)
- DRM_DEBUG_KMS("%s:%s buf_id[%d]\n", __func__,
- i ? "dst" : "src", buf_id[i]);
+ DRM_DEBUG_KMS("%s buf_id[%d]\n", i ? "dst" : "src", buf_id[i]);
if (!drm_dev) {
DRM_ERROR("failed to get drm_dev.\n");
@@ -1585,12 +1537,12 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
}
if (list_empty(&c_node->event_list)) {
- DRM_DEBUG_KMS("%s:event list is empty.\n", __func__);
+ DRM_DEBUG_KMS("event list is empty.\n");
return 0;
}
if (!ipp_check_mem_list(c_node)) {
- DRM_DEBUG_KMS("%s:empty memory.\n", __func__);
+ DRM_DEBUG_KMS("empty memory.\n");
return 0;
}
@@ -1609,7 +1561,7 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
}
tbuf_id[i] = m_node->buf_id;
- DRM_DEBUG_KMS("%s:%s buf_id[%d]\n", __func__,
+ DRM_DEBUG_KMS("%s buf_id[%d]\n",
i ? "dst" : "src", tbuf_id[i]);
ret = ipp_put_mem_node(drm_dev, c_node, m_node);
@@ -1677,8 +1629,7 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
}
do_gettimeofday(&now);
- DRM_DEBUG_KMS("%s:tv_sec[%ld]tv_usec[%ld]\n"
- , __func__, now.tv_sec, now.tv_usec);
+ DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec);
e->event.tv_sec = now.tv_sec;
e->event.tv_usec = now.tv_usec;
e->event.prop_id = property->prop_id;
@@ -1692,7 +1643,7 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
wake_up_interruptible(&e->base.file_priv->event_wait);
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
- DRM_DEBUG_KMS("%s:done cmd[%d]prop_id[%d]buf_id[%d]\n", __func__,
+ DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n",
property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]);
return 0;
@@ -1711,8 +1662,7 @@ void ipp_sched_event(struct work_struct *work)
return;
}
- DRM_DEBUG_KMS("%s:buf_id[%d]\n", __func__,
- event_work->buf_id[EXYNOS_DRM_OPS_DST]);
+ DRM_DEBUG_KMS("buf_id[%d]\n", event_work->buf_id[EXYNOS_DRM_OPS_DST]);
ippdrv = event_work->ippdrv;
if (!ippdrv) {
@@ -1733,8 +1683,8 @@ void ipp_sched_event(struct work_struct *work)
* or going out operations.
*/
if (c_node->state != IPP_STATE_START) {
- DRM_DEBUG_KMS("%s:bypass state[%d]prop_id[%d]\n",
- __func__, c_node->state, c_node->property.prop_id);
+ DRM_DEBUG_KMS("bypass state[%d]prop_id[%d]\n",
+ c_node->state, c_node->property.prop_id);
goto err_completion;
}
@@ -1759,8 +1709,6 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
struct exynos_drm_ippdrv *ippdrv;
int ret, count = 0;
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* get ipp driver entry */
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
ippdrv->drm_dev = drm_dev;
@@ -1772,7 +1720,7 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
goto err_idr;
}
- DRM_DEBUG_KMS("%s:count[%d]ippdrv[0x%x]ipp_id[%d]\n", __func__,
+ DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n",
count++, (int)ippdrv, ippdrv->ipp_id);
if (ippdrv->ipp_id == 0) {
@@ -1816,8 +1764,6 @@ static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
{
struct exynos_drm_ippdrv *ippdrv;
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* get ipp driver entry */
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
if (is_drm_iommu_supported(drm_dev))
@@ -1834,8 +1780,6 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev,
struct drm_exynos_file_private *file_priv = file->driver_priv;
struct exynos_drm_ipp_private *priv;
- DRM_DEBUG_KMS("%s\n", __func__);
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
DRM_ERROR("failed to allocate priv.\n");
@@ -1846,7 +1790,7 @@ static int ipp_subdrv_open(struct drm_device *drm_dev, struct device *dev,
INIT_LIST_HEAD(&priv->event_list);
- DRM_DEBUG_KMS("%s:done priv[0x%x]\n", __func__, (int)priv);
+ DRM_DEBUG_KMS("done priv[0x%x]\n", (int)priv);
return 0;
}
@@ -1860,10 +1804,10 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
struct drm_exynos_ipp_cmd_node *c_node, *tc_node;
int count = 0;
- DRM_DEBUG_KMS("%s:for priv[0x%x]\n", __func__, (int)priv);
+ DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv);
if (list_empty(&exynos_drm_ippdrv_list)) {
- DRM_DEBUG_KMS("%s:ippdrv_list is empty.\n", __func__);
+ DRM_DEBUG_KMS("ippdrv_list is empty.\n");
goto err_clear;
}
@@ -1873,8 +1817,8 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
list_for_each_entry_safe(c_node, tc_node,
&ippdrv->cmd_list, list) {
- DRM_DEBUG_KMS("%s:count[%d]ippdrv[0x%x]\n",
- __func__, count++, (int)ippdrv);
+ DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n",
+ count++, (int)ippdrv);
if (c_node->priv == priv) {
/*
@@ -1913,8 +1857,6 @@ static int ipp_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- DRM_DEBUG_KMS("%s\n", __func__);
-
mutex_init(&ctx->ipp_lock);
mutex_init(&ctx->prop_lock);
@@ -1978,8 +1920,6 @@ static int ipp_remove(struct platform_device *pdev)
{
struct ipp_context *ctx = platform_get_drvdata(pdev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
/* unregister sub driver */
exynos_drm_subdrv_unregister(&ctx->subdrv);
@@ -1999,7 +1939,7 @@ static int ipp_remove(struct platform_device *pdev)
static int ipp_power_ctrl(struct ipp_context *ctx, bool enable)
{
- DRM_DEBUG_KMS("%s:enable[%d]\n", __func__, enable);
+ DRM_DEBUG_KMS("enable[%d]\n", enable);
return 0;
}
@@ -2009,8 +1949,6 @@ static int ipp_suspend(struct device *dev)
{
struct ipp_context *ctx = get_ipp_context(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (pm_runtime_suspended(dev))
return 0;
@@ -2021,8 +1959,6 @@ static int ipp_resume(struct device *dev)
{
struct ipp_context *ctx = get_ipp_context(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!pm_runtime_suspended(dev))
return ipp_power_ctrl(ctx, true);
@@ -2035,8 +1971,6 @@ static int ipp_runtime_suspend(struct device *dev)
{
struct ipp_context *ctx = get_ipp_context(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
return ipp_power_ctrl(ctx, false);
}
@@ -2044,8 +1978,6 @@ static int ipp_runtime_resume(struct device *dev)
{
struct ipp_context *ctx = get_ipp_context(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
return ipp_power_ctrl(ctx, true);
}
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 83efc662d65a..6ee55e68e0a2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -81,8 +81,6 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
int nr;
int i;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
nr = exynos_drm_fb_get_buf_cnt(fb);
for (i = 0; i < nr; i++) {
struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
@@ -159,8 +157,6 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (mode == DRM_MODE_DPMS_ON) {
if (exynos_plane->enabled)
return;
@@ -189,8 +185,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
{
int ret;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
crtc_w, crtc_h, src_x >> 16, src_y >> 16,
src_w >> 16, src_h >> 16);
@@ -207,8 +201,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
static int exynos_disable_plane(struct drm_plane *plane)
{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
return 0;
@@ -218,8 +210,6 @@ static void exynos_plane_destroy(struct drm_plane *plane)
{
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
exynos_disable_plane(plane);
drm_plane_cleanup(plane);
kfree(exynos_plane);
@@ -233,8 +223,6 @@ static int exynos_plane_set_property(struct drm_plane *plane,
struct exynos_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_private *dev_priv = dev->dev_private;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (property == dev_priv->plane_zpos_property) {
exynos_plane->overlay.zpos = val;
return 0;
@@ -256,8 +244,6 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
struct exynos_drm_private *dev_priv = dev->dev_private;
struct drm_property *prop;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
prop = dev_priv->plane_zpos_property;
if (!prop) {
prop = drm_property_create_range(dev, 0, "zpos", 0,
@@ -277,8 +263,6 @@ struct drm_plane *exynos_plane_init(struct drm_device *dev,
struct exynos_plane *exynos_plane;
int err;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
if (!exynos_plane) {
DRM_ERROR("failed to allocate plane\n");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 9b6c70964d71..427640aa5148 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -244,7 +244,7 @@ static int rotator_src_set_size(struct device *dev, int swap,
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
- DRM_ERROR("%s:invalid format.\n", __func__);
+ DRM_ERROR("invalid format.\n");
return -EINVAL;
}
@@ -287,7 +287,7 @@ static int rotator_src_set_addr(struct device *dev,
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
- DRM_ERROR("%s:invalid format.\n", __func__);
+ DRM_ERROR("invalid format.\n");
return -EINVAL;
}
@@ -381,7 +381,7 @@ static int rotator_dst_set_size(struct device *dev, int swap,
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
- DRM_ERROR("%s:invalid format.\n", __func__);
+ DRM_ERROR("invalid format.\n");
return -EINVAL;
}
@@ -422,7 +422,7 @@ static int rotator_dst_set_addr(struct device *dev,
/* Get format */
fmt = rotator_reg_get_fmt(rot);
if (!rotator_check_reg_fmt(fmt)) {
- DRM_ERROR("%s:invalid format.\n", __func__);
+ DRM_ERROR("invalid format.\n");
return -EINVAL;
}
@@ -471,8 +471,6 @@ static int rotator_init_prop_list(struct exynos_drm_ippdrv *ippdrv)
{
struct drm_exynos_ipp_prop_list *prop_list;
- DRM_DEBUG_KMS("%s\n", __func__);
-
prop_list = devm_kzalloc(ippdrv->dev, sizeof(*prop_list), GFP_KERNEL);
if (!prop_list) {
DRM_ERROR("failed to alloc property list.\n");
@@ -502,7 +500,7 @@ static inline bool rotator_check_drm_fmt(u32 fmt)
case DRM_FORMAT_NV12:
return true;
default:
- DRM_DEBUG_KMS("%s:not support format\n", __func__);
+ DRM_DEBUG_KMS("not support format\n");
return false;
}
}
@@ -516,7 +514,7 @@ static inline bool rotator_check_drm_flip(enum drm_exynos_flip flip)
case EXYNOS_DRM_FLIP_BOTH:
return true;
default:
- DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+ DRM_DEBUG_KMS("invalid flip\n");
return false;
}
}
@@ -536,19 +534,18 @@ static int rotator_ippdrv_check_property(struct device *dev,
/* Check format configuration */
if (src_config->fmt != dst_config->fmt) {
- DRM_DEBUG_KMS("%s:not support csc feature\n", __func__);
+ DRM_DEBUG_KMS("not support csc feature\n");
return -EINVAL;
}
if (!rotator_check_drm_fmt(dst_config->fmt)) {
- DRM_DEBUG_KMS("%s:invalid format\n", __func__);
+ DRM_DEBUG_KMS("invalid format\n");
return -EINVAL;
}
/* Check transform configuration */
if (src_config->degree != EXYNOS_DRM_DEGREE_0) {
- DRM_DEBUG_KMS("%s:not support source-side rotation\n",
- __func__);
+ DRM_DEBUG_KMS("not support source-side rotation\n");
return -EINVAL;
}
@@ -561,51 +558,47 @@ static int rotator_ippdrv_check_property(struct device *dev,
/* No problem */
break;
default:
- DRM_DEBUG_KMS("%s:invalid degree\n", __func__);
+ DRM_DEBUG_KMS("invalid degree\n");
return -EINVAL;
}
if (src_config->flip != EXYNOS_DRM_FLIP_NONE) {
- DRM_DEBUG_KMS("%s:not support source-side flip\n", __func__);
+ DRM_DEBUG_KMS("not support source-side flip\n");
return -EINVAL;
}
if (!rotator_check_drm_flip(dst_config->flip)) {
- DRM_DEBUG_KMS("%s:invalid flip\n", __func__);
+ DRM_DEBUG_KMS("invalid flip\n");
return -EINVAL;
}
/* Check size configuration */
if ((src_pos->x + src_pos->w > src_sz->hsize) ||
(src_pos->y + src_pos->h > src_sz->vsize)) {
- DRM_DEBUG_KMS("%s:out of source buffer bound\n", __func__);
+ DRM_DEBUG_KMS("out of source buffer bound\n");
return -EINVAL;
}
if (swap) {
if ((dst_pos->x + dst_pos->h > dst_sz->vsize) ||
(dst_pos->y + dst_pos->w > dst_sz->hsize)) {
- DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
- __func__);
+ DRM_DEBUG_KMS("out of destination buffer bound\n");
return -EINVAL;
}
if ((src_pos->w != dst_pos->h) || (src_pos->h != dst_pos->w)) {
- DRM_DEBUG_KMS("%s:not support scale feature\n",
- __func__);
+ DRM_DEBUG_KMS("not support scale feature\n");
return -EINVAL;
}
} else {
if ((dst_pos->x + dst_pos->w > dst_sz->hsize) ||
(dst_pos->y + dst_pos->h > dst_sz->vsize)) {
- DRM_DEBUG_KMS("%s:out of destination buffer bound\n",
- __func__);
+ DRM_DEBUG_KMS("out of destination buffer bound\n");
return -EINVAL;
}
if ((src_pos->w != dst_pos->w) || (src_pos->h != dst_pos->h)) {
- DRM_DEBUG_KMS("%s:not support scale feature\n",
- __func__);
+ DRM_DEBUG_KMS("not support scale feature\n");
return -EINVAL;
}
}
@@ -693,7 +686,7 @@ static int rotator_probe(struct platform_device *pdev)
goto err_ippdrv_register;
}
- DRM_DEBUG_KMS("%s:ippdrv[0x%x]\n", __func__, (int)ippdrv);
+ DRM_DEBUG_KMS("ippdrv[0x%x]\n", (int)ippdrv);
platform_set_drvdata(pdev, rot);
@@ -752,8 +745,6 @@ static struct platform_device_id rotator_driver_ids[] = {
static int rotator_clk_crtl(struct rot_context *rot, bool enable)
{
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (enable) {
clk_enable(rot->clock);
rot->suspended = false;
@@ -771,8 +762,6 @@ static int rotator_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (pm_runtime_suspended(dev))
return 0;
@@ -783,8 +772,6 @@ static int rotator_resume(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
if (!pm_runtime_suspended(dev))
return rotator_clk_crtl(rot, true);
@@ -797,8 +784,6 @@ static int rotator_runtime_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
return rotator_clk_crtl(rot, false);
}
@@ -806,8 +791,6 @@ static int rotator_runtime_resume(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
- DRM_DEBUG_KMS("%s\n", __func__);
-
return rotator_clk_crtl(rot, true);
}
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 24376c194a5e..41cc74d83e4e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -89,8 +89,6 @@ static bool vidi_display_is_connected(struct device *dev)
{
struct vidi_context *ctx = get_vidi_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* connection request would come from user side
* to do hotplug through specific ioctl.
@@ -105,8 +103,6 @@ static struct edid *vidi_get_edid(struct device *dev,
struct edid *edid;
int edid_len;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* the edid data comes from user side and it would be set
* to ctx->raw_edid through specific ioctl.
@@ -128,17 +124,13 @@ static struct edid *vidi_get_edid(struct device *dev,
static void *vidi_get_panel(struct device *dev)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO. */
return NULL;
}
-static int vidi_check_timing(struct device *dev, void *timing)
+static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO. */
return 0;
@@ -146,8 +138,6 @@ static int vidi_check_timing(struct device *dev, void *timing)
static int vidi_display_power_on(struct device *dev, int mode)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO */
return 0;
@@ -158,7 +148,7 @@ static struct exynos_drm_display_ops vidi_display_ops = {
.is_connected = vidi_display_is_connected,
.get_edid = vidi_get_edid,
.get_panel = vidi_get_panel,
- .check_timing = vidi_check_timing,
+ .check_mode = vidi_check_mode,
.power_on = vidi_display_power_on,
};
@@ -166,7 +156,7 @@ static void vidi_dpms(struct device *subdrv_dev, int mode)
{
struct vidi_context *ctx = get_vidi_context(subdrv_dev);
- DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+ DRM_DEBUG_KMS("%d\n", mode);
mutex_lock(&ctx->lock);
@@ -196,8 +186,6 @@ static void vidi_apply(struct device *subdrv_dev)
struct vidi_win_data *win_data;
int i;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled && (ovl_ops && ovl_ops->commit))
@@ -212,8 +200,6 @@ static void vidi_commit(struct device *dev)
{
struct vidi_context *ctx = get_vidi_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return;
}
@@ -222,8 +208,6 @@ static int vidi_enable_vblank(struct device *dev)
{
struct vidi_context *ctx = get_vidi_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return -EPERM;
@@ -246,8 +230,6 @@ static void vidi_disable_vblank(struct device *dev)
{
struct vidi_context *ctx = get_vidi_context(dev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return;
@@ -271,8 +253,6 @@ static void vidi_win_mode_set(struct device *dev,
int win;
unsigned long offset;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!overlay) {
dev_err(dev, "overlay is NULL\n");
return;
@@ -282,7 +262,7 @@ static void vidi_win_mode_set(struct device *dev,
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
- if (win < 0 || win > WINDOWS_NR)
+ if (win < 0 || win >= WINDOWS_NR)
return;
offset = overlay->fb_x * (overlay->bpp >> 3);
@@ -324,15 +304,13 @@ static void vidi_win_commit(struct device *dev, int zpos)
struct vidi_win_data *win_data;
int win = zpos;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (ctx->suspended)
return;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
- if (win < 0 || win > WINDOWS_NR)
+ if (win < 0 || win >= WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
@@ -351,12 +329,10 @@ static void vidi_win_disable(struct device *dev, int zpos)
struct vidi_win_data *win_data;
int win = zpos;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
- if (win < 0 || win > WINDOWS_NR)
+ if (win < 0 || win >= WINDOWS_NR)
return;
win_data = &ctx->win_data[win];
@@ -407,8 +383,6 @@ static void vidi_fake_vblank_handler(struct work_struct *work)
static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/*
* enable drm irq mode.
* - with irq_enabled = 1, we can use the vblank feature.
@@ -431,8 +405,6 @@ static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
/* TODO. */
}
@@ -441,11 +413,6 @@ static int vidi_power_on(struct vidi_context *ctx, bool enable)
struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
struct device *dev = subdrv->dev;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- if (enable != false && enable != true)
- return -EINVAL;
-
if (enable) {
ctx->suspended = false;
@@ -483,8 +450,6 @@ static int vidi_store_connection(struct device *dev,
struct vidi_context *ctx = get_vidi_context(dev);
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
ret = kstrtoint(buf, 0, &ctx->connected);
if (ret)
return ret;
@@ -522,8 +487,6 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
struct drm_exynos_vidi_connection *vidi = data;
int edid_len;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
if (!vidi) {
DRM_DEBUG_KMS("user data for vidi is null.\n");
return -EINVAL;
@@ -592,8 +555,6 @@ static int vidi_probe(struct platform_device *pdev)
struct exynos_drm_subdrv *subdrv;
int ret;
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -625,8 +586,6 @@ static int vidi_remove(struct platform_device *pdev)
{
struct vidi_context *ctx = platform_get_drvdata(pdev);
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
exynos_drm_subdrv_unregister(&ctx->subdrv);
if (ctx->raw_edid != (struct edid *)fake_edid_info) {
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index fd1426dca882..62ef5971ac3c 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -83,6 +83,7 @@ struct hdmi_resources {
struct clk *sclk_pixel;
struct clk *sclk_hdmiphy;
struct clk *hdmiphy;
+ struct clk *mout_hdmi;
struct regulator_bulk_data *regul_bulk;
int regul_count;
};
@@ -689,8 +690,6 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
u32 mod;
u32 vic;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
if (hdata->dvi_mode) {
hdmi_reg_writeb(hdata, HDMI_VSI_CON,
@@ -755,8 +754,6 @@ static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
struct edid *raw_edid;
struct hdmi_context *hdata = ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (!hdata->ddc_port)
return ERR_PTR(-ENODEV);
@@ -777,8 +774,6 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
const struct hdmiphy_config *confs;
int count, i;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (hdata->type == HDMI_TYPE13) {
confs = hdmiphy_v13_configs;
count = ARRAY_SIZE(hdmiphy_v13_configs);
@@ -796,18 +791,17 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
return -EINVAL;
}
-static int hdmi_check_timing(void *ctx, struct fb_videomode *timing)
+static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
{
struct hdmi_context *hdata = ctx;
int ret;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+ DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
+ mode->hdisplay, mode->vdisplay, mode->vrefresh,
+ (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
+ false, mode->clock * 1000);
- DRM_DEBUG_KMS("[%d]x[%d] [%d]Hz [%x]\n", timing->xres,
- timing->yres, timing->refresh,
- timing->vmode);
-
- ret = hdmi_find_phy_conf(hdata, timing->pixclock);
+ ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
if (ret < 0)
return ret;
return 0;
@@ -1042,7 +1036,7 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
}
}
-static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
+static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
{
const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
const struct hdmi_v13_core_regs *core =
@@ -1118,9 +1112,9 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
hdmi_regs_dump(hdata, "timing apply");
}
- clk_disable(hdata->res.sclk_hdmi);
- clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
- clk_enable(hdata->res.sclk_hdmi);
+ clk_disable_unprepare(hdata->res.sclk_hdmi);
+ clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
+ clk_prepare_enable(hdata->res.sclk_hdmi);
/* enable HDMI and timing generator */
hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
@@ -1131,7 +1125,7 @@ static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
}
-static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
+static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
{
const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
const struct hdmi_v14_core_regs *core =
@@ -1285,9 +1279,9 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
hdmi_regs_dump(hdata, "timing apply");
}
- clk_disable(hdata->res.sclk_hdmi);
- clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_hdmiphy);
- clk_enable(hdata->res.sclk_hdmi);
+ clk_disable_unprepare(hdata->res.sclk_hdmi);
+ clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_hdmiphy);
+ clk_prepare_enable(hdata->res.sclk_hdmi);
/* enable HDMI and timing generator */
hdmi_reg_writemask(hdata, HDMI_CON_0, ~0, HDMI_EN);
@@ -1298,12 +1292,12 @@ static void hdmi_v14_timing_apply(struct hdmi_context *hdata)
hdmi_reg_writemask(hdata, HDMI_TG_CMD, ~0, HDMI_TG_EN);
}
-static void hdmi_timing_apply(struct hdmi_context *hdata)
+static void hdmi_mode_apply(struct hdmi_context *hdata)
{
if (hdata->type == HDMI_TYPE13)
- hdmi_v13_timing_apply(hdata);
+ hdmi_v13_mode_apply(hdata);
else
- hdmi_v14_timing_apply(hdata);
+ hdmi_v14_mode_apply(hdata);
}
static void hdmiphy_conf_reset(struct hdmi_context *hdata)
@@ -1311,9 +1305,9 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
u8 buffer[2];
u32 reg;
- clk_disable(hdata->res.sclk_hdmi);
- clk_set_parent(hdata->res.sclk_hdmi, hdata->res.sclk_pixel);
- clk_enable(hdata->res.sclk_hdmi);
+ clk_disable_unprepare(hdata->res.sclk_hdmi);
+ clk_set_parent(hdata->res.mout_hdmi, hdata->res.sclk_pixel);
+ clk_prepare_enable(hdata->res.sclk_hdmi);
/* operation mode */
buffer[0] = 0x1f;
@@ -1336,8 +1330,6 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
static void hdmiphy_poweron(struct hdmi_context *hdata)
{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (hdata->type == HDMI_TYPE14)
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, 0,
HDMI_PHY_POWER_OFF_EN);
@@ -1345,8 +1337,6 @@ static void hdmiphy_poweron(struct hdmi_context *hdata)
static void hdmiphy_poweroff(struct hdmi_context *hdata)
{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (hdata->type == HDMI_TYPE14)
hdmi_reg_writemask(hdata, HDMI_PHY_CON_0, ~0,
HDMI_PHY_POWER_OFF_EN);
@@ -1410,8 +1400,6 @@ static void hdmiphy_conf_apply(struct hdmi_context *hdata)
static void hdmi_conf_apply(struct hdmi_context *hdata)
{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
hdmiphy_conf_reset(hdata);
hdmiphy_conf_apply(hdata);
@@ -1423,7 +1411,7 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
hdmi_audio_init(hdata);
/* setting core registers */
- hdmi_timing_apply(hdata);
+ hdmi_mode_apply(hdata);
hdmi_audio_control(hdata, true);
hdmi_regs_dump(hdata, "start");
@@ -1569,8 +1557,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
(m->vsync_start - m->vdisplay) / 2);
hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
- hdmi_set_reg(core->v_blank_f0, 2, (m->vtotal +
- ((m->vsync_end - m->vsync_start) * 4) + 5) / 2);
+ hdmi_set_reg(core->v_blank_f0, 2, m->vtotal - m->vdisplay / 2);
hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
@@ -1580,7 +1567,10 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
(m->htotal / 2) + (m->hsync_start - m->hdisplay));
hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
- hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
+ hdmi_set_reg(tg->vact_st2, 2, m->vtotal - m->vdisplay / 2);
+ hdmi_set_reg(tg->vsync2, 2, (m->vtotal / 2) + 1);
+ hdmi_set_reg(tg->vsync_bot_hdmi, 2, (m->vtotal / 2) + 1);
+ hdmi_set_reg(tg->field_bot_hdmi, 2, (m->vtotal / 2) + 1);
hdmi_set_reg(tg->vact_st3, 2, 0x0);
hdmi_set_reg(tg->vact_st4, 2, 0x0);
} else {
@@ -1602,6 +1592,9 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
+ hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
+ hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
+ hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
}
/* Following values & calculations are same irrespective of mode type */
@@ -1633,22 +1626,19 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
hdmi_set_reg(tg->vsync, 2, 0x1);
- hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
- hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
- hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
hdmi_set_reg(tg->tg_3d, 1, 0x0);
}
-static void hdmi_mode_set(void *ctx, void *mode)
+static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
{
struct hdmi_context *hdata = ctx;
struct drm_display_mode *m = mode;
- DRM_DEBUG_KMS("[%s]: xres=%d, yres=%d, refresh=%d, intl=%s\n",
- __func__, m->hdisplay, m->vdisplay,
+ DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
+ m->hdisplay, m->vdisplay,
m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ?
"INTERLACED" : "PROGERESSIVE");
@@ -1661,8 +1651,6 @@ static void hdmi_mode_set(void *ctx, void *mode)
static void hdmi_get_max_resol(void *ctx, unsigned int *width,
unsigned int *height)
{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
*width = MAX_WIDTH;
*height = MAX_HEIGHT;
}
@@ -1671,8 +1659,6 @@ static void hdmi_commit(void *ctx)
{
struct hdmi_context *hdata = ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mutex_lock(&hdata->hdmi_mutex);
if (!hdata->powered) {
mutex_unlock(&hdata->hdmi_mutex);
@@ -1687,8 +1673,6 @@ static void hdmi_poweron(struct hdmi_context *hdata)
{
struct hdmi_resources *res = &hdata->res;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mutex_lock(&hdata->hdmi_mutex);
if (hdata->powered) {
mutex_unlock(&hdata->hdmi_mutex);
@@ -1699,10 +1683,12 @@ static void hdmi_poweron(struct hdmi_context *hdata)
mutex_unlock(&hdata->hdmi_mutex);
- regulator_bulk_enable(res->regul_count, res->regul_bulk);
- clk_enable(res->hdmiphy);
- clk_enable(res->hdmi);
- clk_enable(res->sclk_hdmi);
+ if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
+ DRM_DEBUG_KMS("failed to enable regulator bulk\n");
+
+ clk_prepare_enable(res->hdmiphy);
+ clk_prepare_enable(res->hdmi);
+ clk_prepare_enable(res->sclk_hdmi);
hdmiphy_poweron(hdata);
}
@@ -1711,8 +1697,6 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
{
struct hdmi_resources *res = &hdata->res;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mutex_lock(&hdata->hdmi_mutex);
if (!hdata->powered)
goto out;
@@ -1725,9 +1709,9 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
hdmiphy_conf_reset(hdata);
hdmiphy_poweroff(hdata);
- clk_disable(res->sclk_hdmi);
- clk_disable(res->hdmi);
- clk_disable(res->hdmiphy);
+ clk_disable_unprepare(res->sclk_hdmi);
+ clk_disable_unprepare(res->hdmi);
+ clk_disable_unprepare(res->hdmiphy);
regulator_bulk_disable(res->regul_count, res->regul_bulk);
mutex_lock(&hdata->hdmi_mutex);
@@ -1742,7 +1726,7 @@ static void hdmi_dpms(void *ctx, int mode)
{
struct hdmi_context *hdata = ctx;
- DRM_DEBUG_KMS("[%d] %s mode %d\n", __LINE__, __func__, mode);
+ DRM_DEBUG_KMS("mode %d\n", mode);
switch (mode) {
case DRM_MODE_DPMS_ON:
@@ -1765,7 +1749,7 @@ static struct exynos_hdmi_ops hdmi_ops = {
/* display */
.is_connected = hdmi_is_connected,
.get_edid = hdmi_get_edid,
- .check_timing = hdmi_check_timing,
+ .check_mode = hdmi_check_mode,
/* manager */
.mode_set = hdmi_mode_set,
@@ -1831,8 +1815,13 @@ static int hdmi_resources_init(struct hdmi_context *hdata)
DRM_ERROR("failed to get clock 'hdmiphy'\n");
goto fail;
}
+ res->mout_hdmi = devm_clk_get(dev, "mout_hdmi");
+ if (IS_ERR(res->mout_hdmi)) {
+ DRM_ERROR("failed to get clock 'mout_hdmi'\n");
+ goto fail;
+ }
- clk_set_parent(res->sclk_hdmi, res->sclk_pixel);
+ clk_set_parent(res->mout_hdmi, res->sclk_pixel);
res->regul_bulk = devm_kzalloc(dev, ARRAY_SIZE(supply) *
sizeof(res->regul_bulk[0]), GFP_KERNEL);
@@ -1877,7 +1866,6 @@ static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
{
struct device_node *np = dev->of_node;
struct s5p_hdmi_platform_data *pd;
- enum of_gpio_flags flags;
u32 value;
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
@@ -1891,7 +1879,7 @@ static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
goto err_data;
}
- pd->hpd_gpio = of_get_named_gpio_flags(np, "hpd-gpio", 0, &flags);
+ pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
return pd;
@@ -1930,6 +1918,9 @@ static struct of_device_id hdmi_match_types[] = {
.compatible = "samsung,exynos5-hdmi",
.data = (void *)HDMI_TYPE14,
}, {
+ .compatible = "samsung,exynos4212-hdmi",
+ .data = (void *)HDMI_TYPE14,
+ }, {
/* end node */
}
};
@@ -1944,8 +1935,6 @@ static int hdmi_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- DRM_DEBUG_KMS("[%d]\n", __LINE__);
-
if (dev->of_node) {
pdata = drm_hdmi_dt_parse_pdata(dev);
if (IS_ERR(pdata)) {
@@ -2071,8 +2060,6 @@ static int hdmi_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
pm_runtime_disable(dev);
/* hdmiphy i2c driver */
@@ -2089,8 +2076,6 @@ static int hdmi_suspend(struct device *dev)
struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
struct hdmi_context *hdata = ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
disable_irq(hdata->irq);
hdata->hpd = false;
@@ -2098,7 +2083,7 @@ static int hdmi_suspend(struct device *dev)
drm_helper_hpd_irq_event(ctx->drm_dev);
if (pm_runtime_suspended(dev)) {
- DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
+ DRM_DEBUG_KMS("Already suspended\n");
return 0;
}
@@ -2112,14 +2097,12 @@ static int hdmi_resume(struct device *dev)
struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
struct hdmi_context *hdata = ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
hdata->hpd = gpio_get_value(hdata->hpd_gpio);
enable_irq(hdata->irq);
if (!pm_runtime_suspended(dev)) {
- DRM_DEBUG_KMS("%s : Already resumed\n", __func__);
+ DRM_DEBUG_KMS("Already resumed\n");
return 0;
}
@@ -2134,7 +2117,6 @@ static int hdmi_runtime_suspend(struct device *dev)
{
struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
struct hdmi_context *hdata = ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
hdmi_poweroff(hdata);
@@ -2145,7 +2127,6 @@ static int hdmi_runtime_resume(struct device *dev)
{
struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
struct hdmi_context *hdata = ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
hdmi_poweron(hdata);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
index ea49d132ecf6..ef04255076c7 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
@@ -51,6 +51,10 @@ static struct of_device_id hdmiphy_match_types[] = {
{
.compatible = "samsung,exynos5-hdmiphy",
}, {
+ .compatible = "samsung,exynos4210-hdmiphy",
+ }, {
+ .compatible = "samsung,exynos4212-hdmiphy",
+ }, {
/* end node */
}
};
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 7c197d3820c5..42ffb71c63bc 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -78,6 +78,7 @@ struct mixer_resources {
enum mixer_version_id {
MXR_VER_0_0_0_16,
MXR_VER_16_0_33_0,
+ MXR_VER_128_0_0_184,
};
struct mixer_context {
@@ -283,17 +284,19 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
MXR_CFG_SCAN_PROGRASSIVE);
- /* choosing between porper HD and SD mode */
- if (height <= 480)
- val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
- else if (height <= 576)
- val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
- else if (height <= 720)
- val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
- else if (height <= 1080)
- val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
- else
- val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+ if (ctx->mxr_ver != MXR_VER_128_0_0_184) {
+ /* choosing between proper HD and SD mode */
+ if (height <= 480)
+ val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
+ else if (height <= 576)
+ val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
+ else if (height <= 720)
+ val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+ else if (height <= 1080)
+ val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
+ else
+ val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
+ }
mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
}
@@ -376,7 +379,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
unsigned long flags;
struct hdmi_win_data *win_data;
unsigned int x_ratio, y_ratio;
- unsigned int buf_num;
+ unsigned int buf_num = 1;
dma_addr_t luma_addr[2], chroma_addr[2];
bool tiled_mode = false;
bool crcb_mode = false;
@@ -557,6 +560,14 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
/* setup geometry */
mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
+ /* setup display size */
+ if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
+ win == MIXER_DEFAULT_WIN) {
+ val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
+ val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
+ mixer_reg_write(res, MXR_RESOLUTION, val);
+ }
+
val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
val |= MXR_GRP_WH_H_SCALE(x_ratio);
@@ -581,7 +592,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
mixer_cfg_layer(ctx, win, true);
/* layer update mandatory for mixer 16.0.33.0 */
- if (ctx->mxr_ver == MXR_VER_16_0_33_0)
+ if (ctx->mxr_ver == MXR_VER_16_0_33_0 ||
+ ctx->mxr_ver == MXR_VER_128_0_0_184)
mixer_layer_update(ctx);
mixer_run(ctx);
@@ -696,8 +708,6 @@ static int mixer_enable_vblank(void *ctx, int pipe)
struct mixer_context *mixer_ctx = ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mixer_ctx->pipe = pipe;
/* enable vsync interrupt */
@@ -712,8 +722,6 @@ static void mixer_disable_vblank(void *ctx)
struct mixer_context *mixer_ctx = ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
/* disable vsync interrupt */
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
}
@@ -725,8 +733,6 @@ static void mixer_win_mode_set(void *ctx,
struct hdmi_win_data *win_data;
int win;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (!overlay) {
DRM_ERROR("overlay is NULL\n");
return;
@@ -742,7 +748,7 @@ static void mixer_win_mode_set(void *ctx,
if (win == DEFAULT_ZPOS)
win = MIXER_DEFAULT_WIN;
- if (win < 0 || win > MIXER_WIN_NR) {
+ if (win < 0 || win >= MIXER_WIN_NR) {
DRM_ERROR("mixer window[%d] is wrong\n", win);
return;
}
@@ -776,7 +782,7 @@ static void mixer_win_commit(void *ctx, int win)
{
struct mixer_context *mixer_ctx = ctx;
- DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
+ DRM_DEBUG_KMS("win: %d\n", win);
mutex_lock(&mixer_ctx->mixer_mutex);
if (!mixer_ctx->powered) {
@@ -799,7 +805,7 @@ static void mixer_win_disable(void *ctx, int win)
struct mixer_resources *res = &mixer_ctx->mixer_res;
unsigned long flags;
- DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
+ DRM_DEBUG_KMS("win: %d\n", win);
mutex_lock(&mixer_ctx->mixer_mutex);
if (!mixer_ctx->powered) {
@@ -820,17 +826,21 @@ static void mixer_win_disable(void *ctx, int win)
mixer_ctx->win_data[win].enabled = false;
}
-static int mixer_check_timing(void *ctx, struct fb_videomode *timing)
+static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
{
+ struct mixer_context *mixer_ctx = ctx;
u32 w, h;
- w = timing->xres;
- h = timing->yres;
+ w = mode->hdisplay;
+ h = mode->vdisplay;
- DRM_DEBUG_KMS("%s : xres=%d, yres=%d, refresh=%d, intl=%d\n",
- __func__, timing->xres, timing->yres,
- timing->refresh, (timing->vmode &
- FB_VMODE_INTERLACED) ? true : false);
+ DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
+ mode->hdisplay, mode->vdisplay, mode->vrefresh,
+ (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
+
+ if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
+ mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
+ return 0;
if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
@@ -891,8 +901,6 @@ static void mixer_poweron(struct mixer_context *ctx)
{
struct mixer_resources *res = &ctx->mixer_res;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mutex_lock(&ctx->mixer_mutex);
if (ctx->powered) {
mutex_unlock(&ctx->mixer_mutex);
@@ -901,10 +909,10 @@ static void mixer_poweron(struct mixer_context *ctx)
ctx->powered = true;
mutex_unlock(&ctx->mixer_mutex);
- clk_enable(res->mixer);
+ clk_prepare_enable(res->mixer);
if (ctx->vp_enabled) {
- clk_enable(res->vp);
- clk_enable(res->sclk_mixer);
+ clk_prepare_enable(res->vp);
+ clk_prepare_enable(res->sclk_mixer);
}
mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
@@ -917,8 +925,6 @@ static void mixer_poweroff(struct mixer_context *ctx)
{
struct mixer_resources *res = &ctx->mixer_res;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mutex_lock(&ctx->mixer_mutex);
if (!ctx->powered)
goto out;
@@ -928,10 +934,10 @@ static void mixer_poweroff(struct mixer_context *ctx)
ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
- clk_disable(res->mixer);
+ clk_disable_unprepare(res->mixer);
if (ctx->vp_enabled) {
- clk_disable(res->vp);
- clk_disable(res->sclk_mixer);
+ clk_disable_unprepare(res->vp);
+ clk_disable_unprepare(res->sclk_mixer);
}
mutex_lock(&ctx->mixer_mutex);
@@ -945,8 +951,6 @@ static void mixer_dpms(void *ctx, int mode)
{
struct mixer_context *mixer_ctx = ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
switch (mode) {
case DRM_MODE_DPMS_ON:
if (pm_runtime_suspended(mixer_ctx->dev))
@@ -978,7 +982,7 @@ static struct exynos_mixer_ops mixer_ops = {
.win_disable = mixer_win_disable,
/* display */
- .check_timing = mixer_check_timing,
+ .check_mode = mixer_check_mode,
};
static irqreturn_t mixer_irq_handler(int irq, void *arg)
@@ -1128,12 +1132,17 @@ static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
return 0;
}
-static struct mixer_drv_data exynos5_mxr_drv_data = {
+static struct mixer_drv_data exynos5420_mxr_drv_data = {
+ .version = MXR_VER_128_0_0_184,
+ .is_vp_enabled = 0,
+};
+
+static struct mixer_drv_data exynos5250_mxr_drv_data = {
.version = MXR_VER_16_0_33_0,
.is_vp_enabled = 0,
};
-static struct mixer_drv_data exynos4_mxr_drv_data = {
+static struct mixer_drv_data exynos4210_mxr_drv_data = {
.version = MXR_VER_0_0_0_16,
.is_vp_enabled = 1,
};
@@ -1141,10 +1150,10 @@ static struct mixer_drv_data exynos4_mxr_drv_data = {
static struct platform_device_id mixer_driver_types[] = {
{
.name = "s5p-mixer",
- .driver_data = (unsigned long)&exynos4_mxr_drv_data,
+ .driver_data = (unsigned long)&exynos4210_mxr_drv_data,
}, {
.name = "exynos5-mixer",
- .driver_data = (unsigned long)&exynos5_mxr_drv_data,
+ .driver_data = (unsigned long)&exynos5250_mxr_drv_data,
}, {
/* end node */
}
@@ -1153,7 +1162,13 @@ static struct platform_device_id mixer_driver_types[] = {
static struct of_device_id mixer_match_types[] = {
{
.compatible = "samsung,exynos5-mixer",
- .data = &exynos5_mxr_drv_data,
+ .data = &exynos5250_mxr_drv_data,
+ }, {
+ .compatible = "samsung,exynos5250-mixer",
+ .data = &exynos5250_mxr_drv_data,
+ }, {
+ .compatible = "samsung,exynos5420-mixer",
+ .data = &exynos5420_mxr_drv_data,
}, {
/* end node */
}
@@ -1186,8 +1201,7 @@ static int mixer_probe(struct platform_device *pdev)
if (dev->of_node) {
const struct of_device_id *match;
- match = of_match_node(of_match_ptr(mixer_match_types),
- dev->of_node);
+ match = of_match_node(mixer_match_types, dev->of_node);
drv = (struct mixer_drv_data *)match->data;
} else {
drv = (struct mixer_drv_data *)
@@ -1251,10 +1265,8 @@ static int mixer_suspend(struct device *dev)
struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
struct mixer_context *ctx = drm_hdmi_ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (pm_runtime_suspended(dev)) {
- DRM_DEBUG_KMS("%s : Already suspended\n", __func__);
+ DRM_DEBUG_KMS("Already suspended\n");
return 0;
}
@@ -1268,10 +1280,8 @@ static int mixer_resume(struct device *dev)
struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
struct mixer_context *ctx = drm_hdmi_ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
if (!pm_runtime_suspended(dev)) {
- DRM_DEBUG_KMS("%s : Already resumed\n", __func__);
+ DRM_DEBUG_KMS("Already resumed\n");
return 0;
}
@@ -1287,8 +1297,6 @@ static int mixer_runtime_suspend(struct device *dev)
struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
struct mixer_context *ctx = drm_hdmi_ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mixer_poweroff(ctx);
return 0;
@@ -1299,8 +1307,6 @@ static int mixer_runtime_resume(struct device *dev)
struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
struct mixer_context *ctx = drm_hdmi_ctx->ctx;
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
mixer_poweron(ctx);
return 0;
diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h
index 5d8dbc0301e6..4537026bc385 100644
--- a/drivers/gpu/drm/exynos/regs-mixer.h
+++ b/drivers/gpu/drm/exynos/regs-mixer.h
@@ -44,6 +44,9 @@
#define MXR_CM_COEFF_Y 0x0080
#define MXR_CM_COEFF_CB 0x0084
#define MXR_CM_COEFF_CR 0x0088
+#define MXR_MO 0x0304
+#define MXR_RESOLUTION 0x0310
+
#define MXR_GRAPHIC0_BASE_S 0x2024
#define MXR_GRAPHIC1_BASE_S 0x2044
@@ -119,6 +122,10 @@
#define MXR_GRP_WH_WIDTH(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_WH_HEIGHT(x) MXR_MASK_VAL(x, 10, 0)
+/* bits for MXR_RESOLUTION */
+#define MXR_MXR_RES_HEIGHT(x) MXR_MASK_VAL(x, 26, 16)
+#define MXR_MXR_RES_WIDTH(x) MXR_MASK_VAL(x, 10, 0)
+
/* bits for MXR_GRAPHICn_SXY */
#define MXR_GRP_SXY_SX(x) MXR_MASK_VAL(x, 26, 16)
#define MXR_GRP_SXY_SY(x) MXR_MASK_VAL(x, 10, 0)
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 91f3ac6cef35..40034ecefd3b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -36,6 +36,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
intel_overlay.o \
intel_sprite.o \
intel_opregion.o \
+ intel_sideband.o \
dvo_ch7xxx.o \
dvo_ch7017.o \
dvo_ivch.o \
diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c
index 3edd981e0770..757e0fa11043 100644
--- a/drivers/gpu/drm/i915/dvo_ch7xxx.c
+++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c
@@ -32,12 +32,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define CH7xxx_REG_DID 0x4b
#define CH7011_VID 0x83 /* 7010 as well */
+#define CH7010B_VID 0x05
#define CH7009A_VID 0x84
#define CH7009B_VID 0x85
#define CH7301_VID 0x95
#define CH7xxx_VID 0x84
#define CH7xxx_DID 0x17
+#define CH7010_DID 0x16
#define CH7xxx_NUM_REGS 0x4c
@@ -87,11 +89,20 @@ static struct ch7xxx_id_struct {
char *name;
} ch7xxx_ids[] = {
{ CH7011_VID, "CH7011" },
+ { CH7010B_VID, "CH7010B" },
{ CH7009A_VID, "CH7009A" },
{ CH7009B_VID, "CH7009B" },
{ CH7301_VID, "CH7301" },
};
+static struct ch7xxx_did_struct {
+ uint8_t did;
+ char *name;
+} ch7xxx_dids[] = {
+ { CH7xxx_DID, "CH7XXX" },
+ { CH7010_DID, "CH7010B" },
+};
+
struct ch7xxx_priv {
bool quiet;
};
@@ -108,6 +119,18 @@ static char *ch7xxx_get_id(uint8_t vid)
return NULL;
}
+static char *ch7xxx_get_did(uint8_t did)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ch7xxx_dids); i++) {
+ if (ch7xxx_dids[i].did == did)
+ return ch7xxx_dids[i].name;
+ }
+
+ return NULL;
+}
+
/** Reads an 8 bit register */
static bool ch7xxx_readb(struct intel_dvo_device *dvo, int addr, uint8_t *ch)
{
@@ -179,7 +202,7 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
/* this will detect the CH7xxx chip on the specified i2c bus */
struct ch7xxx_priv *ch7xxx;
uint8_t vendor, device;
- char *name;
+ char *name, *devid;
ch7xxx = kzalloc(sizeof(struct ch7xxx_priv), GFP_KERNEL);
if (ch7xxx == NULL)
@@ -204,7 +227,8 @@ static bool ch7xxx_init(struct intel_dvo_device *dvo,
if (!ch7xxx_readb(dvo, CH7xxx_REG_DID, &device))
goto out;
- if (device != CH7xxx_DID) {
+ devid = ch7xxx_get_did(device);
+ if (!devid) {
DRM_DEBUG_KMS("ch7xxx not detected; got 0x%02x from %s "
"slave %d.\n",
vendor, adapter->name, dvo->slave_addr);
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index e913d325d5b8..47d6c748057e 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -61,11 +61,11 @@ static int i915_capabilities(struct seq_file *m, void *data)
seq_printf(m, "gen: %d\n", info->gen);
seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev));
-#define DEV_INFO_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x))
-#define DEV_INFO_SEP ;
- DEV_INFO_FLAGS;
-#undef DEV_INFO_FLAG
-#undef DEV_INFO_SEP
+#define PRINT_FLAG(x) seq_printf(m, #x ": %s\n", yesno(info->x))
+#define SEP_SEMICOLON ;
+ DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_SEMICOLON);
+#undef PRINT_FLAG
+#undef SEP_SEMICOLON
return 0;
}
@@ -196,6 +196,32 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
} \
} while (0)
+struct file_stats {
+ int count;
+ size_t total, active, inactive, unbound;
+};
+
+static int per_file_stats(int id, void *ptr, void *data)
+{
+ struct drm_i915_gem_object *obj = ptr;
+ struct file_stats *stats = data;
+
+ stats->count++;
+ stats->total += obj->base.size;
+
+ if (obj->gtt_space) {
+ if (!list_empty(&obj->ring_list))
+ stats->active += obj->base.size;
+ else
+ stats->inactive += obj->base.size;
+ } else {
+ if (!list_empty(&obj->global_list))
+ stats->unbound += obj->base.size;
+ }
+
+ return 0;
+}
+
static int i915_gem_object_info(struct seq_file *m, void* data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -204,6 +230,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
u32 count, mappable_count, purgeable_count;
size_t size, mappable_size, purgeable_size;
struct drm_i915_gem_object *obj;
+ struct drm_file *file;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -215,7 +242,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
dev_priv->mm.object_memory);
size = count = mappable_size = mappable_count = 0;
- count_objects(&dev_priv->mm.bound_list, gtt_list);
+ count_objects(&dev_priv->mm.bound_list, global_list);
seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n",
count, mappable_count, size, mappable_size);
@@ -230,7 +257,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
count, mappable_count, size, mappable_size);
size = count = purgeable_size = purgeable_count = 0;
- list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) {
size += obj->base.size, ++count;
if (obj->madv == I915_MADV_DONTNEED)
purgeable_size += obj->base.size, ++purgeable_count;
@@ -238,7 +265,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
seq_printf(m, "%u unbound objects, %zu bytes\n", count, size);
size = count = mappable_size = mappable_count = 0;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
if (obj->fault_mappable) {
size += obj->gtt_space->size;
++count;
@@ -263,6 +290,21 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
dev_priv->gtt.total,
dev_priv->gtt.mappable_end - dev_priv->gtt.start);
+ seq_printf(m, "\n");
+ list_for_each_entry_reverse(file, &dev->filelist, lhead) {
+ struct file_stats stats;
+
+ memset(&stats, 0, sizeof(stats));
+ idr_for_each(&file->object_idr, per_file_stats, &stats);
+ seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n",
+ get_pid_task(file->pid, PIDTYPE_PID)->comm,
+ stats.count,
+ stats.total,
+ stats.active,
+ stats.inactive,
+ stats.unbound);
+ }
+
mutex_unlock(&dev->struct_mutex);
return 0;
@@ -283,7 +325,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
return ret;
total_obj_size = total_gtt_size = count = 0;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
if (list == PINNED_LIST && obj->pin_count == 0)
continue;
@@ -570,6 +612,7 @@ static const char *ring_str(int ring)
case RCS: return "render";
case VCS: return "bsd";
case BCS: return "blt";
+ case VECS: return "vebox";
default: return "";
}
}
@@ -604,73 +647,187 @@ static const char *purgeable_flag(int purgeable)
return purgeable ? " purgeable" : "";
}
-static void print_error_buffers(struct seq_file *m,
+static bool __i915_error_ok(struct drm_i915_error_state_buf *e)
+{
+
+ if (!e->err && WARN(e->bytes > (e->size - 1), "overflow")) {
+ e->err = -ENOSPC;
+ return false;
+ }
+
+ if (e->bytes == e->size - 1 || e->err)
+ return false;
+
+ return true;
+}
+
+static bool __i915_error_seek(struct drm_i915_error_state_buf *e,
+ unsigned len)
+{
+ if (e->pos + len <= e->start) {
+ e->pos += len;
+ return false;
+ }
+
+ /* First vsnprintf needs to fit in its entirety for memmove */
+ if (len >= e->size) {
+ e->err = -EIO;
+ return false;
+ }
+
+ return true;
+}
+
+static void __i915_error_advance(struct drm_i915_error_state_buf *e,
+ unsigned len)
+{
+ /* If this is first printf in this window, adjust it so that
+ * start position matches start of the buffer
+ */
+
+ if (e->pos < e->start) {
+ const size_t off = e->start - e->pos;
+
+ /* Should not happen but be paranoid */
+ if (off > len || e->bytes) {
+ e->err = -EIO;
+ return;
+ }
+
+ memmove(e->buf, e->buf + off, len - off);
+ e->bytes = len - off;
+ e->pos = e->start;
+ return;
+ }
+
+ e->bytes += len;
+ e->pos += len;
+}
+
+static void i915_error_vprintf(struct drm_i915_error_state_buf *e,
+ const char *f, va_list args)
+{
+ unsigned len;
+
+ if (!__i915_error_ok(e))
+ return;
+
+ /* Seek the first printf which is hits start position */
+ if (e->pos < e->start) {
+ len = vsnprintf(NULL, 0, f, args);
+ if (!__i915_error_seek(e, len))
+ return;
+ }
+
+ len = vsnprintf(e->buf + e->bytes, e->size - e->bytes, f, args);
+ if (len >= e->size - e->bytes)
+ len = e->size - e->bytes - 1;
+
+ __i915_error_advance(e, len);
+}
+
+static void i915_error_puts(struct drm_i915_error_state_buf *e,
+ const char *str)
+{
+ unsigned len;
+
+ if (!__i915_error_ok(e))
+ return;
+
+ len = strlen(str);
+
+ /* Seek the first printf which is hits start position */
+ if (e->pos < e->start) {
+ if (!__i915_error_seek(e, len))
+ return;
+ }
+
+ if (len >= e->size - e->bytes)
+ len = e->size - e->bytes - 1;
+ memcpy(e->buf + e->bytes, str, len);
+
+ __i915_error_advance(e, len);
+}
+
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
+{
+ va_list args;
+
+ va_start(args, f);
+ i915_error_vprintf(e, f, args);
+ va_end(args);
+}
+
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+#define err_puts(e, s) i915_error_puts(e, s)
+
+static void print_error_buffers(struct drm_i915_error_state_buf *m,
const char *name,
struct drm_i915_error_buffer *err,
int count)
{
- seq_printf(m, "%s [%d]:\n", name, count);
+ err_printf(m, "%s [%d]:\n", name, count);
while (count--) {
- seq_printf(m, " %08x %8u %02x %02x %x %x%s%s%s%s%s%s%s",
+ err_printf(m, " %08x %8u %02x %02x %x %x",
err->gtt_offset,
err->size,
err->read_domains,
err->write_domain,
- err->rseqno, err->wseqno,
- pin_flag(err->pinned),
- tiling_flag(err->tiling),
- dirty_flag(err->dirty),
- purgeable_flag(err->purgeable),
- err->ring != -1 ? " " : "",
- ring_str(err->ring),
- cache_level_str(err->cache_level));
+ err->rseqno, err->wseqno);
+ err_puts(m, pin_flag(err->pinned));
+ err_puts(m, tiling_flag(err->tiling));
+ err_puts(m, dirty_flag(err->dirty));
+ err_puts(m, purgeable_flag(err->purgeable));
+ err_puts(m, err->ring != -1 ? " " : "");
+ err_puts(m, ring_str(err->ring));
+ err_puts(m, cache_level_str(err->cache_level));
if (err->name)
- seq_printf(m, " (name: %d)", err->name);
+ err_printf(m, " (name: %d)", err->name);
if (err->fence_reg != I915_FENCE_REG_NONE)
- seq_printf(m, " (fence: %d)", err->fence_reg);
+ err_printf(m, " (fence: %d)", err->fence_reg);
- seq_printf(m, "\n");
+ err_puts(m, "\n");
err++;
}
}
-static void i915_ring_error_state(struct seq_file *m,
+static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
struct drm_device *dev,
struct drm_i915_error_state *error,
unsigned ring)
{
BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
- seq_printf(m, "%s command stream:\n", ring_str(ring));
- seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]);
- seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]);
- seq_printf(m, " CTL: 0x%08x\n", error->ctl[ring]);
- seq_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]);
- seq_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]);
- seq_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]);
- seq_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]);
+ err_printf(m, "%s command stream:\n", ring_str(ring));
+ err_printf(m, " HEAD: 0x%08x\n", error->head[ring]);
+ err_printf(m, " TAIL: 0x%08x\n", error->tail[ring]);
+ err_printf(m, " CTL: 0x%08x\n", error->ctl[ring]);
+ err_printf(m, " ACTHD: 0x%08x\n", error->acthd[ring]);
+ err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]);
+ err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]);
+ err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]);
if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
- seq_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr);
+ err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr);
if (INTEL_INFO(dev)->gen >= 4)
- seq_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]);
- seq_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]);
- seq_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]);
+ err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]);
+ err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]);
+ err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]);
if (INTEL_INFO(dev)->gen >= 6) {
- seq_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
- seq_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
- seq_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n",
+ err_printf(m, " RC PSMI: 0x%08x\n", error->rc_psmi[ring]);
+ err_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
+ err_printf(m, " SYNC_0: 0x%08x [last synced 0x%08x]\n",
error->semaphore_mboxes[ring][0],
error->semaphore_seqno[ring][0]);
- seq_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n",
+ err_printf(m, " SYNC_1: 0x%08x [last synced 0x%08x]\n",
error->semaphore_mboxes[ring][1],
error->semaphore_seqno[ring][1]);
}
- seq_printf(m, " seqno: 0x%08x\n", error->seqno[ring]);
- seq_printf(m, " waiting: %s\n", yesno(error->waiting[ring]));
- seq_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
- seq_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
+ err_printf(m, " seqno: 0x%08x\n", error->seqno[ring]);
+ err_printf(m, " waiting: %s\n", yesno(error->waiting[ring]));
+ err_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
+ err_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
}
struct i915_error_state_file_priv {
@@ -678,9 +835,11 @@ struct i915_error_state_file_priv {
struct drm_i915_error_state *error;
};
-static int i915_error_state(struct seq_file *m, void *unused)
+
+static int i915_error_state(struct i915_error_state_file_priv *error_priv,
+ struct drm_i915_error_state_buf *m)
+
{
- struct i915_error_state_file_priv *error_priv = m->private;
struct drm_device *dev = error_priv->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_error_state *error = error_priv->error;
@@ -688,34 +847,35 @@ static int i915_error_state(struct seq_file *m, void *unused)
int i, j, page, offset, elt;
if (!error) {
- seq_printf(m, "no error state collected\n");
+ err_printf(m, "no error state collected\n");
return 0;
}
- seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
+ err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
error->time.tv_usec);
- seq_printf(m, "Kernel: " UTS_RELEASE "\n");
- seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
- seq_printf(m, "EIR: 0x%08x\n", error->eir);
- seq_printf(m, "IER: 0x%08x\n", error->ier);
- seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
- seq_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
- seq_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
- seq_printf(m, "CCID: 0x%08x\n", error->ccid);
+ err_printf(m, "Kernel: " UTS_RELEASE "\n");
+ err_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
+ err_printf(m, "EIR: 0x%08x\n", error->eir);
+ err_printf(m, "IER: 0x%08x\n", error->ier);
+ err_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
+ err_printf(m, "FORCEWAKE: 0x%08x\n", error->forcewake);
+ err_printf(m, "DERRMR: 0x%08x\n", error->derrmr);
+ err_printf(m, "CCID: 0x%08x\n", error->ccid);
for (i = 0; i < dev_priv->num_fence_regs; i++)
- seq_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]);
+ err_printf(m, " fence[%d] = %08llx\n", i, error->fence[i]);
for (i = 0; i < ARRAY_SIZE(error->extra_instdone); i++)
- seq_printf(m, " INSTDONE_%d: 0x%08x\n", i, error->extra_instdone[i]);
+ err_printf(m, " INSTDONE_%d: 0x%08x\n", i,
+ error->extra_instdone[i]);
if (INTEL_INFO(dev)->gen >= 6) {
- seq_printf(m, "ERROR: 0x%08x\n", error->error);
- seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
+ err_printf(m, "ERROR: 0x%08x\n", error->error);
+ err_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
}
if (INTEL_INFO(dev)->gen == 7)
- seq_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
+ err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
for_each_ring(ring, dev_priv, i)
i915_ring_error_state(m, dev, error, i);
@@ -734,24 +894,25 @@ static int i915_error_state(struct seq_file *m, void *unused)
struct drm_i915_error_object *obj;
if ((obj = error->ring[i].batchbuffer)) {
- seq_printf(m, "%s --- gtt_offset = 0x%08x\n",
+ err_printf(m, "%s --- gtt_offset = 0x%08x\n",
dev_priv->ring[i].name,
obj->gtt_offset);
offset = 0;
for (page = 0; page < obj->page_count; page++) {
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
- seq_printf(m, "%08x : %08x\n", offset, obj->pages[page][elt]);
+ err_printf(m, "%08x : %08x\n", offset,
+ obj->pages[page][elt]);
offset += 4;
}
}
}
if (error->ring[i].num_requests) {
- seq_printf(m, "%s --- %d requests\n",
+ err_printf(m, "%s --- %d requests\n",
dev_priv->ring[i].name,
error->ring[i].num_requests);
for (j = 0; j < error->ring[i].num_requests; j++) {
- seq_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n",
+ err_printf(m, " seqno 0x%08x, emitted %ld, tail 0x%08x\n",
error->ring[i].requests[j].seqno,
error->ring[i].requests[j].jiffies,
error->ring[i].requests[j].tail);
@@ -759,13 +920,13 @@ static int i915_error_state(struct seq_file *m, void *unused)
}
if ((obj = error->ring[i].ringbuffer)) {
- seq_printf(m, "%s --- ringbuffer = 0x%08x\n",
+ err_printf(m, "%s --- ringbuffer = 0x%08x\n",
dev_priv->ring[i].name,
obj->gtt_offset);
offset = 0;
for (page = 0; page < obj->page_count; page++) {
for (elt = 0; elt < PAGE_SIZE/4; elt++) {
- seq_printf(m, "%08x : %08x\n",
+ err_printf(m, "%08x : %08x\n",
offset,
obj->pages[page][elt]);
offset += 4;
@@ -775,12 +936,12 @@ static int i915_error_state(struct seq_file *m, void *unused)
obj = error->ring[i].ctx;
if (obj) {
- seq_printf(m, "%s --- HW Context = 0x%08x\n",
+ err_printf(m, "%s --- HW Context = 0x%08x\n",
dev_priv->ring[i].name,
obj->gtt_offset);
offset = 0;
for (elt = 0; elt < PAGE_SIZE/16; elt += 4) {
- seq_printf(m, "[%04x] %08x %08x %08x %08x\n",
+ err_printf(m, "[%04x] %08x %08x %08x %08x\n",
offset,
obj->pages[0][elt],
obj->pages[0][elt+1],
@@ -806,8 +967,7 @@ i915_error_state_write(struct file *filp,
size_t cnt,
loff_t *ppos)
{
- struct seq_file *m = filp->private_data;
- struct i915_error_state_file_priv *error_priv = m->private;
+ struct i915_error_state_file_priv *error_priv = filp->private_data;
struct drm_device *dev = error_priv->dev;
int ret;
@@ -842,25 +1002,81 @@ static int i915_error_state_open(struct inode *inode, struct file *file)
kref_get(&error_priv->error->ref);
spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
- return single_open(file, i915_error_state, error_priv);
+ file->private_data = error_priv;
+
+ return 0;
}
static int i915_error_state_release(struct inode *inode, struct file *file)
{
- struct seq_file *m = file->private_data;
- struct i915_error_state_file_priv *error_priv = m->private;
+ struct i915_error_state_file_priv *error_priv = file->private_data;
if (error_priv->error)
kref_put(&error_priv->error->ref, i915_error_state_free);
kfree(error_priv);
- return single_release(inode, file);
+ return 0;
+}
+
+static ssize_t i915_error_state_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *pos)
+{
+ struct i915_error_state_file_priv *error_priv = file->private_data;
+ struct drm_i915_error_state_buf error_str;
+ loff_t tmp_pos = 0;
+ ssize_t ret_count = 0;
+ int ret = 0;
+
+ memset(&error_str, 0, sizeof(error_str));
+
+ /* We need to have enough room to store any i915_error_state printf
+ * so that we can move it to start position.
+ */
+ error_str.size = count + 1 > PAGE_SIZE ? count + 1 : PAGE_SIZE;
+ error_str.buf = kmalloc(error_str.size,
+ GFP_TEMPORARY | __GFP_NORETRY | __GFP_NOWARN);
+
+ if (error_str.buf == NULL) {
+ error_str.size = PAGE_SIZE;
+ error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
+ }
+
+ if (error_str.buf == NULL) {
+ error_str.size = 128;
+ error_str.buf = kmalloc(error_str.size, GFP_TEMPORARY);
+ }
+
+ if (error_str.buf == NULL)
+ return -ENOMEM;
+
+ error_str.start = *pos;
+
+ ret = i915_error_state(error_priv, &error_str);
+ if (ret)
+ goto out;
+
+ if (error_str.bytes == 0 && error_str.err) {
+ ret = error_str.err;
+ goto out;
+ }
+
+ ret_count = simple_read_from_buffer(userbuf, count, &tmp_pos,
+ error_str.buf,
+ error_str.bytes);
+
+ if (ret_count < 0)
+ ret = ret_count;
+ else
+ *pos = error_str.start + ret_count;
+out:
+ kfree(error_str.buf);
+ return ret ?: ret_count;
}
static const struct file_operations i915_error_state_fops = {
.owner = THIS_MODULE,
.open = i915_error_state_open,
- .read = seq_read,
+ .read = i915_error_state_read,
.write = i915_error_state_write,
.llseek = default_llseek,
.release = i915_error_state_release,
@@ -941,7 +1157,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
MEMSTAT_VID_SHIFT);
seq_printf(m, "Current P-state: %d\n",
(rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
- } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
+ } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
@@ -1009,6 +1225,26 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
seq_printf(m, "Max overclocked frequency: %dMHz\n",
dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
+ } else if (IS_VALLEYVIEW(dev)) {
+ u32 freq_sts, val;
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ freq_sts = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+ seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
+ seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
+
+ val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1);
+ seq_printf(m, "max GPU freq: %d MHz\n",
+ vlv_gpu_freq(dev_priv->mem_freq, val));
+
+ val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM);
+ seq_printf(m, "min GPU freq: %d MHz\n",
+ vlv_gpu_freq(dev_priv->mem_freq, val));
+
+ seq_printf(m, "current GPU freq: %d MHz\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ (freq_sts >> 8) & 0xff));
+ mutex_unlock(&dev_priv->rps.hw_lock);
} else {
seq_printf(m, "no P-state info available\n");
}
@@ -1290,6 +1526,25 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
return 0;
}
+static int i915_ips_status(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!HAS_IPS(dev)) {
+ seq_puts(m, "not supported\n");
+ return 0;
+ }
+
+ if (I915_READ(IPS_CTL) & IPS_ENABLE)
+ seq_puts(m, "enabled\n");
+ else
+ seq_puts(m, "disabled\n");
+
+ return 0;
+}
+
static int i915_sr_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1642,27 +1897,27 @@ static int i915_dpio_info(struct seq_file *m, void *data)
seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
seq_printf(m, "DPIO_DIV_A: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_DIV_A));
+ vlv_dpio_read(dev_priv, _DPIO_DIV_A));
seq_printf(m, "DPIO_DIV_B: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_DIV_B));
+ vlv_dpio_read(dev_priv, _DPIO_DIV_B));
seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_REFSFR_A));
+ vlv_dpio_read(dev_priv, _DPIO_REFSFR_A));
seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_REFSFR_B));
+ vlv_dpio_read(dev_priv, _DPIO_REFSFR_B));
seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
+ vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
+ vlv_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
- seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_A));
- seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n",
- intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_B));
+ seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n",
+ vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_A));
+ seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n",
+ vlv_dpio_read(dev_priv, _DPIO_LPF_COEFF_B));
seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
- intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
+ vlv_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
mutex_unlock(&dev_priv->dpio_lock);
@@ -1780,7 +2035,8 @@ i915_drop_caches_set(void *data, u64 val)
}
if (val & DROP_UNBOUND) {
- list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
+ list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
+ global_list)
if (obj->pages_pin_count == 0) {
ret = i915_gem_object_put_pages(obj);
if (ret)
@@ -1812,7 +2068,11 @@ i915_max_freq_get(void *data, u64 *val)
if (ret)
return ret;
- *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
+ if (IS_VALLEYVIEW(dev))
+ *val = vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.max_delay);
+ else
+ *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
@@ -1837,9 +2097,16 @@ i915_max_freq_set(void *data, u64 val)
/*
* Turbo will still be enabled, but won't go above the set value.
*/
- do_div(val, GT_FREQUENCY_MULTIPLIER);
- dev_priv->rps.max_delay = val;
- gen6_set_rps(dev, val);
+ if (IS_VALLEYVIEW(dev)) {
+ val = vlv_freq_opcode(dev_priv->mem_freq, val);
+ dev_priv->rps.max_delay = val;
+ gen6_set_rps(dev, val);
+ } else {
+ do_div(val, GT_FREQUENCY_MULTIPLIER);
+ dev_priv->rps.max_delay = val;
+ gen6_set_rps(dev, val);
+ }
+
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
@@ -1863,7 +2130,11 @@ i915_min_freq_get(void *data, u64 *val)
if (ret)
return ret;
- *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
+ if (IS_VALLEYVIEW(dev))
+ *val = vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.min_delay);
+ else
+ *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
@@ -1888,9 +2159,15 @@ i915_min_freq_set(void *data, u64 val)
/*
* Turbo will still be enabled, but won't go below the set value.
*/
- do_div(val, GT_FREQUENCY_MULTIPLIER);
- dev_priv->rps.min_delay = val;
- gen6_set_rps(dev, val);
+ if (IS_VALLEYVIEW(dev)) {
+ val = vlv_freq_opcode(dev_priv->mem_freq, val);
+ dev_priv->rps.min_delay = val;
+ valleyview_set_rps(dev, val);
+ } else {
+ do_div(val, GT_FREQUENCY_MULTIPLIER);
+ dev_priv->rps.min_delay = val;
+ gen6_set_rps(dev, val);
+ }
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
@@ -2057,6 +2334,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
+ {"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
{"i915_rstdby_delays", i915_rstdby_delays, 0},
{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
{"i915_delayfreq_table", i915_delayfreq_table, 0},
@@ -2066,6 +2344,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_ring_freq_table", i915_ring_freq_table, 0},
{"i915_gfxec", i915_gfxec, 0},
{"i915_fbc_status", i915_fbc_status, 0},
+ {"i915_ips_status", i915_ips_status, 0},
{"i915_sr_status", i915_sr_status, 0},
{"i915_opregion", i915_opregion, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 3b315ba85a3e..adb319b53ecd 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -42,7 +42,6 @@
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
#include <acpi/video.h>
-#include <asm/pat.h>
#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS])
@@ -956,6 +955,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_BLT:
value = intel_ring_initialized(&dev_priv->ring[BCS]);
break;
+ case I915_PARAM_HAS_VEBOX:
+ value = intel_ring_initialized(&dev_priv->ring[VECS]);
+ break;
case I915_PARAM_HAS_RELAXED_FENCING:
value = 1;
break;
@@ -999,8 +1001,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
value = 1;
break;
default:
- DRM_DEBUG_DRIVER("Unknown parameter %d\n",
- param->param);
+ DRM_DEBUG("Unknown parameter %d\n", param->param);
return -EINVAL;
}
@@ -1359,8 +1360,10 @@ static int i915_load_modeset_init(struct drm_device *dev)
cleanup_gem:
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
+ i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_aliasing_ppgtt(dev);
+ drm_mm_takedown(&dev_priv->mm.gtt_space);
cleanup_irq:
drm_irq_uninstall(dev);
cleanup_gem_stolen:
@@ -1397,29 +1400,6 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
master->driver_priv = NULL;
}
-static void
-i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base,
- unsigned long size)
-{
- dev_priv->mm.gtt_mtrr = -1;
-
-#if defined(CONFIG_X86_PAT)
- if (cpu_has_pat)
- return;
-#endif
-
- /* Set up a WC MTRR for non-PAT systems. This is more common than
- * one would think, because the kernel disables PAT on first
- * generation Core chips because WC PAT gets overridden by a UC
- * MTRR if present. Even if a UC MTRR isn't present.
- */
- dev_priv->mm.gtt_mtrr = mtrr_add(base, size, MTRR_TYPE_WRCOMB, 1);
- if (dev_priv->mm.gtt_mtrr < 0) {
- DRM_INFO("MTRR allocation failed. Graphics "
- "performance may suffer.\n");
- }
-}
-
static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
{
struct apertures_struct *ap;
@@ -1431,7 +1411,7 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
return;
ap->ranges[0].base = dev_priv->gtt.mappable_base;
- ap->ranges[0].size = dev_priv->gtt.mappable_end - dev_priv->gtt.start;
+ ap->ranges[0].size = dev_priv->gtt.mappable_end;
primary =
pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
@@ -1445,15 +1425,19 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
{
const struct intel_device_info *info = dev_priv->info;
-#define DEV_INFO_FLAG(name) info->name ? #name "," : ""
-#define DEV_INFO_SEP ,
+#define PRINT_S(name) "%s"
+#define SEP_EMPTY
+#define PRINT_FLAG(name) info->name ? #name "," : ""
+#define SEP_COMMA ,
DRM_DEBUG_DRIVER("i915 device info: gen=%i, pciid=0x%04x flags="
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ DEV_INFO_FOR_EACH_FLAG(PRINT_S, SEP_EMPTY),
info->gen,
dev_priv->dev->pdev->device,
- DEV_INFO_FLAGS);
-#undef DEV_INFO_FLAG
-#undef DEV_INFO_SEP
+ DEV_INFO_FOR_EACH_FLAG(PRINT_FLAG, SEP_COMMA));
+#undef PRINT_S
+#undef SEP_EMPTY
+#undef PRINT_FLAG
+#undef SEP_COMMA
}
/**
@@ -1468,7 +1452,7 @@ static void intel_early_sanitize_regs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (IS_HASWELL(dev))
+ if (HAS_FPGA_DBG_UNCLAIMED(dev))
I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
}
@@ -1574,8 +1558,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_rmmap;
}
- i915_mtrr_setup(dev_priv, dev_priv->gtt.mappable_base,
- aperture_size);
+ dev_priv->mm.gtt_mtrr = arch_phys_wc_add(dev_priv->gtt.mappable_base,
+ aperture_size);
/* The i915 workqueue is primarily used for batched retirement of
* requests (and thus managing bo) once the task has been completed
@@ -1629,6 +1613,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->gpu_error.lock);
spin_lock_init(&dev_priv->rps.lock);
+ spin_lock_init(&dev_priv->backlight.lock);
mutex_init(&dev_priv->dpio_lock);
mutex_init(&dev_priv->rps.hw_lock);
@@ -1647,6 +1632,9 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
/* Start out suspended */
dev_priv->mm.suspended = 1;
+ if (HAS_POWER_WELL(dev))
+ i915_init_power_well(dev);
+
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
ret = i915_load_modeset_init(dev);
if (ret < 0) {
@@ -1679,12 +1667,7 @@ out_gem_unload:
intel_teardown_mchbar(dev);
destroy_workqueue(dev_priv->wq);
out_mtrrfree:
- if (dev_priv->mm.gtt_mtrr >= 0) {
- mtrr_del(dev_priv->mm.gtt_mtrr,
- dev_priv->gtt.mappable_base,
- aperture_size);
- dev_priv->mm.gtt_mtrr = -1;
- }
+ arch_phys_wc_del(dev_priv->mm.gtt_mtrr);
io_mapping_free(dev_priv->gtt.mappable);
dev_priv->gtt.gtt_remove(dev);
out_rmmap:
@@ -1703,6 +1686,9 @@ int i915_driver_unload(struct drm_device *dev)
intel_gpu_ips_teardown();
+ if (HAS_POWER_WELL(dev))
+ i915_remove_power_well(dev);
+
i915_teardown_sysfs(dev);
if (dev_priv->mm.inactive_shrinker.shrink)
@@ -1719,12 +1705,7 @@ int i915_driver_unload(struct drm_device *dev)
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
io_mapping_free(dev_priv->gtt.mappable);
- if (dev_priv->mm.gtt_mtrr >= 0) {
- mtrr_del(dev_priv->mm.gtt_mtrr,
- dev_priv->gtt.mappable_base,
- dev_priv->gtt.mappable_end);
- dev_priv->mm.gtt_mtrr = -1;
- }
+ arch_phys_wc_del(dev_priv->mm.gtt_mtrr);
acpi_video_unregister();
@@ -1737,10 +1718,10 @@ int i915_driver_unload(struct drm_device *dev)
* free the memory space allocated for the child device
* config parsed from VBT
*/
- if (dev_priv->child_dev && dev_priv->child_dev_num) {
- kfree(dev_priv->child_dev);
- dev_priv->child_dev = NULL;
- dev_priv->child_dev_num = 0;
+ if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) {
+ kfree(dev_priv->vbt.child_dev);
+ dev_priv->vbt.child_dev = NULL;
+ dev_priv->vbt.child_dev_num = 0;
}
vga_switcheroo_unregister_client(dev->pdev);
@@ -1773,6 +1754,7 @@ int i915_driver_unload(struct drm_device *dev)
i915_free_hws(dev);
}
+ drm_mm_takedown(&dev_priv->mm.gtt_space);
if (dev_priv->regs != NULL)
pci_iounmap(dev->pdev, dev_priv->regs);
@@ -1782,6 +1764,8 @@ int i915_driver_unload(struct drm_device *dev)
destroy_workqueue(dev_priv->wq);
pm_qos_remove_request(&dev_priv->pm_qos);
+ dev_priv->gtt.gtt_remove(dev);
+
if (dev_priv->slab)
kmem_cache_destroy(dev_priv->slab);
@@ -1796,7 +1780,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file)
struct drm_i915_file_private *file_priv;
DRM_DEBUG_DRIVER("\n");
- file_priv = kmalloc(sizeof(*file_priv), GFP_KERNEL);
+ file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
if (!file_priv)
return -ENOMEM;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index a2e4953b8e8d..062cbda1bf4a 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -128,6 +128,10 @@ module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
MODULE_PARM_DESC(disable_power_well,
"Disable the power well when possible (default: false)");
+int i915_enable_ips __read_mostly = 1;
+module_param_named(enable_ips, i915_enable_ips, int, 0600);
+MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
+
static struct drm_driver driver;
extern int intel_agp_enabled;
@@ -280,6 +284,7 @@ static const struct intel_device_info intel_ivybridge_m_info = {
GEN7_FEATURES,
.is_ivybridge = 1,
.is_mobile = 1,
+ .has_fbc = 1,
};
static const struct intel_device_info intel_ivybridge_q_info = {
@@ -308,12 +313,19 @@ static const struct intel_device_info intel_valleyview_d_info = {
static const struct intel_device_info intel_haswell_d_info = {
GEN7_FEATURES,
.is_haswell = 1,
+ .has_ddi = 1,
+ .has_fpga_dbg = 1,
+ .has_vebox_ring = 1,
};
static const struct intel_device_info intel_haswell_m_info = {
GEN7_FEATURES,
.is_haswell = 1,
.is_mobile = 1,
+ .has_ddi = 1,
+ .has_fpga_dbg = 1,
+ .has_fbc = 1,
+ .has_vebox_ring = 1,
};
static const struct pci_device_id pciidlist[] = { /* aka */
@@ -445,7 +457,6 @@ void intel_detect_pch(struct drm_device *dev)
*/
if (INTEL_INFO(dev)->num_pipes == 0) {
dev_priv->pch_type = PCH_NOP;
- dev_priv->num_pch_pll = 0;
return;
}
@@ -454,9 +465,15 @@ void intel_detect_pch(struct drm_device *dev)
* make graphics device passthrough work easy for VMM, that only
* need to expose ISA bridge to let driver know the real hardware
* underneath. This is a requirement from virtualization team.
+ *
+ * In some virtualized environments (e.g. XEN), there is irrelevant
+ * ISA bridge in the system. To work reliably, we should scan trhough
+ * all the ISA bridge devices and check for the first match, instead
+ * of only checking the first one.
*/
pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
- if (pch) {
+ while (pch) {
+ struct pci_dev *curr = pch;
if (pch->vendor == PCI_VENDOR_ID_INTEL) {
unsigned short id;
id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
@@ -464,37 +481,39 @@ void intel_detect_pch(struct drm_device *dev)
if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_IBX;
- dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
WARN_ON(!IS_GEN5(dev));
} else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_CPT;
- dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found CougarPoint PCH\n");
WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev)));
} else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
/* PantherPoint is CPT compatible */
dev_priv->pch_type = PCH_CPT;
- dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found PatherPoint PCH\n");
WARN_ON(!(IS_GEN6(dev) || IS_IVYBRIDGE(dev)));
} else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_LPT;
- dev_priv->num_pch_pll = 0;
DRM_DEBUG_KMS("Found LynxPoint PCH\n");
WARN_ON(!IS_HASWELL(dev));
WARN_ON(IS_ULT(dev));
} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_LPT;
- dev_priv->num_pch_pll = 0;
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
WARN_ON(!IS_HASWELL(dev));
WARN_ON(!IS_ULT(dev));
+ } else {
+ goto check_next;
}
- BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
+ pci_dev_put(pch);
+ break;
}
- pci_dev_put(pch);
+check_next:
+ pch = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, curr);
+ pci_dev_put(curr);
}
+ if (!pch)
+ DRM_DEBUG_KMS("No PCH found?\n");
}
bool i915_semaphore_is_enabled(struct drm_device *dev)
@@ -549,6 +568,8 @@ static int i915_drm_freeze(struct drm_device *dev)
*/
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
dev_priv->display.crtc_disable(crtc);
+
+ intel_modeset_suspend_hw(dev);
}
i915_save_state(dev);
@@ -556,7 +577,7 @@ static int i915_drm_freeze(struct drm_device *dev)
intel_opregion_fini(dev);
console_lock();
- intel_fbdev_set_suspend(dev, 1);
+ intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
console_unlock();
return 0;
@@ -600,7 +621,7 @@ void intel_console_resume(struct work_struct *work)
struct drm_device *dev = dev_priv->dev;
console_lock();
- intel_fbdev_set_suspend(dev, 0);
+ intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
console_unlock();
}
@@ -669,7 +690,7 @@ static int __i915_drm_thaw(struct drm_device *dev)
* path of resume if possible.
*/
if (console_trylock()) {
- intel_fbdev_set_suspend(dev, 0);
+ intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
console_unlock();
} else {
schedule_work(&dev_priv->console_resume_work);
@@ -855,37 +876,14 @@ static int gen6_do_reset(struct drm_device *dev)
int intel_gpu_reset(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret = -ENODEV;
-
switch (INTEL_INFO(dev)->gen) {
case 7:
- case 6:
- ret = gen6_do_reset(dev);
- break;
- case 5:
- ret = ironlake_do_reset(dev);
- break;
- case 4:
- ret = i965_do_reset(dev);
- break;
- case 2:
- ret = i8xx_do_reset(dev);
- break;
- }
-
- /* Also reset the gpu hangman. */
- if (dev_priv->gpu_error.stop_rings) {
- DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
- dev_priv->gpu_error.stop_rings = 0;
- if (ret == -ENODEV) {
- DRM_ERROR("Reset not implemented, but ignoring "
- "error for simulated gpu hangs\n");
- ret = 0;
- }
+ case 6: return gen6_do_reset(dev);
+ case 5: return ironlake_do_reset(dev);
+ case 4: return i965_do_reset(dev);
+ case 2: return i8xx_do_reset(dev);
+ default: return -ENODEV;
}
-
- return ret;
}
/**
@@ -906,6 +904,7 @@ int intel_gpu_reset(struct drm_device *dev)
int i915_reset(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ bool simulated;
int ret;
if (!i915_try_reset)
@@ -915,13 +914,26 @@ int i915_reset(struct drm_device *dev)
i915_gem_reset(dev);
- ret = -ENODEV;
- if (get_seconds() - dev_priv->gpu_error.last_reset < 5)
+ simulated = dev_priv->gpu_error.stop_rings != 0;
+
+ if (!simulated && get_seconds() - dev_priv->gpu_error.last_reset < 5) {
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
- else
+ ret = -ENODEV;
+ } else {
ret = intel_gpu_reset(dev);
- dev_priv->gpu_error.last_reset = get_seconds();
+ /* Also reset the gpu hangman. */
+ if (simulated) {
+ DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
+ dev_priv->gpu_error.stop_rings = 0;
+ if (ret == -ENODEV) {
+ DRM_ERROR("Reset not implemented, but ignoring "
+ "error for simulated gpu hangs\n");
+ ret = 0;
+ }
+ } else
+ dev_priv->gpu_error.last_reset = get_seconds();
+ }
if (ret) {
DRM_ERROR("Failed to reset chip.\n");
mutex_unlock(&dev->struct_mutex);
@@ -984,12 +996,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct intel_device_info *intel_info =
(struct intel_device_info *) ent->driver_data;
- if (intel_info->is_valleyview)
- if(!i915_preliminary_hw_support) {
- DRM_ERROR("Preliminary hardware support disabled\n");
- return -ENODEV;
- }
-
/* Only bind to function 0 of the device. Early generations
* used function 1 as a placeholder for multi-head. This causes
* us confusion instead, especially on the systems where both
@@ -1218,16 +1224,16 @@ MODULE_LICENSE("GPL and additional rights");
static void
ilk_dummy_write(struct drm_i915_private *dev_priv)
{
- /* WaIssueDummyWriteToWakeupFromRC6: Issue a dummy write to wake up the
- * chip from rc6 before touching it for real. MI_MODE is masked, hence
- * harmless to write 0 into. */
+ /* WaIssueDummyWriteToWakeupFromRC6:ilk Issue a dummy write to wake up
+ * the chip from rc6 before touching it for real. MI_MODE is masked,
+ * hence harmless to write 0 into. */
I915_WRITE_NOTRACE(MI_MODE, 0);
}
static void
hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
{
- if (IS_HASWELL(dev_priv->dev) &&
+ if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
(I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
DRM_ERROR("Unknown unclaimed register before writing to %x\n",
reg);
@@ -1238,7 +1244,7 @@ hsw_unclaimed_reg_clear(struct drm_i915_private *dev_priv, u32 reg)
static void
hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
{
- if (IS_HASWELL(dev_priv->dev) &&
+ if (HAS_FPGA_DBG_UNCLAIMED(dev_priv->dev) &&
(I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
DRM_ERROR("Unclaimed write to %x\n", reg);
I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9669a0b8b440..a416645bcd23 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -76,6 +76,8 @@ enum plane {
};
#define plane_name(p) ((p) + 'A')
+#define sprite_name(p, s) ((p) * dev_priv->num_plane + (s) + 'A')
+
enum port {
PORT_A = 0,
PORT_B,
@@ -86,6 +88,24 @@ enum port {
};
#define port_name(p) ((p) + 'A')
+enum intel_display_power_domain {
+ POWER_DOMAIN_PIPE_A,
+ POWER_DOMAIN_PIPE_B,
+ POWER_DOMAIN_PIPE_C,
+ POWER_DOMAIN_PIPE_A_PANEL_FITTER,
+ POWER_DOMAIN_PIPE_B_PANEL_FITTER,
+ POWER_DOMAIN_PIPE_C_PANEL_FITTER,
+ POWER_DOMAIN_TRANSCODER_A,
+ POWER_DOMAIN_TRANSCODER_B,
+ POWER_DOMAIN_TRANSCODER_C,
+ POWER_DOMAIN_TRANSCODER_EDP = POWER_DOMAIN_TRANSCODER_A + 0xF,
+};
+
+#define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
+#define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
+ ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER)
+#define POWER_DOMAIN_TRANSCODER(tran) ((tran) + POWER_DOMAIN_TRANSCODER_A)
+
enum hpd_pin {
HPD_NONE = 0,
HPD_PORT_A = HPD_NONE, /* PORT_A is internal */
@@ -112,15 +132,38 @@ enum hpd_pin {
list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
if ((intel_encoder)->base.crtc == (__crtc))
-struct intel_pch_pll {
+struct drm_i915_private;
+
+enum intel_dpll_id {
+ DPLL_ID_PRIVATE = -1, /* non-shared dpll in use */
+ /* real shared dpll ids must be >= 0 */
+ DPLL_ID_PCH_PLL_A,
+ DPLL_ID_PCH_PLL_B,
+};
+#define I915_NUM_PLLS 2
+
+struct intel_dpll_hw_state {
+ uint32_t dpll;
+ uint32_t fp0;
+ uint32_t fp1;
+};
+
+struct intel_shared_dpll {
int refcount; /* count of number of CRTCs sharing this PLL */
int active; /* count of number of active CRTCs (i.e. DPMS on) */
bool on; /* is the PLL actually active? Disabled during modeset */
- int pll_reg;
- int fp0_reg;
- int fp1_reg;
+ const char *name;
+ /* should match the index in the dev_priv->shared_dplls array */
+ enum intel_dpll_id id;
+ struct intel_dpll_hw_state hw_state;
+ void (*enable)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
+ void (*disable)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
+ bool (*get_hw_state)(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
};
-#define I915_NUM_PLLS 2
/* Used by dp and fdi links */
struct intel_link_m_n {
@@ -175,7 +218,6 @@ struct opregion_header;
struct opregion_acpi;
struct opregion_swsci;
struct opregion_asle;
-struct drm_i915_private;
struct intel_opregion {
struct opregion_header __iomem *header;
@@ -286,6 +328,8 @@ struct drm_i915_error_state {
struct intel_crtc_config;
struct intel_crtc;
+struct intel_limit;
+struct dpll;
struct drm_i915_display_funcs {
bool (*fbc_enabled)(struct drm_device *dev);
@@ -293,11 +337,28 @@ struct drm_i915_display_funcs {
void (*disable_fbc)(struct drm_device *dev);
int (*get_display_clock_speed)(struct drm_device *dev);
int (*get_fifo_size)(struct drm_device *dev, int plane);
+ /**
+ * find_dpll() - Find the best values for the PLL
+ * @limit: limits for the PLL
+ * @crtc: current CRTC
+ * @target: target frequency in kHz
+ * @refclk: reference clock frequency in kHz
+ * @match_clock: if provided, @best_clock P divider must
+ * match the P divider from @match_clock
+ * used for LVDS downclocking
+ * @best_clock: best PLL values found
+ *
+ * Returns true on success, false on failure.
+ */
+ bool (*find_dpll)(const struct intel_limit *limit,
+ struct drm_crtc *crtc,
+ int target, int refclk,
+ struct dpll *match_clock,
+ struct dpll *best_clock);
void (*update_wm)(struct drm_device *dev);
void (*update_sprite_wm)(struct drm_device *dev, int pipe,
- uint32_t sprite_width, int pixel_size);
- void (*update_linetime_wm)(struct drm_device *dev, int pipe,
- struct drm_display_mode *mode);
+ uint32_t sprite_width, int pixel_size,
+ bool enable);
void (*modeset_global_resources)(struct drm_device *dev);
/* Returns the active state of the crtc, and if the crtc is active,
* fills out the pipe-config with the hw state. */
@@ -331,68 +392,56 @@ struct drm_i915_gt_funcs {
void (*force_wake_put)(struct drm_i915_private *dev_priv);
};
-#define DEV_INFO_FLAGS \
- DEV_INFO_FLAG(is_mobile) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_i85x) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_i915g) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_i945gm) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_g33) DEV_INFO_SEP \
- DEV_INFO_FLAG(need_gfx_hws) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_g4x) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_pineview) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_broadwater) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_crestline) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_ivybridge) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_valleyview) DEV_INFO_SEP \
- DEV_INFO_FLAG(is_haswell) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_force_wake) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_fbc) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_pipe_cxsr) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_hotplug) DEV_INFO_SEP \
- DEV_INFO_FLAG(cursor_needs_physical) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_overlay) DEV_INFO_SEP \
- DEV_INFO_FLAG(overlay_needs_physical) DEV_INFO_SEP \
- DEV_INFO_FLAG(supports_tv) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_bsd_ring) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_blt_ring) DEV_INFO_SEP \
- DEV_INFO_FLAG(has_llc)
+#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
+ func(is_mobile) sep \
+ func(is_i85x) sep \
+ func(is_i915g) sep \
+ func(is_i945gm) sep \
+ func(is_g33) sep \
+ func(need_gfx_hws) sep \
+ func(is_g4x) sep \
+ func(is_pineview) sep \
+ func(is_broadwater) sep \
+ func(is_crestline) sep \
+ func(is_ivybridge) sep \
+ func(is_valleyview) sep \
+ func(is_haswell) sep \
+ func(has_force_wake) sep \
+ func(has_fbc) sep \
+ func(has_pipe_cxsr) sep \
+ func(has_hotplug) sep \
+ func(cursor_needs_physical) sep \
+ func(has_overlay) sep \
+ func(overlay_needs_physical) sep \
+ func(supports_tv) sep \
+ func(has_bsd_ring) sep \
+ func(has_blt_ring) sep \
+ func(has_vebox_ring) sep \
+ func(has_llc) sep \
+ func(has_ddi) sep \
+ func(has_fpga_dbg)
+
+#define DEFINE_FLAG(name) u8 name:1
+#define SEP_SEMICOLON ;
struct intel_device_info {
u32 display_mmio_offset;
u8 num_pipes:3;
u8 gen;
- u8 is_mobile:1;
- u8 is_i85x:1;
- u8 is_i915g:1;
- u8 is_i945gm:1;
- u8 is_g33:1;
- u8 need_gfx_hws:1;
- u8 is_g4x:1;
- u8 is_pineview:1;
- u8 is_broadwater:1;
- u8 is_crestline:1;
- u8 is_ivybridge:1;
- u8 is_valleyview:1;
- u8 has_force_wake:1;
- u8 is_haswell:1;
- u8 has_fbc:1;
- u8 has_pipe_cxsr:1;
- u8 has_hotplug:1;
- u8 cursor_needs_physical:1;
- u8 has_overlay:1;
- u8 overlay_needs_physical:1;
- u8 supports_tv:1;
- u8 has_bsd_ring:1;
- u8 has_blt_ring:1;
- u8 has_llc:1;
+ DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
};
+#undef DEFINE_FLAG
+#undef SEP_SEMICOLON
+
enum i915_cache_level {
I915_CACHE_NONE = 0,
I915_CACHE_LLC,
I915_CACHE_LLC_MLC, /* gen6+, in docs at least! */
};
+typedef uint32_t gen6_gtt_pte_t;
+
/* The Graphics Translation Table is the way in which GEN hardware translates a
* Graphics Virtual Address into a Physical Address. In addition to the normal
* collateral associated with any va->pa translations GEN hardware also has a
@@ -428,6 +477,9 @@ struct i915_gtt {
struct sg_table *st,
unsigned int pg_start,
enum i915_cache_level cache_level);
+ gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev,
+ dma_addr_t addr,
+ enum i915_cache_level level);
};
#define gtt_total_entries(gtt) ((gtt).total >> PAGE_SHIFT)
@@ -449,19 +501,31 @@ struct i915_hw_ppgtt {
struct sg_table *st,
unsigned int pg_start,
enum i915_cache_level cache_level);
+ gen6_gtt_pte_t (*pte_encode)(struct drm_device *dev,
+ dma_addr_t addr,
+ enum i915_cache_level level);
int (*enable)(struct drm_device *dev);
void (*cleanup)(struct i915_hw_ppgtt *ppgtt);
};
+struct i915_ctx_hang_stats {
+ /* This context had batch pending when hang was declared */
+ unsigned batch_pending;
+
+ /* This context had batch active when hang was declared */
+ unsigned batch_active;
+};
/* This must match up with the value previously used for execbuf2.rsvd1. */
#define DEFAULT_CONTEXT_ID 0
struct i915_hw_context {
+ struct kref ref;
int id;
bool is_initialized;
struct drm_i915_file_private *file_priv;
struct intel_ring_buffer *ring;
struct drm_i915_gem_object *obj;
+ struct i915_ctx_hang_stats hang_stats;
};
enum no_fbc_reason {
@@ -658,6 +722,7 @@ struct i915_suspend_saved_registers {
struct intel_gen6_power_mgmt {
struct work_struct work;
+ struct delayed_work vlv_work;
u32 pm_iir;
/* lock - irqsave spinlock that protectects the work_struct and
* pm_iir. */
@@ -668,6 +733,7 @@ struct intel_gen6_power_mgmt {
u8 cur_delay;
u8 min_delay;
u8 max_delay;
+ u8 rpe_delay;
u8 hw_max;
struct delayed_work delayed_resume_work;
@@ -704,6 +770,15 @@ struct intel_ilk_power_mgmt {
struct drm_i915_gem_object *renderctx;
};
+/* Power well structure for haswell */
+struct i915_power_well {
+ struct drm_device *device;
+ spinlock_t lock;
+ /* power well enable/disable usage count */
+ int count;
+ int i915_request;
+};
+
struct i915_dri1_state {
unsigned allow_batchbuffer : 1;
u32 __iomem *gfx_hws_cpu_addr;
@@ -812,14 +887,20 @@ struct i915_gem_mm {
u32 object_count;
};
+struct drm_i915_error_state_buf {
+ unsigned bytes;
+ unsigned size;
+ int err;
+ u8 *buf;
+ loff_t start;
+ loff_t pos;
+};
+
struct i915_gpu_error {
/* For hangcheck timer */
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
#define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD)
struct timer_list hangcheck_timer;
- int hangcheck_count;
- uint32_t last_acthd[I915_NUM_RINGS];
- uint32_t prev_instdone[I915_NUM_INSTDONE_REG];
/* For reset and error_state handling. */
spinlock_t lock;
@@ -875,6 +956,37 @@ enum modeset_restore {
MODESET_SUSPENDED,
};
+struct intel_vbt_data {
+ struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
+ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
+
+ /* Feature bits */
+ unsigned int int_tv_support:1;
+ unsigned int lvds_dither:1;
+ unsigned int lvds_vbt:1;
+ unsigned int int_crt_support:1;
+ unsigned int lvds_use_ssc:1;
+ unsigned int display_clock_mode:1;
+ unsigned int fdi_rx_polarity_inverted:1;
+ int lvds_ssc_freq;
+ unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
+
+ /* eDP */
+ int edp_rate;
+ int edp_lanes;
+ int edp_preemphasis;
+ int edp_vswing;
+ bool edp_initialized;
+ bool edp_support;
+ int edp_bpp;
+ struct edp_power_seq edp_pps;
+
+ int crt_ddc_pin;
+
+ int child_dev_num;
+ struct child_device_config *child_dev;
+};
+
typedef struct drm_i915_private {
struct drm_device *dev;
struct kmem_cache *slab;
@@ -941,9 +1053,9 @@ typedef struct drm_i915_private {
HPD_MARK_DISABLED = 2
} hpd_mark;
} hpd_stats[HPD_NUM_PINS];
+ u32 hpd_event_bits;
struct timer_list hotplug_reenable_timer;
- int num_pch_pll;
int num_plane;
unsigned long cfb_size;
@@ -953,6 +1065,7 @@ typedef struct drm_i915_private {
struct intel_fbc_work *fbc_work;
struct intel_opregion opregion;
+ struct intel_vbt_data vbt;
/* overlay */
struct intel_overlay *overlay;
@@ -962,37 +1075,15 @@ typedef struct drm_i915_private {
struct {
int level;
bool enabled;
+ spinlock_t lock; /* bl registers and the above bl fields */
struct backlight_device *device;
} backlight;
/* LVDS info */
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
-
- /* Feature bits from the VBIOS */
- unsigned int int_tv_support:1;
- unsigned int lvds_dither:1;
- unsigned int lvds_vbt:1;
- unsigned int int_crt_support:1;
- unsigned int lvds_use_ssc:1;
- unsigned int display_clock_mode:1;
- unsigned int fdi_rx_polarity_inverted:1;
- int lvds_ssc_freq;
- unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
- struct {
- int rate;
- int lanes;
- int preemphasis;
- int vswing;
-
- bool initialized;
- bool support;
- int bpp;
- struct edp_power_seq pps;
- } edp;
bool no_aux_handshake;
- int crt_ddc_pin;
struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
@@ -1020,16 +1111,13 @@ typedef struct drm_i915_private {
/* Kernel Modesetting */
struct sdvo_device_mapping sdvo_mappings[2];
- /* indicate whether the LVDS_BORDER should be enabled or not */
- unsigned int lvds_border_bits;
- /* Panel fitter placement and size for Ironlake+ */
- u32 pch_pf_pos, pch_pf_size;
struct drm_crtc *plane_to_crtc_mapping[3];
struct drm_crtc *pipe_to_crtc_mapping[3];
wait_queue_head_t pending_flip_queue;
- struct intel_pch_pll pch_plls[I915_NUM_PLLS];
+ int num_shared_dpll;
+ struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
struct intel_ddi_plls ddi_plls;
/* Reclocking support */
@@ -1038,8 +1126,6 @@ typedef struct drm_i915_private {
/* indicates the reduced downclock for LVDS*/
int lvds_downclock;
u16 orig_clock;
- int child_dev_num;
- struct child_device_config *child_dev;
bool mchbar_need_disable;
@@ -1052,6 +1138,9 @@ typedef struct drm_i915_private {
* mchdev_lock in intel_pm.c */
struct intel_ilk_power_mgmt ips;
+ /* Haswell power well */
+ struct i915_power_well power_well;
+
enum no_fbc_reason no_fbc_reason;
struct drm_mm_node *compressed_fb;
@@ -1059,6 +1148,8 @@ typedef struct drm_i915_private {
struct i915_gpu_error gpu_error;
+ struct drm_i915_gem_object *vlv_pctx;
+
/* list of fbdev register on this device */
struct intel_fbdev *fbdev;
@@ -1124,7 +1215,7 @@ struct drm_i915_gem_object {
struct drm_mm_node *gtt_space;
/** Stolen memory for this object, instead of being backed by shmem. */
struct drm_mm_node *stolen;
- struct list_head gtt_list;
+ struct list_head global_list;
/** This object's place on the active/inactive lists */
struct list_head ring_list;
@@ -1271,9 +1362,18 @@ struct drm_i915_gem_request {
/** GEM sequence number associated with this request. */
uint32_t seqno;
- /** Postion in the ringbuffer of the end of the request */
+ /** Position in the ringbuffer of the start of the request */
+ u32 head;
+
+ /** Position in the ringbuffer of the end of the request */
u32 tail;
+ /** Context related to this request */
+ struct i915_hw_context *ctx;
+
+ /** Batch buffer related to this request if any */
+ struct drm_i915_gem_object *batch_obj;
+
/** Time at which this request was emitted, in jiffies. */
unsigned long emitted_jiffies;
@@ -1291,6 +1391,8 @@ struct drm_i915_file_private {
struct list_head request_list;
} mm;
struct idr context_idr;
+
+ struct i915_ctx_hang_stats hang_stats;
};
#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info)
@@ -1341,6 +1443,7 @@ struct drm_i915_file_private {
#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
+#define HAS_VEBOX(dev) (INTEL_INFO(dev)->has_vebox_ring)
#define HAS_LLC(dev) (INTEL_INFO(dev)->has_llc)
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
@@ -1371,10 +1474,13 @@ struct drm_i915_file_private {
#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
+#define HAS_IPS(dev) (IS_ULT(dev))
+
#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
-#define HAS_DDI(dev) (IS_HASWELL(dev))
+#define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi)
#define HAS_POWER_WELL(dev) (IS_HASWELL(dev))
+#define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg)
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
@@ -1435,6 +1541,7 @@ extern bool i915_enable_hangcheck __read_mostly;
extern int i915_enable_ppgtt __read_mostly;
extern unsigned int i915_preliminary_hw_support __read_mostly;
extern int i915_disable_power_well __read_mostly;
+extern int i915_enable_ips __read_mostly;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
@@ -1486,8 +1593,6 @@ i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
void
i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
-void intel_enable_asle(struct drm_device *dev);
-
#ifdef CONFIG_DEBUG_FS
extern void i915_destroy_error_state(struct drm_device *dev);
#else
@@ -1626,6 +1731,7 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
{
if (obj->fence_reg != I915_FENCE_REG_NONE) {
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0);
dev_priv->fence_regs[obj->fence_reg].pin_count--;
}
}
@@ -1658,9 +1764,12 @@ void i915_gem_init_swizzling(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int __must_check i915_gpu_idle(struct drm_device *dev);
int __must_check i915_gem_idle(struct drm_device *dev);
-int i915_add_request(struct intel_ring_buffer *ring,
- struct drm_file *file,
- u32 *seqno);
+int __i915_add_request(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ struct drm_i915_gem_object *batch_obj,
+ u32 *seqno);
+#define i915_add_request(ring, seqno) \
+ __i915_add_request(ring, NULL, NULL, seqno)
int __must_check i915_wait_seqno(struct intel_ring_buffer *ring,
uint32_t seqno);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
@@ -1705,6 +1814,21 @@ void i915_gem_context_fini(struct drm_device *dev);
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
int i915_switch_context(struct intel_ring_buffer *ring,
struct drm_file *file, int to_id);
+void i915_gem_context_free(struct kref *ctx_ref);
+static inline void i915_gem_context_reference(struct i915_hw_context *ctx)
+{
+ kref_get(&ctx->ref);
+}
+
+static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)
+{
+ kref_put(&ctx->ref, i915_gem_context_free);
+}
+
+struct i915_ctx_hang_stats * __must_check
+i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ u32 id);
int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
@@ -1786,6 +1910,8 @@ void i915_gem_dump_object(struct drm_i915_gem_object *obj, int len,
/* i915_debugfs.c */
int i915_debugfs_init(struct drm_minor *minor);
void i915_debugfs_cleanup(struct drm_minor *minor);
+__printf(2, 3)
+void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...);
/* i915_suspend.c */
extern int i915_save_state(struct drm_device *dev);
@@ -1802,7 +1928,7 @@ void i915_teardown_sysfs(struct drm_device *dev_priv);
/* intel_i2c.c */
extern int intel_setup_gmbus(struct drm_device *dev);
extern void intel_teardown_gmbus(struct drm_device *dev);
-extern inline bool intel_gmbus_is_port_valid(unsigned port)
+static inline bool intel_gmbus_is_port_valid(unsigned port)
{
return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD);
}
@@ -1811,7 +1937,7 @@ extern struct i2c_adapter *intel_gmbus_get_adapter(
struct drm_i915_private *dev_priv, unsigned port);
extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
-extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
+static inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
{
return container_of(adapter, struct intel_gmbus, adapter)->force_bit;
}
@@ -1823,14 +1949,10 @@ extern int intel_opregion_setup(struct drm_device *dev);
extern void intel_opregion_init(struct drm_device *dev);
extern void intel_opregion_fini(struct drm_device *dev);
extern void intel_opregion_asle_intr(struct drm_device *dev);
-extern void intel_opregion_gse_intr(struct drm_device *dev);
-extern void intel_opregion_enable_asle(struct drm_device *dev);
#else
static inline void intel_opregion_init(struct drm_device *dev) { return; }
static inline void intel_opregion_fini(struct drm_device *dev) { return; }
static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; }
-static inline void intel_opregion_gse_intr(struct drm_device *dev) { return; }
-static inline void intel_opregion_enable_asle(struct drm_device *dev) { return; }
#endif
/* intel_acpi.c */
@@ -1844,6 +1966,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
/* modesetting */
extern void intel_modeset_init_hw(struct drm_device *dev);
+extern void intel_modeset_suspend_hw(struct drm_device *dev);
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
@@ -1856,6 +1979,9 @@ extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void intel_init_pch_refclk(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val);
+extern void valleyview_set_rps(struct drm_device *dev, u8 val);
+extern int valleyview_rps_max_freq(struct drm_i915_private *dev_priv);
+extern int valleyview_rps_min_freq(struct drm_i915_private *dev_priv);
extern void intel_detect_pch(struct drm_device *dev);
extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
extern int intel_enable_rc6(const struct drm_device *dev);
@@ -1867,10 +1993,11 @@ int i915_reg_read_ioctl(struct drm_device *dev, void *data,
/* overlay */
#ifdef CONFIG_DEBUG_FS
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
-extern void intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error);
+extern void intel_overlay_print_error_state(struct drm_i915_error_state_buf *e,
+ struct intel_overlay_error_state *error);
extern struct intel_display_error_state *intel_display_capture_error_state(struct drm_device *dev);
-extern void intel_display_print_error_state(struct seq_file *m,
+extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
struct drm_device *dev,
struct intel_display_error_state *error);
#endif
@@ -1885,8 +2012,20 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
-int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val);
-int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+
+/* intel_sideband.c */
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr);
+void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr);
+u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg);
+void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val);
+u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
+ enum intel_sbi_destination destination);
+void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
+ enum intel_sbi_destination destination);
+
+int vlv_gpu_freq(int ddr_freq, int val);
+int vlv_freq_opcode(int ddr_freq, int val);
#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 9e35dafc5807..4200c32407ec 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -176,7 +176,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
pinned = 0;
mutex_lock(&dev->struct_mutex);
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
if (obj->pin_count)
pinned += obj->gtt_space->size;
mutex_unlock(&dev->struct_mutex);
@@ -956,7 +956,7 @@ i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
ret = 0;
if (seqno == ring->outstanding_lazy_request)
- ret = i915_add_request(ring, NULL, NULL);
+ ret = i915_add_request(ring, NULL);
return ret;
}
@@ -1087,6 +1087,25 @@ i915_wait_seqno(struct intel_ring_buffer *ring, uint32_t seqno)
interruptible, NULL);
}
+static int
+i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring)
+{
+ i915_gem_retire_requests_ring(ring);
+
+ /* Manually manage the write flush as we may have not yet
+ * retired the buffer.
+ *
+ * Note that the last_write_seqno is always the earlier of
+ * the two (read/write) seqno, so if we haved successfully waited,
+ * we know we have passed the last write.
+ */
+ obj->last_write_seqno = 0;
+ obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
+
+ return 0;
+}
+
/**
* Ensures that all rendering to the object has completed and the object is
* safe to unbind from the GTT or access from the CPU.
@@ -1107,18 +1126,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
if (ret)
return ret;
- i915_gem_retire_requests_ring(ring);
-
- /* Manually manage the write flush as we may have not yet
- * retired the buffer.
- */
- if (obj->last_write_seqno &&
- i915_seqno_passed(seqno, obj->last_write_seqno)) {
- obj->last_write_seqno = 0;
- obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
- }
-
- return 0;
+ return i915_gem_object_wait_rendering__tail(obj, ring);
}
/* A nonblocking variant of the above wait. This is a highly dangerous routine
@@ -1154,19 +1162,10 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
mutex_unlock(&dev->struct_mutex);
ret = __wait_seqno(ring, seqno, reset_counter, true, NULL);
mutex_lock(&dev->struct_mutex);
+ if (ret)
+ return ret;
- i915_gem_retire_requests_ring(ring);
-
- /* Manually manage the write flush as we may have not yet
- * retired the buffer.
- */
- if (obj->last_write_seqno &&
- i915_seqno_passed(seqno, obj->last_write_seqno)) {
- obj->last_write_seqno = 0;
- obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
- }
-
- return ret;
+ return i915_gem_object_wait_rendering__tail(obj, ring);
}
/**
@@ -1676,7 +1675,7 @@ i915_gem_object_put_pages(struct drm_i915_gem_object *obj)
/* ->put_pages might need to allocate memory for the bit17 swizzle
* array, hence protect them from being reaped by removing them from gtt
* lists early. */
- list_del(&obj->gtt_list);
+ list_del(&obj->global_list);
ops->put_pages(obj);
obj->pages = NULL;
@@ -1696,7 +1695,7 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
list_for_each_entry_safe(obj, next,
&dev_priv->mm.unbound_list,
- gtt_list) {
+ global_list) {
if ((i915_gem_object_is_purgeable(obj) || !purgeable_only) &&
i915_gem_object_put_pages(obj) == 0) {
count += obj->base.size >> PAGE_SHIFT;
@@ -1733,7 +1732,8 @@ i915_gem_shrink_all(struct drm_i915_private *dev_priv)
i915_gem_evict_everything(dev_priv->dev);
- list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list, gtt_list)
+ list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
+ global_list)
i915_gem_object_put_pages(obj);
}
@@ -1867,7 +1867,7 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
if (ret)
return ret;
- list_add_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
+ list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list);
return 0;
}
@@ -2005,17 +2005,18 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno)
return 0;
}
-int
-i915_add_request(struct intel_ring_buffer *ring,
- struct drm_file *file,
- u32 *out_seqno)
+int __i915_add_request(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ struct drm_i915_gem_object *obj,
+ u32 *out_seqno)
{
drm_i915_private_t *dev_priv = ring->dev->dev_private;
struct drm_i915_gem_request *request;
- u32 request_ring_position;
+ u32 request_ring_position, request_start;
int was_empty;
int ret;
+ request_start = intel_ring_get_tail(ring);
/*
* Emit any outstanding flushes - execbuf can fail to emit the flush
* after having emitted the batchbuffer command. Hence we need to fix
@@ -2047,7 +2048,21 @@ i915_add_request(struct intel_ring_buffer *ring,
request->seqno = intel_ring_get_seqno(ring);
request->ring = ring;
+ request->head = request_start;
request->tail = request_ring_position;
+ request->ctx = ring->last_context;
+ request->batch_obj = obj;
+
+ /* Whilst this request exists, batch_obj will be on the
+ * active_list, and so will hold the active reference. Only when this
+ * request is retired will the the batch_obj be moved onto the
+ * inactive_list and lose its active reference. Hence we do not need
+ * to explicitly hold another reference here.
+ */
+
+ if (request->ctx)
+ i915_gem_context_reference(request->ctx);
+
request->emitted_jiffies = jiffies;
was_empty = list_empty(&ring->request_list);
list_add_tail(&request->list, &ring->request_list);
@@ -2100,9 +2115,114 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
spin_unlock(&file_priv->mm.lock);
}
+static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj)
+{
+ if (acthd >= obj->gtt_offset &&
+ acthd < obj->gtt_offset + obj->base.size)
+ return true;
+
+ return false;
+}
+
+static bool i915_head_inside_request(const u32 acthd_unmasked,
+ const u32 request_start,
+ const u32 request_end)
+{
+ const u32 acthd = acthd_unmasked & HEAD_ADDR;
+
+ if (request_start < request_end) {
+ if (acthd >= request_start && acthd < request_end)
+ return true;
+ } else if (request_start > request_end) {
+ if (acthd >= request_start || acthd < request_end)
+ return true;
+ }
+
+ return false;
+}
+
+static bool i915_request_guilty(struct drm_i915_gem_request *request,
+ const u32 acthd, bool *inside)
+{
+ /* There is a possibility that unmasked head address
+ * pointing inside the ring, matches the batch_obj address range.
+ * However this is extremely unlikely.
+ */
+
+ if (request->batch_obj) {
+ if (i915_head_inside_object(acthd, request->batch_obj)) {
+ *inside = true;
+ return true;
+ }
+ }
+
+ if (i915_head_inside_request(acthd, request->head, request->tail)) {
+ *inside = false;
+ return true;
+ }
+
+ return false;
+}
+
+static void i915_set_reset_status(struct intel_ring_buffer *ring,
+ struct drm_i915_gem_request *request,
+ u32 acthd)
+{
+ struct i915_ctx_hang_stats *hs = NULL;
+ bool inside, guilty;
+
+ /* Innocent until proven guilty */
+ guilty = false;
+
+ if (ring->hangcheck.action != wait &&
+ i915_request_guilty(request, acthd, &inside)) {
+ DRM_ERROR("%s hung %s bo (0x%x ctx %d) at 0x%x\n",
+ ring->name,
+ inside ? "inside" : "flushing",
+ request->batch_obj ?
+ request->batch_obj->gtt_offset : 0,
+ request->ctx ? request->ctx->id : 0,
+ acthd);
+
+ guilty = true;
+ }
+
+ /* If contexts are disabled or this is the default context, use
+ * file_priv->reset_state
+ */
+ if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID)
+ hs = &request->ctx->hang_stats;
+ else if (request->file_priv)
+ hs = &request->file_priv->hang_stats;
+
+ if (hs) {
+ if (guilty)
+ hs->batch_active++;
+ else
+ hs->batch_pending++;
+ }
+}
+
+static void i915_gem_free_request(struct drm_i915_gem_request *request)
+{
+ list_del(&request->list);
+ i915_gem_request_remove_from_client(request);
+
+ if (request->ctx)
+ i915_gem_context_unreference(request->ctx);
+
+ kfree(request);
+}
+
static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
struct intel_ring_buffer *ring)
{
+ u32 completed_seqno;
+ u32 acthd;
+
+ acthd = intel_ring_get_active_head(ring);
+ completed_seqno = ring->get_seqno(ring, false);
+
while (!list_empty(&ring->request_list)) {
struct drm_i915_gem_request *request;
@@ -2110,9 +2230,10 @@ static void i915_gem_reset_ring_lists(struct drm_i915_private *dev_priv,
struct drm_i915_gem_request,
list);
- list_del(&request->list);
- i915_gem_request_remove_from_client(request);
- kfree(request);
+ if (request->seqno > completed_seqno)
+ i915_set_reset_status(ring, request, acthd);
+
+ i915_gem_free_request(request);
}
while (!list_empty(&ring->active_list)) {
@@ -2193,9 +2314,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
*/
ring->last_retired_head = request->tail;
- list_del(&request->list);
- i915_gem_request_remove_from_client(request);
- kfree(request);
+ i915_gem_free_request(request);
}
/* Move any buffers on the active list that are no longer referenced
@@ -2262,7 +2381,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
idle = true;
for_each_ring(ring, dev_priv, i) {
if (ring->gpu_caches_dirty)
- i915_add_request(ring, NULL, NULL);
+ i915_add_request(ring, NULL);
idle &= list_empty(&ring->request_list);
}
@@ -2494,9 +2613,10 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
obj->has_aliasing_ppgtt_mapping = 0;
}
i915_gem_gtt_finish_object(obj);
+ i915_gem_object_unpin_pages(obj);
list_del(&obj->mm_list);
- list_move_tail(&obj->gtt_list, &dev_priv->mm.unbound_list);
+ list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
/* Avoid an unnecessary call to unbind on rebind. */
obj->map_and_fenceable = true;
@@ -2676,18 +2796,33 @@ static inline int fence_number(struct drm_i915_private *dev_priv,
return fence - dev_priv->fence_regs;
}
+struct write_fence {
+ struct drm_device *dev;
+ struct drm_i915_gem_object *obj;
+ int fence;
+};
+
static void i915_gem_write_fence__ipi(void *data)
{
+ struct write_fence *args = data;
+
+ /* Required for SNB+ with LLC */
wbinvd();
+
+ /* Required for VLV */
+ i915_gem_write_fence(args->dev, args->fence, args->obj);
}
static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
struct drm_i915_fence_reg *fence,
bool enable)
{
- struct drm_device *dev = obj->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int fence_reg = fence_number(dev_priv, fence);
+ struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ struct write_fence args = {
+ .dev = obj->base.dev,
+ .fence = fence_number(dev_priv, fence),
+ .obj = enable ? obj : NULL,
+ };
/* In order to fully serialize access to the fenced region and
* the update to the fence register we need to take extreme
@@ -2698,13 +2833,19 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
* SNB+ we need to take a step further and emit an explicit wbinvd()
* on each processor in order to manually flush all memory
* transactions before updating the fence register.
+ *
+ * However, Valleyview complicates matter. There the wbinvd is
+ * insufficient and unlike SNB/IVB requires the serialising
+ * register write. (Note that that register write by itself is
+ * conversely not sufficient for SNB+.) To compromise, we do both.
*/
- if (HAS_LLC(obj->base.dev))
- on_each_cpu(i915_gem_write_fence__ipi, NULL, 1);
- i915_gem_write_fence(dev, fence_reg, enable ? obj : NULL);
+ if (INTEL_INFO(args.dev)->gen >= 6)
+ on_each_cpu(i915_gem_write_fence__ipi, &args, 1);
+ else
+ i915_gem_write_fence(args.dev, args.fence, args.obj);
if (enable) {
- obj->fence_reg = fence_reg;
+ obj->fence_reg = args.fence;
fence->obj = obj;
list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
} else {
@@ -2883,7 +3024,7 @@ static void i915_gem_verify_gtt(struct drm_device *dev)
struct drm_i915_gem_object *obj;
int err = 0;
- list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, global_list) {
if (obj->gtt_space == NULL) {
printk(KERN_ERR "object found on GTT list with no space reserved\n");
err++;
@@ -2930,6 +3071,8 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
struct drm_mm_node *node;
u32 size, fence_size, fence_alignment, unfenced_alignment;
bool mappable, fenceable;
+ size_t gtt_max = map_and_fenceable ?
+ dev_priv->gtt.mappable_end : dev_priv->gtt.total;
int ret;
fence_size = i915_gem_get_gtt_size(dev,
@@ -2956,9 +3099,11 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
/* If the object is bigger than the entire aperture, reject it early
* before evicting everything in a vain attempt to find space.
*/
- if (obj->base.size >
- (map_and_fenceable ? dev_priv->gtt.mappable_end : dev_priv->gtt.total)) {
- DRM_ERROR("Attempting to bind an object larger than the aperture\n");
+ if (obj->base.size > gtt_max) {
+ DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n",
+ obj->base.size,
+ map_and_fenceable ? "mappable" : "total",
+ gtt_max);
return -E2BIG;
}
@@ -2974,14 +3119,10 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
return -ENOMEM;
}
- search_free:
- if (map_and_fenceable)
- ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node,
- size, alignment, obj->cache_level,
- 0, dev_priv->gtt.mappable_end);
- else
- ret = drm_mm_insert_node_generic(&dev_priv->mm.gtt_space, node,
- size, alignment, obj->cache_level);
+search_free:
+ ret = drm_mm_insert_node_in_range_generic(&dev_priv->mm.gtt_space, node,
+ size, alignment,
+ obj->cache_level, 0, gtt_max);
if (ret) {
ret = i915_gem_evict_something(dev, size, alignment,
obj->cache_level,
@@ -3007,7 +3148,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
return ret;
}
- list_move_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
+ list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
obj->gtt_space = node;
@@ -3022,7 +3163,6 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
obj->map_and_fenceable = mappable && fenceable;
- i915_gem_object_unpin_pages(obj);
trace_i915_gem_object_bind(obj, map_and_fenceable);
i915_gem_verify_gtt(dev);
return 0;
@@ -3722,7 +3862,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
const struct drm_i915_gem_object_ops *ops)
{
INIT_LIST_HEAD(&obj->mm_list);
- INIT_LIST_HEAD(&obj->gtt_list);
+ INIT_LIST_HEAD(&obj->global_list);
INIT_LIST_HEAD(&obj->ring_list);
INIT_LIST_HEAD(&obj->exec_list);
@@ -3822,7 +3962,13 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
dev_priv->mm.interruptible = was_interruptible;
}
- obj->pages_pin_count = 0;
+ /* Stolen objects don't hold a ref, but do hold pin count. Fix that up
+ * before progressing. */
+ if (obj->stolen)
+ i915_gem_object_unpin_pages(obj);
+
+ if (WARN_ON(obj->pages_pin_count))
+ obj->pages_pin_count = 0;
i915_gem_object_put_pages(obj);
i915_gem_object_free_mmap_offset(obj);
i915_gem_object_release_stolen(obj);
@@ -3973,12 +4119,21 @@ static int i915_gem_init_rings(struct drm_device *dev)
goto cleanup_bsd_ring;
}
+ if (HAS_VEBOX(dev)) {
+ ret = intel_init_vebox_ring_buffer(dev);
+ if (ret)
+ goto cleanup_blt_ring;
+ }
+
+
ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
if (ret)
- goto cleanup_blt_ring;
+ goto cleanup_vebox_ring;
return 0;
+cleanup_vebox_ring:
+ intel_cleanup_ring_buffer(&dev_priv->ring[VECS]);
cleanup_blt_ring:
intel_cleanup_ring_buffer(&dev_priv->ring[BCS]);
cleanup_bsd_ring:
@@ -4453,10 +4608,10 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
}
cnt = 0;
- list_for_each_entry(obj, &dev_priv->mm.unbound_list, gtt_list)
+ list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
if (obj->pages_pin_count == 0)
cnt += obj->base.size >> PAGE_SHIFT;
- list_for_each_entry(obj, &dev_priv->mm.inactive_list, gtt_list)
+ list_for_each_entry(obj, &dev_priv->mm.inactive_list, global_list)
if (obj->pin_count == 0 && obj->pages_pin_count == 0)
cnt += obj->base.size >> PAGE_SHIFT;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index a1e8ecb6adf6..51b7a2171cae 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -113,7 +113,7 @@ static int get_context_size(struct drm_device *dev)
case 7:
reg = I915_READ(GEN7_CXT_SIZE);
if (IS_HASWELL(dev))
- ret = HSW_CXT_TOTAL_SIZE(reg) * 64;
+ ret = HSW_CXT_TOTAL_SIZE;
else
ret = GEN7_CXT_TOTAL_SIZE(reg) * 64;
break;
@@ -124,10 +124,10 @@ static int get_context_size(struct drm_device *dev)
return ret;
}
-static void do_destroy(struct i915_hw_context *ctx)
+void i915_gem_context_free(struct kref *ctx_ref)
{
- if (ctx->file_priv)
- idr_remove(&ctx->file_priv->context_idr, ctx->id);
+ struct i915_hw_context *ctx = container_of(ctx_ref,
+ typeof(*ctx), ref);
drm_gem_object_unreference(&ctx->obj->base);
kfree(ctx);
@@ -145,6 +145,7 @@ create_hw_context(struct drm_device *dev,
if (ctx == NULL)
return ERR_PTR(-ENOMEM);
+ kref_init(&ctx->ref);
ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size);
if (ctx->obj == NULL) {
kfree(ctx);
@@ -155,7 +156,8 @@ create_hw_context(struct drm_device *dev,
if (INTEL_INFO(dev)->gen >= 7) {
ret = i915_gem_object_set_cache_level(ctx->obj,
I915_CACHE_LLC_MLC);
- if (ret)
+ /* Failure shouldn't ever happen this early */
+ if (WARN_ON(ret))
goto err_out;
}
@@ -169,18 +171,18 @@ create_hw_context(struct drm_device *dev,
if (file_priv == NULL)
return ctx;
- ctx->file_priv = file_priv;
-
ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0,
GFP_KERNEL);
if (ret < 0)
goto err_out;
+
+ ctx->file_priv = file_priv;
ctx->id = ret;
return ctx;
err_out:
- do_destroy(ctx);
+ i915_gem_context_unreference(ctx);
return ERR_PTR(ret);
}
@@ -213,12 +215,16 @@ static int create_default_context(struct drm_i915_private *dev_priv)
*/
dev_priv->ring[RCS].default_context = ctx;
ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false, false);
- if (ret)
+ if (ret) {
+ DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
goto err_destroy;
+ }
ret = do_switch(ctx);
- if (ret)
+ if (ret) {
+ DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
goto err_unpin;
+ }
DRM_DEBUG_DRIVER("Default HW context loaded\n");
return 0;
@@ -226,7 +232,7 @@ static int create_default_context(struct drm_i915_private *dev_priv)
err_unpin:
i915_gem_object_unpin(ctx->obj);
err_destroy:
- do_destroy(ctx);
+ i915_gem_context_unreference(ctx);
return ret;
}
@@ -236,6 +242,7 @@ void i915_gem_context_init(struct drm_device *dev)
if (!HAS_HW_CONTEXTS(dev)) {
dev_priv->hw_contexts_disabled = true;
+ DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n");
return;
}
@@ -248,11 +255,13 @@ void i915_gem_context_init(struct drm_device *dev)
if (dev_priv->hw_context_size > (1<<20)) {
dev_priv->hw_contexts_disabled = true;
+ DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n");
return;
}
if (create_default_context(dev_priv)) {
dev_priv->hw_contexts_disabled = true;
+ DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n");
return;
}
@@ -262,6 +271,7 @@ void i915_gem_context_init(struct drm_device *dev)
void i915_gem_context_fini(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
if (dev_priv->hw_contexts_disabled)
return;
@@ -271,9 +281,16 @@ void i915_gem_context_fini(struct drm_device *dev)
* other code, leading to spurious errors. */
intel_gpu_reset(dev);
- i915_gem_object_unpin(dev_priv->ring[RCS].default_context->obj);
+ i915_gem_object_unpin(dctx->obj);
- do_destroy(dev_priv->ring[RCS].default_context);
+ /* When default context is created and switched to, base object refcount
+ * will be 2 (+1 from object creation and +1 from do_switch()).
+ * i915_gem_context_fini() will be called after gpu_idle() has switched
+ * to default context. So we need to unreference the base object once
+ * to offset the do_switch part, so that i915_gem_context_unreference()
+ * can then free the base object correctly. */
+ drm_gem_object_unreference(&dctx->obj->base);
+ i915_gem_context_unreference(dctx);
}
static int context_idr_cleanup(int id, void *p, void *data)
@@ -282,11 +299,38 @@ static int context_idr_cleanup(int id, void *p, void *data)
BUG_ON(id == DEFAULT_CONTEXT_ID);
- do_destroy(ctx);
-
+ i915_gem_context_unreference(ctx);
return 0;
}
+struct i915_ctx_hang_stats *
+i915_gem_context_get_hang_stats(struct intel_ring_buffer *ring,
+ struct drm_file *file,
+ u32 id)
+{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct drm_i915_file_private *file_priv = file->driver_priv;
+ struct i915_hw_context *to;
+
+ if (dev_priv->hw_contexts_disabled)
+ return ERR_PTR(-ENOENT);
+
+ if (ring->id != RCS)
+ return ERR_PTR(-EINVAL);
+
+ if (file == NULL)
+ return ERR_PTR(-EINVAL);
+
+ if (id == DEFAULT_CONTEXT_ID)
+ return &file_priv->hang_stats;
+
+ to = i915_gem_context_get(file->driver_priv, id);
+ if (to == NULL)
+ return ERR_PTR(-ENOENT);
+
+ return &to->hang_stats;
+}
+
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
{
struct drm_i915_file_private *file_priv = file->driver_priv;
@@ -325,6 +369,7 @@ mi_set_context(struct intel_ring_buffer *ring,
if (ret)
return ret;
+ /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw */
if (IS_GEN7(ring->dev))
intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
else
@@ -353,13 +398,13 @@ mi_set_context(struct intel_ring_buffer *ring,
static int do_switch(struct i915_hw_context *to)
{
struct intel_ring_buffer *ring = to->ring;
- struct drm_i915_gem_object *from_obj = ring->last_context_obj;
+ struct i915_hw_context *from = ring->last_context;
u32 hw_flags = 0;
int ret;
- BUG_ON(from_obj != NULL && from_obj->pin_count == 0);
+ BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
- if (from_obj == to->obj)
+ if (from == to)
return 0;
ret = i915_gem_object_pin(to->obj, CONTEXT_ALIGN, false, false);
@@ -382,7 +427,7 @@ static int do_switch(struct i915_hw_context *to)
if (!to->is_initialized || is_default_context(to))
hw_flags |= MI_RESTORE_INHIBIT;
- else if (WARN_ON_ONCE(from_obj == to->obj)) /* not yet expected */
+ else if (WARN_ON_ONCE(from == to)) /* not yet expected */
hw_flags |= MI_FORCE_RESTORE;
ret = mi_set_context(ring, to, hw_flags);
@@ -397,9 +442,9 @@ static int do_switch(struct i915_hw_context *to)
* is a bit suboptimal because the retiring can occur simply after the
* MI_SET_CONTEXT instead of when the next seqno has completed.
*/
- if (from_obj != NULL) {
- from_obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
- i915_gem_object_move_to_active(from_obj, ring);
+ if (from != NULL) {
+ from->obj->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION;
+ i915_gem_object_move_to_active(from->obj, ring);
/* As long as MI_SET_CONTEXT is serializing, ie. it flushes the
* whole damn pipeline, we don't need to explicitly mark the
* object dirty. The only exception is that the context must be
@@ -407,15 +452,26 @@ static int do_switch(struct i915_hw_context *to)
* able to defer doing this until we know the object would be
* swapped, but there is no way to do that yet.
*/
- from_obj->dirty = 1;
- BUG_ON(from_obj->ring != ring);
- i915_gem_object_unpin(from_obj);
+ from->obj->dirty = 1;
+ BUG_ON(from->obj->ring != ring);
+
+ ret = i915_add_request(ring, NULL);
+ if (ret) {
+ /* Too late, we've already scheduled a context switch.
+ * Try to undo the change so that the hw state is
+ * consistent with out tracking. In case of emergency,
+ * scream.
+ */
+ WARN_ON(mi_set_context(ring, from, MI_RESTORE_INHIBIT));
+ return ret;
+ }
- drm_gem_object_unreference(&from_obj->base);
+ i915_gem_object_unpin(from->obj);
+ i915_gem_context_unreference(from);
}
- drm_gem_object_reference(&to->obj->base);
- ring->last_context_obj = to->obj;
+ i915_gem_context_reference(to);
+ ring->last_context = to;
to->is_initialized = true;
return 0;
@@ -444,6 +500,8 @@ int i915_switch_context(struct intel_ring_buffer *ring,
if (dev_priv->hw_contexts_disabled)
return 0;
+ WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
if (ring != &dev_priv->ring[RCS])
return 0;
@@ -512,8 +570,8 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
return -ENOENT;
}
- do_destroy(ctx);
-
+ idr_remove(&ctx->file_priv->context_idr, ctx->id);
+ i915_gem_context_unreference(ctx);
mutex_unlock(&dev->struct_mutex);
DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id);
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 117ce3813681..87a3227e5179 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -786,7 +786,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
obj->dirty = 1;
obj->last_write_seqno = intel_ring_get_seqno(ring);
if (obj->pin_count) /* check for potential scanout */
- intel_mark_fb_busy(obj);
+ intel_mark_fb_busy(obj, ring);
}
trace_i915_gem_object_change_domain(obj, old_read, old_write);
@@ -796,13 +796,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
static void
i915_gem_execbuffer_retire_commands(struct drm_device *dev,
struct drm_file *file,
- struct intel_ring_buffer *ring)
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_object *obj)
{
/* Unconditionally force add_request to emit a full flush. */
ring->gpu_caches_dirty = true;
/* Add a breadcrumb for the completion of the batch buffer */
- (void)i915_add_request(ring, file, NULL);
+ (void)__i915_add_request(ring, file, obj, NULL);
}
static int
@@ -885,6 +886,15 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
return -EPERM;
}
break;
+ case I915_EXEC_VEBOX:
+ ring = &dev_priv->ring[VECS];
+ if (ctx_id != 0) {
+ DRM_DEBUG("Ring %s doesn't support contexts\n",
+ ring->name);
+ return -EPERM;
+ }
+ break;
+
default:
DRM_DEBUG("execbuf with unknown ring: %d\n",
(int)(args->flags & I915_EXEC_RING_MASK));
@@ -1074,7 +1084,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
i915_gem_execbuffer_move_to_active(&eb->objects, ring);
- i915_gem_execbuffer_retire_commands(dev, file, ring);
+ i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
err:
eb_destroy(eb);
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index bdb0d7717bc7..5101ab6869b4 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -28,8 +28,6 @@
#include "i915_trace.h"
#include "intel_drv.h"
-typedef uint32_t gen6_gtt_pte_t;
-
/* PPGTT stuff */
#define GEN6_GTT_ADDR_ENCODE(addr) ((addr) | (((addr) >> 28) & 0xff0))
@@ -44,29 +42,22 @@ typedef uint32_t gen6_gtt_pte_t;
#define GEN6_PTE_CACHE_LLC_MLC (3 << 1)
#define GEN6_PTE_ADDR_ENCODE(addr) GEN6_GTT_ADDR_ENCODE(addr)
-static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
- dma_addr_t addr,
- enum i915_cache_level level)
+static gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
+ dma_addr_t addr,
+ enum i915_cache_level level)
{
gen6_gtt_pte_t pte = GEN6_PTE_VALID;
pte |= GEN6_PTE_ADDR_ENCODE(addr);
switch (level) {
case I915_CACHE_LLC_MLC:
- /* Haswell doesn't set L3 this way */
- if (IS_HASWELL(dev))
- pte |= GEN6_PTE_CACHE_LLC;
- else
- pte |= GEN6_PTE_CACHE_LLC_MLC;
+ pte |= GEN6_PTE_CACHE_LLC_MLC;
break;
case I915_CACHE_LLC:
pte |= GEN6_PTE_CACHE_LLC;
break;
case I915_CACHE_NONE:
- if (IS_HASWELL(dev))
- pte |= HSW_PTE_UNCACHED;
- else
- pte |= GEN6_PTE_UNCACHED;
+ pte |= GEN6_PTE_UNCACHED;
break;
default:
BUG();
@@ -75,16 +66,48 @@ static inline gen6_gtt_pte_t gen6_pte_encode(struct drm_device *dev,
return pte;
}
-static int gen6_ppgtt_enable(struct drm_device *dev)
+#define BYT_PTE_WRITEABLE (1 << 1)
+#define BYT_PTE_SNOOPED_BY_CPU_CACHES (1 << 2)
+
+static gen6_gtt_pte_t byt_pte_encode(struct drm_device *dev,
+ dma_addr_t addr,
+ enum i915_cache_level level)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t pd_offset;
- struct intel_ring_buffer *ring;
- struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+ gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+ pte |= GEN6_PTE_ADDR_ENCODE(addr);
+
+ /* Mark the page as writeable. Other platforms don't have a
+ * setting for read-only/writable, so this matches that behavior.
+ */
+ pte |= BYT_PTE_WRITEABLE;
+
+ if (level != I915_CACHE_NONE)
+ pte |= BYT_PTE_SNOOPED_BY_CPU_CACHES;
+
+ return pte;
+}
+
+static gen6_gtt_pte_t hsw_pte_encode(struct drm_device *dev,
+ dma_addr_t addr,
+ enum i915_cache_level level)
+{
+ gen6_gtt_pte_t pte = GEN6_PTE_VALID;
+ pte |= GEN6_PTE_ADDR_ENCODE(addr);
+
+ if (level != I915_CACHE_NONE)
+ pte |= GEN6_PTE_CACHE_LLC;
+
+ return pte;
+}
+
+static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
+{
+ struct drm_i915_private *dev_priv = ppgtt->dev->dev_private;
gen6_gtt_pte_t __iomem *pd_addr;
uint32_t pd_entry;
int i;
+ WARN_ON(ppgtt->pd_offset & 0x3f);
pd_addr = (gen6_gtt_pte_t __iomem*)dev_priv->gtt.gsm +
ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
for (i = 0; i < ppgtt->num_pd_entries; i++) {
@@ -97,6 +120,19 @@ static int gen6_ppgtt_enable(struct drm_device *dev)
writel(pd_entry, pd_addr + i);
}
readl(pd_addr);
+}
+
+static int gen6_ppgtt_enable(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ uint32_t pd_offset;
+ struct intel_ring_buffer *ring;
+ struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+ int i;
+
+ BUG_ON(ppgtt->pd_offset & 0x3f);
+
+ gen6_write_pdes(ppgtt);
pd_offset = ppgtt->pd_offset;
pd_offset /= 64; /* in cachelines, */
@@ -154,9 +190,9 @@ static void gen6_ppgtt_clear_range(struct i915_hw_ppgtt *ppgtt,
unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
unsigned last_pte, i;
- scratch_pte = gen6_pte_encode(ppgtt->dev,
- ppgtt->scratch_page_dma_addr,
- I915_CACHE_LLC);
+ scratch_pte = ppgtt->pte_encode(ppgtt->dev,
+ ppgtt->scratch_page_dma_addr,
+ I915_CACHE_LLC);
while (num_entries) {
last_pte = first_pte + num_entries;
@@ -191,8 +227,8 @@ static void gen6_ppgtt_insert_entries(struct i915_hw_ppgtt *ppgtt,
dma_addr_t page_addr;
page_addr = sg_page_iter_dma_address(&sg_iter);
- pt_vaddr[act_pte] = gen6_pte_encode(ppgtt->dev, page_addr,
- cache_level);
+ pt_vaddr[act_pte] = ppgtt->pte_encode(ppgtt->dev, page_addr,
+ cache_level);
if (++act_pte == I915_PPGTT_PT_ENTRIES) {
kunmap_atomic(pt_vaddr);
act_pt++;
@@ -233,8 +269,15 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
/* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
* entries. For aliasing ppgtt support we just steal them at the end for
* now. */
- first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
+ first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
+ if (IS_HASWELL(dev)) {
+ ppgtt->pte_encode = hsw_pte_encode;
+ } else if (IS_VALLEYVIEW(dev)) {
+ ppgtt->pte_encode = byt_pte_encode;
+ } else {
+ ppgtt->pte_encode = gen6_pte_encode;
+ }
ppgtt->num_pd_entries = I915_PPGTT_PD_ENTRIES;
ppgtt->enable = gen6_ppgtt_enable;
ppgtt->clear_range = gen6_ppgtt_clear_range;
@@ -396,7 +439,7 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
dev_priv->gtt.gtt_clear_range(dev, dev_priv->gtt.start / PAGE_SIZE,
dev_priv->gtt.total / PAGE_SIZE);
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
i915_gem_clflush_object(obj);
i915_gem_gtt_bind_object(obj, obj->cache_level);
}
@@ -437,7 +480,8 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
for_each_sg_page(st->sgl, &sg_iter, st->nents, 0) {
addr = sg_page_iter_dma_address(&sg_iter);
- iowrite32(gen6_pte_encode(dev, addr, level), &gtt_entries[i]);
+ iowrite32(dev_priv->gtt.pte_encode(dev, addr, level),
+ &gtt_entries[i]);
i++;
}
@@ -449,7 +493,7 @@ static void gen6_ggtt_insert_entries(struct drm_device *dev,
*/
if (i != 0)
WARN_ON(readl(&gtt_entries[i-1])
- != gen6_pte_encode(dev, addr, level));
+ != dev_priv->gtt.pte_encode(dev, addr, level));
/* This next bit makes the above posting read even more important. We
* want to flush the TLBs only after we're certain all the PTE updates
@@ -474,8 +518,9 @@ static void gen6_ggtt_clear_range(struct drm_device *dev,
first_entry, num_entries, max_entries))
num_entries = max_entries;
- scratch_pte = gen6_pte_encode(dev, dev_priv->gtt.scratch_page_dma,
- I915_CACHE_LLC);
+ scratch_pte = dev_priv->gtt.pte_encode(dev,
+ dev_priv->gtt.scratch_page_dma,
+ I915_CACHE_LLC);
for (i = 0; i < num_entries; i++)
iowrite32(scratch_pte, &gtt_base[i]);
readl(gtt_base);
@@ -586,7 +631,7 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
dev_priv->mm.gtt_space.color_adjust = i915_gtt_color_adjust;
/* Mark any preallocated objects as occupied */
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
DRM_DEBUG_KMS("reserving preallocated space: %x + %zx\n",
obj->gtt_offset, obj->base.size);
@@ -809,6 +854,13 @@ int i915_gem_gtt_init(struct drm_device *dev)
} else {
dev_priv->gtt.gtt_probe = gen6_gmch_probe;
dev_priv->gtt.gtt_remove = gen6_gmch_remove;
+ if (IS_HASWELL(dev)) {
+ dev_priv->gtt.pte_encode = hsw_pte_encode;
+ } else if (IS_VALLEYVIEW(dev)) {
+ dev_priv->gtt.pte_encode = byt_pte_encode;
+ } else {
+ dev_priv->gtt.pte_encode = gen6_pte_encode;
+ }
}
ret = dev_priv->gtt.gtt_probe(dev, &dev_priv->gtt.total,
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index 130d1db27e28..982d4732cecf 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -62,7 +62,10 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev)
* its value of TOLUD.
*/
base = 0;
- if (INTEL_INFO(dev)->gen >= 6) {
+ if (IS_VALLEYVIEW(dev)) {
+ pci_read_config_dword(dev->pdev, 0x5c, &base);
+ base &= ~((1<<20) - 1);
+ } else if (INTEL_INFO(dev)->gen >= 6) {
/* Read Base Data of Stolen Memory Register (BDSM) directly.
* Note that there is also a MCHBAR miror at 0x1080c0 or
* we could use device 2:0x5c instead.
@@ -136,6 +139,7 @@ static int i915_setup_compression(struct drm_device *dev, int size)
err_fb:
drm_mm_put_block(compressed_fb);
err:
+ pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size);
return -ENOSPC;
}
@@ -143,7 +147,7 @@ int i915_gem_stolen_setup_compression(struct drm_device *dev, int size)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (dev_priv->mm.stolen_base == 0)
+ if (!drm_mm_initialized(&dev_priv->mm.stolen))
return -ENODEV;
if (size < dev_priv->cfb_size)
@@ -175,6 +179,9 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ if (!drm_mm_initialized(&dev_priv->mm.stolen))
+ return;
+
i915_gem_stolen_cleanup_compression(dev);
drm_mm_takedown(&dev_priv->mm.stolen);
}
@@ -182,6 +189,7 @@ void i915_gem_cleanup_stolen(struct drm_device *dev)
int i915_gem_init_stolen(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ int bios_reserved = 0;
dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
if (dev_priv->mm.stolen_base == 0)
@@ -190,8 +198,12 @@ int i915_gem_init_stolen(struct drm_device *dev)
DRM_DEBUG_KMS("found %zd bytes of stolen memory at %08lx\n",
dev_priv->gtt.stolen_size, dev_priv->mm.stolen_base);
+ if (IS_VALLEYVIEW(dev))
+ bios_reserved = 1024*1024; /* top 1M on VLV/BYT */
+
/* Basic memrange allocator for stolen space */
- drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size);
+ drm_mm_init(&dev_priv->mm.stolen, 0, dev_priv->gtt.stolen_size -
+ bios_reserved);
return 0;
}
@@ -270,7 +282,7 @@ _i915_gem_object_create_stolen(struct drm_device *dev,
goto cleanup;
obj->has_dma_mapping = true;
- obj->pages_pin_count = 1;
+ i915_gem_object_pin_pages(obj);
obj->stolen = stolen;
obj->base.write_domain = I915_GEM_DOMAIN_GTT;
@@ -291,7 +303,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
struct drm_i915_gem_object *obj;
struct drm_mm_node *stolen;
- if (dev_priv->mm.stolen_base == 0)
+ if (!drm_mm_initialized(&dev_priv->mm.stolen))
return NULL;
DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
@@ -322,7 +334,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
struct drm_i915_gem_object *obj;
struct drm_mm_node *stolen;
- if (dev_priv->mm.stolen_base == 0)
+ if (!drm_mm_initialized(&dev_priv->mm.stolen))
return NULL;
DRM_DEBUG_KMS("creating preallocated stolen object: stolen_offset=%x, gtt_offset=%x, size=%x\n",
@@ -330,7 +342,6 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
/* KISS and expect everything to be page-aligned */
BUG_ON(stolen_offset & 4095);
- BUG_ON(gtt_offset & 4095);
BUG_ON(size & 4095);
if (WARN_ON(size == 0))
@@ -351,6 +362,10 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
return NULL;
}
+ /* Some objects just need physical mem from stolen space */
+ if (gtt_offset == -1)
+ return obj;
+
/* To simplify the initialisation sequence between KMS and GTT,
* we allow construction of the stolen object prior to
* setting up the GTT space. The actual reservation will occur
@@ -371,7 +386,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
obj->gtt_offset = gtt_offset;
obj->has_global_gtt_mapping = 1;
- list_add_tail(&obj->gtt_list, &dev_priv->mm.bound_list);
+ list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
return obj;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 0aa2ef0d2ae0..3d92a7cef154 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -70,15 +70,6 @@ static const u32 hpd_status_gen4[] = {
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
};
-static const u32 hpd_status_i965[] = {
- [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
- [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I965,
- [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I965,
- [HPD_PORT_B] = PORTB_HOTPLUG_INT_STATUS,
- [HPD_PORT_C] = PORTC_HOTPLUG_INT_STATUS,
- [HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
-};
-
static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
@@ -88,13 +79,12 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
};
-static void ibx_hpd_irq_setup(struct drm_device *dev);
-static void i915_hpd_irq_setup(struct drm_device *dev);
-
/* For display hotplug interrupt */
static void
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
+ assert_spin_locked(&dev_priv->irq_lock);
+
if ((dev_priv->irq_mask & mask) != 0) {
dev_priv->irq_mask &= ~mask;
I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -105,6 +95,8 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
static void
ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
{
+ assert_spin_locked(&dev_priv->irq_lock);
+
if ((dev_priv->irq_mask & mask) != mask) {
dev_priv->irq_mask |= mask;
I915_WRITE(DEIMR, dev_priv->irq_mask);
@@ -112,6 +104,215 @@ ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
}
}
+static bool ivb_can_enable_err_int(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+ enum pipe pipe;
+
+ assert_spin_locked(&dev_priv->irq_lock);
+
+ for_each_pipe(pipe) {
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+ if (crtc->cpu_fifo_underrun_disabled)
+ return false;
+ }
+
+ return true;
+}
+
+static bool cpt_can_enable_serr_int(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum pipe pipe;
+ struct intel_crtc *crtc;
+
+ for_each_pipe(pipe) {
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+
+ if (crtc->pch_fifo_underrun_disabled)
+ return false;
+ }
+
+ return true;
+}
+
+static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t bit = (pipe == PIPE_A) ? DE_PIPEA_FIFO_UNDERRUN :
+ DE_PIPEB_FIFO_UNDERRUN;
+
+ if (enable)
+ ironlake_enable_display_irq(dev_priv, bit);
+ else
+ ironlake_disable_display_irq(dev_priv, bit);
+}
+
+static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev,
+ bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (enable) {
+ if (!ivb_can_enable_err_int(dev))
+ return;
+
+ I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN_A |
+ ERR_INT_FIFO_UNDERRUN_B |
+ ERR_INT_FIFO_UNDERRUN_C);
+
+ ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ } else {
+ ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ }
+}
+
+static void ibx_set_fifo_underrun_reporting(struct intel_crtc *crtc,
+ bool enable)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t bit = (crtc->pipe == PIPE_A) ? SDE_TRANSA_FIFO_UNDER :
+ SDE_TRANSB_FIFO_UNDER;
+
+ if (enable)
+ I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~bit);
+ else
+ I915_WRITE(SDEIMR, I915_READ(SDEIMR) | bit);
+
+ POSTING_READ(SDEIMR);
+}
+
+static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
+ enum transcoder pch_transcoder,
+ bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (enable) {
+ if (!cpt_can_enable_serr_int(dev))
+ return;
+
+ I915_WRITE(SERR_INT, SERR_INT_TRANS_A_FIFO_UNDERRUN |
+ SERR_INT_TRANS_B_FIFO_UNDERRUN |
+ SERR_INT_TRANS_C_FIFO_UNDERRUN);
+
+ I915_WRITE(SDEIMR, I915_READ(SDEIMR) & ~SDE_ERROR_CPT);
+ } else {
+ I915_WRITE(SDEIMR, I915_READ(SDEIMR) | SDE_ERROR_CPT);
+ }
+
+ POSTING_READ(SDEIMR);
+}
+
+/**
+ * intel_set_cpu_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pipe: pipe
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable CPU fifo underruns for a specific
+ * pipe. Notice that on some Gens (e.g. IVB, HSW), disabling FIFO underrun
+ * reporting for one pipe may also disable all the other CPU error interruts for
+ * the other pipes, due to the fact that there's just one interrupt mask/enable
+ * bit for all the pipes.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+
+ ret = !intel_crtc->cpu_fifo_underrun_disabled;
+
+ if (enable == ret)
+ goto done;
+
+ intel_crtc->cpu_fifo_underrun_disabled = !enable;
+
+ if (IS_GEN5(dev) || IS_GEN6(dev))
+ ironlake_set_fifo_underrun_reporting(dev, pipe, enable);
+ else if (IS_GEN7(dev))
+ ivybridge_set_fifo_underrun_reporting(dev, enable);
+
+done:
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+ return ret;
+}
+
+/**
+ * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
+ * @dev: drm device
+ * @pch_transcoder: the PCH transcoder (same as pipe on IVB and older)
+ * @enable: true if we want to report FIFO underrun errors, false otherwise
+ *
+ * This function makes us disable or enable PCH fifo underruns for a specific
+ * PCH transcoder. Notice that on some PCHs (e.g. CPT/PPT), disabling FIFO
+ * underrun reporting for one transcoder may also disable all the other PCH
+ * error interruts for the other transcoders, due to the fact that there's just
+ * one interrupt mask/enable bit for all the transcoders.
+ *
+ * Returns the previous state of underrun reporting.
+ */
+bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+ enum transcoder pch_transcoder,
+ bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum pipe p;
+ struct drm_crtc *crtc;
+ struct intel_crtc *intel_crtc;
+ unsigned long flags;
+ bool ret;
+
+ if (HAS_PCH_LPT(dev)) {
+ crtc = NULL;
+ for_each_pipe(p) {
+ struct drm_crtc *c = dev_priv->pipe_to_crtc_mapping[p];
+ if (intel_pipe_has_type(c, INTEL_OUTPUT_ANALOG)) {
+ crtc = c;
+ break;
+ }
+ }
+ if (!crtc) {
+ DRM_ERROR("PCH FIFO underrun, but no CRTC using the PCH found\n");
+ return false;
+ }
+ } else {
+ crtc = dev_priv->pipe_to_crtc_mapping[pch_transcoder];
+ }
+ intel_crtc = to_intel_crtc(crtc);
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+
+ ret = !intel_crtc->pch_fifo_underrun_disabled;
+
+ if (enable == ret)
+ goto done;
+
+ intel_crtc->pch_fifo_underrun_disabled = !enable;
+
+ if (HAS_PCH_IBX(dev))
+ ibx_set_fifo_underrun_reporting(intel_crtc, enable);
+ else
+ cpt_set_fifo_underrun_reporting(dev, pch_transcoder, enable);
+
+done:
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+ return ret;
+}
+
+
void
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
{
@@ -142,28 +343,21 @@ i915_disable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask)
}
/**
- * intel_enable_asle - enable ASLE interrupt for OpRegion
+ * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
*/
-void intel_enable_asle(struct drm_device *dev)
+static void i915_enable_asle_pipestat(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned long irqflags;
- /* FIXME: opregion/asle for VLV */
- if (IS_VALLEYVIEW(dev))
+ if (!dev_priv->opregion.asle || !IS_MOBILE(dev))
return;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- if (HAS_PCH_SPLIT(dev))
- ironlake_enable_display_irq(dev_priv, DE_GSE);
- else {
- i915_enable_pipestat(dev_priv, 1,
- PIPE_LEGACY_BLC_EVENT_ENABLE);
- if (INTEL_INFO(dev)->gen >= 4)
- i915_enable_pipestat(dev_priv, 0,
- PIPE_LEGACY_BLC_EVENT_ENABLE);
- }
+ i915_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
+ if (INTEL_INFO(dev)->gen >= 4)
+ i915_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
@@ -181,10 +375,16 @@ static int
i915_pipe_enabled(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
- pipe);
- return I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE;
+ if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ /* Locking is horribly broken here, but whatever. */
+ struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ return intel_crtc->active;
+ } else {
+ return I915_READ(PIPECONF(pipe)) & PIPECONF_ENABLE;
+ }
}
/* Called from drm generic code, passed a 'crtc', which
@@ -334,6 +534,21 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
crtc);
}
+static int intel_hpd_irq_event(struct drm_device *dev, struct drm_connector *connector)
+{
+ enum drm_connector_status old_status;
+
+ WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+ old_status = connector->status;
+
+ connector->status = connector->funcs->detect(connector, false);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+ connector->base.id,
+ drm_get_connector_name(connector),
+ old_status, connector->status);
+ return (old_status != connector->status);
+}
+
/*
* Handle hotplug events outside the interrupt handler proper.
*/
@@ -350,6 +565,8 @@ static void i915_hotplug_work_func(struct work_struct *work)
struct drm_connector *connector;
unsigned long irqflags;
bool hpd_disabled = false;
+ bool changed = false;
+ u32 hpd_event_bits;
/* HPD irq before everything is fully set up. */
if (!dev_priv->enable_hotplug_processing)
@@ -359,6 +576,9 @@ static void i915_hotplug_work_func(struct work_struct *work)
DRM_DEBUG_KMS("running encoder hotplug functions\n");
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+ hpd_event_bits = dev_priv->hpd_event_bits;
+ dev_priv->hpd_event_bits = 0;
list_for_each_entry(connector, &mode_config->connector_list, head) {
intel_connector = to_intel_connector(connector);
intel_encoder = intel_connector->encoder;
@@ -373,6 +593,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
| DRM_CONNECTOR_POLL_DISCONNECT;
hpd_disabled = true;
}
+ if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
+ DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
+ drm_get_connector_name(connector), intel_encoder->hpd_pin);
+ }
}
/* if there were no outputs to poll, poll was disabled,
* therefore make sure it's enabled when disabling HPD on
@@ -385,14 +609,20 @@ static void i915_hotplug_work_func(struct work_struct *work)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
- list_for_each_entry(intel_encoder, &mode_config->encoder_list, base.head)
- if (intel_encoder->hot_plug)
- intel_encoder->hot_plug(intel_encoder);
-
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ intel_connector = to_intel_connector(connector);
+ intel_encoder = intel_connector->encoder;
+ if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
+ if (intel_encoder->hot_plug)
+ intel_encoder->hot_plug(intel_encoder);
+ if (intel_hpd_irq_event(dev, connector))
+ changed = true;
+ }
+ }
mutex_unlock(&mode_config->mutex);
- /* Just fire off a uevent and let userspace tell us what to do */
- drm_helper_hpd_irq_event(dev);
+ if (changed)
+ drm_kms_helper_hotplug_event(dev);
}
static void ironlake_handle_rps_change(struct drm_device *dev)
@@ -447,7 +677,6 @@ static void notify_ring(struct drm_device *dev,
wake_up_all(&ring->irq_queue);
if (i915_enable_hangcheck) {
- dev_priv->gpu_error.hangcheck_count = 0;
mod_timer(&dev_priv->gpu_error.hangcheck_timer,
round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
}
@@ -464,25 +693,48 @@ static void gen6_pm_rps_work(struct work_struct *work)
pm_iir = dev_priv->rps.pm_iir;
dev_priv->rps.pm_iir = 0;
pm_imr = I915_READ(GEN6_PMIMR);
- I915_WRITE(GEN6_PMIMR, 0);
+ /* Make sure not to corrupt PMIMR state used by ringbuffer code */
+ I915_WRITE(GEN6_PMIMR, pm_imr & ~GEN6_PM_RPS_EVENTS);
spin_unlock_irq(&dev_priv->rps.lock);
- if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0)
+ if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
return;
mutex_lock(&dev_priv->rps.hw_lock);
- if (pm_iir & GEN6_PM_RP_UP_THRESHOLD)
+ if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
new_delay = dev_priv->rps.cur_delay + 1;
- else
+
+ /*
+ * For better performance, jump directly
+ * to RPe if we're below it.
+ */
+ if (IS_VALLEYVIEW(dev_priv->dev) &&
+ dev_priv->rps.cur_delay < dev_priv->rps.rpe_delay)
+ new_delay = dev_priv->rps.rpe_delay;
+ } else
new_delay = dev_priv->rps.cur_delay - 1;
/* sysfs frequency interfaces may have snuck in while servicing the
* interrupt
*/
- if (!(new_delay > dev_priv->rps.max_delay ||
- new_delay < dev_priv->rps.min_delay)) {
- gen6_set_rps(dev_priv->dev, new_delay);
+ if (new_delay >= dev_priv->rps.min_delay &&
+ new_delay <= dev_priv->rps.max_delay) {
+ if (IS_VALLEYVIEW(dev_priv->dev))
+ valleyview_set_rps(dev_priv->dev, new_delay);
+ else
+ gen6_set_rps(dev_priv->dev, new_delay);
+ }
+
+ if (IS_VALLEYVIEW(dev_priv->dev)) {
+ /*
+ * On VLV, when we enter RC6 we may not be at the minimum
+ * voltage level, so arm a timer to check. It should only
+ * fire when there's activity or once after we've entered
+ * RC6, and then won't be re-armed until the next RPS interrupt.
+ */
+ mod_delayed_work(dev_priv->wq, &dev_priv->rps.vlv_work,
+ msecs_to_jiffies(100));
}
mutex_unlock(&dev_priv->rps.hw_lock);
@@ -529,7 +781,7 @@ static void ivybridge_parity_work(struct work_struct *work)
I915_WRITE(GEN7_MISCCPCTL, misccpctl);
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- dev_priv->gt_irq_mask &= ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+ dev_priv->gt_irq_mask &= ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
@@ -561,7 +813,7 @@ static void ivybridge_handle_parity_error(struct drm_device *dev)
return;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- dev_priv->gt_irq_mask |= GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+ dev_priv->gt_irq_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
@@ -573,25 +825,26 @@ static void snb_gt_irq_handler(struct drm_device *dev,
u32 gt_iir)
{
- if (gt_iir & (GEN6_RENDER_USER_INTERRUPT |
- GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT))
+ if (gt_iir &
+ (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
notify_ring(dev, &dev_priv->ring[RCS]);
- if (gt_iir & GEN6_BSD_USER_INTERRUPT)
+ if (gt_iir & GT_BSD_USER_INTERRUPT)
notify_ring(dev, &dev_priv->ring[VCS]);
- if (gt_iir & GEN6_BLITTER_USER_INTERRUPT)
+ if (gt_iir & GT_BLT_USER_INTERRUPT)
notify_ring(dev, &dev_priv->ring[BCS]);
- if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT |
- GT_GEN6_BSD_CS_ERROR_INTERRUPT |
- GT_RENDER_CS_ERROR_INTERRUPT)) {
+ if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
+ GT_BSD_CS_ERROR_INTERRUPT |
+ GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) {
DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
i915_handle_error(dev, false);
}
- if (gt_iir & GT_GEN7_L3_PARITY_ERROR_INTERRUPT)
+ if (gt_iir & GT_RENDER_L3_PARITY_ERROR_INTERRUPT)
ivybridge_handle_parity_error(dev);
}
+/* Legacy way of handling PM interrupts */
static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
u32 pm_iir)
{
@@ -619,23 +872,25 @@ static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
#define HPD_STORM_DETECT_PERIOD 1000
#define HPD_STORM_THRESHOLD 5
-static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
- u32 hotplug_trigger,
- const u32 *hpd)
+static inline void intel_hpd_irq_handler(struct drm_device *dev,
+ u32 hotplug_trigger,
+ const u32 *hpd)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned long irqflags;
int i;
- bool ret = false;
+ bool storm_detected = false;
- spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ if (!hotplug_trigger)
+ return;
+ spin_lock(&dev_priv->irq_lock);
for (i = 1; i < HPD_NUM_PINS; i++) {
if (!(hpd[i] & hotplug_trigger) ||
dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
continue;
+ dev_priv->hpd_event_bits |= (1 << i);
if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies,
dev_priv->hpd_stats[i].hpd_last_jiffies
+ msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) {
@@ -643,16 +898,20 @@ static inline bool hotplug_irq_storm_detect(struct drm_device *dev,
dev_priv->hpd_stats[i].hpd_cnt = 0;
} else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) {
dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED;
+ dev_priv->hpd_event_bits &= ~(1 << i);
DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i);
- ret = true;
+ storm_detected = true;
} else {
dev_priv->hpd_stats[i].hpd_cnt++;
}
}
- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+ if (storm_detected)
+ dev_priv->display.hpd_irq_setup(dev);
+ spin_unlock(&dev_priv->irq_lock);
- return ret;
+ queue_work(dev_priv->wq,
+ &dev_priv->hotplug_work);
}
static void gmbus_irq_handler(struct drm_device *dev)
@@ -669,6 +928,38 @@ static void dp_aux_irq_handler(struct drm_device *dev)
wake_up_all(&dev_priv->gmbus_wait_queue);
}
+/* Unlike gen6_queue_rps_work() from which this function is originally derived,
+ * we must be able to deal with other PM interrupts. This is complicated because
+ * of the way in which we use the masks to defer the RPS work (which for
+ * posterity is necessary because of forcewake).
+ */
+static void hsw_pm_irq_handler(struct drm_i915_private *dev_priv,
+ u32 pm_iir)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->rps.lock, flags);
+ dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
+ if (dev_priv->rps.pm_iir) {
+ I915_WRITE(GEN6_PMIMR, dev_priv->rps.pm_iir);
+ /* never want to mask useful interrupts. (also posting read) */
+ WARN_ON(I915_READ_NOTRACE(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+ /* TODO: if queue_work is slow, move it out of the spinlock */
+ queue_work(dev_priv->wq, &dev_priv->rps.work);
+ }
+ spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+
+ if (pm_iir & ~GEN6_PM_RPS_EVENTS) {
+ if (pm_iir & PM_VEBOX_USER_INTERRUPT)
+ notify_ring(dev_priv->dev, &dev_priv->ring[VECS]);
+
+ if (pm_iir & PM_VEBOX_CS_ERROR_INTERRUPT) {
+ DRM_ERROR("VEBOX CS error interrupt 0x%08x\n", pm_iir);
+ i915_handle_error(dev_priv->dev, false);
+ }
+ }
+}
+
static irqreturn_t valleyview_irq_handler(int irq, void *arg)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -727,12 +1018,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status);
- if (hotplug_trigger) {
- if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
- i915_hpd_irq_setup(dev);
- queue_work(dev_priv->wq,
- &dev_priv->hotplug_work);
- }
+
+ intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT);
}
@@ -740,7 +1028,7 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
gmbus_irq_handler(dev);
- if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+ if (pm_iir & GEN6_PM_RPS_EVENTS)
gen6_queue_rps_work(dev_priv, pm_iir);
I915_WRITE(GTIIR, gt_iir);
@@ -758,15 +1046,14 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
- if (hotplug_trigger) {
- if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_ibx))
- ibx_hpd_irq_setup(dev);
- queue_work(dev_priv->wq, &dev_priv->hotplug_work);
- }
- if (pch_iir & SDE_AUDIO_POWER_MASK)
+ intel_hpd_irq_handler(dev, hotplug_trigger, hpd_ibx);
+
+ if (pch_iir & SDE_AUDIO_POWER_MASK) {
+ int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >>
+ SDE_AUDIO_POWER_SHIFT);
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
- (pch_iir & SDE_AUDIO_POWER_MASK) >>
- SDE_AUDIO_POWER_SHIFT);
+ port_name(port));
+ }
if (pch_iir & SDE_AUX_MASK)
dp_aux_irq_handler(dev);
@@ -795,10 +1082,64 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
if (pch_iir & (SDE_TRANSB_CRC_ERR | SDE_TRANSA_CRC_ERR))
DRM_DEBUG_DRIVER("PCH transcoder CRC error interrupt\n");
- if (pch_iir & SDE_TRANSB_FIFO_UNDER)
- DRM_DEBUG_DRIVER("PCH transcoder B underrun interrupt\n");
if (pch_iir & SDE_TRANSA_FIFO_UNDER)
- DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
+ if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
+ false))
+ DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+
+ if (pch_iir & SDE_TRANSB_FIFO_UNDER)
+ if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
+ false))
+ DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+}
+
+static void ivb_err_int_handler(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 err_int = I915_READ(GEN7_ERR_INT);
+
+ if (err_int & ERR_INT_POISON)
+ DRM_ERROR("Poison interrupt\n");
+
+ if (err_int & ERR_INT_FIFO_UNDERRUN_A)
+ if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
+ DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
+
+ if (err_int & ERR_INT_FIFO_UNDERRUN_B)
+ if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
+ DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
+
+ if (err_int & ERR_INT_FIFO_UNDERRUN_C)
+ if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_C, false))
+ DRM_DEBUG_DRIVER("Pipe C FIFO underrun\n");
+
+ I915_WRITE(GEN7_ERR_INT, err_int);
+}
+
+static void cpt_serr_int_handler(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 serr_int = I915_READ(SERR_INT);
+
+ if (serr_int & SERR_INT_POISON)
+ DRM_ERROR("PCH poison interrupt\n");
+
+ if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
+ if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
+ false))
+ DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+
+ if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
+ if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
+ false))
+ DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+
+ if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
+ if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
+ false))
+ DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
+
+ I915_WRITE(SERR_INT, serr_int);
}
static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
@@ -807,15 +1148,14 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
int pipe;
u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
- if (hotplug_trigger) {
- if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_cpt))
- ibx_hpd_irq_setup(dev);
- queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+ intel_hpd_irq_handler(dev, hotplug_trigger, hpd_cpt);
+
+ if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) {
+ int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
+ SDE_AUDIO_POWER_SHIFT_CPT);
+ DRM_DEBUG_DRIVER("PCH audio power change on port %c\n",
+ port_name(port));
}
- if (pch_iir & SDE_AUDIO_POWER_MASK_CPT)
- DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
- (pch_iir & SDE_AUDIO_POWER_MASK_CPT) >>
- SDE_AUDIO_POWER_SHIFT_CPT);
if (pch_iir & SDE_AUX_MASK_CPT)
dp_aux_irq_handler(dev);
@@ -834,6 +1174,9 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
DRM_DEBUG_DRIVER(" pipe %c FDI IIR: 0x%08x\n",
pipe_name(pipe),
I915_READ(FDI_RX_IIR(pipe)));
+
+ if (pch_iir & SDE_ERROR_CPT)
+ cpt_serr_int_handler(dev);
}
static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
@@ -846,6 +1189,14 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
atomic_inc(&dev_priv->irq_received);
+ /* We get interrupts on unclaimed registers, so check for this before we
+ * do any I915_{READ,WRITE}. */
+ if (IS_HASWELL(dev) &&
+ (I915_READ_NOTRACE(FPGA_DBG) & FPGA_DBG_RM_NOCLAIM)) {
+ DRM_ERROR("Unclaimed register before interrupt\n");
+ I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+ }
+
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
@@ -861,6 +1212,15 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
POSTING_READ(SDEIER);
}
+ /* On Haswell, also mask ERR_INT because we don't want to risk
+ * generating "unclaimed register" interrupts from inside the interrupt
+ * handler. */
+ if (IS_HASWELL(dev)) {
+ spin_lock(&dev_priv->irq_lock);
+ ironlake_disable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ spin_unlock(&dev_priv->irq_lock);
+ }
+
gt_iir = I915_READ(GTIIR);
if (gt_iir) {
snb_gt_irq_handler(dev, dev_priv, gt_iir);
@@ -870,11 +1230,14 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
de_iir = I915_READ(DEIIR);
if (de_iir) {
+ if (de_iir & DE_ERR_INT_IVB)
+ ivb_err_int_handler(dev);
+
if (de_iir & DE_AUX_CHANNEL_A_IVB)
dp_aux_irq_handler(dev);
if (de_iir & DE_GSE_IVB)
- intel_opregion_gse_intr(dev);
+ intel_opregion_asle_intr(dev);
for (i = 0; i < 3; i++) {
if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
@@ -901,12 +1264,21 @@ static irqreturn_t ivybridge_irq_handler(int irq, void *arg)
pm_iir = I915_READ(GEN6_PMIIR);
if (pm_iir) {
- if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+ if (IS_HASWELL(dev))
+ hsw_pm_irq_handler(dev_priv, pm_iir);
+ else if (pm_iir & GEN6_PM_RPS_EVENTS)
gen6_queue_rps_work(dev_priv, pm_iir);
I915_WRITE(GEN6_PMIIR, pm_iir);
ret = IRQ_HANDLED;
}
+ if (IS_HASWELL(dev)) {
+ spin_lock(&dev_priv->irq_lock);
+ if (ivb_can_enable_err_int(dev))
+ ironlake_enable_display_irq(dev_priv, DE_ERR_INT_IVB);
+ spin_unlock(&dev_priv->irq_lock);
+ }
+
I915_WRITE(DEIER, de_ier);
POSTING_READ(DEIER);
if (!HAS_PCH_NOP(dev)) {
@@ -921,9 +1293,10 @@ static void ilk_gt_irq_handler(struct drm_device *dev,
struct drm_i915_private *dev_priv,
u32 gt_iir)
{
- if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+ if (gt_iir &
+ (GT_RENDER_USER_INTERRUPT | GT_RENDER_PIPECTL_NOTIFY_INTERRUPT))
notify_ring(dev, &dev_priv->ring[RCS]);
- if (gt_iir & GT_BSD_USER_INTERRUPT)
+ if (gt_iir & ILK_BSD_USER_INTERRUPT)
notify_ring(dev, &dev_priv->ring[VCS]);
}
@@ -968,7 +1341,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
dp_aux_irq_handler(dev);
if (de_iir & DE_GSE)
- intel_opregion_gse_intr(dev);
+ intel_opregion_asle_intr(dev);
if (de_iir & DE_PIPEA_VBLANK)
drm_handle_vblank(dev, 0);
@@ -976,6 +1349,17 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
if (de_iir & DE_PIPEB_VBLANK)
drm_handle_vblank(dev, 1);
+ if (de_iir & DE_POISON)
+ DRM_ERROR("Poison interrupt\n");
+
+ if (de_iir & DE_PIPEA_FIFO_UNDERRUN)
+ if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_A, false))
+ DRM_DEBUG_DRIVER("Pipe A FIFO underrun\n");
+
+ if (de_iir & DE_PIPEB_FIFO_UNDERRUN)
+ if (intel_set_cpu_fifo_underrun_reporting(dev, PIPE_B, false))
+ DRM_DEBUG_DRIVER("Pipe B FIFO underrun\n");
+
if (de_iir & DE_PLANEA_FLIP_DONE) {
intel_prepare_page_flip(dev, 0);
intel_finish_page_flip_plane(dev, 0);
@@ -1002,7 +1386,7 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
if (IS_GEN5(dev) && de_iir & DE_PCU_EVENT)
ironlake_handle_rps_change(dev);
- if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
+ if (IS_GEN6(dev) && pm_iir & GEN6_PM_RPS_EVENTS)
gen6_queue_rps_work(dev_priv, pm_iir);
I915_WRITE(GTIIR, gt_iir);
@@ -1222,11 +1606,13 @@ i915_error_state_free(struct kref *error_ref)
for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
i915_error_object_free(error->ring[i].batchbuffer);
i915_error_object_free(error->ring[i].ringbuffer);
+ i915_error_object_free(error->ring[i].ctx);
kfree(error->ring[i].requests);
}
kfree(error->active_bo);
kfree(error->overlay);
+ kfree(error->display);
kfree(error);
}
static void capture_bo(struct drm_i915_error_buffer *err,
@@ -1273,7 +1659,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
struct drm_i915_gem_object *obj;
int i = 0;
- list_for_each_entry(obj, head, gtt_list) {
+ list_for_each_entry(obj, head, global_list) {
if (obj->pin_count == 0)
continue;
@@ -1415,7 +1801,7 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
if (ring->id != RCS || !error->ccid)
return;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list) {
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
if ((error->ccid & PAGE_MASK) == obj->gtt_offset) {
ering->ctx = i915_error_object_create_sized(dev_priv,
obj, 1);
@@ -1552,7 +1938,7 @@ static void i915_capture_error_state(struct drm_device *dev)
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
i++;
error->active_bo_count = i;
- list_for_each_entry(obj, &dev_priv->mm.bound_list, gtt_list)
+ list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
if (obj->pin_count)
i++;
error->pinned_bo_count = i - error->active_bo_count;
@@ -1932,38 +2318,28 @@ ring_last_seqno(struct intel_ring_buffer *ring)
struct drm_i915_gem_request, list)->seqno;
}
-static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
+static bool
+ring_idle(struct intel_ring_buffer *ring, u32 seqno)
{
- if (list_empty(&ring->request_list) ||
- i915_seqno_passed(ring->get_seqno(ring, false),
- ring_last_seqno(ring))) {
- /* Issue a wake-up to catch stuck h/w. */
- if (waitqueue_active(&ring->irq_queue)) {
- DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
- ring->name);
- wake_up_all(&ring->irq_queue);
- *err = true;
- }
- return true;
- }
- return false;
+ return (list_empty(&ring->request_list) ||
+ i915_seqno_passed(seqno, ring_last_seqno(ring)));
}
-static bool semaphore_passed(struct intel_ring_buffer *ring)
+static struct intel_ring_buffer *
+semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
- u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
- struct intel_ring_buffer *signaller;
- u32 cmd, ipehr, acthd_min;
+ u32 cmd, ipehr, acthd, acthd_min;
ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
if ((ipehr & ~(0x3 << 16)) !=
(MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
- return false;
+ return NULL;
/* ACTHD is likely pointing to the dword after the actual command,
* so scan backwards until we find the MBOX.
*/
+ acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
acthd_min = max((int)acthd - 3 * 4, 0);
do {
cmd = ioread32(ring->virtual_start + acthd);
@@ -1972,124 +2348,216 @@ static bool semaphore_passed(struct intel_ring_buffer *ring)
acthd -= 4;
if (acthd < acthd_min)
- return false;
+ return NULL;
} while (1);
- signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
- return i915_seqno_passed(signaller->get_seqno(signaller, false),
- ioread32(ring->virtual_start+acthd+4)+1);
+ *seqno = ioread32(ring->virtual_start+acthd+4)+1;
+ return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
}
-static bool kick_ring(struct intel_ring_buffer *ring)
+static int semaphore_passed(struct intel_ring_buffer *ring)
{
- struct drm_device *dev = ring->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 tmp = I915_READ_CTL(ring);
- if (tmp & RING_WAIT) {
- DRM_ERROR("Kicking stuck wait on %s\n",
- ring->name);
- I915_WRITE_CTL(ring, tmp);
- return true;
- }
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+ struct intel_ring_buffer *signaller;
+ u32 seqno, ctl;
- if (INTEL_INFO(dev)->gen >= 6 &&
- tmp & RING_WAIT_SEMAPHORE &&
- semaphore_passed(ring)) {
- DRM_ERROR("Kicking stuck semaphore on %s\n",
- ring->name);
- I915_WRITE_CTL(ring, tmp);
- return true;
- }
- return false;
+ ring->hangcheck.deadlock = true;
+
+ signaller = semaphore_waits_for(ring, &seqno);
+ if (signaller == NULL || signaller->hangcheck.deadlock)
+ return -1;
+
+ /* cursory check for an unkickable deadlock */
+ ctl = I915_READ_CTL(signaller);
+ if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) < 0)
+ return -1;
+
+ return i915_seqno_passed(signaller->get_seqno(signaller, false), seqno);
}
-static bool i915_hangcheck_hung(struct drm_device *dev)
+static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- if (dev_priv->gpu_error.hangcheck_count++ > 1) {
- bool hung = true;
+ struct intel_ring_buffer *ring;
+ int i;
- DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
- i915_handle_error(dev, true);
+ for_each_ring(ring, dev_priv, i)
+ ring->hangcheck.deadlock = false;
+}
- if (!IS_GEN2(dev)) {
- struct intel_ring_buffer *ring;
- int i;
+static enum intel_ring_hangcheck_action
+ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 tmp;
- /* Is the chip hanging on a WAIT_FOR_EVENT?
- * If so we can simply poke the RB_WAIT bit
- * and break the hang. This should work on
- * all but the second generation chipsets.
- */
- for_each_ring(ring, dev_priv, i)
- hung &= !kick_ring(ring);
- }
+ if (ring->hangcheck.acthd != acthd)
+ return active;
+ if (IS_GEN2(dev))
return hung;
+
+ /* Is the chip hanging on a WAIT_FOR_EVENT?
+ * If so we can simply poke the RB_WAIT bit
+ * and break the hang. This should work on
+ * all but the second generation chipsets.
+ */
+ tmp = I915_READ_CTL(ring);
+ if (tmp & RING_WAIT) {
+ DRM_ERROR("Kicking stuck wait on %s\n",
+ ring->name);
+ I915_WRITE_CTL(ring, tmp);
+ return kick;
}
- return false;
+ if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) {
+ switch (semaphore_passed(ring)) {
+ default:
+ return hung;
+ case 1:
+ DRM_ERROR("Kicking stuck semaphore on %s\n",
+ ring->name);
+ I915_WRITE_CTL(ring, tmp);
+ return kick;
+ case 0:
+ return wait;
+ }
+ }
+
+ return hung;
}
/**
* This is called when the chip hasn't reported back with completed
- * batchbuffers in a long time. The first time this is called we simply record
- * ACTHD. If ACTHD hasn't changed by the time the hangcheck timer elapses
- * again, we assume the chip is wedged and try to fix it.
+ * batchbuffers in a long time. We keep track per ring seqno progress and
+ * if there are no progress, hangcheck score for that ring is increased.
+ * Further, acthd is inspected to see if the ring is stuck. On stuck case
+ * we kick the ring. If we see no progress on three subsequent calls
+ * we assume chip is wedged and try to fix it by resetting the chip.
*/
void i915_hangcheck_elapsed(unsigned long data)
{
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG];
struct intel_ring_buffer *ring;
- bool err = false, idle;
int i;
+ int busy_count = 0, rings_hung = 0;
+ bool stuck[I915_NUM_RINGS] = { 0 };
+#define BUSY 1
+#define KICK 5
+#define HUNG 20
+#define FIRE 30
if (!i915_enable_hangcheck)
return;
- memset(acthd, 0, sizeof(acthd));
- idle = true;
for_each_ring(ring, dev_priv, i) {
- idle &= i915_hangcheck_ring_idle(ring, &err);
- acthd[i] = intel_ring_get_active_head(ring);
- }
+ u32 seqno, acthd;
+ bool busy = true;
+
+ semaphore_clear_deadlocks(dev_priv);
+
+ seqno = ring->get_seqno(ring, false);
+ acthd = intel_ring_get_active_head(ring);
+
+ if (ring->hangcheck.seqno == seqno) {
+ if (ring_idle(ring, seqno)) {
+ if (waitqueue_active(&ring->irq_queue)) {
+ /* Issue a wake-up to catch stuck h/w. */
+ DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
+ ring->name);
+ wake_up_all(&ring->irq_queue);
+ ring->hangcheck.score += HUNG;
+ } else
+ busy = false;
+ } else {
+ int score;
+
+ /* We always increment the hangcheck score
+ * if the ring is busy and still processing
+ * the same request, so that no single request
+ * can run indefinitely (such as a chain of
+ * batches). The only time we do not increment
+ * the hangcheck score on this ring, if this
+ * ring is in a legitimate wait for another
+ * ring. In that case the waiting ring is a
+ * victim and we want to be sure we catch the
+ * right culprit. Then every time we do kick
+ * the ring, add a small increment to the
+ * score so that we can catch a batch that is
+ * being repeatedly kicked and so responsible
+ * for stalling the machine.
+ */
+ ring->hangcheck.action = ring_stuck(ring,
+ acthd);
+
+ switch (ring->hangcheck.action) {
+ case wait:
+ score = 0;
+ break;
+ case active:
+ score = BUSY;
+ break;
+ case kick:
+ score = KICK;
+ break;
+ case hung:
+ score = HUNG;
+ stuck[i] = true;
+ break;
+ }
+ ring->hangcheck.score += score;
+ }
+ } else {
+ /* Gradually reduce the count so that we catch DoS
+ * attempts across multiple batches.
+ */
+ if (ring->hangcheck.score > 0)
+ ring->hangcheck.score--;
+ }
- /* If all work is done then ACTHD clearly hasn't advanced. */
- if (idle) {
- if (err) {
- if (i915_hangcheck_hung(dev))
- return;
+ ring->hangcheck.seqno = seqno;
+ ring->hangcheck.acthd = acthd;
+ busy_count += busy;
+ }
- goto repeat;
+ for_each_ring(ring, dev_priv, i) {
+ if (ring->hangcheck.score > FIRE) {
+ DRM_ERROR("%s on %s\n",
+ stuck[i] ? "stuck" : "no progress",
+ ring->name);
+ rings_hung++;
}
-
- dev_priv->gpu_error.hangcheck_count = 0;
- return;
}
- i915_get_extra_instdone(dev, instdone);
- if (memcmp(dev_priv->gpu_error.last_acthd, acthd,
- sizeof(acthd)) == 0 &&
- memcmp(dev_priv->gpu_error.prev_instdone, instdone,
- sizeof(instdone)) == 0) {
- if (i915_hangcheck_hung(dev))
- return;
- } else {
- dev_priv->gpu_error.hangcheck_count = 0;
+ if (rings_hung)
+ return i915_handle_error(dev, true);
- memcpy(dev_priv->gpu_error.last_acthd, acthd,
- sizeof(acthd));
- memcpy(dev_priv->gpu_error.prev_instdone, instdone,
- sizeof(instdone));
- }
+ if (busy_count)
+ /* Reset timer case chip hangs without another request
+ * being added */
+ mod_timer(&dev_priv->gpu_error.hangcheck_timer,
+ round_jiffies_up(jiffies +
+ DRM_I915_HANGCHECK_JIFFIES));
+}
+
+static void ibx_irq_preinstall(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (HAS_PCH_NOP(dev))
+ return;
-repeat:
- /* Reset timer case chip hangs without another request being added */
- mod_timer(&dev_priv->gpu_error.hangcheck_timer,
- round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
+ /* south display irq */
+ I915_WRITE(SDEIMR, 0xffffffff);
+ /*
+ * SDEIER is also touched by the interrupt handler to work around missed
+ * PCH interrupts. Hence we can't update it after the interrupt handler
+ * is enabled - instead we unconditionally enable all PCH interrupt
+ * sources here, but then only unmask them as needed with SDEIMR.
+ */
+ I915_WRITE(SDEIER, 0xffffffff);
+ POSTING_READ(SDEIER);
}
/* drm_dma.h hooks
@@ -2113,19 +2581,34 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
I915_WRITE(GTIER, 0x0);
POSTING_READ(GTIER);
- if (HAS_PCH_NOP(dev))
- return;
+ ibx_irq_preinstall(dev);
+}
- /* south display irq */
- I915_WRITE(SDEIMR, 0xffffffff);
- /*
- * SDEIER is also touched by the interrupt handler to work around missed
- * PCH interrupts. Hence we can't update it after the interrupt handler
- * is enabled - instead we unconditionally enable all PCH interrupt
- * sources here, but then only unmask them as needed with SDEIMR.
- */
- I915_WRITE(SDEIER, 0xffffffff);
- POSTING_READ(SDEIER);
+static void ivybridge_irq_preinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ atomic_set(&dev_priv->irq_received, 0);
+
+ I915_WRITE(HWSTAM, 0xeffe);
+
+ /* XXX hotplug from PCH */
+
+ I915_WRITE(DEIMR, 0xffffffff);
+ I915_WRITE(DEIER, 0x0);
+ POSTING_READ(DEIER);
+
+ /* and GT */
+ I915_WRITE(GTIMR, 0xffffffff);
+ I915_WRITE(GTIER, 0x0);
+ POSTING_READ(GTIER);
+
+ /* Power management */
+ I915_WRITE(GEN6_PMIMR, 0xffffffff);
+ I915_WRITE(GEN6_PMIER, 0x0);
+ POSTING_READ(GEN6_PMIER);
+
+ ibx_irq_preinstall(dev);
}
static void valleyview_irq_preinstall(struct drm_device *dev)
@@ -2201,33 +2684,41 @@ static void ibx_irq_postinstall(struct drm_device *dev)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 mask;
- if (HAS_PCH_IBX(dev))
- mask = SDE_GMBUS | SDE_AUX_MASK;
- else
- mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT;
-
if (HAS_PCH_NOP(dev))
return;
+ if (HAS_PCH_IBX(dev)) {
+ mask = SDE_GMBUS | SDE_AUX_MASK | SDE_TRANSB_FIFO_UNDER |
+ SDE_TRANSA_FIFO_UNDER | SDE_POISON;
+ } else {
+ mask = SDE_GMBUS_CPT | SDE_AUX_MASK_CPT | SDE_ERROR_CPT;
+
+ I915_WRITE(SERR_INT, I915_READ(SERR_INT));
+ }
+
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
I915_WRITE(SDEIMR, ~mask);
}
static int ironlake_irq_postinstall(struct drm_device *dev)
{
+ unsigned long irqflags;
+
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE |
- DE_AUX_CHANNEL_A;
- u32 render_irqs;
+ DE_AUX_CHANNEL_A | DE_PIPEB_FIFO_UNDERRUN |
+ DE_PIPEA_FIFO_UNDERRUN | DE_POISON;
+ u32 gt_irqs;
dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(DEIMR, dev_priv->irq_mask);
- I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK | DE_PIPEB_VBLANK);
+ I915_WRITE(DEIER, display_mask |
+ DE_PIPEA_VBLANK | DE_PIPEB_VBLANK | DE_PCU_EVENT);
POSTING_READ(DEIER);
dev_priv->gt_irq_mask = ~0;
@@ -2235,26 +2726,28 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ gt_irqs = GT_RENDER_USER_INTERRUPT;
+
if (IS_GEN6(dev))
- render_irqs =
- GT_USER_INTERRUPT |
- GEN6_BSD_USER_INTERRUPT |
- GEN6_BLITTER_USER_INTERRUPT;
+ gt_irqs |= GT_BLT_USER_INTERRUPT | GT_BSD_USER_INTERRUPT;
else
- render_irqs =
- GT_USER_INTERRUPT |
- GT_PIPE_NOTIFY |
- GT_BSD_USER_INTERRUPT;
- I915_WRITE(GTIER, render_irqs);
+ gt_irqs |= GT_RENDER_PIPECTL_NOTIFY_INTERRUPT |
+ ILK_BSD_USER_INTERRUPT;
+
+ I915_WRITE(GTIER, gt_irqs);
POSTING_READ(GTIER);
ibx_irq_postinstall(dev);
if (IS_IRONLAKE_M(dev)) {
- /* Clear & enable PCU event interrupts */
- I915_WRITE(DEIIR, DE_PCU_EVENT);
- I915_WRITE(DEIER, I915_READ(DEIER) | DE_PCU_EVENT);
+ /* Enable PCU event interrupts
+ *
+ * spinlocking not required here for correctness since interrupt
+ * setup is guaranteed to run in single-threaded context. But we
+ * need it to make the assert_spin_locked happy. */
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
ironlake_enable_display_irq(dev_priv, DE_PCU_EVENT);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
return 0;
@@ -2269,12 +2762,15 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
DE_PLANEC_FLIP_DONE_IVB |
DE_PLANEB_FLIP_DONE_IVB |
DE_PLANEA_FLIP_DONE_IVB |
- DE_AUX_CHANNEL_A_IVB;
- u32 render_irqs;
+ DE_AUX_CHANNEL_A_IVB |
+ DE_ERR_INT_IVB;
+ u32 pm_irqs = GEN6_PM_RPS_EVENTS;
+ u32 gt_irqs;
dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
+ I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(DEIMR, dev_priv->irq_mask);
I915_WRITE(DEIER,
@@ -2284,16 +2780,32 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
DE_PIPEA_VBLANK_IVB);
POSTING_READ(DEIER);
- dev_priv->gt_irq_mask = ~GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
+ dev_priv->gt_irq_mask = ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
- render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
- GEN6_BLITTER_USER_INTERRUPT | GT_GEN7_L3_PARITY_ERROR_INTERRUPT;
- I915_WRITE(GTIER, render_irqs);
+ gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
+ GT_BLT_USER_INTERRUPT | GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+ I915_WRITE(GTIER, gt_irqs);
POSTING_READ(GTIER);
+ I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+ if (HAS_VEBOX(dev))
+ pm_irqs |= PM_VEBOX_USER_INTERRUPT |
+ PM_VEBOX_CS_ERROR_INTERRUPT;
+
+ /* Our enable/disable rps functions may touch these registers so
+ * make sure to set a known state for only the non-RPS bits.
+ * The RMW is extra paranoia since this should be called after being set
+ * to a known state in preinstall.
+ * */
+ I915_WRITE(GEN6_PMIMR,
+ (I915_READ(GEN6_PMIMR) | ~GEN6_PM_RPS_EVENTS) & ~pm_irqs);
+ I915_WRITE(GEN6_PMIER,
+ (I915_READ(GEN6_PMIER) & GEN6_PM_RPS_EVENTS) | pm_irqs);
+ POSTING_READ(GEN6_PMIER);
+
ibx_irq_postinstall(dev);
return 0;
@@ -2302,10 +2814,9 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
static int valleyview_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 gt_irqs;
u32 enable_mask;
u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV;
- u32 render_irqs;
- u16 msid;
enable_mask = I915_DISPLAY_PORT_INTERRUPT;
enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
@@ -2321,13 +2832,6 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
- /* Hack for broken MSIs on VLV */
- pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000);
- pci_read_config_word(dev->pdev, 0x98, &msid);
- msid &= 0xff; /* mask out delivery bits */
- msid |= (1<<14);
- pci_write_config_word(dev_priv->dev->pdev, 0x98, msid);
-
I915_WRITE(PORT_HOTPLUG_EN, 0);
POSTING_READ(PORT_HOTPLUG_EN);
@@ -2348,9 +2852,9 @@ static int valleyview_irq_postinstall(struct drm_device *dev)
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
- render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
- GEN6_BLITTER_USER_INTERRUPT;
- I915_WRITE(GTIER, render_irqs);
+ gt_irqs = GT_RENDER_USER_INTERRUPT | GT_BSD_USER_INTERRUPT |
+ GT_BLT_USER_INTERRUPT;
+ I915_WRITE(GTIER, gt_irqs);
POSTING_READ(GTIER);
/* ack & enable invalid PTE error interrupts */
@@ -2402,6 +2906,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(DEIMR, 0xffffffff);
I915_WRITE(DEIER, 0x0);
I915_WRITE(DEIIR, I915_READ(DEIIR));
+ if (IS_GEN7(dev))
+ I915_WRITE(GEN7_ERR_INT, I915_READ(GEN7_ERR_INT));
I915_WRITE(GTIMR, 0xffffffff);
I915_WRITE(GTIER, 0x0);
@@ -2413,6 +2919,8 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(SDEIMR, 0xffffffff);
I915_WRITE(SDEIER, 0x0);
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+ if (HAS_PCH_CPT(dev) || HAS_PCH_LPT(dev))
+ I915_WRITE(SERR_INT, I915_READ(SERR_INT));
}
static void i8xx_irq_preinstall(struct drm_device * dev)
@@ -2626,7 +3134,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
I915_WRITE(IER, enable_mask);
POSTING_READ(IER);
- intel_opregion_enable_asle(dev);
+ i915_enable_asle_pipestat(dev);
return 0;
}
@@ -2715,12 +3223,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status);
- if (hotplug_trigger) {
- if (hotplug_irq_storm_detect(dev, hotplug_trigger, hpd_status_i915))
- i915_hpd_irq_setup(dev);
- queue_work(dev_priv->wq,
- &dev_priv->hotplug_work);
- }
+
+ intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
+
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
POSTING_READ(PORT_HOTPLUG_STAT);
}
@@ -2860,7 +3365,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
I915_WRITE(PORT_HOTPLUG_EN, 0);
POSTING_READ(PORT_HOTPLUG_EN);
- intel_opregion_enable_asle(dev);
+ i915_enable_asle_pipestat(dev);
return 0;
}
@@ -2872,6 +3377,8 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
struct intel_encoder *intel_encoder;
u32 hotplug_en;
+ assert_spin_locked(&dev_priv->irq_lock);
+
if (I915_HAS_HOTPLUG(dev)) {
hotplug_en = I915_READ(PORT_HOTPLUG_EN);
hotplug_en &= ~HOTPLUG_INT_EN_MASK;
@@ -2952,17 +3459,14 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
u32 hotplug_trigger = hotplug_status & (IS_G4X(dev) ?
HOTPLUG_INT_STATUS_G4X :
- HOTPLUG_INT_STATUS_I965);
+ HOTPLUG_INT_STATUS_I915);
DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
hotplug_status);
- if (hotplug_trigger) {
- if (hotplug_irq_storm_detect(dev, hotplug_trigger,
- IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i965))
- i915_hpd_irq_setup(dev);
- queue_work(dev_priv->wq,
- &dev_priv->hotplug_work);
- }
+
+ intel_hpd_irq_handler(dev, hotplug_trigger,
+ IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
+
I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
I915_READ(PORT_HOTPLUG_STAT);
}
@@ -3113,9 +3617,9 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->disable_vblank = valleyview_disable_vblank;
dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
- /* Share pre & uninstall handlers with ILK/SNB */
+ /* Share uninstall handlers with ILK/SNB */
dev->driver->irq_handler = ivybridge_irq_handler;
- dev->driver->irq_preinstall = ironlake_irq_preinstall;
+ dev->driver->irq_preinstall = ivybridge_irq_preinstall;
dev->driver->irq_postinstall = ivybridge_irq_postinstall;
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ivybridge_enable_vblank;
@@ -3158,6 +3662,7 @@ void intel_hpd_init(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
+ unsigned long irqflags;
int i;
for (i = 1; i < HPD_NUM_PINS; i++) {
@@ -3170,6 +3675,11 @@ void intel_hpd_init(struct drm_device *dev)
if (!connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE)
connector->polled = DRM_CONNECTOR_POLL_HPD;
}
+
+ /* Interrupt setup is already guaranteed to be single-threaded, this is
+ * just to make the assert_spin_locked checks happy. */
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (dev_priv->display.hpd_irq_setup)
dev_priv->display.hpd_irq_setup(dev);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 2d6b62e42daf..f2326fc60ac9 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -147,15 +147,9 @@
#define VGA_MSR_MEM_EN (1<<1)
#define VGA_MSR_CGA_MODE (1<<0)
-/*
- * SR01 is the only VGA register touched on non-UMS setups.
- * VLV doesn't do UMS, so the sequencer index/data registers
- * are the only VGA registers which need to include
- * display_mmio_offset.
- */
-#define VGA_SR_INDEX (dev_priv->info->display_mmio_offset + 0x3c4)
+#define VGA_SR_INDEX 0x3c4
#define SR01 1
-#define VGA_SR_DATA (dev_priv->info->display_mmio_offset + 0x3c5)
+#define VGA_SR_DATA 0x3c5
#define VGA_AR_INDEX 0x3c0
#define VGA_AR_VID_EN (1<<5)
@@ -265,13 +259,19 @@
#define MI_SEMAPHORE_UPDATE (1<<21)
#define MI_SEMAPHORE_COMPARE (1<<20)
#define MI_SEMAPHORE_REGISTER (1<<18)
-#define MI_SEMAPHORE_SYNC_RV (2<<16)
-#define MI_SEMAPHORE_SYNC_RB (0<<16)
-#define MI_SEMAPHORE_SYNC_VR (0<<16)
-#define MI_SEMAPHORE_SYNC_VB (2<<16)
-#define MI_SEMAPHORE_SYNC_BR (2<<16)
-#define MI_SEMAPHORE_SYNC_BV (0<<16)
-#define MI_SEMAPHORE_SYNC_INVALID (1<<0)
+#define MI_SEMAPHORE_SYNC_VR (0<<16) /* RCS wait for VCS (RVSYNC) */
+#define MI_SEMAPHORE_SYNC_VER (1<<16) /* RCS wait for VECS (RVESYNC) */
+#define MI_SEMAPHORE_SYNC_BR (2<<16) /* RCS wait for BCS (RBSYNC) */
+#define MI_SEMAPHORE_SYNC_BV (0<<16) /* VCS wait for BCS (VBSYNC) */
+#define MI_SEMAPHORE_SYNC_VEV (1<<16) /* VCS wait for VECS (VVESYNC) */
+#define MI_SEMAPHORE_SYNC_RV (2<<16) /* VCS wait for RCS (VRSYNC) */
+#define MI_SEMAPHORE_SYNC_RB (0<<16) /* BCS wait for RCS (BRSYNC) */
+#define MI_SEMAPHORE_SYNC_VEB (1<<16) /* BCS wait for VECS (BVESYNC) */
+#define MI_SEMAPHORE_SYNC_VB (2<<16) /* BCS wait for VCS (BVSYNC) */
+#define MI_SEMAPHORE_SYNC_BVE (0<<16) /* VECS wait for BCS (VEBSYNC) */
+#define MI_SEMAPHORE_SYNC_VVE (1<<16) /* VECS wait for VCS (VEVSYNC) */
+#define MI_SEMAPHORE_SYNC_RVE (2<<16) /* VECS wait for RCS (VERSYNC) */
+#define MI_SEMAPHORE_SYNC_INVALID (3<<16)
/*
* 3D instructions used by the kernel
*/
@@ -342,33 +342,74 @@
#define DEBUG_RESET_DISPLAY (1<<9)
/*
- * DPIO - a special bus for various display related registers to hide behind:
- * 0x800c: m1, m2, n, p1, p2, k dividers
- * 0x8014: REF and SFR select
- * 0x8014: N divider, VCO select
- * 0x801c/3c: core clock bits
- * 0x8048/68: low pass filter coefficients
- * 0x8100: fast clock controls
+ * IOSF sideband
+ */
+#define VLV_IOSF_DOORBELL_REQ (VLV_DISPLAY_BASE + 0x2100)
+#define IOSF_DEVFN_SHIFT 24
+#define IOSF_OPCODE_SHIFT 16
+#define IOSF_PORT_SHIFT 8
+#define IOSF_BYTE_ENABLES_SHIFT 4
+#define IOSF_BAR_SHIFT 1
+#define IOSF_SB_BUSY (1<<0)
+#define IOSF_PORT_PUNIT 0x4
+#define IOSF_PORT_NC 0x11
+#define IOSF_PORT_DPIO 0x12
+#define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104)
+#define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108)
+
+#define PUNIT_OPCODE_REG_READ 6
+#define PUNIT_OPCODE_REG_WRITE 7
+
+#define PUNIT_REG_GPU_LFM 0xd3
+#define PUNIT_REG_GPU_FREQ_REQ 0xd4
+#define PUNIT_REG_GPU_FREQ_STS 0xd8
+#define PUNIT_REG_MEDIA_TURBO_FREQ_REQ 0xdc
+
+#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */
+#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */
+
+#define IOSF_NC_FB_GFX_FREQ_FUSE 0x1c
+#define FB_GFX_MAX_FREQ_FUSE_SHIFT 3
+#define FB_GFX_MAX_FREQ_FUSE_MASK 0x000007f8
+#define FB_GFX_FGUARANTEED_FREQ_FUSE_SHIFT 11
+#define FB_GFX_FGUARANTEED_FREQ_FUSE_MASK 0x0007f800
+#define IOSF_NC_FB_GFX_FMAX_FUSE_HI 0x34
+#define FB_FMAX_VMIN_FREQ_HI_MASK 0x00000007
+#define IOSF_NC_FB_GFX_FMAX_FUSE_LO 0x30
+#define FB_FMAX_VMIN_FREQ_LO_SHIFT 27
+#define FB_FMAX_VMIN_FREQ_LO_MASK 0xf8000000
+
+/*
+ * DPIO - a special bus for various display related registers to hide behind
*
* DPIO is VLV only.
+ *
+ * Note: digital port B is DDI0, digital pot C is DDI1
*/
-#define DPIO_PKT (VLV_DISPLAY_BASE + 0x2100)
-#define DPIO_RID (0<<24)
-#define DPIO_OP_WRITE (1<<16)
-#define DPIO_OP_READ (0<<16)
-#define DPIO_PORTID (0x12<<8)
-#define DPIO_BYTE (0xf<<4)
-#define DPIO_BUSY (1<<0) /* status only */
-#define DPIO_DATA (VLV_DISPLAY_BASE + 0x2104)
-#define DPIO_REG (VLV_DISPLAY_BASE + 0x2108)
+#define DPIO_DEVFN 0
+#define DPIO_OPCODE_REG_WRITE 1
+#define DPIO_OPCODE_REG_READ 0
+
#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110)
#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */
#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */
#define DPIO_SFR_BYPASS (1<<1)
#define DPIO_RESET (1<<0)
+#define _DPIO_TX3_SWING_CTL4_A 0x690
+#define _DPIO_TX3_SWING_CTL4_B 0x2a90
+#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX_SWING_CTL4_A, \
+ _DPIO_TX3_SWING_CTL4_B)
+
+/*
+ * Per pipe/PLL DPIO regs
+ */
#define _DPIO_DIV_A 0x800c
#define DPIO_POST_DIV_SHIFT (28) /* 3 bits */
+#define DPIO_POST_DIV_DAC 0
+#define DPIO_POST_DIV_HDMIDP 1 /* DAC 225-400M rate */
+#define DPIO_POST_DIV_LVDS1 2
+#define DPIO_POST_DIV_LVDS2 3
#define DPIO_K_SHIFT (24) /* 4 bits */
#define DPIO_P1_SHIFT (21) /* 3 bits */
#define DPIO_P2_SHIFT (16) /* 5 bits */
@@ -394,14 +435,111 @@
#define _DPIO_CORE_CLK_B 0x803c
#define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B)
-#define _DPIO_LFP_COEFF_A 0x8048
-#define _DPIO_LFP_COEFF_B 0x8068
-#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B)
+#define _DPIO_IREF_CTL_A 0x8040
+#define _DPIO_IREF_CTL_B 0x8060
+#define DPIO_IREF_CTL(pipe) _PIPE(pipe, _DPIO_IREF_CTL_A, _DPIO_IREF_CTL_B)
+
+#define DPIO_IREF_BCAST 0xc044
+#define _DPIO_IREF_A 0x8044
+#define _DPIO_IREF_B 0x8064
+#define DPIO_IREF(pipe) _PIPE(pipe, _DPIO_IREF_A, _DPIO_IREF_B)
+
+#define _DPIO_PLL_CML_A 0x804c
+#define _DPIO_PLL_CML_B 0x806c
+#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B)
+
+#define _DPIO_LPF_COEFF_A 0x8048
+#define _DPIO_LPF_COEFF_B 0x8068
+#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B)
+
+#define DPIO_CALIBRATION 0x80ac
#define DPIO_FASTCLK_DISABLE 0x8100
-#define DPIO_DATA_CHANNEL1 0x8220
-#define DPIO_DATA_CHANNEL2 0x8420
+/*
+ * Per DDI channel DPIO regs
+ */
+
+#define _DPIO_PCS_TX_0 0x8200
+#define _DPIO_PCS_TX_1 0x8400
+#define DPIO_PCS_TX_LANE2_RESET (1<<16)
+#define DPIO_PCS_TX_LANE1_RESET (1<<7)
+#define DPIO_PCS_TX(port) _PORT(port, _DPIO_PCS_TX_0, _DPIO_PCS_TX_1)
+
+#define _DPIO_PCS_CLK_0 0x8204
+#define _DPIO_PCS_CLK_1 0x8404
+#define DPIO_PCS_CLK_CRI_RXEB_EIOS_EN (1<<22)
+#define DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21)
+#define DPIO_PCS_CLK_DATAWIDTH_SHIFT (6)
+#define DPIO_PCS_CLK_SOFT_RESET (1<<5)
+#define DPIO_PCS_CLK(port) _PORT(port, _DPIO_PCS_CLK_0, _DPIO_PCS_CLK_1)
+
+#define _DPIO_PCS_CTL_OVR1_A 0x8224
+#define _DPIO_PCS_CTL_OVR1_B 0x8424
+#define DPIO_PCS_CTL_OVER1(port) _PORT(port, _DPIO_PCS_CTL_OVR1_A, \
+ _DPIO_PCS_CTL_OVR1_B)
+
+#define _DPIO_PCS_STAGGER0_A 0x822c
+#define _DPIO_PCS_STAGGER0_B 0x842c
+#define DPIO_PCS_STAGGER0(port) _PORT(port, _DPIO_PCS_STAGGER0_A, \
+ _DPIO_PCS_STAGGER0_B)
+
+#define _DPIO_PCS_STAGGER1_A 0x8230
+#define _DPIO_PCS_STAGGER1_B 0x8430
+#define DPIO_PCS_STAGGER1(port) _PORT(port, _DPIO_PCS_STAGGER1_A, \
+ _DPIO_PCS_STAGGER1_B)
+
+#define _DPIO_PCS_CLOCKBUF0_A 0x8238
+#define _DPIO_PCS_CLOCKBUF0_B 0x8438
+#define DPIO_PCS_CLOCKBUF0(port) _PORT(port, _DPIO_PCS_CLOCKBUF0_A, \
+ _DPIO_PCS_CLOCKBUF0_B)
+
+#define _DPIO_PCS_CLOCKBUF8_A 0x825c
+#define _DPIO_PCS_CLOCKBUF8_B 0x845c
+#define DPIO_PCS_CLOCKBUF8(port) _PORT(port, _DPIO_PCS_CLOCKBUF8_A, \
+ _DPIO_PCS_CLOCKBUF8_B)
+
+#define _DPIO_TX_SWING_CTL2_A 0x8288
+#define _DPIO_TX_SWING_CTL2_B 0x8488
+#define DPIO_TX_SWING_CTL2(port) _PORT(port, _DPIO_TX_SWING_CTL2_A, \
+ _DPIO_TX_SWING_CTL2_B)
+
+#define _DPIO_TX_SWING_CTL3_A 0x828c
+#define _DPIO_TX_SWING_CTL3_B 0x848c
+#define DPIO_TX_SWING_CTL3(port) _PORT(port, _DPIO_TX_SWING_CTL3_A, \
+ _DPIO_TX_SWING_CTL3_B)
+
+#define _DPIO_TX_SWING_CTL4_A 0x8290
+#define _DPIO_TX_SWING_CTL4_B 0x8490
+#define DPIO_TX_SWING_CTL4(port) _PORT(port, _DPIO_TX_SWING_CTL4_A, \
+ _DPIO_TX_SWING_CTL4_B)
+
+#define _DPIO_TX_OCALINIT_0 0x8294
+#define _DPIO_TX_OCALINIT_1 0x8494
+#define DPIO_TX_OCALINIT_EN (1<<31)
+#define DPIO_TX_OCALINIT(port) _PORT(port, _DPIO_TX_OCALINIT_0, \
+ _DPIO_TX_OCALINIT_1)
+
+#define _DPIO_TX_CTL_0 0x82ac
+#define _DPIO_TX_CTL_1 0x84ac
+#define DPIO_TX_CTL(port) _PORT(port, _DPIO_TX_CTL_0, _DPIO_TX_CTL_1)
+
+#define _DPIO_TX_LANE_0 0x82b8
+#define _DPIO_TX_LANE_1 0x84b8
+#define DPIO_TX_LANE(port) _PORT(port, _DPIO_TX_LANE_0, _DPIO_TX_LANE_1)
+
+#define _DPIO_DATA_CHANNEL1 0x8220
+#define _DPIO_DATA_CHANNEL2 0x8420
+#define DPIO_DATA_CHANNEL(port) _PORT(port, _DPIO_DATA_CHANNEL1, _DPIO_DATA_CHANNEL2)
+
+#define _DPIO_PORT0_PCS0 0x0220
+#define _DPIO_PORT0_PCS1 0x0420
+#define _DPIO_PORT1_PCS2 0x2620
+#define _DPIO_PORT1_PCS3 0x2820
+#define DPIO_DATA_LANE_A(port) _PORT(port, _DPIO_PORT0_PCS0, _DPIO_PORT1_PCS2)
+#define DPIO_DATA_LANE_B(port) _PORT(port, _DPIO_PORT0_PCS1, _DPIO_PORT1_PCS3)
+#define DPIO_DATA_CHANNEL1 0x8220
+#define DPIO_DATA_CHANNEL2 0x8420
/*
* Fence registers
@@ -443,6 +581,7 @@
#define RENDER_RING_BASE 0x02000
#define BSD_RING_BASE 0x04000
#define GEN6_BSD_RING_BASE 0x12000
+#define VEBOX_RING_BASE 0x1a000
#define BLT_RING_BASE 0x22000
#define RING_TAIL(base) ((base)+0x30)
#define RING_HEAD(base) ((base)+0x34)
@@ -450,12 +589,20 @@
#define RING_CTL(base) ((base)+0x3c)
#define RING_SYNC_0(base) ((base)+0x40)
#define RING_SYNC_1(base) ((base)+0x44)
-#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE))
-#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE))
-#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE))
-#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE))
-#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE))
-#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE))
+#define RING_SYNC_2(base) ((base)+0x48)
+#define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE))
+#define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE))
+#define GEN6_RVESYNC (RING_SYNC_2(RENDER_RING_BASE))
+#define GEN6_VBSYNC (RING_SYNC_0(GEN6_BSD_RING_BASE))
+#define GEN6_VRSYNC (RING_SYNC_1(GEN6_BSD_RING_BASE))
+#define GEN6_VVESYNC (RING_SYNC_2(GEN6_BSD_RING_BASE))
+#define GEN6_BRSYNC (RING_SYNC_0(BLT_RING_BASE))
+#define GEN6_BVSYNC (RING_SYNC_1(BLT_RING_BASE))
+#define GEN6_BVESYNC (RING_SYNC_2(BLT_RING_BASE))
+#define GEN6_VEBSYNC (RING_SYNC_0(VEBOX_RING_BASE))
+#define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE))
+#define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE))
+#define GEN6_NOSYNC 0
#define RING_MAX_IDLE(base) ((base)+0x54)
#define RING_HWS_PGA(base) ((base)+0x80)
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
@@ -467,6 +614,7 @@
#define DONE_REG 0x40b0
#define BSD_HWS_PGA_GEN7 (0x04180)
#define BLT_HWS_PGA_GEN7 (0x04280)
+#define VEBOX_HWS_PGA_GEN7 (0x04380)
#define RING_ACTHD(base) ((base)+0x74)
#define RING_NOPID(base) ((base)+0x94)
#define RING_IMR(base) ((base)+0xa8)
@@ -527,7 +675,11 @@
#define ERROR_GEN6 0x040a0
#define GEN7_ERR_INT 0x44040
-#define ERR_INT_MMIO_UNCLAIMED (1<<13)
+#define ERR_INT_POISON (1<<31)
+#define ERR_INT_MMIO_UNCLAIMED (1<<13)
+#define ERR_INT_FIFO_UNDERRUN_C (1<<6)
+#define ERR_INT_FIFO_UNDERRUN_B (1<<3)
+#define ERR_INT_FIFO_UNDERRUN_A (1<<0)
#define FPGA_DBG 0x42300
#define FPGA_DBG_RM_NOCLAIM (1<<31)
@@ -583,24 +735,7 @@
#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4)
#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8)
#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac)
-#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
-#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
-#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
-#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
-#define I915_HWB_OOM_INTERRUPT (1<<13)
-#define I915_SYNC_STATUS_INTERRUPT (1<<12)
-#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
-#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10)
-#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9)
-#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8)
-#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7)
-#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6)
-#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5)
-#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4)
-#define I915_DEBUG_INTERRUPT (1<<2)
-#define I915_USER_INTERRUPT (1<<1)
-#define I915_ASLE_INTERRUPT (1<<0)
-#define I915_BSD_USER_INTERRUPT (1<<25)
+#define VLV_PCBR (VLV_DISPLAY_BASE + 0x2120)
#define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */
#define EIR 0x020b0
#define EMR 0x020b4
@@ -712,28 +847,6 @@
#define CACHE_MODE_1 0x7004 /* IVB+ */
#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
-/* GEN6 interrupt control
- * Note that the per-ring interrupt bits do alias with the global interrupt bits
- * in GTIMR. */
-#define GEN6_RENDER_HWSTAM 0x2098
-#define GEN6_RENDER_IMR 0x20a8
-#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8)
-#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7)
-#define GEN6_RENDER_TIMEOUT_COUNTER_EXPIRED (1 << 6)
-#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5)
-#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4)
-#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3)
-#define GEN6_RENDER_SYNC_STATUS (1 << 2)
-#define GEN6_RENDER_DEBUG_INTERRUPT (1 << 1)
-#define GEN6_RENDER_USER_INTERRUPT (1 << 0)
-
-#define GEN6_BLITTER_HWSTAM 0x22098
-#define GEN6_BLITTER_IMR 0x220a8
-#define GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT (1 << 26)
-#define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25)
-#define GEN6_BLITTER_SYNC_STATUS (1 << 24)
-#define GEN6_BLITTER_USER_INTERRUPT (1 << 22)
-
#define GEN6_BLITTER_ECOSKPD 0x221d0
#define GEN6_BLITTER_LOCK_SHIFT 16
#define GEN6_BLITTER_FBC_NOTIFY (1<<3)
@@ -744,9 +857,52 @@
#define GEN6_BSD_SLEEP_INDICATOR (1 << 3)
#define GEN6_BSD_GO_INDICATOR (1 << 4)
-#define GEN6_BSD_HWSTAM 0x12098
-#define GEN6_BSD_IMR 0x120a8
-#define GEN6_BSD_USER_INTERRUPT (1 << 12)
+/* On modern GEN architectures interrupt control consists of two sets
+ * of registers. The first set pertains to the ring generating the
+ * interrupt. The second control is for the functional block generating the
+ * interrupt. These are PM, GT, DE, etc.
+ *
+ * Luckily *knocks on wood* all the ring interrupt bits match up with the
+ * GT interrupt bits, so we don't need to duplicate the defines.
+ *
+ * These defines should cover us well from SNB->HSW with minor exceptions
+ * it can also work on ILK.
+ */
+#define GT_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26)
+#define GT_BLT_CS_ERROR_INTERRUPT (1 << 25)
+#define GT_BLT_USER_INTERRUPT (1 << 22)
+#define GT_BSD_CS_ERROR_INTERRUPT (1 << 15)
+#define GT_BSD_USER_INTERRUPT (1 << 12)
+#define GT_RENDER_L3_PARITY_ERROR_INTERRUPT (1 << 5) /* !snb */
+#define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT (1 << 4)
+#define GT_RENDER_CS_MASTER_ERROR_INTERRUPT (1 << 3)
+#define GT_RENDER_SYNC_STATUS_INTERRUPT (1 << 2)
+#define GT_RENDER_DEBUG_INTERRUPT (1 << 1)
+#define GT_RENDER_USER_INTERRUPT (1 << 0)
+
+#define PM_VEBOX_CS_ERROR_INTERRUPT (1 << 12) /* hsw+ */
+#define PM_VEBOX_USER_INTERRUPT (1 << 10) /* hsw+ */
+
+/* These are all the "old" interrupts */
+#define ILK_BSD_USER_INTERRUPT (1<<5)
+#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
+#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
+#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
+#define I915_GMCH_THERMAL_SENSOR_EVENT_INTERRUPT (1<<14) /* p-state */
+#define I915_HWB_OOM_INTERRUPT (1<<13)
+#define I915_SYNC_STATUS_INTERRUPT (1<<12)
+#define I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT (1<<11)
+#define I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT (1<<10)
+#define I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT (1<<9)
+#define I915_DISPLAY_PLANE_C_FLIP_PENDING_INTERRUPT (1<<8)
+#define I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT (1<<7)
+#define I915_DISPLAY_PIPE_A_EVENT_INTERRUPT (1<<6)
+#define I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT (1<<5)
+#define I915_DISPLAY_PIPE_B_EVENT_INTERRUPT (1<<4)
+#define I915_DEBUG_INTERRUPT (1<<2)
+#define I915_USER_INTERRUPT (1<<1)
+#define I915_ASLE_INTERRUPT (1<<0)
+#define I915_BSD_USER_INTERRUPT (1 << 25)
#define GEN6_BSD_RNCID 0x12198
@@ -807,7 +963,9 @@
#define DPFC_CTL_EN (1<<31)
#define DPFC_CTL_PLANEA (0<<30)
#define DPFC_CTL_PLANEB (1<<30)
+#define IVB_DPFC_CTL_PLANE_SHIFT (29)
#define DPFC_CTL_FENCE_EN (1<<29)
+#define IVB_DPFC_CTL_FENCE_EN (1<<28)
#define DPFC_CTL_PERSISTENT_MODE (1<<25)
#define DPFC_SR_EN (1<<10)
#define DPFC_CTL_LIMIT_1X (0<<6)
@@ -840,6 +998,7 @@
#define ILK_DPFC_CHICKEN 0x43224
#define ILK_FBC_RT_BASE 0x2128
#define ILK_FBC_RT_VALID (1<<0)
+#define SNB_FBC_FRONT_BUFFER (1<<1)
#define ILK_DISPLAY_CHICKEN1 0x42000
#define ILK_FBCQ_DIS (1<<22)
@@ -855,6 +1014,25 @@
#define SNB_CPU_FENCE_ENABLE (1<<29)
#define DPFC_CPU_FENCE_OFFSET 0x100104
+/* Framebuffer compression for Ivybridge */
+#define IVB_FBC_RT_BASE 0x7020
+
+#define IPS_CTL 0x43408
+#define IPS_ENABLE (1 << 31)
+
+#define MSG_FBC_REND_STATE 0x50380
+#define FBC_REND_NUKE (1<<2)
+#define FBC_REND_CACHE_CLEAN (1<<1)
+
+#define _HSW_PIPE_SLICE_CHICKEN_1_A 0x420B0
+#define _HSW_PIPE_SLICE_CHICKEN_1_B 0x420B4
+#define HSW_BYPASS_FBC_QUEUE (1<<22)
+#define HSW_PIPE_SLICE_CHICKEN_1(pipe) _PIPE(pipe, + \
+ _HSW_PIPE_SLICE_CHICKEN_1_A, + \
+ _HSW_PIPE_SLICE_CHICKEN_1_B)
+
+#define HSW_CLKGATE_DISABLE_PART_1 0x46500
+#define HSW_DPFC_GATING_DISABLE (1<<23)
/*
* GPIO regs
@@ -963,7 +1141,10 @@
#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */
#define DPLL_LOCK_VLV (1<<15)
+#define DPLL_INTEGRATED_CRI_CLK_VLV (1<<14)
#define DPLL_INTEGRATED_CLOCK_VLV (1<<13)
+#define DPLL_PORTC_READY_MASK (0xf << 4)
+#define DPLL_PORTB_READY_MASK (0xf)
#define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000
/*
@@ -1073,7 +1254,7 @@
#define DSTATE_PLL_D3_OFF (1<<3)
#define DSTATE_GFX_CLOCK_GATING (1<<1)
#define DSTATE_DOT_CLOCK_GATING (1<<0)
-#define DSPCLK_GATE_D 0x6200
+#define DSPCLK_GATE_D (dev_priv->info->display_mmio_offset + 0x6200)
# define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */
# define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */
# define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */
@@ -1186,6 +1367,8 @@
#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500)
#define FW_CSPWRDWNEN (1<<15)
+#define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504)
+
/*
* Palette regs
*/
@@ -1535,14 +1718,13 @@
GEN7_CXT_EXTENDED_SIZE(ctx_reg) + \
GEN7_CXT_GT1_SIZE(ctx_reg) + \
GEN7_CXT_VFSTATE_SIZE(ctx_reg))
-#define HSW_CXT_POWER_SIZE(ctx_reg) ((ctx_reg >> 26) & 0x3f)
-#define HSW_CXT_RING_SIZE(ctx_reg) ((ctx_reg >> 23) & 0x7)
-#define HSW_CXT_RENDER_SIZE(ctx_reg) ((ctx_reg >> 15) & 0xff)
-#define HSW_CXT_TOTAL_SIZE(ctx_reg) (HSW_CXT_POWER_SIZE(ctx_reg) + \
- HSW_CXT_RING_SIZE(ctx_reg) + \
- HSW_CXT_RENDER_SIZE(ctx_reg) + \
- GEN7_CXT_VFSTATE_SIZE(ctx_reg))
-
+/* Haswell does have the CXT_SIZE register however it does not appear to be
+ * valid. Now, docs explain in dwords what is in the context object. The full
+ * size is 70720 bytes, however, the power context and execlist context will
+ * never be saved (power context is stored elsewhere, and execlists don't work
+ * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages.
+ */
+#define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE)
/*
* Overlay regs
@@ -1691,6 +1873,12 @@
/* SDVO is different across gen3/4 */
#define SDVOC_HOTPLUG_INT_STATUS_G4X (1 << 3)
#define SDVOB_HOTPLUG_INT_STATUS_G4X (1 << 2)
+/*
+ * Bspec seems to be seriously misleaded about the SDVO hpd bits on i965g/gm,
+ * since reality corrobates that they're the same as on gen3. But keep these
+ * bits here (and the comment!) to help any other lost wanderers back onto the
+ * right tracks.
+ */
#define SDVOC_HOTPLUG_INT_STATUS_I965 (3 << 4)
#define SDVOB_HOTPLUG_INT_STATUS_I965 (3 << 2)
#define SDVOC_HOTPLUG_INT_STATUS_I915 (1 << 7)
@@ -1702,13 +1890,6 @@
PORTC_HOTPLUG_INT_STATUS | \
PORTD_HOTPLUG_INT_STATUS)
-#define HOTPLUG_INT_STATUS_I965 (CRT_HOTPLUG_INT_STATUS | \
- SDVOB_HOTPLUG_INT_STATUS_I965 | \
- SDVOC_HOTPLUG_INT_STATUS_I965 | \
- PORTB_HOTPLUG_INT_STATUS | \
- PORTC_HOTPLUG_INT_STATUS | \
- PORTD_HOTPLUG_INT_STATUS)
-
#define HOTPLUG_INT_STATUS_I915 (CRT_HOTPLUG_INT_STATUS | \
SDVOB_HOTPLUG_INT_STATUS_I915 | \
SDVOC_HOTPLUG_INT_STATUS_I915 | \
@@ -1967,6 +2148,10 @@
#define BLM_PIPE_A (0 << 29)
#define BLM_PIPE_B (1 << 29)
#define BLM_PIPE_C (2 << 29) /* ivb + */
+#define BLM_TRANSCODER_A BLM_PIPE_A /* hsw */
+#define BLM_TRANSCODER_B BLM_PIPE_B
+#define BLM_TRANSCODER_C BLM_PIPE_C
+#define BLM_TRANSCODER_EDP (3 << 29)
#define BLM_PIPE(pipe) ((pipe) << 29)
#define BLM_POLARITY_I965 (1 << 28) /* gen4 only */
#define BLM_PHASE_IN_INTERUPT_STATUS (1 << 26)
@@ -2540,9 +2725,7 @@
#define DP_PRE_EMPHASIS_SHIFT 22
/* How many wires to use. I guess 3 was too hard */
-#define DP_PORT_WIDTH_1 (0 << 19)
-#define DP_PORT_WIDTH_2 (1 << 19)
-#define DP_PORT_WIDTH_4 (3 << 19)
+#define DP_PORT_WIDTH(width) (((width) - 1) << 19)
#define DP_PORT_WIDTH_MASK (7 << 19)
/* Mystic DPCD version 1.1 special mode */
@@ -2646,18 +2829,20 @@
* which is after the LUTs, so we want the bytes for our color format.
* For our current usage, this is always 3, one byte for R, G and B.
*/
-#define _PIPEA_GMCH_DATA_M 0x70050
-#define _PIPEB_GMCH_DATA_M 0x71050
+#define _PIPEA_DATA_M_G4X 0x70050
+#define _PIPEB_DATA_M_G4X 0x71050
/* Transfer unit size for display port - 1, default is 0x3f (for TU size 64) */
#define TU_SIZE(x) (((x)-1) << 25) /* default size 64 */
+#define TU_SIZE_SHIFT 25
#define TU_SIZE_MASK (0x3f << 25)
#define DATA_LINK_M_N_MASK (0xffffff)
#define DATA_LINK_N_MAX (0x800000)
-#define _PIPEA_GMCH_DATA_N 0x70054
-#define _PIPEB_GMCH_DATA_N 0x71054
+#define _PIPEA_DATA_N_G4X 0x70054
+#define _PIPEB_DATA_N_G4X 0x71054
+#define PIPE_GMCH_DATA_N_MASK (0xffffff)
/*
* Computing Link M and N values for the Display Port link
@@ -2670,16 +2855,18 @@
* Attributes and VB-ID.
*/
-#define _PIPEA_DP_LINK_M 0x70060
-#define _PIPEB_DP_LINK_M 0x71060
+#define _PIPEA_LINK_M_G4X 0x70060
+#define _PIPEB_LINK_M_G4X 0x71060
+#define PIPEA_DP_LINK_M_MASK (0xffffff)
-#define _PIPEA_DP_LINK_N 0x70064
-#define _PIPEB_DP_LINK_N 0x71064
+#define _PIPEA_LINK_N_G4X 0x70064
+#define _PIPEB_LINK_N_G4X 0x71064
+#define PIPEA_DP_LINK_N_MASK (0xffffff)
-#define PIPE_GMCH_DATA_M(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_M, _PIPEB_GMCH_DATA_M)
-#define PIPE_GMCH_DATA_N(pipe) _PIPE(pipe, _PIPEA_GMCH_DATA_N, _PIPEB_GMCH_DATA_N)
-#define PIPE_DP_LINK_M(pipe) _PIPE(pipe, _PIPEA_DP_LINK_M, _PIPEB_DP_LINK_M)
-#define PIPE_DP_LINK_N(pipe) _PIPE(pipe, _PIPEA_DP_LINK_N, _PIPEB_DP_LINK_N)
+#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X)
+#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X)
+#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X)
+#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X)
/* Display & cursor control */
@@ -2715,6 +2902,7 @@
#define PIPECONF_INTERLACED_ILK (3 << 21)
#define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */
#define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */
+#define PIPECONF_INTERLACE_MODE_MASK (7 << 21)
#define PIPECONF_CXSR_DOWNCLOCK (1<<16)
#define PIPECONF_COLOR_RANGE_SELECT (1 << 13)
#define PIPECONF_BPC_MASK (0x7 << 5)
@@ -2915,6 +3103,10 @@
#define WM3S_LP_IVB 0x45128
#define WM1S_LP_EN (1<<31)
+#define HSW_WM_LP_VAL(lat, fbc, pri, cur) \
+ (WM3_LP_EN | ((lat) << WM1_LP_LATENCY_SHIFT) | \
+ ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur))
+
/* Memory latency timer register */
#define MLTR_ILK 0x11222
#define MLTR_WM1_SHIFT 0
@@ -3294,7 +3486,7 @@
#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC)
#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE)
-#define _SPACNTR 0x72180
+#define _SPACNTR (VLV_DISPLAY_BASE + 0x72180)
#define SP_ENABLE (1<<31)
#define SP_GEAMMA_ENABLE (1<<30)
#define SP_PIXFORMAT_MASK (0xf<<26)
@@ -3313,30 +3505,30 @@
#define SP_YUV_ORDER_YVYU (2<<16)
#define SP_YUV_ORDER_VYUY (3<<16)
#define SP_TILED (1<<10)
-#define _SPALINOFF 0x72184
-#define _SPASTRIDE 0x72188
-#define _SPAPOS 0x7218c
-#define _SPASIZE 0x72190
-#define _SPAKEYMINVAL 0x72194
-#define _SPAKEYMSK 0x72198
-#define _SPASURF 0x7219c
-#define _SPAKEYMAXVAL 0x721a0
-#define _SPATILEOFF 0x721a4
-#define _SPACONSTALPHA 0x721a8
-#define _SPAGAMC 0x721f4
-
-#define _SPBCNTR 0x72280
-#define _SPBLINOFF 0x72284
-#define _SPBSTRIDE 0x72288
-#define _SPBPOS 0x7228c
-#define _SPBSIZE 0x72290
-#define _SPBKEYMINVAL 0x72294
-#define _SPBKEYMSK 0x72298
-#define _SPBSURF 0x7229c
-#define _SPBKEYMAXVAL 0x722a0
-#define _SPBTILEOFF 0x722a4
-#define _SPBCONSTALPHA 0x722a8
-#define _SPBGAMC 0x722f4
+#define _SPALINOFF (VLV_DISPLAY_BASE + 0x72184)
+#define _SPASTRIDE (VLV_DISPLAY_BASE + 0x72188)
+#define _SPAPOS (VLV_DISPLAY_BASE + 0x7218c)
+#define _SPASIZE (VLV_DISPLAY_BASE + 0x72190)
+#define _SPAKEYMINVAL (VLV_DISPLAY_BASE + 0x72194)
+#define _SPAKEYMSK (VLV_DISPLAY_BASE + 0x72198)
+#define _SPASURF (VLV_DISPLAY_BASE + 0x7219c)
+#define _SPAKEYMAXVAL (VLV_DISPLAY_BASE + 0x721a0)
+#define _SPATILEOFF (VLV_DISPLAY_BASE + 0x721a4)
+#define _SPACONSTALPHA (VLV_DISPLAY_BASE + 0x721a8)
+#define _SPAGAMC (VLV_DISPLAY_BASE + 0x721f4)
+
+#define _SPBCNTR (VLV_DISPLAY_BASE + 0x72280)
+#define _SPBLINOFF (VLV_DISPLAY_BASE + 0x72284)
+#define _SPBSTRIDE (VLV_DISPLAY_BASE + 0x72288)
+#define _SPBPOS (VLV_DISPLAY_BASE + 0x7228c)
+#define _SPBSIZE (VLV_DISPLAY_BASE + 0x72290)
+#define _SPBKEYMINVAL (VLV_DISPLAY_BASE + 0x72294)
+#define _SPBKEYMSK (VLV_DISPLAY_BASE + 0x72298)
+#define _SPBSURF (VLV_DISPLAY_BASE + 0x7229c)
+#define _SPBKEYMAXVAL (VLV_DISPLAY_BASE + 0x722a0)
+#define _SPBTILEOFF (VLV_DISPLAY_BASE + 0x722a4)
+#define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8)
+#define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4)
#define SPCNTR(pipe, plane) _PIPE(pipe * 2 + plane, _SPACNTR, _SPBCNTR)
#define SPLINOFF(pipe, plane) _PIPE(pipe * 2 + plane, _SPALINOFF, _SPBLINOFF)
@@ -3474,6 +3666,15 @@
#define _LGC_PALETTE_B 0x4a800
#define LGC_PALETTE(pipe) _PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B)
+#define _GAMMA_MODE_A 0x4a480
+#define _GAMMA_MODE_B 0x4ac80
+#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B)
+#define GAMMA_MODE_MODE_MASK (3 << 0)
+#define GAMMA_MODE_MODE_8BIT (0 << 0)
+#define GAMMA_MODE_MODE_10BIT (1 << 0)
+#define GAMMA_MODE_MODE_12BIT (2 << 0)
+#define GAMMA_MODE_MODE_SPLIT (3 << 0)
+
/* interrupts */
#define DE_MASTER_IRQ_CONTROL (1 << 31)
#define DE_SPRITEB_FLIP_DONE (1 << 29)
@@ -3502,7 +3703,7 @@
#define DE_PIPEA_FIFO_UNDERRUN (1 << 0)
/* More Ivybridge lolz */
-#define DE_ERR_DEBUG_IVB (1<<30)
+#define DE_ERR_INT_IVB (1<<30)
#define DE_GSE_IVB (1<<29)
#define DE_PCH_EVENT_IVB (1<<28)
#define DE_DP_A_HOTPLUG_IVB (1<<27)
@@ -3525,21 +3726,6 @@
#define DEIIR 0x44008
#define DEIER 0x4400c
-/* GT interrupt.
- * Note that for gen6+ the ring-specific interrupt bits do alias with the
- * corresponding bits in the per-ring interrupt control registers. */
-#define GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26)
-#define GT_GEN6_BLT_CS_ERROR_INTERRUPT (1 << 25)
-#define GT_GEN6_BLT_USER_INTERRUPT (1 << 22)
-#define GT_GEN6_BSD_CS_ERROR_INTERRUPT (1 << 15)
-#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12)
-#define GT_BSD_USER_INTERRUPT (1 << 5) /* ilk only */
-#define GT_GEN7_L3_PARITY_ERROR_INTERRUPT (1 << 5)
-#define GT_PIPE_NOTIFY (1 << 4)
-#define GT_RENDER_CS_ERROR_INTERRUPT (1 << 3)
-#define GT_SYNC_STATUS (1 << 2)
-#define GT_USER_INTERRUPT (1 << 0)
-
#define GTISR 0x44010
#define GTIMR 0x44014
#define GTIIR 0x44018
@@ -3569,6 +3755,9 @@
# define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5)
# define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2)
+#define CHICKEN_PAR1_1 0x42080
+#define FORCE_ARB_IDLE_PLANES (1 << 14)
+
#define DISP_ARB_CTL 0x45000
#define DISP_TILE_SURFACE_SWIZZLING (1<<13)
#define DISP_FBC_WM_DIS (1<<15)
@@ -3661,6 +3850,7 @@
SDE_PORTC_HOTPLUG_CPT | \
SDE_PORTB_HOTPLUG_CPT)
#define SDE_GMBUS_CPT (1 << 17)
+#define SDE_ERROR_CPT (1 << 16)
#define SDE_AUDIO_CP_REQ_C_CPT (1 << 10)
#define SDE_AUDIO_CP_CHG_C_CPT (1 << 9)
#define SDE_FDI_RXC_CPT (1 << 8)
@@ -3685,6 +3875,12 @@
#define SDEIIR 0xc4008
#define SDEIER 0xc400c
+#define SERR_INT 0xc4040
+#define SERR_INT_POISON (1<<31)
+#define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6)
+#define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3)
+#define SERR_INT_TRANS_A_FIFO_UNDERRUN (1<<0)
+
/* digital port hotplug */
#define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */
#define PORTD_HOTPLUG_ENABLE (1 << 20)
@@ -3734,15 +3930,15 @@
#define _PCH_DPLL_A 0xc6014
#define _PCH_DPLL_B 0xc6018
-#define _PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
+#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
#define _PCH_FPA0 0xc6040
#define FP_CB_TUNE (0x3<<22)
#define _PCH_FPA1 0xc6044
#define _PCH_FPB0 0xc6048
#define _PCH_FPB1 0xc604c
-#define _PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
-#define _PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
+#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
+#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
#define PCH_DPLL_TEST 0xc606c
@@ -3782,46 +3978,40 @@
#define PCH_SSC4_AUX_PARMS 0xc6214
#define PCH_DPLL_SEL 0xc7000
-#define TRANSA_DPLL_ENABLE (1<<3)
-#define TRANSA_DPLLB_SEL (1<<0)
-#define TRANSA_DPLLA_SEL 0
-#define TRANSB_DPLL_ENABLE (1<<7)
-#define TRANSB_DPLLB_SEL (1<<4)
-#define TRANSB_DPLLA_SEL (0)
-#define TRANSC_DPLL_ENABLE (1<<11)
-#define TRANSC_DPLLB_SEL (1<<8)
-#define TRANSC_DPLLA_SEL (0)
+#define TRANS_DPLLB_SEL(pipe) (1 << (pipe * 4))
+#define TRANS_DPLLA_SEL(pipe) 0
+#define TRANS_DPLL_ENABLE(pipe) (1 << (pipe * 4 + 3))
/* transcoder */
-#define _TRANS_HTOTAL_A 0xe0000
-#define TRANS_HTOTAL_SHIFT 16
-#define TRANS_HACTIVE_SHIFT 0
-#define _TRANS_HBLANK_A 0xe0004
-#define TRANS_HBLANK_END_SHIFT 16
-#define TRANS_HBLANK_START_SHIFT 0
-#define _TRANS_HSYNC_A 0xe0008
-#define TRANS_HSYNC_END_SHIFT 16
-#define TRANS_HSYNC_START_SHIFT 0
-#define _TRANS_VTOTAL_A 0xe000c
-#define TRANS_VTOTAL_SHIFT 16
-#define TRANS_VACTIVE_SHIFT 0
-#define _TRANS_VBLANK_A 0xe0010
-#define TRANS_VBLANK_END_SHIFT 16
-#define TRANS_VBLANK_START_SHIFT 0
-#define _TRANS_VSYNC_A 0xe0014
-#define TRANS_VSYNC_END_SHIFT 16
-#define TRANS_VSYNC_START_SHIFT 0
-#define _TRANS_VSYNCSHIFT_A 0xe0028
-
-#define _TRANSA_DATA_M1 0xe0030
-#define _TRANSA_DATA_N1 0xe0034
-#define _TRANSA_DATA_M2 0xe0038
-#define _TRANSA_DATA_N2 0xe003c
-#define _TRANSA_DP_LINK_M1 0xe0040
-#define _TRANSA_DP_LINK_N1 0xe0044
-#define _TRANSA_DP_LINK_M2 0xe0048
-#define _TRANSA_DP_LINK_N2 0xe004c
+#define _PCH_TRANS_HTOTAL_A 0xe0000
+#define TRANS_HTOTAL_SHIFT 16
+#define TRANS_HACTIVE_SHIFT 0
+#define _PCH_TRANS_HBLANK_A 0xe0004
+#define TRANS_HBLANK_END_SHIFT 16
+#define TRANS_HBLANK_START_SHIFT 0
+#define _PCH_TRANS_HSYNC_A 0xe0008
+#define TRANS_HSYNC_END_SHIFT 16
+#define TRANS_HSYNC_START_SHIFT 0
+#define _PCH_TRANS_VTOTAL_A 0xe000c
+#define TRANS_VTOTAL_SHIFT 16
+#define TRANS_VACTIVE_SHIFT 0
+#define _PCH_TRANS_VBLANK_A 0xe0010
+#define TRANS_VBLANK_END_SHIFT 16
+#define TRANS_VBLANK_START_SHIFT 0
+#define _PCH_TRANS_VSYNC_A 0xe0014
+#define TRANS_VSYNC_END_SHIFT 16
+#define TRANS_VSYNC_START_SHIFT 0
+#define _PCH_TRANS_VSYNCSHIFT_A 0xe0028
+
+#define _PCH_TRANSA_DATA_M1 0xe0030
+#define _PCH_TRANSA_DATA_N1 0xe0034
+#define _PCH_TRANSA_DATA_M2 0xe0038
+#define _PCH_TRANSA_DATA_N2 0xe003c
+#define _PCH_TRANSA_LINK_M1 0xe0040
+#define _PCH_TRANSA_LINK_N1 0xe0044
+#define _PCH_TRANSA_LINK_M2 0xe0048
+#define _PCH_TRANSA_LINK_N2 0xe004c
/* Per-transcoder DIP controls */
@@ -3890,44 +4080,45 @@
#define HSW_TVIDEO_DIP_VSC_DATA(trans) \
_TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
-#define _TRANS_HTOTAL_B 0xe1000
-#define _TRANS_HBLANK_B 0xe1004
-#define _TRANS_HSYNC_B 0xe1008
-#define _TRANS_VTOTAL_B 0xe100c
-#define _TRANS_VBLANK_B 0xe1010
-#define _TRANS_VSYNC_B 0xe1014
-#define _TRANS_VSYNCSHIFT_B 0xe1028
-
-#define TRANS_HTOTAL(pipe) _PIPE(pipe, _TRANS_HTOTAL_A, _TRANS_HTOTAL_B)
-#define TRANS_HBLANK(pipe) _PIPE(pipe, _TRANS_HBLANK_A, _TRANS_HBLANK_B)
-#define TRANS_HSYNC(pipe) _PIPE(pipe, _TRANS_HSYNC_A, _TRANS_HSYNC_B)
-#define TRANS_VTOTAL(pipe) _PIPE(pipe, _TRANS_VTOTAL_A, _TRANS_VTOTAL_B)
-#define TRANS_VBLANK(pipe) _PIPE(pipe, _TRANS_VBLANK_A, _TRANS_VBLANK_B)
-#define TRANS_VSYNC(pipe) _PIPE(pipe, _TRANS_VSYNC_A, _TRANS_VSYNC_B)
-#define TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _TRANS_VSYNCSHIFT_A, \
- _TRANS_VSYNCSHIFT_B)
-
-#define _TRANSB_DATA_M1 0xe1030
-#define _TRANSB_DATA_N1 0xe1034
-#define _TRANSB_DATA_M2 0xe1038
-#define _TRANSB_DATA_N2 0xe103c
-#define _TRANSB_DP_LINK_M1 0xe1040
-#define _TRANSB_DP_LINK_N1 0xe1044
-#define _TRANSB_DP_LINK_M2 0xe1048
-#define _TRANSB_DP_LINK_N2 0xe104c
-
-#define TRANSDATA_M1(pipe) _PIPE(pipe, _TRANSA_DATA_M1, _TRANSB_DATA_M1)
-#define TRANSDATA_N1(pipe) _PIPE(pipe, _TRANSA_DATA_N1, _TRANSB_DATA_N1)
-#define TRANSDATA_M2(pipe) _PIPE(pipe, _TRANSA_DATA_M2, _TRANSB_DATA_M2)
-#define TRANSDATA_N2(pipe) _PIPE(pipe, _TRANSA_DATA_N2, _TRANSB_DATA_N2)
-#define TRANSDPLINK_M1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M1, _TRANSB_DP_LINK_M1)
-#define TRANSDPLINK_N1(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N1, _TRANSB_DP_LINK_N1)
-#define TRANSDPLINK_M2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_M2, _TRANSB_DP_LINK_M2)
-#define TRANSDPLINK_N2(pipe) _PIPE(pipe, _TRANSA_DP_LINK_N2, _TRANSB_DP_LINK_N2)
-
-#define _TRANSACONF 0xf0008
-#define _TRANSBCONF 0xf1008
-#define TRANSCONF(plane) _PIPE(plane, _TRANSACONF, _TRANSBCONF)
+#define _PCH_TRANS_HTOTAL_B 0xe1000
+#define _PCH_TRANS_HBLANK_B 0xe1004
+#define _PCH_TRANS_HSYNC_B 0xe1008
+#define _PCH_TRANS_VTOTAL_B 0xe100c
+#define _PCH_TRANS_VBLANK_B 0xe1010
+#define _PCH_TRANS_VSYNC_B 0xe1014
+#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028
+
+#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B)
+#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B)
+#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B)
+#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B)
+#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B)
+#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B)
+#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \
+ _PCH_TRANS_VSYNCSHIFT_B)
+
+#define _PCH_TRANSB_DATA_M1 0xe1030
+#define _PCH_TRANSB_DATA_N1 0xe1034
+#define _PCH_TRANSB_DATA_M2 0xe1038
+#define _PCH_TRANSB_DATA_N2 0xe103c
+#define _PCH_TRANSB_LINK_M1 0xe1040
+#define _PCH_TRANSB_LINK_N1 0xe1044
+#define _PCH_TRANSB_LINK_M2 0xe1048
+#define _PCH_TRANSB_LINK_N2 0xe104c
+
+#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1)
+#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1)
+#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2)
+#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2)
+#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1)
+#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1)
+#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2)
+#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2)
+
+#define _PCH_TRANSACONF 0xf0008
+#define _PCH_TRANSBCONF 0xf1008
+#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF)
+#define LPT_TRANSCONF _PCH_TRANSACONF /* lpt has only one transcoder */
#define TRANS_DISABLE (0<<31)
#define TRANS_ENABLE (1<<31)
#define TRANS_STATE_MASK (1<<30)
@@ -4011,10 +4202,9 @@
#define FDI_LINK_TRAIN_600MV_3_5DB_SNB_B (0x39<<22)
#define FDI_LINK_TRAIN_800MV_0DB_SNB_B (0x38<<22)
#define FDI_LINK_TRAIN_VOL_EMP_MASK (0x3f<<22)
-#define FDI_DP_PORT_WIDTH_X1 (0<<19)
-#define FDI_DP_PORT_WIDTH_X2 (1<<19)
-#define FDI_DP_PORT_WIDTH_X3 (2<<19)
-#define FDI_DP_PORT_WIDTH_X4 (3<<19)
+#define FDI_DP_PORT_WIDTH_SHIFT 19
+#define FDI_DP_PORT_WIDTH_MASK (7 << FDI_DP_PORT_WIDTH_SHIFT)
+#define FDI_DP_PORT_WIDTH(width) (((width) - 1) << FDI_DP_PORT_WIDTH_SHIFT)
#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18)
/* Ironlake: hardwired to 1 */
#define FDI_TX_PLL_ENABLE (1<<14)
@@ -4039,7 +4229,6 @@
/* train, dp width same as FDI_TX */
#define FDI_FS_ERRC_ENABLE (1<<27)
#define FDI_FE_ERRC_ENABLE (1<<26)
-#define FDI_DP_PORT_WIDTH_X8 (7<<19)
#define FDI_RX_POLARITY_REVERSED_LPT (1<<16)
#define FDI_8BPC (0<<16)
#define FDI_10BPC (1<<16)
@@ -4061,9 +4250,6 @@
#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8)
#define FDI_LINK_TRAIN_NORMAL_CPT (3<<8)
#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8)
-/* LPT */
-#define FDI_PORT_WIDTH_2X_LPT (1<<19)
-#define FDI_PORT_WIDTH_1X_LPT (0<<19)
#define _FDI_RXA_MISC 0xf0010
#define _FDI_RXB_MISC 0xf1010
@@ -4309,6 +4495,7 @@
#define GEN6_RC_CTL_RC6_ENABLE (1<<18)
#define GEN6_RC_CTL_RC1e_ENABLE (1<<20)
#define GEN6_RC_CTL_RC7_ENABLE (1<<22)
+#define GEN7_RC_CTL_TO_MODE (1<<28)
#define GEN6_RC_CTL_EI_MODE(x) ((x)<<27)
#define GEN6_RC_CTL_HW_ENABLE (1<<31)
#define GEN6_RP_DOWN_TIMEOUT 0xA010
@@ -4370,7 +4557,7 @@
#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4)
#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2)
#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1)
-#define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \
+#define GEN6_PM_RPS_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \
GEN6_PM_RP_DOWN_THRESHOLD | \
GEN6_PM_RP_DOWN_TIMEOUT)
@@ -4392,20 +4579,6 @@
#define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8
#define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16
-#define VLV_IOSF_DOORBELL_REQ 0x182100
-#define IOSF_DEVFN_SHIFT 24
-#define IOSF_OPCODE_SHIFT 16
-#define IOSF_PORT_SHIFT 8
-#define IOSF_BYTE_ENABLES_SHIFT 4
-#define IOSF_BAR_SHIFT 1
-#define IOSF_SB_BUSY (1<<0)
-#define IOSF_PORT_PUNIT 0x4
-#define VLV_IOSF_DATA 0x182104
-#define VLV_IOSF_ADDR 0x182108
-
-#define PUNIT_OPCODE_REG_READ 6
-#define PUNIT_OPCODE_REG_WRITE 7
-
#define GEN6_GT_CORE_STATUS 0x138060
#define GEN6_CORE_CPD_STATE_MASK (7<<4)
#define GEN6_RCn_MASK 7
@@ -4602,9 +4775,6 @@
#define TRANS_DDI_EDP_INPUT_B_ONOFF (5<<12)
#define TRANS_DDI_EDP_INPUT_C_ONOFF (6<<12)
#define TRANS_DDI_BFI_ENABLE (1<<4)
-#define TRANS_DDI_PORT_WIDTH_X1 (0<<1)
-#define TRANS_DDI_PORT_WIDTH_X2 (1<<1)
-#define TRANS_DDI_PORT_WIDTH_X4 (3<<1)
/* DisplayPort Transport Control */
#define DP_TP_CTL_A 0x64040
@@ -4648,9 +4818,7 @@
#define DDI_BUF_PORT_REVERSAL (1<<16)
#define DDI_BUF_IS_IDLE (1<<7)
#define DDI_A_4_LANES (1<<4)
-#define DDI_PORT_WIDTH_X1 (0<<1)
-#define DDI_PORT_WIDTH_X2 (1<<1)
-#define DDI_PORT_WIDTH_X4 (3<<1)
+#define DDI_PORT_WIDTH(width) (((width) - 1) << 1)
#define DDI_INIT_DISPLAY_DETECTED (1<<0)
/* DDI Buffer Translations */
@@ -4774,6 +4942,9 @@
#define SFUSE_STRAP_DDIC_DETECTED (1<<1)
#define SFUSE_STRAP_DDID_DETECTED (1<<0)
+#define WM_MISC 0x45260
+#define WM_MISC_DATA_PARTITION_5_6 (1 << 0)
+
#define WM_DBG 0x45280
#define WM_DBG_DISALLOW_MULTIPLE_LP (1<<0)
#define WM_DBG_DISALLOW_MAXFIFO (1<<1)
@@ -4787,6 +4958,9 @@
#define _PIPE_A_CSC_COEFF_RV_GV 0x49020
#define _PIPE_A_CSC_COEFF_BV 0x49024
#define _PIPE_A_CSC_MODE 0x49028
+#define CSC_BLACK_SCREEN_OFFSET (1 << 2)
+#define CSC_POSITION_BEFORE_GAMMA (1 << 1)
+#define CSC_MODE_YUV_TO_RGB (1 << 0)
#define _PIPE_A_CSC_PREOFF_HI 0x49030
#define _PIPE_A_CSC_PREOFF_ME 0x49034
#define _PIPE_A_CSC_PREOFF_LO 0x49038
@@ -4808,10 +4982,6 @@
#define _PIPE_B_CSC_POSTOFF_ME 0x49144
#define _PIPE_B_CSC_POSTOFF_LO 0x49148
-#define CSC_BLACK_SCREEN_OFFSET (1 << 2)
-#define CSC_POSITION_BEFORE_GAMMA (1 << 1)
-#define CSC_MODE_YUV_TO_RGB (1 << 0)
-
#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY)
#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY)
#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 369b3d8776ab..70db618989c4 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -192,6 +192,7 @@ static void i915_restore_vga(struct drm_device *dev)
static void i915_save_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
/* Display arbitration control */
if (INTEL_INFO(dev)->gen <= 4)
@@ -202,6 +203,8 @@ static void i915_save_display(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_save_display_reg(dev);
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+
/* LVDS state */
if (HAS_PCH_SPLIT(dev)) {
dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
@@ -222,6 +225,8 @@ static void i915_save_display(struct drm_device *dev)
dev_priv->regfile.saveLVDS = I915_READ(LVDS);
}
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+
if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
@@ -257,6 +262,7 @@ static void i915_restore_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 mask = 0xffffffff;
+ unsigned long flags;
/* Display arbitration */
if (INTEL_INFO(dev)->gen <= 4)
@@ -265,6 +271,8 @@ static void i915_restore_display(struct drm_device *dev)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
i915_restore_display_reg(dev);
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+
/* LVDS state */
if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
@@ -304,6 +312,8 @@ static void i915_restore_display(struct drm_device *dev)
I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
}
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+
/* only restore FBC info on the platform that supports FBC*/
intel_disable_fbc(dev);
if (I915_HAS_FBC(dev)) {
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index d5e1890678f9..6875b5654c63 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -212,7 +212,13 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
int ret;
mutex_lock(&dev_priv->rps.hw_lock);
- ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
+ if (IS_VALLEYVIEW(dev_priv->dev)) {
+ u32 freq;
+ freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+ ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff);
+ } else {
+ ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
+ }
mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -226,7 +232,10 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
int ret;
mutex_lock(&dev_priv->rps.hw_lock);
- ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
+ if (IS_VALLEYVIEW(dev_priv->dev))
+ ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay);
+ else
+ ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -246,16 +255,25 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
if (ret)
return ret;
- val /= GT_FREQUENCY_MULTIPLIER;
-
mutex_lock(&dev_priv->rps.hw_lock);
- rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- hw_max = dev_priv->rps.hw_max;
- non_oc_max = (rp_state_cap & 0xff);
- hw_min = ((rp_state_cap & 0xff0000) >> 16);
+ if (IS_VALLEYVIEW(dev_priv->dev)) {
+ val = vlv_freq_opcode(dev_priv->mem_freq, val);
+
+ hw_max = valleyview_rps_max_freq(dev_priv);
+ hw_min = valleyview_rps_min_freq(dev_priv);
+ non_oc_max = hw_max;
+ } else {
+ val /= GT_FREQUENCY_MULTIPLIER;
+
+ rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+ hw_max = dev_priv->rps.hw_max;
+ non_oc_max = (rp_state_cap & 0xff);
+ hw_min = ((rp_state_cap & 0xff0000) >> 16);
+ }
- if (val < hw_min || val > hw_max || val < dev_priv->rps.min_delay) {
+ if (val < hw_min || val > hw_max ||
+ val < dev_priv->rps.min_delay) {
mutex_unlock(&dev_priv->rps.hw_lock);
return -EINVAL;
}
@@ -264,8 +282,12 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
DRM_DEBUG("User requested overclocking to %d\n",
val * GT_FREQUENCY_MULTIPLIER);
- if (dev_priv->rps.cur_delay > val)
- gen6_set_rps(dev_priv->dev, val);
+ if (dev_priv->rps.cur_delay > val) {
+ if (IS_VALLEYVIEW(dev_priv->dev))
+ valleyview_set_rps(dev_priv->dev, val);
+ else
+ gen6_set_rps(dev_priv->dev, val);
+ }
dev_priv->rps.max_delay = val;
@@ -282,7 +304,10 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
int ret;
mutex_lock(&dev_priv->rps.hw_lock);
- ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
+ if (IS_VALLEYVIEW(dev_priv->dev))
+ ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay);
+ else
+ ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -302,21 +327,32 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
if (ret)
return ret;
- val /= GT_FREQUENCY_MULTIPLIER;
-
mutex_lock(&dev_priv->rps.hw_lock);
- rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- hw_max = dev_priv->rps.hw_max;
- hw_min = ((rp_state_cap & 0xff0000) >> 16);
+ if (IS_VALLEYVIEW(dev)) {
+ val = vlv_freq_opcode(dev_priv->mem_freq, val);
+
+ hw_max = valleyview_rps_max_freq(dev_priv);
+ hw_min = valleyview_rps_min_freq(dev_priv);
+ } else {
+ val /= GT_FREQUENCY_MULTIPLIER;
+
+ rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+ hw_max = dev_priv->rps.hw_max;
+ hw_min = ((rp_state_cap & 0xff0000) >> 16);
+ }
if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
mutex_unlock(&dev_priv->rps.hw_lock);
return -EINVAL;
}
- if (dev_priv->rps.cur_delay < val)
- gen6_set_rps(dev_priv->dev, val);
+ if (dev_priv->rps.cur_delay < val) {
+ if (IS_VALLEYVIEW(dev))
+ valleyview_set_rps(dev, val);
+ else
+ gen6_set_rps(dev_priv->dev, val);
+ }
dev_priv->rps.min_delay = val;
diff --git a/drivers/gpu/drm/i915/i915_ums.c b/drivers/gpu/drm/i915/i915_ums.c
index 985a09716237..967da4772c44 100644
--- a/drivers/gpu/drm/i915/i915_ums.c
+++ b/drivers/gpu/drm/i915/i915_ums.c
@@ -41,7 +41,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
return false;
if (HAS_PCH_SPLIT(dev))
- dpll_reg = _PCH_DPLL(pipe);
+ dpll_reg = PCH_DPLL(pipe);
else
dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
@@ -148,13 +148,13 @@ void i915_save_display_reg(struct drm_device *dev)
dev_priv->regfile.savePFA_WIN_SZ = I915_READ(_PFA_WIN_SZ);
dev_priv->regfile.savePFA_WIN_POS = I915_READ(_PFA_WIN_POS);
- dev_priv->regfile.saveTRANSACONF = I915_READ(_TRANSACONF);
- dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_TRANS_HTOTAL_A);
- dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_TRANS_HBLANK_A);
- dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_TRANS_HSYNC_A);
- dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_TRANS_VTOTAL_A);
- dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_TRANS_VBLANK_A);
- dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_TRANS_VSYNC_A);
+ dev_priv->regfile.saveTRANSACONF = I915_READ(_PCH_TRANSACONF);
+ dev_priv->regfile.saveTRANS_HTOTAL_A = I915_READ(_PCH_TRANS_HTOTAL_A);
+ dev_priv->regfile.saveTRANS_HBLANK_A = I915_READ(_PCH_TRANS_HBLANK_A);
+ dev_priv->regfile.saveTRANS_HSYNC_A = I915_READ(_PCH_TRANS_HSYNC_A);
+ dev_priv->regfile.saveTRANS_VTOTAL_A = I915_READ(_PCH_TRANS_VTOTAL_A);
+ dev_priv->regfile.saveTRANS_VBLANK_A = I915_READ(_PCH_TRANS_VBLANK_A);
+ dev_priv->regfile.saveTRANS_VSYNC_A = I915_READ(_PCH_TRANS_VSYNC_A);
}
dev_priv->regfile.saveDSPACNTR = I915_READ(_DSPACNTR);
@@ -205,13 +205,13 @@ void i915_save_display_reg(struct drm_device *dev)
dev_priv->regfile.savePFB_WIN_SZ = I915_READ(_PFB_WIN_SZ);
dev_priv->regfile.savePFB_WIN_POS = I915_READ(_PFB_WIN_POS);
- dev_priv->regfile.saveTRANSBCONF = I915_READ(_TRANSBCONF);
- dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_TRANS_HTOTAL_B);
- dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_TRANS_HBLANK_B);
- dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_TRANS_HSYNC_B);
- dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_TRANS_VTOTAL_B);
- dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_TRANS_VBLANK_B);
- dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_TRANS_VSYNC_B);
+ dev_priv->regfile.saveTRANSBCONF = I915_READ(_PCH_TRANSBCONF);
+ dev_priv->regfile.saveTRANS_HTOTAL_B = I915_READ(_PCH_TRANS_HTOTAL_B);
+ dev_priv->regfile.saveTRANS_HBLANK_B = I915_READ(_PCH_TRANS_HBLANK_B);
+ dev_priv->regfile.saveTRANS_HSYNC_B = I915_READ(_PCH_TRANS_HSYNC_B);
+ dev_priv->regfile.saveTRANS_VTOTAL_B = I915_READ(_PCH_TRANS_VTOTAL_B);
+ dev_priv->regfile.saveTRANS_VBLANK_B = I915_READ(_PCH_TRANS_VBLANK_B);
+ dev_priv->regfile.saveTRANS_VSYNC_B = I915_READ(_PCH_TRANS_VSYNC_B);
}
dev_priv->regfile.saveDSPBCNTR = I915_READ(_DSPBCNTR);
@@ -259,14 +259,14 @@ void i915_save_display_reg(struct drm_device *dev)
dev_priv->regfile.saveDP_B = I915_READ(DP_B);
dev_priv->regfile.saveDP_C = I915_READ(DP_C);
dev_priv->regfile.saveDP_D = I915_READ(DP_D);
- dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_GMCH_DATA_M);
- dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_GMCH_DATA_M);
- dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_GMCH_DATA_N);
- dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_GMCH_DATA_N);
- dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_DP_LINK_M);
- dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_DP_LINK_M);
- dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_DP_LINK_N);
- dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_DP_LINK_N);
+ dev_priv->regfile.savePIPEA_GMCH_DATA_M = I915_READ(_PIPEA_DATA_M_G4X);
+ dev_priv->regfile.savePIPEB_GMCH_DATA_M = I915_READ(_PIPEB_DATA_M_G4X);
+ dev_priv->regfile.savePIPEA_GMCH_DATA_N = I915_READ(_PIPEA_DATA_N_G4X);
+ dev_priv->regfile.savePIPEB_GMCH_DATA_N = I915_READ(_PIPEB_DATA_N_G4X);
+ dev_priv->regfile.savePIPEA_DP_LINK_M = I915_READ(_PIPEA_LINK_M_G4X);
+ dev_priv->regfile.savePIPEB_DP_LINK_M = I915_READ(_PIPEB_LINK_M_G4X);
+ dev_priv->regfile.savePIPEA_DP_LINK_N = I915_READ(_PIPEA_LINK_N_G4X);
+ dev_priv->regfile.savePIPEB_DP_LINK_N = I915_READ(_PIPEB_LINK_N_G4X);
}
/* FIXME: regfile.save TV & SDVO state */
@@ -282,14 +282,14 @@ void i915_restore_display_reg(struct drm_device *dev)
/* Display port ratios (must be done before clock is set) */
if (SUPPORTS_INTEGRATED_DP(dev)) {
- I915_WRITE(_PIPEA_GMCH_DATA_M, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
- I915_WRITE(_PIPEB_GMCH_DATA_M, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
- I915_WRITE(_PIPEA_GMCH_DATA_N, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
- I915_WRITE(_PIPEB_GMCH_DATA_N, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
- I915_WRITE(_PIPEA_DP_LINK_M, dev_priv->regfile.savePIPEA_DP_LINK_M);
- I915_WRITE(_PIPEB_DP_LINK_M, dev_priv->regfile.savePIPEB_DP_LINK_M);
- I915_WRITE(_PIPEA_DP_LINK_N, dev_priv->regfile.savePIPEA_DP_LINK_N);
- I915_WRITE(_PIPEB_DP_LINK_N, dev_priv->regfile.savePIPEB_DP_LINK_N);
+ I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
+ I915_WRITE(_PIPEB_DATA_M_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_M);
+ I915_WRITE(_PIPEA_DATA_N_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_N);
+ I915_WRITE(_PIPEB_DATA_N_G4X, dev_priv->regfile.savePIPEB_GMCH_DATA_N);
+ I915_WRITE(_PIPEA_LINK_M_G4X, dev_priv->regfile.savePIPEA_DP_LINK_M);
+ I915_WRITE(_PIPEB_LINK_M_G4X, dev_priv->regfile.savePIPEB_DP_LINK_M);
+ I915_WRITE(_PIPEA_LINK_N_G4X, dev_priv->regfile.savePIPEA_DP_LINK_N);
+ I915_WRITE(_PIPEB_LINK_N_G4X, dev_priv->regfile.savePIPEB_DP_LINK_N);
}
/* Fences */
@@ -379,13 +379,13 @@ void i915_restore_display_reg(struct drm_device *dev)
I915_WRITE(_PFA_WIN_SZ, dev_priv->regfile.savePFA_WIN_SZ);
I915_WRITE(_PFA_WIN_POS, dev_priv->regfile.savePFA_WIN_POS);
- I915_WRITE(_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
- I915_WRITE(_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
- I915_WRITE(_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
- I915_WRITE(_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
- I915_WRITE(_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
- I915_WRITE(_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
- I915_WRITE(_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
+ I915_WRITE(_PCH_TRANSACONF, dev_priv->regfile.saveTRANSACONF);
+ I915_WRITE(_PCH_TRANS_HTOTAL_A, dev_priv->regfile.saveTRANS_HTOTAL_A);
+ I915_WRITE(_PCH_TRANS_HBLANK_A, dev_priv->regfile.saveTRANS_HBLANK_A);
+ I915_WRITE(_PCH_TRANS_HSYNC_A, dev_priv->regfile.saveTRANS_HSYNC_A);
+ I915_WRITE(_PCH_TRANS_VTOTAL_A, dev_priv->regfile.saveTRANS_VTOTAL_A);
+ I915_WRITE(_PCH_TRANS_VBLANK_A, dev_priv->regfile.saveTRANS_VBLANK_A);
+ I915_WRITE(_PCH_TRANS_VSYNC_A, dev_priv->regfile.saveTRANS_VSYNC_A);
}
/* Restore plane info */
@@ -448,13 +448,13 @@ void i915_restore_display_reg(struct drm_device *dev)
I915_WRITE(_PFB_WIN_SZ, dev_priv->regfile.savePFB_WIN_SZ);
I915_WRITE(_PFB_WIN_POS, dev_priv->regfile.savePFB_WIN_POS);
- I915_WRITE(_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
- I915_WRITE(_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
- I915_WRITE(_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
- I915_WRITE(_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
- I915_WRITE(_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
- I915_WRITE(_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
- I915_WRITE(_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
+ I915_WRITE(_PCH_TRANSBCONF, dev_priv->regfile.saveTRANSBCONF);
+ I915_WRITE(_PCH_TRANS_HTOTAL_B, dev_priv->regfile.saveTRANS_HTOTAL_B);
+ I915_WRITE(_PCH_TRANS_HBLANK_B, dev_priv->regfile.saveTRANS_HBLANK_B);
+ I915_WRITE(_PCH_TRANS_HSYNC_B, dev_priv->regfile.saveTRANS_HSYNC_B);
+ I915_WRITE(_PCH_TRANS_VTOTAL_B, dev_priv->regfile.saveTRANS_VTOTAL_B);
+ I915_WRITE(_PCH_TRANS_VBLANK_B, dev_priv->regfile.saveTRANS_VBLANK_B);
+ I915_WRITE(_PCH_TRANS_VSYNC_B, dev_priv->regfile.saveTRANS_VSYNC_B);
}
/* Restore plane info */
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 95070b2124c6..53f2bed8bc5f 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -212,7 +212,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
if (!lvds_options)
return;
- dev_priv->lvds_dither = lvds_options->pixel_dither;
+ dev_priv->vbt.lvds_dither = lvds_options->pixel_dither;
if (lvds_options->panel_type == 0xff)
return;
@@ -226,7 +226,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
if (!lvds_lfp_data_ptrs)
return;
- dev_priv->lvds_vbt = 1;
+ dev_priv->vbt.lvds_vbt = 1;
panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data,
lvds_lfp_data_ptrs,
@@ -238,7 +238,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);
- dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
+ dev_priv->vbt.lfp_lvds_vbt_mode = panel_fixed_mode;
DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
drm_mode_debug_printmodeline(panel_fixed_mode);
@@ -274,9 +274,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
/* check the resolution, just to be sure */
if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
fp_timing->y_res == panel_fixed_mode->vdisplay) {
- dev_priv->bios_lvds_val = fp_timing->lvds_reg_val;
+ dev_priv->vbt.bios_lvds_val = fp_timing->lvds_reg_val;
DRM_DEBUG_KMS("VBT initial LVDS value %x\n",
- dev_priv->bios_lvds_val);
+ dev_priv->vbt.bios_lvds_val);
}
}
}
@@ -316,7 +316,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
fill_detail_timing_data(panel_fixed_mode, dvo_timing + index);
- dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode;
+ dev_priv->vbt.sdvo_lvds_vbt_mode = panel_fixed_mode;
DRM_DEBUG_KMS("Found SDVO panel mode in BIOS VBT tables:\n");
drm_mode_debug_printmodeline(panel_fixed_mode);
@@ -345,20 +345,20 @@ parse_general_features(struct drm_i915_private *dev_priv,
general = find_section(bdb, BDB_GENERAL_FEATURES);
if (general) {
- dev_priv->int_tv_support = general->int_tv_support;
- dev_priv->int_crt_support = general->int_crt_support;
- dev_priv->lvds_use_ssc = general->enable_ssc;
- dev_priv->lvds_ssc_freq =
+ dev_priv->vbt.int_tv_support = general->int_tv_support;
+ dev_priv->vbt.int_crt_support = general->int_crt_support;
+ dev_priv->vbt.lvds_use_ssc = general->enable_ssc;
+ dev_priv->vbt.lvds_ssc_freq =
intel_bios_ssc_frequency(dev, general->ssc_freq);
- dev_priv->display_clock_mode = general->display_clock_mode;
- dev_priv->fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
+ dev_priv->vbt.display_clock_mode = general->display_clock_mode;
+ dev_priv->vbt.fdi_rx_polarity_inverted = general->fdi_rx_polarity_inverted;
DRM_DEBUG_KMS("BDB_GENERAL_FEATURES int_tv_support %d int_crt_support %d lvds_use_ssc %d lvds_ssc_freq %d display_clock_mode %d fdi_rx_polarity_inverted %d\n",
- dev_priv->int_tv_support,
- dev_priv->int_crt_support,
- dev_priv->lvds_use_ssc,
- dev_priv->lvds_ssc_freq,
- dev_priv->display_clock_mode,
- dev_priv->fdi_rx_polarity_inverted);
+ dev_priv->vbt.int_tv_support,
+ dev_priv->vbt.int_crt_support,
+ dev_priv->vbt.lvds_use_ssc,
+ dev_priv->vbt.lvds_ssc_freq,
+ dev_priv->vbt.display_clock_mode,
+ dev_priv->vbt.fdi_rx_polarity_inverted);
}
}
@@ -375,7 +375,7 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
int bus_pin = general->crt_ddc_gmbus_pin;
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
if (intel_gmbus_is_port_valid(bus_pin))
- dev_priv->crt_ddc_pin = bus_pin;
+ dev_priv->vbt.crt_ddc_pin = bus_pin;
} else {
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
block_size);
@@ -486,7 +486,7 @@ parse_driver_features(struct drm_i915_private *dev_priv,
if (SUPPORTS_EDP(dev) &&
driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
- dev_priv->edp.support = 1;
+ dev_priv->vbt.edp_support = 1;
if (driver->dual_frequency)
dev_priv->render_reclock_avail = true;
@@ -501,20 +501,20 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
edp = find_section(bdb, BDB_EDP);
if (!edp) {
- if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support)
+ if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->vbt.edp_support)
DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n");
return;
}
switch ((edp->color_depth >> (panel_type * 2)) & 3) {
case EDP_18BPP:
- dev_priv->edp.bpp = 18;
+ dev_priv->vbt.edp_bpp = 18;
break;
case EDP_24BPP:
- dev_priv->edp.bpp = 24;
+ dev_priv->vbt.edp_bpp = 24;
break;
case EDP_30BPP:
- dev_priv->edp.bpp = 30;
+ dev_priv->vbt.edp_bpp = 30;
break;
}
@@ -522,48 +522,48 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
edp_pps = &edp->power_seqs[panel_type];
edp_link_params = &edp->link_params[panel_type];
- dev_priv->edp.pps = *edp_pps;
+ dev_priv->vbt.edp_pps = *edp_pps;
- dev_priv->edp.rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
+ dev_priv->vbt.edp_rate = edp_link_params->rate ? DP_LINK_BW_2_7 :
DP_LINK_BW_1_62;
switch (edp_link_params->lanes) {
case 0:
- dev_priv->edp.lanes = 1;
+ dev_priv->vbt.edp_lanes = 1;
break;
case 1:
- dev_priv->edp.lanes = 2;
+ dev_priv->vbt.edp_lanes = 2;
break;
case 3:
default:
- dev_priv->edp.lanes = 4;
+ dev_priv->vbt.edp_lanes = 4;
break;
}
switch (edp_link_params->preemphasis) {
case 0:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
+ dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_0;
break;
case 1:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
+ dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_3_5;
break;
case 2:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
+ dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_6;
break;
case 3:
- dev_priv->edp.preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
+ dev_priv->vbt.edp_preemphasis = DP_TRAIN_PRE_EMPHASIS_9_5;
break;
}
switch (edp_link_params->vswing) {
case 0:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_400;
+ dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_400;
break;
case 1:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_600;
+ dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_600;
break;
case 2:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_800;
+ dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_800;
break;
case 3:
- dev_priv->edp.vswing = DP_TRAIN_VOLTAGE_SWING_1200;
+ dev_priv->vbt.edp_vswing = DP_TRAIN_VOLTAGE_SWING_1200;
break;
}
}
@@ -611,13 +611,13 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
return;
}
- dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
- if (!dev_priv->child_dev) {
+ dev_priv->vbt.child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
+ if (!dev_priv->vbt.child_dev) {
DRM_DEBUG_KMS("No memory space for child device\n");
return;
}
- dev_priv->child_dev_num = count;
+ dev_priv->vbt.child_dev_num = count;
count = 0;
for (i = 0; i < child_device_num; i++) {
p_child = &(p_defs->devices[i]);
@@ -625,7 +625,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
/* skip the device block if device type is invalid */
continue;
}
- child_dev_ptr = dev_priv->child_dev + count;
+ child_dev_ptr = dev_priv->vbt.child_dev + count;
count++;
memcpy((void *)child_dev_ptr, (void *)p_child,
sizeof(*p_child));
@@ -638,23 +638,23 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
- dev_priv->crt_ddc_pin = GMBUS_PORT_VGADDC;
+ dev_priv->vbt.crt_ddc_pin = GMBUS_PORT_VGADDC;
/* LFP panel data */
- dev_priv->lvds_dither = 1;
- dev_priv->lvds_vbt = 0;
+ dev_priv->vbt.lvds_dither = 1;
+ dev_priv->vbt.lvds_vbt = 0;
/* SDVO panel data */
- dev_priv->sdvo_lvds_vbt_mode = NULL;
+ dev_priv->vbt.sdvo_lvds_vbt_mode = NULL;
/* general features */
- dev_priv->int_tv_support = 1;
- dev_priv->int_crt_support = 1;
+ dev_priv->vbt.int_tv_support = 1;
+ dev_priv->vbt.int_crt_support = 1;
/* Default to using SSC */
- dev_priv->lvds_use_ssc = 1;
- dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
- DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
+ dev_priv->vbt.lvds_use_ssc = 1;
+ dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
+ DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq);
}
static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 58b4a53715cd..3acec8c48166 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -84,6 +84,28 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
return true;
}
+static void intel_crt_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_crt *crt = intel_encoder_to_crt(encoder);
+ u32 tmp, flags = 0;
+
+ tmp = I915_READ(crt->adpa_reg);
+
+ if (tmp & ADPA_HSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (tmp & ADPA_VSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+
+ pipe_config->adjusted_mode.flags |= flags;
+}
+
/* Note: The caller is required to filter out dpms modes not supported by the
* platform. */
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -127,7 +149,7 @@ static void intel_enable_crt(struct intel_encoder *encoder)
intel_crt_set_dpms(encoder, crt->connector->base.dpms);
}
-
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
static void intel_crt_dpms(struct drm_connector *connector, int mode)
{
struct drm_device *dev = connector->dev;
@@ -158,6 +180,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
else
encoder->connectors_active = true;
+ /* We call connector dpms manually below in case pipe dpms doesn't
+ * change due to cloning. */
if (mode < old_dpms) {
/* From off to on, enable the pipe first. */
intel_crtc_update_dpms(crtc);
@@ -207,6 +231,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev))
pipe_config->has_pch_encoder = true;
+ /* LPT FDI RX only supports 8bpc. */
+ if (HAS_PCH_LPT(dev))
+ pipe_config->pipe_bpp = 24;
+
return true;
}
@@ -431,7 +459,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
- i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+ i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
edid = intel_crt_get_edid(connector, i2c);
if (edid) {
@@ -637,7 +665,7 @@ static int intel_crt_get_modes(struct drm_connector *connector)
int ret;
struct i2c_adapter *i2c;
- i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+ i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
ret = intel_crt_ddc_get_modes(connector, i2c);
if (ret || !IS_G4X(dev))
return ret;
@@ -774,6 +802,7 @@ void intel_crt_init(struct drm_device *dev)
crt->base.compute_config = intel_crt_compute_config;
crt->base.disable = intel_disable_crt;
crt->base.enable = intel_enable_crt;
+ crt->base.get_config = intel_crt_get_config;
if (I915_HAS_HOTPLUG(dev))
crt->base.hpd_pin = HPD_CRT;
if (HAS_DDI(dev))
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index fb961bb81903..324211ac9c55 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -174,6 +174,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
* mode set "sequence for CRT port" document:
* - TP1 to TP2 time with the default value
* - FDI delay to 90h
+ *
+ * WaFDIAutoLinkSetTimingOverrride:hsw
*/
I915_WRITE(_FDI_RXA_MISC, FDI_RX_PWRDN_LANE1_VAL(2) |
FDI_RX_PWRDN_LANE0_VAL(2) |
@@ -181,7 +183,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
/* Enable the PCH Receiver FDI PLL */
rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
- FDI_RX_PLL_ENABLE | ((intel_crtc->fdi_lanes - 1) << 19);
+ FDI_RX_PLL_ENABLE |
+ FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
POSTING_READ(_FDI_RXA_CTL);
udelay(220);
@@ -209,7 +212,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
* port reversal bit */
I915_WRITE(DDI_BUF_CTL(PORT_E),
DDI_BUF_CTL_ENABLE |
- ((intel_crtc->fdi_lanes - 1) << 1) |
+ ((intel_crtc->config.fdi_lanes - 1) << 1) |
hsw_ddi_buf_ctl_values[i / 2]);
POSTING_READ(DDI_BUF_CTL(PORT_E));
@@ -278,392 +281,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
DRM_ERROR("FDI link training failed!\n");
}
-/* WRPLL clock dividers */
-struct wrpll_tmds_clock {
- u32 clock;
- u16 p; /* Post divider */
- u16 n2; /* Feedback divider */
- u16 r2; /* Reference divider */
-};
-
-/* Table of matching values for WRPLL clocks programming for each frequency.
- * The code assumes this table is sorted. */
-static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
- {19750, 38, 25, 18},
- {20000, 48, 32, 18},
- {21000, 36, 21, 15},
- {21912, 42, 29, 17},
- {22000, 36, 22, 15},
- {23000, 36, 23, 15},
- {23500, 40, 40, 23},
- {23750, 26, 16, 14},
- {24000, 36, 24, 15},
- {25000, 36, 25, 15},
- {25175, 26, 40, 33},
- {25200, 30, 21, 15},
- {26000, 36, 26, 15},
- {27000, 30, 21, 14},
- {27027, 18, 100, 111},
- {27500, 30, 29, 19},
- {28000, 34, 30, 17},
- {28320, 26, 30, 22},
- {28322, 32, 42, 25},
- {28750, 24, 23, 18},
- {29000, 30, 29, 18},
- {29750, 32, 30, 17},
- {30000, 30, 25, 15},
- {30750, 30, 41, 24},
- {31000, 30, 31, 18},
- {31500, 30, 28, 16},
- {32000, 30, 32, 18},
- {32500, 28, 32, 19},
- {33000, 24, 22, 15},
- {34000, 28, 30, 17},
- {35000, 26, 32, 19},
- {35500, 24, 30, 19},
- {36000, 26, 26, 15},
- {36750, 26, 46, 26},
- {37000, 24, 23, 14},
- {37762, 22, 40, 26},
- {37800, 20, 21, 15},
- {38000, 24, 27, 16},
- {38250, 24, 34, 20},
- {39000, 24, 26, 15},
- {40000, 24, 32, 18},
- {40500, 20, 21, 14},
- {40541, 22, 147, 89},
- {40750, 18, 19, 14},
- {41000, 16, 17, 14},
- {41500, 22, 44, 26},
- {41540, 22, 44, 26},
- {42000, 18, 21, 15},
- {42500, 22, 45, 26},
- {43000, 20, 43, 27},
- {43163, 20, 24, 15},
- {44000, 18, 22, 15},
- {44900, 20, 108, 65},
- {45000, 20, 25, 15},
- {45250, 20, 52, 31},
- {46000, 18, 23, 15},
- {46750, 20, 45, 26},
- {47000, 20, 40, 23},
- {48000, 18, 24, 15},
- {49000, 18, 49, 30},
- {49500, 16, 22, 15},
- {50000, 18, 25, 15},
- {50500, 18, 32, 19},
- {51000, 18, 34, 20},
- {52000, 18, 26, 15},
- {52406, 14, 34, 25},
- {53000, 16, 22, 14},
- {54000, 16, 24, 15},
- {54054, 16, 173, 108},
- {54500, 14, 24, 17},
- {55000, 12, 22, 18},
- {56000, 14, 45, 31},
- {56250, 16, 25, 15},
- {56750, 14, 25, 17},
- {57000, 16, 27, 16},
- {58000, 16, 43, 25},
- {58250, 16, 38, 22},
- {58750, 16, 40, 23},
- {59000, 14, 26, 17},
- {59341, 14, 40, 26},
- {59400, 16, 44, 25},
- {60000, 16, 32, 18},
- {60500, 12, 39, 29},
- {61000, 14, 49, 31},
- {62000, 14, 37, 23},
- {62250, 14, 42, 26},
- {63000, 12, 21, 15},
- {63500, 14, 28, 17},
- {64000, 12, 27, 19},
- {65000, 14, 32, 19},
- {65250, 12, 29, 20},
- {65500, 12, 32, 22},
- {66000, 12, 22, 15},
- {66667, 14, 38, 22},
- {66750, 10, 21, 17},
- {67000, 14, 33, 19},
- {67750, 14, 58, 33},
- {68000, 14, 30, 17},
- {68179, 14, 46, 26},
- {68250, 14, 46, 26},
- {69000, 12, 23, 15},
- {70000, 12, 28, 18},
- {71000, 12, 30, 19},
- {72000, 12, 24, 15},
- {73000, 10, 23, 17},
- {74000, 12, 23, 14},
- {74176, 8, 100, 91},
- {74250, 10, 22, 16},
- {74481, 12, 43, 26},
- {74500, 10, 29, 21},
- {75000, 12, 25, 15},
- {75250, 10, 39, 28},
- {76000, 12, 27, 16},
- {77000, 12, 53, 31},
- {78000, 12, 26, 15},
- {78750, 12, 28, 16},
- {79000, 10, 38, 26},
- {79500, 10, 28, 19},
- {80000, 12, 32, 18},
- {81000, 10, 21, 14},
- {81081, 6, 100, 111},
- {81624, 8, 29, 24},
- {82000, 8, 17, 14},
- {83000, 10, 40, 26},
- {83950, 10, 28, 18},
- {84000, 10, 28, 18},
- {84750, 6, 16, 17},
- {85000, 6, 17, 18},
- {85250, 10, 30, 19},
- {85750, 10, 27, 17},
- {86000, 10, 43, 27},
- {87000, 10, 29, 18},
- {88000, 10, 44, 27},
- {88500, 10, 41, 25},
- {89000, 10, 28, 17},
- {89012, 6, 90, 91},
- {89100, 10, 33, 20},
- {90000, 10, 25, 15},
- {91000, 10, 32, 19},
- {92000, 10, 46, 27},
- {93000, 10, 31, 18},
- {94000, 10, 40, 23},
- {94500, 10, 28, 16},
- {95000, 10, 44, 25},
- {95654, 10, 39, 22},
- {95750, 10, 39, 22},
- {96000, 10, 32, 18},
- {97000, 8, 23, 16},
- {97750, 8, 42, 29},
- {98000, 8, 45, 31},
- {99000, 8, 22, 15},
- {99750, 8, 34, 23},
- {100000, 6, 20, 18},
- {100500, 6, 19, 17},
- {101000, 6, 37, 33},
- {101250, 8, 21, 14},
- {102000, 6, 17, 15},
- {102250, 6, 25, 22},
- {103000, 8, 29, 19},
- {104000, 8, 37, 24},
- {105000, 8, 28, 18},
- {106000, 8, 22, 14},
- {107000, 8, 46, 29},
- {107214, 8, 27, 17},
- {108000, 8, 24, 15},
- {108108, 8, 173, 108},
- {109000, 6, 23, 19},
- {110000, 6, 22, 18},
- {110013, 6, 22, 18},
- {110250, 8, 49, 30},
- {110500, 8, 36, 22},
- {111000, 8, 23, 14},
- {111264, 8, 150, 91},
- {111375, 8, 33, 20},
- {112000, 8, 63, 38},
- {112500, 8, 25, 15},
- {113100, 8, 57, 34},
- {113309, 8, 42, 25},
- {114000, 8, 27, 16},
- {115000, 6, 23, 18},
- {116000, 8, 43, 25},
- {117000, 8, 26, 15},
- {117500, 8, 40, 23},
- {118000, 6, 38, 29},
- {119000, 8, 30, 17},
- {119500, 8, 46, 26},
- {119651, 8, 39, 22},
- {120000, 8, 32, 18},
- {121000, 6, 39, 29},
- {121250, 6, 31, 23},
- {121750, 6, 23, 17},
- {122000, 6, 42, 31},
- {122614, 6, 30, 22},
- {123000, 6, 41, 30},
- {123379, 6, 37, 27},
- {124000, 6, 51, 37},
- {125000, 6, 25, 18},
- {125250, 4, 13, 14},
- {125750, 4, 27, 29},
- {126000, 6, 21, 15},
- {127000, 6, 24, 17},
- {127250, 6, 41, 29},
- {128000, 6, 27, 19},
- {129000, 6, 43, 30},
- {129859, 4, 25, 26},
- {130000, 6, 26, 18},
- {130250, 6, 42, 29},
- {131000, 6, 32, 22},
- {131500, 6, 38, 26},
- {131850, 6, 41, 28},
- {132000, 6, 22, 15},
- {132750, 6, 28, 19},
- {133000, 6, 34, 23},
- {133330, 6, 37, 25},
- {134000, 6, 61, 41},
- {135000, 6, 21, 14},
- {135250, 6, 167, 111},
- {136000, 6, 62, 41},
- {137000, 6, 35, 23},
- {138000, 6, 23, 15},
- {138500, 6, 40, 26},
- {138750, 6, 37, 24},
- {139000, 6, 34, 22},
- {139050, 6, 34, 22},
- {139054, 6, 34, 22},
- {140000, 6, 28, 18},
- {141000, 6, 36, 23},
- {141500, 6, 22, 14},
- {142000, 6, 30, 19},
- {143000, 6, 27, 17},
- {143472, 4, 17, 16},
- {144000, 6, 24, 15},
- {145000, 6, 29, 18},
- {146000, 6, 47, 29},
- {146250, 6, 26, 16},
- {147000, 6, 49, 30},
- {147891, 6, 23, 14},
- {148000, 6, 23, 14},
- {148250, 6, 28, 17},
- {148352, 4, 100, 91},
- {148500, 6, 33, 20},
- {149000, 6, 48, 29},
- {150000, 6, 25, 15},
- {151000, 4, 19, 17},
- {152000, 6, 27, 16},
- {152280, 6, 44, 26},
- {153000, 6, 34, 20},
- {154000, 6, 53, 31},
- {155000, 6, 31, 18},
- {155250, 6, 50, 29},
- {155750, 6, 45, 26},
- {156000, 6, 26, 15},
- {157000, 6, 61, 35},
- {157500, 6, 28, 16},
- {158000, 6, 65, 37},
- {158250, 6, 44, 25},
- {159000, 6, 53, 30},
- {159500, 6, 39, 22},
- {160000, 6, 32, 18},
- {161000, 4, 31, 26},
- {162000, 4, 18, 15},
- {162162, 4, 131, 109},
- {162500, 4, 53, 44},
- {163000, 4, 29, 24},
- {164000, 4, 17, 14},
- {165000, 4, 22, 18},
- {166000, 4, 32, 26},
- {167000, 4, 26, 21},
- {168000, 4, 46, 37},
- {169000, 4, 104, 83},
- {169128, 4, 64, 51},
- {169500, 4, 39, 31},
- {170000, 4, 34, 27},
- {171000, 4, 19, 15},
- {172000, 4, 51, 40},
- {172750, 4, 32, 25},
- {172800, 4, 32, 25},
- {173000, 4, 41, 32},
- {174000, 4, 49, 38},
- {174787, 4, 22, 17},
- {175000, 4, 35, 27},
- {176000, 4, 30, 23},
- {177000, 4, 38, 29},
- {178000, 4, 29, 22},
- {178500, 4, 37, 28},
- {179000, 4, 53, 40},
- {179500, 4, 73, 55},
- {180000, 4, 20, 15},
- {181000, 4, 55, 41},
- {182000, 4, 31, 23},
- {183000, 4, 42, 31},
- {184000, 4, 30, 22},
- {184750, 4, 26, 19},
- {185000, 4, 37, 27},
- {186000, 4, 51, 37},
- {187000, 4, 36, 26},
- {188000, 4, 32, 23},
- {189000, 4, 21, 15},
- {190000, 4, 38, 27},
- {190960, 4, 41, 29},
- {191000, 4, 41, 29},
- {192000, 4, 27, 19},
- {192250, 4, 37, 26},
- {193000, 4, 20, 14},
- {193250, 4, 53, 37},
- {194000, 4, 23, 16},
- {194208, 4, 23, 16},
- {195000, 4, 26, 18},
- {196000, 4, 45, 31},
- {197000, 4, 35, 24},
- {197750, 4, 41, 28},
- {198000, 4, 22, 15},
- {198500, 4, 25, 17},
- {199000, 4, 28, 19},
- {200000, 4, 37, 25},
- {201000, 4, 61, 41},
- {202000, 4, 112, 75},
- {202500, 4, 21, 14},
- {203000, 4, 146, 97},
- {204000, 4, 62, 41},
- {204750, 4, 44, 29},
- {205000, 4, 38, 25},
- {206000, 4, 29, 19},
- {207000, 4, 23, 15},
- {207500, 4, 40, 26},
- {208000, 4, 37, 24},
- {208900, 4, 48, 31},
- {209000, 4, 48, 31},
- {209250, 4, 31, 20},
- {210000, 4, 28, 18},
- {211000, 4, 25, 16},
- {212000, 4, 22, 14},
- {213000, 4, 30, 19},
- {213750, 4, 38, 24},
- {214000, 4, 46, 29},
- {214750, 4, 35, 22},
- {215000, 4, 43, 27},
- {216000, 4, 24, 15},
- {217000, 4, 37, 23},
- {218000, 4, 42, 26},
- {218250, 4, 42, 26},
- {218750, 4, 34, 21},
- {219000, 4, 47, 29},
- {220000, 4, 44, 27},
- {220640, 4, 49, 30},
- {220750, 4, 36, 22},
- {221000, 4, 36, 22},
- {222000, 4, 23, 14},
- {222525, 4, 28, 17},
- {222750, 4, 33, 20},
- {227000, 4, 37, 22},
- {230250, 4, 29, 17},
- {233500, 4, 38, 22},
- {235000, 4, 40, 23},
- {238000, 4, 30, 17},
- {241500, 2, 17, 19},
- {245250, 2, 20, 22},
- {247750, 2, 22, 24},
- {253250, 2, 15, 16},
- {256250, 2, 18, 19},
- {262500, 2, 31, 32},
- {267250, 2, 66, 67},
- {268500, 2, 94, 95},
- {270000, 2, 14, 14},
- {272500, 2, 77, 76},
- {273750, 2, 57, 56},
- {280750, 2, 24, 23},
- {281250, 2, 23, 22},
- {286000, 2, 17, 16},
- {291750, 2, 26, 24},
- {296703, 2, 56, 51},
- {297000, 2, 22, 20},
- {298000, 2, 21, 19},
-};
-
static void intel_ddi_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -675,7 +292,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
int pipe = intel_crtc->pipe;
int type = intel_encoder->type;
- DRM_DEBUG_KMS("Preparing DDI mode for Haswell on port %c, pipe %c\n",
+ DRM_DEBUG_KMS("Preparing DDI mode on port %c, pipe %c\n",
port_name(port), pipe_name(pipe));
intel_crtc->eld_vld = false;
@@ -686,22 +303,7 @@ static void intel_ddi_mode_set(struct drm_encoder *encoder,
intel_dp->DP = intel_dig_port->port_reversal |
DDI_BUF_CTL_ENABLE | DDI_BUF_EMP_400MV_0DB_HSW;
- switch (intel_dp->lane_count) {
- case 1:
- intel_dp->DP |= DDI_PORT_WIDTH_X1;
- break;
- case 2:
- intel_dp->DP |= DDI_PORT_WIDTH_X2;
- break;
- case 4:
- intel_dp->DP |= DDI_PORT_WIDTH_X4;
- break;
- default:
- intel_dp->DP |= DDI_PORT_WIDTH_X4;
- WARN(1, "Unexpected DP lane count %d\n",
- intel_dp->lane_count);
- break;
- }
+ intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
if (intel_dp->has_audio) {
DRM_DEBUG_DRIVER("DP audio on pipe %c on DDI\n",
@@ -748,8 +350,8 @@ intel_ddi_get_crtc_encoder(struct drm_crtc *crtc)
}
if (num_encoders != 1)
- WARN(1, "%d encoders on crtc for pipe %d\n", num_encoders,
- intel_crtc->pipe);
+ WARN(1, "%d encoders on crtc for pipe %c\n", num_encoders,
+ pipe_name(intel_crtc->pipe));
BUG_ON(ret == NULL);
return ret;
@@ -802,30 +404,227 @@ void intel_ddi_put_crtc_pll(struct drm_crtc *crtc)
intel_crtc->ddi_pll_sel = PORT_CLK_SEL_NONE;
}
-static void intel_ddi_calculate_wrpll(int clock, int *p, int *n2, int *r2)
+#define LC_FREQ 2700
+#define LC_FREQ_2K (LC_FREQ * 2000)
+
+#define P_MIN 2
+#define P_MAX 64
+#define P_INC 2
+
+/* Constraints for PLL good behavior */
+#define REF_MIN 48
+#define REF_MAX 400
+#define VCO_MIN 2400
+#define VCO_MAX 4800
+
+#define ABS_DIFF(a, b) ((a > b) ? (a - b) : (b - a))
+
+struct wrpll_rnp {
+ unsigned p, n2, r2;
+};
+
+static unsigned wrpll_get_budget_for_freq(int clock)
+{
+ unsigned budget;
+
+ switch (clock) {
+ case 25175000:
+ case 25200000:
+ case 27000000:
+ case 27027000:
+ case 37762500:
+ case 37800000:
+ case 40500000:
+ case 40541000:
+ case 54000000:
+ case 54054000:
+ case 59341000:
+ case 59400000:
+ case 72000000:
+ case 74176000:
+ case 74250000:
+ case 81000000:
+ case 81081000:
+ case 89012000:
+ case 89100000:
+ case 108000000:
+ case 108108000:
+ case 111264000:
+ case 111375000:
+ case 148352000:
+ case 148500000:
+ case 162000000:
+ case 162162000:
+ case 222525000:
+ case 222750000:
+ case 296703000:
+ case 297000000:
+ budget = 0;
+ break;
+ case 233500000:
+ case 245250000:
+ case 247750000:
+ case 253250000:
+ case 298000000:
+ budget = 1500;
+ break;
+ case 169128000:
+ case 169500000:
+ case 179500000:
+ case 202000000:
+ budget = 2000;
+ break;
+ case 256250000:
+ case 262500000:
+ case 270000000:
+ case 272500000:
+ case 273750000:
+ case 280750000:
+ case 281250000:
+ case 286000000:
+ case 291750000:
+ budget = 4000;
+ break;
+ case 267250000:
+ case 268500000:
+ budget = 5000;
+ break;
+ default:
+ budget = 1000;
+ break;
+ }
+
+ return budget;
+}
+
+static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
+ unsigned r2, unsigned n2, unsigned p,
+ struct wrpll_rnp *best)
{
- u32 i;
+ uint64_t a, b, c, d, diff, diff_best;
- for (i = 0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++)
- if (clock <= wrpll_tmds_clock_table[i].clock)
- break;
+ /* No best (r,n,p) yet */
+ if (best->p == 0) {
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ return;
+ }
+
+ /*
+ * Output clock is (LC_FREQ_2K / 2000) * N / (P * R), which compares to
+ * freq2k.
+ *
+ * delta = 1e6 *
+ * abs(freq2k - (LC_FREQ_2K * n2/(p * r2))) /
+ * freq2k;
+ *
+ * and we would like delta <= budget.
+ *
+ * If the discrepancy is above the PPM-based budget, always prefer to
+ * improve upon the previous solution. However, if you're within the
+ * budget, try to maximize Ref * VCO, that is N / (P * R^2).
+ */
+ a = freq2k * budget * p * r2;
+ b = freq2k * budget * best->p * best->r2;
+ diff = ABS_DIFF((freq2k * p * r2), (LC_FREQ_2K * n2));
+ diff_best = ABS_DIFF((freq2k * best->p * best->r2),
+ (LC_FREQ_2K * best->n2));
+ c = 1000000 * diff;
+ d = 1000000 * diff_best;
+
+ if (a < c && b < d) {
+ /* If both are above the budget, pick the closer */
+ if (best->p * best->r2 * diff < p * r2 * diff_best) {
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ }
+ } else if (a >= c && b < d) {
+ /* If A is below the threshold but B is above it? Update. */
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ } else if (a >= c && b >= d) {
+ /* Both are below the limit, so pick the higher n2/(r2*r2) */
+ if (n2 * best->r2 * best->r2 > best->n2 * r2 * r2) {
+ best->p = p;
+ best->n2 = n2;
+ best->r2 = r2;
+ }
+ }
+ /* Otherwise a < c && b >= d, do nothing */
+}
+
+static void
+intel_ddi_calculate_wrpll(int clock /* in Hz */,
+ unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
+{
+ uint64_t freq2k;
+ unsigned p, n2, r2;
+ struct wrpll_rnp best = { 0, 0, 0 };
+ unsigned budget;
- if (i == ARRAY_SIZE(wrpll_tmds_clock_table))
- i--;
+ freq2k = clock / 100;
- *p = wrpll_tmds_clock_table[i].p;
- *n2 = wrpll_tmds_clock_table[i].n2;
- *r2 = wrpll_tmds_clock_table[i].r2;
+ budget = wrpll_get_budget_for_freq(clock);
- if (wrpll_tmds_clock_table[i].clock != clock)
- DRM_INFO("WRPLL: using settings for %dKHz on %dKHz mode\n",
- wrpll_tmds_clock_table[i].clock, clock);
+ /* Special case handling for 540 pixel clock: bypass WR PLL entirely
+ * and directly pass the LC PLL to it. */
+ if (freq2k == 5400000) {
+ *n2_out = 2;
+ *p_out = 1;
+ *r2_out = 2;
+ return;
+ }
+
+ /*
+ * Ref = LC_FREQ / R, where Ref is the actual reference input seen by
+ * the WR PLL.
+ *
+ * We want R so that REF_MIN <= Ref <= REF_MAX.
+ * Injecting R2 = 2 * R gives:
+ * REF_MAX * r2 > LC_FREQ * 2 and
+ * REF_MIN * r2 < LC_FREQ * 2
+ *
+ * Which means the desired boundaries for r2 are:
+ * LC_FREQ * 2 / REF_MAX < r2 < LC_FREQ * 2 / REF_MIN
+ *
+ */
+ for (r2 = LC_FREQ * 2 / REF_MAX + 1;
+ r2 <= LC_FREQ * 2 / REF_MIN;
+ r2++) {
+
+ /*
+ * VCO = N * Ref, that is: VCO = N * LC_FREQ / R
+ *
+ * Once again we want VCO_MIN <= VCO <= VCO_MAX.
+ * Injecting R2 = 2 * R and N2 = 2 * N, we get:
+ * VCO_MAX * r2 > n2 * LC_FREQ and
+ * VCO_MIN * r2 < n2 * LC_FREQ)
+ *
+ * Which means the desired boundaries for n2 are:
+ * VCO_MIN * r2 / LC_FREQ < n2 < VCO_MAX * r2 / LC_FREQ
+ */
+ for (n2 = VCO_MIN * r2 / LC_FREQ + 1;
+ n2 <= VCO_MAX * r2 / LC_FREQ;
+ n2++) {
- DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n",
- clock, *p, *n2, *r2);
+ for (p = P_MIN; p <= P_MAX; p += P_INC)
+ wrpll_update_rnp(freq2k, budget,
+ r2, n2, p, &best);
+ }
+ }
+
+ *n2_out = best.n2;
+ *p_out = best.p;
+ *r2_out = best.r2;
+
+ DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n",
+ clock, *p_out, *n2_out, *r2_out);
}
-bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
+bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
@@ -835,6 +634,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
int type = intel_encoder->type;
enum pipe pipe = intel_crtc->pipe;
uint32_t reg, val;
+ int clock = intel_crtc->config.port_clock;
/* TODO: reuse PLLs when possible (compare values) */
@@ -863,7 +663,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
return true;
} else if (type == INTEL_OUTPUT_HDMI) {
- int p, n2, r2;
+ unsigned p, n2, r2;
if (plls->wrpll1_refcount == 0) {
DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n",
@@ -885,7 +685,7 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock)
WARN(I915_READ(reg) & WRPLL_PLL_ENABLE,
"WRPLL already enabled\n");
- intel_ddi_calculate_wrpll(clock, &p, &n2, &r2);
+ intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
@@ -995,7 +795,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
/* Can only use the always-on power well for eDP when
* not using the panel fitter, and when not using motion
* blur mitigation (which we don't support). */
- if (dev_priv->pch_pf_size)
+ if (intel_crtc->config.pch_pfit.size)
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
else
temp |= TRANS_DDI_EDP_INPUT_A_ON;
@@ -1022,7 +822,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
} else if (type == INTEL_OUTPUT_ANALOG) {
temp |= TRANS_DDI_MODE_SELECT_FDI;
- temp |= (intel_crtc->fdi_lanes - 1) << 1;
+ temp |= (intel_crtc->config.fdi_lanes - 1) << 1;
} else if (type == INTEL_OUTPUT_DISPLAYPORT ||
type == INTEL_OUTPUT_EDP) {
@@ -1030,25 +830,10 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
temp |= TRANS_DDI_MODE_SELECT_DP_SST;
- switch (intel_dp->lane_count) {
- case 1:
- temp |= TRANS_DDI_PORT_WIDTH_X1;
- break;
- case 2:
- temp |= TRANS_DDI_PORT_WIDTH_X2;
- break;
- case 4:
- temp |= TRANS_DDI_PORT_WIDTH_X4;
- break;
- default:
- temp |= TRANS_DDI_PORT_WIDTH_X4;
- WARN(1, "Unsupported lane count %d\n",
- intel_dp->lane_count);
- }
-
+ temp |= DDI_PORT_WIDTH(intel_dp->lane_count);
} else {
- WARN(1, "Invalid encoder type %d for pipe %d\n",
- intel_encoder->type, pipe);
+ WARN(1, "Invalid encoder type %d for pipe %c\n",
+ intel_encoder->type, pipe_name(pipe));
}
I915_WRITE(TRANS_DDI_FUNC_CTL(cpu_transcoder), temp);
@@ -1148,7 +933,7 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
}
}
- DRM_DEBUG_KMS("No pipe for ddi port %i found\n", port);
+ DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
return false;
}
@@ -1334,7 +1119,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
ironlake_edp_backlight_on(intel_dp);
}
- if (intel_crtc->eld_vld) {
+ if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
tmp |= ((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
@@ -1352,9 +1137,12 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
- tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
- tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) << (pipe * 4));
- I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
+ if (intel_crtc->eld_vld && type != INTEL_OUTPUT_EDP) {
+ tmp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);
+ tmp &= ~((AUDIO_OUTPUT_ENABLE_A | AUDIO_ELD_VALID_A) <<
+ (pipe * 4));
+ I915_WRITE(HSW_AUD_PIN_ELD_CP_VLD, tmp);
+ }
if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -1366,14 +1154,14 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
{
if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT)
- return 450;
+ return 450000;
else if ((I915_READ(LCPLL_CTL) & LCPLL_CLK_FREQ_MASK) ==
LCPLL_CLK_FREQ_450)
- return 450;
+ return 450000;
else if (IS_ULT(dev_priv->dev))
- return 338;
+ return 337500;
else
- return 540;
+ return 540000;
}
void intel_ddi_pll_init(struct drm_device *dev)
@@ -1386,7 +1174,7 @@ void intel_ddi_pll_init(struct drm_device *dev)
* Don't even try to turn it on.
*/
- DRM_DEBUG_KMS("CDCLK running at %dMHz\n",
+ DRM_DEBUG_KMS("CDCLK running at %dKHz\n",
intel_ddi_get_cdclk_freq(dev_priv));
if (val & LCPLL_CD_SOURCE_FCLK)
@@ -1472,6 +1260,27 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
intel_dp_check_link_status(intel_dp);
}
+static void intel_ddi_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ u32 temp, flags = 0;
+
+ temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
+ if (temp & TRANS_DDI_PHSYNC)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+ if (temp & TRANS_DDI_PVSYNC)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+
+ pipe_config->adjusted_mode.flags |= flags;
+}
+
static void intel_ddi_destroy(struct drm_encoder *encoder)
{
/* HDMI has nothing special to destroy, so we can go with this. */
@@ -1482,9 +1291,13 @@ static bool intel_ddi_compute_config(struct intel_encoder *encoder,
struct intel_crtc_config *pipe_config)
{
int type = encoder->type;
+ int port = intel_ddi_get_encoder_port(encoder);
WARN(type == INTEL_OUTPUT_UNKNOWN, "compute_config() on unknown output!\n");
+ if (port == PORT_A)
+ pipe_config->cpu_transcoder = TRANSCODER_EDP;
+
if (type == INTEL_OUTPUT_HDMI)
return intel_hdmi_compute_config(encoder, pipe_config);
else
@@ -1518,16 +1331,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
return;
}
- if (port != PORT_A) {
- hdmi_connector = kzalloc(sizeof(struct intel_connector),
- GFP_KERNEL);
- if (!hdmi_connector) {
- kfree(dp_connector);
- kfree(intel_dig_port);
- return;
- }
- }
-
intel_encoder = &intel_dig_port->base;
encoder = &intel_encoder->base;
@@ -1541,12 +1344,11 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_encoder->disable = intel_disable_ddi;
intel_encoder->post_disable = intel_ddi_post_disable;
intel_encoder->get_hw_state = intel_ddi_get_hw_state;
+ intel_encoder->get_config = intel_ddi_get_config;
intel_dig_port->port = port;
intel_dig_port->port_reversal = I915_READ(DDI_BUF_CTL(port)) &
DDI_BUF_PORT_REVERSAL;
- if (hdmi_connector)
- intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
intel_dig_port->dp.output_reg = DDI_BUF_CTL(port);
intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
@@ -1554,7 +1356,21 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
intel_encoder->cloneable = false;
intel_encoder->hot_plug = intel_ddi_hot_plug;
- if (hdmi_connector)
+ if (!intel_dp_init_connector(intel_dig_port, dp_connector)) {
+ drm_encoder_cleanup(encoder);
+ kfree(intel_dig_port);
+ kfree(dp_connector);
+ return;
+ }
+
+ if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+ hdmi_connector = kzalloc(sizeof(struct intel_connector),
+ GFP_KERNEL);
+ if (!hdmi_connector) {
+ return;
+ }
+
+ intel_dig_port->hdmi.hdmi_reg = DDI_BUF_CTL(port);
intel_hdmi_init_connector(intel_dig_port, hdmi_connector);
- intel_dp_init_connector(intel_dig_port, dp_connector);
+ }
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 56746dcac40f..85f3eb74d2b7 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -46,18 +46,6 @@ static void intel_increase_pllclock(struct drm_crtc *crtc);
static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
typedef struct {
- /* given values */
- int n;
- int m1, m2;
- int p1, p2;
- /* derived values */
- int dot;
- int vco;
- int m;
- int p;
-} intel_clock_t;
-
-typedef struct {
int min, max;
} intel_range_t;
@@ -71,24 +59,6 @@ typedef struct intel_limit intel_limit_t;
struct intel_limit {
intel_range_t dot, vco, n, m, m1, m2, p, p1;
intel_p2_t p2;
- /**
- * find_pll() - Find the best values for the PLL
- * @limit: limits for the PLL
- * @crtc: current CRTC
- * @target: target frequency in kHz
- * @refclk: reference clock frequency in kHz
- * @match_clock: if provided, @best_clock P divider must
- * match the P divider from @match_clock
- * used for LVDS downclocking
- * @best_clock: best PLL values found
- *
- * Returns true on success, false on failure.
- */
- bool (*find_pll)(const intel_limit_t *limit,
- struct drm_crtc *crtc,
- int target, int refclk,
- intel_clock_t *match_clock,
- intel_clock_t *best_clock);
};
/* FDI */
@@ -104,29 +74,6 @@ intel_pch_rawclk(struct drm_device *dev)
return I915_READ(PCH_RAWCLK_FREQ) & RAWCLK_FREQ_MASK;
}
-static bool
-intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock);
-static bool
-intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock);
-
-static bool
-intel_find_pll_g4x_dp(const intel_limit_t *, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock);
-static bool
-intel_find_pll_ironlake_dp(const intel_limit_t *, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock);
-
-static bool
-intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock);
-
static inline u32 /* units of 100MHz */
intel_fdi_link_freq(struct drm_device *dev)
{
@@ -148,7 +95,6 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
.p1 = { .min = 2, .max = 33 },
.p2 = { .dot_limit = 165000,
.p2_slow = 4, .p2_fast = 2 },
- .find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_i8xx_lvds = {
@@ -162,7 +108,6 @@ static const intel_limit_t intel_limits_i8xx_lvds = {
.p1 = { .min = 1, .max = 6 },
.p2 = { .dot_limit = 165000,
.p2_slow = 14, .p2_fast = 7 },
- .find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_i9xx_sdvo = {
@@ -176,7 +121,6 @@ static const intel_limit_t intel_limits_i9xx_sdvo = {
.p1 = { .min = 1, .max = 8 },
.p2 = { .dot_limit = 200000,
.p2_slow = 10, .p2_fast = 5 },
- .find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_i9xx_lvds = {
@@ -190,7 +134,6 @@ static const intel_limit_t intel_limits_i9xx_lvds = {
.p1 = { .min = 1, .max = 8 },
.p2 = { .dot_limit = 112000,
.p2_slow = 14, .p2_fast = 7 },
- .find_pll = intel_find_best_PLL,
};
@@ -207,7 +150,6 @@ static const intel_limit_t intel_limits_g4x_sdvo = {
.p2_slow = 10,
.p2_fast = 10
},
- .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_hdmi = {
@@ -221,7 +163,6 @@ static const intel_limit_t intel_limits_g4x_hdmi = {
.p1 = { .min = 1, .max = 8},
.p2 = { .dot_limit = 165000,
.p2_slow = 10, .p2_fast = 5 },
- .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
@@ -236,7 +177,6 @@ static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
.p2 = { .dot_limit = 0,
.p2_slow = 14, .p2_fast = 14
},
- .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
@@ -251,21 +191,6 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
.p2 = { .dot_limit = 0,
.p2_slow = 7, .p2_fast = 7
},
- .find_pll = intel_g4x_find_best_PLL,
-};
-
-static const intel_limit_t intel_limits_g4x_display_port = {
- .dot = { .min = 161670, .max = 227000 },
- .vco = { .min = 1750000, .max = 3500000},
- .n = { .min = 1, .max = 2 },
- .m = { .min = 97, .max = 108 },
- .m1 = { .min = 0x10, .max = 0x12 },
- .m2 = { .min = 0x05, .max = 0x06 },
- .p = { .min = 10, .max = 20 },
- .p1 = { .min = 1, .max = 2},
- .p2 = { .dot_limit = 0,
- .p2_slow = 10, .p2_fast = 10 },
- .find_pll = intel_find_pll_g4x_dp,
};
static const intel_limit_t intel_limits_pineview_sdvo = {
@@ -281,7 +206,6 @@ static const intel_limit_t intel_limits_pineview_sdvo = {
.p1 = { .min = 1, .max = 8 },
.p2 = { .dot_limit = 200000,
.p2_slow = 10, .p2_fast = 5 },
- .find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_pineview_lvds = {
@@ -295,7 +219,6 @@ static const intel_limit_t intel_limits_pineview_lvds = {
.p1 = { .min = 1, .max = 8 },
.p2 = { .dot_limit = 112000,
.p2_slow = 14, .p2_fast = 14 },
- .find_pll = intel_find_best_PLL,
};
/* Ironlake / Sandybridge
@@ -314,7 +237,6 @@ static const intel_limit_t intel_limits_ironlake_dac = {
.p1 = { .min = 1, .max = 8 },
.p2 = { .dot_limit = 225000,
.p2_slow = 10, .p2_fast = 5 },
- .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_single_lvds = {
@@ -328,7 +250,6 @@ static const intel_limit_t intel_limits_ironlake_single_lvds = {
.p1 = { .min = 2, .max = 8 },
.p2 = { .dot_limit = 225000,
.p2_slow = 14, .p2_fast = 14 },
- .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_dual_lvds = {
@@ -342,7 +263,6 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds = {
.p1 = { .min = 2, .max = 8 },
.p2 = { .dot_limit = 225000,
.p2_slow = 7, .p2_fast = 7 },
- .find_pll = intel_g4x_find_best_PLL,
};
/* LVDS 100mhz refclk limits. */
@@ -357,7 +277,6 @@ static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
.p1 = { .min = 2, .max = 8 },
.p2 = { .dot_limit = 225000,
.p2_slow = 14, .p2_fast = 14 },
- .find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
@@ -371,21 +290,6 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
.p1 = { .min = 2, .max = 6 },
.p2 = { .dot_limit = 225000,
.p2_slow = 7, .p2_fast = 7 },
- .find_pll = intel_g4x_find_best_PLL,
-};
-
-static const intel_limit_t intel_limits_ironlake_display_port = {
- .dot = { .min = 25000, .max = 350000 },
- .vco = { .min = 1760000, .max = 3510000},
- .n = { .min = 1, .max = 2 },
- .m = { .min = 81, .max = 90 },
- .m1 = { .min = 12, .max = 22 },
- .m2 = { .min = 5, .max = 9 },
- .p = { .min = 10, .max = 20 },
- .p1 = { .min = 1, .max = 2},
- .p2 = { .dot_limit = 0,
- .p2_slow = 10, .p2_fast = 10 },
- .find_pll = intel_find_pll_ironlake_dp,
};
static const intel_limit_t intel_limits_vlv_dac = {
@@ -396,15 +300,14 @@ static const intel_limit_t intel_limits_vlv_dac = {
.m1 = { .min = 2, .max = 3 },
.m2 = { .min = 11, .max = 156 },
.p = { .min = 10, .max = 30 },
- .p1 = { .min = 2, .max = 3 },
+ .p1 = { .min = 1, .max = 3 },
.p2 = { .dot_limit = 270000,
.p2_slow = 2, .p2_fast = 20 },
- .find_pll = intel_vlv_find_best_pll,
};
static const intel_limit_t intel_limits_vlv_hdmi = {
- .dot = { .min = 20000, .max = 165000 },
- .vco = { .min = 4000000, .max = 5994000},
+ .dot = { .min = 25000, .max = 270000 },
+ .vco = { .min = 4000000, .max = 6000000 },
.n = { .min = 1, .max = 7 },
.m = { .min = 60, .max = 300 }, /* guess */
.m1 = { .min = 2, .max = 3 },
@@ -413,7 +316,6 @@ static const intel_limit_t intel_limits_vlv_hdmi = {
.p1 = { .min = 2, .max = 3 },
.p2 = { .dot_limit = 270000,
.p2_slow = 2, .p2_fast = 20 },
- .find_pll = intel_vlv_find_best_pll,
};
static const intel_limit_t intel_limits_vlv_dp = {
@@ -424,61 +326,11 @@ static const intel_limit_t intel_limits_vlv_dp = {
.m1 = { .min = 2, .max = 3 },
.m2 = { .min = 11, .max = 156 },
.p = { .min = 10, .max = 30 },
- .p1 = { .min = 2, .max = 3 },
+ .p1 = { .min = 1, .max = 3 },
.p2 = { .dot_limit = 270000,
.p2_slow = 2, .p2_fast = 20 },
- .find_pll = intel_vlv_find_best_pll,
};
-u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg)
-{
- WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
- if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
- DRM_ERROR("DPIO idle wait timed out\n");
- return 0;
- }
-
- I915_WRITE(DPIO_REG, reg);
- I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID |
- DPIO_BYTE);
- if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
- DRM_ERROR("DPIO read wait timed out\n");
- return 0;
- }
-
- return I915_READ(DPIO_DATA);
-}
-
-static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg,
- u32 val)
-{
- WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
- if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
- DRM_ERROR("DPIO idle wait timed out\n");
- return;
- }
-
- I915_WRITE(DPIO_DATA, val);
- I915_WRITE(DPIO_REG, reg);
- I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID |
- DPIO_BYTE);
- if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100))
- DRM_ERROR("DPIO write wait timed out\n");
-}
-
-static void vlv_init_dpio(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- /* Reset the DPIO config */
- I915_WRITE(DPIO_CTL, 0);
- POSTING_READ(DPIO_CTL);
- I915_WRITE(DPIO_CTL, 1);
- POSTING_READ(DPIO_CTL);
-}
-
static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
int refclk)
{
@@ -497,10 +349,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
else
limit = &intel_limits_ironlake_single_lvds;
}
- } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
- intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
- limit = &intel_limits_ironlake_display_port;
- else
+ } else
limit = &intel_limits_ironlake_dac;
return limit;
@@ -521,8 +370,6 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
limit = &intel_limits_g4x_hdmi;
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
limit = &intel_limits_g4x_sdvo;
- } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
- limit = &intel_limits_g4x_display_port;
} else /* The option is for other outputs */
limit = &intel_limits_i9xx_sdvo;
@@ -573,13 +420,14 @@ static void pineview_clock(int refclk, intel_clock_t *clock)
clock->dot = clock->vco / clock->p;
}
-static void intel_clock(struct drm_device *dev, int refclk, intel_clock_t *clock)
+static uint32_t i9xx_dpll_compute_m(struct dpll *dpll)
{
- if (IS_PINEVIEW(dev)) {
- pineview_clock(refclk, clock);
- return;
- }
- clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
+ return 5 * (dpll->m1 + 2) + (dpll->m2 + 2);
+}
+
+static void i9xx_clock(int refclk, intel_clock_t *clock)
+{
+ clock->m = i9xx_dpll_compute_m(clock);
clock->p = clock->p1 * clock->p2;
clock->vco = refclk * clock->m / (clock->n + 2);
clock->dot = clock->vco / clock->p;
@@ -636,10 +484,9 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
}
static bool
-intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
+i9xx_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc,
int target, int refclk, intel_clock_t *match_clock,
intel_clock_t *best_clock)
-
{
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
@@ -668,8 +515,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
clock.m1++) {
for (clock.m2 = limit->m2.min;
clock.m2 <= limit->m2.max; clock.m2++) {
- /* m1 is always 0 in Pineview */
- if (clock.m2 >= clock.m1 && !IS_PINEVIEW(dev))
+ if (clock.m2 >= clock.m1)
break;
for (clock.n = limit->n.min;
clock.n <= limit->n.max; clock.n++) {
@@ -677,7 +523,66 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
clock.p1 <= limit->p1.max; clock.p1++) {
int this_err;
- intel_clock(dev, refclk, &clock);
+ i9xx_clock(refclk, &clock);
+ if (!intel_PLL_is_valid(dev, limit,
+ &clock))
+ continue;
+ if (match_clock &&
+ clock.p != match_clock->p)
+ continue;
+
+ this_err = abs(clock.dot - target);
+ if (this_err < err) {
+ *best_clock = clock;
+ err = this_err;
+ }
+ }
+ }
+ }
+ }
+
+ return (err != target);
+}
+
+static bool
+pnv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
+{
+ struct drm_device *dev = crtc->dev;
+ intel_clock_t clock;
+ int err = target;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ /*
+ * For LVDS just rely on its current settings for dual-channel.
+ * We haven't figured out how to reliably set up different
+ * single/dual channel state, if we even can.
+ */
+ if (intel_is_dual_link_lvds(dev))
+ clock.p2 = limit->p2.p2_fast;
+ else
+ clock.p2 = limit->p2.p2_slow;
+ } else {
+ if (target < limit->p2.dot_limit)
+ clock.p2 = limit->p2.p2_slow;
+ else
+ clock.p2 = limit->p2.p2_fast;
+ }
+
+ memset(best_clock, 0, sizeof(*best_clock));
+
+ for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
+ clock.m1++) {
+ for (clock.m2 = limit->m2.min;
+ clock.m2 <= limit->m2.max; clock.m2++) {
+ for (clock.n = limit->n.min;
+ clock.n <= limit->n.max; clock.n++) {
+ for (clock.p1 = limit->p1.min;
+ clock.p1 <= limit->p1.max; clock.p1++) {
+ int this_err;
+
+ pineview_clock(refclk, &clock);
if (!intel_PLL_is_valid(dev, limit,
&clock))
continue;
@@ -699,9 +604,9 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
}
static bool
-intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock)
+g4x_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
struct drm_device *dev = crtc->dev;
intel_clock_t clock;
@@ -712,12 +617,6 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
found = false;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- int lvds_reg;
-
- if (HAS_PCH_SPLIT(dev))
- lvds_reg = PCH_LVDS;
- else
- lvds_reg = LVDS;
if (intel_is_dual_link_lvds(dev))
clock.p2 = limit->p2.p2_fast;
else
@@ -742,13 +641,10 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
clock.p1 >= limit->p1.min; clock.p1--) {
int this_err;
- intel_clock(dev, refclk, &clock);
+ i9xx_clock(refclk, &clock);
if (!intel_PLL_is_valid(dev, limit,
&clock))
continue;
- if (match_clock &&
- clock.p != match_clock->p)
- continue;
this_err = abs(clock.dot - target);
if (this_err < err_most) {
@@ -765,62 +661,9 @@ intel_g4x_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
}
static bool
-intel_find_pll_ironlake_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock)
-{
- struct drm_device *dev = crtc->dev;
- intel_clock_t clock;
-
- if (target < 200000) {
- clock.n = 1;
- clock.p1 = 2;
- clock.p2 = 10;
- clock.m1 = 12;
- clock.m2 = 9;
- } else {
- clock.n = 2;
- clock.p1 = 1;
- clock.p2 = 10;
- clock.m1 = 14;
- clock.m2 = 8;
- }
- intel_clock(dev, refclk, &clock);
- memcpy(best_clock, &clock, sizeof(intel_clock_t));
- return true;
-}
-
-/* DisplayPort has only two frequencies, 162MHz and 270MHz */
-static bool
-intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock)
-{
- intel_clock_t clock;
- if (target < 200000) {
- clock.p1 = 2;
- clock.p2 = 10;
- clock.n = 2;
- clock.m1 = 23;
- clock.m2 = 8;
- } else {
- clock.p1 = 1;
- clock.p2 = 10;
- clock.n = 1;
- clock.m1 = 14;
- clock.m2 = 2;
- }
- clock.m = 5 * (clock.m1 + 2) + (clock.m2 + 2);
- clock.p = (clock.p1 * clock.p2);
- clock.dot = 96000 * clock.m / (clock.n + 2) / clock.p;
- clock.vco = 0;
- memcpy(best_clock, &clock, sizeof(intel_clock_t));
- return true;
-}
-static bool
-intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
- int target, int refclk, intel_clock_t *match_clock,
- intel_clock_t *best_clock)
+vlv_find_best_dpll(const intel_limit_t *limit, struct drm_crtc *crtc,
+ int target, int refclk, intel_clock_t *match_clock,
+ intel_clock_t *best_clock)
{
u32 p1, p2, m1, m2, vco, bestn, bestm1, bestm2, bestp1, bestp2;
u32 m, n, fastclk;
@@ -1066,14 +909,24 @@ static void assert_pll(struct drm_i915_private *dev_priv,
#define assert_pll_enabled(d, p) assert_pll(d, p, true)
#define assert_pll_disabled(d, p) assert_pll(d, p, false)
+static struct intel_shared_dpll *
+intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ if (crtc->config.shared_dpll < 0)
+ return NULL;
+
+ return &dev_priv->shared_dplls[crtc->config.shared_dpll];
+}
+
/* For ILK+ */
-static void assert_pch_pll(struct drm_i915_private *dev_priv,
- struct intel_pch_pll *pll,
- struct intel_crtc *crtc,
- bool state)
+static void assert_shared_dpll(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ bool state)
{
- u32 val;
bool cur_state;
+ struct intel_dpll_hw_state hw_state;
if (HAS_PCH_LPT(dev_priv->dev)) {
DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n");
@@ -1081,36 +934,16 @@ static void assert_pch_pll(struct drm_i915_private *dev_priv,
}
if (WARN (!pll,
- "asserting PCH PLL %s with no PLL\n", state_string(state)))
+ "asserting DPLL %s with no DPLL\n", state_string(state)))
return;
- val = I915_READ(pll->pll_reg);
- cur_state = !!(val & DPLL_VCO_ENABLE);
+ cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
WARN(cur_state != state,
- "PCH PLL state for reg %x assertion failure (expected %s, current %s), val=%08x\n",
- pll->pll_reg, state_string(state), state_string(cur_state), val);
-
- /* Make sure the selected PLL is correctly attached to the transcoder */
- if (crtc && HAS_PCH_CPT(dev_priv->dev)) {
- u32 pch_dpll;
-
- pch_dpll = I915_READ(PCH_DPLL_SEL);
- cur_state = pll->pll_reg == _PCH_DPLL_B;
- if (!WARN(((pch_dpll >> (4 * crtc->pipe)) & 1) != cur_state,
- "PLL[%d] not attached to this transcoder %d: %08x\n",
- cur_state, crtc->pipe, pch_dpll)) {
- cur_state = !!(val >> (4*crtc->pipe + 3));
- WARN(cur_state != state,
- "PLL[%d] not %s on this transcoder %d: %08x\n",
- pll->pll_reg == _PCH_DPLL_B,
- state_string(state),
- crtc->pipe,
- val);
- }
- }
+ "%s assertion failure (expected %s, current %s)\n",
+ pll->name, state_string(state), state_string(cur_state));
}
-#define assert_pch_pll_enabled(d, p, c) assert_pch_pll(d, p, c, true)
-#define assert_pch_pll_disabled(d, p, c) assert_pch_pll(d, p, c, false)
+#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
+#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
static void assert_fdi_tx(struct drm_i915_private *dev_priv,
enum pipe pipe, bool state)
@@ -1227,8 +1060,8 @@ void assert_pipe(struct drm_i915_private *dev_priv,
if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
state = true;
- if (!intel_using_power_well(dev_priv->dev) &&
- cpu_transcoder != TRANSCODER_EDP) {
+ if (!intel_display_power_enabled(dev_priv->dev,
+ POWER_DOMAIN_TRANSCODER(cpu_transcoder))) {
cur_state = false;
} else {
reg = PIPECONF(cpu_transcoder);
@@ -1262,12 +1095,13 @@ static void assert_plane(struct drm_i915_private *dev_priv,
static void assert_planes_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
+ struct drm_device *dev = dev_priv->dev;
int reg, i;
u32 val;
int cur_pipe;
- /* Planes are fixed to pipes on ILK+ */
- if (HAS_PCH_SPLIT(dev_priv->dev) || IS_VALLEYVIEW(dev_priv->dev)) {
+ /* Primary planes are fixed to pipes on gen4+ */
+ if (INTEL_INFO(dev)->gen >= 4) {
reg = DSPCNTR(pipe);
val = I915_READ(reg);
WARN((val & DISPLAY_PLANE_ENABLE),
@@ -1277,7 +1111,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
}
/* Need to check both planes against the pipe */
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
reg = DSPCNTR(i);
val = I915_READ(reg);
cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
@@ -1291,19 +1125,30 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe)
{
+ struct drm_device *dev = dev_priv->dev;
int reg, i;
u32 val;
- if (!IS_VALLEYVIEW(dev_priv->dev))
- return;
-
- /* Need to check both planes against the pipe */
- for (i = 0; i < dev_priv->num_plane; i++) {
- reg = SPCNTR(pipe, i);
+ if (IS_VALLEYVIEW(dev)) {
+ for (i = 0; i < dev_priv->num_plane; i++) {
+ reg = SPCNTR(pipe, i);
+ val = I915_READ(reg);
+ WARN((val & SP_ENABLE),
+ "sprite %c assertion failure, should be off on pipe %c but is still active\n",
+ sprite_name(pipe, i), pipe_name(pipe));
+ }
+ } else if (INTEL_INFO(dev)->gen >= 7) {
+ reg = SPRCTL(pipe);
val = I915_READ(reg);
- WARN((val & SP_ENABLE),
- "sprite %d assertion failure, should be off on pipe %c but is still active\n",
- pipe * 2 + i, pipe_name(pipe));
+ WARN((val & SPRITE_ENABLE),
+ "sprite %c assertion failure, should be off on pipe %c but is still active\n",
+ plane_name(pipe), pipe_name(pipe));
+ } else if (INTEL_INFO(dev)->gen >= 5) {
+ reg = DVSCNTR(pipe);
+ val = I915_READ(reg);
+ WARN((val & DVS_ENABLE),
+ "sprite %c assertion failure, should be off on pipe %c but is still active\n",
+ plane_name(pipe), pipe_name(pipe));
}
}
@@ -1323,14 +1168,14 @@ static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
}
-static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
+ enum pipe pipe)
{
int reg;
u32 val;
bool enabled;
- reg = TRANSCONF(pipe);
+ reg = PCH_TRANSCONF(pipe);
val = I915_READ(reg);
enabled = !!(val & TRANS_ENABLE);
WARN(enabled,
@@ -1474,6 +1319,8 @@ static void intel_enable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
int reg;
u32 val;
+ assert_pipe_disabled(dev_priv, pipe);
+
/* No really, not for ILK+ */
BUG_ON(!IS_VALLEYVIEW(dev_priv->dev) && dev_priv->info->gen >= 5);
@@ -1525,156 +1372,86 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
POSTING_READ(reg);
}
-/* SBI access */
-static void
-intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
- enum intel_sbi_destination destination)
+void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port)
{
- u32 tmp;
+ u32 port_mask;
- WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
- if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
- 100)) {
- DRM_ERROR("timeout waiting for SBI to become ready\n");
- return;
- }
-
- I915_WRITE(SBI_ADDR, (reg << 16));
- I915_WRITE(SBI_DATA, value);
-
- if (destination == SBI_ICLK)
- tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR;
+ if (!port)
+ port_mask = DPLL_PORTB_READY_MASK;
else
- tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR;
- I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp);
+ port_mask = DPLL_PORTC_READY_MASK;
- if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
- 100)) {
- DRM_ERROR("timeout waiting for SBI to complete write transaction\n");
- return;
- }
-}
-
-static u32
-intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
- enum intel_sbi_destination destination)
-{
- u32 value = 0;
- WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
-
- if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
- 100)) {
- DRM_ERROR("timeout waiting for SBI to become ready\n");
- return 0;
- }
-
- I915_WRITE(SBI_ADDR, (reg << 16));
-
- if (destination == SBI_ICLK)
- value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD;
- else
- value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD;
- I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY);
-
- if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
- 100)) {
- DRM_ERROR("timeout waiting for SBI to complete read transaction\n");
- return 0;
- }
-
- return I915_READ(SBI_DATA);
+ if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000))
+ WARN(1, "timed out waiting for port %c ready: 0x%08x\n",
+ 'B' + port, I915_READ(DPLL(0)));
}
/**
- * ironlake_enable_pch_pll - enable PCH PLL
+ * ironlake_enable_shared_dpll - enable PCH PLL
* @dev_priv: i915 private structure
* @pipe: pipe PLL to enable
*
* The PCH PLL needs to be enabled before the PCH transcoder, since it
* drives the transcoder clock.
*/
-static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc)
+static void ironlake_enable_shared_dpll(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
- struct intel_pch_pll *pll;
- int reg;
- u32 val;
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
/* PCH PLLs only available on ILK, SNB and IVB */
BUG_ON(dev_priv->info->gen < 5);
- pll = intel_crtc->pch_pll;
- if (pll == NULL)
+ if (WARN_ON(pll == NULL))
return;
if (WARN_ON(pll->refcount == 0))
return;
- DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n",
- pll->pll_reg, pll->active, pll->on,
- intel_crtc->base.base.id);
-
- /* PCH refclock must be enabled first */
- assert_pch_refclk_enabled(dev_priv);
+ DRM_DEBUG_KMS("enable %s (active %d, on? %d)for crtc %d\n",
+ pll->name, pll->active, pll->on,
+ crtc->base.base.id);
- if (pll->active++ && pll->on) {
- assert_pch_pll_enabled(dev_priv, pll, NULL);
+ if (pll->active++) {
+ WARN_ON(!pll->on);
+ assert_shared_dpll_enabled(dev_priv, pll);
return;
}
+ WARN_ON(pll->on);
- DRM_DEBUG_KMS("enabling PCH PLL %x\n", pll->pll_reg);
-
- reg = pll->pll_reg;
- val = I915_READ(reg);
- val |= DPLL_VCO_ENABLE;
- I915_WRITE(reg, val);
- POSTING_READ(reg);
- udelay(200);
-
+ DRM_DEBUG_KMS("enabling %s\n", pll->name);
+ pll->enable(dev_priv, pll);
pll->on = true;
}
-static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
+static void intel_disable_shared_dpll(struct intel_crtc *crtc)
{
- struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
- struct intel_pch_pll *pll = intel_crtc->pch_pll;
- int reg;
- u32 val;
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
/* PCH only available on ILK+ */
BUG_ON(dev_priv->info->gen < 5);
- if (pll == NULL)
+ if (WARN_ON(pll == NULL))
return;
if (WARN_ON(pll->refcount == 0))
return;
- DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n",
- pll->pll_reg, pll->active, pll->on,
- intel_crtc->base.base.id);
+ DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n",
+ pll->name, pll->active, pll->on,
+ crtc->base.base.id);
if (WARN_ON(pll->active == 0)) {
- assert_pch_pll_disabled(dev_priv, pll, NULL);
+ assert_shared_dpll_disabled(dev_priv, pll);
return;
}
- if (--pll->active) {
- assert_pch_pll_enabled(dev_priv, pll, NULL);
+ assert_shared_dpll_enabled(dev_priv, pll);
+ WARN_ON(!pll->on);
+ if (--pll->active)
return;
- }
-
- DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg);
-
- /* Make sure transcoder isn't still depending on us */
- assert_transcoder_disabled(dev_priv, intel_crtc->pipe);
-
- reg = pll->pll_reg;
- val = I915_READ(reg);
- val &= ~DPLL_VCO_ENABLE;
- I915_WRITE(reg, val);
- POSTING_READ(reg);
- udelay(200);
+ DRM_DEBUG_KMS("disabling %s\n", pll->name);
+ pll->disable(dev_priv, pll);
pll->on = false;
}
@@ -1683,15 +1460,15 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
{
struct drm_device *dev = dev_priv->dev;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
uint32_t reg, val, pipeconf_val;
/* PCH only available on ILK+ */
BUG_ON(dev_priv->info->gen < 5);
/* Make sure PCH DPLL is enabled */
- assert_pch_pll_enabled(dev_priv,
- to_intel_crtc(crtc)->pch_pll,
- to_intel_crtc(crtc));
+ assert_shared_dpll_enabled(dev_priv,
+ intel_crtc_to_shared_dpll(intel_crtc));
/* FDI must be feeding us bits for PCH ports */
assert_fdi_tx_enabled(dev_priv, pipe);
@@ -1706,7 +1483,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
I915_WRITE(reg, val);
}
- reg = TRANSCONF(pipe);
+ reg = PCH_TRANSCONF(pipe);
val = I915_READ(reg);
pipeconf_val = I915_READ(PIPECONF(pipe));
@@ -1731,7 +1508,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
I915_WRITE(reg, val | TRANS_ENABLE);
if (wait_for(I915_READ(reg) & TRANS_STATE_ENABLE, 100))
- DRM_ERROR("failed to enable transcoder %d\n", pipe);
+ DRM_ERROR("failed to enable transcoder %c\n", pipe_name(pipe));
}
static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
@@ -1760,8 +1537,8 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
else
val |= TRANS_PROGRESSIVE;
- I915_WRITE(TRANSCONF(TRANSCODER_A), val);
- if (wait_for(I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE, 100))
+ I915_WRITE(LPT_TRANSCONF, val);
+ if (wait_for(I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE, 100))
DRM_ERROR("Failed to enable PCH transcoder\n");
}
@@ -1778,13 +1555,13 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
/* Ports must be off as well */
assert_pch_ports_disabled(dev_priv, pipe);
- reg = TRANSCONF(pipe);
+ reg = PCH_TRANSCONF(pipe);
val = I915_READ(reg);
val &= ~TRANS_ENABLE;
I915_WRITE(reg, val);
/* wait for PCH transcoder off, transcoder state */
if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
- DRM_ERROR("failed to disable transcoder %d\n", pipe);
+ DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe));
if (!HAS_PCH_IBX(dev)) {
/* Workaround: Clear the timing override chicken bit again. */
@@ -1799,11 +1576,11 @@ static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
{
u32 val;
- val = I915_READ(_TRANSACONF);
+ val = I915_READ(LPT_TRANSCONF);
val &= ~TRANS_ENABLE;
- I915_WRITE(_TRANSACONF, val);
+ I915_WRITE(LPT_TRANSCONF, val);
/* wait for PCH transcoder off, transcoder state */
- if (wait_for((I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE) == 0, 50))
+ if (wait_for((I915_READ(LPT_TRANSCONF) & TRANS_STATE_ENABLE) == 0, 50))
DRM_ERROR("Failed to disable PCH transcoder\n");
/* Workaround: clear timing override bit. */
@@ -1835,6 +1612,9 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
int reg;
u32 val;
+ assert_planes_disabled(dev_priv, pipe);
+ assert_sprites_disabled(dev_priv, pipe);
+
if (HAS_PCH_LPT(dev_priv->dev))
pch_transcoder = TRANSCODER_A;
else
@@ -2096,7 +1876,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
case 1:
break;
default:
- DRM_ERROR("Can't update plane %d in SAREA\n", plane);
+ DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane));
return -EINVAL;
}
@@ -2145,6 +1925,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
dspcntr &= ~DISPPLANE_TILED;
}
+ if (IS_G4X(dev))
+ dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+
I915_WRITE(reg, dspcntr);
linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
@@ -2193,7 +1976,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
case 2:
break;
default:
- DRM_ERROR("Can't update plane %d in SAREA\n", plane);
+ DRM_ERROR("Can't update plane %c in SAREA\n", plane_name(plane));
return -EINVAL;
}
@@ -2384,9 +2167,9 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
}
if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) {
- DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n",
- intel_crtc->plane,
- INTEL_INFO(dev)->num_pipes);
+ DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n",
+ plane_name(intel_crtc->plane),
+ INTEL_INFO(dev)->num_pipes);
return -EINVAL;
}
@@ -2414,7 +2197,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
crtc->y = y;
if (old_fb) {
- intel_wait_for_vblank(dev, intel_crtc->pipe);
+ if (intel_crtc->active && old_fb != fb)
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
}
@@ -2467,6 +2251,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
FDI_FE_ERRC_ENABLE);
}
+static bool pipe_has_enabled_pch(struct intel_crtc *intel_crtc)
+{
+ return intel_crtc->base.enabled && intel_crtc->config.has_pch_encoder;
+}
+
static void ivb_modeset_global_resources(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2476,10 +2265,13 @@ static void ivb_modeset_global_resources(struct drm_device *dev)
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]);
uint32_t temp;
- /* When everything is off disable fdi C so that we could enable fdi B
- * with all lanes. XXX: This misses the case where a pipe is not using
- * any pch resources and so doesn't need any fdi lanes. */
- if (!pipe_B_crtc->base.enabled && !pipe_C_crtc->base.enabled) {
+ /*
+ * When everything is off disable fdi C so that we could enable fdi B
+ * with all lanes. Note that we don't care about enabled pipes without
+ * an enabled pch encoder.
+ */
+ if (!pipe_has_enabled_pch(pipe_B_crtc) &&
+ !pipe_has_enabled_pch(pipe_C_crtc)) {
WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE);
WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE);
@@ -2517,8 +2309,8 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
/* enable CPU FDI TX and PCH FDI RX */
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
- temp &= ~(7 << 19);
- temp |= (intel_crtc->fdi_lanes - 1) << 19;
+ temp &= ~FDI_DP_PORT_WIDTH_MASK;
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(reg, temp | FDI_TX_ENABLE);
@@ -2615,8 +2407,8 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
/* enable CPU FDI TX and PCH FDI RX */
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
- temp &= ~(7 << 19);
- temp |= (intel_crtc->fdi_lanes - 1) << 19;
+ temp &= ~FDI_DP_PORT_WIDTH_MASK;
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -2750,8 +2542,8 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
/* enable CPU FDI TX and PCH FDI RX */
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
- temp &= ~(7 << 19);
- temp |= (intel_crtc->fdi_lanes - 1) << 19;
+ temp &= ~FDI_DP_PORT_WIDTH_MASK;
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -2852,8 +2644,8 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
/* enable PCH FDI RX PLL, wait warmup plus DMI latency */
reg = FDI_RX_CTL(pipe);
temp = I915_READ(reg);
- temp &= ~((0x7 << 19) | (0x7 << 16));
- temp |= (intel_crtc->fdi_lanes - 1) << 19;
+ temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
@@ -3085,6 +2877,30 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
mutex_unlock(&dev_priv->dpio_lock);
}
+static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
+ enum pipe pch_transcoder)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+
+ I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
+ I915_READ(HTOTAL(cpu_transcoder)));
+ I915_WRITE(PCH_TRANS_HBLANK(pch_transcoder),
+ I915_READ(HBLANK(cpu_transcoder)));
+ I915_WRITE(PCH_TRANS_HSYNC(pch_transcoder),
+ I915_READ(HSYNC(cpu_transcoder)));
+
+ I915_WRITE(PCH_TRANS_VTOTAL(pch_transcoder),
+ I915_READ(VTOTAL(cpu_transcoder)));
+ I915_WRITE(PCH_TRANS_VBLANK(pch_transcoder),
+ I915_READ(VBLANK(cpu_transcoder)));
+ I915_WRITE(PCH_TRANS_VSYNC(pch_transcoder),
+ I915_READ(VSYNC(cpu_transcoder)));
+ I915_WRITE(PCH_TRANS_VSYNCSHIFT(pch_transcoder),
+ I915_READ(VSYNCSHIFT(cpu_transcoder)));
+}
+
/*
* Enable PCH resources required for PCH ports:
* - PCH PLLs
@@ -3101,7 +2917,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
int pipe = intel_crtc->pipe;
u32 reg, temp;
- assert_transcoder_disabled(dev_priv, pipe);
+ assert_pch_transcoder_disabled(dev_priv, pipe);
/* Write the TU size bits before fdi link training, so that error
* detection works. */
@@ -3115,31 +2931,18 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
* transcoder, and we actually should do this to not upset any PCH
* transcoder that already use the clock when we share it.
*
- * Note that enable_pch_pll tries to do the right thing, but get_pch_pll
- * unconditionally resets the pll - we need that to have the right LVDS
- * enable sequence. */
- ironlake_enable_pch_pll(intel_crtc);
+ * Note that enable_shared_dpll tries to do the right thing, but
+ * get_shared_dpll unconditionally resets the pll - we need that to have
+ * the right LVDS enable sequence. */
+ ironlake_enable_shared_dpll(intel_crtc);
if (HAS_PCH_CPT(dev)) {
u32 sel;
temp = I915_READ(PCH_DPLL_SEL);
- switch (pipe) {
- default:
- case 0:
- temp |= TRANSA_DPLL_ENABLE;
- sel = TRANSA_DPLLB_SEL;
- break;
- case 1:
- temp |= TRANSB_DPLL_ENABLE;
- sel = TRANSB_DPLLB_SEL;
- break;
- case 2:
- temp |= TRANSC_DPLL_ENABLE;
- sel = TRANSC_DPLLB_SEL;
- break;
- }
- if (intel_crtc->pch_pll->pll_reg == _PCH_DPLL_B)
+ temp |= TRANS_DPLL_ENABLE(pipe);
+ sel = TRANS_DPLLB_SEL(pipe);
+ if (intel_crtc->config.shared_dpll == DPLL_ID_PCH_PLL_B)
temp |= sel;
else
temp &= ~sel;
@@ -3148,14 +2951,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
/* set transcoder timing, panel must allow it */
assert_panel_unlocked(dev_priv, pipe);
- I915_WRITE(TRANS_HTOTAL(pipe), I915_READ(HTOTAL(pipe)));
- I915_WRITE(TRANS_HBLANK(pipe), I915_READ(HBLANK(pipe)));
- I915_WRITE(TRANS_HSYNC(pipe), I915_READ(HSYNC(pipe)));
-
- I915_WRITE(TRANS_VTOTAL(pipe), I915_READ(VTOTAL(pipe)));
- I915_WRITE(TRANS_VBLANK(pipe), I915_READ(VBLANK(pipe)));
- I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
- I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe)));
+ ironlake_pch_transcoder_set_timings(intel_crtc, pipe);
intel_fdi_normal_train(crtc);
@@ -3205,86 +3001,82 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
- assert_transcoder_disabled(dev_priv, TRANSCODER_A);
+ assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A);
lpt_program_iclkip(crtc);
/* Set transcoder timing. */
- I915_WRITE(_TRANS_HTOTAL_A, I915_READ(HTOTAL(cpu_transcoder)));
- I915_WRITE(_TRANS_HBLANK_A, I915_READ(HBLANK(cpu_transcoder)));
- I915_WRITE(_TRANS_HSYNC_A, I915_READ(HSYNC(cpu_transcoder)));
-
- I915_WRITE(_TRANS_VTOTAL_A, I915_READ(VTOTAL(cpu_transcoder)));
- I915_WRITE(_TRANS_VBLANK_A, I915_READ(VBLANK(cpu_transcoder)));
- I915_WRITE(_TRANS_VSYNC_A, I915_READ(VSYNC(cpu_transcoder)));
- I915_WRITE(_TRANS_VSYNCSHIFT_A, I915_READ(VSYNCSHIFT(cpu_transcoder)));
+ ironlake_pch_transcoder_set_timings(intel_crtc, PIPE_A);
lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
}
-static void intel_put_pch_pll(struct intel_crtc *intel_crtc)
+static void intel_put_shared_dpll(struct intel_crtc *crtc)
{
- struct intel_pch_pll *pll = intel_crtc->pch_pll;
+ struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
if (pll == NULL)
return;
if (pll->refcount == 0) {
- WARN(1, "bad PCH PLL refcount\n");
+ WARN(1, "bad %s refcount\n", pll->name);
return;
}
- --pll->refcount;
- intel_crtc->pch_pll = NULL;
+ if (--pll->refcount == 0) {
+ WARN_ON(pll->on);
+ WARN_ON(pll->active);
+ }
+
+ crtc->config.shared_dpll = DPLL_ID_PRIVATE;
}
-static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp)
+static struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, u32 dpll, u32 fp)
{
- struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
- struct intel_pch_pll *pll;
- int i;
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
+ enum intel_dpll_id i;
- pll = intel_crtc->pch_pll;
if (pll) {
- DRM_DEBUG_KMS("CRTC:%d reusing existing PCH PLL %x\n",
- intel_crtc->base.base.id, pll->pll_reg);
- goto prepare;
+ DRM_DEBUG_KMS("CRTC:%d dropping existing %s\n",
+ crtc->base.base.id, pll->name);
+ intel_put_shared_dpll(crtc);
}
if (HAS_PCH_IBX(dev_priv->dev)) {
/* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
- i = intel_crtc->pipe;
- pll = &dev_priv->pch_plls[i];
+ i = crtc->pipe;
+ pll = &dev_priv->shared_dplls[i];
- DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n",
- intel_crtc->base.base.id, pll->pll_reg);
+ DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n",
+ crtc->base.base.id, pll->name);
goto found;
}
- for (i = 0; i < dev_priv->num_pch_pll; i++) {
- pll = &dev_priv->pch_plls[i];
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ pll = &dev_priv->shared_dplls[i];
/* Only want to check enabled timings first */
if (pll->refcount == 0)
continue;
- if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) &&
- fp == I915_READ(pll->fp0_reg)) {
- DRM_DEBUG_KMS("CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d)\n",
- intel_crtc->base.base.id,
- pll->pll_reg, pll->refcount, pll->active);
+ if (dpll == (I915_READ(PCH_DPLL(pll->id)) & 0x7fffffff) &&
+ fp == I915_READ(PCH_FP0(pll->id))) {
+ DRM_DEBUG_KMS("CRTC:%d sharing existing %s (refcount %d, ative %d)\n",
+ crtc->base.base.id,
+ pll->name, pll->refcount, pll->active);
goto found;
}
}
/* Ok no matching timings, maybe there's a free one? */
- for (i = 0; i < dev_priv->num_pch_pll; i++) {
- pll = &dev_priv->pch_plls[i];
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ pll = &dev_priv->shared_dplls[i];
if (pll->refcount == 0) {
- DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n",
- intel_crtc->base.base.id, pll->pll_reg);
+ DRM_DEBUG_KMS("CRTC:%d allocated %s\n",
+ crtc->base.base.id, pll->name);
goto found;
}
}
@@ -3292,24 +3084,32 @@ static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u3
return NULL;
found:
- intel_crtc->pch_pll = pll;
- pll->refcount++;
- DRM_DEBUG_DRIVER("using pll %d for pipe %d\n", i, intel_crtc->pipe);
-prepare: /* separate function? */
- DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg);
+ crtc->config.shared_dpll = i;
+ DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
+ pipe_name(crtc->pipe));
- /* Wait for the clocks to stabilize before rewriting the regs */
- I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
- POSTING_READ(pll->pll_reg);
- udelay(150);
+ if (pll->active == 0) {
+ memcpy(&pll->hw_state, &crtc->config.dpll_hw_state,
+ sizeof(pll->hw_state));
+
+ DRM_DEBUG_DRIVER("setting up %s\n", pll->name);
+ WARN_ON(pll->on);
+ assert_shared_dpll_disabled(dev_priv, pll);
+
+ /* Wait for the clocks to stabilize before rewriting the regs */
+ I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE);
+ POSTING_READ(PCH_DPLL(pll->id));
+ udelay(150);
+
+ I915_WRITE(PCH_FP0(pll->id), fp);
+ I915_WRITE(PCH_DPLL(pll->id), dpll & ~DPLL_VCO_ENABLE);
+ }
+ pll->refcount++;
- I915_WRITE(pll->fp0_reg, fp);
- I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
- pll->on = false;
return pll;
}
-void intel_cpt_verify_modeset(struct drm_device *dev, int pipe)
+static void cpt_verify_modeset(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int dslreg = PIPEDSL(pipe);
@@ -3319,10 +3119,53 @@ void intel_cpt_verify_modeset(struct drm_device *dev, int pipe)
udelay(500);
if (wait_for(I915_READ(dslreg) != temp, 5)) {
if (wait_for(I915_READ(dslreg) != temp, 5))
- DRM_ERROR("mode set failed: pipe %d stuck\n", pipe);
+ DRM_ERROR("mode set failed: pipe %c stuck\n", pipe_name(pipe));
+ }
+}
+
+static void ironlake_pfit_enable(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+
+ if (crtc->config.pch_pfit.size) {
+ /* Force use of hard-coded filter coefficients
+ * as some pre-programmed values are broken,
+ * e.g. x201.
+ */
+ if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
+ I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 |
+ PF_PIPE_SEL_IVB(pipe));
+ else
+ I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
+ I915_WRITE(PF_WIN_POS(pipe), crtc->config.pch_pfit.pos);
+ I915_WRITE(PF_WIN_SZ(pipe), crtc->config.pch_pfit.size);
}
}
+static void intel_enable_planes(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ struct intel_plane *intel_plane;
+
+ list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+ if (intel_plane->pipe == pipe)
+ intel_plane_restore(&intel_plane->base);
+}
+
+static void intel_disable_planes(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ struct intel_plane *intel_plane;
+
+ list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+ if (intel_plane->pipe == pipe)
+ intel_plane_disable(&intel_plane->base);
+}
+
static void ironlake_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -3339,6 +3182,10 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
return;
intel_crtc->active = true;
+
+ intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+ intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
+
intel_update_watermarks(dev);
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
@@ -3362,22 +3209,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
if (encoder->pre_enable)
encoder->pre_enable(encoder);
- /* Enable panel fitting for LVDS */
- if (dev_priv->pch_pf_size &&
- (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
- intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
- /* Force use of hard-coded filter coefficients
- * as some pre-programmed values are broken,
- * e.g. x201.
- */
- if (IS_IVYBRIDGE(dev))
- I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 |
- PF_PIPE_SEL_IVB(pipe));
- else
- I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
- I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos);
- I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
- }
+ ironlake_pfit_enable(intel_crtc);
/*
* On ILK+ LUT must be loaded before the pipe is running but with
@@ -3388,6 +3220,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_enable_pipe(dev_priv, pipe,
intel_crtc->config.has_pch_encoder);
intel_enable_plane(dev_priv, plane, pipe);
+ intel_enable_planes(crtc);
+ intel_crtc_update_cursor(crtc, true);
if (intel_crtc->config.has_pch_encoder)
ironlake_pch_enable(crtc);
@@ -3396,13 +3230,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_update_fbc(dev);
mutex_unlock(&dev->struct_mutex);
- intel_crtc_update_cursor(crtc, true);
-
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
if (HAS_PCH_CPT(dev))
- intel_cpt_verify_modeset(dev, intel_crtc->pipe);
+ cpt_verify_modeset(dev, intel_crtc->pipe);
/*
* There seems to be a race in PCH platform hw (at least on some
@@ -3415,6 +3247,42 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_wait_for_vblank(dev, intel_crtc->pipe);
}
+/* IPS only exists on ULT machines and is tied to pipe A. */
+static bool hsw_crtc_supports_ips(struct intel_crtc *crtc)
+{
+ return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A;
+}
+
+static void hsw_enable_ips(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
+ if (!crtc->config.ips_enabled)
+ return;
+
+ /* We can only enable IPS after we enable a plane and wait for a vblank.
+ * We guarantee that the plane is enabled by calling intel_enable_ips
+ * only after intel_enable_plane. And intel_enable_plane already waits
+ * for a vblank, so all we need to do here is to enable the IPS bit. */
+ assert_plane_enabled(dev_priv, crtc->plane);
+ I915_WRITE(IPS_CTL, IPS_ENABLE);
+}
+
+static void hsw_disable_ips(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!crtc->config.ips_enabled)
+ return;
+
+ assert_plane_enabled(dev_priv, crtc->plane);
+ I915_WRITE(IPS_CTL, 0);
+
+ /* We need to wait for a vblank before we can disable the plane. */
+ intel_wait_for_vblank(dev, crtc->pipe);
+}
+
static void haswell_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -3430,6 +3298,11 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
return;
intel_crtc->active = true;
+
+ intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+ if (intel_crtc->config.has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
+
intel_update_watermarks(dev);
if (intel_crtc->config.has_pch_encoder)
@@ -3441,18 +3314,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_ddi_enable_pipe_clock(intel_crtc);
- /* Enable panel fitting for eDP */
- if (dev_priv->pch_pf_size &&
- intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
- /* Force use of hard-coded filter coefficients
- * as some pre-programmed values are broken,
- * e.g. x201.
- */
- I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 |
- PF_PIPE_SEL_IVB(pipe));
- I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos);
- I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
- }
+ ironlake_pfit_enable(intel_crtc);
/*
* On ILK+ LUT must be loaded before the pipe is running but with
@@ -3466,6 +3328,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_enable_pipe(dev_priv, pipe,
intel_crtc->config.has_pch_encoder);
intel_enable_plane(dev_priv, plane, pipe);
+ intel_enable_planes(crtc);
+ intel_crtc_update_cursor(crtc, true);
+
+ hsw_enable_ips(intel_crtc);
if (intel_crtc->config.has_pch_encoder)
lpt_pch_enable(crtc);
@@ -3474,8 +3340,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_update_fbc(dev);
mutex_unlock(&dev->struct_mutex);
- intel_crtc_update_cursor(crtc, true);
-
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
@@ -3490,6 +3354,21 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_wait_for_vblank(dev, intel_crtc->pipe);
}
+static void ironlake_pfit_disable(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+
+ /* To avoid upsetting the power well on haswell only disable the pfit if
+ * it's in use. The hw state code will make sure we get this right. */
+ if (crtc->config.pch_pfit.size) {
+ I915_WRITE(PF_CTL(pipe), 0);
+ I915_WRITE(PF_WIN_POS(pipe), 0);
+ I915_WRITE(PF_WIN_SZ(pipe), 0);
+ }
+}
+
static void ironlake_crtc_disable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -3509,58 +3388,51 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
intel_crtc_wait_for_pending_flips(crtc);
drm_vblank_off(dev, pipe);
- intel_crtc_update_cursor(crtc, false);
-
- intel_disable_plane(dev_priv, plane, pipe);
if (dev_priv->cfb_plane == plane)
intel_disable_fbc(dev);
+ intel_crtc_update_cursor(crtc, false);
+ intel_disable_planes(crtc);
+ intel_disable_plane(dev_priv, plane, pipe);
+
+ if (intel_crtc->config.has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
+
intel_disable_pipe(dev_priv, pipe);
- /* Disable PF */
- I915_WRITE(PF_CTL(pipe), 0);
- I915_WRITE(PF_WIN_SZ(pipe), 0);
+ ironlake_pfit_disable(intel_crtc);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->post_disable)
encoder->post_disable(encoder);
- ironlake_fdi_disable(crtc);
+ if (intel_crtc->config.has_pch_encoder) {
+ ironlake_fdi_disable(crtc);
- ironlake_disable_pch_transcoder(dev_priv, pipe);
+ ironlake_disable_pch_transcoder(dev_priv, pipe);
+ intel_set_pch_fifo_underrun_reporting(dev, pipe, true);
- if (HAS_PCH_CPT(dev)) {
- /* disable TRANS_DP_CTL */
- reg = TRANS_DP_CTL(pipe);
- temp = I915_READ(reg);
- temp &= ~(TRANS_DP_OUTPUT_ENABLE | TRANS_DP_PORT_SEL_MASK);
- temp |= TRANS_DP_PORT_SEL_NONE;
- I915_WRITE(reg, temp);
-
- /* disable DPLL_SEL */
- temp = I915_READ(PCH_DPLL_SEL);
- switch (pipe) {
- case 0:
- temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
- break;
- case 1:
- temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
- break;
- case 2:
- /* C shares PLL A or B */
- temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL);
- break;
- default:
- BUG(); /* wtf */
+ if (HAS_PCH_CPT(dev)) {
+ /* disable TRANS_DP_CTL */
+ reg = TRANS_DP_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~(TRANS_DP_OUTPUT_ENABLE |
+ TRANS_DP_PORT_SEL_MASK);
+ temp |= TRANS_DP_PORT_SEL_NONE;
+ I915_WRITE(reg, temp);
+
+ /* disable DPLL_SEL */
+ temp = I915_READ(PCH_DPLL_SEL);
+ temp &= ~(TRANS_DPLL_ENABLE(pipe) | TRANS_DPLLB_SEL(pipe));
+ I915_WRITE(PCH_DPLL_SEL, temp);
}
- I915_WRITE(PCH_DPLL_SEL, temp);
- }
- /* disable PCH DPLL */
- intel_disable_pch_pll(intel_crtc);
+ /* disable PCH DPLL */
+ intel_disable_shared_dpll(intel_crtc);
- ironlake_fdi_pll_disable(intel_crtc);
+ ironlake_fdi_pll_disable(intel_crtc);
+ }
intel_crtc->active = false;
intel_update_watermarks(dev);
@@ -3588,24 +3460,24 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
intel_crtc_wait_for_pending_flips(crtc);
drm_vblank_off(dev, pipe);
- intel_crtc_update_cursor(crtc, false);
-
- intel_disable_plane(dev_priv, plane, pipe);
+ /* FBC must be disabled before disabling the plane on HSW. */
if (dev_priv->cfb_plane == plane)
intel_disable_fbc(dev);
+ hsw_disable_ips(intel_crtc);
+
+ intel_crtc_update_cursor(crtc, false);
+ intel_disable_planes(crtc);
+ intel_disable_plane(dev_priv, plane, pipe);
+
+ if (intel_crtc->config.has_pch_encoder)
+ intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, false);
intel_disable_pipe(dev_priv, pipe);
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
- /* XXX: Once we have proper panel fitter state tracking implemented with
- * hardware state read/check support we should switch to only disable
- * the panel fitter when we know it's used. */
- if (intel_using_power_well(dev)) {
- I915_WRITE(PF_CTL(pipe), 0);
- I915_WRITE(PF_WIN_SZ(pipe), 0);
- }
+ ironlake_pfit_disable(intel_crtc);
intel_ddi_disable_pipe_clock(intel_crtc);
@@ -3615,6 +3487,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
if (intel_crtc->config.has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
+ intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true);
intel_ddi_fdi_disable(crtc);
}
@@ -3629,17 +3502,11 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
static void ironlake_crtc_off(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- intel_put_pch_pll(intel_crtc);
+ intel_put_shared_dpll(intel_crtc);
}
static void haswell_crtc_off(struct drm_crtc *crtc)
{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-
- /* Stop saying we're using TRANSCODER_EDP because some other CRTC might
- * start using it. */
- intel_crtc->config.cpu_transcoder = (enum transcoder) intel_crtc->pipe;
-
intel_ddi_put_crtc_pll(crtc);
}
@@ -3685,6 +3552,77 @@ g4x_fixup_plane(struct drm_i915_private *dev_priv, enum pipe pipe)
}
}
+static void i9xx_pfit_enable(struct intel_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc_config *pipe_config = &crtc->config;
+
+ if (!crtc->config.gmch_pfit.control)
+ return;
+
+ /*
+ * The panel fitter should only be adjusted whilst the pipe is disabled,
+ * according to register description and PRM.
+ */
+ WARN_ON(I915_READ(PFIT_CONTROL) & PFIT_ENABLE);
+ assert_pipe_disabled(dev_priv, crtc->pipe);
+
+ I915_WRITE(PFIT_PGM_RATIOS, pipe_config->gmch_pfit.pgm_ratios);
+ I915_WRITE(PFIT_CONTROL, pipe_config->gmch_pfit.control);
+
+ /* Border color in case we don't scale up to the full screen. Black by
+ * default, change to something else for debugging. */
+ I915_WRITE(BCLRPAT(crtc->pipe), 0);
+}
+
+static void valleyview_crtc_enable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_encoder *encoder;
+ int pipe = intel_crtc->pipe;
+ int plane = intel_crtc->plane;
+
+ WARN_ON(!crtc->enabled);
+
+ if (intel_crtc->active)
+ return;
+
+ intel_crtc->active = true;
+ intel_update_watermarks(dev);
+
+ mutex_lock(&dev_priv->dpio_lock);
+
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ if (encoder->pre_pll_enable)
+ encoder->pre_pll_enable(encoder);
+
+ intel_enable_pll(dev_priv, pipe);
+
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ if (encoder->pre_enable)
+ encoder->pre_enable(encoder);
+
+ /* VLV wants encoder enabling _before_ the pipe is up. */
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ encoder->enable(encoder);
+
+ i9xx_pfit_enable(intel_crtc);
+
+ intel_crtc_load_lut(crtc);
+
+ intel_enable_pipe(dev_priv, pipe, false);
+ intel_enable_plane(dev_priv, plane, pipe);
+ intel_enable_planes(crtc);
+ intel_crtc_update_cursor(crtc, true);
+
+ intel_update_fbc(dev);
+
+ mutex_unlock(&dev_priv->dpio_lock);
+}
+
static void i9xx_crtc_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -3708,17 +3646,22 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
if (encoder->pre_enable)
encoder->pre_enable(encoder);
+ i9xx_pfit_enable(intel_crtc);
+
+ intel_crtc_load_lut(crtc);
+
intel_enable_pipe(dev_priv, pipe, false);
intel_enable_plane(dev_priv, plane, pipe);
+ intel_enable_planes(crtc);
+ /* The fixup needs to happen before cursor is enabled */
if (IS_G4X(dev))
g4x_fixup_plane(dev_priv, pipe);
-
- intel_crtc_load_lut(crtc);
- intel_update_fbc(dev);
+ intel_crtc_update_cursor(crtc, true);
/* Give the overlay scaler a chance to enable if it's on this pipe */
intel_crtc_dpms_overlay(intel_crtc, true);
- intel_crtc_update_cursor(crtc, true);
+
+ intel_update_fbc(dev);
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
@@ -3728,20 +3671,15 @@ static void i9xx_pfit_disable(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- enum pipe pipe;
- uint32_t pctl = I915_READ(PFIT_CONTROL);
- assert_pipe_disabled(dev_priv, crtc->pipe);
+ if (!crtc->config.gmch_pfit.control)
+ return;
- if (INTEL_INFO(dev)->gen >= 4)
- pipe = (pctl & PFIT_PIPE_MASK) >> PFIT_PIPE_SHIFT;
- else
- pipe = PIPE_B;
+ assert_pipe_disabled(dev_priv, crtc->pipe);
- if (pipe == crtc->pipe) {
- DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n", pctl);
- I915_WRITE(PFIT_CONTROL, 0);
- }
+ DRM_DEBUG_DRIVER("disabling pfit, current: 0x%08x\n",
+ I915_READ(PFIT_CONTROL));
+ I915_WRITE(PFIT_CONTROL, 0);
}
static void i9xx_crtc_disable(struct drm_crtc *crtc)
@@ -3762,17 +3700,23 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
/* Give the overlay scaler a chance to disable if it's on this pipe */
intel_crtc_wait_for_pending_flips(crtc);
drm_vblank_off(dev, pipe);
- intel_crtc_dpms_overlay(intel_crtc, false);
- intel_crtc_update_cursor(crtc, false);
if (dev_priv->cfb_plane == plane)
intel_disable_fbc(dev);
+ intel_crtc_dpms_overlay(intel_crtc, false);
+ intel_crtc_update_cursor(crtc, false);
+ intel_disable_planes(crtc);
intel_disable_plane(dev_priv, plane, pipe);
+
intel_disable_pipe(dev_priv, pipe);
i9xx_pfit_disable(intel_crtc);
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ if (encoder->post_disable)
+ encoder->post_disable(encoder);
+
intel_disable_pll(dev_priv, pipe);
intel_crtc->active = false;
@@ -3845,8 +3789,8 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
/* crtc should still be enabled when we disable it. */
WARN_ON(!crtc->enabled);
- intel_crtc->eld_vld = false;
dev_priv->display.crtc_disable(crtc);
+ intel_crtc->eld_vld = false;
intel_crtc_update_sarea(crtc, false);
dev_priv->display.off(crtc);
@@ -3977,17 +3921,131 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
return encoder->get_hw_state(encoder, &pipe);
}
-static bool intel_crtc_compute_config(struct drm_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
+ struct intel_crtc_config *pipe_config)
{
- struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *pipe_B_crtc =
+ to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]);
+
+ DRM_DEBUG_KMS("checking fdi config on pipe %c, lanes %i\n",
+ pipe_name(pipe), pipe_config->fdi_lanes);
+ if (pipe_config->fdi_lanes > 4) {
+ DRM_DEBUG_KMS("invalid fdi lane config on pipe %c: %i lanes\n",
+ pipe_name(pipe), pipe_config->fdi_lanes);
+ return false;
+ }
+
+ if (IS_HASWELL(dev)) {
+ if (pipe_config->fdi_lanes > 2) {
+ DRM_DEBUG_KMS("only 2 lanes on haswell, required: %i lanes\n",
+ pipe_config->fdi_lanes);
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ if (INTEL_INFO(dev)->num_pipes == 2)
+ return true;
+
+ /* Ivybridge 3 pipe is really complicated */
+ switch (pipe) {
+ case PIPE_A:
+ return true;
+ case PIPE_B:
+ if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled &&
+ pipe_config->fdi_lanes > 2) {
+ DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
+ pipe_name(pipe), pipe_config->fdi_lanes);
+ return false;
+ }
+ return true;
+ case PIPE_C:
+ if (!pipe_has_enabled_pch(pipe_B_crtc) ||
+ pipe_B_crtc->config.fdi_lanes <= 2) {
+ if (pipe_config->fdi_lanes > 2) {
+ DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
+ pipe_name(pipe), pipe_config->fdi_lanes);
+ return false;
+ }
+ } else {
+ DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n");
+ return false;
+ }
+ return true;
+ default:
+ BUG();
+ }
+}
+
+#define RETRY 1
+static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = intel_crtc->base.dev;
+ struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ int lane, link_bw, fdi_dotclock;
+ bool setup_ok, needs_recompute = false;
+
+retry:
+ /* FDI is a binary signal running at ~2.7GHz, encoding
+ * each output octet as 10 bits. The actual frequency
+ * is stored as a divider into a 100MHz clock, and the
+ * mode pixel clock is stored in units of 1KHz.
+ * Hence the bw of each lane in terms of the mode signal
+ * is:
+ */
+ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+
+ fdi_dotclock = adjusted_mode->clock;
+ fdi_dotclock /= pipe_config->pixel_multiplier;
+
+ lane = ironlake_get_lanes_required(fdi_dotclock, link_bw,
+ pipe_config->pipe_bpp);
+
+ pipe_config->fdi_lanes = lane;
+
+ intel_link_compute_m_n(pipe_config->pipe_bpp, lane, fdi_dotclock,
+ link_bw, &pipe_config->fdi_m_n);
+
+ setup_ok = ironlake_check_fdi_lanes(intel_crtc->base.dev,
+ intel_crtc->pipe, pipe_config);
+ if (!setup_ok && pipe_config->pipe_bpp > 6*3) {
+ pipe_config->pipe_bpp -= 2*3;
+ DRM_DEBUG_KMS("fdi link bw constraint, reducing pipe bpp to %i\n",
+ pipe_config->pipe_bpp);
+ needs_recompute = true;
+ pipe_config->bw_constrained = true;
+
+ goto retry;
+ }
+
+ if (needs_recompute)
+ return RETRY;
+
+ return setup_ok ? 0 : -EINVAL;
+}
+
+static void hsw_compute_ips_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ pipe_config->ips_enabled = i915_enable_ips &&
+ hsw_crtc_supports_ips(crtc) &&
+ pipe_config->pipe_bpp == 24;
+}
+
+static int intel_crtc_compute_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
if (HAS_PCH_SPLIT(dev)) {
/* FDI link clock is fixed at 2.7G */
if (pipe_config->requested_mode.clock * 3
> IRONLAKE_FDI_FREQ * 4)
- return false;
+ return -EINVAL;
}
/* All interlaced capable intel hw wants timings in frames. Note though
@@ -3996,12 +4054,12 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc,
if (!pipe_config->timings_set)
drm_mode_set_crtcinfo(adjusted_mode, 0);
- /* WaPruneModeWithIncorrectHsyncOffset: Cantiga+ cannot handle modes
- * with a hsync front porch of 0.
+ /* Cantiga+ cannot handle modes with a hsync front porch of 0.
+ * WaPruneModeWithIncorrectHsyncOffset:ctg,elk,ilk,snb,ivb,vlv,hsw.
*/
if ((INTEL_INFO(dev)->gen > 4 || IS_G4X(dev)) &&
adjusted_mode->hsync_start == adjusted_mode->hdisplay)
- return false;
+ return -EINVAL;
if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && pipe_config->pipe_bpp > 10*3) {
pipe_config->pipe_bpp = 10*3; /* 12bpc is gen5+ */
@@ -4011,7 +4069,18 @@ static bool intel_crtc_compute_config(struct drm_crtc *crtc,
pipe_config->pipe_bpp = 8*3;
}
- return true;
+ if (HAS_IPS(dev))
+ hsw_compute_ips_config(crtc, pipe_config);
+
+ /* XXX: PCH clock sharing is done in ->mode_set, so make sure the old
+ * clock survives for now. */
+ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+ pipe_config->shared_dpll = crtc->config.shared_dpll;
+
+ if (pipe_config->has_pch_encoder)
+ return ironlake_fdi_compute_config(crtc, pipe_config);
+
+ return 0;
}
static int valleyview_get_display_clock_speed(struct drm_device *dev)
@@ -4120,7 +4189,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
{
if (i915_panel_use_ssc >= 0)
return i915_panel_use_ssc != 0;
- return dev_priv->lvds_use_ssc
+ return dev_priv->vbt.lvds_use_ssc
&& !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
}
@@ -4156,7 +4225,7 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
refclk = vlv_get_refclk(crtc);
} else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
- refclk = dev_priv->lvds_ssc_freq * 1000;
+ refclk = dev_priv->vbt.lvds_ssc_freq * 1000;
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
refclk / 1000);
} else if (!IS_GEN2(dev)) {
@@ -4168,28 +4237,14 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
return refclk;
}
-static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc *crtc)
+static uint32_t pnv_dpll_compute_fp(struct dpll *dpll)
{
- unsigned dotclock = crtc->config.adjusted_mode.clock;
- struct dpll *clock = &crtc->config.dpll;
-
- /* SDVO TV has fixed PLL values depend on its clock range,
- this mirrors vbios setting. */
- if (dotclock >= 100000 && dotclock < 140500) {
- clock->p1 = 2;
- clock->p2 = 10;
- clock->n = 3;
- clock->m1 = 16;
- clock->m2 = 8;
- } else if (dotclock >= 140500 && dotclock <= 200000) {
- clock->p1 = 1;
- clock->p2 = 10;
- clock->n = 6;
- clock->m1 = 12;
- clock->m2 = 8;
- }
+ return (1 << dpll->n) << 16 | dpll->m2;
+}
- crtc->config.clock_set = true;
+static uint32_t i9xx_dpll_compute_fp(struct dpll *dpll)
+{
+ return dpll->n << 16 | dpll->m1 << 8 | dpll->m2;
}
static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
@@ -4199,18 +4254,15 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = crtc->pipe;
u32 fp, fp2 = 0;
- struct dpll *clock = &crtc->config.dpll;
if (IS_PINEVIEW(dev)) {
- fp = (1 << clock->n) << 16 | clock->m1 << 8 | clock->m2;
+ fp = pnv_dpll_compute_fp(&crtc->config.dpll);
if (reduced_clock)
- fp2 = (1 << reduced_clock->n) << 16 |
- reduced_clock->m1 << 8 | reduced_clock->m2;
+ fp2 = pnv_dpll_compute_fp(reduced_clock);
} else {
- fp = clock->n << 16 | clock->m1 << 8 | clock->m2;
+ fp = i9xx_dpll_compute_fp(&crtc->config.dpll);
if (reduced_clock)
- fp2 = reduced_clock->n << 16 | reduced_clock->m1 << 8 |
- reduced_clock->m2;
+ fp2 = i9xx_dpll_compute_fp(reduced_clock);
}
I915_WRITE(FP0(pipe), fp);
@@ -4225,6 +4277,68 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
}
}
+static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv)
+{
+ u32 reg_val;
+
+ /*
+ * PLLB opamp always calibrates to max value of 0x3f, force enable it
+ * and set it to a reasonable value instead.
+ */
+ reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1));
+ reg_val &= 0xffffff00;
+ reg_val |= 0x00000030;
+ vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
+
+ reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION);
+ reg_val &= 0x8cffffff;
+ reg_val = 0x8c000000;
+ vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
+
+ reg_val = vlv_dpio_read(dev_priv, DPIO_IREF(1));
+ reg_val &= 0xffffff00;
+ vlv_dpio_write(dev_priv, DPIO_IREF(1), reg_val);
+
+ reg_val = vlv_dpio_read(dev_priv, DPIO_CALIBRATION);
+ reg_val &= 0x00ffffff;
+ reg_val |= 0xb0000000;
+ vlv_dpio_write(dev_priv, DPIO_CALIBRATION, reg_val);
+}
+
+static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
+ struct intel_link_m_n *m_n)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+
+ I915_WRITE(PCH_TRANS_DATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+ I915_WRITE(PCH_TRANS_DATA_N1(pipe), m_n->gmch_n);
+ I915_WRITE(PCH_TRANS_LINK_M1(pipe), m_n->link_m);
+ I915_WRITE(PCH_TRANS_LINK_N1(pipe), m_n->link_n);
+}
+
+static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
+ struct intel_link_m_n *m_n)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe = crtc->pipe;
+ enum transcoder transcoder = crtc->config.cpu_transcoder;
+
+ if (INTEL_INFO(dev)->gen >= 5) {
+ I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
+ I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
+ I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
+ I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
+ } else {
+ I915_WRITE(PIPE_DATA_M_G4X(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
+ I915_WRITE(PIPE_DATA_N_G4X(pipe), m_n->gmch_n);
+ I915_WRITE(PIPE_LINK_M_G4X(pipe), m_n->link_m);
+ I915_WRITE(PIPE_LINK_N_G4X(pipe), m_n->link_n);
+ }
+}
+
static void intel_dp_set_m_n(struct intel_crtc *crtc)
{
if (crtc->config.has_pch_encoder)
@@ -4237,24 +4351,16 @@ static void vlv_update_pll(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_encoder *encoder;
int pipe = crtc->pipe;
- u32 dpll, mdiv, pdiv;
+ u32 dpll, mdiv;
u32 bestn, bestm1, bestm2, bestp1, bestp2;
- bool is_sdvo;
- u32 temp;
+ bool is_hdmi;
+ u32 coreclk, reg_val, dpll_md;
mutex_lock(&dev_priv->dpio_lock);
- is_sdvo = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_SDVO) ||
- intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
-
- dpll = DPLL_VGA_MODE_DIS;
- dpll |= DPLL_EXT_BUFFER_ENABLE_VLV;
- dpll |= DPLL_REFA_CLK_ENABLE_VLV;
- dpll |= DPLL_INTEGRATED_CLOCK_VLV;
-
- I915_WRITE(DPLL(pipe), dpll);
- POSTING_READ(DPLL(pipe));
+ is_hdmi = intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI);
bestn = crtc->config.dpll.n;
bestm1 = crtc->config.dpll.m1;
@@ -4262,72 +4368,104 @@ static void vlv_update_pll(struct intel_crtc *crtc)
bestp1 = crtc->config.dpll.p1;
bestp2 = crtc->config.dpll.p2;
- /*
- * In Valleyview PLL and program lane counter registers are exposed
- * through DPIO interface
- */
+ /* See eDP HDMI DPIO driver vbios notes doc */
+
+ /* PLL B needs special handling */
+ if (pipe)
+ vlv_pllb_recal_opamp(dev_priv);
+
+ /* Set up Tx target for periodic Rcomp update */
+ vlv_dpio_write(dev_priv, DPIO_IREF_BCAST, 0x0100000f);
+
+ /* Disable target IRef on PLL */
+ reg_val = vlv_dpio_read(dev_priv, DPIO_IREF_CTL(pipe));
+ reg_val &= 0x00ffffff;
+ vlv_dpio_write(dev_priv, DPIO_IREF_CTL(pipe), reg_val);
+
+ /* Disable fast lock */
+ vlv_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x610);
+
+ /* Set idtafcrecal before PLL is enabled */
mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
mdiv |= ((bestp1 << DPIO_P1_SHIFT) | (bestp2 << DPIO_P2_SHIFT));
mdiv |= ((bestn << DPIO_N_SHIFT));
- mdiv |= (1 << DPIO_POST_DIV_SHIFT);
mdiv |= (1 << DPIO_K_SHIFT);
+
+ /*
+ * Post divider depends on pixel clock rate, DAC vs digital (and LVDS,
+ * but we don't support that).
+ * Note: don't use the DAC post divider as it seems unstable.
+ */
+ mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT);
+ vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
+
mdiv |= DPIO_ENABLE_CALIBRATION;
- intel_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
+ vlv_dpio_write(dev_priv, DPIO_DIV(pipe), mdiv);
+
+ /* Set HBR and RBR LPF coefficients */
+ if (crtc->config.port_clock == 162000 ||
+ intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
+ intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
+ vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
+ 0x005f0021);
+ else
+ vlv_dpio_write(dev_priv, DPIO_LPF_COEFF(pipe),
+ 0x00d0000f);
+
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
+ intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) {
+ /* Use SSC source */
+ if (!pipe)
+ vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+ 0x0df40000);
+ else
+ vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+ 0x0df70000);
+ } else { /* HDMI or VGA */
+ /* Use bend source */
+ if (!pipe)
+ vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+ 0x0df70000);
+ else
+ vlv_dpio_write(dev_priv, DPIO_REFSFR(pipe),
+ 0x0df40000);
+ }
- intel_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), 0x01000000);
+ coreclk = vlv_dpio_read(dev_priv, DPIO_CORE_CLK(pipe));
+ coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
+ if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) ||
+ intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP))
+ coreclk |= 0x01000000;
+ vlv_dpio_write(dev_priv, DPIO_CORE_CLK(pipe), coreclk);
- pdiv = (1 << DPIO_REFSEL_OVERRIDE) | (5 << DPIO_PLL_MODESEL_SHIFT) |
- (3 << DPIO_BIAS_CURRENT_CTL_SHIFT) | (1<<20) |
- (7 << DPIO_PLL_REFCLK_SEL_SHIFT) | (8 << DPIO_DRIVER_CTL_SHIFT) |
- (5 << DPIO_CLK_BIAS_CTL_SHIFT);
- intel_dpio_write(dev_priv, DPIO_REFSFR(pipe), pdiv);
+ vlv_dpio_write(dev_priv, DPIO_PLL_CML(pipe), 0x87871000);
- intel_dpio_write(dev_priv, DPIO_LFP_COEFF(pipe), 0x005f003b);
+ for_each_encoder_on_crtc(dev, &crtc->base, encoder)
+ if (encoder->pre_pll_enable)
+ encoder->pre_pll_enable(encoder);
+
+ /* Enable DPIO clock input */
+ dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
+ DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV;
+ if (pipe)
+ dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
dpll |= DPLL_VCO_ENABLE;
I915_WRITE(DPLL(pipe), dpll);
POSTING_READ(DPLL(pipe));
+ udelay(150);
+
if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
DRM_ERROR("DPLL %d failed to lock\n", pipe);
- intel_dpio_write(dev_priv, DPIO_FASTCLK_DISABLE, 0x620);
+ dpll_md = (crtc->config.pixel_multiplier - 1)
+ << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ I915_WRITE(DPLL_MD(pipe), dpll_md);
+ POSTING_READ(DPLL_MD(pipe));
if (crtc->config.has_dp_encoder)
intel_dp_set_m_n(crtc);
- I915_WRITE(DPLL(pipe), dpll);
-
- /* Wait for the clocks to stabilize. */
- POSTING_READ(DPLL(pipe));
- udelay(150);
-
- temp = 0;
- if (is_sdvo) {
- temp = 0;
- if (crtc->config.pixel_multiplier > 1) {
- temp = (crtc->config.pixel_multiplier - 1)
- << DPLL_MD_UDI_MULTIPLIER_SHIFT;
- }
- }
- I915_WRITE(DPLL_MD(pipe), temp);
- POSTING_READ(DPLL_MD(pipe));
-
- /* Now program lane control registers */
- if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)
- || intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI)) {
- temp = 0x1000C4;
- if(pipe == 1)
- temp |= (1 << 21);
- intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL1, temp);
- }
-
- if(intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP)) {
- temp = 0x1000C4;
- if(pipe == 1)
- temp |= (1 << 21);
- intel_dpio_write(dev_priv, DPIO_DATA_CHANNEL2, temp);
- }
-
mutex_unlock(&dev_priv->dpio_lock);
}
@@ -4355,14 +4493,14 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
else
dpll |= DPLLB_MODE_DAC_SERIAL;
- if (is_sdvo) {
- if ((crtc->config.pixel_multiplier > 1) &&
- (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))) {
- dpll |= (crtc->config.pixel_multiplier - 1)
- << SDVO_MULTIPLIER_SHIFT_HIRES;
- }
- dpll |= DPLL_DVO_HIGH_SPEED;
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
+ dpll |= (crtc->config.pixel_multiplier - 1)
+ << SDVO_MULTIPLIER_SHIFT_HIRES;
}
+
+ if (is_sdvo)
+ dpll |= DPLL_DVO_HIGH_SPEED;
+
if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT))
dpll |= DPLL_DVO_HIGH_SPEED;
@@ -4391,12 +4529,8 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
if (INTEL_INFO(dev)->gen >= 4)
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
- if (is_sdvo && intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT))
+ if (crtc->config.sdvo_tv_clock)
dpll |= PLL_REF_INPUT_TVCLKINBC;
- else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_TVOUT))
- /* XXX: just matching BIOS for now */
- /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
- dpll |= 3;
else if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
@@ -4422,15 +4556,9 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
udelay(150);
if (INTEL_INFO(dev)->gen >= 4) {
- u32 temp = 0;
- if (is_sdvo) {
- temp = 0;
- if (crtc->config.pixel_multiplier > 1) {
- temp = (crtc->config.pixel_multiplier - 1)
- << DPLL_MD_UDI_MULTIPLIER_SHIFT;
- }
- }
- I915_WRITE(DPLL_MD(pipe), temp);
+ u32 dpll_md = (crtc->config.pixel_multiplier - 1)
+ << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ I915_WRITE(DPLL_MD(pipe), dpll_md);
} else {
/* The pixel multiplier can only be updated once the
* DPLL is enabled and the clocks are stable.
@@ -4442,7 +4570,6 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
}
static void i8xx_update_pll(struct intel_crtc *crtc,
- struct drm_display_mode *adjusted_mode,
intel_clock_t *reduced_clock,
int num_connectors)
{
@@ -4497,20 +4624,26 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
I915_WRITE(DPLL(pipe), dpll);
}
-static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = intel_crtc->pipe;
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
- uint32_t vsyncshift;
+ struct drm_display_mode *adjusted_mode =
+ &intel_crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
+ uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end;
+
+ /* We need to be careful not to changed the adjusted mode, for otherwise
+ * the hw state checker will get angry at the mismatch. */
+ crtc_vtotal = adjusted_mode->crtc_vtotal;
+ crtc_vblank_end = adjusted_mode->crtc_vblank_end;
if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
/* the chip adds 2 halflines automatically */
- adjusted_mode->crtc_vtotal -= 1;
- adjusted_mode->crtc_vblank_end -= 1;
+ crtc_vtotal -= 1;
+ crtc_vblank_end -= 1;
vsyncshift = adjusted_mode->crtc_hsync_start
- adjusted_mode->crtc_htotal / 2;
} else {
@@ -4532,10 +4665,10 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
I915_WRITE(VTOTAL(cpu_transcoder),
(adjusted_mode->crtc_vdisplay - 1) |
- ((adjusted_mode->crtc_vtotal - 1) << 16));
+ ((crtc_vtotal - 1) << 16));
I915_WRITE(VBLANK(cpu_transcoder),
(adjusted_mode->crtc_vblank_start - 1) |
- ((adjusted_mode->crtc_vblank_end - 1) << 16));
+ ((crtc_vblank_end - 1) << 16));
I915_WRITE(VSYNC(cpu_transcoder),
(adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
@@ -4555,13 +4688,52 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc,
((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
}
+static void intel_get_pipe_timings(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
+ uint32_t tmp;
+
+ tmp = I915_READ(HTOTAL(cpu_transcoder));
+ pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
+ pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
+ tmp = I915_READ(HBLANK(cpu_transcoder));
+ pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
+ pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
+ tmp = I915_READ(HSYNC(cpu_transcoder));
+ pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
+ pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
+
+ tmp = I915_READ(VTOTAL(cpu_transcoder));
+ pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
+ pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
+ tmp = I915_READ(VBLANK(cpu_transcoder));
+ pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
+ pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
+ tmp = I915_READ(VSYNC(cpu_transcoder));
+ pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
+ pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
+
+ if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) {
+ pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+ pipe_config->adjusted_mode.crtc_vtotal += 1;
+ pipe_config->adjusted_mode.crtc_vblank_end += 1;
+ }
+
+ tmp = I915_READ(PIPESRC(crtc->pipe));
+ pipe_config->requested_mode.vdisplay = (tmp & 0xffff) + 1;
+ pipe_config->requested_mode.hdisplay = ((tmp >> 16) & 0xffff) + 1;
+}
+
static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t pipeconf;
- pipeconf = I915_READ(PIPECONF(intel_crtc->pipe));
+ pipeconf = 0;
if (intel_crtc->pipe == 0 && INTEL_INFO(dev)->gen < 4) {
/* Enable pixel doubling when the dot clock is > 90% of the (display)
@@ -4573,26 +4745,28 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
if (intel_crtc->config.requested_mode.clock >
dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
pipeconf |= PIPECONF_DOUBLE_WIDE;
- else
- pipeconf &= ~PIPECONF_DOUBLE_WIDE;
}
- /* default to 8bpc */
- pipeconf &= ~(PIPECONF_BPC_MASK | PIPECONF_DITHER_EN);
- if (intel_crtc->config.has_dp_encoder) {
- if (intel_crtc->config.dither) {
- pipeconf |= PIPECONF_6BPC |
- PIPECONF_DITHER_EN |
+ /* only g4x and later have fancy bpc/dither controls */
+ if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
+ /* Bspec claims that we can't use dithering for 30bpp pipes. */
+ if (intel_crtc->config.dither && intel_crtc->config.pipe_bpp != 30)
+ pipeconf |= PIPECONF_DITHER_EN |
PIPECONF_DITHER_TYPE_SP;
- }
- }
- if (IS_VALLEYVIEW(dev) && intel_pipe_has_type(&intel_crtc->base,
- INTEL_OUTPUT_EDP)) {
- if (intel_crtc->config.dither) {
- pipeconf |= PIPECONF_6BPC |
- PIPECONF_ENABLE |
- I965_PIPECONF_ACTIVE;
+ switch (intel_crtc->config.pipe_bpp) {
+ case 18:
+ pipeconf |= PIPECONF_6BPC;
+ break;
+ case 24:
+ pipeconf |= PIPECONF_8BPC;
+ break;
+ case 30:
+ pipeconf |= PIPECONF_10BPC;
+ break;
+ default:
+ /* Case prevented by intel_choose_pipe_bpp_dither. */
+ BUG();
}
}
@@ -4602,23 +4776,17 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
} else {
DRM_DEBUG_KMS("disabling CxSR downclocking\n");
- pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
}
}
- pipeconf &= ~PIPECONF_INTERLACE_MASK;
if (!IS_GEN2(dev) &&
intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
else
pipeconf |= PIPECONF_PROGRESSIVE;
- if (IS_VALLEYVIEW(dev)) {
- if (intel_crtc->config.limited_color_range)
- pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
- else
- pipeconf &= ~PIPECONF_COLOR_RANGE_SELECT;
- }
+ if (IS_VALLEYVIEW(dev) && intel_crtc->config.limited_color_range)
+ pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
POSTING_READ(PIPECONF(intel_crtc->pipe));
@@ -4631,16 +4799,14 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
u32 dspcntr;
- bool ok, has_reduced_clock = false, is_sdvo = false;
- bool is_lvds = false, is_tv = false;
+ bool ok, has_reduced_clock = false;
+ bool is_lvds = false;
struct intel_encoder *encoder;
const intel_limit_t *limit;
int ret;
@@ -4650,15 +4816,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
- case INTEL_OUTPUT_SDVO:
- case INTEL_OUTPUT_HDMI:
- is_sdvo = true;
- if (encoder->needs_tv_clock)
- is_tv = true;
- break;
- case INTEL_OUTPUT_TVOUT:
- is_tv = true;
- break;
}
num_connectors++;
@@ -4672,9 +4829,10 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc, refclk);
- ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
- &clock);
- if (!ok) {
+ ok = dev_priv->display.find_dpll(limit, crtc,
+ intel_crtc->config.port_clock,
+ refclk, NULL, &clock);
+ if (!ok && !intel_crtc->config.clock_set) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
}
@@ -4689,10 +4847,10 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
* by using the FP0/FP1. In such case we will disable the LVDS
* downclock feature.
*/
- has_reduced_clock = limit->find_pll(limit, crtc,
+ has_reduced_clock =
+ dev_priv->display.find_dpll(limit, crtc,
dev_priv->lvds_downclock,
- refclk,
- &clock,
+ refclk, &clock,
&reduced_clock);
}
/* Compat-code for transition, will disappear. */
@@ -4704,11 +4862,8 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
intel_crtc->config.dpll.p2 = clock.p2;
}
- if (is_sdvo && is_tv)
- i9xx_adjust_sdvo_tv_clock(intel_crtc);
-
if (IS_GEN2(dev))
- i8xx_update_pll(intel_crtc, adjusted_mode,
+ i8xx_update_pll(intel_crtc,
has_reduced_clock ? &reduced_clock : NULL,
num_connectors);
else if (IS_VALLEYVIEW(dev))
@@ -4716,7 +4871,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
else
i9xx_update_pll(intel_crtc,
has_reduced_clock ? &reduced_clock : NULL,
- num_connectors);
+ num_connectors);
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -4728,10 +4883,7 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
dspcntr |= DISPPLANE_SEL_PIPE_B;
}
- DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
- drm_mode_debug_printmodeline(mode);
-
- intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
+ intel_set_pipe_timings(intel_crtc);
/* pipesrc and dspsize control the size that is scaled from,
* which should always be the user's requested size.
@@ -4743,10 +4895,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
i9xx_set_pipeconf(intel_crtc);
- intel_enable_pipe(dev_priv, pipe, false);
-
- intel_wait_for_vblank(dev, pipe);
-
I915_WRITE(DSPCNTR(plane), dspcntr);
POSTING_READ(DSPCNTR(plane));
@@ -4757,6 +4905,36 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
return ret;
}
+static void i9xx_get_pfit_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ tmp = I915_READ(PFIT_CONTROL);
+
+ if (INTEL_INFO(dev)->gen < 4) {
+ if (crtc->pipe != PIPE_B)
+ return;
+
+ /* gen2/3 store dither state in pfit control, needs to match */
+ pipe_config->gmch_pfit.control = tmp & PANEL_8TO6_DITHER_ENABLE;
+ } else {
+ if ((tmp & PFIT_PIPE_MASK) != (crtc->pipe << PFIT_PIPE_SHIFT))
+ return;
+ }
+
+ if (!(tmp & PFIT_ENABLE))
+ return;
+
+ pipe_config->gmch_pfit.control = I915_READ(PFIT_CONTROL);
+ pipe_config->gmch_pfit.pgm_ratios = I915_READ(PFIT_PGM_RATIOS);
+ if (INTEL_INFO(dev)->gen < 5)
+ pipe_config->gmch_pfit.lvds_border_bits =
+ I915_READ(LVDS) & LVDS_BORDER_ENABLE;
+}
+
static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
struct intel_crtc_config *pipe_config)
{
@@ -4764,10 +4942,34 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
+ pipe_config->cpu_transcoder = crtc->pipe;
+ pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+
tmp = I915_READ(PIPECONF(crtc->pipe));
if (!(tmp & PIPECONF_ENABLE))
return false;
+ intel_get_pipe_timings(crtc, pipe_config);
+
+ i9xx_get_pfit_config(crtc, pipe_config);
+
+ if (INTEL_INFO(dev)->gen >= 4) {
+ tmp = I915_READ(DPLL_MD(crtc->pipe));
+ pipe_config->pixel_multiplier =
+ ((tmp & DPLL_MD_UDI_MULTIPLIER_MASK)
+ >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1;
+ } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
+ tmp = I915_READ(DPLL(crtc->pipe));
+ pipe_config->pixel_multiplier =
+ ((tmp & SDVO_MULTIPLIER_MASK)
+ >> SDVO_MULTIPLIER_SHIFT_HIRES) + 1;
+ } else {
+ /* Note that on i915G/GM the pixel multiplier is in the sdvo
+ * port and will be fixed up in the encoder->get_config
+ * function. */
+ pipe_config->pixel_multiplier = 1;
+ }
+
return true;
}
@@ -4779,7 +4981,6 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
u32 val, final;
bool has_lvds = false;
bool has_cpu_edp = false;
- bool has_pch_edp = false;
bool has_panel = false;
bool has_ck505 = false;
bool can_ssc = false;
@@ -4794,25 +4995,22 @@ static void ironlake_init_pch_refclk(struct drm_device *dev)
break;
case INTEL_OUTPUT_EDP:
has_panel = true;
- if (intel_encoder_is_pch_edp(&encoder->base))
- has_pch_edp = true;
- else
+ if (enc_to_dig_port(&encoder->base)->port == PORT_A)
has_cpu_edp = true;
break;
}
}
if (HAS_PCH_IBX(dev)) {
- has_ck505 = dev_priv->display_clock_mode;
+ has_ck505 = dev_priv->vbt.display_clock_mode;
can_ssc = has_ck505;
} else {
has_ck505 = false;
can_ssc = true;
}
- DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d has_ck505 %d\n",
- has_panel, has_lvds, has_pch_edp, has_cpu_edp,
- has_ck505);
+ DRM_DEBUG_KMS("has_panel %d has_lvds %d has_ck505 %d\n",
+ has_panel, has_lvds, has_ck505);
/* Ironlake: try to setup display ref clock before DPLL
* enabling. This is only under driver's control after
@@ -5102,7 +5300,6 @@ static int ironlake_get_refclk(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
- struct intel_encoder *edp_encoder = NULL;
int num_connectors = 0;
bool is_lvds = false;
@@ -5111,34 +5308,28 @@ static int ironlake_get_refclk(struct drm_crtc *crtc)
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
- case INTEL_OUTPUT_EDP:
- edp_encoder = encoder;
- break;
}
num_connectors++;
}
if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
- dev_priv->lvds_ssc_freq);
- return dev_priv->lvds_ssc_freq * 1000;
+ dev_priv->vbt.lvds_ssc_freq);
+ return dev_priv->vbt.lvds_ssc_freq * 1000;
}
return 120000;
}
-static void ironlake_set_pipeconf(struct drm_crtc *crtc,
- struct drm_display_mode *adjusted_mode,
- bool dither)
+static void ironlake_set_pipeconf(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
uint32_t val;
- val = I915_READ(PIPECONF(pipe));
+ val = 0;
- val &= ~PIPECONF_BPC_MASK;
switch (intel_crtc->config.pipe_bpp) {
case 18:
val |= PIPECONF_6BPC;
@@ -5157,20 +5348,16 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc,
BUG();
}
- val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK);
- if (dither)
+ if (intel_crtc->config.dither)
val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
- val &= ~PIPECONF_INTERLACE_MASK;
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+ if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
val |= PIPECONF_INTERLACED_ILK;
else
val |= PIPECONF_PROGRESSIVE;
if (intel_crtc->config.limited_color_range)
val |= PIPECONF_COLOR_RANGE_SELECT;
- else
- val &= ~PIPECONF_COLOR_RANGE_SELECT;
I915_WRITE(PIPECONF(pipe), val);
POSTING_READ(PIPECONF(pipe));
@@ -5240,33 +5427,31 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc)
}
}
-static void haswell_set_pipeconf(struct drm_crtc *crtc,
- struct drm_display_mode *adjusted_mode,
- bool dither)
+static void haswell_set_pipeconf(struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
uint32_t val;
- val = I915_READ(PIPECONF(cpu_transcoder));
+ val = 0;
- val &= ~(PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_MASK);
- if (dither)
+ if (intel_crtc->config.dither)
val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
- val &= ~PIPECONF_INTERLACE_MASK_HSW;
- if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+ if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
val |= PIPECONF_INTERLACED_ILK;
else
val |= PIPECONF_PROGRESSIVE;
I915_WRITE(PIPECONF(cpu_transcoder), val);
POSTING_READ(PIPECONF(cpu_transcoder));
+
+ I915_WRITE(GAMMA_MODE(intel_crtc->pipe), GAMMA_MODE_MODE_8BIT);
+ POSTING_READ(GAMMA_MODE(intel_crtc->pipe));
}
static bool ironlake_compute_clocks(struct drm_crtc *crtc,
- struct drm_display_mode *adjusted_mode,
intel_clock_t *clock,
bool *has_reduced_clock,
intel_clock_t *reduced_clock)
@@ -5276,22 +5461,13 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
struct intel_encoder *intel_encoder;
int refclk;
const intel_limit_t *limit;
- bool ret, is_sdvo = false, is_tv = false, is_lvds = false;
+ bool ret, is_lvds = false;
for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
switch (intel_encoder->type) {
case INTEL_OUTPUT_LVDS:
is_lvds = true;
break;
- case INTEL_OUTPUT_SDVO:
- case INTEL_OUTPUT_HDMI:
- is_sdvo = true;
- if (intel_encoder->needs_tv_clock)
- is_tv = true;
- break;
- case INTEL_OUTPUT_TVOUT:
- is_tv = true;
- break;
}
}
@@ -5303,8 +5479,9 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
* reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
*/
limit = intel_limit(crtc, refclk);
- ret = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, NULL,
- clock);
+ ret = dev_priv->display.find_dpll(limit, crtc,
+ to_intel_crtc(crtc)->config.port_clock,
+ refclk, NULL, clock);
if (!ret)
return false;
@@ -5315,16 +5492,13 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
* by using the FP0/FP1. In such case we will disable the LVDS
* downclock feature.
*/
- *has_reduced_clock = limit->find_pll(limit, crtc,
- dev_priv->lvds_downclock,
- refclk,
- clock,
- reduced_clock);
+ *has_reduced_clock =
+ dev_priv->display.find_dpll(limit, crtc,
+ dev_priv->lvds_downclock,
+ refclk, clock,
+ reduced_clock);
}
- if (is_sdvo && is_tv)
- i9xx_adjust_sdvo_tv_clock(to_intel_crtc(crtc));
-
return true;
}
@@ -5346,65 +5520,25 @@ static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev)
POSTING_READ(SOUTH_CHICKEN1);
}
-static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc)
+static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *pipe_B_crtc =
- to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]);
-
- DRM_DEBUG_KMS("checking fdi config on pipe %i, lanes %i\n",
- intel_crtc->pipe, intel_crtc->fdi_lanes);
- if (intel_crtc->fdi_lanes > 4) {
- DRM_DEBUG_KMS("invalid fdi lane config on pipe %i: %i lanes\n",
- intel_crtc->pipe, intel_crtc->fdi_lanes);
- /* Clamp lanes to avoid programming the hw with bogus values. */
- intel_crtc->fdi_lanes = 4;
-
- return false;
- }
-
- if (INTEL_INFO(dev)->num_pipes == 2)
- return true;
switch (intel_crtc->pipe) {
case PIPE_A:
- return true;
+ break;
case PIPE_B:
- if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled &&
- intel_crtc->fdi_lanes > 2) {
- DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n",
- intel_crtc->pipe, intel_crtc->fdi_lanes);
- /* Clamp lanes to avoid programming the hw with bogus values. */
- intel_crtc->fdi_lanes = 2;
-
- return false;
- }
-
- if (intel_crtc->fdi_lanes > 2)
+ if (intel_crtc->config.fdi_lanes > 2)
WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT);
else
cpt_enable_fdi_bc_bifurcation(dev);
- return true;
+ break;
case PIPE_C:
- if (!pipe_B_crtc->base.enabled || pipe_B_crtc->fdi_lanes <= 2) {
- if (intel_crtc->fdi_lanes > 2) {
- DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n",
- intel_crtc->pipe, intel_crtc->fdi_lanes);
- /* Clamp lanes to avoid programming the hw with bogus values. */
- intel_crtc->fdi_lanes = 2;
-
- return false;
- }
- } else {
- DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n");
- return false;
- }
-
cpt_enable_fdi_bc_bifurcation(dev);
- return true;
+ break;
default:
BUG();
}
@@ -5421,78 +5555,13 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
return bps / (link_bw * 8) + 1;
}
-void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
- struct intel_link_m_n *m_n)
+static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor)
{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe = crtc->pipe;
-
- I915_WRITE(TRANSDATA_M1(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
- I915_WRITE(TRANSDATA_N1(pipe), m_n->gmch_n);
- I915_WRITE(TRANSDPLINK_M1(pipe), m_n->link_m);
- I915_WRITE(TRANSDPLINK_N1(pipe), m_n->link_n);
-}
-
-void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
- struct intel_link_m_n *m_n)
-{
- struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe = crtc->pipe;
- enum transcoder transcoder = crtc->config.cpu_transcoder;
-
- if (INTEL_INFO(dev)->gen >= 5) {
- I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
- I915_WRITE(PIPE_DATA_N1(transcoder), m_n->gmch_n);
- I915_WRITE(PIPE_LINK_M1(transcoder), m_n->link_m);
- I915_WRITE(PIPE_LINK_N1(transcoder), m_n->link_n);
- } else {
- I915_WRITE(PIPE_GMCH_DATA_M(pipe), TU_SIZE(m_n->tu) | m_n->gmch_m);
- I915_WRITE(PIPE_GMCH_DATA_N(pipe), m_n->gmch_n);
- I915_WRITE(PIPE_DP_LINK_M(pipe), m_n->link_m);
- I915_WRITE(PIPE_DP_LINK_N(pipe), m_n->link_n);
- }
-}
-
-static void ironlake_fdi_set_m_n(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
- struct intel_link_m_n m_n = {0};
- int target_clock, lane, link_bw;
-
- /* FDI is a binary signal running at ~2.7GHz, encoding
- * each output octet as 10 bits. The actual frequency
- * is stored as a divider into a 100MHz clock, and the
- * mode pixel clock is stored in units of 1KHz.
- * Hence the bw of each lane in terms of the mode signal
- * is:
- */
- link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
-
- if (intel_crtc->config.pixel_target_clock)
- target_clock = intel_crtc->config.pixel_target_clock;
- else
- target_clock = adjusted_mode->clock;
-
- lane = ironlake_get_lanes_required(target_clock, link_bw,
- intel_crtc->config.pipe_bpp);
-
- intel_crtc->fdi_lanes = lane;
-
- if (intel_crtc->config.pixel_multiplier > 1)
- link_bw *= intel_crtc->config.pixel_multiplier;
- intel_link_compute_m_n(intel_crtc->config.pipe_bpp, lane, target_clock,
- link_bw, &m_n);
-
- intel_cpu_transcoder_set_m_n(intel_crtc, &m_n);
+ return i9xx_dpll_compute_m(dpll) < factor * dpll->n;
}
static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
- intel_clock_t *clock, u32 *fp,
+ u32 *fp,
intel_clock_t *reduced_clock, u32 *fp2)
{
struct drm_crtc *crtc = &intel_crtc->base;
@@ -5501,7 +5570,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
struct intel_encoder *intel_encoder;
uint32_t dpll;
int factor, num_connectors = 0;
- bool is_lvds = false, is_sdvo = false, is_tv = false;
+ bool is_lvds = false, is_sdvo = false;
for_each_encoder_on_crtc(dev, crtc, intel_encoder) {
switch (intel_encoder->type) {
@@ -5511,11 +5580,6 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
case INTEL_OUTPUT_SDVO:
case INTEL_OUTPUT_HDMI:
is_sdvo = true;
- if (intel_encoder->needs_tv_clock)
- is_tv = true;
- break;
- case INTEL_OUTPUT_TVOUT:
- is_tv = true;
break;
}
@@ -5526,13 +5590,13 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
factor = 21;
if (is_lvds) {
if ((intel_panel_use_ssc(dev_priv) &&
- dev_priv->lvds_ssc_freq == 100) ||
+ dev_priv->vbt.lvds_ssc_freq == 100) ||
(HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev)))
factor = 25;
- } else if (is_sdvo && is_tv)
+ } else if (intel_crtc->config.sdvo_tv_clock)
factor = 20;
- if (clock->m < factor * clock->n)
+ if (ironlake_needs_fb_cb_tune(&intel_crtc->config.dpll, factor))
*fp |= FP_CB_TUNE;
if (fp2 && (reduced_clock->m < factor * reduced_clock->n))
@@ -5544,23 +5608,21 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
dpll |= DPLLB_MODE_LVDS;
else
dpll |= DPLLB_MODE_DAC_SERIAL;
- if (is_sdvo) {
- if (intel_crtc->config.pixel_multiplier > 1) {
- dpll |= (intel_crtc->config.pixel_multiplier - 1)
- << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
- }
+
+ dpll |= (intel_crtc->config.pixel_multiplier - 1)
+ << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+
+ if (is_sdvo)
dpll |= DPLL_DVO_HIGH_SPEED;
- }
- if (intel_crtc->config.has_dp_encoder &&
- intel_crtc->config.has_pch_encoder)
+ if (intel_crtc->config.has_dp_encoder)
dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
- dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+ dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
/* also FPA1 */
- dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+ dpll |= (1 << (intel_crtc->config.dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
- switch (clock->p2) {
+ switch (intel_crtc->config.dpll.p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
break;
@@ -5575,18 +5637,12 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
break;
}
- if (is_sdvo && is_tv)
- dpll |= PLL_REF_INPUT_TVCLKINBC;
- else if (is_tv)
- /* XXX: just matching BIOS for now */
- /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
- dpll |= 3;
- else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+ if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
else
dpll |= PLL_REF_INPUT_DREFCLK;
- return dpll;
+ return dpll | DPLL_VCO_ENABLE;
}
static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
@@ -5596,19 +5652,16 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
- struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
int num_connectors = 0;
intel_clock_t clock, reduced_clock;
- u32 dpll, fp = 0, fp2 = 0;
+ u32 dpll = 0, fp = 0, fp2 = 0;
bool ok, has_reduced_clock = false;
bool is_lvds = false;
struct intel_encoder *encoder;
+ struct intel_shared_dpll *pll;
int ret;
- bool dither, fdi_config_ok;
for_each_encoder_on_crtc(dev, crtc, encoder) {
switch (encoder->type) {
@@ -5623,11 +5676,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
"Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
- intel_crtc->config.cpu_transcoder = pipe;
-
- ok = ironlake_compute_clocks(crtc, adjusted_mode, &clock,
+ ok = ironlake_compute_clocks(crtc, &clock,
&has_reduced_clock, &reduced_clock);
- if (!ok) {
+ if (!ok && !intel_crtc->config.clock_set) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
}
@@ -5643,34 +5694,31 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
/* Ensure that the cursor is valid for the new mode before changing... */
intel_crtc_update_cursor(crtc, true);
- /* determine panel color depth */
- dither = intel_crtc->config.dither;
- if (is_lvds && dev_priv->lvds_dither)
- dither = true;
-
- fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
- if (has_reduced_clock)
- fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
- reduced_clock.m2;
-
- dpll = ironlake_compute_dpll(intel_crtc, &clock, &fp, &reduced_clock,
- has_reduced_clock ? &fp2 : NULL);
-
- DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
- drm_mode_debug_printmodeline(mode);
-
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
if (intel_crtc->config.has_pch_encoder) {
- struct intel_pch_pll *pll;
+ fp = i9xx_dpll_compute_fp(&intel_crtc->config.dpll);
+ if (has_reduced_clock)
+ fp2 = i9xx_dpll_compute_fp(&reduced_clock);
+
+ dpll = ironlake_compute_dpll(intel_crtc,
+ &fp, &reduced_clock,
+ has_reduced_clock ? &fp2 : NULL);
+
+ intel_crtc->config.dpll_hw_state.dpll = dpll;
+ intel_crtc->config.dpll_hw_state.fp0 = fp;
+ if (has_reduced_clock)
+ intel_crtc->config.dpll_hw_state.fp1 = fp2;
+ else
+ intel_crtc->config.dpll_hw_state.fp1 = fp;
- pll = intel_get_pch_pll(intel_crtc, dpll, fp);
+ pll = intel_get_shared_dpll(intel_crtc, dpll, fp);
if (pll == NULL) {
- DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n",
- pipe);
+ DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+ pipe_name(pipe));
return -EINVAL;
}
} else
- intel_put_pch_pll(intel_crtc);
+ intel_put_shared_dpll(intel_crtc);
if (intel_crtc->config.has_dp_encoder)
intel_dp_set_m_n(intel_crtc);
@@ -5679,11 +5727,18 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
if (encoder->pre_pll_enable)
encoder->pre_pll_enable(encoder);
- if (intel_crtc->pch_pll) {
- I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
+ if (is_lvds && has_reduced_clock && i915_powersave)
+ intel_crtc->lowfreq_avail = true;
+ else
+ intel_crtc->lowfreq_avail = false;
+
+ if (intel_crtc->config.has_pch_encoder) {
+ pll = intel_crtc_to_shared_dpll(intel_crtc);
+
+ I915_WRITE(PCH_DPLL(pll->id), dpll);
/* Wait for the clocks to stabilize. */
- POSTING_READ(intel_crtc->pch_pll->pll_reg);
+ POSTING_READ(PCH_DPLL(pll->id));
udelay(150);
/* The pixel multiplier can only be updated once the
@@ -5691,32 +5746,25 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
*
* So write it again.
*/
- I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
- }
+ I915_WRITE(PCH_DPLL(pll->id), dpll);
- intel_crtc->lowfreq_avail = false;
- if (intel_crtc->pch_pll) {
- if (is_lvds && has_reduced_clock && i915_powersave) {
- I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2);
- intel_crtc->lowfreq_avail = true;
- } else {
- I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp);
- }
+ if (has_reduced_clock)
+ I915_WRITE(PCH_FP1(pll->id), fp2);
+ else
+ I915_WRITE(PCH_FP1(pll->id), fp);
}
- intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
+ intel_set_pipe_timings(intel_crtc);
- /* Note, this also computes intel_crtc->fdi_lanes which is used below in
- * ironlake_check_fdi_lanes. */
- intel_crtc->fdi_lanes = 0;
- if (intel_crtc->config.has_pch_encoder)
- ironlake_fdi_set_m_n(crtc);
-
- fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc);
+ if (intel_crtc->config.has_pch_encoder) {
+ intel_cpu_transcoder_set_m_n(intel_crtc,
+ &intel_crtc->config.fdi_m_n);
+ }
- ironlake_set_pipeconf(crtc, adjusted_mode, dither);
+ if (IS_IVYBRIDGE(dev))
+ ivybridge_update_fdi_bc_bifurcation(intel_crtc);
- intel_wait_for_vblank(dev, pipe);
+ ironlake_set_pipeconf(crtc);
/* Set up the display plane register */
I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
@@ -5726,9 +5774,46 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_update_watermarks(dev);
- intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
+ return ret;
+}
- return fdi_config_ok ? ret : -EINVAL;
+static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum transcoder transcoder = pipe_config->cpu_transcoder;
+
+ pipe_config->fdi_m_n.link_m = I915_READ(PIPE_LINK_M1(transcoder));
+ pipe_config->fdi_m_n.link_n = I915_READ(PIPE_LINK_N1(transcoder));
+ pipe_config->fdi_m_n.gmch_m = I915_READ(PIPE_DATA_M1(transcoder))
+ & ~TU_SIZE_MASK;
+ pipe_config->fdi_m_n.gmch_n = I915_READ(PIPE_DATA_N1(transcoder));
+ pipe_config->fdi_m_n.tu = ((I915_READ(PIPE_DATA_M1(transcoder))
+ & TU_SIZE_MASK) >> TU_SIZE_SHIFT) + 1;
+}
+
+static void ironlake_get_pfit_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
+ tmp = I915_READ(PF_CTL(crtc->pipe));
+
+ if (tmp & PF_ENABLE) {
+ pipe_config->pch_pfit.pos = I915_READ(PF_WIN_POS(crtc->pipe));
+ pipe_config->pch_pfit.size = I915_READ(PF_WIN_SZ(crtc->pipe));
+
+ /* We currently do not free assignements of panel fitters on
+ * ivb/hsw (since we don't use the higher upscaling modes which
+ * differentiates them) so just WARN about this case for now. */
+ if (IS_GEN7(dev)) {
+ WARN_ON((tmp & PF_PIPE_SEL_MASK_IVB) !=
+ PF_PIPE_SEL_IVB(crtc->pipe));
+ }
+ }
}
static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
@@ -5738,42 +5823,67 @@ static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp;
+ pipe_config->cpu_transcoder = crtc->pipe;
+ pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+
tmp = I915_READ(PIPECONF(crtc->pipe));
if (!(tmp & PIPECONF_ENABLE))
return false;
- if (I915_READ(TRANSCONF(crtc->pipe)) & TRANS_ENABLE)
+ if (I915_READ(PCH_TRANSCONF(crtc->pipe)) & TRANS_ENABLE) {
+ struct intel_shared_dpll *pll;
+
pipe_config->has_pch_encoder = true;
+ tmp = I915_READ(FDI_RX_CTL(crtc->pipe));
+ pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >>
+ FDI_DP_PORT_WIDTH_SHIFT) + 1;
+
+ ironlake_get_fdi_m_n_config(crtc, pipe_config);
+
+ /* XXX: Can't properly read out the pch dpll pixel multiplier
+ * since we don't have state tracking for pch clocks yet. */
+ pipe_config->pixel_multiplier = 1;
+
+ if (HAS_PCH_IBX(dev_priv->dev)) {
+ pipe_config->shared_dpll = crtc->pipe;
+ } else {
+ tmp = I915_READ(PCH_DPLL_SEL);
+ if (tmp & TRANS_DPLLB_SEL(crtc->pipe))
+ pipe_config->shared_dpll = DPLL_ID_PCH_PLL_B;
+ else
+ pipe_config->shared_dpll = DPLL_ID_PCH_PLL_A;
+ }
+
+ pll = &dev_priv->shared_dplls[pipe_config->shared_dpll];
+
+ WARN_ON(!pll->get_hw_state(dev_priv, pll,
+ &pipe_config->dpll_hw_state));
+ } else {
+ pipe_config->pixel_multiplier = 1;
+ }
+
+ intel_get_pipe_timings(crtc, pipe_config);
+
+ ironlake_get_pfit_config(crtc, pipe_config);
+
return true;
}
static void haswell_modeset_global_resources(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
bool enable = false;
struct intel_crtc *crtc;
- struct intel_encoder *encoder;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
- if (crtc->pipe != PIPE_A && crtc->base.enabled)
- enable = true;
- /* XXX: Should check for edp transcoder here, but thanks to init
- * sequence that's not yet available. Just in case desktop eDP
- * on PORT D is possible on haswell, too. */
- }
+ if (!crtc->base.enabled)
+ continue;
- list_for_each_entry(encoder, &dev->mode_config.encoder_list,
- base.head) {
- if (encoder->type != INTEL_OUTPUT_EDP &&
- encoder->connectors_active)
+ if (crtc->pipe != PIPE_A || crtc->config.pch_pfit.size ||
+ crtc->config.cpu_transcoder != TRANSCODER_EDP)
enable = true;
}
- /* Even the eDP panel fitter is outside the always-on well. */
- if (dev_priv->pch_pf_size)
- enable = true;
-
intel_set_power_well(dev, enable);
}
@@ -5784,68 +5894,28 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
- struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
- int pipe = intel_crtc->pipe;
int plane = intel_crtc->plane;
- int num_connectors = 0;
- bool is_cpu_edp = false;
- struct intel_encoder *encoder;
int ret;
- bool dither;
-
- for_each_encoder_on_crtc(dev, crtc, encoder) {
- switch (encoder->type) {
- case INTEL_OUTPUT_EDP:
- if (!intel_encoder_is_pch_edp(&encoder->base))
- is_cpu_edp = true;
- break;
- }
-
- num_connectors++;
- }
-
- if (is_cpu_edp)
- intel_crtc->config.cpu_transcoder = TRANSCODER_EDP;
- else
- intel_crtc->config.cpu_transcoder = pipe;
-
- /* We are not sure yet this won't happen. */
- WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n",
- INTEL_PCH_TYPE(dev));
- WARN(num_connectors != 1, "%d connectors attached to pipe %c\n",
- num_connectors, pipe_name(pipe));
-
- WARN_ON(I915_READ(PIPECONF(intel_crtc->config.cpu_transcoder)) &
- (PIPECONF_ENABLE | I965_PIPECONF_ACTIVE));
-
- WARN_ON(I915_READ(DSPCNTR(plane)) & DISPLAY_PLANE_ENABLE);
-
- if (!intel_ddi_pll_mode_set(crtc, adjusted_mode->clock))
+ if (!intel_ddi_pll_mode_set(crtc))
return -EINVAL;
/* Ensure that the cursor is valid for the new mode before changing... */
intel_crtc_update_cursor(crtc, true);
- /* determine panel color depth */
- dither = intel_crtc->config.dither;
-
- DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
- drm_mode_debug_printmodeline(mode);
-
if (intel_crtc->config.has_dp_encoder)
intel_dp_set_m_n(intel_crtc);
intel_crtc->lowfreq_avail = false;
- intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
+ intel_set_pipe_timings(intel_crtc);
- if (intel_crtc->config.has_pch_encoder)
- ironlake_fdi_set_m_n(crtc);
+ if (intel_crtc->config.has_pch_encoder) {
+ intel_cpu_transcoder_set_m_n(intel_crtc,
+ &intel_crtc->config.fdi_m_n);
+ }
- haswell_set_pipeconf(crtc, adjusted_mode, dither);
+ haswell_set_pipeconf(crtc);
intel_set_pipe_csc(crtc);
@@ -5857,8 +5927,6 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
intel_update_watermarks(dev);
- intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
-
return ret;
}
@@ -5867,22 +5935,69 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ enum intel_display_power_domain pfit_domain;
uint32_t tmp;
- tmp = I915_READ(PIPECONF(crtc->config.cpu_transcoder));
+ pipe_config->cpu_transcoder = crtc->pipe;
+ pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+
+ tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
+ if (tmp & TRANS_DDI_FUNC_ENABLE) {
+ enum pipe trans_edp_pipe;
+ switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
+ default:
+ WARN(1, "unknown pipe linked to edp transcoder\n");
+ case TRANS_DDI_EDP_INPUT_A_ONOFF:
+ case TRANS_DDI_EDP_INPUT_A_ON:
+ trans_edp_pipe = PIPE_A;
+ break;
+ case TRANS_DDI_EDP_INPUT_B_ONOFF:
+ trans_edp_pipe = PIPE_B;
+ break;
+ case TRANS_DDI_EDP_INPUT_C_ONOFF:
+ trans_edp_pipe = PIPE_C;
+ break;
+ }
+
+ if (trans_edp_pipe == crtc->pipe)
+ pipe_config->cpu_transcoder = TRANSCODER_EDP;
+ }
+
+ if (!intel_display_power_enabled(dev,
+ POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder)))
+ return false;
+
+ tmp = I915_READ(PIPECONF(pipe_config->cpu_transcoder));
if (!(tmp & PIPECONF_ENABLE))
return false;
/*
- * aswell has only FDI/PCH transcoder A. It is which is connected to
+ * Haswell has only FDI/PCH transcoder A. It is which is connected to
* DDI E. So just check whether this pipe is wired to DDI E and whether
* the PCH transcoder is on.
*/
- tmp = I915_READ(TRANS_DDI_FUNC_CTL(crtc->pipe));
+ tmp = I915_READ(TRANS_DDI_FUNC_CTL(pipe_config->cpu_transcoder));
if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(PORT_E) &&
- I915_READ(TRANSCONF(PIPE_A)) & TRANS_ENABLE)
+ I915_READ(LPT_TRANSCONF) & TRANS_ENABLE) {
pipe_config->has_pch_encoder = true;
+ tmp = I915_READ(FDI_RX_CTL(PIPE_A));
+ pipe_config->fdi_lanes = ((FDI_DP_PORT_WIDTH_MASK & tmp) >>
+ FDI_DP_PORT_WIDTH_SHIFT) + 1;
+
+ ironlake_get_fdi_m_n_config(crtc, pipe_config);
+ }
+
+ intel_get_pipe_timings(crtc, pipe_config);
+
+ pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
+ if (intel_display_power_enabled(dev, pfit_domain))
+ ironlake_get_pfit_config(crtc, pipe_config);
+
+ pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
+ (I915_READ(IPS_CTL) & IPS_ENABLE);
+
+ pipe_config->pixel_multiplier = 1;
return true;
}
@@ -6120,7 +6235,7 @@ static void ironlake_write_eld(struct drm_connector *connector,
eldv |= IBX_ELD_VALIDB << 4;
eldv |= IBX_ELD_VALIDB << 8;
} else {
- DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i);
+ DRM_DEBUG_DRIVER("ELD on port %c\n", port_name(i));
eldv = IBX_ELD_VALIDB << ((i - 1) * 4);
}
@@ -6188,16 +6303,31 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int palreg = PALETTE(intel_crtc->pipe);
+ enum pipe pipe = intel_crtc->pipe;
+ int palreg = PALETTE(pipe);
int i;
+ bool reenable_ips = false;
/* The clocks have to be on to load the palette. */
if (!crtc->enabled || !intel_crtc->active)
return;
+ if (!HAS_PCH_SPLIT(dev_priv->dev))
+ assert_pll_enabled(dev_priv, pipe);
+
/* use legacy palette for Ironlake */
if (HAS_PCH_SPLIT(dev))
- palreg = LGC_PALETTE(intel_crtc->pipe);
+ palreg = LGC_PALETTE(pipe);
+
+ /* Workaround : Do not read or write the pipe palette/gamma data while
+ * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
+ */
+ if (intel_crtc->config.ips_enabled &&
+ ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
+ GAMMA_MODE_MODE_SPLIT)) {
+ hsw_disable_ips(intel_crtc);
+ reenable_ips = true;
+ }
for (i = 0; i < 256; i++) {
I915_WRITE(palreg + 4 * i,
@@ -6205,6 +6335,9 @@ void intel_crtc_load_lut(struct drm_crtc *crtc)
(intel_crtc->lut_g[i] << 8) |
intel_crtc->lut_b[i]);
}
+
+ if (reenable_ips)
+ hsw_enable_ips(intel_crtc);
}
static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
@@ -6451,7 +6584,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_width = width;
intel_crtc->cursor_height = height;
- intel_crtc_update_cursor(crtc, true);
+ intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
return 0;
fail_unpin:
@@ -6470,7 +6603,7 @@ static int intel_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
intel_crtc->cursor_x = x;
intel_crtc->cursor_y = y;
- intel_crtc_update_cursor(crtc, true);
+ intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
return 0;
}
@@ -6791,8 +6924,10 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
return 0;
}
- /* XXX: Handle the 100Mhz refclk */
- intel_clock(dev, 96000, &clock);
+ if (IS_PINEVIEW(dev))
+ pineview_clock(96000, &clock);
+ else
+ i9xx_clock(96000, &clock);
} else {
bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
@@ -6804,9 +6939,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
if ((dpll & PLL_REF_INPUT_MASK) ==
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
/* XXX: might not be 66MHz */
- intel_clock(dev, 66000, &clock);
+ i9xx_clock(66000, &clock);
} else
- intel_clock(dev, 48000, &clock);
+ i9xx_clock(48000, &clock);
} else {
if (dpll & PLL_P1_DIVIDE_BY_TWO)
clock.p1 = 2;
@@ -6819,7 +6954,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
else
clock.p2 = 2;
- intel_clock(dev, 48000, &clock);
+ i9xx_clock(48000, &clock);
}
}
@@ -6950,7 +7085,8 @@ void intel_mark_idle(struct drm_device *dev)
}
}
-void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
+void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring)
{
struct drm_device *dev = obj->base.dev;
struct drm_crtc *crtc;
@@ -6962,8 +7098,12 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj)
if (!crtc->fb)
continue;
- if (to_intel_framebuffer(crtc->fb)->obj == obj)
- intel_increase_pllclock(crtc);
+ if (to_intel_framebuffer(crtc->fb)->obj != obj)
+ continue;
+
+ intel_increase_pllclock(crtc);
+ if (ring && intel_fbc_enabled(dev))
+ ring->fbc_dirty = true;
}
}
@@ -6984,6 +7124,8 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
kfree(work);
}
+ intel_crtc_cursor_set(crtc, NULL, 0, 0, 0);
+
drm_crtc_cleanup(crtc);
kfree(intel_crtc);
@@ -7411,7 +7553,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
goto cleanup_pending;
intel_disable_fbc(dev);
- intel_mark_fb_busy(obj);
+ intel_mark_fb_busy(obj, NULL);
mutex_unlock(&dev->struct_mutex);
trace_i915_flip_request(intel_crtc->plane, obj);
@@ -7442,28 +7584,6 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
.load_lut = intel_crtc_load_lut,
};
-bool intel_encoder_check_is_cloned(struct intel_encoder *encoder)
-{
- struct intel_encoder *other_encoder;
- struct drm_crtc *crtc = &encoder->new_crtc->base;
-
- if (WARN_ON(!crtc))
- return false;
-
- list_for_each_entry(other_encoder,
- &crtc->dev->mode_config.encoder_list,
- base.head) {
-
- if (&other_encoder->new_crtc->base != crtc ||
- encoder == other_encoder)
- continue;
- else
- return true;
- }
-
- return false;
-}
-
static bool intel_encoder_crtc_ok(struct drm_encoder *encoder,
struct drm_crtc *crtc)
{
@@ -7531,13 +7651,39 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
}
}
+static void
+connected_sink_compute_bpp(struct intel_connector * connector,
+ struct intel_crtc_config *pipe_config)
+{
+ int bpp = pipe_config->pipe_bpp;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] checking for sink bpp constrains\n",
+ connector->base.base.id,
+ drm_get_connector_name(&connector->base));
+
+ /* Don't use an invalid EDID bpc value */
+ if (connector->base.display_info.bpc &&
+ connector->base.display_info.bpc * 3 < bpp) {
+ DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
+ bpp, connector->base.display_info.bpc*3);
+ pipe_config->pipe_bpp = connector->base.display_info.bpc*3;
+ }
+
+ /* Clamp bpp to 8 on screens without EDID 1.4 */
+ if (connector->base.display_info.bpc == 0 && bpp > 24) {
+ DRM_DEBUG_KMS("clamping display bpp (was %d) to default limit of 24\n",
+ bpp);
+ pipe_config->pipe_bpp = 24;
+ }
+}
+
static int
-pipe_config_set_bpp(struct drm_crtc *crtc,
- struct drm_framebuffer *fb,
- struct intel_crtc_config *pipe_config)
+compute_baseline_pipe_bpp(struct intel_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct intel_crtc_config *pipe_config)
{
- struct drm_device *dev = crtc->dev;
- struct drm_connector *connector;
+ struct drm_device *dev = crtc->base.dev;
+ struct intel_connector *connector;
int bpp;
switch (fb->pixel_format) {
@@ -7580,22 +7726,66 @@ pipe_config_set_bpp(struct drm_crtc *crtc,
/* Clamp display bpp to EDID value */
list_for_each_entry(connector, &dev->mode_config.connector_list,
- head) {
- if (connector->encoder && connector->encoder->crtc != crtc)
+ base.head) {
+ if (!connector->new_encoder ||
+ connector->new_encoder->new_crtc != crtc)
continue;
- /* Don't use an invalid EDID bpc value */
- if (connector->display_info.bpc &&
- connector->display_info.bpc * 3 < bpp) {
- DRM_DEBUG_KMS("clamping display bpp (was %d) to EDID reported max of %d\n",
- bpp, connector->display_info.bpc*3);
- pipe_config->pipe_bpp = connector->display_info.bpc*3;
- }
+ connected_sink_compute_bpp(connector, pipe_config);
}
return bpp;
}
+static void intel_dump_pipe_config(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config,
+ const char *context)
+{
+ DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id,
+ context, pipe_name(crtc->pipe));
+
+ DRM_DEBUG_KMS("cpu_transcoder: %c\n", transcoder_name(pipe_config->cpu_transcoder));
+ DRM_DEBUG_KMS("pipe bpp: %i, dithering: %i\n",
+ pipe_config->pipe_bpp, pipe_config->dither);
+ DRM_DEBUG_KMS("fdi/pch: %i, lanes: %i, gmch_m: %u, gmch_n: %u, link_m: %u, link_n: %u, tu: %u\n",
+ pipe_config->has_pch_encoder,
+ pipe_config->fdi_lanes,
+ pipe_config->fdi_m_n.gmch_m, pipe_config->fdi_m_n.gmch_n,
+ pipe_config->fdi_m_n.link_m, pipe_config->fdi_m_n.link_n,
+ pipe_config->fdi_m_n.tu);
+ DRM_DEBUG_KMS("requested mode:\n");
+ drm_mode_debug_printmodeline(&pipe_config->requested_mode);
+ DRM_DEBUG_KMS("adjusted mode:\n");
+ drm_mode_debug_printmodeline(&pipe_config->adjusted_mode);
+ DRM_DEBUG_KMS("gmch pfit: control: 0x%08x, ratios: 0x%08x, lvds border: 0x%08x\n",
+ pipe_config->gmch_pfit.control,
+ pipe_config->gmch_pfit.pgm_ratios,
+ pipe_config->gmch_pfit.lvds_border_bits);
+ DRM_DEBUG_KMS("pch pfit: pos: 0x%08x, size: 0x%08x\n",
+ pipe_config->pch_pfit.pos,
+ pipe_config->pch_pfit.size);
+ DRM_DEBUG_KMS("ips: %i\n", pipe_config->ips_enabled);
+}
+
+static bool check_encoder_cloning(struct drm_crtc *crtc)
+{
+ int num_encoders = 0;
+ bool uncloneable_encoders = false;
+ struct intel_encoder *encoder;
+
+ list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list,
+ base.head) {
+ if (&encoder->new_crtc->base != crtc)
+ continue;
+
+ num_encoders++;
+ if (!encoder->cloneable)
+ uncloneable_encoders = true;
+ }
+
+ return !(num_encoders > 1 && uncloneable_encoders);
+}
+
static struct intel_crtc_config *
intel_modeset_pipe_config(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
@@ -7605,7 +7795,13 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
struct drm_encoder_helper_funcs *encoder_funcs;
struct intel_encoder *encoder;
struct intel_crtc_config *pipe_config;
- int plane_bpp;
+ int plane_bpp, ret = -EINVAL;
+ bool retry = true;
+
+ if (!check_encoder_cloning(crtc)) {
+ DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
+ return ERR_PTR(-EINVAL);
+ }
pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
if (!pipe_config)
@@ -7613,11 +7809,23 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
drm_mode_copy(&pipe_config->adjusted_mode, mode);
drm_mode_copy(&pipe_config->requested_mode, mode);
-
- plane_bpp = pipe_config_set_bpp(crtc, fb, pipe_config);
+ pipe_config->cpu_transcoder = to_intel_crtc(crtc)->pipe;
+ pipe_config->shared_dpll = DPLL_ID_PRIVATE;
+
+ /* Compute a starting value for pipe_config->pipe_bpp taking the source
+ * plane pixel format and any sink constraints into account. Returns the
+ * source plane bpp so that dithering can be selected on mismatches
+ * after encoders and crtc also have had their say. */
+ plane_bpp = compute_baseline_pipe_bpp(to_intel_crtc(crtc),
+ fb, pipe_config);
if (plane_bpp < 0)
goto fail;
+encoder_retry:
+ /* Ensure the port clock defaults are reset when retrying. */
+ pipe_config->port_clock = 0;
+ pipe_config->pixel_multiplier = 1;
+
/* Pass our mode to the connectors and the CRTC to give them a chance to
* adjust it according to limitations or connector properties, and also
* a chance to reject the mode entirely.
@@ -7646,11 +7854,27 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
}
}
- if (!(intel_crtc_compute_config(crtc, pipe_config))) {
+ /* Set default port clock if not overwritten by the encoder. Needs to be
+ * done afterwards in case the encoder adjusts the mode. */
+ if (!pipe_config->port_clock)
+ pipe_config->port_clock = pipe_config->adjusted_mode.clock;
+
+ ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config);
+ if (ret < 0) {
DRM_DEBUG_KMS("CRTC fixup failed\n");
goto fail;
}
- DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
+
+ if (ret == RETRY) {
+ if (WARN(!retry, "loop in pipe configuration computation\n")) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ DRM_DEBUG_KMS("CRTC bw constrained, retrying\n");
+ retry = false;
+ goto encoder_retry;
+ }
pipe_config->dither = pipe_config->pipe_bpp != plane_bpp;
DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n",
@@ -7659,7 +7883,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
return pipe_config;
fail:
kfree(pipe_config);
- return ERR_PTR(-EINVAL);
+ return ERR_PTR(ret);
}
/* Computes which crtcs are affected and sets the relevant bits in the mask. For
@@ -7755,6 +7979,9 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
*/
*modeset_pipes &= 1 << intel_crtc->pipe;
*prepare_pipes &= 1 << intel_crtc->pipe;
+
+ DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
+ *modeset_pipes, *prepare_pipes, *disable_pipes);
}
static bool intel_crtc_in_use(struct drm_crtc *crtc)
@@ -7821,31 +8048,114 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
list_for_each_entry((intel_crtc), \
&(dev)->mode_config.crtc_list, \
base.head) \
- if (mask & (1 <<(intel_crtc)->pipe)) \
+ if (mask & (1 <<(intel_crtc)->pipe))
static bool
-intel_pipe_config_compare(struct intel_crtc_config *current_config,
+intel_pipe_config_compare(struct drm_device *dev,
+ struct intel_crtc_config *current_config,
struct intel_crtc_config *pipe_config)
{
- if (current_config->has_pch_encoder != pipe_config->has_pch_encoder) {
- DRM_ERROR("mismatch in has_pch_encoder "
- "(expected %i, found %i)\n",
- current_config->has_pch_encoder,
- pipe_config->has_pch_encoder);
- return false;
- }
+#define PIPE_CONF_CHECK_X(name) \
+ if (current_config->name != pipe_config->name) { \
+ DRM_ERROR("mismatch in " #name " " \
+ "(expected 0x%08x, found 0x%08x)\n", \
+ current_config->name, \
+ pipe_config->name); \
+ return false; \
+ }
+
+#define PIPE_CONF_CHECK_I(name) \
+ if (current_config->name != pipe_config->name) { \
+ DRM_ERROR("mismatch in " #name " " \
+ "(expected %i, found %i)\n", \
+ current_config->name, \
+ pipe_config->name); \
+ return false; \
+ }
+
+#define PIPE_CONF_CHECK_FLAGS(name, mask) \
+ if ((current_config->name ^ pipe_config->name) & (mask)) { \
+ DRM_ERROR("mismatch in " #name " " \
+ "(expected %i, found %i)\n", \
+ current_config->name & (mask), \
+ pipe_config->name & (mask)); \
+ return false; \
+ }
+
+#define PIPE_CONF_QUIRK(quirk) \
+ ((current_config->quirks | pipe_config->quirks) & (quirk))
+
+ PIPE_CONF_CHECK_I(cpu_transcoder);
+
+ PIPE_CONF_CHECK_I(has_pch_encoder);
+ PIPE_CONF_CHECK_I(fdi_lanes);
+ PIPE_CONF_CHECK_I(fdi_m_n.gmch_m);
+ PIPE_CONF_CHECK_I(fdi_m_n.gmch_n);
+ PIPE_CONF_CHECK_I(fdi_m_n.link_m);
+ PIPE_CONF_CHECK_I(fdi_m_n.link_n);
+ PIPE_CONF_CHECK_I(fdi_m_n.tu);
+
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end);
+
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end);
+
+ if (!HAS_PCH_SPLIT(dev))
+ PIPE_CONF_CHECK_I(pixel_multiplier);
+
+ PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ DRM_MODE_FLAG_INTERLACE);
+
+ if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
+ PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ DRM_MODE_FLAG_PHSYNC);
+ PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ DRM_MODE_FLAG_NHSYNC);
+ PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ DRM_MODE_FLAG_PVSYNC);
+ PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ DRM_MODE_FLAG_NVSYNC);
+ }
+
+ PIPE_CONF_CHECK_I(requested_mode.hdisplay);
+ PIPE_CONF_CHECK_I(requested_mode.vdisplay);
+
+ PIPE_CONF_CHECK_I(gmch_pfit.control);
+ /* pfit ratios are autocomputed by the hw on gen4+ */
+ if (INTEL_INFO(dev)->gen < 4)
+ PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios);
+ PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits);
+ PIPE_CONF_CHECK_I(pch_pfit.pos);
+ PIPE_CONF_CHECK_I(pch_pfit.size);
+
+ PIPE_CONF_CHECK_I(ips_enabled);
+
+ PIPE_CONF_CHECK_I(shared_dpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
+ PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
+
+#undef PIPE_CONF_CHECK_X
+#undef PIPE_CONF_CHECK_I
+#undef PIPE_CONF_CHECK_FLAGS
+#undef PIPE_CONF_QUIRK
return true;
}
-void
-intel_modeset_check_state(struct drm_device *dev)
+static void
+check_connector_state(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_crtc *crtc;
- struct intel_encoder *encoder;
struct intel_connector *connector;
- struct intel_crtc_config pipe_config;
list_for_each_entry(connector, &dev->mode_config.connector_list,
base.head) {
@@ -7856,6 +8166,13 @@ intel_modeset_check_state(struct drm_device *dev)
WARN(&connector->new_encoder->base != connector->base.encoder,
"connector's staged encoder doesn't match current encoder\n");
}
+}
+
+static void
+check_encoder_state(struct drm_device *dev)
+{
+ struct intel_encoder *encoder;
+ struct intel_connector *connector;
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
base.head) {
@@ -7907,12 +8224,23 @@ intel_modeset_check_state(struct drm_device *dev)
tracked_pipe, pipe);
}
+}
+
+static void
+check_crtc_state(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+ struct intel_encoder *encoder;
+ struct intel_crtc_config pipe_config;
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
base.head) {
bool enabled = false;
bool active = false;
+ memset(&pipe_config, 0, sizeof(pipe_config));
+
DRM_DEBUG_KMS("[CRTC:%d]\n",
crtc->base.base.id);
@@ -7927,6 +8255,7 @@ intel_modeset_check_state(struct drm_device *dev)
if (encoder->connectors_active)
active = true;
}
+
WARN(active != crtc->active,
"crtc's computed active state doesn't match tracked active state "
"(expected %i, found %i)\n", active, crtc->active);
@@ -7934,7 +8263,6 @@ intel_modeset_check_state(struct drm_device *dev)
"crtc's computed enabled state doesn't match tracked enabled state "
"(expected %i, found %i)\n", enabled, crtc->base.enabled);
- memset(&pipe_config, 0, sizeof(pipe_config));
active = dev_priv->display.get_pipe_config(crtc,
&pipe_config);
@@ -7942,16 +8270,86 @@ intel_modeset_check_state(struct drm_device *dev)
if (crtc->pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
active = crtc->active;
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list,
+ base.head) {
+ if (encoder->base.crtc != &crtc->base)
+ continue;
+ if (encoder->get_config)
+ encoder->get_config(encoder, &pipe_config);
+ }
+
WARN(crtc->active != active,
"crtc active state doesn't match with hw state "
"(expected %i, found %i)\n", crtc->active, active);
- WARN(active &&
- !intel_pipe_config_compare(&crtc->config, &pipe_config),
- "pipe state doesn't match!\n");
+ if (active &&
+ !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) {
+ WARN(1, "pipe state doesn't match!\n");
+ intel_dump_pipe_config(crtc, &pipe_config,
+ "[hw state]");
+ intel_dump_pipe_config(crtc, &crtc->config,
+ "[sw state]");
+ }
}
}
+static void
+check_shared_dpll_state(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_crtc *crtc;
+ struct intel_dpll_hw_state dpll_hw_state;
+ int i;
+
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+ int enabled_crtcs = 0, active_crtcs = 0;
+ bool active;
+
+ memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
+
+ DRM_DEBUG_KMS("%s\n", pll->name);
+
+ active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
+
+ WARN(pll->active > pll->refcount,
+ "more active pll users than references: %i vs %i\n",
+ pll->active, pll->refcount);
+ WARN(pll->active && !pll->on,
+ "pll in active use but not on in sw tracking\n");
+ WARN(pll->on != active,
+ "pll on state mismatch (expected %i, found %i)\n",
+ pll->on, active);
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+ base.head) {
+ if (crtc->base.enabled && intel_crtc_to_shared_dpll(crtc) == pll)
+ enabled_crtcs++;
+ if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
+ active_crtcs++;
+ }
+ WARN(pll->active != active_crtcs,
+ "pll active crtcs mismatch (expected %i, found %i)\n",
+ pll->active, active_crtcs);
+ WARN(pll->refcount != enabled_crtcs,
+ "pll enabled crtcs mismatch (expected %i, found %i)\n",
+ pll->refcount, enabled_crtcs);
+
+ WARN(pll->on && memcmp(&pll->hw_state, &dpll_hw_state,
+ sizeof(dpll_hw_state)),
+ "pll hw state mismatch\n");
+ }
+}
+
+void
+intel_modeset_check_state(struct drm_device *dev)
+{
+ check_connector_state(dev);
+ check_encoder_state(dev);
+ check_crtc_state(dev);
+ check_shared_dpll_state(dev);
+}
+
static int __intel_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *fb)
@@ -7988,11 +8386,10 @@ static int __intel_set_mode(struct drm_crtc *crtc,
goto out;
}
+ intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
+ "[modeset]");
}
- DRM_DEBUG_KMS("set mode pipe masks: modeset: %x, prepare: %x, disable: %x\n",
- modeset_pipes, prepare_pipes, disable_pipes);
-
for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
intel_crtc_disable(&intel_crtc->base);
@@ -8005,12 +8402,10 @@ static int __intel_set_mode(struct drm_crtc *crtc,
* to set it here already despite that we pass it down the callchain.
*/
if (modeset_pipes) {
- enum transcoder tmp = to_intel_crtc(crtc)->config.cpu_transcoder;
crtc->mode = *mode;
/* mode_set/enable/disable functions rely on a correct pipe
* config. */
to_intel_crtc(crtc)->config = *pipe_config;
- to_intel_crtc(crtc)->config.cpu_transcoder = tmp;
}
/* Only after disabling all output pipelines that will be changed can we
@@ -8349,12 +8744,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
goto fail;
if (config->mode_changed) {
- if (set->mode) {
- DRM_DEBUG_KMS("attempting to set mode from"
- " userspace\n");
- drm_mode_debug_printmodeline(set->mode);
- }
-
ret = intel_set_mode(set->crtc, set->mode,
set->x, set->y, set->fb);
} else if (config->fb_changed) {
@@ -8365,8 +8754,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
}
if (ret) {
- DRM_ERROR("failed to set mode on [CRTC:%d], err = %d\n",
- set->crtc->base.id, ret);
+ DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n",
+ set->crtc->base.id, ret);
fail:
intel_set_config_restore_state(dev, config);
@@ -8397,23 +8786,93 @@ static void intel_cpu_pll_init(struct drm_device *dev)
intel_ddi_pll_init(dev);
}
-static void intel_pch_pll_init(struct drm_device *dev)
+static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int i;
+ uint32_t val;
- if (dev_priv->num_pch_pll == 0) {
- DRM_DEBUG_KMS("No PCH PLLs on this hardware, skipping initialisation\n");
- return;
+ val = I915_READ(PCH_DPLL(pll->id));
+ hw_state->dpll = val;
+ hw_state->fp0 = I915_READ(PCH_FP0(pll->id));
+ hw_state->fp1 = I915_READ(PCH_FP1(pll->id));
+
+ return val & DPLL_VCO_ENABLE;
+}
+
+static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ uint32_t reg, val;
+
+ /* PCH refclock must be enabled first */
+ assert_pch_refclk_enabled(dev_priv);
+
+ reg = PCH_DPLL(pll->id);
+ val = I915_READ(reg);
+ val |= DPLL_VCO_ENABLE;
+ I915_WRITE(reg, val);
+ POSTING_READ(reg);
+ udelay(200);
+}
+
+static void ibx_pch_dpll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ struct drm_device *dev = dev_priv->dev;
+ struct intel_crtc *crtc;
+ uint32_t reg, val;
+
+ /* Make sure no transcoder isn't still depending on us. */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+ if (intel_crtc_to_shared_dpll(crtc) == pll)
+ assert_pch_transcoder_disabled(dev_priv, crtc->pipe);
}
- for (i = 0; i < dev_priv->num_pch_pll; i++) {
- dev_priv->pch_plls[i].pll_reg = _PCH_DPLL(i);
- dev_priv->pch_plls[i].fp0_reg = _PCH_FP0(i);
- dev_priv->pch_plls[i].fp1_reg = _PCH_FP1(i);
+ reg = PCH_DPLL(pll->id);
+ val = I915_READ(reg);
+ val &= ~DPLL_VCO_ENABLE;
+ I915_WRITE(reg, val);
+ POSTING_READ(reg);
+ udelay(200);
+}
+
+static char *ibx_pch_dpll_names[] = {
+ "PCH DPLL A",
+ "PCH DPLL B",
+};
+
+static void ibx_pch_dpll_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int i;
+
+ dev_priv->num_shared_dpll = 2;
+
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ dev_priv->shared_dplls[i].id = i;
+ dev_priv->shared_dplls[i].name = ibx_pch_dpll_names[i];
+ dev_priv->shared_dplls[i].enable = ibx_pch_dpll_enable;
+ dev_priv->shared_dplls[i].disable = ibx_pch_dpll_disable;
+ dev_priv->shared_dplls[i].get_hw_state =
+ ibx_pch_dpll_get_hw_state;
}
}
+static void intel_shared_dpll_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
+ ibx_pch_dpll_init(dev);
+ else
+ dev_priv->num_shared_dpll = 0;
+
+ BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
+ DRM_DEBUG_KMS("%i shared PLLs initialized\n",
+ dev_priv->num_shared_dpll);
+}
+
static void intel_crtc_init(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -8436,7 +8895,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
/* Swap pipes & planes for FBC on pre-965 */
intel_crtc->pipe = pipe;
intel_crtc->plane = pipe;
- intel_crtc->config.cpu_transcoder = pipe;
if (IS_MOBILE(dev) && IS_GEN3(dev)) {
DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
intel_crtc->plane = !pipe;
@@ -8519,13 +8977,8 @@ static void intel_setup_outputs(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
bool dpd_is_edp = false;
- bool has_lvds;
- has_lvds = intel_lvds_init(dev);
- if (!has_lvds && !HAS_PCH_SPLIT(dev)) {
- /* disable the panel fitter on everything but LVDS */
- I915_WRITE(PFIT_CONTROL, 0);
- }
+ intel_lvds_init(dev);
if (!IS_ULT(dev))
intel_crt_init(dev);
@@ -8598,10 +9051,8 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_hdmi_init(dev, GEN4_HDMIB, PORT_B);
}
- if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
- DRM_DEBUG_KMS("probing DP_B\n");
+ if (!found && SUPPORTS_INTEGRATED_DP(dev))
intel_dp_init(dev, DP_B, PORT_B);
- }
}
/* Before G4X SDVOC doesn't have its own detect register */
@@ -8617,17 +9068,13 @@ static void intel_setup_outputs(struct drm_device *dev)
DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
intel_hdmi_init(dev, GEN4_HDMIC, PORT_C);
}
- if (SUPPORTS_INTEGRATED_DP(dev)) {
- DRM_DEBUG_KMS("probing DP_C\n");
+ if (SUPPORTS_INTEGRATED_DP(dev))
intel_dp_init(dev, DP_C, PORT_C);
- }
}
if (SUPPORTS_INTEGRATED_DP(dev) &&
- (I915_READ(DP_D) & DP_DETECTED)) {
- DRM_DEBUG_KMS("probing DP_D\n");
+ (I915_READ(DP_D) & DP_DETECTED))
intel_dp_init(dev, DP_D, PORT_D);
- }
} else if (IS_GEN2(dev))
intel_dvo_init(dev);
@@ -8675,6 +9122,7 @@ int intel_framebuffer_init(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
struct drm_i915_gem_object *obj)
{
+ int pitch_limit;
int ret;
if (obj->tiling_mode == I915_TILING_Y) {
@@ -8688,10 +9136,26 @@ int intel_framebuffer_init(struct drm_device *dev,
return -EINVAL;
}
- /* FIXME <= Gen4 stride limits are bit unclear */
- if (mode_cmd->pitches[0] > 32768) {
- DRM_DEBUG("pitch (%d) must be at less than 32768\n",
- mode_cmd->pitches[0]);
+ if (INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev)) {
+ pitch_limit = 32*1024;
+ } else if (INTEL_INFO(dev)->gen >= 4) {
+ if (obj->tiling_mode)
+ pitch_limit = 16*1024;
+ else
+ pitch_limit = 32*1024;
+ } else if (INTEL_INFO(dev)->gen >= 3) {
+ if (obj->tiling_mode)
+ pitch_limit = 8*1024;
+ else
+ pitch_limit = 16*1024;
+ } else
+ /* XXX DSPC is limited to 4k tiled */
+ pitch_limit = 8*1024;
+
+ if (mode_cmd->pitches[0] > pitch_limit) {
+ DRM_DEBUG("%s pitch (%d) must be at less than %d\n",
+ obj->tiling_mode ? "tiled" : "linear",
+ mode_cmd->pitches[0], pitch_limit);
return -EINVAL;
}
@@ -8712,7 +9176,8 @@ int intel_framebuffer_init(struct drm_device *dev,
case DRM_FORMAT_XRGB1555:
case DRM_FORMAT_ARGB1555:
if (INTEL_INFO(dev)->gen > 3) {
- DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format);
+ DRM_DEBUG("unsupported pixel format: %s\n",
+ drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
}
break;
@@ -8723,7 +9188,8 @@ int intel_framebuffer_init(struct drm_device *dev,
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ABGR2101010:
if (INTEL_INFO(dev)->gen < 4) {
- DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format);
+ DRM_DEBUG("unsupported pixel format: %s\n",
+ drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
}
break;
@@ -8732,12 +9198,14 @@ int intel_framebuffer_init(struct drm_device *dev,
case DRM_FORMAT_YVYU:
case DRM_FORMAT_VYUY:
if (INTEL_INFO(dev)->gen < 5) {
- DRM_DEBUG("invalid format: 0x%08x\n", mode_cmd->pixel_format);
+ DRM_DEBUG("unsupported pixel format: %s\n",
+ drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
}
break;
default:
- DRM_DEBUG("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format);
+ DRM_DEBUG("unsupported pixel format: %s\n",
+ drm_get_format_name(mode_cmd->pixel_format));
return -EINVAL;
}
@@ -8782,6 +9250,15 @@ static void intel_init_display(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ if (HAS_PCH_SPLIT(dev) || IS_G4X(dev))
+ dev_priv->display.find_dpll = g4x_find_best_dpll;
+ else if (IS_VALLEYVIEW(dev))
+ dev_priv->display.find_dpll = vlv_find_best_dpll;
+ else if (IS_PINEVIEW(dev))
+ dev_priv->display.find_dpll = pnv_find_best_dpll;
+ else
+ dev_priv->display.find_dpll = i9xx_find_best_dpll;
+
if (HAS_DDI(dev)) {
dev_priv->display.get_pipe_config = haswell_get_pipe_config;
dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
@@ -8796,6 +9273,13 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.crtc_disable = ironlake_crtc_disable;
dev_priv->display.off = ironlake_crtc_off;
dev_priv->display.update_plane = ironlake_update_plane;
+ } else if (IS_VALLEYVIEW(dev)) {
+ dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+ dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+ dev_priv->display.crtc_enable = valleyview_crtc_enable;
+ dev_priv->display.crtc_disable = i9xx_crtc_disable;
+ dev_priv->display.off = i9xx_crtc_off;
+ dev_priv->display.update_plane = i9xx_update_plane;
} else {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
@@ -9037,6 +9521,11 @@ void intel_modeset_init_hw(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
+void intel_modeset_suspend_hw(struct drm_device *dev)
+{
+ intel_suspend_hw(dev);
+}
+
void intel_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -9082,13 +9571,13 @@ void intel_modeset_init(struct drm_device *dev)
for (j = 0; j < dev_priv->num_plane; j++) {
ret = intel_plane_init(dev, i, j);
if (ret)
- DRM_DEBUG_KMS("pipe %d plane %d init failed: %d\n",
- i, j, ret);
+ DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n",
+ pipe_name(i), sprite_name(i, j), ret);
}
}
intel_cpu_pll_init(dev);
- intel_pch_pll_init(dev);
+ intel_shared_dpll_init(dev);
/* Just disable it once at startup */
i915_disable_vga(dev);
@@ -9289,57 +9778,18 @@ void i915_redisable_vga(struct drm_device *dev)
}
}
-/* Scan out the current hw modeset state, sanitizes it and maps it into the drm
- * and i915 state tracking structures. */
-void intel_modeset_setup_hw_state(struct drm_device *dev,
- bool force_restore)
+static void intel_modeset_readout_hw_state(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe;
- u32 tmp;
- struct drm_plane *plane;
struct intel_crtc *crtc;
struct intel_encoder *encoder;
struct intel_connector *connector;
+ int i;
- if (HAS_DDI(dev)) {
- tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
-
- if (tmp & TRANS_DDI_FUNC_ENABLE) {
- switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
- case TRANS_DDI_EDP_INPUT_A_ON:
- case TRANS_DDI_EDP_INPUT_A_ONOFF:
- pipe = PIPE_A;
- break;
- case TRANS_DDI_EDP_INPUT_B_ONOFF:
- pipe = PIPE_B;
- break;
- case TRANS_DDI_EDP_INPUT_C_ONOFF:
- pipe = PIPE_C;
- break;
- default:
- /* A bogus value has been programmed, disable
- * the transcoder */
- WARN(1, "Bogus eDP source %08x\n", tmp);
- intel_ddi_disable_transcoder_func(dev_priv,
- TRANSCODER_EDP);
- goto setup_pipes;
- }
-
- crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
- crtc->config.cpu_transcoder = TRANSCODER_EDP;
-
- DRM_DEBUG_KMS("Pipe %c using transcoder EDP\n",
- pipe_name(pipe));
- }
- }
-
-setup_pipes:
list_for_each_entry(crtc, &dev->mode_config.crtc_list,
base.head) {
- enum transcoder tmp = crtc->config.cpu_transcoder;
memset(&crtc->config, 0, sizeof(crtc->config));
- crtc->config.cpu_transcoder = tmp;
crtc->active = dev_priv->display.get_pipe_config(crtc,
&crtc->config);
@@ -9351,16 +9801,35 @@ setup_pipes:
crtc->active ? "enabled" : "disabled");
}
+ /* FIXME: Smash this into the new shared dpll infrastructure. */
if (HAS_DDI(dev))
intel_ddi_setup_hw_pll_state(dev);
+ for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
+
+ pll->on = pll->get_hw_state(dev_priv, pll, &pll->hw_state);
+ pll->active = 0;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+ base.head) {
+ if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
+ pll->active++;
+ }
+ pll->refcount = pll->active;
+
+ DRM_DEBUG_KMS("%s hw state readout: refcount %i\n",
+ pll->name, pll->refcount);
+ }
+
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
base.head) {
pipe = 0;
if (encoder->get_hw_state(encoder, &pipe)) {
- encoder->base.crtc =
- dev_priv->pipe_to_crtc_mapping[pipe];
+ crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+ encoder->base.crtc = &crtc->base;
+ if (encoder->get_config)
+ encoder->get_config(encoder, &crtc->config);
} else {
encoder->base.crtc = NULL;
}
@@ -9388,6 +9857,20 @@ setup_pipes:
drm_get_connector_name(&connector->base),
connector->base.encoder ? "enabled" : "disabled");
}
+}
+
+/* Scan out the current hw modeset state, sanitizes it and maps it into the drm
+ * and i915 state tracking structures. */
+void intel_modeset_setup_hw_state(struct drm_device *dev,
+ bool force_restore)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum pipe pipe;
+ struct drm_plane *plane;
+ struct intel_crtc *crtc;
+ struct intel_encoder *encoder;
+
+ intel_modeset_readout_hw_state(dev);
/* HW state is read out, now we need to sanitize this mess. */
list_for_each_entry(encoder, &dev->mode_config.encoder_list,
@@ -9398,6 +9881,7 @@ setup_pipes:
for_each_pipe(pipe) {
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
intel_sanitize_crtc(crtc);
+ intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
}
if (force_restore) {
@@ -9440,12 +9924,23 @@ void intel_modeset_cleanup(struct drm_device *dev)
struct drm_crtc *crtc;
struct intel_crtc *intel_crtc;
+ /*
+ * Interrupts and polling as the first thing to avoid creating havoc.
+ * Too much stuff here (turning of rps, connectors, ...) would
+ * experience fancy races otherwise.
+ */
+ drm_irq_uninstall(dev);
+ cancel_work_sync(&dev_priv->hotplug_work);
+ /*
+ * Due to the hpd irq storm handling the hotplug work can re-arm the
+ * poll handlers. Hence disable polling after hpd handling is shut down.
+ */
drm_kms_helper_poll_fini(dev);
+
mutex_lock(&dev->struct_mutex);
intel_unregister_dsm_handler();
-
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
/* Skip inactive CRTCs */
if (!crtc->fb)
@@ -9461,17 +9956,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
ironlake_teardown_rc6(dev);
- if (IS_VALLEYVIEW(dev))
- vlv_init_dpio(dev);
-
mutex_unlock(&dev->struct_mutex);
- /* Disable the irq before mode object teardown, for the irq might
- * enqueue unpin/hotplug work. */
- drm_irq_uninstall(dev);
- cancel_work_sync(&dev_priv->hotplug_work);
- cancel_work_sync(&dev_priv->rps.work);
-
/* flush any delayed tasks or pending work */
flush_scheduled_work();
@@ -9520,6 +10006,9 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
#include <linux/seq_file.h>
struct intel_display_error_state {
+
+ u32 power_well_driver;
+
struct intel_cursor_error_state {
u32 control;
u32 position;
@@ -9528,6 +10017,7 @@ struct intel_display_error_state {
} cursor[I915_MAX_PIPES];
struct intel_pipe_error_state {
+ enum transcoder cpu_transcoder;
u32 conf;
u32 source;
@@ -9562,8 +10052,12 @@ intel_display_capture_error_state(struct drm_device *dev)
if (error == NULL)
return NULL;
+ if (HAS_POWER_WELL(dev))
+ error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
+
for_each_pipe(i) {
cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i);
+ error->pipe[i].cpu_transcoder = cpu_transcoder;
if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
error->cursor[i].control = I915_READ(CURCNTR(i));
@@ -9598,46 +10092,60 @@ intel_display_capture_error_state(struct drm_device *dev)
error->pipe[i].vsync = I915_READ(VSYNC(cpu_transcoder));
}
+ /* In the code above we read the registers without checking if the power
+ * well was on, so here we have to clear the FPGA_DBG_RM_NOCLAIM bit to
+ * prevent the next I915_WRITE from detecting it and printing an error
+ * message. */
+ if (HAS_POWER_WELL(dev))
+ I915_WRITE_NOTRACE(FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
+
return error;
}
+#define err_printf(e, ...) i915_error_printf(e, __VA_ARGS__)
+
void
-intel_display_print_error_state(struct seq_file *m,
+intel_display_print_error_state(struct drm_i915_error_state_buf *m,
struct drm_device *dev,
struct intel_display_error_state *error)
{
int i;
- seq_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
+ err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
+ if (HAS_POWER_WELL(dev))
+ err_printf(m, "PWR_WELL_CTL2: %08x\n",
+ error->power_well_driver);
for_each_pipe(i) {
- seq_printf(m, "Pipe [%d]:\n", i);
- seq_printf(m, " CONF: %08x\n", error->pipe[i].conf);
- seq_printf(m, " SRC: %08x\n", error->pipe[i].source);
- seq_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal);
- seq_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank);
- seq_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync);
- seq_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal);
- seq_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank);
- seq_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync);
-
- seq_printf(m, "Plane [%d]:\n", i);
- seq_printf(m, " CNTR: %08x\n", error->plane[i].control);
- seq_printf(m, " STRIDE: %08x\n", error->plane[i].stride);
+ err_printf(m, "Pipe [%d]:\n", i);
+ err_printf(m, " CPU transcoder: %c\n",
+ transcoder_name(error->pipe[i].cpu_transcoder));
+ err_printf(m, " CONF: %08x\n", error->pipe[i].conf);
+ err_printf(m, " SRC: %08x\n", error->pipe[i].source);
+ err_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal);
+ err_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank);
+ err_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync);
+ err_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal);
+ err_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank);
+ err_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync);
+
+ err_printf(m, "Plane [%d]:\n", i);
+ err_printf(m, " CNTR: %08x\n", error->plane[i].control);
+ err_printf(m, " STRIDE: %08x\n", error->plane[i].stride);
if (INTEL_INFO(dev)->gen <= 3) {
- seq_printf(m, " SIZE: %08x\n", error->plane[i].size);
- seq_printf(m, " POS: %08x\n", error->plane[i].pos);
+ err_printf(m, " SIZE: %08x\n", error->plane[i].size);
+ err_printf(m, " POS: %08x\n", error->plane[i].pos);
}
if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
- seq_printf(m, " ADDR: %08x\n", error->plane[i].addr);
+ err_printf(m, " ADDR: %08x\n", error->plane[i].addr);
if (INTEL_INFO(dev)->gen >= 4) {
- seq_printf(m, " SURF: %08x\n", error->plane[i].surface);
- seq_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset);
+ err_printf(m, " SURF: %08x\n", error->plane[i].surface);
+ err_printf(m, " TILEOFF: %08x\n", error->plane[i].tile_offset);
}
- seq_printf(m, "Cursor [%d]:\n", i);
- seq_printf(m, " CNTR: %08x\n", error->cursor[i].control);
- seq_printf(m, " POS: %08x\n", error->cursor[i].position);
- seq_printf(m, " BASE: %08x\n", error->cursor[i].base);
+ err_printf(m, "Cursor [%d]:\n", i);
+ err_printf(m, " CNTR: %08x\n", error->cursor[i].control);
+ err_printf(m, " POS: %08x\n", error->cursor[i].position);
+ err_printf(m, " BASE: %08x\n", error->cursor[i].base);
}
}
#endif
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 70789b1b5642..b73971234013 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -52,30 +52,6 @@ static bool is_edp(struct intel_dp *intel_dp)
return intel_dig_port->base.type == INTEL_OUTPUT_EDP;
}
-/**
- * is_pch_edp - is the port on the PCH and attached to an eDP panel?
- * @intel_dp: DP struct
- *
- * Returns true if the given DP struct corresponds to a PCH DP port attached
- * to an eDP panel, false otherwise. Helpful for determining whether we
- * may need FDI resources for a given DP output or not.
- */
-static bool is_pch_edp(struct intel_dp *intel_dp)
-{
- return intel_dp->is_pch_edp;
-}
-
-/**
- * is_cpu_edp - is the port on the CPU and attached to an eDP panel?
- * @intel_dp: DP struct
- *
- * Returns true if the given DP struct corresponds to a CPU eDP port.
- */
-static bool is_cpu_edp(struct intel_dp *intel_dp)
-{
- return is_edp(intel_dp) && !is_pch_edp(intel_dp);
-}
-
static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
@@ -88,25 +64,6 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
return enc_to_intel_dp(&intel_attached_encoder(connector)->base);
}
-/**
- * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
- * @encoder: DRM encoder
- *
- * Return true if @encoder corresponds to a PCH attached eDP panel. Needed
- * by intel_display.c.
- */
-bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
-{
- struct intel_dp *intel_dp;
-
- if (!encoder)
- return false;
-
- intel_dp = enc_to_intel_dp(encoder);
-
- return is_pch_edp(intel_dp);
-}
-
static void intel_dp_link_down(struct intel_dp *intel_dp);
static int
@@ -344,11 +301,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
* Note that PCH attached eDP panels should use a 125MHz input
* clock divider.
*/
- if (is_cpu_edp(intel_dp)) {
+ if (IS_VALLEYVIEW(dev)) {
+ aux_clock_divider = 100;
+ } else if (intel_dig_port->port == PORT_A) {
if (HAS_DDI(dev))
- aux_clock_divider = intel_ddi_get_cdclk_freq(dev_priv) >> 1;
- else if (IS_VALLEYVIEW(dev))
- aux_clock_divider = 100;
+ aux_clock_divider = DIV_ROUND_CLOSEST(
+ intel_ddi_get_cdclk_freq(dev_priv), 2000);
else if (IS_GEN6(dev) || IS_GEN7(dev))
aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
else
@@ -660,6 +618,49 @@ intel_dp_i2c_init(struct intel_dp *intel_dp,
return ret;
}
+static void
+intel_dp_set_clock(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config, int link_bw)
+{
+ struct drm_device *dev = encoder->base.dev;
+
+ if (IS_G4X(dev)) {
+ if (link_bw == DP_LINK_BW_1_62) {
+ pipe_config->dpll.p1 = 2;
+ pipe_config->dpll.p2 = 10;
+ pipe_config->dpll.n = 2;
+ pipe_config->dpll.m1 = 23;
+ pipe_config->dpll.m2 = 8;
+ } else {
+ pipe_config->dpll.p1 = 1;
+ pipe_config->dpll.p2 = 10;
+ pipe_config->dpll.n = 1;
+ pipe_config->dpll.m1 = 14;
+ pipe_config->dpll.m2 = 2;
+ }
+ pipe_config->clock_set = true;
+ } else if (IS_HASWELL(dev)) {
+ /* Haswell has special-purpose DP DDI clocks. */
+ } else if (HAS_PCH_SPLIT(dev)) {
+ if (link_bw == DP_LINK_BW_1_62) {
+ pipe_config->dpll.n = 1;
+ pipe_config->dpll.p1 = 2;
+ pipe_config->dpll.p2 = 10;
+ pipe_config->dpll.m1 = 12;
+ pipe_config->dpll.m2 = 9;
+ } else {
+ pipe_config->dpll.n = 2;
+ pipe_config->dpll.p1 = 1;
+ pipe_config->dpll.p2 = 10;
+ pipe_config->dpll.m1 = 14;
+ pipe_config->dpll.m2 = 8;
+ }
+ pipe_config->clock_set = true;
+ } else if (IS_VALLEYVIEW(dev)) {
+ /* FIXME: Need to figure out optimized DP clocks for vlv. */
+ }
+}
+
bool
intel_dp_compute_config(struct intel_encoder *encoder,
struct intel_crtc_config *pipe_config)
@@ -667,17 +668,18 @@ intel_dp_compute_config(struct intel_encoder *encoder,
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
- struct drm_display_mode *mode = &pipe_config->requested_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ struct intel_crtc *intel_crtc = encoder->new_crtc;
struct intel_connector *intel_connector = intel_dp->attached_connector;
int lane_count, clock;
int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
int bpp, mode_rate;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
- int target_clock, link_avail, link_clock;
+ int link_avail, link_clock;
- if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && !is_cpu_edp(intel_dp))
+ if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
pipe_config->has_pch_encoder = true;
pipe_config->has_dp_encoder = true;
@@ -685,12 +687,13 @@ intel_dp_compute_config(struct intel_encoder *encoder,
if (is_edp(intel_dp) && intel_connector->panel.fixed_mode) {
intel_fixed_panel_mode(intel_connector->panel.fixed_mode,
adjusted_mode);
- intel_pch_panel_fitting(dev,
- intel_connector->panel.fitting_mode,
- mode, adjusted_mode);
+ if (!HAS_PCH_SPLIT(dev))
+ intel_gmch_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.fitting_mode);
+ else
+ intel_pch_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.fitting_mode);
}
- /* We need to take the panel's fixed mode into account. */
- target_clock = adjusted_mode->clock;
if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
return false;
@@ -701,12 +704,12 @@ intel_dp_compute_config(struct intel_encoder *encoder,
/* Walk through all bpp values. Luckily they're all nicely spaced with 2
* bpc in between. */
- bpp = min_t(int, 8*3, pipe_config->pipe_bpp);
- if (is_edp(intel_dp) && dev_priv->edp.bpp)
- bpp = min_t(int, bpp, dev_priv->edp.bpp);
+ bpp = pipe_config->pipe_bpp;
+ if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp)
+ bpp = min_t(int, bpp, dev_priv->vbt.edp_bpp);
for (; bpp >= 6*3; bpp -= 2*3) {
- mode_rate = intel_dp_link_required(target_clock, bpp);
+ mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp);
for (clock = 0; clock <= max_clock; clock++) {
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
@@ -741,20 +744,21 @@ found:
intel_dp->link_bw = bws[clock];
intel_dp->lane_count = lane_count;
- adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
pipe_config->pipe_bpp = bpp;
- pipe_config->pixel_target_clock = target_clock;
+ pipe_config->port_clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw);
DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n",
intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock, bpp);
+ pipe_config->port_clock, bpp);
DRM_DEBUG_KMS("DP link bw required %i available %i\n",
mode_rate, link_avail);
intel_link_compute_m_n(bpp, lane_count,
- target_clock, adjusted_mode->clock,
+ adjusted_mode->clock, pipe_config->port_clock,
&pipe_config->dp_m_n);
+ intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw);
+
return true;
}
@@ -773,24 +777,28 @@ void intel_dp_init_link_config(struct intel_dp *intel_dp)
}
}
-static void ironlake_set_pll_edp(struct drm_crtc *crtc, int clock)
+static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
{
- struct drm_device *dev = crtc->dev;
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
+ struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpa_ctl;
- DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", clock);
+ DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", crtc->config.port_clock);
dpa_ctl = I915_READ(DP_A);
dpa_ctl &= ~DP_PLL_FREQ_MASK;
- if (clock < 200000) {
+ if (crtc->config.port_clock == 162000) {
/* For a long time we've carried around a ILK-DevA w/a for the
* 160MHz clock. If we're really unlucky, it's still required.
*/
DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n");
dpa_ctl |= DP_PLL_FREQ_160MHZ;
+ intel_dp->DP |= DP_PLL_FREQ_160MHZ;
} else {
dpa_ctl |= DP_PLL_FREQ_270MHZ;
+ intel_dp->DP |= DP_PLL_FREQ_270MHZ;
}
I915_WRITE(DP_A, dpa_ctl);
@@ -806,8 +814,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
- struct drm_crtc *crtc = encoder->crtc;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
/*
* There are four kinds of DP registers:
@@ -833,21 +841,11 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/* Handle DP bits in common between all three register formats */
intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
+ intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count);
- switch (intel_dp->lane_count) {
- case 1:
- intel_dp->DP |= DP_PORT_WIDTH_1;
- break;
- case 2:
- intel_dp->DP |= DP_PORT_WIDTH_2;
- break;
- case 4:
- intel_dp->DP |= DP_PORT_WIDTH_4;
- break;
- }
if (intel_dp->has_audio) {
DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
- pipe_name(intel_crtc->pipe));
+ pipe_name(crtc->pipe));
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
intel_write_eld(encoder, adjusted_mode);
}
@@ -856,7 +854,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
/* Split out the IBX/CPU vs CPT settings */
- if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
+ if (port == PORT_A && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
intel_dp->DP |= DP_SYNC_HS_HIGH;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
@@ -866,14 +864,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN)
intel_dp->DP |= DP_ENHANCED_FRAMING;
- intel_dp->DP |= intel_crtc->pipe << 29;
-
- /* don't miss out required setting for eDP */
- if (adjusted_mode->clock < 200000)
- intel_dp->DP |= DP_PLL_FREQ_160MHZ;
- else
- intel_dp->DP |= DP_PLL_FREQ_270MHZ;
- } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+ intel_dp->DP |= crtc->pipe << 29;
+ } else if (!HAS_PCH_CPT(dev) || port == PORT_A) {
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
intel_dp->DP |= intel_dp->color_range;
@@ -886,22 +878,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN)
intel_dp->DP |= DP_ENHANCED_FRAMING;
- if (intel_crtc->pipe == 1)
+ if (crtc->pipe == 1)
intel_dp->DP |= DP_PIPEB_SELECT;
-
- if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
- /* don't miss out required setting for eDP */
- if (adjusted_mode->clock < 200000)
- intel_dp->DP |= DP_PLL_FREQ_160MHZ;
- else
- intel_dp->DP |= DP_PLL_FREQ_270MHZ;
- }
} else {
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
}
- if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
- ironlake_set_pll_edp(crtc, adjusted_mode->clock);
+ if (port == PORT_A && !IS_VALLEYVIEW(dev))
+ ironlake_set_pll_cpu_edp(intel_dp);
}
#define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK)
@@ -1290,6 +1274,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ enum port port = dp_to_dig_port(intel_dp)->port;
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 tmp = I915_READ(intel_dp->output_reg);
@@ -1297,9 +1282,9 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
if (!(tmp & DP_PORT_EN))
return false;
- if (is_cpu_edp(intel_dp) && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
+ if (port == PORT_A && IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) {
*pipe = PORT_TO_PIPE_CPT(tmp);
- } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+ } else if (!HAS_PCH_CPT(dev) || port == PORT_A) {
*pipe = PORT_TO_PIPE(tmp);
} else {
u32 trans_sel;
@@ -1335,9 +1320,48 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
return true;
}
+static void intel_dp_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ u32 tmp, flags = 0;
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+
+ if ((port == PORT_A) || !HAS_PCH_CPT(dev)) {
+ tmp = I915_READ(intel_dp->output_reg);
+ if (tmp & DP_SYNC_HS_HIGH)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (tmp & DP_SYNC_VS_HIGH)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+ } else {
+ tmp = I915_READ(TRANS_DP_CTL(crtc->pipe));
+ if (tmp & TRANS_DP_HSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (tmp & TRANS_DP_VSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+ }
+
+ pipe_config->adjusted_mode.flags |= flags;
+}
+
static void intel_disable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ enum port port = dp_to_dig_port(intel_dp)->port;
+ struct drm_device *dev = encoder->base.dev;
/* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */
@@ -1347,16 +1371,17 @@ static void intel_disable_dp(struct intel_encoder *encoder)
ironlake_edp_panel_off(intel_dp);
/* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
- if (!is_cpu_edp(intel_dp))
+ if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
intel_dp_link_down(intel_dp);
}
static void intel_post_disable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ enum port port = dp_to_dig_port(intel_dp)->port;
struct drm_device *dev = encoder->base.dev;
- if (is_cpu_edp(intel_dp)) {
+ if (port == PORT_A || IS_VALLEYVIEW(dev)) {
intel_dp_link_down(intel_dp);
if (!IS_VALLEYVIEW(dev))
ironlake_edp_pll_off(intel_dp);
@@ -1381,15 +1406,73 @@ static void intel_enable_dp(struct intel_encoder *encoder)
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
ironlake_edp_backlight_on(intel_dp);
+
+ if (IS_VALLEYVIEW(dev)) {
+ struct intel_digital_port *dport =
+ enc_to_dig_port(&encoder->base);
+ int channel = vlv_dport_to_channel(dport);
+
+ vlv_wait_port_ready(dev_priv, channel);
+ }
}
static void intel_pre_enable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+ struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
- if (is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev))
+ if (dport->port == PORT_A && !IS_VALLEYVIEW(dev))
ironlake_edp_pll_on(intel_dp);
+
+ if (IS_VALLEYVIEW(dev)) {
+ struct intel_crtc *intel_crtc =
+ to_intel_crtc(encoder->base.crtc);
+ int port = vlv_dport_to_channel(dport);
+ int pipe = intel_crtc->pipe;
+ u32 val;
+
+ val = vlv_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
+ val = 0;
+ if (pipe)
+ val |= (1<<21);
+ else
+ val &= ~(1<<21);
+ val |= 0x001000c4;
+ vlv_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
+
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
+ 0x00760018);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
+ 0x00400888);
+ }
+}
+
+static void intel_dp_pre_pll_enable(struct intel_encoder *encoder)
+{
+ struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int port = vlv_dport_to_channel(dport);
+
+ if (!IS_VALLEYVIEW(dev))
+ return;
+
+ /* Program Tx lane resets to default */
+ vlv_dpio_write(dev_priv, DPIO_PCS_TX(port),
+ DPIO_PCS_TX_LANE2_RESET |
+ DPIO_PCS_TX_LANE1_RESET);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port),
+ DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
+ DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
+ (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
+ DPIO_PCS_CLK_SOFT_RESET);
+
+ /* Fix up inter-pair skew failure */
+ vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
+ vlv_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
+ vlv_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
}
/*
@@ -1451,10 +1534,13 @@ static uint8_t
intel_dp_voltage_max(struct intel_dp *intel_dp)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ enum port port = dp_to_dig_port(intel_dp)->port;
- if (IS_GEN7(dev) && is_cpu_edp(intel_dp))
+ if (IS_VALLEYVIEW(dev))
+ return DP_TRAIN_VOLTAGE_SWING_1200;
+ else if (IS_GEN7(dev) && port == PORT_A)
return DP_TRAIN_VOLTAGE_SWING_800;
- else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+ else if (HAS_PCH_CPT(dev) && port != PORT_A)
return DP_TRAIN_VOLTAGE_SWING_1200;
else
return DP_TRAIN_VOLTAGE_SWING_800;
@@ -1464,6 +1550,7 @@ static uint8_t
intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
{
struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ enum port port = dp_to_dig_port(intel_dp)->port;
if (HAS_DDI(dev)) {
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
@@ -1477,7 +1564,19 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
default:
return DP_TRAIN_PRE_EMPHASIS_0;
}
- } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev)) {
+ switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ return DP_TRAIN_PRE_EMPHASIS_9_5;
+ case DP_TRAIN_VOLTAGE_SWING_600:
+ return DP_TRAIN_PRE_EMPHASIS_6;
+ case DP_TRAIN_VOLTAGE_SWING_800:
+ return DP_TRAIN_PRE_EMPHASIS_3_5;
+ case DP_TRAIN_VOLTAGE_SWING_1200:
+ default:
+ return DP_TRAIN_PRE_EMPHASIS_0;
+ }
+ } else if (IS_GEN7(dev) && port == PORT_A) {
switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
case DP_TRAIN_VOLTAGE_SWING_400:
return DP_TRAIN_PRE_EMPHASIS_6;
@@ -1502,6 +1601,101 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
}
}
+static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_digital_port *dport = dp_to_dig_port(intel_dp);
+ unsigned long demph_reg_value, preemph_reg_value,
+ uniqtranscale_reg_value;
+ uint8_t train_set = intel_dp->train_set[0];
+ int port = vlv_dport_to_channel(dport);
+
+ switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
+ case DP_TRAIN_PRE_EMPHASIS_0:
+ preemph_reg_value = 0x0004000;
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ demph_reg_value = 0x2B405555;
+ uniqtranscale_reg_value = 0x552AB83A;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_600:
+ demph_reg_value = 0x2B404040;
+ uniqtranscale_reg_value = 0x5548B83A;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_800:
+ demph_reg_value = 0x2B245555;
+ uniqtranscale_reg_value = 0x5560B83A;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_1200:
+ demph_reg_value = 0x2B405555;
+ uniqtranscale_reg_value = 0x5598DA3A;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case DP_TRAIN_PRE_EMPHASIS_3_5:
+ preemph_reg_value = 0x0002000;
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ demph_reg_value = 0x2B404040;
+ uniqtranscale_reg_value = 0x5552B83A;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_600:
+ demph_reg_value = 0x2B404848;
+ uniqtranscale_reg_value = 0x5580B83A;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_800:
+ demph_reg_value = 0x2B404040;
+ uniqtranscale_reg_value = 0x55ADDA3A;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case DP_TRAIN_PRE_EMPHASIS_6:
+ preemph_reg_value = 0x0000000;
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ demph_reg_value = 0x2B305555;
+ uniqtranscale_reg_value = 0x5570B83A;
+ break;
+ case DP_TRAIN_VOLTAGE_SWING_600:
+ demph_reg_value = 0x2B2B4040;
+ uniqtranscale_reg_value = 0x55ADDA3A;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case DP_TRAIN_PRE_EMPHASIS_9_5:
+ preemph_reg_value = 0x0006000;
+ switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
+ case DP_TRAIN_VOLTAGE_SWING_400:
+ demph_reg_value = 0x1B405555;
+ uniqtranscale_reg_value = 0x55ADDA3A;
+ break;
+ default:
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x00000000);
+ vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port), demph_reg_value);
+ vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
+ uniqtranscale_reg_value);
+ vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port), 0x0C782040);
+ vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port), preemph_reg_value);
+ vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0x80000000);
+
+ return 0;
+}
+
static void
intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
{
@@ -1669,6 +1863,7 @@ static void
intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ enum port port = intel_dig_port->port;
struct drm_device *dev = intel_dig_port->base.base.dev;
uint32_t signal_levels, mask;
uint8_t train_set = intel_dp->train_set[0];
@@ -1676,10 +1871,13 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
if (HAS_DDI(dev)) {
signal_levels = intel_hsw_signal_levels(train_set);
mask = DDI_BUF_EMP_MASK;
- } else if (IS_GEN7(dev) && is_cpu_edp(intel_dp) && !IS_VALLEYVIEW(dev)) {
+ } else if (IS_VALLEYVIEW(dev)) {
+ signal_levels = intel_vlv_signal_levels(intel_dp);
+ mask = 0;
+ } else if (IS_GEN7(dev) && port == PORT_A) {
signal_levels = intel_gen7_edp_signal_levels(train_set);
mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB;
- } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
+ } else if (IS_GEN6(dev) && port == PORT_A) {
signal_levels = intel_gen6_edp_signal_levels(train_set);
mask = EDP_LINK_TRAIN_VOL_EMP_MASK_SNB;
} else {
@@ -1729,8 +1927,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
}
I915_WRITE(DP_TP_CTL(port), temp);
- } else if (HAS_PCH_CPT(dev) &&
- (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
+ } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT;
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
@@ -1981,6 +2178,7 @@ static void
intel_dp_link_down(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ enum port port = intel_dig_port->port;
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc =
@@ -2010,7 +2208,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("\n");
- if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
+ if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
DP &= ~DP_LINK_TRAIN_MASK_CPT;
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
} else {
@@ -2301,11 +2499,10 @@ intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
return NULL;
size = (intel_connector->edid->extensions + 1) * EDID_LENGTH;
- edid = kmalloc(size, GFP_KERNEL);
+ edid = kmemdup(intel_connector->edid, size, GFP_KERNEL);
if (!edid)
return NULL;
- memcpy(edid, intel_connector->edid, size);
return edid;
}
@@ -2499,15 +2696,16 @@ done:
}
static void
-intel_dp_destroy(struct drm_connector *connector)
+intel_dp_connector_destroy(struct drm_connector *connector)
{
- struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_connector *intel_connector = to_intel_connector(connector);
if (!IS_ERR_OR_NULL(intel_connector->edid))
kfree(intel_connector->edid);
- if (is_edp(intel_dp))
+ /* Can't call is_edp() since the encoder may have been destroyed
+ * already. */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
intel_panel_fini(&intel_connector->panel);
drm_sysfs_connector_remove(connector);
@@ -2541,7 +2739,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
.detect = intel_dp_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property,
- .destroy = intel_dp_destroy,
+ .destroy = intel_dp_connector_destroy,
};
static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -2588,11 +2786,11 @@ bool intel_dpd_is_edp(struct drm_device *dev)
struct child_device_config *p_child;
int i;
- if (!dev_priv->child_dev_num)
+ if (!dev_priv->vbt.child_dev_num)
return false;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
+ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+ p_child = dev_priv->vbt.child_dev + i;
if (p_child->dvo_port == PORT_IDPD &&
p_child->device_type == DEVICE_TYPE_eDP)
@@ -2670,7 +2868,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n",
cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12);
- vbt = dev_priv->edp.pps;
+ vbt = dev_priv->vbt.edp_pps;
/* Upper limits from eDP 1.3 spec. Note that we use the clunky units of
* our hw here, which are all in 100usec. */
@@ -2738,9 +2936,6 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
pp_div_reg = PIPEA_PP_DIVISOR;
}
- if (IS_VALLEYVIEW(dev))
- port_sel = I915_READ(pp_on_reg) & 0xc0000000;
-
/* And finally store the new values in the power sequencer. */
pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
(seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
@@ -2754,8 +2949,10 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
/* Haswell doesn't have any port selection bits for the panel
* power sequencer any more. */
- if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
- if (is_cpu_edp(intel_dp))
+ if (IS_VALLEYVIEW(dev)) {
+ port_sel = I915_READ(pp_on_reg) & 0xc0000000;
+ } else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) {
+ if (dp_to_dig_port(intel_dp)->port == PORT_A)
port_sel = PANEL_POWER_PORT_DP_A;
else
port_sel = PANEL_POWER_PORT_DP_D;
@@ -2773,7 +2970,85 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
I915_READ(pp_div_reg));
}
-void
+static bool intel_edp_init_connector(struct intel_dp *intel_dp,
+ struct intel_connector *intel_connector)
+{
+ struct drm_connector *connector = &intel_connector->base;
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_display_mode *fixed_mode = NULL;
+ struct edp_power_seq power_seq = { 0 };
+ bool has_dpcd;
+ struct drm_display_mode *scan;
+ struct edid *edid;
+
+ if (!is_edp(intel_dp))
+ return true;
+
+ intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+
+ /* Cache DPCD and EDID for edp. */
+ ironlake_edp_panel_vdd_on(intel_dp);
+ has_dpcd = intel_dp_get_dpcd(intel_dp);
+ ironlake_edp_panel_vdd_off(intel_dp, false);
+
+ if (has_dpcd) {
+ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
+ dev_priv->no_aux_handshake =
+ intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
+ DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
+ } else {
+ /* if this fails, presume the device is a ghost */
+ DRM_INFO("failed to retrieve link info, disabling eDP\n");
+ return false;
+ }
+
+ /* We now know it's not a ghost, init power sequence regs. */
+ intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
+ &power_seq);
+
+ ironlake_edp_panel_vdd_on(intel_dp);
+ edid = drm_get_edid(connector, &intel_dp->adapter);
+ if (edid) {
+ if (drm_add_edid_modes(connector, edid)) {
+ drm_mode_connector_update_edid_property(connector,
+ edid);
+ drm_edid_to_eld(connector, edid);
+ } else {
+ kfree(edid);
+ edid = ERR_PTR(-EINVAL);
+ }
+ } else {
+ edid = ERR_PTR(-ENOENT);
+ }
+ intel_connector->edid = edid;
+
+ /* prefer fixed mode from EDID if available */
+ list_for_each_entry(scan, &connector->probed_modes, head) {
+ if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
+ fixed_mode = drm_mode_duplicate(dev, scan);
+ break;
+ }
+ }
+
+ /* fallback to VBT if available for eDP */
+ if (!fixed_mode && dev_priv->vbt.lfp_lvds_vbt_mode) {
+ fixed_mode = drm_mode_duplicate(dev,
+ dev_priv->vbt.lfp_lvds_vbt_mode);
+ if (fixed_mode)
+ fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
+ }
+
+ ironlake_edp_panel_vdd_off(intel_dp, false);
+
+ intel_panel_init(&intel_connector->panel, fixed_mode);
+ intel_panel_setup_backlight(connector);
+
+ return true;
+}
+
+bool
intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector)
{
@@ -2782,38 +3057,47 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_encoder *intel_encoder = &intel_dig_port->base;
struct drm_device *dev = intel_encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *fixed_mode = NULL;
- struct edp_power_seq power_seq = { 0 };
enum port port = intel_dig_port->port;
const char *name = NULL;
- int type;
+ int type, error;
/* Preserve the current hw state. */
intel_dp->DP = I915_READ(intel_dp->output_reg);
intel_dp->attached_connector = intel_connector;
- if (HAS_PCH_SPLIT(dev) && port == PORT_D)
- if (intel_dpd_is_edp(dev))
- intel_dp->is_pch_edp = true;
-
+ type = DRM_MODE_CONNECTOR_DisplayPort;
/*
* FIXME : We need to initialize built-in panels before external panels.
* For X0, DP_C is fixed as eDP. Revisit this as part of VLV eDP cleanup
*/
- if (IS_VALLEYVIEW(dev) && port == PORT_C) {
- type = DRM_MODE_CONNECTOR_eDP;
- intel_encoder->type = INTEL_OUTPUT_EDP;
- } else if (port == PORT_A || is_pch_edp(intel_dp)) {
+ switch (port) {
+ case PORT_A:
type = DRM_MODE_CONNECTOR_eDP;
- intel_encoder->type = INTEL_OUTPUT_EDP;
- } else {
- /* The intel_encoder->type value may be INTEL_OUTPUT_UNKNOWN for
- * DDI or INTEL_OUTPUT_DISPLAYPORT for the older gens, so don't
- * rewrite it.
- */
- type = DRM_MODE_CONNECTOR_DisplayPort;
+ break;
+ case PORT_C:
+ if (IS_VALLEYVIEW(dev))
+ type = DRM_MODE_CONNECTOR_eDP;
+ break;
+ case PORT_D:
+ if (HAS_PCH_SPLIT(dev) && intel_dpd_is_edp(dev))
+ type = DRM_MODE_CONNECTOR_eDP;
+ break;
+ default: /* silence GCC warning */
+ break;
}
+ /*
+ * For eDP we always set the encoder type to INTEL_OUTPUT_EDP, but
+ * for DP the encoder type can be set by the caller to
+ * INTEL_OUTPUT_UNKNOWN for DDI, so don't rewrite it.
+ */
+ if (type == DRM_MODE_CONNECTOR_eDP)
+ intel_encoder->type = INTEL_OUTPUT_EDP;
+
+ DRM_DEBUG_KMS("Adding %s connector on port %c\n",
+ type == DRM_MODE_CONNECTOR_eDP ? "eDP" : "DP",
+ port_name(port));
+
drm_connector_init(dev, connector, &intel_dp_connector_funcs, type);
drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
@@ -2873,74 +3157,21 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
BUG();
}
- if (is_edp(intel_dp))
- intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-
- intel_dp_i2c_init(intel_dp, intel_connector, name);
-
- /* Cache DPCD and EDID for edp. */
- if (is_edp(intel_dp)) {
- bool ret;
- struct drm_display_mode *scan;
- struct edid *edid;
-
- ironlake_edp_panel_vdd_on(intel_dp);
- ret = intel_dp_get_dpcd(intel_dp);
- ironlake_edp_panel_vdd_off(intel_dp, false);
+ error = intel_dp_i2c_init(intel_dp, intel_connector, name);
+ WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
+ error, port_name(port));
- if (ret) {
- if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
- dev_priv->no_aux_handshake =
- intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
- DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
- } else {
- /* if this fails, presume the device is a ghost */
- DRM_INFO("failed to retrieve link info, disabling eDP\n");
- intel_dp_encoder_destroy(&intel_encoder->base);
- intel_dp_destroy(connector);
- return;
- }
-
- /* We now know it's not a ghost, init power sequence regs. */
- intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
- &power_seq);
-
- ironlake_edp_panel_vdd_on(intel_dp);
- edid = drm_get_edid(connector, &intel_dp->adapter);
- if (edid) {
- if (drm_add_edid_modes(connector, edid)) {
- drm_mode_connector_update_edid_property(connector, edid);
- drm_edid_to_eld(connector, edid);
- } else {
- kfree(edid);
- edid = ERR_PTR(-EINVAL);
- }
- } else {
- edid = ERR_PTR(-ENOENT);
+ if (!intel_edp_init_connector(intel_dp, intel_connector)) {
+ i2c_del_adapter(&intel_dp->adapter);
+ if (is_edp(intel_dp)) {
+ cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+ mutex_lock(&dev->mode_config.mutex);
+ ironlake_panel_vdd_off_sync(intel_dp);
+ mutex_unlock(&dev->mode_config.mutex);
}
- intel_connector->edid = edid;
-
- /* prefer fixed mode from EDID if available */
- list_for_each_entry(scan, &connector->probed_modes, head) {
- if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
- fixed_mode = drm_mode_duplicate(dev, scan);
- break;
- }
- }
-
- /* fallback to VBT if available for eDP */
- if (!fixed_mode && dev_priv->lfp_lvds_vbt_mode) {
- fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
- if (fixed_mode)
- fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
- }
-
- ironlake_edp_panel_vdd_off(intel_dp, false);
- }
-
- if (is_edp(intel_dp)) {
- intel_panel_init(&intel_connector->panel, fixed_mode);
- intel_panel_setup_backlight(connector);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ return false;
}
intel_dp_add_properties(intel_dp, connector);
@@ -2953,6 +3184,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
u32 temp = I915_READ(PEG_BAND_GAP_DATA);
I915_WRITE(PEG_BAND_GAP_DATA, (temp & ~0xf) | 0xd);
}
+
+ return true;
}
void
@@ -2986,6 +3219,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_encoder->disable = intel_disable_dp;
intel_encoder->post_disable = intel_post_disable_dp;
intel_encoder->get_hw_state = intel_dp_get_hw_state;
+ intel_encoder->get_config = intel_dp_get_config;
+ if (IS_VALLEYVIEW(dev))
+ intel_encoder->pre_pll_enable = intel_dp_pre_pll_enable;
intel_dig_port->port = port;
intel_dig_port->dp.output_reg = output_reg;
@@ -2995,5 +3231,9 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
intel_encoder->cloneable = false;
intel_encoder->hot_plug = intel_dp_hot_plug;
- intel_dp_init_connector(intel_dig_port, intel_connector);
+ if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
+ drm_encoder_cleanup(encoder);
+ kfree(intel_dig_port);
+ kfree(intel_connector);
+ }
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 624a9e6b8d71..c8c9b6f48230 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -120,7 +120,6 @@ struct intel_encoder {
struct intel_crtc *new_crtc;
int type;
- bool needs_tv_clock;
/*
* Intel hw has only one MUX where encoders could be clone, hence a
* simple flag is enough to compute the possible_clones mask.
@@ -140,6 +139,12 @@ struct intel_encoder {
* the encoder is active. If the encoder is enabled it also set the pipe
* it is connected to in the pipe parameter. */
bool (*get_hw_state)(struct intel_encoder *, enum pipe *pipe);
+ /* Reconstructs the equivalent mode flags for the current hardware
+ * state. This must be called _after_ display->get_pipe_config has
+ * pre-filled the pipe config. Note that intel_encoder->base.crtc must
+ * be set correctly before calling this function. */
+ void (*get_config)(struct intel_encoder *,
+ struct intel_crtc_config *pipe_config);
int crtc_mask;
enum hpd_pin hpd_pin;
};
@@ -177,7 +182,30 @@ struct intel_connector {
u8 polled;
};
+typedef struct dpll {
+ /* given values */
+ int n;
+ int m1, m2;
+ int p1, p2;
+ /* derived values */
+ int dot;
+ int vco;
+ int m;
+ int p;
+} intel_clock_t;
+
struct intel_crtc_config {
+ /**
+ * quirks - bitfield with hw state readout quirks
+ *
+ * For various reasons the hw state readout code might not be able to
+ * completely faithfully read out the current state. These cases are
+ * tracked with quirk flags so that fastboot and state checker can act
+ * accordingly.
+ */
+#define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */
+ unsigned long quirks;
+
struct drm_display_mode requested_mode;
struct drm_display_mode adjusted_mode;
/* This flag must be set by the encoder's compute_config callback if it
@@ -201,29 +229,67 @@ struct intel_crtc_config {
/* DP has a bunch of special case unfortunately, so mark the pipe
* accordingly. */
bool has_dp_encoder;
+
+ /*
+ * Enable dithering, used when the selected pipe bpp doesn't match the
+ * plane bpp.
+ */
bool dither;
/* Controls for the clock computation, to override various stages. */
bool clock_set;
+ /* SDVO TV has a bunch of special case. To make multifunction encoders
+ * work correctly, we need to track this at runtime.*/
+ bool sdvo_tv_clock;
+
+ /*
+ * crtc bandwidth limit, don't increase pipe bpp or clock if not really
+ * required. This is set in the 2nd loop of calling encoder's
+ * ->compute_config if the first pick doesn't work out.
+ */
+ bool bw_constrained;
+
/* Settings for the intel dpll used on pretty much everything but
* haswell. */
- struct dpll {
- unsigned n;
- unsigned m1, m2;
- unsigned p1, p2;
- } dpll;
+ struct dpll dpll;
+
+ /* Selected dpll when shared or DPLL_ID_PRIVATE. */
+ enum intel_dpll_id shared_dpll;
+
+ /* Actual register state of the dpll, for shared dpll cross-checking. */
+ struct intel_dpll_hw_state dpll_hw_state;
int pipe_bpp;
struct intel_link_m_n dp_m_n;
- /**
- * This is currently used by DP and HDMI encoders since those can have a
- * target pixel clock != the port link clock (which is currently stored
- * in adjusted_mode->clock).
+
+ /*
+ * Frequence the dpll for the port should run at. Differs from the
+ * adjusted dotclock e.g. for DP or 12bpc hdmi mode.
*/
- int pixel_target_clock;
+ int port_clock;
+
/* Used by SDVO (and if we ever fix it, HDMI). */
unsigned pixel_multiplier;
+
+ /* Panel fitter controls for gen2-gen4 + VLV */
+ struct {
+ u32 control;
+ u32 pgm_ratios;
+ u32 lvds_border_bits;
+ } gmch_pfit;
+
+ /* Panel fitter placement and size for Ironlake+ */
+ struct {
+ u32 pos;
+ u32 size;
+ } pch_pfit;
+
+ /* FDI configuration, only valid if has_pch_encoder is set. */
+ int fdi_lanes;
+ struct intel_link_m_n fdi_m_n;
+
+ bool ips_enabled;
};
struct intel_crtc {
@@ -242,7 +308,6 @@ struct intel_crtc {
bool lowfreq_avail;
struct intel_overlay *overlay;
struct intel_unpin_work *unpin_work;
- int fdi_lanes;
atomic_t unpin_work_count;
@@ -259,12 +324,14 @@ struct intel_crtc {
struct intel_crtc_config config;
- /* We can share PLLs across outputs if the timings match */
- struct intel_pch_pll *pch_pll;
uint32_t ddi_pll_sel;
/* reset counter value when the last flip was submitted */
unsigned int reset_counter;
+
+ /* Access to these should be protected by dev_priv->irq_lock. */
+ bool cpu_fifo_underrun_disabled;
+ bool pch_fifo_underrun_disabled;
};
struct intel_plane {
@@ -279,6 +346,18 @@ struct intel_plane {
unsigned int crtc_w, crtc_h;
uint32_t src_x, src_y;
uint32_t src_w, src_h;
+
+ /* Since we need to change the watermarks before/after
+ * enabling/disabling the planes, we need to store the parameters here
+ * as the other pieces of the struct may not reflect the values we want
+ * for the watermark calculations. Currently only Haswell uses this.
+ */
+ struct {
+ bool enable;
+ uint8_t bytes_per_pixel;
+ uint32_t horiz_pixels;
+ } wm;
+
void (*update_plane)(struct drm_plane *plane,
struct drm_framebuffer *fb,
struct drm_i915_gem_object *obj,
@@ -411,7 +490,6 @@ struct intel_dp {
uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
struct i2c_adapter adapter;
struct i2c_algo_dp_aux_data algo;
- bool is_pch_edp;
uint8_t train_set[4];
int panel_power_up_delay;
int panel_power_down_delay;
@@ -431,6 +509,19 @@ struct intel_digital_port {
struct intel_hdmi hdmi;
};
+static inline int
+vlv_dport_to_channel(struct intel_digital_port *dport)
+{
+ switch (dport->port) {
+ case PORT_B:
+ return 0;
+ case PORT_C:
+ return 1;
+ default:
+ BUG();
+ }
+}
+
static inline struct drm_crtc *
intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
{
@@ -474,6 +565,7 @@ int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
extern void intel_attach_force_audio_property(struct drm_connector *connector);
extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
+extern bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
extern void intel_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev,
int hdmi_reg, enum port port);
@@ -488,13 +580,14 @@ extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
extern void intel_mark_busy(struct drm_device *dev);
-extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj);
+extern void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *ring);
extern void intel_mark_idle(struct drm_device *dev);
-extern bool intel_lvds_init(struct drm_device *dev);
+extern void intel_lvds_init(struct drm_device *dev);
extern bool intel_is_dual_link_lvds(struct drm_device *dev);
extern void intel_dp_init(struct drm_device *dev, int output_reg,
enum port port);
-extern void intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
+extern bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
extern void intel_dp_init_link_config(struct intel_dp *intel_dp);
extern void intel_dp_start_link_train(struct intel_dp *intel_dp);
@@ -512,7 +605,6 @@ extern void ironlake_edp_panel_on(struct intel_dp *intel_dp);
extern void ironlake_edp_panel_off(struct intel_dp *intel_dp);
extern void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp);
extern void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
-extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane);
extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane);
@@ -524,12 +616,14 @@ extern void intel_panel_fini(struct intel_panel *panel);
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
-extern void intel_pch_panel_fitting(struct drm_device *dev,
- int fitting_mode,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
-extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
+extern void intel_pch_panel_fitting(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config,
+ int fitting_mode);
+extern void intel_gmch_panel_fitting(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config,
+ int fitting_mode);
+extern void intel_panel_set_backlight(struct drm_device *dev,
+ u32 level, u32 max);
extern int intel_panel_setup_backlight(struct drm_connector *connector);
extern void intel_panel_enable_backlight(struct drm_device *dev,
enum pipe pipe);
@@ -553,11 +647,11 @@ extern void intel_crtc_load_lut(struct drm_crtc *crtc);
extern void intel_crtc_update_dpms(struct drm_crtc *crtc);
extern void intel_encoder_destroy(struct drm_encoder *encoder);
extern void intel_encoder_dpms(struct intel_encoder *encoder, int mode);
-extern bool intel_encoder_check_is_cloned(struct intel_encoder *encoder);
extern void intel_connector_dpms(struct drm_connector *, int mode);
extern bool intel_connector_get_hw_state(struct intel_connector *connector);
extern void intel_modeset_check_state(struct drm_device *dev);
extern void intel_plane_restore(struct drm_plane *plane);
+extern void intel_plane_disable(struct drm_plane *plane);
static inline struct intel_encoder *intel_attached_encoder(struct drm_connector *connector)
@@ -565,19 +659,17 @@ static inline struct intel_encoder *intel_attached_encoder(struct drm_connector
return to_intel_connector(connector)->encoder;
}
-static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
-{
- struct intel_digital_port *intel_dig_port =
- container_of(encoder, struct intel_digital_port, base.base);
- return &intel_dig_port->dp;
-}
-
static inline struct intel_digital_port *
enc_to_dig_port(struct drm_encoder *encoder)
{
return container_of(encoder, struct intel_digital_port, base.base);
}
+static inline struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
+{
+ return &enc_to_dig_port(encoder)->dp;
+}
+
static inline struct intel_digital_port *
dp_to_dig_port(struct intel_dp *intel_dp)
{
@@ -607,6 +699,7 @@ intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
extern int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp);
+extern void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port);
struct intel_load_detect_pipe {
struct drm_framebuffer *release_fb;
@@ -660,13 +753,9 @@ extern void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
#define assert_pipe_disabled(d, p) assert_pipe(d, p, false)
extern void intel_init_clock_gating(struct drm_device *dev);
+extern void intel_suspend_hw(struct drm_device *dev);
extern void intel_write_eld(struct drm_encoder *encoder,
struct drm_display_mode *mode);
-extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
-extern void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
- struct intel_link_m_n *m_n);
-extern void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
- struct intel_link_m_n *m_n);
extern void intel_prepare_ddi(struct drm_device *dev);
extern void hsw_fdi_link_train(struct drm_crtc *crtc);
extern void intel_ddi_init(struct drm_device *dev, enum port port);
@@ -675,9 +764,7 @@ extern void intel_ddi_init(struct drm_device *dev, enum port port);
extern void intel_update_watermarks(struct drm_device *dev);
extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
uint32_t sprite_width,
- int pixel_size);
-extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe,
- struct drm_display_mode *mode);
+ int pixel_size, bool enable);
extern unsigned long intel_gen4_compute_page_offset(int *x, int *y,
unsigned int tiling_mode,
@@ -689,8 +776,6 @@ extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg);
-
/* Power-related functions, located in intel_pm.c */
extern void intel_init_pm(struct drm_device *dev);
/* FBC */
@@ -701,7 +786,12 @@ extern void intel_update_fbc(struct drm_device *dev);
extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
extern void intel_gpu_ips_teardown(void);
-extern bool intel_using_power_well(struct drm_device *dev);
+/* Power well */
+extern int i915_init_power_well(struct drm_device *dev);
+extern void i915_remove_power_well(struct drm_device *dev);
+
+extern bool intel_display_power_enabled(struct drm_device *dev,
+ enum intel_display_power_domain domain);
extern void intel_init_power_well(struct drm_device *dev);
extern void intel_set_power_well(struct drm_device *dev, bool enable);
extern void intel_enable_gt_powersave(struct drm_device *dev);
@@ -719,7 +809,7 @@ extern void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
extern void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc);
extern void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc);
extern void intel_ddi_setup_hw_pll_state(struct drm_device *dev);
-extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc, int clock);
+extern bool intel_ddi_pll_mode_set(struct drm_crtc *crtc);
extern void intel_ddi_put_crtc_pll(struct drm_crtc *crtc);
extern void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
extern void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
@@ -728,5 +818,11 @@ intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
extern void intel_display_handle_reset(struct drm_device *dev);
+extern bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+ enum pipe pipe,
+ bool enable);
+extern bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
+ enum transcoder pch_transcoder,
+ bool enable);
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index cc70b16d5d42..eb2020eb2b7e 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -54,6 +54,13 @@ static const struct intel_dvo_device intel_dvo_devices[] = {
.dev_ops = &ch7xxx_ops,
},
{
+ .type = INTEL_DVO_CHIP_TMDS,
+ .name = "ch7xxx",
+ .dvo_reg = DVOC,
+ .slave_addr = 0x75, /* For some ch7010 */
+ .dev_ops = &ch7xxx_ops,
+ },
+ {
.type = INTEL_DVO_CHIP_LVDS,
.name = "ivch",
.dvo_reg = DVOA,
@@ -129,6 +136,26 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
return true;
}
+static void intel_dvo_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_dvo *intel_dvo = enc_to_intel_dvo(&encoder->base);
+ u32 tmp, flags = 0;
+
+ tmp = I915_READ(intel_dvo->dev.dvo_reg);
+ if (tmp & DVO_HSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+ if (tmp & DVO_VSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+
+ pipe_config->adjusted_mode.flags |= flags;
+}
+
static void intel_disable_dvo(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -153,6 +180,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, true);
}
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
static void intel_dvo_dpms(struct drm_connector *connector, int mode)
{
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
@@ -174,6 +202,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
return;
}
+ /* We call connector dpms manually below in case pipe dpms doesn't
+ * change due to cloning. */
if (mode == DRM_MODE_DPMS_ON) {
intel_dvo->base.connectors_active = true;
@@ -440,6 +470,7 @@ void intel_dvo_init(struct drm_device *dev)
intel_encoder->disable = intel_disable_dvo;
intel_encoder->enable = intel_enable_dvo;
intel_encoder->get_hw_state = intel_dvo_get_hw_state;
+ intel_encoder->get_config = intel_dvo_get_config;
intel_connector->get_hw_state = intel_dvo_connector_get_hw_state;
/* Now, try to find a controller */
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 6b7c3ca2c035..dff669e2387f 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -60,8 +60,9 @@ static struct fb_ops intelfb_ops = {
static int intelfb_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
- struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
- struct drm_device *dev = ifbdev->helper.dev;
+ struct intel_fbdev *ifbdev =
+ container_of(helper, struct intel_fbdev, helper);
+ struct drm_device *dev = helper->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct fb_info *info;
struct drm_framebuffer *fb;
@@ -108,7 +109,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
goto out_unpin;
}
- info->par = ifbdev;
+ info->par = helper;
ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
if (ret)
@@ -217,7 +218,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,
int intel_fbdev_init(struct drm_device *dev)
{
struct intel_fbdev *ifbdev;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
@@ -242,7 +243,7 @@ int intel_fbdev_init(struct drm_device *dev)
void intel_fbdev_initial_config(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
/* Due to peculiar init order wrt to hpd handling this is separate. */
drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
@@ -250,7 +251,7 @@ void intel_fbdev_initial_config(struct drm_device *dev)
void intel_fbdev_fini(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
if (!dev_priv->fbdev)
return;
@@ -261,7 +262,7 @@ void intel_fbdev_fini(struct drm_device *dev)
void intel_fbdev_set_suspend(struct drm_device *dev, int state)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_fbdev *ifbdev = dev_priv->fbdev;
struct fb_info *info;
@@ -274,7 +275,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
* been restored from swap. If the object is stolen however, it will be
* full of whatever garbage was left in there.
*/
- if (!state && ifbdev->ifb.obj->stolen)
+ if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen)
memset_io(info->screen_base, 0, info->screen_size);
fb_set_suspend(info, state);
@@ -284,16 +285,14 @@ MODULE_LICENSE("GPL and additional rights");
void intel_fb_output_poll_changed(struct drm_device *dev)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
}
void intel_fb_restore_mode(struct drm_device *dev)
{
int ret;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_mode_config *config = &dev->mode_config;
- struct drm_plane *plane;
+ struct drm_i915_private *dev_priv = dev->dev_private;
if (INTEL_INFO(dev)->num_pipes == 0)
return;
@@ -304,10 +303,5 @@ void intel_fb_restore_mode(struct drm_device *dev)
if (ret)
DRM_DEBUG("failed to restore crtc mode\n");
- /* Be sure to shut off any planes that may be active */
- list_for_each_entry(plane, &config->plane_list, head)
- if (plane->enabled)
- plane->funcs->disable_plane(plane);
-
drm_modeset_unlock_all(dev);
}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index a9057930f2b2..98df2a0c85bd 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -602,7 +602,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
u32 hdmi_val;
hdmi_val = SDVO_ENCODING_HDMI;
- if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev))
+ if (!HAS_PCH_SPLIT(dev))
hdmi_val |= intel_hdmi->color_range;
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
hdmi_val |= SDVO_VSYNC_ACTIVE_HIGH;
@@ -658,6 +658,28 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
return true;
}
+static void intel_hdmi_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ u32 tmp, flags = 0;
+
+ tmp = I915_READ(intel_hdmi->hdmi_reg);
+
+ if (tmp & SDVO_HSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (tmp & SDVO_VSYNC_ACTIVE_HIGH)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+
+ pipe_config->adjusted_mode.flags |= flags;
+}
+
static void intel_enable_hdmi(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
@@ -697,6 +719,14 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
I915_WRITE(intel_hdmi->hdmi_reg, temp);
POSTING_READ(intel_hdmi->hdmi_reg);
}
+
+ if (IS_VALLEYVIEW(dev)) {
+ struct intel_digital_port *dport =
+ enc_to_dig_port(&encoder->base);
+ int channel = vlv_dport_to_channel(dport);
+
+ vlv_wait_port_ready(dev_priv, channel);
+ }
}
static void intel_disable_hdmi(struct intel_encoder *encoder)
@@ -775,6 +805,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2;
+ int desired_bpp;
if (intel_hdmi->color_range_auto) {
/* See CEA-861-E - 5.1 Default Encoding Parameters */
@@ -794,14 +826,29 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
/*
* HDMI is either 12 or 8, so if the display lets 10bpc sneak
* through, clamp it down. Note that g4x/vlv don't support 12bpc hdmi
- * outputs.
+ * outputs. We also need to check that the higher clock still fits
+ * within limits.
*/
- if (pipe_config->pipe_bpp > 8*3 && HAS_PCH_SPLIT(dev)) {
- DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n");
- pipe_config->pipe_bpp = 12*3;
+ if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000
+ && HAS_PCH_SPLIT(dev)) {
+ DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
+ desired_bpp = 12*3;
+
+ /* Need to adjust the port link by 1.5x for 12bpc. */
+ pipe_config->port_clock = clock_12bpc;
} else {
- DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n");
- pipe_config->pipe_bpp = 8*3;
+ DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
+ desired_bpp = 8*3;
+ }
+
+ if (!pipe_config->bw_constrained) {
+ DRM_DEBUG_KMS("forcing pipe bpc to %i for HDMI\n", desired_bpp);
+ pipe_config->pipe_bpp = desired_bpp;
+ }
+
+ if (adjusted_mode->clock > 225000) {
+ DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n");
+ return false;
}
return true;
@@ -955,6 +1002,97 @@ done:
return 0;
}
+static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
+{
+ struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc =
+ to_intel_crtc(encoder->base.crtc);
+ int port = vlv_dport_to_channel(dport);
+ int pipe = intel_crtc->pipe;
+ u32 val;
+
+ if (!IS_VALLEYVIEW(dev))
+ return;
+
+ /* Enable clock channels for this port */
+ val = vlv_dpio_read(dev_priv, DPIO_DATA_LANE_A(port));
+ val = 0;
+ if (pipe)
+ val |= (1<<21);
+ else
+ val &= ~(1<<21);
+ val |= 0x001000c4;
+ vlv_dpio_write(dev_priv, DPIO_DATA_CHANNEL(port), val);
+
+ /* HDMI 1.0V-2dB */
+ vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port), 0);
+ vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL4(port),
+ 0x2b245f5f);
+ vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL2(port),
+ 0x5578b83a);
+ vlv_dpio_write(dev_priv, DPIO_TX_SWING_CTL3(port),
+ 0x0c782040);
+ vlv_dpio_write(dev_priv, DPIO_TX3_SWING_CTL4(port),
+ 0x2b247878);
+ vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER0(port), 0x00030000);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
+ 0x00002000);
+ vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
+ DPIO_TX_OCALINIT_EN);
+
+ /* Program lane clock */
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF0(port),
+ 0x00760018);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLOCKBUF8(port),
+ 0x00400888);
+}
+
+static void intel_hdmi_pre_pll_enable(struct intel_encoder *encoder)
+{
+ struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int port = vlv_dport_to_channel(dport);
+
+ if (!IS_VALLEYVIEW(dev))
+ return;
+
+ /* Program Tx lane resets to default */
+ vlv_dpio_write(dev_priv, DPIO_PCS_TX(port),
+ DPIO_PCS_TX_LANE2_RESET |
+ DPIO_PCS_TX_LANE1_RESET);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port),
+ DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
+ DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
+ (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
+ DPIO_PCS_CLK_SOFT_RESET);
+
+ /* Fix up inter-pair skew failure */
+ vlv_dpio_write(dev_priv, DPIO_PCS_STAGGER1(port), 0x00750f00);
+ vlv_dpio_write(dev_priv, DPIO_TX_CTL(port), 0x00001500);
+ vlv_dpio_write(dev_priv, DPIO_TX_LANE(port), 0x40400000);
+
+ vlv_dpio_write(dev_priv, DPIO_PCS_CTL_OVER1(port),
+ 0x00002000);
+ vlv_dpio_write(dev_priv, DPIO_TX_OCALINIT(port),
+ DPIO_TX_OCALINIT_EN);
+}
+
+static void intel_hdmi_post_disable(struct intel_encoder *encoder)
+{
+ struct intel_digital_port *dport = enc_to_dig_port(&encoder->base);
+ struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ int port = vlv_dport_to_channel(dport);
+
+ /* Reset lanes to avoid HDMI flicker (VLV w/a) */
+ mutex_lock(&dev_priv->dpio_lock);
+ vlv_dpio_write(dev_priv, DPIO_PCS_TX(port), 0x00000000);
+ vlv_dpio_write(dev_priv, DPIO_PCS_CLK(port), 0x00e00060);
+ mutex_unlock(&dev_priv->dpio_lock);
+}
+
static void intel_hdmi_destroy(struct drm_connector *connector)
{
drm_sysfs_connector_remove(connector);
@@ -1094,6 +1232,12 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
intel_encoder->enable = intel_enable_hdmi;
intel_encoder->disable = intel_disable_hdmi;
intel_encoder->get_hw_state = intel_hdmi_get_hw_state;
+ intel_encoder->get_config = intel_hdmi_get_config;
+ if (IS_VALLEYVIEW(dev)) {
+ intel_encoder->pre_enable = intel_hdmi_pre_enable;
+ intel_encoder->pre_pll_enable = intel_hdmi_pre_pll_enable;
+ intel_encoder->post_disable = intel_hdmi_post_disable;
+ }
intel_encoder->type = INTEL_OUTPUT_HDMI;
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 29412cc89c7a..021e8daa022d 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -49,8 +49,6 @@ struct intel_lvds_connector {
struct intel_lvds_encoder {
struct intel_encoder base;
- u32 pfit_control;
- u32 pfit_pgm_ratios;
bool is_dual_link;
u32 reg;
@@ -88,6 +86,31 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
return true;
}
+static void intel_lvds_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 lvds_reg, tmp, flags = 0;
+
+ if (HAS_PCH_SPLIT(dev))
+ lvds_reg = PCH_LVDS;
+ else
+ lvds_reg = LVDS;
+
+ tmp = I915_READ(lvds_reg);
+ if (tmp & LVDS_HSYNC_POLARITY)
+ flags |= DRM_MODE_FLAG_NHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ if (tmp & LVDS_VSYNC_POLARITY)
+ flags |= DRM_MODE_FLAG_NVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_PVSYNC;
+
+ pipe_config->adjusted_mode.flags |= flags;
+}
+
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn't turn
* things on.
@@ -118,7 +141,8 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
}
/* set the corresponsding LVDS_BORDER bit */
- temp |= dev_priv->lvds_border_bits;
+ temp &= ~LVDS_BORDER_ENABLE;
+ temp |= intel_crtc->config.gmch_pfit.lvds_border_bits;
/* Set the B0-B3 data pairs corresponding to whether we're going to
* set the DPLLs for dual-channel mode or not.
*/
@@ -136,7 +160,10 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
* special lvds dither control bit on pch-split platforms, dithering is
* only controlled through the PIPECONF reg. */
if (INTEL_INFO(dev)->gen == 4) {
- if (dev_priv->lvds_dither)
+ /* Bspec wording suggests that LVDS port dithering only exists
+ * for 18bpp panels. */
+ if (intel_crtc->config.dither &&
+ intel_crtc->config.pipe_bpp == 18)
temp |= LVDS_ENABLE_DITHER;
else
temp &= ~LVDS_ENABLE_DITHER;
@@ -150,29 +177,6 @@ static void intel_pre_pll_enable_lvds(struct intel_encoder *encoder)
I915_WRITE(lvds_encoder->reg, temp);
}
-static void intel_pre_enable_lvds(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct intel_lvds_encoder *enc = to_lvds_encoder(&encoder->base);
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (HAS_PCH_SPLIT(dev) || !enc->pfit_control)
- return;
-
- /*
- * Enable automatic panel scaling so that non-native modes
- * fill the screen. The panel fitter should only be
- * adjusted whilst the pipe is disabled, according to
- * register description and PRM.
- */
- DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",
- enc->pfit_control,
- enc->pfit_pgm_ratios);
-
- I915_WRITE(PFIT_PGM_RATIOS, enc->pfit_pgm_ratios);
- I915_WRITE(PFIT_CONTROL, enc->pfit_control);
-}
-
/**
* Sets the power state for the panel.
*/
@@ -241,62 +245,6 @@ static int intel_lvds_mode_valid(struct drm_connector *connector,
return MODE_OK;
}
-static void
-centre_horizontally(struct drm_display_mode *mode,
- int width)
-{
- u32 border, sync_pos, blank_width, sync_width;
-
- /* keep the hsync and hblank widths constant */
- sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
- blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
- sync_pos = (blank_width - sync_width + 1) / 2;
-
- border = (mode->hdisplay - width + 1) / 2;
- border += border & 1; /* make the border even */
-
- mode->crtc_hdisplay = width;
- mode->crtc_hblank_start = width + border;
- mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
-
- mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
- mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
-}
-
-static void
-centre_vertically(struct drm_display_mode *mode,
- int height)
-{
- u32 border, sync_pos, blank_width, sync_width;
-
- /* keep the vsync and vblank widths constant */
- sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
- blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
- sync_pos = (blank_width - sync_width + 1) / 2;
-
- border = (mode->vdisplay - height + 1) / 2;
-
- mode->crtc_vdisplay = height;
- mode->crtc_vblank_start = height + border;
- mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
-
- mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
- mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
-}
-
-static inline u32 panel_fitter_scaling(u32 source, u32 target)
-{
- /*
- * Floating point operation is not supported. So the FACTOR
- * is defined, which can avoid the floating point computation
- * when calculating the panel ratio.
- */
-#define ACCURACY 12
-#define FACTOR (1 << ACCURACY)
- u32 ratio = source * FACTOR / target;
- return (FACTOR * ratio + FACTOR/2) / FACTOR;
-}
-
static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
struct intel_crtc_config *pipe_config)
{
@@ -307,11 +255,8 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
struct intel_connector *intel_connector =
&lvds_encoder->attached_connector->base;
struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
- struct drm_display_mode *mode = &pipe_config->requested_mode;
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
- u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
unsigned int lvds_bpp;
- int pipe;
/* Should never happen!! */
if (INTEL_INFO(dev)->gen < 4 && intel_crtc->pipe == 0) {
@@ -319,20 +264,18 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
return false;
}
- if (intel_encoder_check_is_cloned(&lvds_encoder->base))
- return false;
-
if ((I915_READ(lvds_encoder->reg) & LVDS_A3_POWER_MASK) ==
LVDS_A3_POWER_UP)
lvds_bpp = 8*3;
else
lvds_bpp = 6*3;
- if (lvds_bpp != pipe_config->pipe_bpp) {
+ if (lvds_bpp != pipe_config->pipe_bpp && !pipe_config->bw_constrained) {
DRM_DEBUG_KMS("forcing display bpp (was %d) to LVDS (%d)\n",
pipe_config->pipe_bpp, lvds_bpp);
pipe_config->pipe_bpp = lvds_bpp;
}
+
/*
* We have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,
@@ -345,139 +288,17 @@ static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
if (HAS_PCH_SPLIT(dev)) {
pipe_config->has_pch_encoder = true;
- intel_pch_panel_fitting(dev,
- intel_connector->panel.fitting_mode,
- mode, adjusted_mode);
+ intel_pch_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.fitting_mode);
return true;
+ } else {
+ intel_gmch_panel_fitting(intel_crtc, pipe_config,
+ intel_connector->panel.fitting_mode);
}
- /* Native modes don't need fitting */
- if (adjusted_mode->hdisplay == mode->hdisplay &&
- adjusted_mode->vdisplay == mode->vdisplay)
- goto out;
-
- /* 965+ wants fuzzy fitting */
- if (INTEL_INFO(dev)->gen >= 4)
- pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
- PFIT_FILTER_FUZZY);
-
- /*
- * Enable automatic panel scaling for non-native modes so that they fill
- * the screen. Should be enabled before the pipe is enabled, according
- * to register description and PRM.
- * Change the value here to see the borders for debugging
- */
- for_each_pipe(pipe)
- I915_WRITE(BCLRPAT(pipe), 0);
-
drm_mode_set_crtcinfo(adjusted_mode, 0);
pipe_config->timings_set = true;
- switch (intel_connector->panel.fitting_mode) {
- case DRM_MODE_SCALE_CENTER:
- /*
- * For centered modes, we have to calculate border widths &
- * heights and modify the values programmed into the CRTC.
- */
- centre_horizontally(adjusted_mode, mode->hdisplay);
- centre_vertically(adjusted_mode, mode->vdisplay);
- border = LVDS_BORDER_ENABLE;
- break;
-
- case DRM_MODE_SCALE_ASPECT:
- /* Scale but preserve the aspect ratio */
- if (INTEL_INFO(dev)->gen >= 4) {
- u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
- u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
-
- /* 965+ is easy, it does everything in hw */
- if (scaled_width > scaled_height)
- pfit_control |= PFIT_ENABLE | PFIT_SCALING_PILLAR;
- else if (scaled_width < scaled_height)
- pfit_control |= PFIT_ENABLE | PFIT_SCALING_LETTER;
- else if (adjusted_mode->hdisplay != mode->hdisplay)
- pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
- } else {
- u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
- u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
- /*
- * For earlier chips we have to calculate the scaling
- * ratio by hand and program it into the
- * PFIT_PGM_RATIO register
- */
- if (scaled_width > scaled_height) { /* pillar */
- centre_horizontally(adjusted_mode, scaled_height / mode->vdisplay);
-
- border = LVDS_BORDER_ENABLE;
- if (mode->vdisplay != adjusted_mode->vdisplay) {
- u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
- pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
- bits << PFIT_VERT_SCALE_SHIFT);
- pfit_control |= (PFIT_ENABLE |
- VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
- }
- } else if (scaled_width < scaled_height) { /* letter */
- centre_vertically(adjusted_mode, scaled_width / mode->hdisplay);
-
- border = LVDS_BORDER_ENABLE;
- if (mode->hdisplay != adjusted_mode->hdisplay) {
- u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
- pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
- bits << PFIT_VERT_SCALE_SHIFT);
- pfit_control |= (PFIT_ENABLE |
- VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
- }
- } else
- /* Aspects match, Let hw scale both directions */
- pfit_control |= (PFIT_ENABLE |
- VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
- VERT_INTERP_BILINEAR |
- HORIZ_INTERP_BILINEAR);
- }
- break;
-
- case DRM_MODE_SCALE_FULLSCREEN:
- /*
- * Full scaling, even if it changes the aspect ratio.
- * Fortunately this is all done for us in hw.
- */
- if (mode->vdisplay != adjusted_mode->vdisplay ||
- mode->hdisplay != adjusted_mode->hdisplay) {
- pfit_control |= PFIT_ENABLE;
- if (INTEL_INFO(dev)->gen >= 4)
- pfit_control |= PFIT_SCALING_AUTO;
- else
- pfit_control |= (VERT_AUTO_SCALE |
- VERT_INTERP_BILINEAR |
- HORIZ_AUTO_SCALE |
- HORIZ_INTERP_BILINEAR);
- }
- break;
-
- default:
- break;
- }
-
-out:
- /* If not enabling scaling, be consistent and always use 0. */
- if ((pfit_control & PFIT_ENABLE) == 0) {
- pfit_control = 0;
- pfit_pgm_ratios = 0;
- }
-
- /* Make sure pre-965 set dither correctly */
- if (INTEL_INFO(dev)->gen < 4 && dev_priv->lvds_dither)
- pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-
- if (pfit_control != lvds_encoder->pfit_control ||
- pfit_pgm_ratios != lvds_encoder->pfit_pgm_ratios) {
- lvds_encoder->pfit_control = pfit_control;
- lvds_encoder->pfit_pgm_ratios = pfit_pgm_ratios;
- }
- dev_priv->lvds_border_bits = border;
-
/*
* XXX: It would be nice to support lower refresh rates on the
* panels to reduce power consumption, and perhaps match the
@@ -869,6 +690,22 @@ static const struct dmi_system_id intel_no_lvds[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Q900"),
},
},
+ {
+ .callback = intel_no_lvds_dmi_callback,
+ .ident = "Intel D510MO",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "D510MO"),
+ },
+ },
+ {
+ .callback = intel_no_lvds_dmi_callback,
+ .ident = "Intel D525MW",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Intel"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"),
+ },
+ },
{ } /* terminating entry */
};
@@ -937,11 +774,11 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
- if (!dev_priv->child_dev_num)
+ if (!dev_priv->vbt.child_dev_num)
return true;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- struct child_device_config *child = dev_priv->child_dev + i;
+ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+ struct child_device_config *child = dev_priv->vbt.child_dev + i;
/* If the device type is not LFP, continue.
* We have to check both the new identifiers as well as the
@@ -1029,7 +866,7 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
*/
val = I915_READ(lvds_encoder->reg);
if (!(val & ~(LVDS_PIPE_MASK | LVDS_DETECTED)))
- val = dev_priv->bios_lvds_val;
+ val = dev_priv->vbt.bios_lvds_val;
return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
}
@@ -1056,7 +893,7 @@ static bool intel_lvds_supported(struct drm_device *dev)
* Create the connector, register the LVDS DDC bus, and try to figure out what
* modes we can display on the LVDS panel (if present).
*/
-bool intel_lvds_init(struct drm_device *dev)
+void intel_lvds_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_lvds_encoder *lvds_encoder;
@@ -1074,43 +911,39 @@ bool intel_lvds_init(struct drm_device *dev)
u8 pin;
if (!intel_lvds_supported(dev))
- return false;
+ return;
/* Skip init on machines we know falsely report LVDS */
if (dmi_check_system(intel_no_lvds))
- return false;
+ return;
pin = GMBUS_PORT_PANEL;
if (!lvds_is_present_in_vbt(dev, &pin)) {
DRM_DEBUG_KMS("LVDS is not present in VBT\n");
- return false;
+ return;
}
if (HAS_PCH_SPLIT(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
- return false;
- if (dev_priv->edp.support) {
+ return;
+ if (dev_priv->vbt.edp_support) {
DRM_DEBUG_KMS("disable LVDS for eDP support\n");
- return false;
+ return;
}
}
lvds_encoder = kzalloc(sizeof(struct intel_lvds_encoder), GFP_KERNEL);
if (!lvds_encoder)
- return false;
+ return;
lvds_connector = kzalloc(sizeof(struct intel_lvds_connector), GFP_KERNEL);
if (!lvds_connector) {
kfree(lvds_encoder);
- return false;
+ return;
}
lvds_encoder->attached_connector = lvds_connector;
- if (!HAS_PCH_SPLIT(dev)) {
- lvds_encoder->pfit_control = I915_READ(PFIT_CONTROL);
- }
-
intel_encoder = &lvds_encoder->base;
encoder = &intel_encoder->base;
intel_connector = &lvds_connector->base;
@@ -1122,11 +955,11 @@ bool intel_lvds_init(struct drm_device *dev)
DRM_MODE_ENCODER_LVDS);
intel_encoder->enable = intel_enable_lvds;
- intel_encoder->pre_enable = intel_pre_enable_lvds;
intel_encoder->pre_pll_enable = intel_pre_pll_enable_lvds;
intel_encoder->compute_config = intel_lvds_compute_config;
intel_encoder->disable = intel_disable_lvds;
intel_encoder->get_hw_state = intel_lvds_get_hw_state;
+ intel_encoder->get_config = intel_lvds_get_config;
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector_attach_encoder(intel_connector, intel_encoder);
@@ -1212,11 +1045,11 @@ bool intel_lvds_init(struct drm_device *dev)
}
/* Failed to get EDID, what about VBT? */
- if (dev_priv->lfp_lvds_vbt_mode) {
+ if (dev_priv->vbt.lfp_lvds_vbt_mode) {
DRM_DEBUG_KMS("using mode from VBT: ");
- drm_mode_debug_printmodeline(dev_priv->lfp_lvds_vbt_mode);
+ drm_mode_debug_printmodeline(dev_priv->vbt.lfp_lvds_vbt_mode);
- fixed_mode = drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode);
+ fixed_mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode);
if (fixed_mode) {
fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
goto out;
@@ -1277,7 +1110,7 @@ out:
intel_panel_init(&intel_connector->panel, fixed_mode);
intel_panel_setup_backlight(connector);
- return true;
+ return;
failed:
DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
@@ -1287,5 +1120,5 @@ failed:
drm_mode_destroy(dev, fixed_mode);
kfree(lvds_encoder);
kfree(lvds_connector);
- return false;
+ return;
}
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index a8117e614009..cfb8fb68f09c 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -110,6 +110,10 @@ struct opregion_asle {
u8 rsvd[102];
} __attribute__((packed));
+/* Driver readiness indicator */
+#define ASLE_ARDY_READY (1 << 0)
+#define ASLE_ARDY_NOT_READY (0 << 0)
+
/* ASLE irq request bits */
#define ASLE_SET_ALS_ILLUM (1 << 0)
#define ASLE_SET_BACKLIGHT (1 << 1)
@@ -123,6 +127,12 @@ struct opregion_asle {
#define ASLE_PFIT_FAILED (1<<14)
#define ASLE_PWM_FREQ_FAILED (1<<16)
+/* Technology enabled indicator */
+#define ASLE_TCHE_ALS_EN (1 << 0)
+#define ASLE_TCHE_BLC_EN (1 << 1)
+#define ASLE_TCHE_PFIT_EN (1 << 2)
+#define ASLE_TCHE_PFMB_EN (1 << 3)
+
/* ASLE backlight brightness to set */
#define ASLE_BCLP_VALID (1<<31)
#define ASLE_BCLP_MSK (~(1<<31))
@@ -152,7 +162,6 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
- u32 max;
DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
@@ -163,8 +172,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
if (bclp > 255)
return ASLE_BACKLIGHT_FAILED;
- max = intel_panel_get_max_backlight(dev);
- intel_panel_set_backlight(dev, bclp * max / 255);
+ intel_panel_set_backlight(dev, bclp, 255);
iowrite32((bclp*0x64)/0xff | ASLE_CBLV_VALID, &asle->cblv);
return 0;
@@ -174,29 +182,22 @@ static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
{
/* alsi is the current ALS reading in lux. 0 indicates below sensor
range, 0xffff indicates above sensor range. 1-0xfffe are valid */
- return 0;
+ DRM_DEBUG_DRIVER("Illum is not supported\n");
+ return ASLE_ALS_ILLUM_FAILED;
}
static u32 asle_set_pwm_freq(struct drm_device *dev, u32 pfmb)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- if (pfmb & ASLE_PFMB_PWM_VALID) {
- u32 blc_pwm_ctl = I915_READ(BLC_PWM_CTL);
- u32 pwm = pfmb & ASLE_PFMB_PWM_MASK;
- blc_pwm_ctl &= BACKLIGHT_DUTY_CYCLE_MASK;
- pwm = pwm >> 9;
- /* FIXME - what do we do with the PWM? */
- }
- return 0;
+ DRM_DEBUG_DRIVER("PWM freq is not supported\n");
+ return ASLE_PWM_FREQ_FAILED;
}
static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
{
/* Panel fitting is currently controlled by the X code, so this is a
noop until modesetting support works fully */
- if (!(pfit & ASLE_PFIT_VALID))
- return ASLE_PFIT_FAILED;
- return 0;
+ DRM_DEBUG_DRIVER("Pfit is not supported\n");
+ return ASLE_PFIT_FAILED;
}
void intel_opregion_asle_intr(struct drm_device *dev)
@@ -231,64 +232,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)
iowrite32(asle_stat, &asle->aslc);
}
-void intel_opregion_gse_intr(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
- u32 asle_stat = 0;
- u32 asle_req;
-
- if (!asle)
- return;
-
- asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK;
-
- if (!asle_req) {
- DRM_DEBUG_DRIVER("non asle set request??\n");
- return;
- }
-
- if (asle_req & ASLE_SET_ALS_ILLUM) {
- DRM_DEBUG_DRIVER("Illum is not supported\n");
- asle_stat |= ASLE_ALS_ILLUM_FAILED;
- }
-
- if (asle_req & ASLE_SET_BACKLIGHT)
- asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
-
- if (asle_req & ASLE_SET_PFIT) {
- DRM_DEBUG_DRIVER("Pfit is not supported\n");
- asle_stat |= ASLE_PFIT_FAILED;
- }
-
- if (asle_req & ASLE_SET_PWM_FREQ) {
- DRM_DEBUG_DRIVER("PWM freq is not supported\n");
- asle_stat |= ASLE_PWM_FREQ_FAILED;
- }
-
- iowrite32(asle_stat, &asle->aslc);
-}
-#define ASLE_ALS_EN (1<<0)
-#define ASLE_BLC_EN (1<<1)
-#define ASLE_PFIT_EN (1<<2)
-#define ASLE_PFMB_EN (1<<3)
-
-void intel_opregion_enable_asle(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
-
- if (asle) {
- if (IS_MOBILE(dev))
- intel_enable_asle(dev);
-
- iowrite32(ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
- ASLE_PFMB_EN,
- &asle->tche);
- iowrite32(1, &asle->ardy);
- }
-}
-
#define ACPI_EV_DISPLAY_SWITCH (1<<0)
#define ACPI_EV_LID (1<<1)
#define ACPI_EV_DOCK (1<<2)
@@ -368,8 +311,8 @@ static void intel_didl_outputs(struct drm_device *dev)
list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) {
if (i >= 8) {
- dev_printk(KERN_ERR, &dev->pdev->dev,
- "More than 8 outputs detected\n");
+ dev_dbg(&dev->pdev->dev,
+ "More than 8 outputs detected via ACPI\n");
return;
}
status =
@@ -395,8 +338,8 @@ blind_set:
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
int output_type = ACPI_OTHER_OUTPUT;
if (i >= 8) {
- dev_printk(KERN_ERR, &dev->pdev->dev,
- "More than 8 outputs detected\n");
+ dev_dbg(&dev->pdev->dev,
+ "More than 8 outputs in connector list\n");
return;
}
switch (connector->connector_type) {
@@ -472,8 +415,10 @@ void intel_opregion_init(struct drm_device *dev)
register_acpi_notifier(&intel_opregion_notifier);
}
- if (opregion->asle)
- intel_opregion_enable_asle(dev);
+ if (opregion->asle) {
+ iowrite32(ASLE_TCHE_BLC_EN, &opregion->asle->tche);
+ iowrite32(ASLE_ARDY_READY, &opregion->asle->ardy);
+ }
}
void intel_opregion_fini(struct drm_device *dev)
@@ -484,6 +429,9 @@ void intel_opregion_fini(struct drm_device *dev)
if (!opregion->header)
return;
+ if (opregion->asle)
+ iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy);
+
if (opregion->acpi) {
iowrite32(0, &opregion->acpi->drdy);
@@ -546,6 +494,8 @@ int intel_opregion_setup(struct drm_device *dev)
if (mboxes & MBOX_ASLE) {
DRM_DEBUG_DRIVER("ASLE supported\n");
opregion->asle = base + OPREGION_ASLE_OFFSET;
+
+ iowrite32(ASLE_ARDY_NOT_READY, &opregion->asle->ardy);
}
return 0;
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 67a2501d519d..a3698812e9c7 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -217,7 +217,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
int ret;
BUG_ON(overlay->last_flip_req);
- ret = i915_add_request(ring, NULL, &overlay->last_flip_req);
+ ret = i915_add_request(ring, &overlay->last_flip_req);
if (ret)
return ret;
@@ -286,7 +286,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
intel_ring_emit(ring, flip_addr);
intel_ring_advance(ring);
- return i915_add_request(ring, NULL, &overlay->last_flip_req);
+ return i915_add_request(ring, &overlay->last_flip_req);
}
static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
@@ -1485,14 +1485,15 @@ err:
}
void
-intel_overlay_print_error_state(struct seq_file *m, struct intel_overlay_error_state *error)
+intel_overlay_print_error_state(struct drm_i915_error_state_buf *m,
+ struct intel_overlay_error_state *error)
{
- seq_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
- error->dovsta, error->isr);
- seq_printf(m, " Register file at 0x%08lx:\n",
- error->base);
+ i915_error_printf(m, "Overlay, status: 0x%08x, interrupt: 0x%08x\n",
+ error->dovsta, error->isr);
+ i915_error_printf(m, " Register file at 0x%08lx:\n",
+ error->base);
-#define P(x) seq_printf(m, " " #x ": 0x%08x\n", error->regs.x)
+#define P(x) i915_error_printf(m, " " #x ": 0x%08x\n", error->regs.x)
P(OBUF_0Y);
P(OBUF_1Y);
P(OBUF_0U);
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index eb5e6e95f3c7..80bea1d3209f 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -54,14 +54,16 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
/* adjusted_mode has been preset to be the panel's fixed mode */
void
-intel_pch_panel_fitting(struct drm_device *dev,
- int fitting_mode,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
+ struct intel_crtc_config *pipe_config,
+ int fitting_mode)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_display_mode *mode, *adjusted_mode;
int x, y, width, height;
+ mode = &pipe_config->requested_mode;
+ adjusted_mode = &pipe_config->adjusted_mode;
+
x = y = width = height = 0;
/* Native modes don't need fitting */
@@ -104,17 +106,209 @@ intel_pch_panel_fitting(struct drm_device *dev,
}
break;
- default:
case DRM_MODE_SCALE_FULLSCREEN:
x = y = 0;
width = adjusted_mode->hdisplay;
height = adjusted_mode->vdisplay;
break;
+
+ default:
+ WARN(1, "bad panel fit mode: %d\n", fitting_mode);
+ return;
}
done:
- dev_priv->pch_pf_pos = (x << 16) | y;
- dev_priv->pch_pf_size = (width << 16) | height;
+ pipe_config->pch_pfit.pos = (x << 16) | y;
+ pipe_config->pch_pfit.size = (width << 16) | height;
+}
+
+static void
+centre_horizontally(struct drm_display_mode *mode,
+ int width)
+{
+ u32 border, sync_pos, blank_width, sync_width;
+
+ /* keep the hsync and hblank widths constant */
+ sync_width = mode->crtc_hsync_end - mode->crtc_hsync_start;
+ blank_width = mode->crtc_hblank_end - mode->crtc_hblank_start;
+ sync_pos = (blank_width - sync_width + 1) / 2;
+
+ border = (mode->hdisplay - width + 1) / 2;
+ border += border & 1; /* make the border even */
+
+ mode->crtc_hdisplay = width;
+ mode->crtc_hblank_start = width + border;
+ mode->crtc_hblank_end = mode->crtc_hblank_start + blank_width;
+
+ mode->crtc_hsync_start = mode->crtc_hblank_start + sync_pos;
+ mode->crtc_hsync_end = mode->crtc_hsync_start + sync_width;
+}
+
+static void
+centre_vertically(struct drm_display_mode *mode,
+ int height)
+{
+ u32 border, sync_pos, blank_width, sync_width;
+
+ /* keep the vsync and vblank widths constant */
+ sync_width = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ blank_width = mode->crtc_vblank_end - mode->crtc_vblank_start;
+ sync_pos = (blank_width - sync_width + 1) / 2;
+
+ border = (mode->vdisplay - height + 1) / 2;
+
+ mode->crtc_vdisplay = height;
+ mode->crtc_vblank_start = height + border;
+ mode->crtc_vblank_end = mode->crtc_vblank_start + blank_width;
+
+ mode->crtc_vsync_start = mode->crtc_vblank_start + sync_pos;
+ mode->crtc_vsync_end = mode->crtc_vsync_start + sync_width;
+}
+
+static inline u32 panel_fitter_scaling(u32 source, u32 target)
+{
+ /*
+ * Floating point operation is not supported. So the FACTOR
+ * is defined, which can avoid the floating point computation
+ * when calculating the panel ratio.
+ */
+#define ACCURACY 12
+#define FACTOR (1 << ACCURACY)
+ u32 ratio = source * FACTOR / target;
+ return (FACTOR * ratio + FACTOR/2) / FACTOR;
+}
+
+void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
+ struct intel_crtc_config *pipe_config,
+ int fitting_mode)
+{
+ struct drm_device *dev = intel_crtc->base.dev;
+ u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
+ struct drm_display_mode *mode, *adjusted_mode;
+
+ mode = &pipe_config->requested_mode;
+ adjusted_mode = &pipe_config->adjusted_mode;
+
+ /* Native modes don't need fitting */
+ if (adjusted_mode->hdisplay == mode->hdisplay &&
+ adjusted_mode->vdisplay == mode->vdisplay)
+ goto out;
+
+ switch (fitting_mode) {
+ case DRM_MODE_SCALE_CENTER:
+ /*
+ * For centered modes, we have to calculate border widths &
+ * heights and modify the values programmed into the CRTC.
+ */
+ centre_horizontally(adjusted_mode, mode->hdisplay);
+ centre_vertically(adjusted_mode, mode->vdisplay);
+ border = LVDS_BORDER_ENABLE;
+ break;
+ case DRM_MODE_SCALE_ASPECT:
+ /* Scale but preserve the aspect ratio */
+ if (INTEL_INFO(dev)->gen >= 4) {
+ u32 scaled_width = adjusted_mode->hdisplay *
+ mode->vdisplay;
+ u32 scaled_height = mode->hdisplay *
+ adjusted_mode->vdisplay;
+
+ /* 965+ is easy, it does everything in hw */
+ if (scaled_width > scaled_height)
+ pfit_control |= PFIT_ENABLE |
+ PFIT_SCALING_PILLAR;
+ else if (scaled_width < scaled_height)
+ pfit_control |= PFIT_ENABLE |
+ PFIT_SCALING_LETTER;
+ else if (adjusted_mode->hdisplay != mode->hdisplay)
+ pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
+ } else {
+ u32 scaled_width = adjusted_mode->hdisplay *
+ mode->vdisplay;
+ u32 scaled_height = mode->hdisplay *
+ adjusted_mode->vdisplay;
+ /*
+ * For earlier chips we have to calculate the scaling
+ * ratio by hand and program it into the
+ * PFIT_PGM_RATIO register
+ */
+ if (scaled_width > scaled_height) { /* pillar */
+ centre_horizontally(adjusted_mode,
+ scaled_height /
+ mode->vdisplay);
+
+ border = LVDS_BORDER_ENABLE;
+ if (mode->vdisplay != adjusted_mode->vdisplay) {
+ u32 bits = panel_fitter_scaling(mode->vdisplay, adjusted_mode->vdisplay);
+ pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
+ bits << PFIT_VERT_SCALE_SHIFT);
+ pfit_control |= (PFIT_ENABLE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ }
+ } else if (scaled_width < scaled_height) { /* letter */
+ centre_vertically(adjusted_mode,
+ scaled_width /
+ mode->hdisplay);
+
+ border = LVDS_BORDER_ENABLE;
+ if (mode->hdisplay != adjusted_mode->hdisplay) {
+ u32 bits = panel_fitter_scaling(mode->hdisplay, adjusted_mode->hdisplay);
+ pfit_pgm_ratios |= (bits << PFIT_HORIZ_SCALE_SHIFT |
+ bits << PFIT_VERT_SCALE_SHIFT);
+ pfit_control |= (PFIT_ENABLE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ }
+ } else {
+ /* Aspects match, Let hw scale both directions */
+ pfit_control |= (PFIT_ENABLE |
+ VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_INTERP_BILINEAR);
+ }
+ }
+ break;
+ case DRM_MODE_SCALE_FULLSCREEN:
+ /*
+ * Full scaling, even if it changes the aspect ratio.
+ * Fortunately this is all done for us in hw.
+ */
+ if (mode->vdisplay != adjusted_mode->vdisplay ||
+ mode->hdisplay != adjusted_mode->hdisplay) {
+ pfit_control |= PFIT_ENABLE;
+ if (INTEL_INFO(dev)->gen >= 4)
+ pfit_control |= PFIT_SCALING_AUTO;
+ else
+ pfit_control |= (VERT_AUTO_SCALE |
+ VERT_INTERP_BILINEAR |
+ HORIZ_AUTO_SCALE |
+ HORIZ_INTERP_BILINEAR);
+ }
+ break;
+ default:
+ WARN(1, "bad panel fit mode: %d\n", fitting_mode);
+ return;
+ }
+
+ /* 965+ wants fuzzy fitting */
+ /* FIXME: handle multiple panels by failing gracefully */
+ if (INTEL_INFO(dev)->gen >= 4)
+ pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |
+ PFIT_FILTER_FUZZY);
+
+out:
+ if ((pfit_control & PFIT_ENABLE) == 0) {
+ pfit_control = 0;
+ pfit_pgm_ratios = 0;
+ }
+
+ /* Make sure pre-965 set dither correctly for 18bpp panels. */
+ if (INTEL_INFO(dev)->gen < 4 && pipe_config->pipe_bpp == 18)
+ pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+
+ pipe_config->gmch_pfit.control = pfit_control;
+ pipe_config->gmch_pfit.pgm_ratios = pfit_pgm_ratios;
+ pipe_config->gmch_pfit.lvds_border_bits = border;
}
static int is_backlight_combination_mode(struct drm_device *dev)
@@ -130,11 +324,16 @@ static int is_backlight_combination_mode(struct drm_device *dev)
return 0;
}
+/* XXX: query mode clock or hardware clock and program max PWM appropriately
+ * when it's 0.
+ */
static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 val;
+ WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock));
+
/* Restore the CTL value if it lost, e.g. GPU reset */
if (HAS_PCH_SPLIT(dev_priv->dev)) {
@@ -164,7 +363,7 @@ static u32 i915_read_blc_pwm_ctl(struct drm_device *dev)
return val;
}
-static u32 _intel_panel_get_max_backlight(struct drm_device *dev)
+static u32 intel_panel_get_max_backlight(struct drm_device *dev)
{
u32 max;
@@ -182,23 +381,8 @@ static u32 _intel_panel_get_max_backlight(struct drm_device *dev)
max *= 0xff;
}
- return max;
-}
-
-u32 intel_panel_get_max_backlight(struct drm_device *dev)
-{
- u32 max;
-
- max = _intel_panel_get_max_backlight(dev);
- if (max == 0) {
- /* XXX add code here to query mode clock or hardware clock
- * and program max PWM appropriately.
- */
- pr_warn_once("fixme: max PWM is zero\n");
- return 1;
- }
-
DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
+
return max;
}
@@ -217,8 +401,11 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
return val;
if (i915_panel_invert_brightness > 0 ||
- dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)
- return intel_panel_get_max_backlight(dev) - val;
+ dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
+ u32 max = intel_panel_get_max_backlight(dev);
+ if (max)
+ return max - val;
+ }
return val;
}
@@ -227,6 +414,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
if (HAS_PCH_SPLIT(dev)) {
val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
@@ -244,6 +434,9 @@ static u32 intel_panel_get_backlight(struct drm_device *dev)
}
val = intel_panel_compute_brightness(dev, val);
+
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+
DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
return val;
}
@@ -270,6 +463,10 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level
u32 max = intel_panel_get_max_backlight(dev);
u8 lbpc;
+ /* we're screwed, but keep behaviour backwards compatible */
+ if (!max)
+ max = 1;
+
lbpc = level * 0xfe / max + 1;
level /= lbpc;
pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
@@ -282,9 +479,23 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level
I915_WRITE(BLC_PWM_CTL, tmp | level);
}
-void intel_panel_set_backlight(struct drm_device *dev, u32 level)
+/* set backlight brightness to level in range [0..max] */
+void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 freq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+
+ freq = intel_panel_get_max_backlight(dev);
+ if (!freq) {
+ /* we are screwed, bail out */
+ goto out;
+ }
+
+ /* scale to hardware */
+ level = level * freq / max;
dev_priv->backlight.level = level;
if (dev_priv->backlight.device)
@@ -292,11 +503,16 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level)
if (dev_priv->backlight.enabled)
intel_panel_actually_set_backlight(dev, level);
+out:
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
}
void intel_panel_disable_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
dev_priv->backlight.enabled = false;
intel_panel_actually_set_backlight(dev, 0);
@@ -314,12 +530,19 @@ void intel_panel_disable_backlight(struct drm_device *dev)
I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
}
}
+
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
}
void intel_panel_enable_backlight(struct drm_device *dev,
enum pipe pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ enum transcoder cpu_transcoder =
+ intel_pipe_to_cpu_transcoder(dev_priv, pipe);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
if (dev_priv->backlight.level == 0) {
dev_priv->backlight.level = intel_panel_get_max_backlight(dev);
@@ -347,7 +570,10 @@ void intel_panel_enable_backlight(struct drm_device *dev,
else
tmp &= ~BLM_PIPE_SELECT;
- tmp |= BLM_PIPE(pipe);
+ if (cpu_transcoder == TRANSCODER_EDP)
+ tmp |= BLM_TRANSCODER_EDP;
+ else
+ tmp |= BLM_PIPE(cpu_transcoder);
tmp &= ~BLM_PWM_ENABLE;
I915_WRITE(reg, tmp);
@@ -369,6 +595,8 @@ set_level:
*/
dev_priv->backlight.enabled = true;
intel_panel_actually_set_backlight(dev, dev_priv->backlight.level);
+
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
}
static void intel_panel_init_backlight(struct drm_device *dev)
@@ -405,7 +633,8 @@ intel_panel_detect(struct drm_device *dev)
static int intel_panel_update_status(struct backlight_device *bd)
{
struct drm_device *dev = bl_get_data(bd);
- intel_panel_set_backlight(dev, bd->props.brightness);
+ intel_panel_set_backlight(dev, bd->props.brightness,
+ bd->props.max_brightness);
return 0;
}
@@ -425,6 +654,7 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct backlight_properties props;
+ unsigned long flags;
intel_panel_init_backlight(dev);
@@ -434,7 +664,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector)
memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
props.brightness = dev_priv->backlight.level;
- props.max_brightness = _intel_panel_get_max_backlight(dev);
+
+ spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+ props.max_brightness = intel_panel_get_max_backlight(dev);
+ spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+
if (props.max_brightness == 0) {
DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
return -ENODEV;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index aa01128ff192..ccbdd83f5220 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -113,8 +113,8 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
fbc_ctl |= obj->fence_reg;
I915_WRITE(FBC_CONTROL, fbc_ctl);
- DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
- cfb_pitch, crtc->y, intel_crtc->plane);
+ DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c, ",
+ cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
}
static bool i8xx_fbc_enabled(struct drm_device *dev)
@@ -148,7 +148,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
/* enable it... */
I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
- DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+ DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
static void g4x_disable_fbc(struct drm_device *dev)
@@ -228,7 +228,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
sandybridge_blit_fbc_update(dev);
}
- DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+ DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
}
static void ironlake_disable_fbc(struct drm_device *dev)
@@ -242,6 +242,18 @@ static void ironlake_disable_fbc(struct drm_device *dev)
dpfc_ctl &= ~DPFC_CTL_EN;
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+ if (IS_IVYBRIDGE(dev))
+ /* WaFbcDisableDpfcClockGating:ivb */
+ I915_WRITE(ILK_DSPCLK_GATE_D,
+ I915_READ(ILK_DSPCLK_GATE_D) &
+ ~ILK_DPFCUNIT_CLOCK_GATE_DISABLE);
+
+ if (IS_HASWELL(dev))
+ /* WaFbcDisableDpfcClockGating:hsw */
+ I915_WRITE(HSW_CLKGATE_DISABLE_PART_1,
+ I915_READ(HSW_CLKGATE_DISABLE_PART_1) &
+ ~HSW_DPFC_GATING_DISABLE);
+
DRM_DEBUG_KMS("disabled FBC\n");
}
}
@@ -253,6 +265,47 @@ static bool ironlake_fbc_enabled(struct drm_device *dev)
return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
}
+static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->fb;
+ struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ I915_WRITE(IVB_FBC_RT_BASE, obj->gtt_offset);
+
+ I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X |
+ IVB_DPFC_CTL_FENCE_EN |
+ intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT);
+
+ if (IS_IVYBRIDGE(dev)) {
+ /* WaFbcAsynchFlipDisableFbcQueue:ivb */
+ I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS);
+ /* WaFbcDisableDpfcClockGating:ivb */
+ I915_WRITE(ILK_DSPCLK_GATE_D,
+ I915_READ(ILK_DSPCLK_GATE_D) |
+ ILK_DPFCUNIT_CLOCK_GATE_DISABLE);
+ } else {
+ /* WaFbcAsynchFlipDisableFbcQueue:hsw */
+ I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe),
+ HSW_BYPASS_FBC_QUEUE);
+ /* WaFbcDisableDpfcClockGating:hsw */
+ I915_WRITE(HSW_CLKGATE_DISABLE_PART_1,
+ I915_READ(HSW_CLKGATE_DISABLE_PART_1) |
+ HSW_DPFC_GATING_DISABLE);
+ }
+
+ I915_WRITE(SNB_DPFC_CTL_SA,
+ SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+
+ sandybridge_blit_fbc_update(dev);
+
+ DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+}
+
bool intel_fbc_enabled(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -378,7 +431,7 @@ void intel_disable_fbc(struct drm_device *dev)
* - no pixel mulitply/line duplication
* - no alpha buffer discard
* - no dual wide
- * - framebuffer <= 2048 in width, 1536 in height
+ * - framebuffer <= max_hdisplay in width, max_vdisplay in height
*
* We can't assume that any compression will take place (worst case),
* so the compressed buffer has to be the same size as the uncompressed
@@ -396,6 +449,7 @@ void intel_update_fbc(struct drm_device *dev)
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj;
int enable_fbc;
+ unsigned int max_hdisplay, max_vdisplay;
if (!i915_powersave)
return;
@@ -439,7 +493,7 @@ void intel_update_fbc(struct drm_device *dev)
if (enable_fbc < 0) {
DRM_DEBUG_KMS("fbc set to per-chip default\n");
enable_fbc = 1;
- if (INTEL_INFO(dev)->gen <= 6)
+ if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
enable_fbc = 0;
}
if (!enable_fbc) {
@@ -454,13 +508,22 @@ void intel_update_fbc(struct drm_device *dev)
dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
goto out_disable;
}
- if ((crtc->mode.hdisplay > 2048) ||
- (crtc->mode.vdisplay > 1536)) {
+
+ if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+ max_hdisplay = 4096;
+ max_vdisplay = 2048;
+ } else {
+ max_hdisplay = 2048;
+ max_vdisplay = 1536;
+ }
+ if ((crtc->mode.hdisplay > max_hdisplay) ||
+ (crtc->mode.vdisplay > max_vdisplay)) {
DRM_DEBUG_KMS("mode too large for compression, disabling\n");
dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
goto out_disable;
}
- if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
+ if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) &&
+ intel_crtc->plane != 0) {
DRM_DEBUG_KMS("plane not 0, disabling compression\n");
dev_priv->no_fbc_reason = FBC_BAD_PLANE;
goto out_disable;
@@ -481,8 +544,6 @@ void intel_update_fbc(struct drm_device *dev)
goto out_disable;
if (i915_gem_stolen_setup_compression(dev, intel_fb->obj->base.size)) {
- DRM_INFO("not enough stolen space for compressed buffer (need %zd bytes), disabling\n", intel_fb->obj->base.size);
- DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
goto out_disable;
@@ -1633,6 +1694,10 @@ static bool ironlake_check_srwm(struct drm_device *dev, int level,
I915_WRITE(DISP_ARB_CTL,
I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
return false;
+ } else if (INTEL_INFO(dev)->gen >= 6) {
+ /* enable FBC WM (except on ILK, where it must remain off) */
+ I915_WRITE(DISP_ARB_CTL,
+ I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS);
}
if (display_wm > display->max_wm) {
@@ -2016,31 +2081,558 @@ static void ivybridge_update_wm(struct drm_device *dev)
cursor_wm);
}
-static void
-haswell_update_linetime_wm(struct drm_device *dev, int pipe,
- struct drm_display_mode *mode)
+static uint32_t hsw_wm_get_pixel_rate(struct drm_device *dev,
+ struct drm_crtc *crtc)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ uint32_t pixel_rate, pfit_size;
+
+ pixel_rate = intel_crtc->config.adjusted_mode.clock;
+
+ /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
+ * adjust the pixel_rate here. */
+
+ pfit_size = intel_crtc->config.pch_pfit.size;
+ if (pfit_size) {
+ uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
+
+ pipe_w = intel_crtc->config.requested_mode.hdisplay;
+ pipe_h = intel_crtc->config.requested_mode.vdisplay;
+ pfit_w = (pfit_size >> 16) & 0xFFFF;
+ pfit_h = pfit_size & 0xFFFF;
+ if (pipe_w < pfit_w)
+ pipe_w = pfit_w;
+ if (pipe_h < pfit_h)
+ pipe_h = pfit_h;
+
+ pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h,
+ pfit_w * pfit_h);
+ }
+
+ return pixel_rate;
+}
+
+static uint32_t hsw_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
+ uint32_t latency)
+{
+ uint64_t ret;
+
+ ret = (uint64_t) pixel_rate * bytes_per_pixel * latency;
+ ret = DIV_ROUND_UP_ULL(ret, 64 * 10000) + 2;
+
+ return ret;
+}
+
+static uint32_t hsw_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
+ uint32_t horiz_pixels, uint8_t bytes_per_pixel,
+ uint32_t latency)
+{
+ uint32_t ret;
+
+ ret = (latency * pixel_rate) / (pipe_htotal * 10000);
+ ret = (ret + 1) * horiz_pixels * bytes_per_pixel;
+ ret = DIV_ROUND_UP(ret, 64) + 2;
+ return ret;
+}
+
+static uint32_t hsw_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
+ uint8_t bytes_per_pixel)
+{
+ return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
+}
+
+struct hsw_pipe_wm_parameters {
+ bool active;
+ bool sprite_enabled;
+ uint8_t pri_bytes_per_pixel;
+ uint8_t spr_bytes_per_pixel;
+ uint8_t cur_bytes_per_pixel;
+ uint32_t pri_horiz_pixels;
+ uint32_t spr_horiz_pixels;
+ uint32_t cur_horiz_pixels;
+ uint32_t pipe_htotal;
+ uint32_t pixel_rate;
+};
+
+struct hsw_wm_maximums {
+ uint16_t pri;
+ uint16_t spr;
+ uint16_t cur;
+ uint16_t fbc;
+};
+
+struct hsw_lp_wm_result {
+ bool enable;
+ bool fbc_enable;
+ uint32_t pri_val;
+ uint32_t spr_val;
+ uint32_t cur_val;
+ uint32_t fbc_val;
+};
+
+struct hsw_wm_values {
+ uint32_t wm_pipe[3];
+ uint32_t wm_lp[3];
+ uint32_t wm_lp_spr[3];
+ uint32_t wm_linetime[3];
+ bool enable_fbc_wm;
+};
+
+enum hsw_data_buf_partitioning {
+ HSW_DATA_BUF_PART_1_2,
+ HSW_DATA_BUF_PART_5_6,
+};
+
+/* For both WM_PIPE and WM_LP. */
+static uint32_t hsw_compute_pri_wm(struct hsw_pipe_wm_parameters *params,
+ uint32_t mem_value,
+ bool is_lp)
+{
+ uint32_t method1, method2;
+
+ /* TODO: for now, assume the primary plane is always enabled. */
+ if (!params->active)
+ return 0;
+
+ method1 = hsw_wm_method1(params->pixel_rate,
+ params->pri_bytes_per_pixel,
+ mem_value);
+
+ if (!is_lp)
+ return method1;
+
+ method2 = hsw_wm_method2(params->pixel_rate,
+ params->pipe_htotal,
+ params->pri_horiz_pixels,
+ params->pri_bytes_per_pixel,
+ mem_value);
+
+ return min(method1, method2);
+}
+
+/* For both WM_PIPE and WM_LP. */
+static uint32_t hsw_compute_spr_wm(struct hsw_pipe_wm_parameters *params,
+ uint32_t mem_value)
+{
+ uint32_t method1, method2;
+
+ if (!params->active || !params->sprite_enabled)
+ return 0;
+
+ method1 = hsw_wm_method1(params->pixel_rate,
+ params->spr_bytes_per_pixel,
+ mem_value);
+ method2 = hsw_wm_method2(params->pixel_rate,
+ params->pipe_htotal,
+ params->spr_horiz_pixels,
+ params->spr_bytes_per_pixel,
+ mem_value);
+ return min(method1, method2);
+}
+
+/* For both WM_PIPE and WM_LP. */
+static uint32_t hsw_compute_cur_wm(struct hsw_pipe_wm_parameters *params,
+ uint32_t mem_value)
+{
+ if (!params->active)
+ return 0;
+
+ return hsw_wm_method2(params->pixel_rate,
+ params->pipe_htotal,
+ params->cur_horiz_pixels,
+ params->cur_bytes_per_pixel,
+ mem_value);
+}
+
+/* Only for WM_LP. */
+static uint32_t hsw_compute_fbc_wm(struct hsw_pipe_wm_parameters *params,
+ uint32_t pri_val,
+ uint32_t mem_value)
+{
+ if (!params->active)
+ return 0;
+
+ return hsw_wm_fbc(pri_val,
+ params->pri_horiz_pixels,
+ params->pri_bytes_per_pixel);
+}
+
+static bool hsw_compute_lp_wm(uint32_t mem_value, struct hsw_wm_maximums *max,
+ struct hsw_pipe_wm_parameters *params,
+ struct hsw_lp_wm_result *result)
+{
+ enum pipe pipe;
+ uint32_t pri_val[3], spr_val[3], cur_val[3], fbc_val[3];
+
+ for (pipe = PIPE_A; pipe <= PIPE_C; pipe++) {
+ struct hsw_pipe_wm_parameters *p = &params[pipe];
+
+ pri_val[pipe] = hsw_compute_pri_wm(p, mem_value, true);
+ spr_val[pipe] = hsw_compute_spr_wm(p, mem_value);
+ cur_val[pipe] = hsw_compute_cur_wm(p, mem_value);
+ fbc_val[pipe] = hsw_compute_fbc_wm(p, pri_val[pipe], mem_value);
+ }
+
+ result->pri_val = max3(pri_val[0], pri_val[1], pri_val[2]);
+ result->spr_val = max3(spr_val[0], spr_val[1], spr_val[2]);
+ result->cur_val = max3(cur_val[0], cur_val[1], cur_val[2]);
+ result->fbc_val = max3(fbc_val[0], fbc_val[1], fbc_val[2]);
+
+ if (result->fbc_val > max->fbc) {
+ result->fbc_enable = false;
+ result->fbc_val = 0;
+ } else {
+ result->fbc_enable = true;
+ }
+
+ result->enable = result->pri_val <= max->pri &&
+ result->spr_val <= max->spr &&
+ result->cur_val <= max->cur;
+ return result->enable;
+}
+
+static uint32_t hsw_compute_wm_pipe(struct drm_i915_private *dev_priv,
+ uint32_t mem_value, enum pipe pipe,
+ struct hsw_pipe_wm_parameters *params)
+{
+ uint32_t pri_val, cur_val, spr_val;
+
+ pri_val = hsw_compute_pri_wm(params, mem_value, false);
+ spr_val = hsw_compute_spr_wm(params, mem_value);
+ cur_val = hsw_compute_cur_wm(params, mem_value);
+
+ WARN(pri_val > 127,
+ "Primary WM error, mode not supported for pipe %c\n",
+ pipe_name(pipe));
+ WARN(spr_val > 127,
+ "Sprite WM error, mode not supported for pipe %c\n",
+ pipe_name(pipe));
+ WARN(cur_val > 63,
+ "Cursor WM error, mode not supported for pipe %c\n",
+ pipe_name(pipe));
+
+ return (pri_val << WM0_PIPE_PLANE_SHIFT) |
+ (spr_val << WM0_PIPE_SPRITE_SHIFT) |
+ cur_val;
+}
+
+static uint32_t
+hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 temp;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+ u32 linetime, ips_linetime;
- temp = I915_READ(PIPE_WM_LINETIME(pipe));
- temp &= ~PIPE_WM_LINETIME_MASK;
+ if (!intel_crtc_active(crtc))
+ return 0;
/* The WM are computed with base on how long it takes to fill a single
* row at the given clock rate, multiplied by 8.
* */
- temp |= PIPE_WM_LINETIME_TIME(
- ((mode->crtc_hdisplay * 1000) / mode->clock) * 8);
+ linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8, mode->clock);
+ ips_linetime = DIV_ROUND_CLOSEST(mode->htotal * 1000 * 8,
+ intel_ddi_get_cdclk_freq(dev_priv));
- /* IPS watermarks are only used by pipe A, and are ignored by
- * pipes B and C. They are calculated similarly to the common
- * linetime values, except that we are using CD clock frequency
- * in MHz instead of pixel rate for the division.
- *
- * This is a placeholder for the IPS watermark calculation code.
- */
+ return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) |
+ PIPE_WM_LINETIME_TIME(linetime);
+}
+
+static void hsw_compute_wm_parameters(struct drm_device *dev,
+ struct hsw_pipe_wm_parameters *params,
+ uint32_t *wm,
+ struct hsw_wm_maximums *lp_max_1_2,
+ struct hsw_wm_maximums *lp_max_5_6)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ struct drm_plane *plane;
+ uint64_t sskpd = I915_READ64(MCH_SSKPD);
+ enum pipe pipe;
+ int pipes_active = 0, sprites_enabled = 0;
+
+ if ((sskpd >> 56) & 0xFF)
+ wm[0] = (sskpd >> 56) & 0xFF;
+ else
+ wm[0] = sskpd & 0xF;
+ wm[1] = ((sskpd >> 4) & 0xFF) * 5;
+ wm[2] = ((sskpd >> 12) & 0xFF) * 5;
+ wm[3] = ((sskpd >> 20) & 0x1FF) * 5;
+ wm[4] = ((sskpd >> 32) & 0x1FF) * 5;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct hsw_pipe_wm_parameters *p;
+
+ pipe = intel_crtc->pipe;
+ p = &params[pipe];
+
+ p->active = intel_crtc_active(crtc);
+ if (!p->active)
+ continue;
+
+ pipes_active++;
+
+ p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal;
+ p->pixel_rate = hsw_wm_get_pixel_rate(dev, crtc);
+ p->pri_bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
+ p->cur_bytes_per_pixel = 4;
+ p->pri_horiz_pixels =
+ intel_crtc->config.requested_mode.hdisplay;
+ p->cur_horiz_pixels = 64;
+ }
+
+ list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct hsw_pipe_wm_parameters *p;
+
+ pipe = intel_plane->pipe;
+ p = &params[pipe];
+
+ p->sprite_enabled = intel_plane->wm.enable;
+ p->spr_bytes_per_pixel = intel_plane->wm.bytes_per_pixel;
+ p->spr_horiz_pixels = intel_plane->wm.horiz_pixels;
+
+ if (p->sprite_enabled)
+ sprites_enabled++;
+ }
- I915_WRITE(PIPE_WM_LINETIME(pipe), temp);
+ if (pipes_active > 1) {
+ lp_max_1_2->pri = lp_max_5_6->pri = sprites_enabled ? 128 : 256;
+ lp_max_1_2->spr = lp_max_5_6->spr = 128;
+ lp_max_1_2->cur = lp_max_5_6->cur = 64;
+ } else {
+ lp_max_1_2->pri = sprites_enabled ? 384 : 768;
+ lp_max_5_6->pri = sprites_enabled ? 128 : 768;
+ lp_max_1_2->spr = 384;
+ lp_max_5_6->spr = 640;
+ lp_max_1_2->cur = lp_max_5_6->cur = 255;
+ }
+ lp_max_1_2->fbc = lp_max_5_6->fbc = 15;
+}
+
+static void hsw_compute_wm_results(struct drm_device *dev,
+ struct hsw_pipe_wm_parameters *params,
+ uint32_t *wm,
+ struct hsw_wm_maximums *lp_maximums,
+ struct hsw_wm_values *results)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ struct hsw_lp_wm_result lp_results[4] = {};
+ enum pipe pipe;
+ int level, max_level, wm_lp;
+
+ for (level = 1; level <= 4; level++)
+ if (!hsw_compute_lp_wm(wm[level], lp_maximums, params,
+ &lp_results[level - 1]))
+ break;
+ max_level = level - 1;
+
+ /* The spec says it is preferred to disable FBC WMs instead of disabling
+ * a WM level. */
+ results->enable_fbc_wm = true;
+ for (level = 1; level <= max_level; level++) {
+ if (!lp_results[level - 1].fbc_enable) {
+ results->enable_fbc_wm = false;
+ break;
+ }
+ }
+
+ memset(results, 0, sizeof(*results));
+ for (wm_lp = 1; wm_lp <= 3; wm_lp++) {
+ const struct hsw_lp_wm_result *r;
+
+ level = (max_level == 4 && wm_lp > 1) ? wm_lp + 1 : wm_lp;
+ if (level > max_level)
+ break;
+
+ r = &lp_results[level - 1];
+ results->wm_lp[wm_lp - 1] = HSW_WM_LP_VAL(level * 2,
+ r->fbc_val,
+ r->pri_val,
+ r->cur_val);
+ results->wm_lp_spr[wm_lp - 1] = r->spr_val;
+ }
+
+ for_each_pipe(pipe)
+ results->wm_pipe[pipe] = hsw_compute_wm_pipe(dev_priv, wm[0],
+ pipe,
+ &params[pipe]);
+
+ for_each_pipe(pipe) {
+ crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ results->wm_linetime[pipe] = hsw_compute_linetime_wm(dev, crtc);
+ }
+}
+
+/* Find the result with the highest level enabled. Check for enable_fbc_wm in
+ * case both are at the same level. Prefer r1 in case they're the same. */
+struct hsw_wm_values *hsw_find_best_result(struct hsw_wm_values *r1,
+ struct hsw_wm_values *r2)
+{
+ int i, val_r1 = 0, val_r2 = 0;
+
+ for (i = 0; i < 3; i++) {
+ if (r1->wm_lp[i] & WM3_LP_EN)
+ val_r1 = r1->wm_lp[i] & WM1_LP_LATENCY_MASK;
+ if (r2->wm_lp[i] & WM3_LP_EN)
+ val_r2 = r2->wm_lp[i] & WM1_LP_LATENCY_MASK;
+ }
+
+ if (val_r1 == val_r2) {
+ if (r2->enable_fbc_wm && !r1->enable_fbc_wm)
+ return r2;
+ else
+ return r1;
+ } else if (val_r1 > val_r2) {
+ return r1;
+ } else {
+ return r2;
+ }
+}
+
+/*
+ * The spec says we shouldn't write when we don't need, because every write
+ * causes WMs to be re-evaluated, expending some power.
+ */
+static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
+ struct hsw_wm_values *results,
+ enum hsw_data_buf_partitioning partitioning)
+{
+ struct hsw_wm_values previous;
+ uint32_t val;
+ enum hsw_data_buf_partitioning prev_partitioning;
+ bool prev_enable_fbc_wm;
+
+ previous.wm_pipe[0] = I915_READ(WM0_PIPEA_ILK);
+ previous.wm_pipe[1] = I915_READ(WM0_PIPEB_ILK);
+ previous.wm_pipe[2] = I915_READ(WM0_PIPEC_IVB);
+ previous.wm_lp[0] = I915_READ(WM1_LP_ILK);
+ previous.wm_lp[1] = I915_READ(WM2_LP_ILK);
+ previous.wm_lp[2] = I915_READ(WM3_LP_ILK);
+ previous.wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
+ previous.wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
+ previous.wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
+ previous.wm_linetime[0] = I915_READ(PIPE_WM_LINETIME(PIPE_A));
+ previous.wm_linetime[1] = I915_READ(PIPE_WM_LINETIME(PIPE_B));
+ previous.wm_linetime[2] = I915_READ(PIPE_WM_LINETIME(PIPE_C));
+
+ prev_partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
+ HSW_DATA_BUF_PART_5_6 : HSW_DATA_BUF_PART_1_2;
+
+ prev_enable_fbc_wm = !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
+
+ if (memcmp(results->wm_pipe, previous.wm_pipe,
+ sizeof(results->wm_pipe)) == 0 &&
+ memcmp(results->wm_lp, previous.wm_lp,
+ sizeof(results->wm_lp)) == 0 &&
+ memcmp(results->wm_lp_spr, previous.wm_lp_spr,
+ sizeof(results->wm_lp_spr)) == 0 &&
+ memcmp(results->wm_linetime, previous.wm_linetime,
+ sizeof(results->wm_linetime)) == 0 &&
+ partitioning == prev_partitioning &&
+ results->enable_fbc_wm == prev_enable_fbc_wm)
+ return;
+
+ if (previous.wm_lp[2] != 0)
+ I915_WRITE(WM3_LP_ILK, 0);
+ if (previous.wm_lp[1] != 0)
+ I915_WRITE(WM2_LP_ILK, 0);
+ if (previous.wm_lp[0] != 0)
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ if (previous.wm_pipe[0] != results->wm_pipe[0])
+ I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
+ if (previous.wm_pipe[1] != results->wm_pipe[1])
+ I915_WRITE(WM0_PIPEB_ILK, results->wm_pipe[1]);
+ if (previous.wm_pipe[2] != results->wm_pipe[2])
+ I915_WRITE(WM0_PIPEC_IVB, results->wm_pipe[2]);
+
+ if (previous.wm_linetime[0] != results->wm_linetime[0])
+ I915_WRITE(PIPE_WM_LINETIME(PIPE_A), results->wm_linetime[0]);
+ if (previous.wm_linetime[1] != results->wm_linetime[1])
+ I915_WRITE(PIPE_WM_LINETIME(PIPE_B), results->wm_linetime[1]);
+ if (previous.wm_linetime[2] != results->wm_linetime[2])
+ I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]);
+
+ if (prev_partitioning != partitioning) {
+ val = I915_READ(WM_MISC);
+ if (partitioning == HSW_DATA_BUF_PART_1_2)
+ val &= ~WM_MISC_DATA_PARTITION_5_6;
+ else
+ val |= WM_MISC_DATA_PARTITION_5_6;
+ I915_WRITE(WM_MISC, val);
+ }
+
+ if (prev_enable_fbc_wm != results->enable_fbc_wm) {
+ val = I915_READ(DISP_ARB_CTL);
+ if (results->enable_fbc_wm)
+ val &= ~DISP_FBC_WM_DIS;
+ else
+ val |= DISP_FBC_WM_DIS;
+ I915_WRITE(DISP_ARB_CTL, val);
+ }
+
+ if (previous.wm_lp_spr[0] != results->wm_lp_spr[0])
+ I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
+ if (previous.wm_lp_spr[1] != results->wm_lp_spr[1])
+ I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
+ if (previous.wm_lp_spr[2] != results->wm_lp_spr[2])
+ I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
+
+ if (results->wm_lp[0] != 0)
+ I915_WRITE(WM1_LP_ILK, results->wm_lp[0]);
+ if (results->wm_lp[1] != 0)
+ I915_WRITE(WM2_LP_ILK, results->wm_lp[1]);
+ if (results->wm_lp[2] != 0)
+ I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
+}
+
+static void haswell_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct hsw_wm_maximums lp_max_1_2, lp_max_5_6;
+ struct hsw_pipe_wm_parameters params[3];
+ struct hsw_wm_values results_1_2, results_5_6, *best_results;
+ uint32_t wm[5];
+ enum hsw_data_buf_partitioning partitioning;
+
+ hsw_compute_wm_parameters(dev, params, wm, &lp_max_1_2, &lp_max_5_6);
+
+ hsw_compute_wm_results(dev, params, wm, &lp_max_1_2, &results_1_2);
+ if (lp_max_1_2.pri != lp_max_5_6.pri) {
+ hsw_compute_wm_results(dev, params, wm, &lp_max_5_6,
+ &results_5_6);
+ best_results = hsw_find_best_result(&results_1_2, &results_5_6);
+ } else {
+ best_results = &results_1_2;
+ }
+
+ partitioning = (best_results == &results_1_2) ?
+ HSW_DATA_BUF_PART_1_2 : HSW_DATA_BUF_PART_5_6;
+
+ hsw_write_wm_values(dev_priv, best_results, partitioning);
+}
+
+static void haswell_update_sprite_wm(struct drm_device *dev, int pipe,
+ uint32_t sprite_width, int pixel_size,
+ bool enable)
+{
+ struct drm_plane *plane;
+
+ list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+
+ if (intel_plane->pipe == pipe) {
+ intel_plane->wm.enable = enable;
+ intel_plane->wm.horiz_pixels = sprite_width + 1;
+ intel_plane->wm.bytes_per_pixel = pixel_size;
+ break;
+ }
+ }
+
+ haswell_update_wm(dev);
}
static bool
@@ -2120,7 +2712,8 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
}
static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
- uint32_t sprite_width, int pixel_size)
+ uint32_t sprite_width, int pixel_size,
+ bool enable)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
@@ -2128,6 +2721,9 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
int sprite_wm, reg;
int ret;
+ if (!enable)
+ return;
+
switch (pipe) {
case 0:
reg = WM0_PIPEA_ILK;
@@ -2146,15 +2742,15 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
&sandybridge_display_wm_info,
latency, &sprite_wm);
if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n",
- pipe);
+ DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n",
+ pipe_name(pipe));
return;
}
val = I915_READ(reg);
val &= ~WM0_PIPE_SPRITE_MASK;
I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
- DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
+ DRM_DEBUG_KMS("sprite watermarks For pipe %c - %d\n", pipe_name(pipe), sprite_wm);
ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
@@ -2163,8 +2759,8 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
SNB_READ_WM1_LATENCY() * 500,
&sprite_wm);
if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n",
- pipe);
+ DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n",
+ pipe_name(pipe));
return;
}
I915_WRITE(WM1S_LP_ILK, sprite_wm);
@@ -2179,8 +2775,8 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
SNB_READ_WM2_LATENCY() * 500,
&sprite_wm);
if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n",
- pipe);
+ DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n",
+ pipe_name(pipe));
return;
}
I915_WRITE(WM2S_LP_IVB, sprite_wm);
@@ -2191,8 +2787,8 @@ static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
SNB_READ_WM3_LATENCY() * 500,
&sprite_wm);
if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n",
- pipe);
+ DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n",
+ pipe_name(pipe));
return;
}
I915_WRITE(WM3S_LP_IVB, sprite_wm);
@@ -2238,23 +2834,15 @@ void intel_update_watermarks(struct drm_device *dev)
dev_priv->display.update_wm(dev);
}
-void intel_update_linetime_watermarks(struct drm_device *dev,
- int pipe, struct drm_display_mode *mode)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->display.update_linetime_wm)
- dev_priv->display.update_linetime_wm(dev, pipe, mode);
-}
-
void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
- uint32_t sprite_width, int pixel_size)
+ uint32_t sprite_width, int pixel_size,
+ bool enable)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (dev_priv->display.update_sprite_wm)
dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
- pixel_size);
+ pixel_size, enable);
}
static struct drm_i915_gem_object *
@@ -2481,6 +3069,67 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
trace_intel_gpu_freq_change(val * 50);
}
+/*
+ * Wait until the previous freq change has completed,
+ * or the timeout elapsed, and then update our notion
+ * of the current GPU frequency.
+ */
+static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+ u32 pval;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+ do {
+ pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+ if (time_after(jiffies, timeout)) {
+ DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
+ break;
+ }
+ udelay(10);
+ } while (pval & 1);
+
+ pval >>= 8;
+
+ if (pval != dev_priv->rps.cur_delay)
+ DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay),
+ dev_priv->rps.cur_delay,
+ vlv_gpu_freq(dev_priv->mem_freq, pval), pval);
+
+ dev_priv->rps.cur_delay = pval;
+}
+
+void valleyview_set_rps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ gen6_rps_limits(dev_priv, &val);
+
+ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+ WARN_ON(val > dev_priv->rps.max_delay);
+ WARN_ON(val < dev_priv->rps.min_delay);
+
+ vlv_update_rps_cur_delay(dev_priv);
+
+ DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.cur_delay),
+ dev_priv->rps.cur_delay,
+ vlv_gpu_freq(dev_priv->mem_freq, val), val);
+
+ if (val == dev_priv->rps.cur_delay)
+ return;
+
+ vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+
+ dev_priv->rps.cur_delay = val;
+
+ trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val));
+}
+
+
static void gen6_disable_rps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2488,6 +3137,25 @@ static void gen6_disable_rps(struct drm_device *dev)
I915_WRITE(GEN6_RC_CONTROL, 0);
I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+ I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS);
+ /* Complete PM interrupt masking here doesn't race with the rps work
+ * item again unmasking PM interrupts because that is using a different
+ * register (PMIMR) to mask PM interrupts. The only risk is in leaving
+ * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
+
+ spin_lock_irq(&dev_priv->rps.lock);
+ dev_priv->rps.pm_iir = 0;
+ spin_unlock_irq(&dev_priv->rps.lock);
+
+ I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
+}
+
+static void valleyview_disable_rps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(GEN6_RC_CONTROL, 0);
+ I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
I915_WRITE(GEN6_PMIER, 0);
/* Complete PM interrupt masking here doesn't race with the rps work
* item again unmasking PM interrupts because that is using a different
@@ -2499,6 +3167,11 @@ static void gen6_disable_rps(struct drm_device *dev)
spin_unlock_irq(&dev_priv->rps.lock);
I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+
+ if (dev_priv->vlv_pctx) {
+ drm_gem_object_unreference(&dev_priv->vlv_pctx->base);
+ dev_priv->vlv_pctx = NULL;
+ }
}
int intel_enable_rc6(const struct drm_device *dev)
@@ -2655,12 +3328,15 @@ static void gen6_enable_rps(struct drm_device *dev)
gen6_set_rps(dev_priv->dev, (gt_perf_status & 0xff00) >> 8);
/* requires MSI enabled */
- I915_WRITE(GEN6_PMIER, GEN6_PM_DEFERRED_EVENTS);
+ I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) | GEN6_PM_RPS_EVENTS);
spin_lock_irq(&dev_priv->rps.lock);
- WARN_ON(dev_priv->rps.pm_iir != 0);
- I915_WRITE(GEN6_PMIMR, 0);
+ /* FIXME: Our interrupt enabling sequence is bonghits.
+ * dev_priv->rps.pm_iir really should be 0 here. */
+ dev_priv->rps.pm_iir = 0;
+ I915_WRITE(GEN6_PMIMR, I915_READ(GEN6_PMIMR) & ~GEN6_PM_RPS_EVENTS);
+ I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
spin_unlock_irq(&dev_priv->rps.lock);
- /* enable all PM interrupts */
+ /* unmask all PM interrupts */
I915_WRITE(GEN6_PMINTRMSK, 0);
rc6vids = 0;
@@ -2742,6 +3418,207 @@ static void gen6_update_ring_freq(struct drm_device *dev)
}
}
+int valleyview_rps_max_freq(struct drm_i915_private *dev_priv)
+{
+ u32 val, rp0;
+
+ val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FREQ_FUSE);
+
+ rp0 = (val & FB_GFX_MAX_FREQ_FUSE_MASK) >> FB_GFX_MAX_FREQ_FUSE_SHIFT;
+ /* Clamp to max */
+ rp0 = min_t(u32, rp0, 0xea);
+
+ return rp0;
+}
+
+static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
+{
+ u32 val, rpe;
+
+ val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_LO);
+ rpe = (val & FB_FMAX_VMIN_FREQ_LO_MASK) >> FB_FMAX_VMIN_FREQ_LO_SHIFT;
+ val = vlv_nc_read(dev_priv, IOSF_NC_FB_GFX_FMAX_FUSE_HI);
+ rpe |= (val & FB_FMAX_VMIN_FREQ_HI_MASK) << 5;
+
+ return rpe;
+}
+
+int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
+{
+ return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
+}
+
+static void vlv_rps_timer_work(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+ rps.vlv_work.work);
+
+ /*
+ * Timer fired, we must be idle. Drop to min voltage state.
+ * Note: we use RPe here since it should match the
+ * Vmin we were shooting for. That should give us better
+ * perf when we come back out of RC6 than if we used the
+ * min freq available.
+ */
+ mutex_lock(&dev_priv->rps.hw_lock);
+ if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay)
+ valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void valleyview_setup_pctx(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *pctx;
+ unsigned long pctx_paddr;
+ u32 pcbr;
+ int pctx_size = 24*1024;
+
+ pcbr = I915_READ(VLV_PCBR);
+ if (pcbr) {
+ /* BIOS set it up already, grab the pre-alloc'd space */
+ int pcbr_offset;
+
+ pcbr_offset = (pcbr & (~4095)) - dev_priv->mm.stolen_base;
+ pctx = i915_gem_object_create_stolen_for_preallocated(dev_priv->dev,
+ pcbr_offset,
+ -1,
+ pctx_size);
+ goto out;
+ }
+
+ /*
+ * From the Gunit register HAS:
+ * The Gfx driver is expected to program this register and ensure
+ * proper allocation within Gfx stolen memory. For example, this
+ * register should be programmed such than the PCBR range does not
+ * overlap with other ranges, such as the frame buffer, protected
+ * memory, or any other relevant ranges.
+ */
+ pctx = i915_gem_object_create_stolen(dev, pctx_size);
+ if (!pctx) {
+ DRM_DEBUG("not enough stolen space for PCTX, disabling\n");
+ return;
+ }
+
+ pctx_paddr = dev_priv->mm.stolen_base + pctx->stolen->start;
+ I915_WRITE(VLV_PCBR, pctx_paddr);
+
+out:
+ dev_priv->vlv_pctx = pctx;
+}
+
+static void valleyview_enable_rps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
+ u32 gtfifodbg, val;
+ int i;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+ if ((gtfifodbg = I915_READ(GTFIFODBG))) {
+ DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
+ I915_WRITE(GTFIFODBG, gtfifodbg);
+ }
+
+ valleyview_setup_pctx(dev);
+
+ gen6_gt_force_wake_get(dev_priv);
+
+ I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
+ I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
+ I915_WRITE(GEN6_RP_UP_EI, 66000);
+ I915_WRITE(GEN6_RP_DOWN_EI, 350000);
+
+ I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
+
+ I915_WRITE(GEN6_RP_CONTROL,
+ GEN6_RP_MEDIA_TURBO |
+ GEN6_RP_MEDIA_HW_NORMAL_MODE |
+ GEN6_RP_MEDIA_IS_GFX |
+ GEN6_RP_ENABLE |
+ GEN6_RP_UP_BUSY_AVG |
+ GEN6_RP_DOWN_IDLE_CONT);
+
+ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 0x00280000);
+ I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
+ I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
+
+ for_each_ring(ring, dev_priv, i)
+ I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
+
+ I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350);
+
+ /* allows RC6 residency counter to work */
+ I915_WRITE(0x138104, _MASKED_BIT_ENABLE(0x3));
+ I915_WRITE(GEN6_RC_CONTROL,
+ GEN7_RC_CTL_TO_MODE);
+
+ val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+ switch ((val >> 6) & 3) {
+ case 0:
+ case 1:
+ dev_priv->mem_freq = 800;
+ break;
+ case 2:
+ dev_priv->mem_freq = 1066;
+ break;
+ case 3:
+ dev_priv->mem_freq = 1333;
+ break;
+ }
+ DRM_DEBUG_DRIVER("DDR speed: %d MHz", dev_priv->mem_freq);
+
+ DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no");
+ DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
+
+ dev_priv->rps.cur_delay = (val >> 8) & 0xff;
+ DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.cur_delay),
+ dev_priv->rps.cur_delay);
+
+ dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv);
+ dev_priv->rps.hw_max = dev_priv->rps.max_delay;
+ DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.max_delay),
+ dev_priv->rps.max_delay);
+
+ dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv);
+ DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.rpe_delay),
+ dev_priv->rps.rpe_delay);
+
+ dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv);
+ DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.min_delay),
+ dev_priv->rps.min_delay);
+
+ DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
+ vlv_gpu_freq(dev_priv->mem_freq,
+ dev_priv->rps.rpe_delay),
+ dev_priv->rps.rpe_delay);
+
+ INIT_DELAYED_WORK(&dev_priv->rps.vlv_work, vlv_rps_timer_work);
+
+ valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
+
+ /* requires MSI enabled */
+ I915_WRITE(GEN6_PMIER, GEN6_PM_RPS_EVENTS);
+ spin_lock_irq(&dev_priv->rps.lock);
+ WARN_ON(dev_priv->rps.pm_iir != 0);
+ I915_WRITE(GEN6_PMIMR, 0);
+ spin_unlock_irq(&dev_priv->rps.lock);
+ /* enable all PM interrupts */
+ I915_WRITE(GEN6_PMINTRMSK, 0);
+
+ gen6_gt_force_wake_put(dev_priv);
+}
+
void ironlake_teardown_rc6(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3465,13 +4342,22 @@ void intel_disable_gt_powersave(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ /* Interrupts should be disabled already to avoid re-arming. */
+ WARN_ON(dev->irq_enabled);
+
if (IS_IRONLAKE_M(dev)) {
ironlake_disable_drps(dev);
ironlake_disable_rc6(dev);
- } else if (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev)) {
+ } else if (INTEL_INFO(dev)->gen >= 6) {
cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
+ cancel_work_sync(&dev_priv->rps.work);
+ if (IS_VALLEYVIEW(dev))
+ cancel_delayed_work_sync(&dev_priv->rps.vlv_work);
mutex_lock(&dev_priv->rps.hw_lock);
- gen6_disable_rps(dev);
+ if (IS_VALLEYVIEW(dev))
+ valleyview_disable_rps(dev);
+ else
+ gen6_disable_rps(dev);
mutex_unlock(&dev_priv->rps.hw_lock);
}
}
@@ -3484,8 +4370,13 @@ static void intel_gen6_powersave_work(struct work_struct *work)
struct drm_device *dev = dev_priv->dev;
mutex_lock(&dev_priv->rps.hw_lock);
- gen6_enable_rps(dev);
- gen6_update_ring_freq(dev);
+
+ if (IS_VALLEYVIEW(dev)) {
+ valleyview_enable_rps(dev);
+ } else {
+ gen6_enable_rps(dev);
+ gen6_update_ring_freq(dev);
+ }
mutex_unlock(&dev_priv->rps.hw_lock);
}
@@ -3497,7 +4388,7 @@ void intel_enable_gt_powersave(struct drm_device *dev)
ironlake_enable_drps(dev);
ironlake_enable_rc6(dev);
intel_init_emon(dev);
- } else if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
+ } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
/*
* PCU communication is slow and this doesn't need to be
* done at any specific time, so do this out of our fast path
@@ -3520,6 +4411,19 @@ static void ibx_init_clock_gating(struct drm_device *dev)
I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
}
+static void g4x_disable_trickle_feed(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+}
+
static void ironlake_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3579,10 +4483,12 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
_3D_CHICKEN2_WM_READ_PIPELINED << 16 |
_3D_CHICKEN2_WM_READ_PIPELINED);
- /* WaDisableRenderCachePipelinedFlush */
+ /* WaDisableRenderCachePipelinedFlush:ilk */
I915_WRITE(CACHE_MODE_0,
_MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE));
+ g4x_disable_trickle_feed(dev);
+
ibx_init_clock_gating(dev);
}
@@ -3607,7 +4513,7 @@ static void cpt_init_clock_gating(struct drm_device *dev)
val = I915_READ(TRANS_CHICKEN2(pipe));
val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
val &= ~TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
- if (dev_priv->fdi_rx_polarity_inverted)
+ if (dev_priv->vbt.fdi_rx_polarity_inverted)
val |= TRANS_CHICKEN2_FDI_POLARITY_REVERSED;
val &= ~TRANS_CHICKEN2_FRAME_START_DELAY_MASK;
val &= ~TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER;
@@ -3637,7 +4543,6 @@ static void gen6_check_mch_setup(struct drm_device *dev)
static void gen6_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate);
@@ -3646,11 +4551,11 @@ static void gen6_init_clock_gating(struct drm_device *dev)
I915_READ(ILK_DISPLAY_CHICKEN2) |
ILK_ELPIN_409_SELECT);
- /* WaDisableHiZPlanesWhenMSAAEnabled */
+ /* WaDisableHiZPlanesWhenMSAAEnabled:snb */
I915_WRITE(_3D_CHICKEN,
_MASKED_BIT_ENABLE(_3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB));
- /* WaSetupGtModeTdRowDispatch */
+ /* WaSetupGtModeTdRowDispatch:snb */
if (IS_SNB_GT1(dev))
I915_WRITE(GEN6_GT_MODE,
_MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE));
@@ -3677,8 +4582,8 @@ static void gen6_init_clock_gating(struct drm_device *dev)
* According to the spec, bit 11 (RCCUNIT) must also be set,
* but we didn't debug actual testcases to find it out.
*
- * Also apply WaDisableVDSUnitClockGating and
- * WaDisableRCPBUnitClockGating.
+ * Also apply WaDisableVDSUnitClockGating:snb and
+ * WaDisableRCPBUnitClockGating:snb.
*/
I915_WRITE(GEN6_UCGCTL2,
GEN7_VDSUNIT_CLOCK_GATE_DISABLE |
@@ -3709,16 +4614,11 @@ static void gen6_init_clock_gating(struct drm_device *dev)
ILK_DPARBUNIT_CLOCK_GATE_ENABLE |
ILK_DPFDUNIT_CLOCK_GATE_ENABLE);
- /* WaMbcDriverBootEnable */
+ /* WaMbcDriverBootEnable:snb */
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
+ g4x_disable_trickle_feed(dev);
/* The default value should be 0x200 according to docs, but the two
* platforms I checked have a 0 for this. (Maybe BIOS overrides?) */
@@ -3739,7 +4639,6 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
reg |= GEN7_FF_VS_SCHED_HW;
reg |= GEN7_FF_DS_SCHED_HW;
- /* WaVSRefCountFullforceMissDisable */
if (IS_HASWELL(dev_priv->dev))
reg &= ~GEN7_FF_VS_REF_CNT_FFME;
@@ -3758,65 +4657,72 @@ static void lpt_init_clock_gating(struct drm_device *dev)
I915_WRITE(SOUTH_DSPCLK_GATE_D,
I915_READ(SOUTH_DSPCLK_GATE_D) |
PCH_LP_PARTITION_LEVEL_DISABLE);
+
+ /* WADPOClockGatingDisable:hsw */
+ I915_WRITE(_TRANSA_CHICKEN1,
+ I915_READ(_TRANSA_CHICKEN1) |
+ TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
+}
+
+static void lpt_suspend_hw(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
+ uint32_t val = I915_READ(SOUTH_DSPCLK_GATE_D);
+
+ val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, val);
+ }
}
static void haswell_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
I915_WRITE(WM3_LP_ILK, 0);
I915_WRITE(WM2_LP_ILK, 0);
I915_WRITE(WM1_LP_ILK, 0);
/* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
- * This implements the WaDisableRCZUnitClockGating workaround.
+ * This implements the WaDisableRCZUnitClockGating:hsw workaround.
*/
I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
- /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ /* Apply the WaDisableRHWOOptimizationForRenderHang:hsw workaround. */
I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
- /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ /* WaApplyL3ControlAndL3ChickenMode:hsw */
I915_WRITE(GEN7_L3CNTLREG1,
GEN7_WA_FOR_GEN7_L3_CONTROL);
I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
GEN7_WA_L3_CHICKEN_MODE);
- /* This is required by WaCatErrorRejectionIssue */
+ /* This is required by WaCatErrorRejectionIssue:hsw */
I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
+ g4x_disable_trickle_feed(dev);
+ /* WaVSRefCountFullforceMissDisable:hsw */
gen7_setup_fixed_func_scheduler(dev_priv);
- /* WaDisable4x2SubspanOptimization */
+ /* WaDisable4x2SubspanOptimization:hsw */
I915_WRITE(CACHE_MODE_1,
_MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
- /* WaMbcDriverBootEnable */
+ /* WaMbcDriverBootEnable:hsw */
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
- /* WaSwitchSolVfFArbitrationPriority */
+ /* WaSwitchSolVfFArbitrationPriority:hsw */
I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
- /* XXX: This is a workaround for early silicon revisions and should be
- * removed later.
- */
- I915_WRITE(WM_DBG,
- I915_READ(WM_DBG) |
- WM_DBG_DISALLOW_MULTIPLE_LP |
- WM_DBG_DISALLOW_SPRITE |
- WM_DBG_DISALLOW_MAXFIFO);
+ /* WaRsPkgCStateDisplayPMReq:hsw */
+ I915_WRITE(CHICKEN_PAR1_1,
+ I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
lpt_init_clock_gating(dev);
}
@@ -3824,7 +4730,6 @@ static void haswell_init_clock_gating(struct drm_device *dev)
static void ivybridge_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
uint32_t snpcr;
I915_WRITE(WM3_LP_ILK, 0);
@@ -3833,16 +4738,16 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
- /* WaDisableEarlyCull */
+ /* WaDisableEarlyCull:ivb */
I915_WRITE(_3D_CHICKEN3,
_MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL));
- /* WaDisableBackToBackFlipFix */
+ /* WaDisableBackToBackFlipFix:ivb */
I915_WRITE(IVB_CHICKEN3,
CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
CHICKEN3_DGMG_DONE_FIX_DISABLE);
- /* WaDisablePSDDualDispatchEnable */
+ /* WaDisablePSDDualDispatchEnable:ivb */
if (IS_IVB_GT1(dev))
I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
_MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
@@ -3850,11 +4755,11 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2,
_MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
- /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */
I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
- /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ /* WaApplyL3ControlAndL3ChickenMode:ivb */
I915_WRITE(GEN7_L3CNTLREG1,
GEN7_WA_FOR_GEN7_L3_CONTROL);
I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
@@ -3867,7 +4772,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
- /* WaForceL3Serialization */
+ /* WaForceL3Serialization:ivb */
I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
~L3SQ_URB_READ_CAM_MATCH_DISABLE);
@@ -3882,31 +4787,27 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
* but we didn't debug actual testcases to find it out.
*
* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
- * This implements the WaDisableRCZUnitClockGating workaround.
+ * This implements the WaDisableRCZUnitClockGating:ivb workaround.
*/
I915_WRITE(GEN6_UCGCTL2,
GEN6_RCZUNIT_CLOCK_GATE_DISABLE |
GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
- /* This is required by WaCatErrorRejectionIssue */
+ /* This is required by WaCatErrorRejectionIssue:ivb */
I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
+ g4x_disable_trickle_feed(dev);
- /* WaMbcDriverBootEnable */
+ /* WaMbcDriverBootEnable:ivb */
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
+ /* WaVSRefCountFullforceMissDisable:ivb */
gen7_setup_fixed_func_scheduler(dev_priv);
- /* WaDisable4x2SubspanOptimization */
+ /* WaDisable4x2SubspanOptimization:ivb */
I915_WRITE(CACHE_MODE_1,
_MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
@@ -3924,54 +4825,45 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
static void valleyview_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
-
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
- I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE);
- /* WaDisableEarlyCull */
+ /* WaDisableEarlyCull:vlv */
I915_WRITE(_3D_CHICKEN3,
_MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL));
- /* WaDisableBackToBackFlipFix */
+ /* WaDisableBackToBackFlipFix:vlv */
I915_WRITE(IVB_CHICKEN3,
CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
CHICKEN3_DGMG_DONE_FIX_DISABLE);
- /* WaDisablePSDDualDispatchEnable */
+ /* WaDisablePSDDualDispatchEnable:vlv */
I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
_MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP |
GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
- /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ /* Apply the WaDisableRHWOOptimizationForRenderHang:vlv workaround. */
I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
- /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ /* WaApplyL3ControlAndL3ChickenMode:vlv */
I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS);
I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE);
- /* WaForceL3Serialization */
+ /* WaForceL3Serialization:vlv */
I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
~L3SQ_URB_READ_CAM_MATCH_DISABLE);
- /* WaDisableDopClockGating */
+ /* WaDisableDopClockGating:vlv */
I915_WRITE(GEN7_ROW_CHICKEN2,
_MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
- /* WaForceL3Serialization */
- I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
- ~L3SQ_URB_READ_CAM_MATCH_DISABLE);
-
- /* This is required by WaCatErrorRejectionIssue */
+ /* This is required by WaCatErrorRejectionIssue:vlv */
I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
- /* WaMbcDriverBootEnable */
+ /* WaMbcDriverBootEnable:vlv */
I915_WRITE(GEN6_MBCTL, I915_READ(GEN6_MBCTL) |
GEN6_MBCTL_ENABLE_BOOT_FETCH);
@@ -3987,10 +4879,10 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
* but we didn't debug actual testcases to find it out.
*
* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
- * This implements the WaDisableRCZUnitClockGating workaround.
+ * This implements the WaDisableRCZUnitClockGating:vlv workaround.
*
- * Also apply WaDisableVDSUnitClockGating and
- * WaDisableRCPBUnitClockGating.
+ * Also apply WaDisableVDSUnitClockGating:vlv and
+ * WaDisableRCPBUnitClockGating:vlv.
*/
I915_WRITE(GEN6_UCGCTL2,
GEN7_VDSUNIT_CLOCK_GATE_DISABLE |
@@ -4001,18 +4893,13 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
+ I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
I915_WRITE(CACHE_MODE_1,
_MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
/*
- * WaDisableVLVClockGating_VBIIssue
+ * WaDisableVLVClockGating_VBIIssue:vlv
* Disable clock gating on th GCFG unit to prevent a delay
* in the reporting of vblank events.
*/
@@ -4048,6 +4935,8 @@ static void g4x_init_clock_gating(struct drm_device *dev)
/* WaDisableRenderCachePipelinedFlush */
I915_WRITE(CACHE_MODE_0,
_MASKED_BIT_ENABLE(CM0_PIPELINED_RENDER_FLUSH_DISABLE));
+
+ g4x_disable_trickle_feed(dev);
}
static void crestline_init_clock_gating(struct drm_device *dev)
@@ -4059,6 +4948,8 @@ static void crestline_init_clock_gating(struct drm_device *dev)
I915_WRITE(DSPCLK_GATE_D, 0);
I915_WRITE(RAMCLK_GATE_D, 0);
I915_WRITE16(DEUC, 0);
+ I915_WRITE(MI_ARB_STATE,
+ _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
}
static void broadwater_init_clock_gating(struct drm_device *dev)
@@ -4071,6 +4962,8 @@ static void broadwater_init_clock_gating(struct drm_device *dev)
I965_ISC_CLOCK_GATE_DISABLE |
I965_FBC_CLOCK_GATE_DISABLE);
I915_WRITE(RENCLK_GATE_D2, 0);
+ I915_WRITE(MI_ARB_STATE,
+ _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
}
static void gen3_init_clock_gating(struct drm_device *dev)
@@ -4110,34 +5003,50 @@ void intel_init_clock_gating(struct drm_device *dev)
dev_priv->display.init_clock_gating(dev);
}
+void intel_suspend_hw(struct drm_device *dev)
+{
+ if (HAS_PCH_LPT(dev))
+ lpt_suspend_hw(dev);
+}
+
/**
* We should only use the power well if we explicitly asked the hardware to
* enable it, so check if it's enabled and also check if we've requested it to
* be enabled.
*/
-bool intel_using_power_well(struct drm_device *dev)
+bool intel_display_power_enabled(struct drm_device *dev,
+ enum intel_display_power_domain domain)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (IS_HASWELL(dev))
+ if (!HAS_POWER_WELL(dev))
+ return true;
+
+ switch (domain) {
+ case POWER_DOMAIN_PIPE_A:
+ case POWER_DOMAIN_TRANSCODER_EDP:
+ return true;
+ case POWER_DOMAIN_PIPE_B:
+ case POWER_DOMAIN_PIPE_C:
+ case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
+ case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
+ case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
+ case POWER_DOMAIN_TRANSCODER_A:
+ case POWER_DOMAIN_TRANSCODER_B:
+ case POWER_DOMAIN_TRANSCODER_C:
return I915_READ(HSW_PWR_WELL_DRIVER) ==
(HSW_PWR_WELL_ENABLE | HSW_PWR_WELL_STATE);
- else
- return true;
+ default:
+ BUG();
+ }
}
-void intel_set_power_well(struct drm_device *dev, bool enable)
+static void __intel_set_power_well(struct drm_device *dev, bool enable)
{
struct drm_i915_private *dev_priv = dev->dev_private;
bool is_enabled, enable_requested;
uint32_t tmp;
- if (!HAS_POWER_WELL(dev))
- return;
-
- if (!i915_disable_power_well && !enable)
- return;
-
tmp = I915_READ(HSW_PWR_WELL_DRIVER);
is_enabled = tmp & HSW_PWR_WELL_STATE;
enable_requested = tmp & HSW_PWR_WELL_ENABLE;
@@ -4160,6 +5069,79 @@ void intel_set_power_well(struct drm_device *dev, bool enable)
}
}
+static struct i915_power_well *hsw_pwr;
+
+/* Display audio driver power well request */
+void i915_request_power_well(void)
+{
+ if (WARN_ON(!hsw_pwr))
+ return;
+
+ spin_lock_irq(&hsw_pwr->lock);
+ if (!hsw_pwr->count++ &&
+ !hsw_pwr->i915_request)
+ __intel_set_power_well(hsw_pwr->device, true);
+ spin_unlock_irq(&hsw_pwr->lock);
+}
+EXPORT_SYMBOL_GPL(i915_request_power_well);
+
+/* Display audio driver power well release */
+void i915_release_power_well(void)
+{
+ if (WARN_ON(!hsw_pwr))
+ return;
+
+ spin_lock_irq(&hsw_pwr->lock);
+ WARN_ON(!hsw_pwr->count);
+ if (!--hsw_pwr->count &&
+ !hsw_pwr->i915_request)
+ __intel_set_power_well(hsw_pwr->device, false);
+ spin_unlock_irq(&hsw_pwr->lock);
+}
+EXPORT_SYMBOL_GPL(i915_release_power_well);
+
+int i915_init_power_well(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ hsw_pwr = &dev_priv->power_well;
+
+ hsw_pwr->device = dev;
+ spin_lock_init(&hsw_pwr->lock);
+ hsw_pwr->count = 0;
+
+ return 0;
+}
+
+void i915_remove_power_well(struct drm_device *dev)
+{
+ hsw_pwr = NULL;
+}
+
+void intel_set_power_well(struct drm_device *dev, bool enable)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct i915_power_well *power_well = &dev_priv->power_well;
+
+ if (!HAS_POWER_WELL(dev))
+ return;
+
+ if (!i915_disable_power_well && !enable)
+ return;
+
+ spin_lock_irq(&power_well->lock);
+ power_well->i915_request = enable;
+
+ /* only reject "disable" power well request */
+ if (power_well->count && !enable) {
+ spin_unlock_irq(&power_well->lock);
+ return;
+ }
+
+ __intel_set_power_well(dev, enable);
+ spin_unlock_irq(&power_well->lock);
+}
+
/*
* Starting with Haswell, we have a "Power Down Well" that can be turned off
* when not needed anymore. We have 4 registers that can request the power well
@@ -4190,7 +5172,12 @@ void intel_init_pm(struct drm_device *dev)
if (I915_HAS_FBC(dev)) {
if (HAS_PCH_SPLIT(dev)) {
dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
- dev_priv->display.enable_fbc = ironlake_enable_fbc;
+ if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
+ dev_priv->display.enable_fbc =
+ gen7_enable_fbc;
+ else
+ dev_priv->display.enable_fbc =
+ ironlake_enable_fbc;
dev_priv->display.disable_fbc = ironlake_disable_fbc;
} else if (IS_GM45(dev)) {
dev_priv->display.fbc_enabled = g4x_fbc_enabled;
@@ -4242,10 +5229,10 @@ void intel_init_pm(struct drm_device *dev)
}
dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
} else if (IS_HASWELL(dev)) {
- if (SNB_READ_WM0_LATENCY()) {
- dev_priv->display.update_wm = sandybridge_update_wm;
- dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
- dev_priv->display.update_linetime_wm = haswell_update_linetime_wm;
+ if (I915_READ64(MCH_SSKPD)) {
+ dev_priv->display.update_wm = haswell_update_wm;
+ dev_priv->display.update_sprite_wm =
+ haswell_update_sprite_wm;
} else {
DRM_DEBUG_KMS("Failed to read display plane latency. "
"Disable CxSR\n");
@@ -4340,6 +5327,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+ /* WaRsForcewakeWaitTC0:snb */
__gen6_gt_wait_for_thread_c0(dev_priv);
}
@@ -4371,6 +5359,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+ /* WaRsForcewakeWaitTC0:ivb,hsw */
__gen6_gt_wait_for_thread_c0(dev_priv);
}
@@ -4474,6 +5463,7 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
FORCEWAKE_ACK_TIMEOUT_MS))
DRM_ERROR("Timed out waiting for media to ack forcewake request.\n");
+ /* WaRsForcewakeWaitTC0:vlv */
__gen6_gt_wait_for_thread_c0(dev_priv);
}
@@ -4568,55 +5558,58 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
return 0;
}
-static int vlv_punit_rw(struct drm_i915_private *dev_priv, u8 opcode,
- u8 addr, u32 *val)
+int vlv_gpu_freq(int ddr_freq, int val)
{
- u32 cmd, devfn, port, be, bar;
-
- bar = 0;
- be = 0xf;
- port = IOSF_PORT_PUNIT;
- devfn = PCI_DEVFN(2, 0);
+ int mult, base;
- cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
- (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
- (bar << IOSF_BAR_SHIFT);
-
- WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-
- if (I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) {
- DRM_DEBUG_DRIVER("warning: pcode (%s) mailbox access failed\n",
- opcode == PUNIT_OPCODE_REG_READ ?
- "read" : "write");
- return -EAGAIN;
+ switch (ddr_freq) {
+ case 800:
+ mult = 20;
+ base = 120;
+ break;
+ case 1066:
+ mult = 22;
+ base = 133;
+ break;
+ case 1333:
+ mult = 21;
+ base = 125;
+ break;
+ default:
+ return -1;
}
- I915_WRITE(VLV_IOSF_ADDR, addr);
- if (opcode == PUNIT_OPCODE_REG_WRITE)
- I915_WRITE(VLV_IOSF_DATA, *val);
- I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd);
+ return ((val - 0xbd) * mult) + base;
+}
- if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0,
- 500)) {
- DRM_ERROR("timeout waiting for pcode %s (%d) to finish\n",
- opcode == PUNIT_OPCODE_REG_READ ? "read" : "write",
- addr);
- return -ETIMEDOUT;
+int vlv_freq_opcode(int ddr_freq, int val)
+{
+ int mult, base;
+
+ switch (ddr_freq) {
+ case 800:
+ mult = 20;
+ base = 120;
+ break;
+ case 1066:
+ mult = 22;
+ base = 133;
+ break;
+ case 1333:
+ mult = 21;
+ base = 125;
+ break;
+ default:
+ return -1;
}
- if (opcode == PUNIT_OPCODE_REG_READ)
- *val = I915_READ(VLV_IOSF_DATA);
- I915_WRITE(VLV_IOSF_DATA, 0);
+ val /= mult;
+ val -= base / mult;
+ val += 0xbd;
- return 0;
-}
+ if (val > 0xea)
+ val = 0xea;
-int valleyview_punit_read(struct drm_i915_private *dev_priv, u8 addr, u32 *val)
-{
- return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_READ, addr, val);
+ return val;
}
-int valleyview_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
-{
- return vlv_punit_rw(dev_priv, PUNIT_OPCODE_REG_WRITE, addr, &val);
-}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 1d5d613eb6be..e51ab552046c 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -280,6 +280,27 @@ gen7_render_ring_cs_stall_wa(struct intel_ring_buffer *ring)
return 0;
}
+static int gen7_ring_fbc_flush(struct intel_ring_buffer *ring, u32 value)
+{
+ int ret;
+
+ if (!ring->fbc_dirty)
+ return 0;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+ intel_ring_emit(ring, MI_NOOP);
+ /* WaFbcNukeOn3DBlt:ivb/hsw */
+ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+ intel_ring_emit(ring, MSG_FBC_REND_STATE);
+ intel_ring_emit(ring, value);
+ intel_ring_advance(ring);
+
+ ring->fbc_dirty = false;
+ return 0;
+}
+
static int
gen7_render_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate_domains, u32 flush_domains)
@@ -336,6 +357,9 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
intel_ring_emit(ring, 0);
intel_ring_advance(ring);
+ if (flush_domains)
+ return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
+
return 0;
}
@@ -429,6 +453,8 @@ static int init_ring_common(struct intel_ring_buffer *ring)
ring->last_retired_head = -1;
}
+ memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
+
out:
if (HAS_FORCE_WAKE(dev))
gen6_gt_force_wake_put(dev_priv);
@@ -464,9 +490,11 @@ init_pipe_control(struct intel_ring_buffer *ring)
goto err_unref;
pc->gtt_offset = obj->gtt_offset;
- pc->cpu_page = kmap(sg_page(obj->pages->sgl));
- if (pc->cpu_page == NULL)
+ pc->cpu_page = kmap(sg_page(obj->pages->sgl));
+ if (pc->cpu_page == NULL) {
+ ret = -ENOMEM;
goto err_unpin;
+ }
DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
ring->name, pc->gtt_offset);
@@ -515,6 +543,8 @@ static int init_render_ring(struct intel_ring_buffer *ring)
/* We need to disable the AsyncFlip performance optimisations in order
* to use MI_WAIT_FOR_EVENT within the CS. It should already be
* programmed to '1' on all products.
+ *
+ * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
*/
if (INTEL_INFO(dev)->gen >= 6)
I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
@@ -556,7 +586,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
if (HAS_L3_GPU_CACHE(dev))
- I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+ I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
return ret;
}
@@ -578,9 +608,16 @@ static void
update_mboxes(struct intel_ring_buffer *ring,
u32 mmio_offset)
{
+/* NB: In order to be able to do semaphore MBOX updates for varying number
+ * of rings, it's easiest if we round up each individual update to a
+ * multiple of 2 (since ring updates must always be a multiple of 2)
+ * even though the actual update only requires 3 dwords.
+ */
+#define MBOX_UPDATE_DWORDS 4
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
intel_ring_emit(ring, mmio_offset);
intel_ring_emit(ring, ring->outstanding_lazy_request);
+ intel_ring_emit(ring, MI_NOOP);
}
/**
@@ -595,19 +632,24 @@ update_mboxes(struct intel_ring_buffer *ring,
static int
gen6_add_request(struct intel_ring_buffer *ring)
{
- u32 mbox1_reg;
- u32 mbox2_reg;
- int ret;
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *useless;
+ int i, ret;
- ret = intel_ring_begin(ring, 10);
+ ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) *
+ MBOX_UPDATE_DWORDS) +
+ 4);
if (ret)
return ret;
+#undef MBOX_UPDATE_DWORDS
- mbox1_reg = ring->signal_mbox[0];
- mbox2_reg = ring->signal_mbox[1];
+ for_each_ring(useless, dev_priv, i) {
+ u32 mbox_reg = ring->signal_mbox[i];
+ if (mbox_reg != GEN6_NOSYNC)
+ update_mboxes(ring, mbox_reg);
+ }
- update_mboxes(ring, mbox1_reg);
- update_mboxes(ring, mbox2_reg);
intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
intel_ring_emit(ring, ring->outstanding_lazy_request);
@@ -779,7 +821,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
return false;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
POSTING_READ(GTIMR);
@@ -797,7 +839,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
dev_priv->gt_irq_mask |= ring->irq_enable_mask;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
POSTING_READ(GTIMR);
@@ -816,7 +858,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
return false;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
dev_priv->irq_mask &= ~ring->irq_enable_mask;
I915_WRITE(IMR, dev_priv->irq_mask);
POSTING_READ(IMR);
@@ -834,7 +876,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
dev_priv->irq_mask |= ring->irq_enable_mask;
I915_WRITE(IMR, dev_priv->irq_mask);
POSTING_READ(IMR);
@@ -853,7 +895,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
return false;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
dev_priv->irq_mask &= ~ring->irq_enable_mask;
I915_WRITE16(IMR, dev_priv->irq_mask);
POSTING_READ16(IMR);
@@ -871,7 +913,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
dev_priv->irq_mask |= ring->irq_enable_mask;
I915_WRITE16(IMR, dev_priv->irq_mask);
POSTING_READ16(IMR);
@@ -899,6 +941,9 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
case VCS:
mmio = BSD_HWS_PGA_GEN7;
break;
+ case VECS:
+ mmio = VEBOX_HWS_PGA_GEN7;
+ break;
}
} else if (IS_GEN6(ring->dev)) {
mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
@@ -961,10 +1006,11 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
gen6_gt_force_wake_get(dev_priv);
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
- I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
- GEN6_RENDER_L3_PARITY_ERROR));
+ I915_WRITE_IMR(ring,
+ ~(ring->irq_enable_mask |
+ GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
else
I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
@@ -984,9 +1030,10 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
- I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+ I915_WRITE_IMR(ring,
+ ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
else
I915_WRITE_IMR(ring, ~0);
dev_priv->gt_irq_mask |= ring->irq_enable_mask;
@@ -998,6 +1045,48 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
gen6_gt_force_wake_put(dev_priv);
}
+static bool
+hsw_vebox_get_irq(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock_irqsave(&dev_priv->rps.lock, flags);
+ if (ring->irq_refcount.pm++ == 0) {
+ u32 pm_imr = I915_READ(GEN6_PMIMR);
+ I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+ I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
+ POSTING_READ(GEN6_PMIMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+
+ return true;
+}
+
+static void
+hsw_vebox_put_irq(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ if (!dev->irq_enabled)
+ return;
+
+ spin_lock_irqsave(&dev_priv->rps.lock, flags);
+ if (--ring->irq_refcount.pm == 0) {
+ u32 pm_imr = I915_READ(GEN6_PMIMR);
+ I915_WRITE_IMR(ring, ~0);
+ I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
+ POSTING_READ(GEN6_PMIMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+}
+
static int
i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
u32 offset, u32 length,
@@ -1423,7 +1512,7 @@ int intel_ring_idle(struct intel_ring_buffer *ring)
/* We need to add any requests required to flush the objects and ring */
if (ring->outstanding_lazy_request) {
- ret = i915_add_request(ring, NULL, NULL);
+ ret = i915_add_request(ring, NULL);
if (ret)
return ret;
}
@@ -1500,6 +1589,7 @@ void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
}
ring->set_seqno(ring, seqno);
+ ring->hangcheck.seqno = seqno;
}
void intel_ring_advance(struct intel_ring_buffer *ring)
@@ -1546,8 +1636,8 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
_MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
}
-static int gen6_ring_flush(struct intel_ring_buffer *ring,
- u32 invalidate, u32 flush)
+static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate, u32 flush)
{
uint32_t cmd;
int ret;
@@ -1618,9 +1708,10 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
/* Blitter support (SandyBridge+) */
-static int blt_ring_flush(struct intel_ring_buffer *ring,
- u32 invalidate, u32 flush)
+static int gen6_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate, u32 flush)
{
+ struct drm_device *dev = ring->dev;
uint32_t cmd;
int ret;
@@ -1643,6 +1734,10 @@ static int blt_ring_flush(struct intel_ring_buffer *ring,
intel_ring_emit(ring, 0);
intel_ring_emit(ring, MI_NOOP);
intel_ring_advance(ring);
+
+ if (IS_GEN7(dev) && flush)
+ return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN);
+
return 0;
}
@@ -1662,15 +1757,18 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->flush = gen6_render_ring_flush;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
- ring->irq_enable_mask = GT_USER_INTERRUPT;
+ ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
ring->get_seqno = gen6_ring_get_seqno;
ring->set_seqno = ring_set_seqno;
ring->sync_to = gen6_ring_sync;
- ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID;
- ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV;
- ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB;
- ring->signal_mbox[0] = GEN6_VRSYNC;
- ring->signal_mbox[1] = GEN6_BRSYNC;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_RVE;
+ ring->signal_mbox[RCS] = GEN6_NOSYNC;
+ ring->signal_mbox[VCS] = GEN6_VRSYNC;
+ ring->signal_mbox[BCS] = GEN6_BRSYNC;
+ ring->signal_mbox[VECS] = GEN6_VERSYNC;
} else if (IS_GEN5(dev)) {
ring->add_request = pc_render_add_request;
ring->flush = gen4_render_ring_flush;
@@ -1678,7 +1776,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->set_seqno = pc_render_set_seqno;
ring->irq_get = gen5_ring_get_irq;
ring->irq_put = gen5_ring_put_irq;
- ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY;
+ ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT |
+ GT_RENDER_PIPECTL_NOTIFY_INTERRUPT;
} else {
ring->add_request = i9xx_add_request;
if (INTEL_INFO(dev)->gen < 4)
@@ -1816,20 +1915,23 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
/* gen6 bsd needs a special wa for tail updates */
if (IS_GEN6(dev))
ring->write_tail = gen6_bsd_ring_write_tail;
- ring->flush = gen6_ring_flush;
+ ring->flush = gen6_bsd_ring_flush;
ring->add_request = gen6_add_request;
ring->get_seqno = gen6_ring_get_seqno;
ring->set_seqno = ring_set_seqno;
- ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT;
+ ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
ring->sync_to = gen6_ring_sync;
- ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR;
- ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID;
- ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB;
- ring->signal_mbox[0] = GEN6_RVSYNC;
- ring->signal_mbox[1] = GEN6_BVSYNC;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_VVE;
+ ring->signal_mbox[RCS] = GEN6_RVSYNC;
+ ring->signal_mbox[VCS] = GEN6_NOSYNC;
+ ring->signal_mbox[BCS] = GEN6_BVSYNC;
+ ring->signal_mbox[VECS] = GEN6_VEVSYNC;
} else {
ring->mmio_base = BSD_RING_BASE;
ring->flush = bsd_ring_flush;
@@ -1837,7 +1939,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
ring->get_seqno = ring_get_seqno;
ring->set_seqno = ring_set_seqno;
if (IS_GEN5(dev)) {
- ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
+ ring->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
ring->irq_get = gen5_ring_get_irq;
ring->irq_put = gen5_ring_put_irq;
} else {
@@ -1862,20 +1964,56 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
ring->mmio_base = BLT_RING_BASE;
ring->write_tail = ring_write_tail;
- ring->flush = blt_ring_flush;
+ ring->flush = gen6_ring_flush;
ring->add_request = gen6_add_request;
ring->get_seqno = gen6_ring_get_seqno;
ring->set_seqno = ring_set_seqno;
- ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT;
+ ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
ring->sync_to = gen6_ring_sync;
- ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR;
- ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV;
- ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID;
- ring->signal_mbox[0] = GEN6_RBSYNC;
- ring->signal_mbox[1] = GEN6_VBSYNC;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_BVE;
+ ring->signal_mbox[RCS] = GEN6_RBSYNC;
+ ring->signal_mbox[VCS] = GEN6_VBSYNC;
+ ring->signal_mbox[BCS] = GEN6_NOSYNC;
+ ring->signal_mbox[VECS] = GEN6_VEBSYNC;
+ ring->init = init_ring_common;
+
+ return intel_init_ring_buffer(dev, ring);
+}
+
+int intel_init_vebox_ring_buffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[VECS];
+
+ ring->name = "video enhancement ring";
+ ring->id = VECS;
+
+ ring->mmio_base = VEBOX_RING_BASE;
+ ring->write_tail = ring_write_tail;
+ ring->flush = gen6_ring_flush;
+ ring->add_request = gen6_add_request;
+ ring->get_seqno = gen6_ring_get_seqno;
+ ring->set_seqno = ring_set_seqno;
+ ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT |
+ PM_VEBOX_CS_ERROR_INTERRUPT;
+ ring->irq_get = hsw_vebox_get_irq;
+ ring->irq_put = hsw_vebox_put_irq;
+ ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+ ring->sync_to = gen6_ring_sync;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VEB;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->signal_mbox[RCS] = GEN6_RVESYNC;
+ ring->signal_mbox[VCS] = GEN6_VVESYNC;
+ ring->signal_mbox[BCS] = GEN6_BVESYNC;
+ ring->signal_mbox[VECS] = GEN6_NOSYNC;
ring->init = init_ring_common;
return intel_init_ring_buffer(dev, ring);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index d66208c2c48b..799f04c9da45 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -37,14 +37,25 @@ struct intel_hw_status_page {
#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
+enum intel_ring_hangcheck_action { wait, active, kick, hung };
+
+struct intel_ring_hangcheck {
+ bool deadlock;
+ u32 seqno;
+ u32 acthd;
+ int score;
+ enum intel_ring_hangcheck_action action;
+};
+
struct intel_ring_buffer {
const char *name;
enum intel_ring_id {
RCS = 0x0,
VCS,
BCS,
+ VECS,
} id;
-#define I915_NUM_RINGS 3
+#define I915_NUM_RINGS 4
u32 mmio_base;
void __iomem *virtual_start;
struct drm_device *dev;
@@ -67,7 +78,10 @@ struct intel_ring_buffer {
*/
u32 last_retired_head;
- u32 irq_refcount; /* protected by dev_priv->irq_lock */
+ struct {
+ u32 gt; /* protected by dev_priv->irq_lock */
+ u32 pm; /* protected by dev_priv->rps.lock (sucks) */
+ } irq_refcount;
u32 irq_enable_mask; /* bitmask to enable ring interrupt */
u32 trace_irq_seqno;
u32 sync_seqno[I915_NUM_RINGS-1];
@@ -102,8 +116,11 @@ struct intel_ring_buffer {
struct intel_ring_buffer *to,
u32 seqno);
- u32 semaphore_register[3]; /*our mbox written by others */
- u32 signal_mbox[2]; /* mboxes this ring signals to */
+ /* our mbox written by others */
+ u32 semaphore_register[I915_NUM_RINGS];
+ /* mboxes this ring signals to */
+ u32 signal_mbox[I915_NUM_RINGS];
+
/**
* List of objects currently involved in rendering from the
* ringbuffer.
@@ -127,6 +144,7 @@ struct intel_ring_buffer {
*/
u32 outstanding_lazy_request;
bool gpu_caches_dirty;
+ bool fbc_dirty;
wait_queue_head_t irq_queue;
@@ -135,7 +153,9 @@ struct intel_ring_buffer {
*/
bool itlb_before_ctx_switch;
struct i915_hw_context *default_context;
- struct drm_i915_gem_object *last_context_obj;
+ struct i915_hw_context *last_context;
+
+ struct intel_ring_hangcheck hangcheck;
void *private;
};
@@ -224,6 +244,7 @@ int intel_ring_invalidate_all_caches(struct intel_ring_buffer *ring);
int intel_init_render_ring_buffer(struct drm_device *dev);
int intel_init_bsd_ring_buffer(struct drm_device *dev);
int intel_init_blt_ring_buffer(struct drm_device *dev);
+int intel_init_vebox_ring_buffer(struct drm_device *dev);
u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index d4ea6c265ce1..2628d5622449 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -80,7 +80,7 @@ struct intel_sdvo {
/*
* Capabilities of the SDVO device returned by
- * i830_sdvo_get_capabilities()
+ * intel_sdvo_get_capabilities()
*/
struct intel_sdvo_caps caps;
@@ -712,6 +712,13 @@ static bool intel_sdvo_set_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
intel_sdvo_set_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
}
+static bool intel_sdvo_get_timing(struct intel_sdvo *intel_sdvo, u8 cmd,
+ struct intel_sdvo_dtd *dtd)
+{
+ return intel_sdvo_get_value(intel_sdvo, cmd, &dtd->part1, sizeof(dtd->part1)) &&
+ intel_sdvo_get_value(intel_sdvo, cmd + 1, &dtd->part2, sizeof(dtd->part2));
+}
+
static bool intel_sdvo_set_input_timing(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_dtd *dtd)
{
@@ -726,6 +733,13 @@ static bool intel_sdvo_set_output_timing(struct intel_sdvo *intel_sdvo,
SDVO_CMD_SET_OUTPUT_TIMINGS_PART1, dtd);
}
+static bool intel_sdvo_get_input_timing(struct intel_sdvo *intel_sdvo,
+ struct intel_sdvo_dtd *dtd)
+{
+ return intel_sdvo_get_timing(intel_sdvo,
+ SDVO_CMD_GET_INPUT_TIMINGS_PART1, dtd);
+}
+
static bool
intel_sdvo_create_preferred_input_timing(struct intel_sdvo *intel_sdvo,
uint16_t clock,
@@ -1041,6 +1055,32 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
return true;
}
+static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config)
+{
+ unsigned dotclock = pipe_config->adjusted_mode.clock;
+ struct dpll *clock = &pipe_config->dpll;
+
+ /* SDVO TV has fixed PLL values depend on its clock range,
+ this mirrors vbios setting. */
+ if (dotclock >= 100000 && dotclock < 140500) {
+ clock->p1 = 2;
+ clock->p2 = 10;
+ clock->n = 3;
+ clock->m1 = 16;
+ clock->m2 = 8;
+ } else if (dotclock >= 140500 && dotclock <= 200000) {
+ clock->p1 = 1;
+ clock->p2 = 10;
+ clock->n = 6;
+ clock->m1 = 12;
+ clock->m2 = 8;
+ } else {
+ WARN(1, "SDVO TV clock out of range: %i\n", dotclock);
+ }
+
+ pipe_config->clock_set = true;
+}
+
static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
struct intel_crtc_config *pipe_config)
{
@@ -1066,6 +1106,7 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
(void) intel_sdvo_get_preferred_input_mode(intel_sdvo,
mode,
adjusted_mode);
+ pipe_config->sdvo_tv_clock = true;
} else if (intel_sdvo->is_lvds) {
if (!intel_sdvo_set_output_timings_from_mode(intel_sdvo,
intel_sdvo->sdvo_lvds_fixed_mode))
@@ -1097,6 +1138,10 @@ static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
if (intel_sdvo->color_range)
pipe_config->limited_color_range = true;
+ /* Clock computation needs to happen after pixel multiplier. */
+ if (intel_sdvo->is_tv)
+ i9xx_adjust_sdvo_tv_clock(pipe_config);
+
return true;
}
@@ -1174,6 +1219,7 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
switch (intel_crtc->config.pixel_multiplier) {
default:
+ WARN(1, "unknown pixel mutlipler specified\n");
case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1231,7 +1277,7 @@ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
struct intel_sdvo_connector *intel_sdvo_connector =
to_intel_sdvo_connector(&connector->base);
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
- u16 active_outputs;
+ u16 active_outputs = 0;
intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
@@ -1247,7 +1293,7 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
- u16 active_outputs;
+ u16 active_outputs = 0;
u32 tmp;
tmp = I915_READ(intel_sdvo->sdvo_reg);
@@ -1264,6 +1310,74 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
return true;
}
+static void intel_sdvo_get_config(struct intel_encoder *encoder,
+ struct intel_crtc_config *pipe_config)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
+ struct intel_sdvo_dtd dtd;
+ int encoder_pixel_multiplier = 0;
+ u32 flags = 0, sdvox;
+ u8 val;
+ bool ret;
+
+ ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
+ if (!ret) {
+ /* Some sdvo encoders are not spec compliant and don't
+ * implement the mandatory get_timings function. */
+ DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
+ pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS;
+ } else {
+ if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
+ flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
+ flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ flags |= DRM_MODE_FLAG_NVSYNC;
+ }
+
+ pipe_config->adjusted_mode.flags |= flags;
+
+ /*
+ * pixel multiplier readout is tricky: Only on i915g/gm it is stored in
+ * the sdvo port register, on all other platforms it is part of the dpll
+ * state. Since the general pipe state readout happens before the
+ * encoder->get_config we so already have a valid pixel multplier on all
+ * other platfroms.
+ */
+ if (IS_I915G(dev) || IS_I915GM(dev)) {
+ sdvox = I915_READ(intel_sdvo->sdvo_reg);
+ pipe_config->pixel_multiplier =
+ ((sdvox & SDVO_PORT_MULTIPLY_MASK)
+ >> SDVO_PORT_MULTIPLY_SHIFT) + 1;
+ }
+
+ /* Cross check the port pixel multiplier with the sdvo encoder state. */
+ intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1);
+ switch (val) {
+ case SDVO_CLOCK_RATE_MULT_1X:
+ encoder_pixel_multiplier = 1;
+ break;
+ case SDVO_CLOCK_RATE_MULT_2X:
+ encoder_pixel_multiplier = 2;
+ break;
+ case SDVO_CLOCK_RATE_MULT_4X:
+ encoder_pixel_multiplier = 4;
+ break;
+ }
+
+ if(HAS_PCH_SPLIT(dev))
+ return; /* no pixel multiplier readout support yet */
+
+ WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
+ "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
+ pipe_config->pixel_multiplier, encoder_pixel_multiplier);
+}
+
static void intel_disable_sdvo(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
@@ -1344,6 +1458,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
}
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
{
struct drm_crtc *crtc;
@@ -1365,6 +1480,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
return;
}
+ /* We set active outputs manually below in case pipe dpms doesn't change
+ * due to cloning. */
if (mode != DRM_MODE_DPMS_ON) {
intel_sdvo_set_active_outputs(intel_sdvo, 0);
if (0)
@@ -1495,7 +1612,7 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector)
return drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv,
- dev_priv->crt_ddc_pin));
+ dev_priv->vbt.crt_ddc_pin));
}
static enum drm_connector_status
@@ -1625,12 +1742,9 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
if (ret == connector_status_connected) {
intel_sdvo->is_tv = false;
intel_sdvo->is_lvds = false;
- intel_sdvo->base.needs_tv_clock = false;
- if (response & SDVO_TV_MASK) {
+ if (response & SDVO_TV_MASK)
intel_sdvo->is_tv = true;
- intel_sdvo->base.needs_tv_clock = true;
- }
if (response & SDVO_LVDS_MASK)
intel_sdvo->is_lvds = intel_sdvo->sdvo_lvds_fixed_mode != NULL;
}
@@ -1772,21 +1886,12 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
struct drm_display_mode *newmode;
/*
- * Attempt to get the mode list from DDC.
- * Assume that the preferred modes are
- * arranged in priority order.
- */
- intel_ddc_get_modes(connector, &intel_sdvo->ddc);
-
- /*
* Fetch modes from VBT. For SDVO prefer the VBT mode since some
- * SDVO->LVDS transcoders can't cope with the EDID mode. Since
- * drm_mode_probed_add adds the mode at the head of the list we add it
- * last.
+ * SDVO->LVDS transcoders can't cope with the EDID mode.
*/
- if (dev_priv->sdvo_lvds_vbt_mode != NULL) {
+ if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) {
newmode = drm_mode_duplicate(connector->dev,
- dev_priv->sdvo_lvds_vbt_mode);
+ dev_priv->vbt.sdvo_lvds_vbt_mode);
if (newmode != NULL) {
/* Guarantee the mode is preferred */
newmode->type = (DRM_MODE_TYPE_PREFERRED |
@@ -1795,6 +1900,13 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
}
}
+ /*
+ * Attempt to get the mode list from DDC.
+ * Assume that the preferred modes are
+ * arranged in priority order.
+ */
+ intel_ddc_get_modes(connector, &intel_sdvo->ddc);
+
list_for_each_entry(newmode, &connector->probed_modes, head) {
if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
intel_sdvo->sdvo_lvds_fixed_mode =
@@ -2329,7 +2441,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
intel_sdvo_connector->output_flag = type;
intel_sdvo->is_tv = true;
- intel_sdvo->base.needs_tv_clock = true;
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
@@ -2417,7 +2528,6 @@ static bool
intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
{
intel_sdvo->is_tv = false;
- intel_sdvo->base.needs_tv_clock = false;
intel_sdvo->is_lvds = false;
/* SDVO requires XXX1 function may not exist unless it has XXX0 function.*/
@@ -2751,7 +2861,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
struct intel_sdvo *intel_sdvo;
- u32 hotplug_mask;
int i;
intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
if (!intel_sdvo)
@@ -2780,23 +2889,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
}
}
- hotplug_mask = 0;
- if (IS_G4X(dev)) {
- hotplug_mask = intel_sdvo->is_sdvob ?
- SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X;
- } else if (IS_GEN4(dev)) {
- hotplug_mask = intel_sdvo->is_sdvob ?
- SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965;
- } else {
- hotplug_mask = intel_sdvo->is_sdvob ?
- SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
- }
-
intel_encoder->compute_config = intel_sdvo_compute_config;
intel_encoder->disable = intel_disable_sdvo;
intel_encoder->mode_set = intel_sdvo_mode_set;
intel_encoder->enable = intel_enable_sdvo;
intel_encoder->get_hw_state = intel_sdvo_get_hw_state;
+ intel_encoder->get_config = intel_sdvo_get_config;
/* In default case sdvo lvds is false */
if (!intel_sdvo_get_capabilities(intel_sdvo, &intel_sdvo->caps))
diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c
new file mode 100644
index 000000000000..9a0e6c5ea540
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_sideband.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+/* IOSF sideband */
+static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn,
+ u32 port, u32 opcode, u32 addr, u32 *val)
+{
+ u32 cmd, be = 0xf, bar = 0;
+ bool is_read = (opcode == PUNIT_OPCODE_REG_READ ||
+ opcode == DPIO_OPCODE_REG_READ);
+
+ cmd = (devfn << IOSF_DEVFN_SHIFT) | (opcode << IOSF_OPCODE_SHIFT) |
+ (port << IOSF_PORT_SHIFT) | (be << IOSF_BYTE_ENABLES_SHIFT) |
+ (bar << IOSF_BAR_SHIFT);
+
+ WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
+
+ if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) {
+ DRM_DEBUG_DRIVER("IOSF sideband idle wait (%s) timed out\n",
+ is_read ? "read" : "write");
+ return -EAGAIN;
+ }
+
+ I915_WRITE(VLV_IOSF_ADDR, addr);
+ if (!is_read)
+ I915_WRITE(VLV_IOSF_DATA, *val);
+ I915_WRITE(VLV_IOSF_DOORBELL_REQ, cmd);
+
+ if (wait_for((I915_READ(VLV_IOSF_DOORBELL_REQ) & IOSF_SB_BUSY) == 0, 5)) {
+ DRM_DEBUG_DRIVER("IOSF sideband finish wait (%s) timed out\n",
+ is_read ? "read" : "write");
+ return -ETIMEDOUT;
+ }
+
+ if (is_read)
+ *val = I915_READ(VLV_IOSF_DATA);
+ I915_WRITE(VLV_IOSF_DATA, 0);
+
+ return 0;
+}
+
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr)
+{
+ u32 val = 0;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+ mutex_lock(&dev_priv->dpio_lock);
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+ PUNIT_OPCODE_REG_READ, addr, &val);
+ mutex_unlock(&dev_priv->dpio_lock);
+
+ return val;
+}
+
+void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
+{
+ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+ mutex_lock(&dev_priv->dpio_lock);
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+ PUNIT_OPCODE_REG_WRITE, addr, &val);
+ mutex_unlock(&dev_priv->dpio_lock);
+}
+
+u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr)
+{
+ u32 val = 0;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+ mutex_lock(&dev_priv->dpio_lock);
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC,
+ PUNIT_OPCODE_REG_READ, addr, &val);
+ mutex_unlock(&dev_priv->dpio_lock);
+
+ return val;
+}
+
+u32 vlv_dpio_read(struct drm_i915_private *dev_priv, int reg)
+{
+ u32 val = 0;
+
+ vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO,
+ DPIO_OPCODE_REG_READ, reg, &val);
+
+ return val;
+}
+
+void vlv_dpio_write(struct drm_i915_private *dev_priv, int reg, u32 val)
+{
+ vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_DPIO,
+ DPIO_OPCODE_REG_WRITE, reg, &val);
+}
+
+/* SBI access */
+u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
+ enum intel_sbi_destination destination)
+{
+ u32 value = 0;
+ WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
+
+ if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to become ready\n");
+ return 0;
+ }
+
+ I915_WRITE(SBI_ADDR, (reg << 16));
+
+ if (destination == SBI_ICLK)
+ value = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRRD;
+ else
+ value = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IORD;
+ I915_WRITE(SBI_CTL_STAT, value | SBI_BUSY);
+
+ if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to complete read transaction\n");
+ return 0;
+ }
+
+ return I915_READ(SBI_DATA);
+}
+
+void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
+ enum intel_sbi_destination destination)
+{
+ u32 tmp;
+
+ WARN_ON(!mutex_is_locked(&dev_priv->dpio_lock));
+
+ if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_BUSY) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to become ready\n");
+ return;
+ }
+
+ I915_WRITE(SBI_ADDR, (reg << 16));
+ I915_WRITE(SBI_DATA, value);
+
+ if (destination == SBI_ICLK)
+ tmp = SBI_CTL_DEST_ICLK | SBI_CTL_OP_CRWR;
+ else
+ tmp = SBI_CTL_DEST_MPHY | SBI_CTL_OP_IOWR;
+ I915_WRITE(SBI_CTL_STAT, SBI_BUSY | tmp);
+
+ if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_BUSY | SBI_RESPONSE_FAIL)) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to complete write transaction\n");
+ return;
+ }
+}
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index c7d25c5dd4e6..1fa5612a4572 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -32,6 +32,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
+#include <drm/drm_rect.h>
#include "intel_drv.h"
#include <drm/i915_drm.h>
#include "i915_drv.h"
@@ -113,7 +114,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_framebuffer *fb,
crtc_w--;
crtc_h--;
- intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+ intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true);
I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
@@ -267,7 +268,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
crtc_w--;
crtc_h--;
- intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+ intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true);
/*
* IVB workaround: must disable low power watermarks for at least
@@ -334,6 +335,8 @@ ivb_disable_plane(struct drm_plane *plane)
dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
+ intel_update_sprite_watermarks(dev, pipe, 0, 0, false);
+
/* potentially re-enable LP watermarks */
if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
intel_update_watermarks(dev);
@@ -452,7 +455,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
crtc_w--;
crtc_h--;
- intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
+ intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size, true);
dvsscale = 0;
if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
@@ -583,6 +586,20 @@ ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
key->flags = I915_SET_COLORKEY_NONE;
}
+static bool
+format_is_yuv(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_YVYU:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int
intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -600,9 +617,29 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
pipe);
int ret = 0;
- int x = src_x >> 16, y = src_y >> 16;
- int primary_w = crtc->mode.hdisplay, primary_h = crtc->mode.vdisplay;
bool disable_primary = false;
+ bool visible;
+ int hscale, vscale;
+ int max_scale, min_scale;
+ int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+ struct drm_rect src = {
+ /* sample coordinates in 16.16 fixed point */
+ .x1 = src_x,
+ .x2 = src_x + src_w,
+ .y1 = src_y,
+ .y2 = src_y + src_h,
+ };
+ struct drm_rect dst = {
+ /* integer pixels */
+ .x1 = crtc_x,
+ .x2 = crtc_x + crtc_w,
+ .y1 = crtc_y,
+ .y2 = crtc_y + crtc_h,
+ };
+ const struct drm_rect clip = {
+ .x2 = crtc->mode.hdisplay,
+ .y2 = crtc->mode.vdisplay,
+ };
intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;
@@ -618,19 +655,23 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
intel_plane->src_w = src_w;
intel_plane->src_h = src_h;
- src_w = src_w >> 16;
- src_h = src_h >> 16;
-
/* Pipe must be running... */
- if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE))
+ if (!(I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_ENABLE)) {
+ DRM_DEBUG_KMS("Pipe disabled\n");
return -EINVAL;
+ }
- if (crtc_x >= primary_w || crtc_y >= primary_h)
+ /* Don't modify another pipe's plane */
+ if (intel_plane->pipe != intel_crtc->pipe) {
+ DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
return -EINVAL;
+ }
- /* Don't modify another pipe's plane */
- if (intel_plane->pipe != intel_crtc->pipe)
+ /* FIXME check all gen limits */
+ if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) {
+ DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
return -EINVAL;
+ }
/* Sprite planes can be linear or x-tiled surfaces */
switch (obj->tiling_mode) {
@@ -638,55 +679,123 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
case I915_TILING_X:
break;
default:
+ DRM_DEBUG_KMS("Unsupported tiling mode\n");
return -EINVAL;
}
/*
- * Clamp the width & height into the visible area. Note we don't
- * try to scale the source if part of the visible region is offscreen.
- * The caller must handle that by adjusting source offset and size.
+ * FIXME the following code does a bunch of fuzzy adjustments to the
+ * coordinates and sizes. We probably need some way to decide whether
+ * more strict checking should be done instead.
*/
- if ((crtc_x < 0) && ((crtc_x + crtc_w) > 0)) {
- crtc_w += crtc_x;
- crtc_x = 0;
- }
- if ((crtc_x + crtc_w) <= 0) /* Nothing to display */
- goto out;
- if ((crtc_x + crtc_w) > primary_w)
- crtc_w = primary_w - crtc_x;
+ max_scale = intel_plane->max_downscale << 16;
+ min_scale = intel_plane->can_scale ? 1 : (1 << 16);
+
+ hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale);
+ BUG_ON(hscale < 0);
+
+ vscale = drm_rect_calc_vscale_relaxed(&src, &dst, min_scale, max_scale);
+ BUG_ON(vscale < 0);
+
+ visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale);
+
+ crtc_x = dst.x1;
+ crtc_y = dst.y1;
+ crtc_w = drm_rect_width(&dst);
+ crtc_h = drm_rect_height(&dst);
+
+ if (visible) {
+ /* check again in case clipping clamped the results */
+ hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale);
+ if (hscale < 0) {
+ DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
+ drm_rect_debug_print(&src, true);
+ drm_rect_debug_print(&dst, false);
+
+ return hscale;
+ }
- if ((crtc_y < 0) && ((crtc_y + crtc_h) > 0)) {
- crtc_h += crtc_y;
- crtc_y = 0;
+ vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale);
+ if (vscale < 0) {
+ DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
+ drm_rect_debug_print(&src, true);
+ drm_rect_debug_print(&dst, false);
+
+ return vscale;
+ }
+
+ /* Make the source viewport size an exact multiple of the scaling factors. */
+ drm_rect_adjust_size(&src,
+ drm_rect_width(&dst) * hscale - drm_rect_width(&src),
+ drm_rect_height(&dst) * vscale - drm_rect_height(&src));
+
+ /* sanity check to make sure the src viewport wasn't enlarged */
+ WARN_ON(src.x1 < (int) src_x ||
+ src.y1 < (int) src_y ||
+ src.x2 > (int) (src_x + src_w) ||
+ src.y2 > (int) (src_y + src_h));
+
+ /*
+ * Hardware doesn't handle subpixel coordinates.
+ * Adjust to (macro)pixel boundary, but be careful not to
+ * increase the source viewport size, because that could
+ * push the downscaling factor out of bounds.
+ */
+ src_x = src.x1 >> 16;
+ src_w = drm_rect_width(&src) >> 16;
+ src_y = src.y1 >> 16;
+ src_h = drm_rect_height(&src) >> 16;
+
+ if (format_is_yuv(fb->pixel_format)) {
+ src_x &= ~1;
+ src_w &= ~1;
+
+ /*
+ * Must keep src and dst the
+ * same if we can't scale.
+ */
+ if (!intel_plane->can_scale)
+ crtc_w &= ~1;
+
+ if (crtc_w == 0)
+ visible = false;
+ }
}
- if ((crtc_y + crtc_h) <= 0) /* Nothing to display */
- goto out;
- if (crtc_y + crtc_h > primary_h)
- crtc_h = primary_h - crtc_y;
- if (!crtc_w || !crtc_h) /* Again, nothing to display */
- goto out;
+ /* Check size restrictions when scaling */
+ if (visible && (src_w != crtc_w || src_h != crtc_h)) {
+ unsigned int width_bytes;
- /*
- * We may not have a scaler, eg. HSW does not have it any more
- */
- if (!intel_plane->can_scale && (crtc_w != src_w || crtc_h != src_h))
- return -EINVAL;
+ WARN_ON(!intel_plane->can_scale);
- /*
- * We can take a larger source and scale it down, but
- * only so much... 16x is the max on SNB.
- */
- if (((src_w * src_h) / (crtc_w * crtc_h)) > intel_plane->max_downscale)
- return -EINVAL;
+ /* FIXME interlacing min height is 6 */
+
+ if (crtc_w < 3 || crtc_h < 3)
+ visible = false;
+
+ if (src_w < 3 || src_h < 3)
+ visible = false;
+
+ width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size;
+
+ if (src_w > 2048 || src_h > 2048 ||
+ width_bytes > 4096 || fb->pitches[0] > 4096) {
+ DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
+ return -EINVAL;
+ }
+ }
+
+ dst.x1 = crtc_x;
+ dst.x2 = crtc_x + crtc_w;
+ dst.y1 = crtc_y;
+ dst.y2 = crtc_y + crtc_h;
/*
* If the sprite is completely covering the primary plane,
* we can disable the primary and save power.
*/
- if ((crtc_x == 0) && (crtc_y == 0) &&
- (crtc_w == primary_w) && (crtc_h == primary_h))
- disable_primary = true;
+ disable_primary = drm_rect_equals(&dst, &clip);
+ WARN_ON(disable_primary && !visible);
mutex_lock(&dev->struct_mutex);
@@ -708,8 +817,12 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
if (!disable_primary)
intel_enable_primary(crtc);
- intel_plane->update_plane(plane, fb, obj, crtc_x, crtc_y,
- crtc_w, crtc_h, x, y, src_w, src_h);
+ if (visible)
+ intel_plane->update_plane(plane, fb, obj,
+ crtc_x, crtc_y, crtc_w, crtc_h,
+ src_x, src_y, src_w, src_h);
+ else
+ intel_plane->disable_plane(plane);
if (disable_primary)
intel_disable_primary(crtc);
@@ -732,7 +845,6 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
out_unlock:
mutex_unlock(&dev->struct_mutex);
-out:
return ret;
}
@@ -845,6 +957,14 @@ void intel_plane_restore(struct drm_plane *plane)
intel_plane->src_w, intel_plane->src_h);
}
+void intel_plane_disable(struct drm_plane *plane)
+{
+ if (!plane->crtc || !plane->fb)
+ return;
+
+ intel_disable_plane(plane);
+}
+
static const struct drm_plane_funcs intel_plane_funcs = {
.update_plane = intel_update_plane,
.disable_plane = intel_disable_plane,
@@ -918,13 +1038,15 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
break;
case 7:
- if (IS_HASWELL(dev) || IS_VALLEYVIEW(dev))
- intel_plane->can_scale = false;
- else
+ if (IS_IVYBRIDGE(dev)) {
intel_plane->can_scale = true;
+ intel_plane->max_downscale = 2;
+ } else {
+ intel_plane->can_scale = false;
+ intel_plane->max_downscale = 1;
+ }
if (IS_VALLEYVIEW(dev)) {
- intel_plane->max_downscale = 1;
intel_plane->update_plane = vlv_update_plane;
intel_plane->disable_plane = vlv_disable_plane;
intel_plane->update_colorkey = vlv_update_colorkey;
@@ -933,7 +1055,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
plane_formats = vlv_plane_formats;
num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
} else {
- intel_plane->max_downscale = 2;
intel_plane->update_plane = ivb_update_plane;
intel_plane->disable_plane = ivb_disable_plane;
intel_plane->update_colorkey = ivb_update_colorkey;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index b945bc54207a..39debd80d190 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -914,9 +914,6 @@ intel_tv_compute_config(struct intel_encoder *encoder,
if (!tv_mode)
return false;
- if (intel_encoder_check_is_cloned(&intel_tv->base))
- return false;
-
pipe_config->adjusted_mode.clock = tv_mode->clock;
DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
pipe_config->pipe_bpp = 8*3;
@@ -1521,12 +1518,12 @@ static int tv_is_present_in_vbt(struct drm_device *dev)
struct child_device_config *p_child;
int i, ret;
- if (!dev_priv->child_dev_num)
+ if (!dev_priv->vbt.child_dev_num)
return 1;
ret = 0;
- for (i = 0; i < dev_priv->child_dev_num; i++) {
- p_child = dev_priv->child_dev + i;
+ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) {
+ p_child = dev_priv->vbt.child_dev + i;
/*
* If the device type is not TV, continue.
*/
@@ -1564,7 +1561,7 @@ intel_tv_init(struct drm_device *dev)
return;
}
/* Even if we have an encoder we may not have a connector */
- if (!dev_priv->int_tv_support)
+ if (!dev_priv->vbt.int_tv_support)
return;
/*
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
index 7db592eedbf1..a9a0300f09fc 100644
--- a/drivers/gpu/drm/mgag200/Makefile
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -1,5 +1,5 @@
ccflags-y := -Iinclude/drm
-mgag200-y := mgag200_main.o mgag200_mode.o \
+mgag200-y := mgag200_main.o mgag200_mode.o mgag200_cursor.o \
mgag200_drv.o mgag200_fb.o mgag200_i2c.o mgag200_ttm.o
obj-$(CONFIG_DRM_MGAG200) += mgag200.o
diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c
new file mode 100644
index 000000000000..801731aeab61
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2013 Matrox Graphics
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Author: Christopher Harvey <charvey@matrox.com>
+ */
+
+#include <drm/drmP.h>
+#include "mgag200_drv.h"
+
+static bool warn_transparent = true;
+static bool warn_palette = true;
+
+/*
+ Hide the cursor off screen. We can't disable the cursor hardware because it
+ takes too long to re-activate and causes momentary corruption
+*/
+static void mga_hide_cursor(struct mga_device *mdev)
+{
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ mgag200_bo_unpin(mdev->cursor.pixels_1);
+ mgag200_bo_unpin(mdev->cursor.pixels_2);
+}
+
+int mga_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height)
+{
+ struct drm_device *dev = (struct drm_device *)file_priv->minor->dev;
+ struct mga_device *mdev = (struct mga_device *)dev->dev_private;
+ struct mgag200_bo *pixels_1 = mdev->cursor.pixels_1;
+ struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2;
+ struct mgag200_bo *pixels_current = mdev->cursor.pixels_current;
+ struct mgag200_bo *pixels_prev = mdev->cursor.pixels_prev;
+ struct drm_gem_object *obj;
+ struct mgag200_bo *bo = NULL;
+ int ret = 0;
+ unsigned int i, row, col;
+ uint32_t colour_set[16];
+ uint32_t *next_space = &colour_set[0];
+ uint32_t *palette_iter;
+ uint32_t this_colour;
+ bool found = false;
+ int colour_count = 0;
+ u64 gpu_addr;
+ u8 reg_index;
+ u8 this_row[48];
+
+ if (!pixels_1 || !pixels_2) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ return -ENOTSUPP; /* Didn't allocate space for cursors */
+ }
+
+ if ((width != 64 || height != 64) && handle) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ return -EINVAL;
+ }
+
+ BUG_ON(pixels_1 != pixels_current && pixels_1 != pixels_prev);
+ BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev);
+ BUG_ON(pixels_current == pixels_prev);
+
+ ret = mgag200_bo_reserve(pixels_1, true);
+ if (ret) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ return ret;
+ }
+ ret = mgag200_bo_reserve(pixels_2, true);
+ if (ret) {
+ WREG8(MGA_CURPOSXL, 0);
+ WREG8(MGA_CURPOSXH, 0);
+ mgag200_bo_unreserve(pixels_1);
+ return ret;
+ }
+
+ if (!handle) {
+ mga_hide_cursor(mdev);
+ ret = 0;
+ goto out1;
+ }
+
+ /* Move cursor buffers into VRAM if they aren't already */
+ if (!pixels_1->pin_count) {
+ ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM,
+ &mdev->cursor.pixels_1_gpu_addr);
+ if (ret)
+ goto out1;
+ }
+ if (!pixels_2->pin_count) {
+ ret = mgag200_bo_pin(pixels_2, TTM_PL_FLAG_VRAM,
+ &mdev->cursor.pixels_2_gpu_addr);
+ if (ret) {
+ mgag200_bo_unpin(pixels_1);
+ goto out1;
+ }
+ }
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file_priv, handle);
+ if (!obj) {
+ mutex_unlock(&dev->struct_mutex);
+ ret = -ENOENT;
+ goto out1;
+ }
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ bo = gem_to_mga_bo(obj);
+ ret = mgag200_bo_reserve(bo, true);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failed to reserve user bo\n");
+ goto out1;
+ }
+ if (!bo->kmap.virtual) {
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failed to kmap user buffer updates\n");
+ goto out2;
+ }
+ }
+
+ memset(&colour_set[0], 0, sizeof(uint32_t)*16);
+ /* width*height*4 = 16384 */
+ for (i = 0; i < 16384; i += 4) {
+ this_colour = ioread32(bo->kmap.virtual + i);
+ /* No transparency */
+ if (this_colour>>24 != 0xff &&
+ this_colour>>24 != 0x0) {
+ if (warn_transparent) {
+ dev_info(&dev->pdev->dev, "Video card doesn't support cursors with partial transparency.\n");
+ dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
+ warn_transparent = false; /* Only tell the user once. */
+ }
+ ret = -EINVAL;
+ goto out3;
+ }
+ /* Don't need to store transparent pixels as colours */
+ if (this_colour>>24 == 0x0)
+ continue;
+ found = false;
+ for (palette_iter = &colour_set[0]; palette_iter != next_space; palette_iter++) {
+ if (*palette_iter == this_colour) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+ /* We only support 4bit paletted cursors */
+ if (colour_count >= 16) {
+ if (warn_palette) {
+ dev_info(&dev->pdev->dev, "Video card only supports cursors with up to 16 colours.\n");
+ dev_info(&dev->pdev->dev, "Not enabling hardware cursor.\n");
+ warn_palette = false; /* Only tell the user once. */
+ }
+ ret = -EINVAL;
+ goto out3;
+ }
+ *next_space = this_colour;
+ next_space++;
+ colour_count++;
+ }
+
+ /* Program colours from cursor icon into palette */
+ for (i = 0; i < colour_count; i++) {
+ if (i <= 2)
+ reg_index = 0x8 + i*0x4;
+ else
+ reg_index = 0x60 + i*0x3;
+ WREG_DAC(reg_index, colour_set[i] & 0xff);
+ WREG_DAC(reg_index+1, colour_set[i]>>8 & 0xff);
+ WREG_DAC(reg_index+2, colour_set[i]>>16 & 0xff);
+ BUG_ON((colour_set[i]>>24 & 0xff) != 0xff);
+ }
+
+ /* Map up-coming buffer to write colour indices */
+ if (!pixels_prev->kmap.virtual) {
+ ret = ttm_bo_kmap(&pixels_prev->bo, 0,
+ pixels_prev->bo.num_pages,
+ &pixels_prev->kmap);
+ if (ret) {
+ dev_err(&dev->pdev->dev, "failed to kmap cursor updates\n");
+ goto out3;
+ }
+ }
+
+ /* now write colour indices into hardware cursor buffer */
+ for (row = 0; row < 64; row++) {
+ memset(&this_row[0], 0, 48);
+ for (col = 0; col < 64; col++) {
+ this_colour = ioread32(bo->kmap.virtual + 4*(col + 64*row));
+ /* write transparent pixels */
+ if (this_colour>>24 == 0x0) {
+ this_row[47 - col/8] |= 0x80>>(col%8);
+ continue;
+ }
+
+ /* write colour index here */
+ for (i = 0; i < colour_count; i++) {
+ if (colour_set[i] == this_colour) {
+ if (col % 2)
+ this_row[col/2] |= i<<4;
+ else
+ this_row[col/2] |= i;
+ break;
+ }
+ }
+ }
+ memcpy_toio(pixels_prev->kmap.virtual + row*48, &this_row[0], 48);
+ }
+
+ /* Program gpu address of cursor buffer */
+ if (pixels_prev == pixels_1)
+ gpu_addr = mdev->cursor.pixels_1_gpu_addr;
+ else
+ gpu_addr = mdev->cursor.pixels_2_gpu_addr;
+ WREG_DAC(MGA1064_CURSOR_BASE_ADR_LOW, (u8)((gpu_addr>>10) & 0xff));
+ WREG_DAC(MGA1064_CURSOR_BASE_ADR_HI, (u8)((gpu_addr>>18) & 0x3f));
+
+ /* Adjust cursor control register to turn on the cursor */
+ WREG_DAC(MGA1064_CURSOR_CTL, 4); /* 16-colour palletized cursor mode */
+
+ /* Now swap internal buffer pointers */
+ if (mdev->cursor.pixels_1 == mdev->cursor.pixels_prev) {
+ mdev->cursor.pixels_prev = mdev->cursor.pixels_2;
+ mdev->cursor.pixels_current = mdev->cursor.pixels_1;
+ } else if (mdev->cursor.pixels_1 == mdev->cursor.pixels_current) {
+ mdev->cursor.pixels_prev = mdev->cursor.pixels_1;
+ mdev->cursor.pixels_current = mdev->cursor.pixels_2;
+ } else {
+ BUG();
+ }
+ ret = 0;
+
+ ttm_bo_kunmap(&pixels_prev->kmap);
+ out3:
+ ttm_bo_kunmap(&bo->kmap);
+ out2:
+ mgag200_bo_unreserve(bo);
+ out1:
+ if (ret)
+ mga_hide_cursor(mdev);
+ mgag200_bo_unreserve(pixels_1);
+ mgag200_bo_unreserve(pixels_2);
+ return ret;
+}
+
+int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct mga_device *mdev = (struct mga_device *)crtc->dev->dev_private;
+ /* Our origin is at (64,64) */
+ x += 64;
+ y += 64;
+
+ BUG_ON(x <= 0);
+ BUG_ON(y <= 0);
+ BUG_ON(x & ~0xffff);
+ BUG_ON(y & ~0xffff);
+
+ WREG8(MGA_CURPOSXL, x & 0xff);
+ WREG8(MGA_CURPOSXH, (x>>8) & 0xff);
+
+ WREG8(MGA_CURPOSYL, y & 0xff);
+ WREG8(MGA_CURPOSYH, (y>>8) & 0xff);
+ return 0;
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
index bf29b2f4d68d..12e2499d9352 100644
--- a/drivers/gpu/drm/mgag200/mgag200_drv.h
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -149,6 +149,21 @@ struct mga_connector {
struct mga_i2c_chan *i2c;
};
+struct mga_cursor {
+ /*
+ We have to have 2 buffers for the cursor to avoid occasional
+ corruption while switching cursor icons.
+ If either of these is NULL, then don't do hardware cursors, and
+ fall back to software.
+ */
+ struct mgag200_bo *pixels_1;
+ struct mgag200_bo *pixels_2;
+ u64 pixels_1_gpu_addr, pixels_2_gpu_addr;
+ /* The currently displayed icon, this points to one of pixels_1, or pixels_2 */
+ struct mgag200_bo *pixels_current;
+ /* The previously displayed icon */
+ struct mgag200_bo *pixels_prev;
+};
struct mga_mc {
resource_size_t vram_size;
@@ -181,6 +196,7 @@ struct mga_device {
struct mga_mode_info mode_info;
struct mga_fbdev *mfbdev;
+ struct mga_cursor cursor;
bool suspended;
int num_crtc;
@@ -198,7 +214,8 @@ struct mga_device {
struct ttm_bo_device bdev;
} ttm;
- u32 reg_1e24; /* SE model number */
+ /* SE model number stored in reg 0x1e24 */
+ u32 unique_rev_id;
};
@@ -263,8 +280,24 @@ void mgag200_i2c_destroy(struct mga_i2c_chan *i2c);
#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
void mgag200_ttm_placement(struct mgag200_bo *bo, int domain);
-int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait);
-void mgag200_bo_unreserve(struct mgag200_bo *bo);
+static inline int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS && ret != -EBUSY)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+static inline void mgag200_bo_unreserve(struct mgag200_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
int mgag200_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct mgag200_bo **pastbo);
int mgag200_mm_init(struct mga_device *mdev);
@@ -273,4 +306,9 @@ int mgag200_mmap(struct file *filp, struct vm_area_struct *vma);
int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr);
int mgag200_bo_unpin(struct mgag200_bo *bo);
int mgag200_bo_push_sysram(struct mgag200_bo *bo);
+ /* mgag200_cursor.c */
+int mga_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t handle, uint32_t width, uint32_t height);
+int mga_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
+
#endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 5da824ce9ba1..964f58cee5ea 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -27,7 +27,7 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev,
struct mgag200_bo *bo;
int src_offset, dst_offset;
int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8;
- int ret;
+ int ret = -EBUSY;
bool unmap = false;
bool store_for_later = false;
int x2, y2;
@@ -41,7 +41,8 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev,
* then the BO is being moved and we should
* store up the damage until later.
*/
- ret = mgag200_bo_reserve(bo, true);
+ if (!in_interrupt())
+ ret = mgag200_bo_reserve(bo, true);
if (ret) {
if (ret != -EBUSY)
return;
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 99059237da38..9fa5685baee0 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -176,7 +176,7 @@ static int mgag200_device_init(struct drm_device *dev,
/* stash G200 SE model number for later use */
if (IS_G200_SE(mdev))
- mdev->reg_1e24 = RREG32(0x1e24);
+ mdev->unique_rev_id = RREG32(0x1e24);
ret = mga_vram_init(mdev);
if (ret)
@@ -209,7 +209,7 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
r = mgag200_device_init(dev, flags);
if (r) {
dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
- goto out;
+ return r;
}
r = mgag200_mm_init(mdev);
if (r)
@@ -221,8 +221,27 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
dev->mode_config.prefer_shadow = 1;
r = mgag200_modeset_init(mdev);
- if (r)
+ if (r) {
dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
+ goto out;
+ }
+
+ /* Make small buffers to store a hardware cursor (double buffered icon updates) */
+ mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0,
+ &mdev->cursor.pixels_1);
+ mgag200_bo_create(dev, roundup(48*64, PAGE_SIZE), 0, 0,
+ &mdev->cursor.pixels_2);
+ if (!mdev->cursor.pixels_2 || !mdev->cursor.pixels_1)
+ goto cursor_nospace;
+ mdev->cursor.pixels_current = mdev->cursor.pixels_1;
+ mdev->cursor.pixels_prev = mdev->cursor.pixels_2;
+ goto cursor_done;
+ cursor_nospace:
+ mdev->cursor.pixels_1 = NULL;
+ mdev->cursor.pixels_2 = NULL;
+ dev_warn(&dev->pdev->dev, "Could not allocate space for cursors. Not doing hardware cursors.\n");
+ cursor_done:
+
out:
if (r)
mgag200_driver_unload(dev);
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
index ee66badc8bb6..251784aa2225 100644
--- a/drivers/gpu/drm/mgag200/mgag200_mode.c
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -1008,7 +1008,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
if (IS_G200_SE(mdev)) {
- if (mdev->reg_1e24 >= 0x02) {
+ if (mdev->unique_rev_id >= 0x02) {
u8 hi_pri_lvl;
u32 bpp;
u32 mb;
@@ -1038,7 +1038,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
WREG8(MGAREG_CRTCEXT_DATA, hi_pri_lvl);
} else {
WREG8(MGAREG_CRTCEXT_INDEX, 0x06);
- if (mdev->reg_1e24 >= 0x01)
+ if (mdev->unique_rev_id >= 0x01)
WREG8(MGAREG_CRTCEXT_DATA, 0x03);
else
WREG8(MGAREG_CRTCEXT_DATA, 0x04);
@@ -1253,6 +1253,8 @@ static void mga_crtc_destroy(struct drm_crtc *crtc)
/* These provide the minimum set of functions required to handle a CRTC */
static const struct drm_crtc_funcs mga_crtc_funcs = {
+ .cursor_set = mga_crtc_cursor_set,
+ .cursor_move = mga_crtc_cursor_move,
.gamma_set = mga_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
.destroy = mga_crtc_destroy,
@@ -1410,6 +1412,32 @@ static int mga_vga_get_modes(struct drm_connector *connector)
return ret;
}
+static uint32_t mga_vga_calculate_mode_bandwidth(struct drm_display_mode *mode,
+ int bits_per_pixel)
+{
+ uint32_t total_area, divisor;
+ int64_t active_area, pixels_per_second, bandwidth;
+ uint64_t bytes_per_pixel = (bits_per_pixel + 7) / 8;
+
+ divisor = 1024;
+
+ if (!mode->htotal || !mode->vtotal || !mode->clock)
+ return 0;
+
+ active_area = mode->hdisplay * mode->vdisplay;
+ total_area = mode->htotal * mode->vtotal;
+
+ pixels_per_second = active_area * mode->clock * 1000;
+ do_div(pixels_per_second, total_area);
+
+ bandwidth = pixels_per_second * bytes_per_pixel * 100;
+ do_div(bandwidth, divisor);
+
+ return (uint32_t)(bandwidth);
+}
+
+#define MODE_BANDWIDTH MODE_BAD
+
static int mga_vga_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
@@ -1421,7 +1449,45 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
int bpp = 32;
int i = 0;
- /* FIXME: Add bandwidth and g200se limitations */
+ if (IS_G200_SE(mdev)) {
+ if (mdev->unique_rev_id == 0x01) {
+ if (mode->hdisplay > 1600)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1200)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (24400 * 1024))
+ return MODE_BANDWIDTH;
+ } else if (mdev->unique_rev_id >= 0x02) {
+ if (mode->hdisplay > 1920)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1200)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (30100 * 1024))
+ return MODE_BANDWIDTH;
+ }
+ } else if (mdev->type == G200_WB) {
+ if (mode->hdisplay > 1280)
+ return MODE_VIRTUAL_X;
+ if (mode->vdisplay > 1024)
+ return MODE_VIRTUAL_Y;
+ if (mga_vga_calculate_mode_bandwidth(mode,
+ bpp > (31877 * 1024)))
+ return MODE_BANDWIDTH;
+ } else if (mdev->type == G200_EV &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (32700 * 1024))) {
+ return MODE_BANDWIDTH;
+ } else if (mode->type == G200_EH &&
+ (mga_vga_calculate_mode_bandwidth(mode, bpp)
+ > (37500 * 1024))) {
+ return MODE_BANDWIDTH;
+ } else if (mode->type == G200_ER &&
+ (mga_vga_calculate_mode_bandwidth(mode,
+ bpp) > (55000 * 1024))) {
+ return MODE_BANDWIDTH;
+ }
if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h
index fb24d8655feb..3ae442a64bd6 100644
--- a/drivers/gpu/drm/mgag200/mgag200_reg.h
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -235,7 +235,11 @@
#define MGAREG_CRTCEXT_INDEX 0x1fde
#define MGAREG_CRTCEXT_DATA 0x1fdf
-
+/* Cursor X and Y position */
+#define MGA_CURPOSXL 0x3c0c
+#define MGA_CURPOSXH 0x3c0d
+#define MGA_CURPOSYL 0x3c0e
+#define MGA_CURPOSYH 0x3c0f
/* MGA bits for registers PCI_OPTION_REG */
#define MGA1064_OPT_SYS_CLK_PCI ( 0x00 << 0 )
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
index 401c9891d3a8..3acb2b044c7b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_ttm.c
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -270,26 +270,20 @@ int mgag200_mm_init(struct mga_device *mdev)
return ret;
}
- mdev->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0),
- DRM_MTRR_WC);
+ mdev->fb_mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0));
return 0;
}
void mgag200_mm_fini(struct mga_device *mdev)
{
- struct drm_device *dev = mdev->dev;
ttm_bo_device_release(&mdev->ttm.bdev);
mgag200_ttm_global_release(mdev);
- if (mdev->fb_mtrr >= 0) {
- drm_mtrr_del(mdev->fb_mtrr,
- pci_resource_start(dev->pdev, 0),
- pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
- mdev->fb_mtrr = -1;
- }
+ arch_phys_wc_del(mdev->fb_mtrr);
+ mdev->fb_mtrr = 0;
}
void mgag200_ttm_placement(struct mgag200_bo *bo, int domain)
@@ -309,24 +303,6 @@ void mgag200_ttm_placement(struct mgag200_bo *bo, int domain)
bo->placement.num_busy_placement = c;
}
-int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait)
-{
- int ret;
-
- ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
- if (ret) {
- if (ret != -ERESTARTSYS && ret != -EBUSY)
- DRM_ERROR("reserve failed %p %d\n", bo, ret);
- return ret;
- }
- return 0;
-}
-
-void mgag200_bo_unreserve(struct mgag200_bo *bo)
-{
- ttm_bo_unreserve(&bo->bo);
-}
-
int mgag200_bo_create(struct drm_device *dev, int size, int align,
uint32_t flags, struct mgag200_bo **pmgabo)
{
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index a7ff6d5a34b9..ff80f12480ea 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -15,6 +15,13 @@ config DRM_NOUVEAU
select ACPI_WMI if ACPI && X86
select MXM_WMI if ACPI && X86
select POWER_SUPPLY
+ # Similar to i915, we need to select ACPI_VIDEO and it's dependencies
+ select BACKLIGHT_LCD_SUPPORT if ACPI && X86
+ select BACKLIGHT_CLASS_DEVICE if ACPI && X86
+ select VIDEO_OUTPUT_CONTROL if ACPI && X86
+ select INPUT if ACPI && X86
+ select THERMAL if ACPI && X86
+ select ACPI_VIDEO if ACPI && X86
help
Choose this option for open-source nVidia support.
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 998e8b4444f3..d939a1da3203 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -12,7 +12,6 @@ nouveau-y += core/core/engctx.o
nouveau-y += core/core/engine.o
nouveau-y += core/core/enum.o
nouveau-y += core/core/event.o
-nouveau-y += core/core/falcon.o
nouveau-y += core/core/gpuobj.o
nouveau-y += core/core/handle.o
nouveau-y += core/core/mm.o
@@ -60,6 +59,8 @@ nouveau-y += core/subdev/devinit/nv10.o
nouveau-y += core/subdev/devinit/nv1a.o
nouveau-y += core/subdev/devinit/nv20.o
nouveau-y += core/subdev/devinit/nv50.o
+nouveau-y += core/subdev/devinit/nva3.o
+nouveau-y += core/subdev/devinit/nvc0.o
nouveau-y += core/subdev/fb/base.o
nouveau-y += core/subdev/fb/nv04.o
nouveau-y += core/subdev/fb/nv10.o
@@ -78,6 +79,17 @@ nouveau-y += core/subdev/fb/nv49.o
nouveau-y += core/subdev/fb/nv4e.o
nouveau-y += core/subdev/fb/nv50.o
nouveau-y += core/subdev/fb/nvc0.o
+nouveau-y += core/subdev/fb/ramnv04.o
+nouveau-y += core/subdev/fb/ramnv10.o
+nouveau-y += core/subdev/fb/ramnv1a.o
+nouveau-y += core/subdev/fb/ramnv20.o
+nouveau-y += core/subdev/fb/ramnv40.o
+nouveau-y += core/subdev/fb/ramnv41.o
+nouveau-y += core/subdev/fb/ramnv44.o
+nouveau-y += core/subdev/fb/ramnv49.o
+nouveau-y += core/subdev/fb/ramnv4e.o
+nouveau-y += core/subdev/fb/ramnv50.o
+nouveau-y += core/subdev/fb/ramnvc0.o
nouveau-y += core/subdev/gpio/base.o
nouveau-y += core/subdev/gpio/nv10.o
nouveau-y += core/subdev/gpio/nv50.o
@@ -129,12 +141,15 @@ nouveau-y += core/subdev/vm/nv44.o
nouveau-y += core/subdev/vm/nv50.o
nouveau-y += core/subdev/vm/nvc0.o
+nouveau-y += core/engine/falcon.o
+nouveau-y += core/engine/xtensa.o
nouveau-y += core/engine/dmaobj/base.o
nouveau-y += core/engine/dmaobj/nv04.o
nouveau-y += core/engine/dmaobj/nv50.o
nouveau-y += core/engine/dmaobj/nvc0.o
nouveau-y += core/engine/dmaobj/nvd0.o
nouveau-y += core/engine/bsp/nv84.o
+nouveau-y += core/engine/bsp/nv98.o
nouveau-y += core/engine/bsp/nvc0.o
nouveau-y += core/engine/bsp/nve0.o
nouveau-y += core/engine/copy/nva3.o
@@ -185,7 +200,13 @@ nouveau-y += core/engine/fifo/nve0.o
nouveau-y += core/engine/graph/ctxnv40.o
nouveau-y += core/engine/graph/ctxnv50.o
nouveau-y += core/engine/graph/ctxnvc0.o
-nouveau-y += core/engine/graph/ctxnve0.o
+nouveau-y += core/engine/graph/ctxnvc1.o
+nouveau-y += core/engine/graph/ctxnvc3.o
+nouveau-y += core/engine/graph/ctxnvc8.o
+nouveau-y += core/engine/graph/ctxnvd7.o
+nouveau-y += core/engine/graph/ctxnvd9.o
+nouveau-y += core/engine/graph/ctxnve4.o
+nouveau-y += core/engine/graph/ctxnvf0.o
nouveau-y += core/engine/graph/nv04.o
nouveau-y += core/engine/graph/nv10.o
nouveau-y += core/engine/graph/nv20.o
@@ -197,7 +218,13 @@ nouveau-y += core/engine/graph/nv35.o
nouveau-y += core/engine/graph/nv40.o
nouveau-y += core/engine/graph/nv50.o
nouveau-y += core/engine/graph/nvc0.o
-nouveau-y += core/engine/graph/nve0.o
+nouveau-y += core/engine/graph/nvc1.o
+nouveau-y += core/engine/graph/nvc3.o
+nouveau-y += core/engine/graph/nvc8.o
+nouveau-y += core/engine/graph/nvd7.o
+nouveau-y += core/engine/graph/nvd9.o
+nouveau-y += core/engine/graph/nve4.o
+nouveau-y += core/engine/graph/nvf0.o
nouveau-y += core/engine/mpeg/nv31.o
nouveau-y += core/engine/mpeg/nv40.o
nouveau-y += core/engine/mpeg/nv50.o
@@ -209,6 +236,7 @@ nouveau-y += core/engine/software/nv10.o
nouveau-y += core/engine/software/nv50.o
nouveau-y += core/engine/software/nvc0.o
nouveau-y += core/engine/vp/nv84.o
+nouveau-y += core/engine/vp/nv98.o
nouveau-y += core/engine/vp/nvc0.o
nouveau-y += core/engine/vp/nve0.o
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
index 0261a11b2ae0..d8291724dbd4 100644
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -208,7 +208,6 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
struct nouveau_mm_node *node;
if (block) {
- mutex_init(&mm->mutex);
INIT_LIST_HEAD(&mm->nodes);
INIT_LIST_HEAD(&mm->free);
mm->block_size = block;
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
index 1d9f614cb97d..1e8e75c0684a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
@@ -19,24 +19,19 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Ilia Mirkin
*/
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/xtensa.h>
#include <engine/bsp.h>
-struct nv84_bsp_priv {
- struct nouveau_engine base;
-};
-
/*******************************************************************************
* BSP object classes
******************************************************************************/
static struct nouveau_oclass
nv84_bsp_sclass[] = {
+ { 0x74b0, &nouveau_object_ofuncs },
{},
};
@@ -48,7 +43,7 @@ static struct nouveau_oclass
nv84_bsp_cclass = {
.handle = NV_ENGCTX(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
+ .ctor = _nouveau_xtensa_engctx_ctor,
.dtor = _nouveau_engctx_dtor,
.init = _nouveau_engctx_init,
.fini = _nouveau_engctx_fini,
@@ -66,10 +61,10 @@ nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
- struct nv84_bsp_priv *priv;
+ struct nouveau_xtensa *priv;
int ret;
- ret = nouveau_engine_create(parent, engine, oclass, true,
+ ret = nouveau_xtensa_create(parent, engine, oclass, 0x103000, true,
"PBSP", "bsp", &priv);
*pobject = nv_object(priv);
if (ret)
@@ -78,6 +73,8 @@ nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->unit = 0x04008000;
nv_engine(priv)->cclass = &nv84_bsp_cclass;
nv_engine(priv)->sclass = nv84_bsp_sclass;
+ priv->fifo_val = 0x1111;
+ priv->unkd28 = 0x90044;
return 0;
}
@@ -86,8 +83,10 @@ nv84_bsp_oclass = {
.handle = NV_ENGINE(BSP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_bsp_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = _nouveau_xtensa_dtor,
+ .init = _nouveau_xtensa_init,
+ .fini = _nouveau_xtensa_fini,
+ .rd32 = _nouveau_xtensa_rd32,
+ .wr32 = _nouveau_xtensa_wr32,
},
};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
new file mode 100644
index 000000000000..8bf92b0e6d82
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/engctx.h>
+#include <core/class.h>
+
+#include <engine/bsp.h>
+
+struct nv98_bsp_priv {
+ struct nouveau_engine base;
+};
+
+/*******************************************************************************
+ * BSP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_bsp_sclass[] = {
+ {},
+};
+
+/*******************************************************************************
+ * BSP context
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_bsp_cclass = {
+ .handle = NV_ENGCTX(BSP, 0x98),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = _nouveau_engctx_ctor,
+ .dtor = _nouveau_engctx_dtor,
+ .init = _nouveau_engctx_init,
+ .fini = _nouveau_engctx_fini,
+ .rd32 = _nouveau_engctx_rd32,
+ .wr32 = _nouveau_engctx_wr32,
+ },
+};
+
+/*******************************************************************************
+ * BSP engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv98_bsp_priv *priv;
+ int ret;
+
+ ret = nouveau_engine_create(parent, engine, oclass, true,
+ "PBSP", "bsp", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x04008000;
+ nv_engine(priv)->cclass = &nv98_bsp_cclass;
+ nv_engine(priv)->sclass = nv98_bsp_sclass;
+ return 0;
+}
+
+struct nouveau_oclass
+nv98_bsp_oclass = {
+ .handle = NV_ENGINE(BSP, 0x98),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv98_bsp_ctor,
+ .dtor = _nouveau_engine_dtor,
+ .init = _nouveau_engine_init,
+ .fini = _nouveau_engine_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
index 0a5aa6bb0870..262c9f5f5f60 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
@@ -22,8 +22,7 @@
* Authors: Maarten Lankhorst
*/
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
#include <engine/bsp.h>
struct nvc0_bsp_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
index d4f23bbd75b4..c46882c83982 100644
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
@@ -22,8 +22,7 @@
* Authors: Ben Skeggs
*/
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
#include <engine/bsp.h>
struct nve0_bsp_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
index c92520f3ed46..241b27201206 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
@@ -1,4 +1,4 @@
-static u32 nva3_pcopy_data[] = {
+uint32_t nva3_pcopy_data[] = {
/* 0x0000: ctx_object */
0x00000000,
/* 0x0004: ctx_dma */
@@ -183,7 +183,7 @@ static u32 nva3_pcopy_data[] = {
0x00000800,
};
-static u32 nva3_pcopy_code[] = {
+uint32_t nva3_pcopy_code[] = {
/* 0x0000: main */
0x04fe04bd,
0x3517f000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
index 0d98c6c0958d..98cc4216a372 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
@@ -1,4 +1,4 @@
-static u32 nvc0_pcopy_data[] = {
+uint32_t nvc0_pcopy_data[] = {
/* 0x0000: ctx_object */
0x00000000,
/* 0x0004: ctx_query_address_high */
@@ -171,7 +171,7 @@ static u32 nvc0_pcopy_data[] = {
0x00000800,
};
-static u32 nvc0_pcopy_code[] = {
+uint32_t nvc0_pcopy_code[] = {
/* 0x0000: main */
0x04fe04bd,
0x3517f000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
index d6dc2a65ccd1..f31527733e00 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
@@ -22,16 +22,17 @@
* Authors: Ben Skeggs
*/
-#include <core/client.h>
-#include <core/falcon.h>
-#include <core/class.h>
-#include <core/enum.h>
+#include <engine/falcon.h>
+#include <engine/fifo.h>
+#include <engine/copy.h>
#include <subdev/fb.h>
#include <subdev/vm.h>
-#include <engine/fifo.h>
-#include <engine/copy.h>
+#include <core/client.h>
+#include <core/class.h>
+#include <core/enum.h>
+
#include "fuc/nva3.fuc.h"
@@ -117,13 +118,6 @@ nva3_copy_intr(struct nouveau_subdev *subdev)
}
static int
-nva3_copy_tlb_flush(struct nouveau_engine *engine)
-{
- nv50_vm_flush_engine(&engine->base, 0x0d);
- return 0;
-}
-
-static int
nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -142,7 +136,6 @@ nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->intr = nva3_copy_intr;
nv_engine(priv)->cclass = &nva3_copy_cclass;
nv_engine(priv)->sclass = nva3_copy_sclass;
- nv_engine(priv)->tlb_flush = nva3_copy_tlb_flush;
nv_falcon(priv)->code.data = nva3_pcopy_code;
nv_falcon(priv)->code.size = sizeof(nva3_pcopy_code);
nv_falcon(priv)->data.data = nva3_pcopy_data;
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
index b3ed2737e21f..993df09ad643 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
@@ -22,13 +22,15 @@
* Authors: Ben Skeggs
*/
-#include <core/falcon.h>
-#include <core/class.h>
-#include <core/enum.h>
-
+#include <engine/falcon.h>
#include <engine/fifo.h>
#include <engine/copy.h>
+#include <core/class.h>
+#include <core/enum.h>
+#include <core/class.h>
+#include <core/enum.h>
+
#include "fuc/nvc0.fuc.h"
struct nvc0_copy_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
index dbbe9e8998fe..30f1ef1edcc5 100644
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
@@ -67,6 +67,19 @@ nve0_copy_cclass = {
* PCOPY engine/subdev functions
******************************************************************************/
+static void
+nve0_copy_intr(struct nouveau_subdev *subdev)
+{
+ const int ce = nv_subidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
+ struct nve0_copy_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
+
+ if (stat) {
+ nv_warn(priv, "unhandled intr 0x%08x\n", stat);
+ nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
+ }
+}
+
static int
nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -85,6 +98,7 @@ nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00000040;
+ nv_subdev(priv)->intr = nve0_copy_intr;
nv_engine(priv)->cclass = &nve0_copy_cclass;
nv_engine(priv)->sclass = nve0_copy_sclass;
return 0;
@@ -108,6 +122,28 @@ nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
nv_subdev(priv)->unit = 0x00000080;
+ nv_subdev(priv)->intr = nve0_copy_intr;
+ nv_engine(priv)->cclass = &nve0_copy_cclass;
+ nv_engine(priv)->sclass = nve0_copy_sclass;
+ return 0;
+}
+
+static int
+nve0_copy2_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nve0_copy_priv *priv;
+ int ret;
+
+ ret = nouveau_engine_create(parent, engine, oclass, true,
+ "PCE2", "copy2", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00200000;
+ nv_subdev(priv)->intr = nve0_copy_intr;
nv_engine(priv)->cclass = &nve0_copy_cclass;
nv_engine(priv)->sclass = nve0_copy_sclass;
return 0;
@@ -134,3 +170,14 @@ nve0_copy1_oclass = {
.fini = _nouveau_engine_fini,
},
};
+
+struct nouveau_oclass
+nve0_copy2_oclass = {
+ .handle = NV_ENGINE(COPY2, 0xe0),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nve0_copy2_ctor,
+ .dtor = _nouveau_engine_dtor,
+ .init = _nouveau_engine_init,
+ .fini = _nouveau_engine_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
index 09962e4210e9..38676c74e6e0 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
@@ -1,4 +1,4 @@
-static uint32_t nv98_pcrypt_data[] = {
+uint32_t nv98_pcrypt_data[] = {
/* 0x0000: ctx_dma */
/* 0x0000: ctx_dma_query */
0x00000000,
@@ -150,7 +150,7 @@ static uint32_t nv98_pcrypt_data[] = {
0x00000000,
};
-static uint32_t nv98_pcrypt_code[] = {
+uint32_t nv98_pcrypt_code[] = {
0x17f004bd,
0x0010fe35,
0xf10004fe,
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
index 5bc021f471f9..2551dafbec73 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
@@ -141,13 +141,6 @@ nv84_crypt_intr(struct nouveau_subdev *subdev)
}
static int
-nv84_crypt_tlb_flush(struct nouveau_engine *engine)
-{
- nv50_vm_flush_engine(&engine->base, 0x0a);
- return 0;
-}
-
-static int
nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -165,7 +158,6 @@ nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->intr = nv84_crypt_intr;
nv_engine(priv)->cclass = &nv84_crypt_cclass;
nv_engine(priv)->sclass = nv84_crypt_sclass;
- nv_engine(priv)->tlb_flush = nv84_crypt_tlb_flush;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
index 8bf8955051d4..c7082377ec76 100644
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
+++ b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
@@ -27,11 +27,11 @@
#include <core/enum.h>
#include <core/class.h>
#include <core/engctx.h>
-#include <core/falcon.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
+#include <engine/falcon.h>
#include <engine/fifo.h>
#include <engine/crypt.h>
@@ -119,13 +119,6 @@ nv98_crypt_intr(struct nouveau_subdev *subdev)
}
static int
-nv98_crypt_tlb_flush(struct nouveau_engine *engine)
-{
- nv50_vm_flush_engine(&engine->base, 0x0a);
- return 0;
-}
-
-static int
nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -143,7 +136,6 @@ nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->intr = nv98_crypt_intr;
nv_engine(priv)->cclass = &nv98_crypt_cclass;
nv_engine(priv)->sclass = nv98_crypt_sclass;
- nv_engine(priv)->tlb_flush = nv98_crypt_tlb_flush;
nv_falcon(priv)->code.data = nv98_pcrypt_code;
nv_falcon(priv)->code.size = sizeof(nv98_pcrypt_code);
nv_falcon(priv)->data.data = nv98_pcrypt_data;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
index 5e8c3de75593..ffc18b80c5d9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
@@ -227,9 +227,9 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
break;
@@ -279,9 +279,9 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
break;
@@ -305,9 +305,9 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass;
break;
@@ -319,7 +319,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -332,8 +332,8 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
@@ -346,7 +346,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -358,8 +358,8 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
@@ -372,7 +372,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -384,8 +384,8 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
@@ -398,7 +398,7 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nv98_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nv50_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -410,8 +410,8 @@ nv50_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_FIFO ] = &nv84_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nv50_software_oclass;
device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
index a36e64e98ef3..418f51f50d7a 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
@@ -62,7 +62,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -75,7 +75,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc0_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -91,7 +91,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -104,7 +104,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -120,7 +120,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -133,7 +133,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -148,7 +148,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -161,7 +161,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -177,7 +177,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -190,7 +190,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -206,7 +206,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -219,7 +219,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc1_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -234,7 +234,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -247,7 +247,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvc8_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -263,7 +263,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -276,7 +276,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvd9_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -291,7 +291,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -304,7 +304,7 @@ nvc0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nvc0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nvc0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nvd7_graph_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
index a354e409cdff..7aca1877add4 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
@@ -62,7 +62,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -75,10 +75,11 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
+ device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -91,7 +92,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -104,10 +105,11 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
+ device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -120,7 +122,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -133,10 +135,11 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass;
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
+ device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
@@ -149,7 +152,7 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
device->oclass[NVDEV_SUBDEV_MC ] = &nvc0_mc_oclass;
device->oclass[NVDEV_SUBDEV_BUS ] = &nvc0_bus_oclass;
device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
@@ -160,16 +163,14 @@ nve0_identify(struct nouveau_device *device)
device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-#if 0
device->oclass[NVDEV_ENGINE_FIFO ] = &nve0_fifo_oclass;
device->oclass[NVDEV_ENGINE_SW ] = &nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nve0_graph_oclass;
-#endif
+ device->oclass[NVDEV_ENGINE_GR ] = nvf0_graph_oclass;
device->oclass[NVDEV_ENGINE_DISP ] = &nvf0_disp_oclass;
-#if 0
device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
+#if 0
device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
index f065fc248adf..db8c6fd46278 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
@@ -55,6 +55,10 @@ nva3_hdmi_ctrl(struct nv50_disp_priv *priv, int head, int or, u32 data)
nv_wr32(priv, 0x61c510 + soff, 0x00000000);
nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
+ nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+ nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+ nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
/* ??? */
nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 6a38402fa56c..7ffe2f309f12 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -34,9 +34,9 @@
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
#include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
#include <subdev/timer.h>
#include <subdev/fb.h>
-#include <subdev/clock.h>
#include "nv50.h"
@@ -987,10 +987,10 @@ nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
static void
nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
{
- struct nouveau_clock *clk = nouveau_clock(priv);
+ struct nouveau_devinit *devinit = nouveau_devinit(priv);
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
if (pclk)
- clk->pll_set(clk, PLL_VPLL0 + head, pclk);
+ devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
}
static void
@@ -1107,6 +1107,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
u32 hval, hreg = 0x614200 + (head * 0x800);
u32 oval, oreg;
+ u32 mask;
u32 conf = exec_clkcmp(priv, head, 0xff, pclk, &outp);
if (conf != ~0) {
if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) {
@@ -1133,6 +1134,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
oreg = 0x614280 + (ffs(outp.or) - 1) * 0x800;
oval = 0x00000000;
hval = 0x00000000;
+ mask = 0xffffffff;
} else
if (!outp.location) {
if (outp.type == DCB_OUTPUT_DP)
@@ -1140,14 +1142,16 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
oreg = 0x614300 + (ffs(outp.or) - 1) * 0x800;
oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
hval = 0x00000000;
+ mask = 0x00000707;
} else {
oreg = 0x614380 + (ffs(outp.or) - 1) * 0x800;
oval = 0x00000001;
hval = 0x00000001;
+ mask = 0x00000707;
}
nv_mask(priv, hreg, 0x0000000f, hval);
- nv_mask(priv, oreg, 0x00000707, oval);
+ nv_mask(priv, oreg, mask, oval);
}
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
index 019eacd8a68f..52dd7a1db729 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
@@ -29,15 +29,14 @@
#include <engine/disp.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/clock.h>
-
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
#include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
#include "nv50.h"
@@ -738,10 +737,10 @@ nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
static void
nvd0_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
{
- struct nouveau_clock *clk = nouveau_clock(priv);
+ struct nouveau_devinit *devinit = nouveau_devinit(priv);
u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
if (pclk)
- clk->pll_set(clk, PLL_VPLL0 + head, pclk);
+ devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
}
@@ -959,6 +958,9 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int heads = nv_rd32(parent, 0x022448);
int ret;
+ if (nv_rd32(parent, 0x022500) & 0x00000001)
+ return -ENODEV;
+
ret = nouveau_disp_create(parent, engine, oclass, heads,
"PDISP", "display", &priv);
*pobject = nv_object(priv);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
index 20725b363d58..fb1fe6ae5e74 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
@@ -54,6 +54,9 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int heads = nv_rd32(parent, 0x022448);
int ret;
+ if (nv_rd32(parent, 0x022500) & 0x00000001)
+ return -ENODEV;
+
ret = nouveau_disp_create(parent, engine, oclass, heads,
"PDISP", "display", &priv);
*pobject = nv_object(priv);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
index a488c36e40f9..42aa6b97dbea 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
@@ -54,6 +54,9 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
int heads = nv_rd32(parent, 0x022448);
int ret;
+ if (nv_rd32(parent, 0x022500) & 0x00000001)
+ return -ENODEV;
+
ret = nouveau_disp_create(parent, engine, oclass, heads,
"PDISP", "display", &priv);
*pobject = nv_object(priv);
diff --git a/drivers/gpu/drm/nouveau/core/core/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c
index e05c15777588..3c7a31f7590e 100644
--- a/drivers/gpu/drm/nouveau/core/core/falcon.c
+++ b/drivers/gpu/drm/nouveau/core/engine/falcon.c
@@ -20,8 +20,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
#include <subdev/timer.h>
u32
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
index 2b1f91721225..5c7433d5069f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
@@ -320,7 +320,7 @@ nv40_fifo_init(struct nouveau_object *object)
break;
default:
nv_wr32(priv, 0x002230, 0x00000000);
- nv_wr32(priv, 0x002220, ((pfb->ram.size - 512 * 1024 +
+ nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
priv->ramfc->addr) >> 16) |
0x00030000);
break;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
index 35b94bd18808..7f53196cff52 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
@@ -56,7 +56,9 @@ nv84_fifo_context_attach(struct nouveau_object *parent,
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : addr = 0x0020; break;
+ case NVDEV_ENGINE_VP : addr = 0x0040; break;
case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+ case NVDEV_ENGINE_BSP : addr = 0x0080; break;
case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
default:
@@ -89,7 +91,9 @@ nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break;
+ case NVDEV_ENGINE_VP : engn = 3; addr = 0x0040; break;
case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
+ case NVDEV_ENGINE_BSP : engn = 5; addr = 0x0080; break;
case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break;
default:
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
index 56192a7242ae..09644fa9602c 100644
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
@@ -44,7 +44,8 @@ static const struct {
u64 subdev;
u64 mask;
} fifo_engine[] = {
- _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW)),
+ _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_COPY2)),
_(NVDEV_ENGINE_VP , 0),
_(NVDEV_ENGINE_PPP , 0),
_(NVDEV_ENGINE_BSP , 0),
@@ -96,18 +97,6 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
mutex_lock(&nv_subdev(priv)->mutex);
cur = engn->playlist[engn->cur_playlist];
- if (unlikely(cur == NULL)) {
- int ret = nouveau_gpuobj_new(nv_object(priv), NULL,
- 0x8000, 0x1000, 0, &cur);
- if (ret) {
- mutex_unlock(&nv_subdev(priv)->mutex);
- nv_error(priv, "playlist alloc failed\n");
- return;
- }
-
- engn->playlist[engn->cur_playlist] = cur;
- }
-
engn->cur_playlist = !engn->cur_playlist;
for (i = 0, p = 0; i < priv->base.max; i++) {
@@ -138,10 +127,12 @@ nve0_fifo_context_attach(struct nouveau_object *parent,
int ret;
switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR :
+ case NVDEV_ENGINE_SW :
case NVDEV_ENGINE_COPY0:
- case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
+ case NVDEV_ENGINE_COPY1:
+ case NVDEV_ENGINE_COPY2:
+ return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_BSP : addr = 0x0270; break;
case NVDEV_ENGINE_VP : addr = 0x0250; break;
case NVDEV_ENGINE_PPP : addr = 0x0260; break;
@@ -176,9 +167,10 @@ nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
switch (nv_engidx(object->engine)) {
case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR :
case NVDEV_ENGINE_COPY0:
- case NVDEV_ENGINE_COPY1: addr = 0x0210; break;
+ case NVDEV_ENGINE_COPY1:
+ case NVDEV_ENGINE_COPY2: addr = 0x0000; break;
+ case NVDEV_ENGINE_GR : addr = 0x0210; break;
case NVDEV_ENGINE_BSP : addr = 0x0270; break;
case NVDEV_ENGINE_VP : addr = 0x0250; break;
case NVDEV_ENGINE_PPP : addr = 0x0260; break;
@@ -194,9 +186,12 @@ nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
return -EBUSY;
}
- nv_wo32(base, addr + 0x00, 0x00000000);
- nv_wo32(base, addr + 0x04, 0x00000000);
- bar->flush(bar);
+ if (addr) {
+ nv_wo32(base, addr + 0x00, 0x00000000);
+ nv_wo32(base, addr + 0x04, 0x00000000);
+ bar->flush(bar);
+ }
+
return 0;
}
@@ -226,8 +221,10 @@ nve0_fifo_chan_ctor(struct nouveau_object *parent,
}
}
- if (i == FIFO_ENGINE_NR)
+ if (i == FIFO_ENGINE_NR) {
+ nv_error(priv, "unsupported engines 0x%08x\n", args->engine);
return -ENODEV;
+ }
ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
priv->user.bar.offset, 0x200,
@@ -592,13 +589,25 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_object **pobject)
{
struct nve0_fifo_priv *priv;
- int ret;
+ int ret, i;
ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
+ for (i = 0; i < FIFO_ENGINE_NR; i++) {
+ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+ 0, &priv->engine[i].playlist[0]);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+ 0, &priv->engine[i].playlist[1]);
+ if (ret)
+ return ret;
+ }
+
ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
if (ret)
@@ -629,7 +638,7 @@ nve0_fifo_dtor(struct nouveau_object *object)
nouveau_gpuobj_unmap(&priv->user.bar);
nouveau_gpuobj_ref(NULL, &priv->user.mem);
- for (i = 0; i < ARRAY_SIZE(priv->engine); i++) {
+ for (i = 0; i < FIFO_ENGINE_NR; i++) {
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
index 4cc6269d4077..64dca260912f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
@@ -24,3015 +24,1220 @@
#include "nvc0.h"
-void
-nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data)
-{
- nv_wr32(priv, 0x400204, data);
- nv_wr32(priv, 0x400200, icmd);
- while (nv_rd32(priv, 0x400700) & 2) {}
-}
+struct nvc0_graph_init
+nvc0_grctx_init_icmd[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 1, 0x01, 0x00000001 },
+ { 0x000639, 1, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_9097[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x002700, 8, 0x20, 0x00000000 },
+ { 0x002704, 8, 0x20, 0x00000000 },
+ { 0x002708, 8, 0x20, 0x00000000 },
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x002710, 8, 0x20, 0x00014000 },
+ { 0x002714, 8, 0x20, 0x00000040 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002200, 5, 0x10, 0x00000022 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00001fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x003fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 1, 0x04, 0x00000000 },
+ { 0x001320, 3, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 1, 0x04, 0x003fffff },
+ { 0x0002d0, 1, 0x04, 0x00000c48 },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00300008 },
+ { 0x001284, 1, 0x04, 0x04000080 },
+ { 0x001450, 1, 0x04, 0x00300008 },
+ { 0x001454, 1, 0x04, 0x04000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_902d[] = {
+ { 0x000200, 1, 0x04, 0x000000cf },
+ { 0x000204, 1, 0x04, 0x00000001 },
+ { 0x000208, 1, 0x04, 0x00000020 },
+ { 0x00020c, 1, 0x04, 0x00000001 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000214, 1, 0x04, 0x00000080 },
+ { 0x000218, 2, 0x04, 0x00000100 },
+ { 0x000220, 2, 0x04, 0x00000000 },
+ { 0x000230, 1, 0x04, 0x000000cf },
+ { 0x000234, 1, 0x04, 0x00000001 },
+ { 0x000238, 1, 0x04, 0x00000020 },
+ { 0x00023c, 1, 0x04, 0x00000001 },
+ { 0x000244, 1, 0x04, 0x00000080 },
+ { 0x000248, 2, 0x04, 0x00000100 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_9039[] = {
+ { 0x00030c, 3, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000238, 2, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_90c0[] = {
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x000758, 1, 0x04, 0x00000100 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x000204, 3, 0x04, 0x00000000 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ { 0x00024c, 1, 0x04, 0x00000000 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_base[] = {
+ { 0x400204, 2, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk40xx[] = {
+ { 0x404004, 10, 0x04, 0x00000000 },
+ { 0x404044, 1, 0x04, 0x00000000 },
+ { 0x404094, 1, 0x04, 0x00000000 },
+ { 0x404098, 12, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf0000087 },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 1, 0x04, 0x00000000 },
+ { 0x404134, 1, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x404168, 1, 0x04, 0x00000000 },
+ { 0x404174, 1, 0x04, 0x00000000 },
+ { 0x404178, 2, 0x04, 0x00000000 },
+ { 0x404200, 8, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk44xx[] = {
+ { 0x404404, 14, 0x04, 0x00000000 },
+ { 0x404460, 2, 0x04, 0x00000000 },
+ { 0x404468, 1, 0x04, 0x00ffffff },
+ { 0x40446c, 1, 0x04, 0x00000000 },
+ { 0x404480, 1, 0x04, 0x00000001 },
+ { 0x404498, 1, 0x04, 0x00000001 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk46xx[] = {
+ { 0x404604, 1, 0x04, 0x00000015 },
+ { 0x404608, 1, 0x04, 0x00000000 },
+ { 0x40460c, 1, 0x04, 0x00002e00 },
+ { 0x404610, 1, 0x04, 0x00000100 },
+ { 0x404618, 8, 0x04, 0x00000000 },
+ { 0x404638, 1, 0x04, 0x00000004 },
+ { 0x40463c, 8, 0x04, 0x00000000 },
+ { 0x40465c, 1, 0x04, 0x007f0100 },
+ { 0x404660, 7, 0x04, 0x00000000 },
+ { 0x40467c, 1, 0x04, 0x00000002 },
+ { 0x404680, 8, 0x04, 0x00000000 },
+ { 0x4046a0, 1, 0x04, 0x007f0080 },
+ { 0x4046a4, 18, 0x04, 0x00000000 },
+ { 0x4046f0, 2, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk47xx[] = {
+ { 0x404700, 13, 0x04, 0x00000000 },
+ { 0x404734, 1, 0x04, 0x00000100 },
+ { 0x404738, 8, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk58xx[] = {
+ { 0x405800, 1, 0x04, 0x078000bf },
+ { 0x405830, 1, 0x04, 0x02180000 },
+ { 0x405834, 2, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk60xx[] = {
+ { 0x406020, 1, 0x04, 0x000103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk64xx[] = {
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 2, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk78xx[] = {
+ { 0x407804, 1, 0x04, 0x00000023 },
+ { 0x40780c, 1, 0x04, 0x0a418820 },
+ { 0x407810, 1, 0x04, 0x062080e6 },
+ { 0x407814, 1, 0x04, 0x020398a4 },
+ { 0x407818, 1, 0x04, 0x0e629062 },
+ { 0x40781c, 1, 0x04, 0x0a418820 },
+ { 0x407820, 1, 0x04, 0x000000e6 },
+ { 0x4078bc, 1, 0x04, 0x00000103 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_unk80xx[] = {
+ { 0x408000, 2, 0x04, 0x00000000 },
+ { 0x408008, 1, 0x04, 0x00000018 },
+ { 0x40800c, 2, 0x04, 0x00000000 },
+ { 0x408014, 1, 0x04, 0x00000069 },
+ { 0x408018, 1, 0x04, 0xe100e100 },
+ { 0x408064, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_rop[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x0003e00d },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x02000001 },
+ { 0x408908, 1, 0x04, 0x00c80929 },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_gpc_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x00200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 1, 0x04, 0x00000000 },
+ { 0x41870c, 1, 0x04, 0x07c80000 },
+ { 0x418710, 1, 0x04, 0x00000000 },
+ { 0x418800, 1, 0x04, 0x0006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x00000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x00100000 },
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ { 0x418b00, 1, 0x04, 0x00000000 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_gpc_1[] = {
+ { 0x418a00, 3, 0x04, 0x00000000 },
+ { 0x418a0c, 1, 0x04, 0x00010000 },
+ { 0x418a10, 3, 0x04, 0x00000000 },
+ { 0x418a20, 3, 0x04, 0x00000000 },
+ { 0x418a2c, 1, 0x04, 0x00010000 },
+ { 0x418a30, 3, 0x04, 0x00000000 },
+ { 0x418a40, 3, 0x04, 0x00000000 },
+ { 0x418a4c, 1, 0x04, 0x00010000 },
+ { 0x418a50, 3, 0x04, 0x00000000 },
+ { 0x418a60, 3, 0x04, 0x00000000 },
+ { 0x418a6c, 1, 0x04, 0x00010000 },
+ { 0x418a70, 3, 0x04, 0x00000000 },
+ { 0x418a80, 3, 0x04, 0x00000000 },
+ { 0x418a8c, 1, 0x04, 0x00010000 },
+ { 0x418a90, 3, 0x04, 0x00000000 },
+ { 0x418aa0, 3, 0x04, 0x00000000 },
+ { 0x418aac, 1, 0x04, 0x00010000 },
+ { 0x418ab0, 3, 0x04, 0x00000000 },
+ { 0x418ac0, 3, 0x04, 0x00000000 },
+ { 0x418acc, 1, 0x04, 0x00010000 },
+ { 0x418ad0, 3, 0x04, 0x00000000 },
+ { 0x418ae0, 3, 0x04, 0x00000000 },
+ { 0x418aec, 1, 0x04, 0x00010000 },
+ { 0x418af0, 3, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_tpc[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x0000012a },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00000001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ { 0x419c00, 1, 0x04, 0x00000002 },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x00060048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ { 0x419d20, 1, 0x04, 0x02180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419f50, 2, 0x04, 0x00000000 },
+ {}
+};
-int
-nvc0_grctx_init(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+void
+nvc0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
{
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nouveau_gpuobj *chan;
- u32 size = (0x80000 + priv->size + 4095) & ~4095;
- int ret, i;
-
- /* allocate memory to for a "channel", which we'll use to generate
- * the default context values
- */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, size, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &info->chan);
- chan = info->chan;
- if (ret) {
- nv_error(priv, "failed to allocate channel memory, %d\n", ret);
- return ret;
- }
-
- /* PGD pointer */
- nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000));
- nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000));
- nv_wo32(chan, 0x0208, 0xffffffff);
- nv_wo32(chan, 0x020c, 0x000000ff);
-
- /* PGT[0] pointer */
- nv_wo32(chan, 0x1000, 0x00000000);
- nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
-
- /* identity-map the whole "channel" into its own vm */
- for (i = 0; i < size / 4096; i++) {
- u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
- nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
- nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
- }
-
- /* context pointer (virt) */
- nv_wo32(chan, 0x0210, 0x00080004);
- nv_wo32(chan, 0x0214, 0x00000000);
+ int gpc, tpc;
+ u32 offset;
- bar->flush(bar);
-
- nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
- nv_wr32(priv, 0x100cbc, 0x80000001);
- nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
-
- /* setup default state for mmio list construction */
- info->data = priv->mmio_data;
- info->mmio = priv->mmio_list;
- info->addr = 0x2000 + (i * 8);
- info->priv = priv;
- info->buffer_nr = 0;
+ mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
- if (priv->firmware) {
- nv_wr32(priv, 0x409840, 0x00000030);
- nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
- nv_wr32(priv, 0x409504, 0x00000003);
- if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
- nv_error(priv, "load_ctx timeout\n");
+ mmio_list(0x408004, 0x00000000, 8, 0);
+ mmio_list(0x408008, 0x80000018, 0, 0);
+ mmio_list(0x40800c, 0x00000000, 8, 1);
+ mmio_list(0x408010, 0x80000000, 0, 0);
+ mmio_list(0x418810, 0x80000000, 12, 2);
+ mmio_list(0x419848, 0x10000000, 12, 2);
+ mmio_list(0x419004, 0x00000000, 8, 1);
+ mmio_list(0x419008, 0x00000000, 0, 0);
+ mmio_list(0x418808, 0x00000000, 8, 0);
+ mmio_list(0x41880c, 0x80000018, 0, 0);
- nv_wo32(chan, 0x8001c, 1);
- nv_wo32(chan, 0x80020, 0);
- nv_wo32(chan, 0x80028, 0);
- nv_wo32(chan, 0x8002c, 0);
- bar->flush(bar);
- return 0;
- }
+ mmio_list(0x405830, 0x02180000, 0, 0);
- /* HUB_FUC(SET_CHAN) */
- nv_wr32(priv, 0x409840, 0x80000000);
- nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
- nv_wr32(priv, 0x409504, 0x00000001);
- if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
- nv_error(priv, "HUB_SET_CHAN timeout\n");
- nvc0_graph_ctxctl_debug(priv);
- nouveau_gpuobj_ref(NULL, &info->chan);
- return -EBUSY;
+ for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ u32 addr = TPC_UNIT(gpc, tpc, 0x0520);
+ mmio_list(addr, 0x02180000 | offset, 0, 0);
+ offset += 0x0324;
+ }
}
-
- return 0;
}
void
-nvc0_grctx_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access)
+nvc0_grctx_generate_unkn(struct nvc0_graph_priv *priv)
{
- info->buffer[info->buffer_nr] = info->addr;
- info->buffer[info->buffer_nr] += (align - 1);
- info->buffer[info->buffer_nr] &= ~(align - 1);
- info->addr = info->buffer[info->buffer_nr++] + size;
-
- info->data->size = size;
- info->data->align = align;
- info->data->access = access;
- info->data++;
}
void
-nvc0_grctx_mmio(struct nvc0_grctx *info, u32 addr, u32 data, u32 shift, u32 buf)
+nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
{
- struct nvc0_graph_priv *priv = info->priv;
-
- info->mmio->addr = addr;
- info->mmio->data = data;
- info->mmio->shift = shift;
- info->mmio->buffer = buf;
- info->mmio++;
+ int gpc, tpc, id;
- if (shift)
- data |= info->buffer[buf] >> shift;
- nv_wr32(priv, addr, data);
-}
-
-int
-nvc0_grctx_fini(struct nvc0_grctx *info)
-{
- struct nvc0_graph_priv *priv = info->priv;
- int i;
-
- /* trigger a context unload by unsetting the "next channel valid" bit
- * and faking a context switch interrupt
- */
- nv_mask(priv, 0x409b04, 0x80000000, 0x00000000);
- nv_wr32(priv, 0x409000, 0x00000100);
- if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
- nv_error(priv, "grctx template channel unload timeout\n");
- return -EBUSY;
- }
-
- priv->data = kmalloc(priv->size, GFP_KERNEL);
- if (priv->data) {
- for (i = 0; i < priv->size; i += 4)
- priv->data[i / 4] = nv_ro32(info->chan, 0x80000 + i);
- }
-
- nouveau_gpuobj_ref(NULL, &info->chan);
- return priv->data ? 0 : -ENOMEM;
-}
+ for (tpc = 0, id = 0; tpc < 4; tpc++) {
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ if (tpc < priv->tpc_nr[gpc]) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+ id++;
+ }
-static void
-nvc0_grctx_generate_9097(struct nvc0_graph_priv *priv)
-{
- u32 fermi = nvc0_graph_class(priv);
- u32 mthd;
-
- nv_mthd(priv, 0x9097, 0x0800, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0840, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0880, 0x00000000);
- nv_mthd(priv, 0x9097, 0x08c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0900, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0940, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0980, 0x00000000);
- nv_mthd(priv, 0x9097, 0x09c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0804, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0844, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0884, 0x00000000);
- nv_mthd(priv, 0x9097, 0x08c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0904, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0944, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0984, 0x00000000);
- nv_mthd(priv, 0x9097, 0x09c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0808, 0x00000400);
- nv_mthd(priv, 0x9097, 0x0848, 0x00000400);
- nv_mthd(priv, 0x9097, 0x0888, 0x00000400);
- nv_mthd(priv, 0x9097, 0x08c8, 0x00000400);
- nv_mthd(priv, 0x9097, 0x0908, 0x00000400);
- nv_mthd(priv, 0x9097, 0x0948, 0x00000400);
- nv_mthd(priv, 0x9097, 0x0988, 0x00000400);
- nv_mthd(priv, 0x9097, 0x09c8, 0x00000400);
- nv_mthd(priv, 0x9097, 0x080c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x084c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x088c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x08cc, 0x00000300);
- nv_mthd(priv, 0x9097, 0x090c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x094c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x098c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x09cc, 0x00000300);
- nv_mthd(priv, 0x9097, 0x0810, 0x000000cf);
- nv_mthd(priv, 0x9097, 0x0850, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0890, 0x00000000);
- nv_mthd(priv, 0x9097, 0x08d0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0910, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0950, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0990, 0x00000000);
- nv_mthd(priv, 0x9097, 0x09d0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0814, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0854, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0894, 0x00000040);
- nv_mthd(priv, 0x9097, 0x08d4, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0914, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0954, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0994, 0x00000040);
- nv_mthd(priv, 0x9097, 0x09d4, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0818, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0858, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0898, 0x00000001);
- nv_mthd(priv, 0x9097, 0x08d8, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0918, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0958, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0998, 0x00000001);
- nv_mthd(priv, 0x9097, 0x09d8, 0x00000001);
- nv_mthd(priv, 0x9097, 0x081c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x085c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x089c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x08dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x091c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x095c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x099c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x09dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0820, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0860, 0x00000000);
- nv_mthd(priv, 0x9097, 0x08a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x08e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0920, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0960, 0x00000000);
- nv_mthd(priv, 0x9097, 0x09a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x09e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2700, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2720, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2740, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2760, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2780, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2704, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2724, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2744, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2764, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2784, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2708, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2728, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2748, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2768, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2788, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27a8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27c8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x270c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x272c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x274c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x276c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x278c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27ac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x27ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2710, 0x00014000);
- nv_mthd(priv, 0x9097, 0x2730, 0x00014000);
- nv_mthd(priv, 0x9097, 0x2750, 0x00014000);
- nv_mthd(priv, 0x9097, 0x2770, 0x00014000);
- nv_mthd(priv, 0x9097, 0x2790, 0x00014000);
- nv_mthd(priv, 0x9097, 0x27b0, 0x00014000);
- nv_mthd(priv, 0x9097, 0x27d0, 0x00014000);
- nv_mthd(priv, 0x9097, 0x27f0, 0x00014000);
- nv_mthd(priv, 0x9097, 0x2714, 0x00000040);
- nv_mthd(priv, 0x9097, 0x2734, 0x00000040);
- nv_mthd(priv, 0x9097, 0x2754, 0x00000040);
- nv_mthd(priv, 0x9097, 0x2774, 0x00000040);
- nv_mthd(priv, 0x9097, 0x2794, 0x00000040);
- nv_mthd(priv, 0x9097, 0x27b4, 0x00000040);
- nv_mthd(priv, 0x9097, 0x27d4, 0x00000040);
- nv_mthd(priv, 0x9097, 0x27f4, 0x00000040);
- nv_mthd(priv, 0x9097, 0x1c00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ca0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cb0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cc0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cd0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ce0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cf0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c24, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c34, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c64, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c94, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ca4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cb4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cc4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cd4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ce4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cf4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c18, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c28, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c38, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c58, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c68, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c78, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c98, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ca8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cb8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cc8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cd8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ce8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cf8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c0c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c1c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c2c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c3c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c4c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c5c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c6c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c7c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1c9c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cbc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ccc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cdc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1cfc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1da0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1db0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dc0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dd0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1de0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1df0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d24, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d34, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d64, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d94, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1da4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1db4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dc4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dd4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1de4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1df4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d18, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d28, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d38, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d58, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d68, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d78, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d98, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1da8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1db8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dc8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dd8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1de8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1df8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d0c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d1c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d2c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d3c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d4c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d5c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d6c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d7c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1d9c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dbc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dcc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ddc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1dfc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f18, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f28, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f38, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f58, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f68, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f78, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f0c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f1c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f24, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f2c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f34, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f3c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f4c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f5c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f64, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f6c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f7c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f98, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fa0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fa8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fb0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fb8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fc0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fc8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fd0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fd8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fe0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fe8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ff0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ff8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f94, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1f9c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fa4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fb4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fbc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fc4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fcc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fd4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fdc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fe4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1fec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ff4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1ffc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2200, 0x00000022);
- nv_mthd(priv, 0x9097, 0x2210, 0x00000022);
- nv_mthd(priv, 0x9097, 0x2220, 0x00000022);
- nv_mthd(priv, 0x9097, 0x2230, 0x00000022);
- nv_mthd(priv, 0x9097, 0x2240, 0x00000022);
- nv_mthd(priv, 0x9097, 0x2000, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2040, 0x00000011);
- nv_mthd(priv, 0x9097, 0x2080, 0x00000020);
- nv_mthd(priv, 0x9097, 0x20c0, 0x00000030);
- nv_mthd(priv, 0x9097, 0x2100, 0x00000040);
- nv_mthd(priv, 0x9097, 0x2140, 0x00000051);
- nv_mthd(priv, 0x9097, 0x200c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x204c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x208c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x20cc, 0x00000001);
- nv_mthd(priv, 0x9097, 0x210c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x214c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x2010, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2050, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2090, 0x00000001);
- nv_mthd(priv, 0x9097, 0x20d0, 0x00000002);
- nv_mthd(priv, 0x9097, 0x2110, 0x00000003);
- nv_mthd(priv, 0x9097, 0x2150, 0x00000004);
- nv_mthd(priv, 0x9097, 0x0380, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0384, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0388, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03a8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03c8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x038c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03ac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x03ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0700, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0710, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0720, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0730, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0704, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0714, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0724, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0734, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0708, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0718, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0728, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0738, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2800, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2804, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2808, 0x00000000);
- nv_mthd(priv, 0x9097, 0x280c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2810, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2814, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2818, 0x00000000);
- nv_mthd(priv, 0x9097, 0x281c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2820, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2824, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2828, 0x00000000);
- nv_mthd(priv, 0x9097, 0x282c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2830, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2834, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2838, 0x00000000);
- nv_mthd(priv, 0x9097, 0x283c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2840, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2844, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2848, 0x00000000);
- nv_mthd(priv, 0x9097, 0x284c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2850, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2854, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2858, 0x00000000);
- nv_mthd(priv, 0x9097, 0x285c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2860, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2864, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2868, 0x00000000);
- nv_mthd(priv, 0x9097, 0x286c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2870, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2874, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2878, 0x00000000);
- nv_mthd(priv, 0x9097, 0x287c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2880, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2884, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2888, 0x00000000);
- nv_mthd(priv, 0x9097, 0x288c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2890, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2894, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2898, 0x00000000);
- nv_mthd(priv, 0x9097, 0x289c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28a8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28ac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28b0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28b4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28b8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28bc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28c8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28d0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28d4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28d8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28f0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28f4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28f8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x28fc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2900, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2904, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2908, 0x00000000);
- nv_mthd(priv, 0x9097, 0x290c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2910, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2914, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2918, 0x00000000);
- nv_mthd(priv, 0x9097, 0x291c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2920, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2924, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2928, 0x00000000);
- nv_mthd(priv, 0x9097, 0x292c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2930, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2934, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2938, 0x00000000);
- nv_mthd(priv, 0x9097, 0x293c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2940, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2944, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2948, 0x00000000);
- nv_mthd(priv, 0x9097, 0x294c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2950, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2954, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2958, 0x00000000);
- nv_mthd(priv, 0x9097, 0x295c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2960, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2964, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2968, 0x00000000);
- nv_mthd(priv, 0x9097, 0x296c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2970, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2974, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2978, 0x00000000);
- nv_mthd(priv, 0x9097, 0x297c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2980, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2984, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2988, 0x00000000);
- nv_mthd(priv, 0x9097, 0x298c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2990, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2994, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2998, 0x00000000);
- nv_mthd(priv, 0x9097, 0x299c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29a8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29ac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29b0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29b4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29b8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29bc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29c8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29d0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29d4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29d8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29f0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29f4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29f8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x29fc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0aa0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ac0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ae0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ba0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bc0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0be0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a24, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a64, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0aa4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ac4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ae4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b24, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b64, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ba4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bc4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0be4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a28, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a68, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0aa8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ac8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ae8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b28, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b68, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ba8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bc8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0be8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a0c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a2c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a4c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a6c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0aac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0acc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0aec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b0c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b2c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b4c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b6c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bcc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ab0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ad0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0af0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bb0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bd0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bf0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a34, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0a94, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ab4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ad4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0af4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b34, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0b94, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bb4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bd4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0bf4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ca0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cb0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cc0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cd0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ce0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cf0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c24, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c34, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c64, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c94, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ca4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cb4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cc4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cd4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ce4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cf4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c18, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c28, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c38, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c58, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c68, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c78, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c98, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ca8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cb8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cc8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cd8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ce8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0cf8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0c0c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c1c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c2c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c3c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c4c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c5c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c6c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c7c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c8c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0c9c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0cac, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0cbc, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0ccc, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0cdc, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0cec, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0cfc, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0d00, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d08, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d10, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d18, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d20, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d28, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d30, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d38, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d04, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d0c, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d14, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d1c, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d24, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d2c, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d34, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d3c, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e00, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e20, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e30, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e60, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e70, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ea0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0eb0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ec0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ed0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ee0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ef0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0e04, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e14, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e24, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e34, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e44, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e54, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e64, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e74, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e84, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e94, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ea4, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0eb4, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ec4, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ed4, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ee4, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ef4, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e08, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e18, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e28, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e38, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e48, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e58, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e68, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e78, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e88, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0e98, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ea8, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0eb8, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ec8, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ed8, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ee8, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0ef8, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d40, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d48, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d50, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d58, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d44, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d4c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d5c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1e00, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e20, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e40, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e60, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e80, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ea0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ec0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ee0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e04, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e24, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e44, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e64, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e84, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ea4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ec4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ee4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e08, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e28, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e48, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e68, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e88, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1ea8, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1ec8, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1ee8, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e0c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e2c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e4c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e6c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e8c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1eac, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ecc, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1eec, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e10, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e30, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e50, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e70, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e90, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1eb0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ed0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ef0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e14, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e34, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e54, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e74, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e94, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1eb4, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1ed4, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1ef4, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1e18, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e38, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e58, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e78, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1e98, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1eb8, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ed8, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1ef8, 0x00000001);
- if (fermi == 0x9097) {
- for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4)
- nv_mthd(priv, 0x9097, mthd, 0x00000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+ }
}
- nv_mthd(priv, 0x9097, 0x030c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1944, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1514, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d68, 0x0000ffff);
- nv_mthd(priv, 0x9097, 0x121c, 0x0fac6881);
- nv_mthd(priv, 0x9097, 0x0fac, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1538, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0fe0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0fe4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0fe8, 0x00000014);
- nv_mthd(priv, 0x9097, 0x0fec, 0x00000040);
- nv_mthd(priv, 0x9097, 0x0ff0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x179c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1228, 0x00000400);
- nv_mthd(priv, 0x9097, 0x122c, 0x00000300);
- nv_mthd(priv, 0x9097, 0x1230, 0x00010001);
- nv_mthd(priv, 0x9097, 0x07f8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x15b4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x15cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1534, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0fb0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x15d0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x153c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x16b4, 0x00000003);
- nv_mthd(priv, 0x9097, 0x0fbc, 0x0000ffff);
- nv_mthd(priv, 0x9097, 0x0fc0, 0x0000ffff);
- nv_mthd(priv, 0x9097, 0x0fc4, 0x0000ffff);
- nv_mthd(priv, 0x9097, 0x0fc8, 0x0000ffff);
- nv_mthd(priv, 0x9097, 0x0df8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0dfc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1948, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1970, 0x00000001);
- nv_mthd(priv, 0x9097, 0x161c, 0x000009f0);
- nv_mthd(priv, 0x9097, 0x0dcc, 0x00000010);
- nv_mthd(priv, 0x9097, 0x163c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x15e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1160, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1164, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1168, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x116c, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1170, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1174, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1178, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x117c, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1180, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1184, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1188, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x118c, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1190, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1194, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1198, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x119c, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11a0, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11a4, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11a8, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11ac, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11b0, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11b4, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11b8, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11bc, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11c0, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11c4, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11c8, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11cc, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11d0, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11d4, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11d8, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x11dc, 0x25e00040);
- nv_mthd(priv, 0x9097, 0x1880, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1884, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1888, 0x00000000);
- nv_mthd(priv, 0x9097, 0x188c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1890, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1894, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1898, 0x00000000);
- nv_mthd(priv, 0x9097, 0x189c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18a8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18ac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18b0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18b4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18b8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18bc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18c8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18d0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18d4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18d8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18e0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18f0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18f4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18f8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x18fc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x17c8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x17cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x17d0, 0x000000ff);
- nv_mthd(priv, 0x9097, 0x17d4, 0xffffffff);
- nv_mthd(priv, 0x9097, 0x17d8, 0x00000002);
- nv_mthd(priv, 0x9097, 0x17dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x15f4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x15f8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1434, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1438, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d74, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0dec, 0x00000001);
- nv_mthd(priv, 0x9097, 0x13a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1318, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1644, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0748, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0de8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1648, 0x00000000);
- nv_mthd(priv, 0x9097, 0x12a4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1120, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1124, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1128, 0x00000000);
- nv_mthd(priv, 0x9097, 0x112c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1118, 0x00000000);
- nv_mthd(priv, 0x9097, 0x164c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1658, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1910, 0x00000290);
- nv_mthd(priv, 0x9097, 0x1518, 0x00000000);
- nv_mthd(priv, 0x9097, 0x165c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1520, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1604, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1570, 0x00000000);
- nv_mthd(priv, 0x9097, 0x13b0, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x13b4, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x020c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1670, 0x30201000);
- nv_mthd(priv, 0x9097, 0x1674, 0x70605040);
- nv_mthd(priv, 0x9097, 0x1678, 0xb8a89888);
- nv_mthd(priv, 0x9097, 0x167c, 0xf8e8d8c8);
- nv_mthd(priv, 0x9097, 0x166c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1680, 0x00ffff00);
- nv_mthd(priv, 0x9097, 0x12d0, 0x00000003);
- nv_mthd(priv, 0x9097, 0x12d4, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1684, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1688, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0dac, 0x00001b02);
- nv_mthd(priv, 0x9097, 0x0db0, 0x00001b02);
- nv_mthd(priv, 0x9097, 0x0db4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x168c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x15bc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x156c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x187c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1110, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0dc0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0dc4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0dc8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1234, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1690, 0x00000000);
- nv_mthd(priv, 0x9097, 0x12ac, 0x00000001);
- nv_mthd(priv, 0x9097, 0x02c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0790, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0794, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0798, 0x00000000);
- nv_mthd(priv, 0x9097, 0x079c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x07a0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x077c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1000, 0x00000010);
- nv_mthd(priv, 0x9097, 0x10fc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1290, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0218, 0x00000010);
- nv_mthd(priv, 0x9097, 0x12d8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x12dc, 0x00000010);
- nv_mthd(priv, 0x9097, 0x0d94, 0x00000001);
- nv_mthd(priv, 0x9097, 0x155c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1560, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1564, 0x00001fff);
- nv_mthd(priv, 0x9097, 0x1574, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1578, 0x00000000);
- nv_mthd(priv, 0x9097, 0x157c, 0x003fffff);
- nv_mthd(priv, 0x9097, 0x1354, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1664, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1610, 0x00000012);
- nv_mthd(priv, 0x9097, 0x1608, 0x00000000);
- nv_mthd(priv, 0x9097, 0x160c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x162c, 0x00000003);
- nv_mthd(priv, 0x9097, 0x0210, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0320, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0324, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0328, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x032c, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0330, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0334, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0338, 0x3f800000);
- nv_mthd(priv, 0x9097, 0x0750, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0760, 0x39291909);
- nv_mthd(priv, 0x9097, 0x0764, 0x79695949);
- nv_mthd(priv, 0x9097, 0x0768, 0xb9a99989);
- nv_mthd(priv, 0x9097, 0x076c, 0xf9e9d9c9);
- nv_mthd(priv, 0x9097, 0x0770, 0x30201000);
- nv_mthd(priv, 0x9097, 0x0774, 0x70605040);
- nv_mthd(priv, 0x9097, 0x0778, 0x00009080);
- nv_mthd(priv, 0x9097, 0x0780, 0x39291909);
- nv_mthd(priv, 0x9097, 0x0784, 0x79695949);
- nv_mthd(priv, 0x9097, 0x0788, 0xb9a99989);
- nv_mthd(priv, 0x9097, 0x078c, 0xf9e9d9c9);
- nv_mthd(priv, 0x9097, 0x07d0, 0x30201000);
- nv_mthd(priv, 0x9097, 0x07d4, 0x70605040);
- nv_mthd(priv, 0x9097, 0x07d8, 0x00009080);
- nv_mthd(priv, 0x9097, 0x037c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0740, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0744, 0x00000000);
- nv_mthd(priv, 0x9097, 0x2600, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1918, 0x00000000);
- nv_mthd(priv, 0x9097, 0x191c, 0x00000900);
- nv_mthd(priv, 0x9097, 0x1920, 0x00000405);
- nv_mthd(priv, 0x9097, 0x1308, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1924, 0x00000000);
- nv_mthd(priv, 0x9097, 0x13ac, 0x00000000);
- nv_mthd(priv, 0x9097, 0x192c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x193c, 0x00002c1c);
- nv_mthd(priv, 0x9097, 0x0d7c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x02c0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1510, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1940, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ff4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0ff8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x194c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1950, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1968, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1590, 0x0000003f);
- nv_mthd(priv, 0x9097, 0x07e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x07ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x07f0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x07f4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x196c, 0x00000011);
- nv_mthd(priv, 0x9097, 0x197c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0fcc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0fd0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x02d8, 0x00000040);
- nv_mthd(priv, 0x9097, 0x1980, 0x00000080);
- nv_mthd(priv, 0x9097, 0x1504, 0x00000080);
- nv_mthd(priv, 0x9097, 0x1984, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0300, 0x00000001);
- nv_mthd(priv, 0x9097, 0x13a8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x12ec, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1310, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1314, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1380, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1384, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1388, 0x00000001);
- nv_mthd(priv, 0x9097, 0x138c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1390, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1394, 0x00000000);
- nv_mthd(priv, 0x9097, 0x139c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1398, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1594, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1598, 0x00000001);
- nv_mthd(priv, 0x9097, 0x159c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x15a0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x15a4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x0f54, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f58, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f5c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x19bc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f9c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0fa0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x12cc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x12e8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x130c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1360, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1364, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1368, 0x00000000);
- nv_mthd(priv, 0x9097, 0x136c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1370, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1374, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1378, 0x00000000);
- nv_mthd(priv, 0x9097, 0x137c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x133c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1340, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1344, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1348, 0x00000001);
- nv_mthd(priv, 0x9097, 0x134c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1350, 0x00000002);
- nv_mthd(priv, 0x9097, 0x1358, 0x00000001);
- nv_mthd(priv, 0x9097, 0x12e4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x131c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1320, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1324, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1328, 0x00000000);
- nv_mthd(priv, 0x9097, 0x19c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1140, 0x00000000);
- nv_mthd(priv, 0x9097, 0x19c4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x19c8, 0x00001500);
- nv_mthd(priv, 0x9097, 0x135c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x19e0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19e4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19e8, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19ec, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19f0, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19f4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19f8, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19fc, 0x00000001);
- nv_mthd(priv, 0x9097, 0x19cc, 0x00000001);
- nv_mthd(priv, 0x9097, 0x15b8, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a00, 0x00001111);
- nv_mthd(priv, 0x9097, 0x1a04, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a08, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a0c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a10, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a14, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a18, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1a1c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d6c, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x0d70, 0xffff0000);
- nv_mthd(priv, 0x9097, 0x10f8, 0x00001010);
- nv_mthd(priv, 0x9097, 0x0d80, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d84, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d88, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d8c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0d90, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0da0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1508, 0x80000000);
- nv_mthd(priv, 0x9097, 0x150c, 0x40000000);
- nv_mthd(priv, 0x9097, 0x1668, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0318, 0x00000008);
- nv_mthd(priv, 0x9097, 0x031c, 0x00000008);
- nv_mthd(priv, 0x9097, 0x0d9c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x07dc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x074c, 0x00000055);
- nv_mthd(priv, 0x9097, 0x1420, 0x00000003);
- nv_mthd(priv, 0x9097, 0x17bc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x17c0, 0x00000000);
- nv_mthd(priv, 0x9097, 0x17c4, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1008, 0x00000008);
- nv_mthd(priv, 0x9097, 0x100c, 0x00000040);
- nv_mthd(priv, 0x9097, 0x1010, 0x0000012c);
- nv_mthd(priv, 0x9097, 0x0d60, 0x00000040);
- nv_mthd(priv, 0x9097, 0x075c, 0x00000003);
- nv_mthd(priv, 0x9097, 0x1018, 0x00000020);
- nv_mthd(priv, 0x9097, 0x101c, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1020, 0x00000020);
- nv_mthd(priv, 0x9097, 0x1024, 0x00000001);
- nv_mthd(priv, 0x9097, 0x1444, 0x00000000);
- nv_mthd(priv, 0x9097, 0x1448, 0x00000000);
- nv_mthd(priv, 0x9097, 0x144c, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0360, 0x20164010);
- nv_mthd(priv, 0x9097, 0x0364, 0x00000020);
- nv_mthd(priv, 0x9097, 0x0368, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0de4, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0204, 0x00000006);
- nv_mthd(priv, 0x9097, 0x0208, 0x00000000);
- nv_mthd(priv, 0x9097, 0x02cc, 0x003fffff);
- nv_mthd(priv, 0x9097, 0x02d0, 0x00000c48);
- nv_mthd(priv, 0x9097, 0x1220, 0x00000005);
- nv_mthd(priv, 0x9097, 0x0fdc, 0x00000000);
- nv_mthd(priv, 0x9097, 0x0f98, 0x00300008);
- nv_mthd(priv, 0x9097, 0x1284, 0x04000080);
- nv_mthd(priv, 0x9097, 0x1450, 0x00300008);
- nv_mthd(priv, 0x9097, 0x1454, 0x04000080);
- nv_mthd(priv, 0x9097, 0x0214, 0x00000000);
- /* in trace, right after 0x90c0, not here */
- nv_mthd(priv, 0x9097, 0x3410, 0x80002006);
}
-static void
-nvc0_grctx_generate_9197(struct nvc0_graph_priv *priv)
+void
+nvc0_grctx_generate_r406028(struct nvc0_graph_priv *priv)
{
- u32 fermi = nvc0_graph_class(priv);
- u32 mthd;
-
- if (fermi == 0x9197) {
- for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4)
- nv_mthd(priv, 0x9197, mthd, 0x00000000);
+ u32 tmp[GPC_MAX / 8] = {}, i = 0;
+ for (i = 0; i < priv->gpc_nr; i++)
+ tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4);
+ for (i = 0; i < 4; i++) {
+ nv_wr32(priv, 0x406028 + (i * 4), tmp[i]);
+ nv_wr32(priv, 0x405870 + (i * 4), tmp[i]);
}
- nv_mthd(priv, 0x9197, 0x02e4, 0x0000b001);
}
-static void
-nvc0_grctx_generate_9297(struct nvc0_graph_priv *priv)
+void
+nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *priv)
{
- u32 fermi = nvc0_graph_class(priv);
- u32 mthd;
-
- if (fermi == 0x9297) {
- for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4)
- nv_mthd(priv, 0x9297, mthd, 0x00000000);
+ u8 tpcnr[GPC_MAX], data[TPC_MAX];
+ int gpc, tpc, i;
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ memset(data, 0x1f, sizeof(data));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+ data[tpc] = gpc;
}
- nv_mthd(priv, 0x9297, 0x036c, 0x00000000);
- nv_mthd(priv, 0x9297, 0x0370, 0x00000000);
- nv_mthd(priv, 0x9297, 0x07a4, 0x00000000);
- nv_mthd(priv, 0x9297, 0x07a8, 0x00000000);
- nv_mthd(priv, 0x9297, 0x0374, 0x00000000);
- nv_mthd(priv, 0x9297, 0x0378, 0x00000020);
-}
-static void
-nvc0_grctx_generate_902d(struct nvc0_graph_priv *priv)
-{
- nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
- nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0208, 0x00000020);
- nv_mthd(priv, 0x902d, 0x020c, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0210, 0x00000000);
- nv_mthd(priv, 0x902d, 0x0214, 0x00000080);
- nv_mthd(priv, 0x902d, 0x0218, 0x00000100);
- nv_mthd(priv, 0x902d, 0x021c, 0x00000100);
- nv_mthd(priv, 0x902d, 0x0220, 0x00000000);
- nv_mthd(priv, 0x902d, 0x0224, 0x00000000);
- nv_mthd(priv, 0x902d, 0x0230, 0x000000cf);
- nv_mthd(priv, 0x902d, 0x0234, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0238, 0x00000020);
- nv_mthd(priv, 0x902d, 0x023c, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0244, 0x00000080);
- nv_mthd(priv, 0x902d, 0x0248, 0x00000100);
- nv_mthd(priv, 0x902d, 0x024c, 0x00000100);
-}
-
-static void
-nvc0_grctx_generate_9039(struct nvc0_graph_priv *priv)
-{
- nv_mthd(priv, 0x9039, 0x030c, 0x00000000);
- nv_mthd(priv, 0x9039, 0x0310, 0x00000000);
- nv_mthd(priv, 0x9039, 0x0314, 0x00000000);
- nv_mthd(priv, 0x9039, 0x0320, 0x00000000);
- nv_mthd(priv, 0x9039, 0x0238, 0x00000000);
- nv_mthd(priv, 0x9039, 0x023c, 0x00000000);
- nv_mthd(priv, 0x9039, 0x0318, 0x00000000);
- nv_mthd(priv, 0x9039, 0x031c, 0x00000000);
+ for (i = 0; i < 4; i++)
+ nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
}
-static void
-nvc0_grctx_generate_90c0(struct nvc0_graph_priv *priv)
+void
+nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
{
- int i;
-
- for (i = 0; nv_device(priv)->chipset >= 0xd0 && i < 4; i++) {
- nv_mthd(priv, 0x90c0, 0x2700 + (i * 0x40), 0x00000000);
- nv_mthd(priv, 0x90c0, 0x2720 + (i * 0x40), 0x00000000);
- nv_mthd(priv, 0x90c0, 0x2704 + (i * 0x40), 0x00000000);
- nv_mthd(priv, 0x90c0, 0x2724 + (i * 0x40), 0x00000000);
- nv_mthd(priv, 0x90c0, 0x2708 + (i * 0x40), 0x00000000);
- nv_mthd(priv, 0x90c0, 0x2728 + (i * 0x40), 0x00000000);
+ u32 data[6] = {}, data2[2] = {};
+ u8 tpcnr[GPC_MAX];
+ u8 shift, ntpcv;
+ int gpc, tpc, i;
+
+ /* calculate first set of magics */
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+
+ data[tpc / 6] |= gpc << ((tpc % 6) * 5);
}
- nv_mthd(priv, 0x90c0, 0x270c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x272c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x274c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x276c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x278c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x27ac, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x27cc, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x27ec, 0x00000000);
- for (i = 0; nv_device(priv)->chipset >= 0xd0 && i < 4; i++) {
- nv_mthd(priv, 0x90c0, 0x2710 + (i * 0x40), 0x00014000);
- nv_mthd(priv, 0x90c0, 0x2730 + (i * 0x40), 0x00014000);
- nv_mthd(priv, 0x90c0, 0x2714 + (i * 0x40), 0x00000040);
- nv_mthd(priv, 0x90c0, 0x2734 + (i * 0x40), 0x00000040);
- }
- nv_mthd(priv, 0x90c0, 0x030c, 0x00000001);
- nv_mthd(priv, 0x90c0, 0x1944, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0758, 0x00000100);
- nv_mthd(priv, 0x90c0, 0x02c4, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0790, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0794, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0798, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x079c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x07a0, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x077c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0204, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0208, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x020c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0214, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x024c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x0d94, 0x00000001);
- nv_mthd(priv, 0x90c0, 0x1608, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x160c, 0x00000000);
- nv_mthd(priv, 0x90c0, 0x1664, 0x00000000);
-}
-static void
-nvc0_grctx_generate_dispatch(struct nvc0_graph_priv *priv)
-{
- int i;
+ for (; tpc < 32; tpc++)
+ data[tpc / 6] |= 7 << ((tpc % 6) * 5);
- nv_wr32(priv, 0x404004, 0x00000000);
- nv_wr32(priv, 0x404008, 0x00000000);
- nv_wr32(priv, 0x40400c, 0x00000000);
- nv_wr32(priv, 0x404010, 0x00000000);
- nv_wr32(priv, 0x404014, 0x00000000);
- nv_wr32(priv, 0x404018, 0x00000000);
- nv_wr32(priv, 0x40401c, 0x00000000);
- nv_wr32(priv, 0x404020, 0x00000000);
- nv_wr32(priv, 0x404024, 0x00000000);
- nv_wr32(priv, 0x404028, 0x00000000);
- nv_wr32(priv, 0x40402c, 0x00000000);
- nv_wr32(priv, 0x404044, 0x00000000);
- nv_wr32(priv, 0x404094, 0x00000000);
- nv_wr32(priv, 0x404098, 0x00000000);
- nv_wr32(priv, 0x40409c, 0x00000000);
- nv_wr32(priv, 0x4040a0, 0x00000000);
- nv_wr32(priv, 0x4040a4, 0x00000000);
- nv_wr32(priv, 0x4040a8, 0x00000000);
- nv_wr32(priv, 0x4040ac, 0x00000000);
- nv_wr32(priv, 0x4040b0, 0x00000000);
- nv_wr32(priv, 0x4040b4, 0x00000000);
- nv_wr32(priv, 0x4040b8, 0x00000000);
- nv_wr32(priv, 0x4040bc, 0x00000000);
- nv_wr32(priv, 0x4040c0, 0x00000000);
- nv_wr32(priv, 0x4040c4, 0x00000000);
- nv_wr32(priv, 0x4040c8, 0xf0000087);
- nv_wr32(priv, 0x4040d4, 0x00000000);
- nv_wr32(priv, 0x4040d8, 0x00000000);
- nv_wr32(priv, 0x4040dc, 0x00000000);
- nv_wr32(priv, 0x4040e0, 0x00000000);
- nv_wr32(priv, 0x4040e4, 0x00000000);
- nv_wr32(priv, 0x4040e8, 0x00001000);
- nv_wr32(priv, 0x4040f8, 0x00000000);
- nv_wr32(priv, 0x404130, 0x00000000);
- nv_wr32(priv, 0x404134, 0x00000000);
- nv_wr32(priv, 0x404138, 0x20000040);
- nv_wr32(priv, 0x404150, 0x0000002e);
- nv_wr32(priv, 0x404154, 0x00000400);
- nv_wr32(priv, 0x404158, 0x00000200);
- nv_wr32(priv, 0x404164, 0x00000055);
- nv_wr32(priv, 0x404168, 0x00000000);
- nv_wr32(priv, 0x404174, 0x00000000);
- nv_wr32(priv, 0x404178, 0x00000000);
- nv_wr32(priv, 0x40417c, 0x00000000);
- for (i = 0; i < 8; i++)
- nv_wr32(priv, 0x404200 + (i * 4), 0x00000000); /* subc */
-}
-
-static void
-nvc0_grctx_generate_macro(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404404, 0x00000000);
- nv_wr32(priv, 0x404408, 0x00000000);
- nv_wr32(priv, 0x40440c, 0x00000000);
- nv_wr32(priv, 0x404410, 0x00000000);
- nv_wr32(priv, 0x404414, 0x00000000);
- nv_wr32(priv, 0x404418, 0x00000000);
- nv_wr32(priv, 0x40441c, 0x00000000);
- nv_wr32(priv, 0x404420, 0x00000000);
- nv_wr32(priv, 0x404424, 0x00000000);
- nv_wr32(priv, 0x404428, 0x00000000);
- nv_wr32(priv, 0x40442c, 0x00000000);
- nv_wr32(priv, 0x404430, 0x00000000);
- nv_wr32(priv, 0x404434, 0x00000000);
- nv_wr32(priv, 0x404438, 0x00000000);
- nv_wr32(priv, 0x404460, 0x00000000);
- nv_wr32(priv, 0x404464, 0x00000000);
- nv_wr32(priv, 0x404468, 0x00ffffff);
- nv_wr32(priv, 0x40446c, 0x00000000);
- nv_wr32(priv, 0x404480, 0x00000001);
- nv_wr32(priv, 0x404498, 0x00000001);
-}
-
-static void
-nvc0_grctx_generate_m2mf(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404604, 0x00000015);
- nv_wr32(priv, 0x404608, 0x00000000);
- nv_wr32(priv, 0x40460c, 0x00002e00);
- nv_wr32(priv, 0x404610, 0x00000100);
- nv_wr32(priv, 0x404618, 0x00000000);
- nv_wr32(priv, 0x40461c, 0x00000000);
- nv_wr32(priv, 0x404620, 0x00000000);
- nv_wr32(priv, 0x404624, 0x00000000);
- nv_wr32(priv, 0x404628, 0x00000000);
- nv_wr32(priv, 0x40462c, 0x00000000);
- nv_wr32(priv, 0x404630, 0x00000000);
- nv_wr32(priv, 0x404634, 0x00000000);
- nv_wr32(priv, 0x404638, 0x00000004);
- nv_wr32(priv, 0x40463c, 0x00000000);
- nv_wr32(priv, 0x404640, 0x00000000);
- nv_wr32(priv, 0x404644, 0x00000000);
- nv_wr32(priv, 0x404648, 0x00000000);
- nv_wr32(priv, 0x40464c, 0x00000000);
- nv_wr32(priv, 0x404650, 0x00000000);
- nv_wr32(priv, 0x404654, 0x00000000);
- nv_wr32(priv, 0x404658, 0x00000000);
- nv_wr32(priv, 0x40465c, 0x007f0100);
- nv_wr32(priv, 0x404660, 0x00000000);
- nv_wr32(priv, 0x404664, 0x00000000);
- nv_wr32(priv, 0x404668, 0x00000000);
- nv_wr32(priv, 0x40466c, 0x00000000);
- nv_wr32(priv, 0x404670, 0x00000000);
- nv_wr32(priv, 0x404674, 0x00000000);
- nv_wr32(priv, 0x404678, 0x00000000);
- nv_wr32(priv, 0x40467c, 0x00000002);
- nv_wr32(priv, 0x404680, 0x00000000);
- nv_wr32(priv, 0x404684, 0x00000000);
- nv_wr32(priv, 0x404688, 0x00000000);
- nv_wr32(priv, 0x40468c, 0x00000000);
- nv_wr32(priv, 0x404690, 0x00000000);
- nv_wr32(priv, 0x404694, 0x00000000);
- nv_wr32(priv, 0x404698, 0x00000000);
- nv_wr32(priv, 0x40469c, 0x00000000);
- nv_wr32(priv, 0x4046a0, 0x007f0080);
- nv_wr32(priv, 0x4046a4, 0x00000000);
- nv_wr32(priv, 0x4046a8, 0x00000000);
- nv_wr32(priv, 0x4046ac, 0x00000000);
- nv_wr32(priv, 0x4046b0, 0x00000000);
- nv_wr32(priv, 0x4046b4, 0x00000000);
- nv_wr32(priv, 0x4046b8, 0x00000000);
- nv_wr32(priv, 0x4046bc, 0x00000000);
- nv_wr32(priv, 0x4046c0, 0x00000000);
- nv_wr32(priv, 0x4046c4, 0x00000000);
- nv_wr32(priv, 0x4046c8, 0x00000000);
- nv_wr32(priv, 0x4046cc, 0x00000000);
- nv_wr32(priv, 0x4046d0, 0x00000000);
- nv_wr32(priv, 0x4046d4, 0x00000000);
- nv_wr32(priv, 0x4046d8, 0x00000000);
- nv_wr32(priv, 0x4046dc, 0x00000000);
- nv_wr32(priv, 0x4046e0, 0x00000000);
- nv_wr32(priv, 0x4046e4, 0x00000000);
- nv_wr32(priv, 0x4046e8, 0x00000000);
- nv_wr32(priv, 0x4046f0, 0x00000000);
- nv_wr32(priv, 0x4046f4, 0x00000000);
-}
+ /* and the second... */
+ shift = 0;
+ ntpcv = priv->tpc_total;
+ while (!(ntpcv & (1 << 4))) {
+ ntpcv <<= 1;
+ shift++;
+ }
-static void
-nvc0_grctx_generate_unk47xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404700, 0x00000000);
- nv_wr32(priv, 0x404704, 0x00000000);
- nv_wr32(priv, 0x404708, 0x00000000);
- nv_wr32(priv, 0x40470c, 0x00000000);
- nv_wr32(priv, 0x404710, 0x00000000);
- nv_wr32(priv, 0x404714, 0x00000000);
- nv_wr32(priv, 0x404718, 0x00000000);
- nv_wr32(priv, 0x40471c, 0x00000000);
- nv_wr32(priv, 0x404720, 0x00000000);
- nv_wr32(priv, 0x404724, 0x00000000);
- nv_wr32(priv, 0x404728, 0x00000000);
- nv_wr32(priv, 0x40472c, 0x00000000);
- nv_wr32(priv, 0x404730, 0x00000000);
- nv_wr32(priv, 0x404734, 0x00000100);
- nv_wr32(priv, 0x404738, 0x00000000);
- nv_wr32(priv, 0x40473c, 0x00000000);
- nv_wr32(priv, 0x404740, 0x00000000);
- nv_wr32(priv, 0x404744, 0x00000000);
- nv_wr32(priv, 0x404748, 0x00000000);
- nv_wr32(priv, 0x40474c, 0x00000000);
- nv_wr32(priv, 0x404750, 0x00000000);
- nv_wr32(priv, 0x404754, 0x00000000);
-}
+ data2[0] = (ntpcv << 16);
+ data2[0] |= (shift << 21);
+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+ for (i = 1; i < 7; i++)
+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-static void
-nvc0_grctx_generate_shaders(struct nvc0_graph_priv *priv)
-{
+ /* GPC_BROADCAST */
+ nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
- if (nv_device(priv)->chipset >= 0xd0) {
- nv_wr32(priv, 0x405800, 0x0f8000bf);
- nv_wr32(priv, 0x405830, 0x02180218);
- nv_wr32(priv, 0x405834, 0x08000000);
- } else
- if (nv_device(priv)->chipset == 0xc1) {
- nv_wr32(priv, 0x405800, 0x0f8000bf);
- nv_wr32(priv, 0x405830, 0x02180218);
- nv_wr32(priv, 0x405834, 0x00000000);
- } else {
- nv_wr32(priv, 0x405800, 0x078000bf);
- nv_wr32(priv, 0x405830, 0x02180000);
- nv_wr32(priv, 0x405834, 0x00000000);
- }
- nv_wr32(priv, 0x405838, 0x00000000);
- nv_wr32(priv, 0x405854, 0x00000000);
- nv_wr32(priv, 0x405870, 0x00000001);
- nv_wr32(priv, 0x405874, 0x00000001);
- nv_wr32(priv, 0x405878, 0x00000001);
- nv_wr32(priv, 0x40587c, 0x00000001);
- nv_wr32(priv, 0x405a00, 0x00000000);
- nv_wr32(priv, 0x405a04, 0x00000000);
- nv_wr32(priv, 0x405a18, 0x00000000);
+ /* GPC_BROADCAST.TP_BROADCAST */
+ nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr | data2[0]);
+ nv_wr32(priv, 0x419be4, data2[1]);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
+
+ /* UNK78xx */
+ nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x40780c + (i * 4), data[i]);
}
-static void
-nvc0_grctx_generate_unk60xx(struct nvc0_graph_priv *priv)
+void
+nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv)
{
- nv_wr32(priv, 0x406020, 0x000103c1);
- nv_wr32(priv, 0x406028, 0x00000001);
- nv_wr32(priv, 0x40602c, 0x00000001);
- nv_wr32(priv, 0x406030, 0x00000001);
- nv_wr32(priv, 0x406034, 0x00000001);
-}
+ u64 tpc_mask = 0, tpc_set = 0;
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc;
+ int i, a, b;
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+ tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
+
+ for (i = 0, gpc = -1, b = -1; i < 32; i++) {
+ a = (i * (priv->tpc_total - 1)) / 32;
+ if (a != b) {
+ b = a;
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-static void
-nvc0_grctx_generate_unk64xx(struct nvc0_graph_priv *priv)
-{
+ tpc_set |= 1 << ((gpc * 8) + tpc);
+ }
- nv_wr32(priv, 0x4064a8, 0x00000000);
- nv_wr32(priv, 0x4064ac, 0x00003fff);
- nv_wr32(priv, 0x4064b4, 0x00000000);
- nv_wr32(priv, 0x4064b8, 0x00000000);
- if (nv_device(priv)->chipset >= 0xd0)
- nv_wr32(priv, 0x4064bc, 0x00000000);
- if (nv_device(priv)->chipset == 0xc1 ||
- nv_device(priv)->chipset >= 0xd0) {
- nv_wr32(priv, 0x4064c0, 0x80140078);
- nv_wr32(priv, 0x4064c4, 0x0086ffff);
+ nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
+ nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask));
+ if (priv->gpc_nr > 4) {
+ nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set));
+ nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask));
+ }
}
}
-static void
-nvc0_grctx_generate_tpbus(struct nvc0_graph_priv *priv)
+void
+nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
{
- nv_wr32(priv, 0x407804, 0x00000023);
- nv_wr32(priv, 0x40780c, 0x0a418820);
- nv_wr32(priv, 0x407810, 0x062080e6);
- nv_wr32(priv, 0x407814, 0x020398a4);
- nv_wr32(priv, 0x407818, 0x0e629062);
- nv_wr32(priv, 0x40781c, 0x0a418820);
- nv_wr32(priv, 0x407820, 0x000000e6);
- nv_wr32(priv, 0x4078bc, 0x00000103);
-}
+ struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ int i;
-static void
-nvc0_grctx_generate_ccache(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x408000, 0x00000000);
- nv_wr32(priv, 0x408004, 0x00000000);
- nv_wr32(priv, 0x408008, 0x00000018);
- nv_wr32(priv, 0x40800c, 0x00000000);
- nv_wr32(priv, 0x408010, 0x00000000);
- nv_wr32(priv, 0x408014, 0x00000069);
- nv_wr32(priv, 0x408018, 0xe100e100);
- nv_wr32(priv, 0x408064, 0x00000000);
-}
+ nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
-static void
-nvc0_grctx_generate_rop(struct nvc0_graph_priv *priv)
-{
- int chipset = nv_device(priv)->chipset;
-
- /* ROPC_BROADCAST */
- nv_wr32(priv, 0x408800, 0x02802a3c);
- nv_wr32(priv, 0x408804, 0x00000040);
- if (chipset >= 0xd0) {
- nv_wr32(priv, 0x408808, 0x1043e005);
- nv_wr32(priv, 0x408900, 0x3080b801);
- nv_wr32(priv, 0x408904, 0x1043e005);
- nv_wr32(priv, 0x408908, 0x00c8102f);
- } else
- if (chipset == 0xc1) {
- nv_wr32(priv, 0x408808, 0x1003e005);
- nv_wr32(priv, 0x408900, 0x3080b801);
- nv_wr32(priv, 0x408904, 0x62000001);
- nv_wr32(priv, 0x408908, 0x00c80929);
- } else {
- nv_wr32(priv, 0x408808, 0x0003e00d);
- nv_wr32(priv, 0x408900, 0x3080b801);
- nv_wr32(priv, 0x408904, 0x02000001);
- nv_wr32(priv, 0x408908, 0x00c80929);
- }
- nv_wr32(priv, 0x40890c, 0x00000000);
- nv_wr32(priv, 0x408980, 0x0000011d);
-}
+ for (i = 0; oclass->hub[i]; i++)
+ nvc0_graph_mmio(priv, oclass->hub[i]);
+ for (i = 0; oclass->gpc[i]; i++)
+ nvc0_graph_mmio(priv, oclass->gpc[i]);
-static void
-nvc0_grctx_generate_gpc(struct nvc0_graph_priv *priv)
-{
- int chipset = nv_device(priv)->chipset;
- int i;
+ nv_wr32(priv, 0x404154, 0x00000000);
- /* GPC_BROADCAST */
- nv_wr32(priv, 0x418380, 0x00000016);
- nv_wr32(priv, 0x418400, 0x38004e00);
- nv_wr32(priv, 0x418404, 0x71e0ffff);
- nv_wr32(priv, 0x418408, 0x00000000);
- nv_wr32(priv, 0x41840c, 0x00001008);
- nv_wr32(priv, 0x418410, 0x0fff0fff);
- nv_wr32(priv, 0x418414, chipset < 0xd0 ? 0x00200fff : 0x02200fff);
- nv_wr32(priv, 0x418450, 0x00000000);
- nv_wr32(priv, 0x418454, 0x00000000);
- nv_wr32(priv, 0x418458, 0x00000000);
- nv_wr32(priv, 0x41845c, 0x00000000);
- nv_wr32(priv, 0x418460, 0x00000000);
- nv_wr32(priv, 0x418464, 0x00000000);
- nv_wr32(priv, 0x418468, 0x00000001);
- nv_wr32(priv, 0x41846c, 0x00000000);
- nv_wr32(priv, 0x418470, 0x00000000);
- nv_wr32(priv, 0x418600, 0x0000001f);
- nv_wr32(priv, 0x418684, 0x0000000f);
- nv_wr32(priv, 0x418700, 0x00000002);
- nv_wr32(priv, 0x418704, 0x00000080);
- nv_wr32(priv, 0x418708, 0x00000000);
- nv_wr32(priv, 0x41870c, chipset < 0xd0 ? 0x07c80000 : 0x00000000);
- nv_wr32(priv, 0x418710, 0x00000000);
- nv_wr32(priv, 0x418800, chipset < 0xd0 ? 0x0006860a : 0x7006860a);
- nv_wr32(priv, 0x418808, 0x00000000);
- nv_wr32(priv, 0x41880c, 0x00000000);
- nv_wr32(priv, 0x418810, 0x00000000);
- nv_wr32(priv, 0x418828, 0x00008442);
- if (chipset == 0xc1 || chipset >= 0xd0)
- nv_wr32(priv, 0x418830, 0x10000001);
- else
- nv_wr32(priv, 0x418830, 0x00000001);
- nv_wr32(priv, 0x4188d8, 0x00000008);
- nv_wr32(priv, 0x4188e0, 0x01000000);
- nv_wr32(priv, 0x4188e8, 0x00000000);
- nv_wr32(priv, 0x4188ec, 0x00000000);
- nv_wr32(priv, 0x4188f0, 0x00000000);
- nv_wr32(priv, 0x4188f4, 0x00000000);
- nv_wr32(priv, 0x4188f8, 0x00000000);
- if (chipset >= 0xd0)
- nv_wr32(priv, 0x4188fc, 0x20100008);
- else if (chipset == 0xc1)
- nv_wr32(priv, 0x4188fc, 0x00100018);
- else
- nv_wr32(priv, 0x4188fc, 0x00100000);
- nv_wr32(priv, 0x41891c, 0x00ff00ff);
- nv_wr32(priv, 0x418924, 0x00000000);
- nv_wr32(priv, 0x418928, 0x00ffff00);
- nv_wr32(priv, 0x41892c, 0x0000ff00);
- for (i = 0; i < 8; i++) {
- nv_wr32(priv, 0x418a00 + (i * 0x20), 0x00000000);
- nv_wr32(priv, 0x418a04 + (i * 0x20), 0x00000000);
- nv_wr32(priv, 0x418a08 + (i * 0x20), 0x00000000);
- nv_wr32(priv, 0x418a0c + (i * 0x20), 0x00010000);
- nv_wr32(priv, 0x418a10 + (i * 0x20), 0x00000000);
- nv_wr32(priv, 0x418a14 + (i * 0x20), 0x00000000);
- nv_wr32(priv, 0x418a18 + (i * 0x20), 0x00000000);
- }
- nv_wr32(priv, 0x418b00, chipset < 0xd0 ? 0x00000000 : 0x00000006);
- nv_wr32(priv, 0x418b08, 0x0a418820);
- nv_wr32(priv, 0x418b0c, 0x062080e6);
- nv_wr32(priv, 0x418b10, 0x020398a4);
- nv_wr32(priv, 0x418b14, 0x0e629062);
- nv_wr32(priv, 0x418b18, 0x0a418820);
- nv_wr32(priv, 0x418b1c, 0x000000e6);
- nv_wr32(priv, 0x418bb8, 0x00000103);
- nv_wr32(priv, 0x418c08, 0x00000001);
- nv_wr32(priv, 0x418c10, 0x00000000);
- nv_wr32(priv, 0x418c14, 0x00000000);
- nv_wr32(priv, 0x418c18, 0x00000000);
- nv_wr32(priv, 0x418c1c, 0x00000000);
- nv_wr32(priv, 0x418c20, 0x00000000);
- nv_wr32(priv, 0x418c24, 0x00000000);
- nv_wr32(priv, 0x418c28, 0x00000000);
- nv_wr32(priv, 0x418c2c, 0x00000000);
- if (chipset == 0xc1 || chipset >= 0xd0)
- nv_wr32(priv, 0x418c6c, 0x00000001);
- nv_wr32(priv, 0x418c80, 0x20200004);
- nv_wr32(priv, 0x418c8c, 0x00000001);
- nv_wr32(priv, 0x419000, 0x00000780);
- nv_wr32(priv, 0x419004, 0x00000000);
- nv_wr32(priv, 0x419008, 0x00000000);
- nv_wr32(priv, 0x419014, 0x00000004);
-}
+ oclass->mods(priv, info);
+ oclass->unkn(priv);
-static void
-nvc0_grctx_generate_tp(struct nvc0_graph_priv *priv)
-{
- int chipset = nv_device(priv)->chipset;
+ nvc0_grctx_generate_tpcid(priv);
+ nvc0_grctx_generate_r406028(priv);
+ nvc0_grctx_generate_r4060a8(priv);
+ nvc0_grctx_generate_r418bb8(priv);
+ nvc0_grctx_generate_r406800(priv);
- /* GPC_BROADCAST.TP_BROADCAST */
- nv_wr32(priv, 0x419818, 0x00000000);
- nv_wr32(priv, 0x41983c, 0x00038bc7);
- nv_wr32(priv, 0x419848, 0x00000000);
- if (chipset == 0xc1 || chipset >= 0xd0)
- nv_wr32(priv, 0x419864, 0x00000129);
- else
- nv_wr32(priv, 0x419864, 0x0000012a);
- nv_wr32(priv, 0x419888, 0x00000000);
- nv_wr32(priv, 0x419a00, 0x000001f0);
- nv_wr32(priv, 0x419a04, 0x00000001);
- nv_wr32(priv, 0x419a08, 0x00000023);
- nv_wr32(priv, 0x419a0c, 0x00020000);
- nv_wr32(priv, 0x419a10, 0x00000000);
- nv_wr32(priv, 0x419a14, 0x00000200);
- nv_wr32(priv, 0x419a1c, 0x00000000);
- nv_wr32(priv, 0x419a20, 0x00000800);
- if (chipset >= 0xd0)
- nv_wr32(priv, 0x00419ac4, 0x0017f440);
- else if (chipset != 0xc0 && chipset != 0xc8)
- nv_wr32(priv, 0x00419ac4, 0x0007f440);
- nv_wr32(priv, 0x419b00, 0x0a418820);
- nv_wr32(priv, 0x419b04, 0x062080e6);
- nv_wr32(priv, 0x419b08, 0x020398a4);
- nv_wr32(priv, 0x419b0c, 0x0e629062);
- nv_wr32(priv, 0x419b10, 0x0a418820);
- nv_wr32(priv, 0x419b14, 0x000000e6);
- nv_wr32(priv, 0x419bd0, 0x00900103);
- if (chipset == 0xc1 || chipset >= 0xd0)
- nv_wr32(priv, 0x419be0, 0x00400001);
- else
- nv_wr32(priv, 0x419be0, 0x00000001);
- nv_wr32(priv, 0x419be4, 0x00000000);
- nv_wr32(priv, 0x419c00, chipset < 0xd0 ? 0x00000002 : 0x0000000a);
- nv_wr32(priv, 0x419c04, 0x00000006);
- nv_wr32(priv, 0x419c08, 0x00000002);
- nv_wr32(priv, 0x419c20, 0x00000000);
- if (nv_device(priv)->chipset >= 0xd0) {
- nv_wr32(priv, 0x419c24, 0x00084210);
- nv_wr32(priv, 0x419c28, 0x3cf3cf3c);
- nv_wr32(priv, 0x419cb0, 0x00020048);
- } else
- if (chipset == 0xce || chipset == 0xcf) {
- nv_wr32(priv, 0x419cb0, 0x00020048);
- } else {
- nv_wr32(priv, 0x419cb0, 0x00060048);
- }
- nv_wr32(priv, 0x419ce8, 0x00000000);
- nv_wr32(priv, 0x419cf4, 0x00000183);
- if (chipset == 0xc1 || chipset >= 0xd0)
- nv_wr32(priv, 0x419d20, 0x12180000);
- else
- nv_wr32(priv, 0x419d20, 0x02180000);
- nv_wr32(priv, 0x419d24, 0x00001fff);
- if (chipset == 0xc1 || chipset >= 0xd0)
- nv_wr32(priv, 0x419d44, 0x02180218);
- nv_wr32(priv, 0x419e04, 0x00000000);
- nv_wr32(priv, 0x419e08, 0x00000000);
- nv_wr32(priv, 0x419e0c, 0x00000000);
- nv_wr32(priv, 0x419e10, 0x00000002);
- nv_wr32(priv, 0x419e44, 0x001beff2);
- nv_wr32(priv, 0x419e48, 0x00000000);
- nv_wr32(priv, 0x419e4c, 0x0000000f);
- nv_wr32(priv, 0x419e50, 0x00000000);
- nv_wr32(priv, 0x419e54, 0x00000000);
- nv_wr32(priv, 0x419e58, 0x00000000);
- nv_wr32(priv, 0x419e5c, 0x00000000);
- nv_wr32(priv, 0x419e60, 0x00000000);
- nv_wr32(priv, 0x419e64, 0x00000000);
- nv_wr32(priv, 0x419e68, 0x00000000);
- nv_wr32(priv, 0x419e6c, 0x00000000);
- nv_wr32(priv, 0x419e70, 0x00000000);
- nv_wr32(priv, 0x419e74, 0x00000000);
- nv_wr32(priv, 0x419e78, 0x00000000);
- nv_wr32(priv, 0x419e7c, 0x00000000);
- nv_wr32(priv, 0x419e80, 0x00000000);
- nv_wr32(priv, 0x419e84, 0x00000000);
- nv_wr32(priv, 0x419e88, 0x00000000);
- nv_wr32(priv, 0x419e8c, 0x00000000);
- nv_wr32(priv, 0x419e90, 0x00000000);
- nv_wr32(priv, 0x419e98, 0x00000000);
- if (chipset != 0xc0 && chipset != 0xc8)
- nv_wr32(priv, 0x419ee0, 0x00011110);
- nv_wr32(priv, 0x419f50, 0x00000000);
- nv_wr32(priv, 0x419f54, 0x00000000);
- if (chipset != 0xc0 && chipset != 0xc8)
- nv_wr32(priv, 0x419f58, 0x00000000);
+ nvc0_graph_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ nvc0_graph_mthd(priv, oclass->mthd);
+ nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
}
int
nvc0_grctx_generate(struct nvc0_graph_priv *priv)
{
+ struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ struct nouveau_bar *bar = nouveau_bar(priv);
+ struct nouveau_gpuobj *chan;
struct nvc0_grctx info;
- int ret, i, gpc, tpc, id;
- u32 fermi = nvc0_graph_class(priv);
- u32 r000260, tmp;
+ int ret, i;
- ret = nvc0_grctx_init(priv, &info);
- if (ret)
+ /* allocate memory to for a "channel", which we'll use to generate
+ * the default context values
+ */
+ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ if (ret) {
+ nv_error(priv, "failed to allocate channel memory, %d\n", ret);
return ret;
-
- r000260 = nv_rd32(priv, 0x000260);
- nv_wr32(priv, 0x000260, r000260 & ~1);
- nv_wr32(priv, 0x400208, 0x00000000);
-
- nvc0_grctx_generate_dispatch(priv);
- nvc0_grctx_generate_macro(priv);
- nvc0_grctx_generate_m2mf(priv);
- nvc0_grctx_generate_unk47xx(priv);
- nvc0_grctx_generate_shaders(priv);
- nvc0_grctx_generate_unk60xx(priv);
- nvc0_grctx_generate_unk64xx(priv);
- nvc0_grctx_generate_tpbus(priv);
- nvc0_grctx_generate_ccache(priv);
- nvc0_grctx_generate_rop(priv);
- nvc0_grctx_generate_gpc(priv);
- nvc0_grctx_generate_tp(priv);
-
- nv_wr32(priv, 0x404154, 0x00000000);
-
- /* generate per-context mmio list data */
- mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
- mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
- mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
- mmio_list(0x408004, 0x00000000, 8, 0);
- mmio_list(0x408008, 0x80000018, 0, 0);
- mmio_list(0x40800c, 0x00000000, 8, 1);
- mmio_list(0x408010, 0x80000000, 0, 0);
- mmio_list(0x418810, 0x80000000, 12, 2);
- mmio_list(0x419848, 0x10000000, 12, 2);
- mmio_list(0x419004, 0x00000000, 8, 1);
- mmio_list(0x419008, 0x00000000, 0, 0);
- mmio_list(0x418808, 0x00000000, 8, 0);
- mmio_list(0x41880c, 0x80000018, 0, 0);
- if (nv_device(priv)->chipset != 0xc1) {
- tmp = 0x02180000;
- mmio_list(0x405830, tmp, 0, 0);
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
- mmio_list(reg, tmp, 0, 0);
- tmp += 0x0324;
- }
- }
- } else {
- tmp = 0x02180000;
- mmio_list(0x405830, 0x00000218 | tmp, 0, 0);
- mmio_list(0x4064c4, 0x0086ffff, 0, 0);
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- u32 reg = TPC_UNIT(gpc, tpc, 0x0520);
- mmio_list(reg, 0x10000000 | tmp, 0, 0);
- tmp += 0x0324;
- }
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- u32 reg = TPC_UNIT(gpc, tpc, 0x0544);
- mmio_list(reg, tmp, 0, 0);
- tmp += 0x0324;
- }
- }
}
- for (tpc = 0, id = 0; tpc < 4; tpc++) {
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- if (tpc < priv->tpc_nr[gpc]) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
- id++;
- }
-
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
- }
- }
-
- tmp = 0;
- for (i = 0; i < priv->gpc_nr; i++)
- tmp |= priv->tpc_nr[i] << (i * 4);
- nv_wr32(priv, 0x406028, tmp);
- nv_wr32(priv, 0x405870, tmp);
-
- nv_wr32(priv, 0x40602c, 0x00000000);
- nv_wr32(priv, 0x405874, 0x00000000);
- nv_wr32(priv, 0x406030, 0x00000000);
- nv_wr32(priv, 0x405878, 0x00000000);
- nv_wr32(priv, 0x406034, 0x00000000);
- nv_wr32(priv, 0x40587c, 0x00000000);
-
- if (1) {
- u8 tpcnr[GPC_MAX], data[TPC_MAX];
-
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- memset(data, 0x1f, sizeof(data));
+ /* PGD pointer */
+ nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000));
+ nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000));
+ nv_wo32(chan, 0x0208, 0xffffffff);
+ nv_wo32(chan, 0x020c, 0x000000ff);
- gpc = -1;
- for (tpc = 0; tpc < priv->tpc_total; tpc++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpcnr[gpc]--;
- data[tpc] = gpc;
- }
+ /* PGT[0] pointer */
+ nv_wo32(chan, 0x1000, 0x00000000);
+ nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
+ /* identity-map the whole "channel" into its own vm */
+ for (i = 0; i < chan->size / 4096; i++) {
+ u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
+ nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
+ nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
}
- if (1) {
- u32 data[6] = {}, data2[2] = {};
- u8 tpcnr[GPC_MAX];
- u8 shift, ntpcv;
-
- /* calculate first set of magics */
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ /* context pointer (virt) */
+ nv_wo32(chan, 0x0210, 0x00080004);
+ nv_wo32(chan, 0x0214, 0x00000000);
- gpc = -1;
- for (tpc = 0; tpc < priv->tpc_total; tpc++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpcnr[gpc]--;
+ bar->flush(bar);
- data[tpc / 6] |= gpc << ((tpc % 6) * 5);
- }
+ nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
+ nv_wr32(priv, 0x100cbc, 0x80000001);
+ nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
- for (; tpc < 32; tpc++)
- data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+ /* setup default state for mmio list construction */
+ info.priv = priv;
+ info.data = priv->mmio_data;
+ info.mmio = priv->mmio_list;
+ info.addr = 0x2000 + (i * 8);
+ info.buffer_nr = 0;
- /* and the second... */
- shift = 0;
- ntpcv = priv->tpc_total;
- while (!(ntpcv & (1 << 4))) {
- ntpcv <<= 1;
- shift++;
- }
+ /* make channel current */
+ if (priv->firmware) {
+ nv_wr32(priv, 0x409840, 0x00000030);
+ nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+ nv_wr32(priv, 0x409504, 0x00000003);
+ if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
+ nv_error(priv, "load_ctx timeout\n");
- data2[0] = (ntpcv << 16);
- data2[0] |= (shift << 21);
- data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
- for (i = 1; i < 7; i++)
- data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
- /* GPC_BROADCAST */
- nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
- /* GPC_BROADCAST.TP_BROADCAST */
- nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr |
- data2[0]);
- nv_wr32(priv, 0x419be4, data2[1]);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
-
- /* UNK78xx */
- nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+ nv_wo32(chan, 0x8001c, 1);
+ nv_wo32(chan, 0x80020, 0);
+ nv_wo32(chan, 0x80028, 0);
+ nv_wo32(chan, 0x8002c, 0);
+ bar->flush(bar);
+ } else {
+ nv_wr32(priv, 0x409840, 0x80000000);
+ nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+ nv_wr32(priv, 0x409504, 0x00000001);
+ if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000))
+ nv_error(priv, "HUB_SET_CHAN timeout\n");
}
- if (1) {
- u32 tpc_mask = 0, tpc_set = 0;
- u8 tpcnr[GPC_MAX], a, b;
-
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (gpc = 0; gpc < priv->gpc_nr; gpc++)
- tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
-
- for (i = 0, gpc = -1, b = -1; i < 32; i++) {
- a = (i * (priv->tpc_total - 1)) / 32;
- if (a != b) {
- b = a;
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- tpc_set |= 1 << ((gpc * 8) + tpc);
- }
+ oclass->main(priv, &info);
- nv_wr32(priv, 0x406800 + (i * 0x20), tpc_set);
- nv_wr32(priv, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask);
- }
+ /* trigger a context unload by unsetting the "next channel valid" bit
+ * and faking a context switch interrupt
+ */
+ nv_mask(priv, 0x409b04, 0x80000000, 0x00000000);
+ nv_wr32(priv, 0x409000, 0x00000100);
+ if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
+ nv_error(priv, "grctx template channel unload timeout\n");
+ ret = -EBUSY;
+ goto done;
}
- nv_wr32(priv, 0x400208, 0x80000000);
-
- nv_icmd(priv, 0x00001000, 0x00000004);
- nv_icmd(priv, 0x000000a9, 0x0000ffff);
- nv_icmd(priv, 0x00000038, 0x0fac6881);
- nv_icmd(priv, 0x0000003d, 0x00000001);
- nv_icmd(priv, 0x000000e8, 0x00000400);
- nv_icmd(priv, 0x000000e9, 0x00000400);
- nv_icmd(priv, 0x000000ea, 0x00000400);
- nv_icmd(priv, 0x000000eb, 0x00000400);
- nv_icmd(priv, 0x000000ec, 0x00000400);
- nv_icmd(priv, 0x000000ed, 0x00000400);
- nv_icmd(priv, 0x000000ee, 0x00000400);
- nv_icmd(priv, 0x000000ef, 0x00000400);
- nv_icmd(priv, 0x00000078, 0x00000300);
- nv_icmd(priv, 0x00000079, 0x00000300);
- nv_icmd(priv, 0x0000007a, 0x00000300);
- nv_icmd(priv, 0x0000007b, 0x00000300);
- nv_icmd(priv, 0x0000007c, 0x00000300);
- nv_icmd(priv, 0x0000007d, 0x00000300);
- nv_icmd(priv, 0x0000007e, 0x00000300);
- nv_icmd(priv, 0x0000007f, 0x00000300);
- nv_icmd(priv, 0x00000050, 0x00000011);
- nv_icmd(priv, 0x00000058, 0x00000008);
- nv_icmd(priv, 0x00000059, 0x00000008);
- nv_icmd(priv, 0x0000005a, 0x00000008);
- nv_icmd(priv, 0x0000005b, 0x00000008);
- nv_icmd(priv, 0x0000005c, 0x00000008);
- nv_icmd(priv, 0x0000005d, 0x00000008);
- nv_icmd(priv, 0x0000005e, 0x00000008);
- nv_icmd(priv, 0x0000005f, 0x00000008);
- nv_icmd(priv, 0x00000208, 0x00000001);
- nv_icmd(priv, 0x00000209, 0x00000001);
- nv_icmd(priv, 0x0000020a, 0x00000001);
- nv_icmd(priv, 0x0000020b, 0x00000001);
- nv_icmd(priv, 0x0000020c, 0x00000001);
- nv_icmd(priv, 0x0000020d, 0x00000001);
- nv_icmd(priv, 0x0000020e, 0x00000001);
- nv_icmd(priv, 0x0000020f, 0x00000001);
- nv_icmd(priv, 0x00000081, 0x00000001);
- nv_icmd(priv, 0x00000085, 0x00000004);
- nv_icmd(priv, 0x00000088, 0x00000400);
- nv_icmd(priv, 0x00000090, 0x00000300);
- nv_icmd(priv, 0x00000098, 0x00001001);
- nv_icmd(priv, 0x000000e3, 0x00000001);
- nv_icmd(priv, 0x000000da, 0x00000001);
- nv_icmd(priv, 0x000000f8, 0x00000003);
- nv_icmd(priv, 0x000000fa, 0x00000001);
- nv_icmd(priv, 0x0000009f, 0x0000ffff);
- nv_icmd(priv, 0x000000a0, 0x0000ffff);
- nv_icmd(priv, 0x000000a1, 0x0000ffff);
- nv_icmd(priv, 0x000000a2, 0x0000ffff);
- nv_icmd(priv, 0x000000b1, 0x00000001);
- nv_icmd(priv, 0x000000b2, 0x00000000);
- nv_icmd(priv, 0x000000b3, 0x00000000);
- nv_icmd(priv, 0x000000b4, 0x00000000);
- nv_icmd(priv, 0x000000b5, 0x00000000);
- nv_icmd(priv, 0x000000b6, 0x00000000);
- nv_icmd(priv, 0x000000b7, 0x00000000);
- nv_icmd(priv, 0x000000b8, 0x00000000);
- nv_icmd(priv, 0x000000b9, 0x00000000);
- nv_icmd(priv, 0x000000ba, 0x00000000);
- nv_icmd(priv, 0x000000bb, 0x00000000);
- nv_icmd(priv, 0x000000bc, 0x00000000);
- nv_icmd(priv, 0x000000bd, 0x00000000);
- nv_icmd(priv, 0x000000be, 0x00000000);
- nv_icmd(priv, 0x000000bf, 0x00000000);
- nv_icmd(priv, 0x000000c0, 0x00000000);
- nv_icmd(priv, 0x000000c1, 0x00000000);
- nv_icmd(priv, 0x000000c2, 0x00000000);
- nv_icmd(priv, 0x000000c3, 0x00000000);
- nv_icmd(priv, 0x000000c4, 0x00000000);
- nv_icmd(priv, 0x000000c5, 0x00000000);
- nv_icmd(priv, 0x000000c6, 0x00000000);
- nv_icmd(priv, 0x000000c7, 0x00000000);
- nv_icmd(priv, 0x000000c8, 0x00000000);
- nv_icmd(priv, 0x000000c9, 0x00000000);
- nv_icmd(priv, 0x000000ca, 0x00000000);
- nv_icmd(priv, 0x000000cb, 0x00000000);
- nv_icmd(priv, 0x000000cc, 0x00000000);
- nv_icmd(priv, 0x000000cd, 0x00000000);
- nv_icmd(priv, 0x000000ce, 0x00000000);
- nv_icmd(priv, 0x000000cf, 0x00000000);
- nv_icmd(priv, 0x000000d0, 0x00000000);
- nv_icmd(priv, 0x000000d1, 0x00000000);
- nv_icmd(priv, 0x000000d2, 0x00000000);
- nv_icmd(priv, 0x000000d3, 0x00000000);
- nv_icmd(priv, 0x000000d4, 0x00000000);
- nv_icmd(priv, 0x000000d5, 0x00000000);
- nv_icmd(priv, 0x000000d6, 0x00000000);
- nv_icmd(priv, 0x000000d7, 0x00000000);
- nv_icmd(priv, 0x000000d8, 0x00000000);
- nv_icmd(priv, 0x000000d9, 0x00000000);
- nv_icmd(priv, 0x00000210, 0x00000040);
- nv_icmd(priv, 0x00000211, 0x00000040);
- nv_icmd(priv, 0x00000212, 0x00000040);
- nv_icmd(priv, 0x00000213, 0x00000040);
- nv_icmd(priv, 0x00000214, 0x00000040);
- nv_icmd(priv, 0x00000215, 0x00000040);
- nv_icmd(priv, 0x00000216, 0x00000040);
- nv_icmd(priv, 0x00000217, 0x00000040);
- if (nv_device(priv)->chipset >= 0xd0) {
- for (i = 0x0400; i <= 0x0417; i++)
- nv_icmd(priv, i, 0x00000040);
- }
- nv_icmd(priv, 0x00000218, 0x0000c080);
- nv_icmd(priv, 0x00000219, 0x0000c080);
- nv_icmd(priv, 0x0000021a, 0x0000c080);
- nv_icmd(priv, 0x0000021b, 0x0000c080);
- nv_icmd(priv, 0x0000021c, 0x0000c080);
- nv_icmd(priv, 0x0000021d, 0x0000c080);
- nv_icmd(priv, 0x0000021e, 0x0000c080);
- nv_icmd(priv, 0x0000021f, 0x0000c080);
- if (nv_device(priv)->chipset >= 0xd0) {
- for (i = 0x0440; i <= 0x0457; i++)
- nv_icmd(priv, i, 0x0000c080);
+ priv->data = kmalloc(priv->size, GFP_KERNEL);
+ if (priv->data) {
+ for (i = 0; i < priv->size; i += 4)
+ priv->data[i / 4] = nv_ro32(chan, 0x80000 + i);
+ ret = 0;
+ } else {
+ ret = -ENOMEM;
}
- nv_icmd(priv, 0x000000ad, 0x0000013e);
- nv_icmd(priv, 0x000000e1, 0x00000010);
- nv_icmd(priv, 0x00000290, 0x00000000);
- nv_icmd(priv, 0x00000291, 0x00000000);
- nv_icmd(priv, 0x00000292, 0x00000000);
- nv_icmd(priv, 0x00000293, 0x00000000);
- nv_icmd(priv, 0x00000294, 0x00000000);
- nv_icmd(priv, 0x00000295, 0x00000000);
- nv_icmd(priv, 0x00000296, 0x00000000);
- nv_icmd(priv, 0x00000297, 0x00000000);
- nv_icmd(priv, 0x00000298, 0x00000000);
- nv_icmd(priv, 0x00000299, 0x00000000);
- nv_icmd(priv, 0x0000029a, 0x00000000);
- nv_icmd(priv, 0x0000029b, 0x00000000);
- nv_icmd(priv, 0x0000029c, 0x00000000);
- nv_icmd(priv, 0x0000029d, 0x00000000);
- nv_icmd(priv, 0x0000029e, 0x00000000);
- nv_icmd(priv, 0x0000029f, 0x00000000);
- nv_icmd(priv, 0x000003b0, 0x00000000);
- nv_icmd(priv, 0x000003b1, 0x00000000);
- nv_icmd(priv, 0x000003b2, 0x00000000);
- nv_icmd(priv, 0x000003b3, 0x00000000);
- nv_icmd(priv, 0x000003b4, 0x00000000);
- nv_icmd(priv, 0x000003b5, 0x00000000);
- nv_icmd(priv, 0x000003b6, 0x00000000);
- nv_icmd(priv, 0x000003b7, 0x00000000);
- nv_icmd(priv, 0x000003b8, 0x00000000);
- nv_icmd(priv, 0x000003b9, 0x00000000);
- nv_icmd(priv, 0x000003ba, 0x00000000);
- nv_icmd(priv, 0x000003bb, 0x00000000);
- nv_icmd(priv, 0x000003bc, 0x00000000);
- nv_icmd(priv, 0x000003bd, 0x00000000);
- nv_icmd(priv, 0x000003be, 0x00000000);
- nv_icmd(priv, 0x000003bf, 0x00000000);
- nv_icmd(priv, 0x000002a0, 0x00000000);
- nv_icmd(priv, 0x000002a1, 0x00000000);
- nv_icmd(priv, 0x000002a2, 0x00000000);
- nv_icmd(priv, 0x000002a3, 0x00000000);
- nv_icmd(priv, 0x000002a4, 0x00000000);
- nv_icmd(priv, 0x000002a5, 0x00000000);
- nv_icmd(priv, 0x000002a6, 0x00000000);
- nv_icmd(priv, 0x000002a7, 0x00000000);
- nv_icmd(priv, 0x000002a8, 0x00000000);
- nv_icmd(priv, 0x000002a9, 0x00000000);
- nv_icmd(priv, 0x000002aa, 0x00000000);
- nv_icmd(priv, 0x000002ab, 0x00000000);
- nv_icmd(priv, 0x000002ac, 0x00000000);
- nv_icmd(priv, 0x000002ad, 0x00000000);
- nv_icmd(priv, 0x000002ae, 0x00000000);
- nv_icmd(priv, 0x000002af, 0x00000000);
- nv_icmd(priv, 0x00000420, 0x00000000);
- nv_icmd(priv, 0x00000421, 0x00000000);
- nv_icmd(priv, 0x00000422, 0x00000000);
- nv_icmd(priv, 0x00000423, 0x00000000);
- nv_icmd(priv, 0x00000424, 0x00000000);
- nv_icmd(priv, 0x00000425, 0x00000000);
- nv_icmd(priv, 0x00000426, 0x00000000);
- nv_icmd(priv, 0x00000427, 0x00000000);
- nv_icmd(priv, 0x00000428, 0x00000000);
- nv_icmd(priv, 0x00000429, 0x00000000);
- nv_icmd(priv, 0x0000042a, 0x00000000);
- nv_icmd(priv, 0x0000042b, 0x00000000);
- nv_icmd(priv, 0x0000042c, 0x00000000);
- nv_icmd(priv, 0x0000042d, 0x00000000);
- nv_icmd(priv, 0x0000042e, 0x00000000);
- nv_icmd(priv, 0x0000042f, 0x00000000);
- nv_icmd(priv, 0x000002b0, 0x00000000);
- nv_icmd(priv, 0x000002b1, 0x00000000);
- nv_icmd(priv, 0x000002b2, 0x00000000);
- nv_icmd(priv, 0x000002b3, 0x00000000);
- nv_icmd(priv, 0x000002b4, 0x00000000);
- nv_icmd(priv, 0x000002b5, 0x00000000);
- nv_icmd(priv, 0x000002b6, 0x00000000);
- nv_icmd(priv, 0x000002b7, 0x00000000);
- nv_icmd(priv, 0x000002b8, 0x00000000);
- nv_icmd(priv, 0x000002b9, 0x00000000);
- nv_icmd(priv, 0x000002ba, 0x00000000);
- nv_icmd(priv, 0x000002bb, 0x00000000);
- nv_icmd(priv, 0x000002bc, 0x00000000);
- nv_icmd(priv, 0x000002bd, 0x00000000);
- nv_icmd(priv, 0x000002be, 0x00000000);
- nv_icmd(priv, 0x000002bf, 0x00000000);
- nv_icmd(priv, 0x00000430, 0x00000000);
- nv_icmd(priv, 0x00000431, 0x00000000);
- nv_icmd(priv, 0x00000432, 0x00000000);
- nv_icmd(priv, 0x00000433, 0x00000000);
- nv_icmd(priv, 0x00000434, 0x00000000);
- nv_icmd(priv, 0x00000435, 0x00000000);
- nv_icmd(priv, 0x00000436, 0x00000000);
- nv_icmd(priv, 0x00000437, 0x00000000);
- nv_icmd(priv, 0x00000438, 0x00000000);
- nv_icmd(priv, 0x00000439, 0x00000000);
- nv_icmd(priv, 0x0000043a, 0x00000000);
- nv_icmd(priv, 0x0000043b, 0x00000000);
- nv_icmd(priv, 0x0000043c, 0x00000000);
- nv_icmd(priv, 0x0000043d, 0x00000000);
- nv_icmd(priv, 0x0000043e, 0x00000000);
- nv_icmd(priv, 0x0000043f, 0x00000000);
- nv_icmd(priv, 0x000002c0, 0x00000000);
- nv_icmd(priv, 0x000002c1, 0x00000000);
- nv_icmd(priv, 0x000002c2, 0x00000000);
- nv_icmd(priv, 0x000002c3, 0x00000000);
- nv_icmd(priv, 0x000002c4, 0x00000000);
- nv_icmd(priv, 0x000002c5, 0x00000000);
- nv_icmd(priv, 0x000002c6, 0x00000000);
- nv_icmd(priv, 0x000002c7, 0x00000000);
- nv_icmd(priv, 0x000002c8, 0x00000000);
- nv_icmd(priv, 0x000002c9, 0x00000000);
- nv_icmd(priv, 0x000002ca, 0x00000000);
- nv_icmd(priv, 0x000002cb, 0x00000000);
- nv_icmd(priv, 0x000002cc, 0x00000000);
- nv_icmd(priv, 0x000002cd, 0x00000000);
- nv_icmd(priv, 0x000002ce, 0x00000000);
- nv_icmd(priv, 0x000002cf, 0x00000000);
- nv_icmd(priv, 0x000004d0, 0x00000000);
- nv_icmd(priv, 0x000004d1, 0x00000000);
- nv_icmd(priv, 0x000004d2, 0x00000000);
- nv_icmd(priv, 0x000004d3, 0x00000000);
- nv_icmd(priv, 0x000004d4, 0x00000000);
- nv_icmd(priv, 0x000004d5, 0x00000000);
- nv_icmd(priv, 0x000004d6, 0x00000000);
- nv_icmd(priv, 0x000004d7, 0x00000000);
- nv_icmd(priv, 0x000004d8, 0x00000000);
- nv_icmd(priv, 0x000004d9, 0x00000000);
- nv_icmd(priv, 0x000004da, 0x00000000);
- nv_icmd(priv, 0x000004db, 0x00000000);
- nv_icmd(priv, 0x000004dc, 0x00000000);
- nv_icmd(priv, 0x000004dd, 0x00000000);
- nv_icmd(priv, 0x000004de, 0x00000000);
- nv_icmd(priv, 0x000004df, 0x00000000);
- nv_icmd(priv, 0x00000720, 0x00000000);
- nv_icmd(priv, 0x00000721, 0x00000000);
- nv_icmd(priv, 0x00000722, 0x00000000);
- nv_icmd(priv, 0x00000723, 0x00000000);
- nv_icmd(priv, 0x00000724, 0x00000000);
- nv_icmd(priv, 0x00000725, 0x00000000);
- nv_icmd(priv, 0x00000726, 0x00000000);
- nv_icmd(priv, 0x00000727, 0x00000000);
- nv_icmd(priv, 0x00000728, 0x00000000);
- nv_icmd(priv, 0x00000729, 0x00000000);
- nv_icmd(priv, 0x0000072a, 0x00000000);
- nv_icmd(priv, 0x0000072b, 0x00000000);
- nv_icmd(priv, 0x0000072c, 0x00000000);
- nv_icmd(priv, 0x0000072d, 0x00000000);
- nv_icmd(priv, 0x0000072e, 0x00000000);
- nv_icmd(priv, 0x0000072f, 0x00000000);
- nv_icmd(priv, 0x000008c0, 0x00000000);
- nv_icmd(priv, 0x000008c1, 0x00000000);
- nv_icmd(priv, 0x000008c2, 0x00000000);
- nv_icmd(priv, 0x000008c3, 0x00000000);
- nv_icmd(priv, 0x000008c4, 0x00000000);
- nv_icmd(priv, 0x000008c5, 0x00000000);
- nv_icmd(priv, 0x000008c6, 0x00000000);
- nv_icmd(priv, 0x000008c7, 0x00000000);
- nv_icmd(priv, 0x000008c8, 0x00000000);
- nv_icmd(priv, 0x000008c9, 0x00000000);
- nv_icmd(priv, 0x000008ca, 0x00000000);
- nv_icmd(priv, 0x000008cb, 0x00000000);
- nv_icmd(priv, 0x000008cc, 0x00000000);
- nv_icmd(priv, 0x000008cd, 0x00000000);
- nv_icmd(priv, 0x000008ce, 0x00000000);
- nv_icmd(priv, 0x000008cf, 0x00000000);
- nv_icmd(priv, 0x00000890, 0x00000000);
- nv_icmd(priv, 0x00000891, 0x00000000);
- nv_icmd(priv, 0x00000892, 0x00000000);
- nv_icmd(priv, 0x00000893, 0x00000000);
- nv_icmd(priv, 0x00000894, 0x00000000);
- nv_icmd(priv, 0x00000895, 0x00000000);
- nv_icmd(priv, 0x00000896, 0x00000000);
- nv_icmd(priv, 0x00000897, 0x00000000);
- nv_icmd(priv, 0x00000898, 0x00000000);
- nv_icmd(priv, 0x00000899, 0x00000000);
- nv_icmd(priv, 0x0000089a, 0x00000000);
- nv_icmd(priv, 0x0000089b, 0x00000000);
- nv_icmd(priv, 0x0000089c, 0x00000000);
- nv_icmd(priv, 0x0000089d, 0x00000000);
- nv_icmd(priv, 0x0000089e, 0x00000000);
- nv_icmd(priv, 0x0000089f, 0x00000000);
- nv_icmd(priv, 0x000008e0, 0x00000000);
- nv_icmd(priv, 0x000008e1, 0x00000000);
- nv_icmd(priv, 0x000008e2, 0x00000000);
- nv_icmd(priv, 0x000008e3, 0x00000000);
- nv_icmd(priv, 0x000008e4, 0x00000000);
- nv_icmd(priv, 0x000008e5, 0x00000000);
- nv_icmd(priv, 0x000008e6, 0x00000000);
- nv_icmd(priv, 0x000008e7, 0x00000000);
- nv_icmd(priv, 0x000008e8, 0x00000000);
- nv_icmd(priv, 0x000008e9, 0x00000000);
- nv_icmd(priv, 0x000008ea, 0x00000000);
- nv_icmd(priv, 0x000008eb, 0x00000000);
- nv_icmd(priv, 0x000008ec, 0x00000000);
- nv_icmd(priv, 0x000008ed, 0x00000000);
- nv_icmd(priv, 0x000008ee, 0x00000000);
- nv_icmd(priv, 0x000008ef, 0x00000000);
- nv_icmd(priv, 0x000008a0, 0x00000000);
- nv_icmd(priv, 0x000008a1, 0x00000000);
- nv_icmd(priv, 0x000008a2, 0x00000000);
- nv_icmd(priv, 0x000008a3, 0x00000000);
- nv_icmd(priv, 0x000008a4, 0x00000000);
- nv_icmd(priv, 0x000008a5, 0x00000000);
- nv_icmd(priv, 0x000008a6, 0x00000000);
- nv_icmd(priv, 0x000008a7, 0x00000000);
- nv_icmd(priv, 0x000008a8, 0x00000000);
- nv_icmd(priv, 0x000008a9, 0x00000000);
- nv_icmd(priv, 0x000008aa, 0x00000000);
- nv_icmd(priv, 0x000008ab, 0x00000000);
- nv_icmd(priv, 0x000008ac, 0x00000000);
- nv_icmd(priv, 0x000008ad, 0x00000000);
- nv_icmd(priv, 0x000008ae, 0x00000000);
- nv_icmd(priv, 0x000008af, 0x00000000);
- nv_icmd(priv, 0x000008f0, 0x00000000);
- nv_icmd(priv, 0x000008f1, 0x00000000);
- nv_icmd(priv, 0x000008f2, 0x00000000);
- nv_icmd(priv, 0x000008f3, 0x00000000);
- nv_icmd(priv, 0x000008f4, 0x00000000);
- nv_icmd(priv, 0x000008f5, 0x00000000);
- nv_icmd(priv, 0x000008f6, 0x00000000);
- nv_icmd(priv, 0x000008f7, 0x00000000);
- nv_icmd(priv, 0x000008f8, 0x00000000);
- nv_icmd(priv, 0x000008f9, 0x00000000);
- nv_icmd(priv, 0x000008fa, 0x00000000);
- nv_icmd(priv, 0x000008fb, 0x00000000);
- nv_icmd(priv, 0x000008fc, 0x00000000);
- nv_icmd(priv, 0x000008fd, 0x00000000);
- nv_icmd(priv, 0x000008fe, 0x00000000);
- nv_icmd(priv, 0x000008ff, 0x00000000);
- nv_icmd(priv, 0x0000094c, 0x000000ff);
- nv_icmd(priv, 0x0000094d, 0xffffffff);
- nv_icmd(priv, 0x0000094e, 0x00000002);
- nv_icmd(priv, 0x000002ec, 0x00000001);
- nv_icmd(priv, 0x00000303, 0x00000001);
- nv_icmd(priv, 0x000002e6, 0x00000001);
- nv_icmd(priv, 0x00000466, 0x00000052);
- nv_icmd(priv, 0x00000301, 0x3f800000);
- nv_icmd(priv, 0x00000304, 0x30201000);
- nv_icmd(priv, 0x00000305, 0x70605040);
- nv_icmd(priv, 0x00000306, 0xb8a89888);
- nv_icmd(priv, 0x00000307, 0xf8e8d8c8);
- nv_icmd(priv, 0x0000030a, 0x00ffff00);
- nv_icmd(priv, 0x0000030b, 0x0000001a);
- nv_icmd(priv, 0x0000030c, 0x00000001);
- nv_icmd(priv, 0x00000318, 0x00000001);
- nv_icmd(priv, 0x00000340, 0x00000000);
- nv_icmd(priv, 0x00000375, 0x00000001);
- nv_icmd(priv, 0x00000351, 0x00000100);
- nv_icmd(priv, 0x0000037d, 0x00000006);
- nv_icmd(priv, 0x000003a0, 0x00000002);
- nv_icmd(priv, 0x000003aa, 0x00000001);
- nv_icmd(priv, 0x000003a9, 0x00000001);
- nv_icmd(priv, 0x00000380, 0x00000001);
- nv_icmd(priv, 0x00000360, 0x00000040);
- nv_icmd(priv, 0x00000366, 0x00000000);
- nv_icmd(priv, 0x00000367, 0x00000000);
- nv_icmd(priv, 0x00000368, 0x00001fff);
- nv_icmd(priv, 0x00000370, 0x00000000);
- nv_icmd(priv, 0x00000371, 0x00000000);
- nv_icmd(priv, 0x00000372, 0x003fffff);
- nv_icmd(priv, 0x0000037a, 0x00000012);
- nv_icmd(priv, 0x000005e0, 0x00000022);
- nv_icmd(priv, 0x000005e1, 0x00000022);
- nv_icmd(priv, 0x000005e2, 0x00000022);
- nv_icmd(priv, 0x000005e3, 0x00000022);
- nv_icmd(priv, 0x000005e4, 0x00000022);
- nv_icmd(priv, 0x00000619, 0x00000003);
- nv_icmd(priv, 0x00000811, 0x00000003);
- nv_icmd(priv, 0x00000812, 0x00000004);
- nv_icmd(priv, 0x00000813, 0x00000006);
- nv_icmd(priv, 0x00000814, 0x00000008);
- nv_icmd(priv, 0x00000815, 0x0000000b);
- nv_icmd(priv, 0x00000800, 0x00000001);
- nv_icmd(priv, 0x00000801, 0x00000001);
- nv_icmd(priv, 0x00000802, 0x00000001);
- nv_icmd(priv, 0x00000803, 0x00000001);
- nv_icmd(priv, 0x00000804, 0x00000001);
- nv_icmd(priv, 0x00000805, 0x00000001);
- nv_icmd(priv, 0x00000632, 0x00000001);
- nv_icmd(priv, 0x00000633, 0x00000002);
- nv_icmd(priv, 0x00000634, 0x00000003);
- nv_icmd(priv, 0x00000635, 0x00000004);
- nv_icmd(priv, 0x00000654, 0x3f800000);
- nv_icmd(priv, 0x00000657, 0x3f800000);
- nv_icmd(priv, 0x00000655, 0x3f800000);
- nv_icmd(priv, 0x00000656, 0x3f800000);
- nv_icmd(priv, 0x000006cd, 0x3f800000);
- nv_icmd(priv, 0x000007f5, 0x3f800000);
- nv_icmd(priv, 0x000007dc, 0x39291909);
- nv_icmd(priv, 0x000007dd, 0x79695949);
- nv_icmd(priv, 0x000007de, 0xb9a99989);
- nv_icmd(priv, 0x000007df, 0xf9e9d9c9);
- nv_icmd(priv, 0x000007e8, 0x00003210);
- nv_icmd(priv, 0x000007e9, 0x00007654);
- nv_icmd(priv, 0x000007ea, 0x00000098);
- nv_icmd(priv, 0x000007ec, 0x39291909);
- nv_icmd(priv, 0x000007ed, 0x79695949);
- nv_icmd(priv, 0x000007ee, 0xb9a99989);
- nv_icmd(priv, 0x000007ef, 0xf9e9d9c9);
- nv_icmd(priv, 0x000007f0, 0x00003210);
- nv_icmd(priv, 0x000007f1, 0x00007654);
- nv_icmd(priv, 0x000007f2, 0x00000098);
- nv_icmd(priv, 0x000005a5, 0x00000001);
- nv_icmd(priv, 0x00000980, 0x00000000);
- nv_icmd(priv, 0x00000981, 0x00000000);
- nv_icmd(priv, 0x00000982, 0x00000000);
- nv_icmd(priv, 0x00000983, 0x00000000);
- nv_icmd(priv, 0x00000984, 0x00000000);
- nv_icmd(priv, 0x00000985, 0x00000000);
- nv_icmd(priv, 0x00000986, 0x00000000);
- nv_icmd(priv, 0x00000987, 0x00000000);
- nv_icmd(priv, 0x00000988, 0x00000000);
- nv_icmd(priv, 0x00000989, 0x00000000);
- nv_icmd(priv, 0x0000098a, 0x00000000);
- nv_icmd(priv, 0x0000098b, 0x00000000);
- nv_icmd(priv, 0x0000098c, 0x00000000);
- nv_icmd(priv, 0x0000098d, 0x00000000);
- nv_icmd(priv, 0x0000098e, 0x00000000);
- nv_icmd(priv, 0x0000098f, 0x00000000);
- nv_icmd(priv, 0x00000990, 0x00000000);
- nv_icmd(priv, 0x00000991, 0x00000000);
- nv_icmd(priv, 0x00000992, 0x00000000);
- nv_icmd(priv, 0x00000993, 0x00000000);
- nv_icmd(priv, 0x00000994, 0x00000000);
- nv_icmd(priv, 0x00000995, 0x00000000);
- nv_icmd(priv, 0x00000996, 0x00000000);
- nv_icmd(priv, 0x00000997, 0x00000000);
- nv_icmd(priv, 0x00000998, 0x00000000);
- nv_icmd(priv, 0x00000999, 0x00000000);
- nv_icmd(priv, 0x0000099a, 0x00000000);
- nv_icmd(priv, 0x0000099b, 0x00000000);
- nv_icmd(priv, 0x0000099c, 0x00000000);
- nv_icmd(priv, 0x0000099d, 0x00000000);
- nv_icmd(priv, 0x0000099e, 0x00000000);
- nv_icmd(priv, 0x0000099f, 0x00000000);
- nv_icmd(priv, 0x000009a0, 0x00000000);
- nv_icmd(priv, 0x000009a1, 0x00000000);
- nv_icmd(priv, 0x000009a2, 0x00000000);
- nv_icmd(priv, 0x000009a3, 0x00000000);
- nv_icmd(priv, 0x000009a4, 0x00000000);
- nv_icmd(priv, 0x000009a5, 0x00000000);
- nv_icmd(priv, 0x000009a6, 0x00000000);
- nv_icmd(priv, 0x000009a7, 0x00000000);
- nv_icmd(priv, 0x000009a8, 0x00000000);
- nv_icmd(priv, 0x000009a9, 0x00000000);
- nv_icmd(priv, 0x000009aa, 0x00000000);
- nv_icmd(priv, 0x000009ab, 0x00000000);
- nv_icmd(priv, 0x000009ac, 0x00000000);
- nv_icmd(priv, 0x000009ad, 0x00000000);
- nv_icmd(priv, 0x000009ae, 0x00000000);
- nv_icmd(priv, 0x000009af, 0x00000000);
- nv_icmd(priv, 0x000009b0, 0x00000000);
- nv_icmd(priv, 0x000009b1, 0x00000000);
- nv_icmd(priv, 0x000009b2, 0x00000000);
- nv_icmd(priv, 0x000009b3, 0x00000000);
- nv_icmd(priv, 0x000009b4, 0x00000000);
- nv_icmd(priv, 0x000009b5, 0x00000000);
- nv_icmd(priv, 0x000009b6, 0x00000000);
- nv_icmd(priv, 0x000009b7, 0x00000000);
- nv_icmd(priv, 0x000009b8, 0x00000000);
- nv_icmd(priv, 0x000009b9, 0x00000000);
- nv_icmd(priv, 0x000009ba, 0x00000000);
- nv_icmd(priv, 0x000009bb, 0x00000000);
- nv_icmd(priv, 0x000009bc, 0x00000000);
- nv_icmd(priv, 0x000009bd, 0x00000000);
- nv_icmd(priv, 0x000009be, 0x00000000);
- nv_icmd(priv, 0x000009bf, 0x00000000);
- nv_icmd(priv, 0x000009c0, 0x00000000);
- nv_icmd(priv, 0x000009c1, 0x00000000);
- nv_icmd(priv, 0x000009c2, 0x00000000);
- nv_icmd(priv, 0x000009c3, 0x00000000);
- nv_icmd(priv, 0x000009c4, 0x00000000);
- nv_icmd(priv, 0x000009c5, 0x00000000);
- nv_icmd(priv, 0x000009c6, 0x00000000);
- nv_icmd(priv, 0x000009c7, 0x00000000);
- nv_icmd(priv, 0x000009c8, 0x00000000);
- nv_icmd(priv, 0x000009c9, 0x00000000);
- nv_icmd(priv, 0x000009ca, 0x00000000);
- nv_icmd(priv, 0x000009cb, 0x00000000);
- nv_icmd(priv, 0x000009cc, 0x00000000);
- nv_icmd(priv, 0x000009cd, 0x00000000);
- nv_icmd(priv, 0x000009ce, 0x00000000);
- nv_icmd(priv, 0x000009cf, 0x00000000);
- nv_icmd(priv, 0x000009d0, 0x00000000);
- nv_icmd(priv, 0x000009d1, 0x00000000);
- nv_icmd(priv, 0x000009d2, 0x00000000);
- nv_icmd(priv, 0x000009d3, 0x00000000);
- nv_icmd(priv, 0x000009d4, 0x00000000);
- nv_icmd(priv, 0x000009d5, 0x00000000);
- nv_icmd(priv, 0x000009d6, 0x00000000);
- nv_icmd(priv, 0x000009d7, 0x00000000);
- nv_icmd(priv, 0x000009d8, 0x00000000);
- nv_icmd(priv, 0x000009d9, 0x00000000);
- nv_icmd(priv, 0x000009da, 0x00000000);
- nv_icmd(priv, 0x000009db, 0x00000000);
- nv_icmd(priv, 0x000009dc, 0x00000000);
- nv_icmd(priv, 0x000009dd, 0x00000000);
- nv_icmd(priv, 0x000009de, 0x00000000);
- nv_icmd(priv, 0x000009df, 0x00000000);
- nv_icmd(priv, 0x000009e0, 0x00000000);
- nv_icmd(priv, 0x000009e1, 0x00000000);
- nv_icmd(priv, 0x000009e2, 0x00000000);
- nv_icmd(priv, 0x000009e3, 0x00000000);
- nv_icmd(priv, 0x000009e4, 0x00000000);
- nv_icmd(priv, 0x000009e5, 0x00000000);
- nv_icmd(priv, 0x000009e6, 0x00000000);
- nv_icmd(priv, 0x000009e7, 0x00000000);
- nv_icmd(priv, 0x000009e8, 0x00000000);
- nv_icmd(priv, 0x000009e9, 0x00000000);
- nv_icmd(priv, 0x000009ea, 0x00000000);
- nv_icmd(priv, 0x000009eb, 0x00000000);
- nv_icmd(priv, 0x000009ec, 0x00000000);
- nv_icmd(priv, 0x000009ed, 0x00000000);
- nv_icmd(priv, 0x000009ee, 0x00000000);
- nv_icmd(priv, 0x000009ef, 0x00000000);
- nv_icmd(priv, 0x000009f0, 0x00000000);
- nv_icmd(priv, 0x000009f1, 0x00000000);
- nv_icmd(priv, 0x000009f2, 0x00000000);
- nv_icmd(priv, 0x000009f3, 0x00000000);
- nv_icmd(priv, 0x000009f4, 0x00000000);
- nv_icmd(priv, 0x000009f5, 0x00000000);
- nv_icmd(priv, 0x000009f6, 0x00000000);
- nv_icmd(priv, 0x000009f7, 0x00000000);
- nv_icmd(priv, 0x000009f8, 0x00000000);
- nv_icmd(priv, 0x000009f9, 0x00000000);
- nv_icmd(priv, 0x000009fa, 0x00000000);
- nv_icmd(priv, 0x000009fb, 0x00000000);
- nv_icmd(priv, 0x000009fc, 0x00000000);
- nv_icmd(priv, 0x000009fd, 0x00000000);
- nv_icmd(priv, 0x000009fe, 0x00000000);
- nv_icmd(priv, 0x000009ff, 0x00000000);
- nv_icmd(priv, 0x00000468, 0x00000004);
- nv_icmd(priv, 0x0000046c, 0x00000001);
- nv_icmd(priv, 0x00000470, 0x00000000);
- nv_icmd(priv, 0x00000471, 0x00000000);
- nv_icmd(priv, 0x00000472, 0x00000000);
- nv_icmd(priv, 0x00000473, 0x00000000);
- nv_icmd(priv, 0x00000474, 0x00000000);
- nv_icmd(priv, 0x00000475, 0x00000000);
- nv_icmd(priv, 0x00000476, 0x00000000);
- nv_icmd(priv, 0x00000477, 0x00000000);
- nv_icmd(priv, 0x00000478, 0x00000000);
- nv_icmd(priv, 0x00000479, 0x00000000);
- nv_icmd(priv, 0x0000047a, 0x00000000);
- nv_icmd(priv, 0x0000047b, 0x00000000);
- nv_icmd(priv, 0x0000047c, 0x00000000);
- nv_icmd(priv, 0x0000047d, 0x00000000);
- nv_icmd(priv, 0x0000047e, 0x00000000);
- nv_icmd(priv, 0x0000047f, 0x00000000);
- nv_icmd(priv, 0x00000480, 0x00000000);
- nv_icmd(priv, 0x00000481, 0x00000000);
- nv_icmd(priv, 0x00000482, 0x00000000);
- nv_icmd(priv, 0x00000483, 0x00000000);
- nv_icmd(priv, 0x00000484, 0x00000000);
- nv_icmd(priv, 0x00000485, 0x00000000);
- nv_icmd(priv, 0x00000486, 0x00000000);
- nv_icmd(priv, 0x00000487, 0x00000000);
- nv_icmd(priv, 0x00000488, 0x00000000);
- nv_icmd(priv, 0x00000489, 0x00000000);
- nv_icmd(priv, 0x0000048a, 0x00000000);
- nv_icmd(priv, 0x0000048b, 0x00000000);
- nv_icmd(priv, 0x0000048c, 0x00000000);
- nv_icmd(priv, 0x0000048d, 0x00000000);
- nv_icmd(priv, 0x0000048e, 0x00000000);
- nv_icmd(priv, 0x0000048f, 0x00000000);
- nv_icmd(priv, 0x00000490, 0x00000000);
- nv_icmd(priv, 0x00000491, 0x00000000);
- nv_icmd(priv, 0x00000492, 0x00000000);
- nv_icmd(priv, 0x00000493, 0x00000000);
- nv_icmd(priv, 0x00000494, 0x00000000);
- nv_icmd(priv, 0x00000495, 0x00000000);
- nv_icmd(priv, 0x00000496, 0x00000000);
- nv_icmd(priv, 0x00000497, 0x00000000);
- nv_icmd(priv, 0x00000498, 0x00000000);
- nv_icmd(priv, 0x00000499, 0x00000000);
- nv_icmd(priv, 0x0000049a, 0x00000000);
- nv_icmd(priv, 0x0000049b, 0x00000000);
- nv_icmd(priv, 0x0000049c, 0x00000000);
- nv_icmd(priv, 0x0000049d, 0x00000000);
- nv_icmd(priv, 0x0000049e, 0x00000000);
- nv_icmd(priv, 0x0000049f, 0x00000000);
- nv_icmd(priv, 0x000004a0, 0x00000000);
- nv_icmd(priv, 0x000004a1, 0x00000000);
- nv_icmd(priv, 0x000004a2, 0x00000000);
- nv_icmd(priv, 0x000004a3, 0x00000000);
- nv_icmd(priv, 0x000004a4, 0x00000000);
- nv_icmd(priv, 0x000004a5, 0x00000000);
- nv_icmd(priv, 0x000004a6, 0x00000000);
- nv_icmd(priv, 0x000004a7, 0x00000000);
- nv_icmd(priv, 0x000004a8, 0x00000000);
- nv_icmd(priv, 0x000004a9, 0x00000000);
- nv_icmd(priv, 0x000004aa, 0x00000000);
- nv_icmd(priv, 0x000004ab, 0x00000000);
- nv_icmd(priv, 0x000004ac, 0x00000000);
- nv_icmd(priv, 0x000004ad, 0x00000000);
- nv_icmd(priv, 0x000004ae, 0x00000000);
- nv_icmd(priv, 0x000004af, 0x00000000);
- nv_icmd(priv, 0x000004b0, 0x00000000);
- nv_icmd(priv, 0x000004b1, 0x00000000);
- nv_icmd(priv, 0x000004b2, 0x00000000);
- nv_icmd(priv, 0x000004b3, 0x00000000);
- nv_icmd(priv, 0x000004b4, 0x00000000);
- nv_icmd(priv, 0x000004b5, 0x00000000);
- nv_icmd(priv, 0x000004b6, 0x00000000);
- nv_icmd(priv, 0x000004b7, 0x00000000);
- nv_icmd(priv, 0x000004b8, 0x00000000);
- nv_icmd(priv, 0x000004b9, 0x00000000);
- nv_icmd(priv, 0x000004ba, 0x00000000);
- nv_icmd(priv, 0x000004bb, 0x00000000);
- nv_icmd(priv, 0x000004bc, 0x00000000);
- nv_icmd(priv, 0x000004bd, 0x00000000);
- nv_icmd(priv, 0x000004be, 0x00000000);
- nv_icmd(priv, 0x000004bf, 0x00000000);
- nv_icmd(priv, 0x000004c0, 0x00000000);
- nv_icmd(priv, 0x000004c1, 0x00000000);
- nv_icmd(priv, 0x000004c2, 0x00000000);
- nv_icmd(priv, 0x000004c3, 0x00000000);
- nv_icmd(priv, 0x000004c4, 0x00000000);
- nv_icmd(priv, 0x000004c5, 0x00000000);
- nv_icmd(priv, 0x000004c6, 0x00000000);
- nv_icmd(priv, 0x000004c7, 0x00000000);
- nv_icmd(priv, 0x000004c8, 0x00000000);
- nv_icmd(priv, 0x000004c9, 0x00000000);
- nv_icmd(priv, 0x000004ca, 0x00000000);
- nv_icmd(priv, 0x000004cb, 0x00000000);
- nv_icmd(priv, 0x000004cc, 0x00000000);
- nv_icmd(priv, 0x000004cd, 0x00000000);
- nv_icmd(priv, 0x000004ce, 0x00000000);
- nv_icmd(priv, 0x000004cf, 0x00000000);
- nv_icmd(priv, 0x00000510, 0x3f800000);
- nv_icmd(priv, 0x00000511, 0x3f800000);
- nv_icmd(priv, 0x00000512, 0x3f800000);
- nv_icmd(priv, 0x00000513, 0x3f800000);
- nv_icmd(priv, 0x00000514, 0x3f800000);
- nv_icmd(priv, 0x00000515, 0x3f800000);
- nv_icmd(priv, 0x00000516, 0x3f800000);
- nv_icmd(priv, 0x00000517, 0x3f800000);
- nv_icmd(priv, 0x00000518, 0x3f800000);
- nv_icmd(priv, 0x00000519, 0x3f800000);
- nv_icmd(priv, 0x0000051a, 0x3f800000);
- nv_icmd(priv, 0x0000051b, 0x3f800000);
- nv_icmd(priv, 0x0000051c, 0x3f800000);
- nv_icmd(priv, 0x0000051d, 0x3f800000);
- nv_icmd(priv, 0x0000051e, 0x3f800000);
- nv_icmd(priv, 0x0000051f, 0x3f800000);
- nv_icmd(priv, 0x00000520, 0x000002b6);
- nv_icmd(priv, 0x00000529, 0x00000001);
- nv_icmd(priv, 0x00000530, 0xffff0000);
- nv_icmd(priv, 0x00000531, 0xffff0000);
- nv_icmd(priv, 0x00000532, 0xffff0000);
- nv_icmd(priv, 0x00000533, 0xffff0000);
- nv_icmd(priv, 0x00000534, 0xffff0000);
- nv_icmd(priv, 0x00000535, 0xffff0000);
- nv_icmd(priv, 0x00000536, 0xffff0000);
- nv_icmd(priv, 0x00000537, 0xffff0000);
- nv_icmd(priv, 0x00000538, 0xffff0000);
- nv_icmd(priv, 0x00000539, 0xffff0000);
- nv_icmd(priv, 0x0000053a, 0xffff0000);
- nv_icmd(priv, 0x0000053b, 0xffff0000);
- nv_icmd(priv, 0x0000053c, 0xffff0000);
- nv_icmd(priv, 0x0000053d, 0xffff0000);
- nv_icmd(priv, 0x0000053e, 0xffff0000);
- nv_icmd(priv, 0x0000053f, 0xffff0000);
- nv_icmd(priv, 0x00000585, 0x0000003f);
- nv_icmd(priv, 0x00000576, 0x00000003);
- if (nv_device(priv)->chipset == 0xc1 ||
- nv_device(priv)->chipset >= 0xd0)
- nv_icmd(priv, 0x0000057b, 0x00000059);
- nv_icmd(priv, 0x00000586, 0x00000040);
- nv_icmd(priv, 0x00000582, 0x00000080);
- nv_icmd(priv, 0x00000583, 0x00000080);
- nv_icmd(priv, 0x000005c2, 0x00000001);
- nv_icmd(priv, 0x00000638, 0x00000001);
- nv_icmd(priv, 0x00000639, 0x00000001);
- nv_icmd(priv, 0x0000063a, 0x00000002);
- nv_icmd(priv, 0x0000063b, 0x00000001);
- nv_icmd(priv, 0x0000063c, 0x00000001);
- nv_icmd(priv, 0x0000063d, 0x00000002);
- nv_icmd(priv, 0x0000063e, 0x00000001);
- nv_icmd(priv, 0x000008b8, 0x00000001);
- nv_icmd(priv, 0x000008b9, 0x00000001);
- nv_icmd(priv, 0x000008ba, 0x00000001);
- nv_icmd(priv, 0x000008bb, 0x00000001);
- nv_icmd(priv, 0x000008bc, 0x00000001);
- nv_icmd(priv, 0x000008bd, 0x00000001);
- nv_icmd(priv, 0x000008be, 0x00000001);
- nv_icmd(priv, 0x000008bf, 0x00000001);
- nv_icmd(priv, 0x00000900, 0x00000001);
- nv_icmd(priv, 0x00000901, 0x00000001);
- nv_icmd(priv, 0x00000902, 0x00000001);
- nv_icmd(priv, 0x00000903, 0x00000001);
- nv_icmd(priv, 0x00000904, 0x00000001);
- nv_icmd(priv, 0x00000905, 0x00000001);
- nv_icmd(priv, 0x00000906, 0x00000001);
- nv_icmd(priv, 0x00000907, 0x00000001);
- nv_icmd(priv, 0x00000908, 0x00000002);
- nv_icmd(priv, 0x00000909, 0x00000002);
- nv_icmd(priv, 0x0000090a, 0x00000002);
- nv_icmd(priv, 0x0000090b, 0x00000002);
- nv_icmd(priv, 0x0000090c, 0x00000002);
- nv_icmd(priv, 0x0000090d, 0x00000002);
- nv_icmd(priv, 0x0000090e, 0x00000002);
- nv_icmd(priv, 0x0000090f, 0x00000002);
- nv_icmd(priv, 0x00000910, 0x00000001);
- nv_icmd(priv, 0x00000911, 0x00000001);
- nv_icmd(priv, 0x00000912, 0x00000001);
- nv_icmd(priv, 0x00000913, 0x00000001);
- nv_icmd(priv, 0x00000914, 0x00000001);
- nv_icmd(priv, 0x00000915, 0x00000001);
- nv_icmd(priv, 0x00000916, 0x00000001);
- nv_icmd(priv, 0x00000917, 0x00000001);
- nv_icmd(priv, 0x00000918, 0x00000001);
- nv_icmd(priv, 0x00000919, 0x00000001);
- nv_icmd(priv, 0x0000091a, 0x00000001);
- nv_icmd(priv, 0x0000091b, 0x00000001);
- nv_icmd(priv, 0x0000091c, 0x00000001);
- nv_icmd(priv, 0x0000091d, 0x00000001);
- nv_icmd(priv, 0x0000091e, 0x00000001);
- nv_icmd(priv, 0x0000091f, 0x00000001);
- nv_icmd(priv, 0x00000920, 0x00000002);
- nv_icmd(priv, 0x00000921, 0x00000002);
- nv_icmd(priv, 0x00000922, 0x00000002);
- nv_icmd(priv, 0x00000923, 0x00000002);
- nv_icmd(priv, 0x00000924, 0x00000002);
- nv_icmd(priv, 0x00000925, 0x00000002);
- nv_icmd(priv, 0x00000926, 0x00000002);
- nv_icmd(priv, 0x00000927, 0x00000002);
- nv_icmd(priv, 0x00000928, 0x00000001);
- nv_icmd(priv, 0x00000929, 0x00000001);
- nv_icmd(priv, 0x0000092a, 0x00000001);
- nv_icmd(priv, 0x0000092b, 0x00000001);
- nv_icmd(priv, 0x0000092c, 0x00000001);
- nv_icmd(priv, 0x0000092d, 0x00000001);
- nv_icmd(priv, 0x0000092e, 0x00000001);
- nv_icmd(priv, 0x0000092f, 0x00000001);
- nv_icmd(priv, 0x00000648, 0x00000001);
- nv_icmd(priv, 0x00000649, 0x00000001);
- nv_icmd(priv, 0x0000064a, 0x00000001);
- nv_icmd(priv, 0x0000064b, 0x00000001);
- nv_icmd(priv, 0x0000064c, 0x00000001);
- nv_icmd(priv, 0x0000064d, 0x00000001);
- nv_icmd(priv, 0x0000064e, 0x00000001);
- nv_icmd(priv, 0x0000064f, 0x00000001);
- nv_icmd(priv, 0x00000650, 0x00000001);
- nv_icmd(priv, 0x00000658, 0x0000000f);
- nv_icmd(priv, 0x000007ff, 0x0000000a);
- nv_icmd(priv, 0x0000066a, 0x40000000);
- nv_icmd(priv, 0x0000066b, 0x10000000);
- nv_icmd(priv, 0x0000066c, 0xffff0000);
- nv_icmd(priv, 0x0000066d, 0xffff0000);
- nv_icmd(priv, 0x000007af, 0x00000008);
- nv_icmd(priv, 0x000007b0, 0x00000008);
- nv_icmd(priv, 0x000007f6, 0x00000001);
- nv_icmd(priv, 0x000006b2, 0x00000055);
- nv_icmd(priv, 0x000007ad, 0x00000003);
- nv_icmd(priv, 0x00000937, 0x00000001);
- nv_icmd(priv, 0x00000971, 0x00000008);
- nv_icmd(priv, 0x00000972, 0x00000040);
- nv_icmd(priv, 0x00000973, 0x0000012c);
- nv_icmd(priv, 0x0000097c, 0x00000040);
- nv_icmd(priv, 0x00000979, 0x00000003);
- nv_icmd(priv, 0x00000975, 0x00000020);
- nv_icmd(priv, 0x00000976, 0x00000001);
- nv_icmd(priv, 0x00000977, 0x00000020);
- nv_icmd(priv, 0x00000978, 0x00000001);
- nv_icmd(priv, 0x00000957, 0x00000003);
- nv_icmd(priv, 0x0000095e, 0x20164010);
- nv_icmd(priv, 0x0000095f, 0x00000020);
- if (nv_device(priv)->chipset >= 0xd0)
- nv_icmd(priv, 0x0000097d, 0x00000020);
- nv_icmd(priv, 0x00000683, 0x00000006);
- nv_icmd(priv, 0x00000685, 0x003fffff);
- nv_icmd(priv, 0x00000687, 0x00000c48);
- nv_icmd(priv, 0x000006a0, 0x00000005);
- nv_icmd(priv, 0x00000840, 0x00300008);
- nv_icmd(priv, 0x00000841, 0x04000080);
- nv_icmd(priv, 0x00000842, 0x00300008);
- nv_icmd(priv, 0x00000843, 0x04000080);
- nv_icmd(priv, 0x00000818, 0x00000000);
- nv_icmd(priv, 0x00000819, 0x00000000);
- nv_icmd(priv, 0x0000081a, 0x00000000);
- nv_icmd(priv, 0x0000081b, 0x00000000);
- nv_icmd(priv, 0x0000081c, 0x00000000);
- nv_icmd(priv, 0x0000081d, 0x00000000);
- nv_icmd(priv, 0x0000081e, 0x00000000);
- nv_icmd(priv, 0x0000081f, 0x00000000);
- nv_icmd(priv, 0x00000848, 0x00000000);
- nv_icmd(priv, 0x00000849, 0x00000000);
- nv_icmd(priv, 0x0000084a, 0x00000000);
- nv_icmd(priv, 0x0000084b, 0x00000000);
- nv_icmd(priv, 0x0000084c, 0x00000000);
- nv_icmd(priv, 0x0000084d, 0x00000000);
- nv_icmd(priv, 0x0000084e, 0x00000000);
- nv_icmd(priv, 0x0000084f, 0x00000000);
- nv_icmd(priv, 0x00000850, 0x00000000);
- nv_icmd(priv, 0x00000851, 0x00000000);
- nv_icmd(priv, 0x00000852, 0x00000000);
- nv_icmd(priv, 0x00000853, 0x00000000);
- nv_icmd(priv, 0x00000854, 0x00000000);
- nv_icmd(priv, 0x00000855, 0x00000000);
- nv_icmd(priv, 0x00000856, 0x00000000);
- nv_icmd(priv, 0x00000857, 0x00000000);
- nv_icmd(priv, 0x00000738, 0x00000000);
- nv_icmd(priv, 0x000006aa, 0x00000001);
- nv_icmd(priv, 0x000006ab, 0x00000002);
- nv_icmd(priv, 0x000006ac, 0x00000080);
- nv_icmd(priv, 0x000006ad, 0x00000100);
- nv_icmd(priv, 0x000006ae, 0x00000100);
- nv_icmd(priv, 0x000006b1, 0x00000011);
- nv_icmd(priv, 0x000006bb, 0x000000cf);
- nv_icmd(priv, 0x000006ce, 0x2a712488);
- nv_icmd(priv, 0x00000739, 0x4085c000);
- nv_icmd(priv, 0x0000073a, 0x00000080);
- nv_icmd(priv, 0x00000786, 0x80000100);
- nv_icmd(priv, 0x0000073c, 0x00010100);
- nv_icmd(priv, 0x0000073d, 0x02800000);
- nv_icmd(priv, 0x00000787, 0x000000cf);
- nv_icmd(priv, 0x0000078c, 0x00000008);
- nv_icmd(priv, 0x00000792, 0x00000001);
- nv_icmd(priv, 0x00000794, 0x00000001);
- nv_icmd(priv, 0x00000795, 0x00000001);
- nv_icmd(priv, 0x00000796, 0x00000001);
- nv_icmd(priv, 0x00000797, 0x000000cf);
- nv_icmd(priv, 0x00000836, 0x00000001);
- nv_icmd(priv, 0x0000079a, 0x00000002);
- nv_icmd(priv, 0x00000833, 0x04444480);
- nv_icmd(priv, 0x000007a1, 0x00000001);
- nv_icmd(priv, 0x000007a3, 0x00000001);
- nv_icmd(priv, 0x000007a4, 0x00000001);
- nv_icmd(priv, 0x000007a5, 0x00000001);
- nv_icmd(priv, 0x00000831, 0x00000004);
- nv_icmd(priv, 0x0000080c, 0x00000002);
- nv_icmd(priv, 0x0000080d, 0x00000100);
- nv_icmd(priv, 0x0000080e, 0x00000100);
- nv_icmd(priv, 0x0000080f, 0x00000001);
- nv_icmd(priv, 0x00000823, 0x00000002);
- nv_icmd(priv, 0x00000824, 0x00000100);
- nv_icmd(priv, 0x00000825, 0x00000100);
- nv_icmd(priv, 0x00000826, 0x00000001);
- nv_icmd(priv, 0x0000095d, 0x00000001);
- nv_icmd(priv, 0x0000082b, 0x00000004);
- nv_icmd(priv, 0x00000942, 0x00010001);
- nv_icmd(priv, 0x00000943, 0x00000001);
- nv_icmd(priv, 0x00000944, 0x00000022);
- nv_icmd(priv, 0x000007c5, 0x00010001);
- nv_icmd(priv, 0x00000834, 0x00000001);
- nv_icmd(priv, 0x000007c7, 0x00000001);
- nv_icmd(priv, 0x0000c1b0, 0x0000000f);
- nv_icmd(priv, 0x0000c1b1, 0x0000000f);
- nv_icmd(priv, 0x0000c1b2, 0x0000000f);
- nv_icmd(priv, 0x0000c1b3, 0x0000000f);
- nv_icmd(priv, 0x0000c1b4, 0x0000000f);
- nv_icmd(priv, 0x0000c1b5, 0x0000000f);
- nv_icmd(priv, 0x0000c1b6, 0x0000000f);
- nv_icmd(priv, 0x0000c1b7, 0x0000000f);
- nv_icmd(priv, 0x0000c1b8, 0x0fac6881);
- nv_icmd(priv, 0x0000c1b9, 0x00fac688);
- nv_icmd(priv, 0x0001e100, 0x00000001);
- nv_icmd(priv, 0x00001000, 0x00000002);
- nv_icmd(priv, 0x000006aa, 0x00000001);
- nv_icmd(priv, 0x000006ad, 0x00000100);
- nv_icmd(priv, 0x000006ae, 0x00000100);
- nv_icmd(priv, 0x000006b1, 0x00000011);
- nv_icmd(priv, 0x0000078c, 0x00000008);
- nv_icmd(priv, 0x00000792, 0x00000001);
- nv_icmd(priv, 0x00000794, 0x00000001);
- nv_icmd(priv, 0x00000795, 0x00000001);
- nv_icmd(priv, 0x00000796, 0x00000001);
- nv_icmd(priv, 0x00000797, 0x000000cf);
- nv_icmd(priv, 0x0000079a, 0x00000002);
- nv_icmd(priv, 0x00000833, 0x04444480);
- nv_icmd(priv, 0x000007a1, 0x00000001);
- nv_icmd(priv, 0x000007a3, 0x00000001);
- nv_icmd(priv, 0x000007a4, 0x00000001);
- nv_icmd(priv, 0x000007a5, 0x00000001);
- nv_icmd(priv, 0x00000831, 0x00000004);
- nv_icmd(priv, 0x0001e100, 0x00000001);
- nv_icmd(priv, 0x00001000, 0x00000014);
- nv_icmd(priv, 0x00000351, 0x00000100);
- nv_icmd(priv, 0x00000957, 0x00000003);
- nv_icmd(priv, 0x0000095d, 0x00000001);
- nv_icmd(priv, 0x0000082b, 0x00000004);
- nv_icmd(priv, 0x00000942, 0x00010001);
- nv_icmd(priv, 0x00000943, 0x00000001);
- nv_icmd(priv, 0x000007c5, 0x00010001);
- nv_icmd(priv, 0x00000834, 0x00000001);
- nv_icmd(priv, 0x000007c7, 0x00000001);
- nv_icmd(priv, 0x0001e100, 0x00000001);
- nv_icmd(priv, 0x00001000, 0x00000001);
- nv_icmd(priv, 0x0000080c, 0x00000002);
- nv_icmd(priv, 0x0000080d, 0x00000100);
- nv_icmd(priv, 0x0000080e, 0x00000100);
- nv_icmd(priv, 0x0000080f, 0x00000001);
- nv_icmd(priv, 0x00000823, 0x00000002);
- nv_icmd(priv, 0x00000824, 0x00000100);
- nv_icmd(priv, 0x00000825, 0x00000100);
- nv_icmd(priv, 0x00000826, 0x00000001);
- nv_icmd(priv, 0x0001e100, 0x00000001);
- nv_wr32(priv, 0x400208, 0x00000000);
- nv_wr32(priv, 0x404154, 0x00000400);
-
- nvc0_grctx_generate_9097(priv);
- if (fermi >= 0x9197)
- nvc0_grctx_generate_9197(priv);
- if (fermi >= 0x9297)
- nvc0_grctx_generate_9297(priv);
- nvc0_grctx_generate_902d(priv);
- nvc0_grctx_generate_9039(priv);
- nvc0_grctx_generate_90c0(priv);
- nv_wr32(priv, 0x000260, r000260);
-
- return nvc0_grctx_fini(&info);
+done:
+ nouveau_gpuobj_ref(NULL, &chan);
+ return ret;
}
+
+struct nvc0_graph_init *
+nvc0_grctx_init_hub[] = {
+ nvc0_grctx_init_base,
+ nvc0_grctx_init_unk40xx,
+ nvc0_grctx_init_unk44xx,
+ nvc0_grctx_init_unk46xx,
+ nvc0_grctx_init_unk47xx,
+ nvc0_grctx_init_unk58xx,
+ nvc0_grctx_init_unk60xx,
+ nvc0_grctx_init_unk64xx,
+ nvc0_grctx_init_unk78xx,
+ nvc0_grctx_init_unk80xx,
+ nvc0_grctx_init_rop,
+ NULL
+};
+
+static struct nvc0_graph_init *
+nvc0_grctx_init_gpc[] = {
+ nvc0_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvc0_grctx_init_tpc,
+ NULL
+};
+
+struct nvc0_graph_init
+nvc0_grctx_init_mthd_magic[] = {
+ { 0x3410, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_mthd
+nvc0_grctx_init_mthd[] = {
+ { 0x9097, nvc0_grctx_init_9097, },
+ { 0x902d, nvc0_grctx_init_902d, },
+ { 0x9039, nvc0_grctx_init_9039, },
+ { 0x90c0, nvc0_grctx_init_90c0, },
+ { 0x902d, nvc0_grctx_init_mthd_magic, },
+ {}
+};
+
+struct nouveau_oclass *
+nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc0),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nvc0_grctx_generate_main,
+ .mods = nvc0_grctx_generate_mods,
+ .unkn = nvc0_grctx_generate_unkn,
+ .hub = nvc0_grctx_init_hub,
+ .gpc = nvc0_grctx_init_gpc,
+ .icmd = nvc0_grctx_init_icmd,
+ .mthd = nvc0_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
new file mode 100644
index 000000000000..e5be3ee7f172
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
@@ -0,0 +1,823 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvc1_grctx_init_icmd[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 1, 0x01, 0x00000001 },
+ { 0x000639, 1, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc1_grctx_init_9097[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x002700, 8, 0x20, 0x00000000 },
+ { 0x002704, 8, 0x20, 0x00000000 },
+ { 0x002708, 8, 0x20, 0x00000000 },
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x002710, 8, 0x20, 0x00014000 },
+ { 0x002714, 8, 0x20, 0x00000040 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002200, 5, 0x10, 0x00000022 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00001fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x003fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 1, 0x04, 0x00000000 },
+ { 0x001320, 3, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 1, 0x04, 0x003fffff },
+ { 0x0002d0, 1, 0x04, 0x00000c48 },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00300008 },
+ { 0x001284, 1, 0x04, 0x04000080 },
+ { 0x001450, 1, 0x04, 0x00300008 },
+ { 0x001454, 1, 0x04, 0x04000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_9197[] = {
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_unk58xx[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180218 },
+ { 0x405834, 2, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_rop[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1003e005 },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c80929 },
+ { 0x408980, 1, 0x04, 0x0000011d },
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_gpc_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x00200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 1, 0x04, 0x00000000 },
+ { 0x41870c, 1, 0x04, 0x07c80000 },
+ { 0x418710, 1, 0x04, 0x00000000 },
+ { 0x418800, 1, 0x04, 0x0006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x00100018 },
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ { 0x418a00, 3, 0x04, 0x00000000 },
+ { 0x418a0c, 1, 0x04, 0x00010000 },
+ { 0x418a10, 3, 0x04, 0x00000000 },
+ { 0x418a20, 3, 0x04, 0x00000000 },
+ { 0x418a2c, 1, 0x04, 0x00010000 },
+ { 0x418a30, 3, 0x04, 0x00000000 },
+ { 0x418a40, 3, 0x04, 0x00000000 },
+ { 0x418a4c, 1, 0x04, 0x00010000 },
+ { 0x418a50, 3, 0x04, 0x00000000 },
+ { 0x418a60, 3, 0x04, 0x00000000 },
+ { 0x418a6c, 1, 0x04, 0x00010000 },
+ { 0x418a70, 3, 0x04, 0x00000000 },
+ { 0x418a80, 3, 0x04, 0x00000000 },
+ { 0x418a8c, 1, 0x04, 0x00010000 },
+ { 0x418a90, 3, 0x04, 0x00000000 },
+ { 0x418aa0, 3, 0x04, 0x00000000 },
+ { 0x418aac, 1, 0x04, 0x00010000 },
+ { 0x418ab0, 3, 0x04, 0x00000000 },
+ { 0x418ac0, 3, 0x04, 0x00000000 },
+ { 0x418acc, 1, 0x04, 0x00010000 },
+ { 0x418ad0, 3, 0x04, 0x00000000 },
+ { 0x418ae0, 3, 0x04, 0x00000000 },
+ { 0x418aec, 1, 0x04, 0x00010000 },
+ { 0x418af0, 3, 0x04, 0x00000000 },
+ { 0x418b00, 1, 0x04, 0x00000000 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+};
+
+static struct nvc0_graph_init
+nvc1_grctx_init_tpc[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00000000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0007f440 },
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00400001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ { 0x419c00, 1, 0x04, 0x00000002 },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x00020048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ { 0x419d20, 1, 0x04, 0x12180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ { 0x419d44, 1, 0x04, 0x02180218 },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00011110 },
+ { 0x419f30, 11, 0x04, 0x00000000 },
+};
+
+void
+nvc1_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+ int gpc, tpc;
+ u32 offset;
+
+ mmio_data(0x002000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+ mmio_list(0x408004, 0x00000000, 8, 0);
+ mmio_list(0x408008, 0x80000018, 0, 0);
+ mmio_list(0x40800c, 0x00000000, 8, 1);
+ mmio_list(0x408010, 0x80000000, 0, 0);
+ mmio_list(0x418810, 0x80000000, 12, 2);
+ mmio_list(0x419848, 0x10000000, 12, 2);
+ mmio_list(0x419004, 0x00000000, 8, 1);
+ mmio_list(0x419008, 0x00000000, 0, 0);
+ mmio_list(0x418808, 0x00000000, 8, 0);
+ mmio_list(0x41880c, 0x80000018, 0, 0);
+
+ mmio_list(0x405830, 0x02180218, 0, 0);
+ mmio_list(0x4064c4, 0x0086ffff, 0, 0);
+
+ for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ u32 addr = TPC_UNIT(gpc, tpc, 0x0520);
+ mmio_list(addr, 0x12180000 | offset, 0, 0);
+ offset += 0x0324;
+ }
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ u32 addr = TPC_UNIT(gpc, tpc, 0x0544);
+ mmio_list(addr, 0x02180000 | offset, 0, 0);
+ offset += 0x0324;
+ }
+ }
+}
+
+void
+nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv)
+{
+ nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+ nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+ nv_mask(priv, 0x419814, 0x00000004, 0x00000004);
+ nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+ nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+ nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+static struct nvc0_graph_init *
+nvc1_grctx_init_hub[] = {
+ nvc0_grctx_init_base,
+ nvc0_grctx_init_unk40xx,
+ nvc0_grctx_init_unk44xx,
+ nvc0_grctx_init_unk46xx,
+ nvc0_grctx_init_unk47xx,
+ nvc1_grctx_init_unk58xx,
+ nvc0_grctx_init_unk60xx,
+ nvc0_grctx_init_unk64xx,
+ nvc0_grctx_init_unk78xx,
+ nvc0_grctx_init_unk80xx,
+ nvc1_grctx_init_rop,
+ NULL
+};
+
+struct nvc0_graph_init *
+nvc1_grctx_init_gpc[] = {
+ nvc1_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvc1_grctx_init_tpc,
+ NULL
+};
+
+static struct nvc0_graph_mthd
+nvc1_grctx_init_mthd[] = {
+ { 0x9097, nvc1_grctx_init_9097, },
+ { 0x9197, nvc1_grctx_init_9197, },
+ { 0x902d, nvc0_grctx_init_902d, },
+ { 0x9039, nvc0_grctx_init_9039, },
+ { 0x90c0, nvc0_grctx_init_90c0, },
+ { 0x902d, nvc0_grctx_init_mthd_magic, },
+ {}
+};
+
+struct nouveau_oclass *
+nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc1),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nvc0_grctx_generate_main,
+ .mods = nvc1_grctx_generate_mods,
+ .unkn = nvc1_grctx_generate_unkn,
+ .hub = nvc1_grctx_init_hub,
+ .gpc = nvc1_grctx_init_gpc,
+ .icmd = nvc1_grctx_init_icmd,
+ .mthd = nvc1_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c
new file mode 100644
index 000000000000..8f237b3bd8c6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvc3_grctx_init_tpc[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x0000012a },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00000000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0007f440 },
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00000001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ { 0x419c00, 1, 0x04, 0x00000002 },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x00020048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ { 0x419d20, 1, 0x04, 0x02180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00011110 },
+ { 0x419f30, 11, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init *
+nvc3_grctx_init_gpc[] = {
+ nvc0_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvc3_grctx_init_tpc,
+ NULL
+};
+
+struct nouveau_oclass *
+nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc3),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nvc0_grctx_generate_main,
+ .mods = nvc0_grctx_generate_mods,
+ .unkn = nvc0_grctx_generate_unkn,
+ .hub = nvc0_grctx_init_hub,
+ .gpc = nvc3_grctx_init_gpc,
+ .icmd = nvc0_grctx_init_icmd,
+ .mthd = nvc0_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
new file mode 100644
index 000000000000..d0d4ce3c4892
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvc8_grctx_init_icmd[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 1, 0x01, 0x00000001 },
+ { 0x000639, 1, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc8_grctx_init_tpc[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x0000012a },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00000000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00000001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ { 0x419c00, 1, 0x04, 0x00000002 },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x00060048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ { 0x419d20, 1, 0x04, 0x02180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419f50, 2, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc8_grctx_init_9197[] = {
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc8_grctx_init_9297[] = {
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00036c, 2, 0x04, 0x00000000 },
+ { 0x0007a4, 2, 0x04, 0x00000000 },
+ { 0x000374, 1, 0x04, 0x00000000 },
+ { 0x000378, 1, 0x04, 0x00000020 },
+ {}
+};
+
+static struct nvc0_graph_mthd
+nvc8_grctx_init_mthd[] = {
+ { 0x9097, nvc1_grctx_init_9097, },
+ { 0x9197, nvc8_grctx_init_9197, },
+ { 0x9297, nvc8_grctx_init_9297, },
+ { 0x902d, nvc0_grctx_init_902d, },
+ { 0x9039, nvc0_grctx_init_9039, },
+ { 0x90c0, nvc0_grctx_init_90c0, },
+ { 0x902d, nvc0_grctx_init_mthd_magic, },
+ {}
+};
+
+static struct nvc0_graph_init *
+nvc8_grctx_init_gpc[] = {
+ nvc0_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvc8_grctx_init_tpc,
+ NULL
+};
+
+struct nouveau_oclass *
+nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc8),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nvc0_grctx_generate_main,
+ .mods = nvc0_grctx_generate_mods,
+ .unkn = nvc0_grctx_generate_unkn,
+ .hub = nvc0_grctx_init_hub,
+ .gpc = nvc8_grctx_init_gpc,
+ .icmd = nvc8_grctx_init_icmd,
+ .mthd = nvc8_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
new file mode 100644
index 000000000000..438e78410808
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+struct nvc0_graph_init
+nvd7_grctx_init_unk40xx[] = {
+ { 0x404004, 10, 0x04, 0x00000000 },
+ { 0x404044, 1, 0x04, 0x00000000 },
+ { 0x404094, 1, 0x04, 0x00000000 },
+ { 0x404098, 12, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf0000087 },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 1, 0x04, 0x00000000 },
+ { 0x404134, 1, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x404168, 1, 0x04, 0x00000000 },
+ { 0x404178, 2, 0x04, 0x00000000 },
+ { 0x404200, 8, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_unk58xx[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180324 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_unk64xx[] = {
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x801a0078 },
+ { 0x4064c4, 1, 0x04, 0x00c9ffff },
+ { 0x4064d0, 8, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_gpc_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x02200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 3, 0x04, 0x00000000 },
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100018 },
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ { 0x418b00, 1, 0x04, 0x00000006 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_tpc[] = {
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00008000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0017f440 },
+ { 0x419c00, 1, 0x04, 0x0000000a },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ { 0x419cb0, 1, 0x04, 0x00020048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00010110 },
+ { 0x419f30, 11, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_grctx_init_unk[] = {
+ { 0x41be24, 1, 0x04, 0x00000002 },
+ { 0x41bec0, 1, 0x04, 0x12180000 },
+ { 0x41bec4, 1, 0x04, 0x00003fff },
+ { 0x41bee4, 1, 0x04, 0x03240218 },
+ { 0x41bf00, 1, 0x04, 0x0a418820 },
+ { 0x41bf04, 1, 0x04, 0x062080e6 },
+ { 0x41bf08, 1, 0x04, 0x020398a4 },
+ { 0x41bf0c, 1, 0x04, 0x0e629062 },
+ { 0x41bf10, 1, 0x04, 0x0a418820 },
+ { 0x41bf14, 1, 0x04, 0x000000e6 },
+ { 0x41bfd0, 1, 0x04, 0x00900103 },
+ { 0x41bfe0, 1, 0x04, 0x00400001 },
+ { 0x41bfe4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static void
+nvd7_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+ u32 magic[GPC_MAX][2];
+ u32 offset;
+ int gpc;
+
+ mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+ mmio_list(0x40800c, 0x00000000, 8, 1);
+ mmio_list(0x408010, 0x80000000, 0, 0);
+ mmio_list(0x419004, 0x00000000, 8, 1);
+ mmio_list(0x419008, 0x00000000, 0, 0);
+ mmio_list(0x408004, 0x00000000, 8, 0);
+ mmio_list(0x408008, 0x80000018, 0, 0);
+ mmio_list(0x418808, 0x00000000, 8, 0);
+ mmio_list(0x41880c, 0x80000018, 0, 0);
+ mmio_list(0x418810, 0x80000000, 12, 2);
+ mmio_list(0x419848, 0x10000000, 12, 2);
+
+ mmio_list(0x405830, 0x02180324, 0, 0);
+ mmio_list(0x4064c4, 0x00c9ffff, 0, 0);
+
+ for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+ u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+ u16 magic1 = 0x0324 * priv->tpc_nr[gpc];
+ magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset;
+ magic[gpc][1] = 0x00000000 | (magic1 << 16);
+ offset += 0x0324 * priv->tpc_nr[gpc];
+ }
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+ mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+ offset += 0x07ff * priv->tpc_nr[gpc];
+ }
+ mmio_list(0x17e91c, 0x03060609, 0, 0); /* different from kepler */
+}
+
+void
+nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+ struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ int i;
+
+ nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+
+ for (i = 0; oclass->hub[i]; i++)
+ nvc0_graph_mmio(priv, oclass->hub[i]);
+ for (i = 0; oclass->gpc[i]; i++)
+ nvc0_graph_mmio(priv, oclass->gpc[i]);
+
+ nv_wr32(priv, 0x404154, 0x00000000);
+
+ oclass->mods(priv, info);
+ oclass->unkn(priv);
+
+ nvc0_grctx_generate_tpcid(priv);
+ nvc0_grctx_generate_r406028(priv);
+ nvc0_grctx_generate_r4060a8(priv);
+ nve4_grctx_generate_r418bb8(priv);
+ nvc0_grctx_generate_r406800(priv);
+
+ for (i = 0; i < 8; i++)
+ nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+ nvc0_graph_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ nvc0_graph_mthd(priv, oclass->mthd);
+ nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
+}
+
+
+static struct nvc0_graph_init *
+nvd7_grctx_init_hub[] = {
+ nvc0_grctx_init_base,
+ nvd7_grctx_init_unk40xx,
+ nvc0_grctx_init_unk44xx,
+ nvc0_grctx_init_unk46xx,
+ nvc0_grctx_init_unk47xx,
+ nvd7_grctx_init_unk58xx,
+ nvc0_grctx_init_unk60xx,
+ nvd7_grctx_init_unk64xx,
+ nvc0_grctx_init_unk78xx,
+ nvc0_grctx_init_unk80xx,
+ nvd9_grctx_init_rop,
+};
+
+struct nvc0_graph_init *
+nvd7_grctx_init_gpc[] = {
+ nvd7_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvd7_grctx_init_tpc,
+ nvd7_grctx_init_unk,
+ NULL
+};
+
+struct nouveau_oclass *
+nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xd7),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nvd7_grctx_generate_main,
+ .mods = nvd7_grctx_generate_mods,
+ .unkn = nve4_grctx_generate_unkn,
+ .hub = nvd7_grctx_init_hub,
+ .gpc = nvd7_grctx_init_gpc,
+ .icmd = nvd9_grctx_init_icmd,
+ .mthd = nvd9_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
new file mode 100644
index 000000000000..818a4751df46
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+struct nvc0_graph_init
+nvd9_grctx_init_90c0[] = {
+ { 0x002700, 4, 0x40, 0x00000000 },
+ { 0x002720, 4, 0x40, 0x00000000 },
+ { 0x002704, 4, 0x40, 0x00000000 },
+ { 0x002724, 4, 0x40, 0x00000000 },
+ { 0x002708, 4, 0x40, 0x00000000 },
+ { 0x002728, 4, 0x40, 0x00000000 },
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x002710, 4, 0x40, 0x00014000 },
+ { 0x002730, 4, 0x40, 0x00014000 },
+ { 0x002714, 4, 0x40, 0x00000040 },
+ { 0x002734, 4, 0x40, 0x00000040 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x000758, 1, 0x04, 0x00000100 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x000204, 3, 0x04, 0x00000000 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ { 0x00024c, 1, 0x04, 0x00000000 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_icmd[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000400, 24, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x000440, 24, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 1, 0x01, 0x00000001 },
+ { 0x000639, 1, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_unk40xx[] = {
+ { 0x404004, 11, 0x04, 0x00000000 },
+ { 0x404044, 1, 0x04, 0x00000000 },
+ { 0x404094, 1, 0x04, 0x00000000 },
+ { 0x404098, 12, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf0000087 },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 1, 0x04, 0x00000000 },
+ { 0x404134, 1, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x404168, 1, 0x04, 0x00000000 },
+ { 0x404178, 2, 0x04, 0x00000000 },
+ { 0x404200, 8, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_unk58xx[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180218 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_unk64xx[] = {
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x80140078 },
+ { 0x4064c4, 1, 0x04, 0x0086ffff },
+ {}
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_rop[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1043e005 },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x1043e005 },
+ { 0x408908, 1, 0x04, 0x00c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_gpc_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x02200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 3, 0x04, 0x00000000 },
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100008 },
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ { 0x418b00, 1, 0x04, 0x00000006 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd9_grctx_init_tpc[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00000000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0017f440 },
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00400001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ { 0x419c00, 1, 0x04, 0x0000000a },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3cf3cf3c },
+ { 0x419cb0, 1, 0x04, 0x00020048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ { 0x419d20, 1, 0x04, 0x12180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ { 0x419d44, 1, 0x04, 0x02180218 },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00010110 },
+ { 0x419f30, 11, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init *
+nvd9_grctx_init_hub[] = {
+ nvc0_grctx_init_base,
+ nvd9_grctx_init_unk40xx,
+ nvc0_grctx_init_unk44xx,
+ nvc0_grctx_init_unk46xx,
+ nvc0_grctx_init_unk47xx,
+ nvd9_grctx_init_unk58xx,
+ nvc0_grctx_init_unk60xx,
+ nvd9_grctx_init_unk64xx,
+ nvc0_grctx_init_unk78xx,
+ nvc0_grctx_init_unk80xx,
+ nvd9_grctx_init_rop,
+};
+
+struct nvc0_graph_init *
+nvd9_grctx_init_gpc[] = {
+ nvd9_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvd9_grctx_init_tpc,
+ NULL
+};
+
+struct nvc0_graph_init
+nvd9_grctx_init_mthd_magic[] = {
+ { 0x3410, 1, 0x04, 0x80002006 },
+ {}
+};
+
+struct nvc0_graph_mthd
+nvd9_grctx_init_mthd[] = {
+ { 0x9097, nvc1_grctx_init_9097, },
+ { 0x9197, nvc8_grctx_init_9197, },
+ { 0x9297, nvc8_grctx_init_9297, },
+ { 0x902d, nvc0_grctx_init_902d, },
+ { 0x9039, nvc0_grctx_init_9039, },
+ { 0x90c0, nvd9_grctx_init_90c0, },
+ { 0x902d, nvd9_grctx_init_mthd_magic, },
+ {}
+};
+
+struct nouveau_oclass *
+nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xd9),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nvc0_grctx_generate_main,
+ .mods = nvc1_grctx_generate_mods,
+ .unkn = nvc1_grctx_generate_unkn,
+ .hub = nvd9_grctx_init_hub,
+ .gpc = nvd9_grctx_init_gpc,
+ .icmd = nvd9_grctx_init_icmd,
+ .mthd = nvd9_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
deleted file mode 100644
index ae27dae3fe38..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve0.c
+++ /dev/null
@@ -1,2793 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-static void
-nve0_grctx_generate_icmd(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x400208, 0x80000000);
- nv_icmd(priv, 0x001000, 0x00000004);
- nv_icmd(priv, 0x000039, 0x00000000);
- nv_icmd(priv, 0x00003a, 0x00000000);
- nv_icmd(priv, 0x00003b, 0x00000000);
- nv_icmd(priv, 0x0000a9, 0x0000ffff);
- nv_icmd(priv, 0x000038, 0x0fac6881);
- nv_icmd(priv, 0x00003d, 0x00000001);
- nv_icmd(priv, 0x0000e8, 0x00000400);
- nv_icmd(priv, 0x0000e9, 0x00000400);
- nv_icmd(priv, 0x0000ea, 0x00000400);
- nv_icmd(priv, 0x0000eb, 0x00000400);
- nv_icmd(priv, 0x0000ec, 0x00000400);
- nv_icmd(priv, 0x0000ed, 0x00000400);
- nv_icmd(priv, 0x0000ee, 0x00000400);
- nv_icmd(priv, 0x0000ef, 0x00000400);
- nv_icmd(priv, 0x000078, 0x00000300);
- nv_icmd(priv, 0x000079, 0x00000300);
- nv_icmd(priv, 0x00007a, 0x00000300);
- nv_icmd(priv, 0x00007b, 0x00000300);
- nv_icmd(priv, 0x00007c, 0x00000300);
- nv_icmd(priv, 0x00007d, 0x00000300);
- nv_icmd(priv, 0x00007e, 0x00000300);
- nv_icmd(priv, 0x00007f, 0x00000300);
- nv_icmd(priv, 0x000050, 0x00000011);
- nv_icmd(priv, 0x000058, 0x00000008);
- nv_icmd(priv, 0x000059, 0x00000008);
- nv_icmd(priv, 0x00005a, 0x00000008);
- nv_icmd(priv, 0x00005b, 0x00000008);
- nv_icmd(priv, 0x00005c, 0x00000008);
- nv_icmd(priv, 0x00005d, 0x00000008);
- nv_icmd(priv, 0x00005e, 0x00000008);
- nv_icmd(priv, 0x00005f, 0x00000008);
- nv_icmd(priv, 0x000208, 0x00000001);
- nv_icmd(priv, 0x000209, 0x00000001);
- nv_icmd(priv, 0x00020a, 0x00000001);
- nv_icmd(priv, 0x00020b, 0x00000001);
- nv_icmd(priv, 0x00020c, 0x00000001);
- nv_icmd(priv, 0x00020d, 0x00000001);
- nv_icmd(priv, 0x00020e, 0x00000001);
- nv_icmd(priv, 0x00020f, 0x00000001);
- nv_icmd(priv, 0x000081, 0x00000001);
- nv_icmd(priv, 0x000085, 0x00000004);
- nv_icmd(priv, 0x000088, 0x00000400);
- nv_icmd(priv, 0x000090, 0x00000300);
- nv_icmd(priv, 0x000098, 0x00001001);
- nv_icmd(priv, 0x0000e3, 0x00000001);
- nv_icmd(priv, 0x0000da, 0x00000001);
- nv_icmd(priv, 0x0000f8, 0x00000003);
- nv_icmd(priv, 0x0000fa, 0x00000001);
- nv_icmd(priv, 0x00009f, 0x0000ffff);
- nv_icmd(priv, 0x0000a0, 0x0000ffff);
- nv_icmd(priv, 0x0000a1, 0x0000ffff);
- nv_icmd(priv, 0x0000a2, 0x0000ffff);
- nv_icmd(priv, 0x0000b1, 0x00000001);
- nv_icmd(priv, 0x0000ad, 0x0000013e);
- nv_icmd(priv, 0x0000e1, 0x00000010);
- nv_icmd(priv, 0x000290, 0x00000000);
- nv_icmd(priv, 0x000291, 0x00000000);
- nv_icmd(priv, 0x000292, 0x00000000);
- nv_icmd(priv, 0x000293, 0x00000000);
- nv_icmd(priv, 0x000294, 0x00000000);
- nv_icmd(priv, 0x000295, 0x00000000);
- nv_icmd(priv, 0x000296, 0x00000000);
- nv_icmd(priv, 0x000297, 0x00000000);
- nv_icmd(priv, 0x000298, 0x00000000);
- nv_icmd(priv, 0x000299, 0x00000000);
- nv_icmd(priv, 0x00029a, 0x00000000);
- nv_icmd(priv, 0x00029b, 0x00000000);
- nv_icmd(priv, 0x00029c, 0x00000000);
- nv_icmd(priv, 0x00029d, 0x00000000);
- nv_icmd(priv, 0x00029e, 0x00000000);
- nv_icmd(priv, 0x00029f, 0x00000000);
- nv_icmd(priv, 0x0003b0, 0x00000000);
- nv_icmd(priv, 0x0003b1, 0x00000000);
- nv_icmd(priv, 0x0003b2, 0x00000000);
- nv_icmd(priv, 0x0003b3, 0x00000000);
- nv_icmd(priv, 0x0003b4, 0x00000000);
- nv_icmd(priv, 0x0003b5, 0x00000000);
- nv_icmd(priv, 0x0003b6, 0x00000000);
- nv_icmd(priv, 0x0003b7, 0x00000000);
- nv_icmd(priv, 0x0003b8, 0x00000000);
- nv_icmd(priv, 0x0003b9, 0x00000000);
- nv_icmd(priv, 0x0003ba, 0x00000000);
- nv_icmd(priv, 0x0003bb, 0x00000000);
- nv_icmd(priv, 0x0003bc, 0x00000000);
- nv_icmd(priv, 0x0003bd, 0x00000000);
- nv_icmd(priv, 0x0003be, 0x00000000);
- nv_icmd(priv, 0x0003bf, 0x00000000);
- nv_icmd(priv, 0x0002a0, 0x00000000);
- nv_icmd(priv, 0x0002a1, 0x00000000);
- nv_icmd(priv, 0x0002a2, 0x00000000);
- nv_icmd(priv, 0x0002a3, 0x00000000);
- nv_icmd(priv, 0x0002a4, 0x00000000);
- nv_icmd(priv, 0x0002a5, 0x00000000);
- nv_icmd(priv, 0x0002a6, 0x00000000);
- nv_icmd(priv, 0x0002a7, 0x00000000);
- nv_icmd(priv, 0x0002a8, 0x00000000);
- nv_icmd(priv, 0x0002a9, 0x00000000);
- nv_icmd(priv, 0x0002aa, 0x00000000);
- nv_icmd(priv, 0x0002ab, 0x00000000);
- nv_icmd(priv, 0x0002ac, 0x00000000);
- nv_icmd(priv, 0x0002ad, 0x00000000);
- nv_icmd(priv, 0x0002ae, 0x00000000);
- nv_icmd(priv, 0x0002af, 0x00000000);
- nv_icmd(priv, 0x000420, 0x00000000);
- nv_icmd(priv, 0x000421, 0x00000000);
- nv_icmd(priv, 0x000422, 0x00000000);
- nv_icmd(priv, 0x000423, 0x00000000);
- nv_icmd(priv, 0x000424, 0x00000000);
- nv_icmd(priv, 0x000425, 0x00000000);
- nv_icmd(priv, 0x000426, 0x00000000);
- nv_icmd(priv, 0x000427, 0x00000000);
- nv_icmd(priv, 0x000428, 0x00000000);
- nv_icmd(priv, 0x000429, 0x00000000);
- nv_icmd(priv, 0x00042a, 0x00000000);
- nv_icmd(priv, 0x00042b, 0x00000000);
- nv_icmd(priv, 0x00042c, 0x00000000);
- nv_icmd(priv, 0x00042d, 0x00000000);
- nv_icmd(priv, 0x00042e, 0x00000000);
- nv_icmd(priv, 0x00042f, 0x00000000);
- nv_icmd(priv, 0x0002b0, 0x00000000);
- nv_icmd(priv, 0x0002b1, 0x00000000);
- nv_icmd(priv, 0x0002b2, 0x00000000);
- nv_icmd(priv, 0x0002b3, 0x00000000);
- nv_icmd(priv, 0x0002b4, 0x00000000);
- nv_icmd(priv, 0x0002b5, 0x00000000);
- nv_icmd(priv, 0x0002b6, 0x00000000);
- nv_icmd(priv, 0x0002b7, 0x00000000);
- nv_icmd(priv, 0x0002b8, 0x00000000);
- nv_icmd(priv, 0x0002b9, 0x00000000);
- nv_icmd(priv, 0x0002ba, 0x00000000);
- nv_icmd(priv, 0x0002bb, 0x00000000);
- nv_icmd(priv, 0x0002bc, 0x00000000);
- nv_icmd(priv, 0x0002bd, 0x00000000);
- nv_icmd(priv, 0x0002be, 0x00000000);
- nv_icmd(priv, 0x0002bf, 0x00000000);
- nv_icmd(priv, 0x000430, 0x00000000);
- nv_icmd(priv, 0x000431, 0x00000000);
- nv_icmd(priv, 0x000432, 0x00000000);
- nv_icmd(priv, 0x000433, 0x00000000);
- nv_icmd(priv, 0x000434, 0x00000000);
- nv_icmd(priv, 0x000435, 0x00000000);
- nv_icmd(priv, 0x000436, 0x00000000);
- nv_icmd(priv, 0x000437, 0x00000000);
- nv_icmd(priv, 0x000438, 0x00000000);
- nv_icmd(priv, 0x000439, 0x00000000);
- nv_icmd(priv, 0x00043a, 0x00000000);
- nv_icmd(priv, 0x00043b, 0x00000000);
- nv_icmd(priv, 0x00043c, 0x00000000);
- nv_icmd(priv, 0x00043d, 0x00000000);
- nv_icmd(priv, 0x00043e, 0x00000000);
- nv_icmd(priv, 0x00043f, 0x00000000);
- nv_icmd(priv, 0x0002c0, 0x00000000);
- nv_icmd(priv, 0x0002c1, 0x00000000);
- nv_icmd(priv, 0x0002c2, 0x00000000);
- nv_icmd(priv, 0x0002c3, 0x00000000);
- nv_icmd(priv, 0x0002c4, 0x00000000);
- nv_icmd(priv, 0x0002c5, 0x00000000);
- nv_icmd(priv, 0x0002c6, 0x00000000);
- nv_icmd(priv, 0x0002c7, 0x00000000);
- nv_icmd(priv, 0x0002c8, 0x00000000);
- nv_icmd(priv, 0x0002c9, 0x00000000);
- nv_icmd(priv, 0x0002ca, 0x00000000);
- nv_icmd(priv, 0x0002cb, 0x00000000);
- nv_icmd(priv, 0x0002cc, 0x00000000);
- nv_icmd(priv, 0x0002cd, 0x00000000);
- nv_icmd(priv, 0x0002ce, 0x00000000);
- nv_icmd(priv, 0x0002cf, 0x00000000);
- nv_icmd(priv, 0x0004d0, 0x00000000);
- nv_icmd(priv, 0x0004d1, 0x00000000);
- nv_icmd(priv, 0x0004d2, 0x00000000);
- nv_icmd(priv, 0x0004d3, 0x00000000);
- nv_icmd(priv, 0x0004d4, 0x00000000);
- nv_icmd(priv, 0x0004d5, 0x00000000);
- nv_icmd(priv, 0x0004d6, 0x00000000);
- nv_icmd(priv, 0x0004d7, 0x00000000);
- nv_icmd(priv, 0x0004d8, 0x00000000);
- nv_icmd(priv, 0x0004d9, 0x00000000);
- nv_icmd(priv, 0x0004da, 0x00000000);
- nv_icmd(priv, 0x0004db, 0x00000000);
- nv_icmd(priv, 0x0004dc, 0x00000000);
- nv_icmd(priv, 0x0004dd, 0x00000000);
- nv_icmd(priv, 0x0004de, 0x00000000);
- nv_icmd(priv, 0x0004df, 0x00000000);
- nv_icmd(priv, 0x000720, 0x00000000);
- nv_icmd(priv, 0x000721, 0x00000000);
- nv_icmd(priv, 0x000722, 0x00000000);
- nv_icmd(priv, 0x000723, 0x00000000);
- nv_icmd(priv, 0x000724, 0x00000000);
- nv_icmd(priv, 0x000725, 0x00000000);
- nv_icmd(priv, 0x000726, 0x00000000);
- nv_icmd(priv, 0x000727, 0x00000000);
- nv_icmd(priv, 0x000728, 0x00000000);
- nv_icmd(priv, 0x000729, 0x00000000);
- nv_icmd(priv, 0x00072a, 0x00000000);
- nv_icmd(priv, 0x00072b, 0x00000000);
- nv_icmd(priv, 0x00072c, 0x00000000);
- nv_icmd(priv, 0x00072d, 0x00000000);
- nv_icmd(priv, 0x00072e, 0x00000000);
- nv_icmd(priv, 0x00072f, 0x00000000);
- nv_icmd(priv, 0x0008c0, 0x00000000);
- nv_icmd(priv, 0x0008c1, 0x00000000);
- nv_icmd(priv, 0x0008c2, 0x00000000);
- nv_icmd(priv, 0x0008c3, 0x00000000);
- nv_icmd(priv, 0x0008c4, 0x00000000);
- nv_icmd(priv, 0x0008c5, 0x00000000);
- nv_icmd(priv, 0x0008c6, 0x00000000);
- nv_icmd(priv, 0x0008c7, 0x00000000);
- nv_icmd(priv, 0x0008c8, 0x00000000);
- nv_icmd(priv, 0x0008c9, 0x00000000);
- nv_icmd(priv, 0x0008ca, 0x00000000);
- nv_icmd(priv, 0x0008cb, 0x00000000);
- nv_icmd(priv, 0x0008cc, 0x00000000);
- nv_icmd(priv, 0x0008cd, 0x00000000);
- nv_icmd(priv, 0x0008ce, 0x00000000);
- nv_icmd(priv, 0x0008cf, 0x00000000);
- nv_icmd(priv, 0x000890, 0x00000000);
- nv_icmd(priv, 0x000891, 0x00000000);
- nv_icmd(priv, 0x000892, 0x00000000);
- nv_icmd(priv, 0x000893, 0x00000000);
- nv_icmd(priv, 0x000894, 0x00000000);
- nv_icmd(priv, 0x000895, 0x00000000);
- nv_icmd(priv, 0x000896, 0x00000000);
- nv_icmd(priv, 0x000897, 0x00000000);
- nv_icmd(priv, 0x000898, 0x00000000);
- nv_icmd(priv, 0x000899, 0x00000000);
- nv_icmd(priv, 0x00089a, 0x00000000);
- nv_icmd(priv, 0x00089b, 0x00000000);
- nv_icmd(priv, 0x00089c, 0x00000000);
- nv_icmd(priv, 0x00089d, 0x00000000);
- nv_icmd(priv, 0x00089e, 0x00000000);
- nv_icmd(priv, 0x00089f, 0x00000000);
- nv_icmd(priv, 0x0008e0, 0x00000000);
- nv_icmd(priv, 0x0008e1, 0x00000000);
- nv_icmd(priv, 0x0008e2, 0x00000000);
- nv_icmd(priv, 0x0008e3, 0x00000000);
- nv_icmd(priv, 0x0008e4, 0x00000000);
- nv_icmd(priv, 0x0008e5, 0x00000000);
- nv_icmd(priv, 0x0008e6, 0x00000000);
- nv_icmd(priv, 0x0008e7, 0x00000000);
- nv_icmd(priv, 0x0008e8, 0x00000000);
- nv_icmd(priv, 0x0008e9, 0x00000000);
- nv_icmd(priv, 0x0008ea, 0x00000000);
- nv_icmd(priv, 0x0008eb, 0x00000000);
- nv_icmd(priv, 0x0008ec, 0x00000000);
- nv_icmd(priv, 0x0008ed, 0x00000000);
- nv_icmd(priv, 0x0008ee, 0x00000000);
- nv_icmd(priv, 0x0008ef, 0x00000000);
- nv_icmd(priv, 0x0008a0, 0x00000000);
- nv_icmd(priv, 0x0008a1, 0x00000000);
- nv_icmd(priv, 0x0008a2, 0x00000000);
- nv_icmd(priv, 0x0008a3, 0x00000000);
- nv_icmd(priv, 0x0008a4, 0x00000000);
- nv_icmd(priv, 0x0008a5, 0x00000000);
- nv_icmd(priv, 0x0008a6, 0x00000000);
- nv_icmd(priv, 0x0008a7, 0x00000000);
- nv_icmd(priv, 0x0008a8, 0x00000000);
- nv_icmd(priv, 0x0008a9, 0x00000000);
- nv_icmd(priv, 0x0008aa, 0x00000000);
- nv_icmd(priv, 0x0008ab, 0x00000000);
- nv_icmd(priv, 0x0008ac, 0x00000000);
- nv_icmd(priv, 0x0008ad, 0x00000000);
- nv_icmd(priv, 0x0008ae, 0x00000000);
- nv_icmd(priv, 0x0008af, 0x00000000);
- nv_icmd(priv, 0x0008f0, 0x00000000);
- nv_icmd(priv, 0x0008f1, 0x00000000);
- nv_icmd(priv, 0x0008f2, 0x00000000);
- nv_icmd(priv, 0x0008f3, 0x00000000);
- nv_icmd(priv, 0x0008f4, 0x00000000);
- nv_icmd(priv, 0x0008f5, 0x00000000);
- nv_icmd(priv, 0x0008f6, 0x00000000);
- nv_icmd(priv, 0x0008f7, 0x00000000);
- nv_icmd(priv, 0x0008f8, 0x00000000);
- nv_icmd(priv, 0x0008f9, 0x00000000);
- nv_icmd(priv, 0x0008fa, 0x00000000);
- nv_icmd(priv, 0x0008fb, 0x00000000);
- nv_icmd(priv, 0x0008fc, 0x00000000);
- nv_icmd(priv, 0x0008fd, 0x00000000);
- nv_icmd(priv, 0x0008fe, 0x00000000);
- nv_icmd(priv, 0x0008ff, 0x00000000);
- nv_icmd(priv, 0x00094c, 0x000000ff);
- nv_icmd(priv, 0x00094d, 0xffffffff);
- nv_icmd(priv, 0x00094e, 0x00000002);
- nv_icmd(priv, 0x0002ec, 0x00000001);
- nv_icmd(priv, 0x000303, 0x00000001);
- nv_icmd(priv, 0x0002e6, 0x00000001);
- nv_icmd(priv, 0x000466, 0x00000052);
- nv_icmd(priv, 0x000301, 0x3f800000);
- nv_icmd(priv, 0x000304, 0x30201000);
- nv_icmd(priv, 0x000305, 0x70605040);
- nv_icmd(priv, 0x000306, 0xb8a89888);
- nv_icmd(priv, 0x000307, 0xf8e8d8c8);
- nv_icmd(priv, 0x00030a, 0x00ffff00);
- nv_icmd(priv, 0x00030b, 0x0000001a);
- nv_icmd(priv, 0x00030c, 0x00000001);
- nv_icmd(priv, 0x000318, 0x00000001);
- nv_icmd(priv, 0x000340, 0x00000000);
- nv_icmd(priv, 0x000375, 0x00000001);
- nv_icmd(priv, 0x00037d, 0x00000006);
- nv_icmd(priv, 0x0003a0, 0x00000002);
- nv_icmd(priv, 0x0003aa, 0x00000001);
- nv_icmd(priv, 0x0003a9, 0x00000001);
- nv_icmd(priv, 0x000380, 0x00000001);
- nv_icmd(priv, 0x000383, 0x00000011);
- nv_icmd(priv, 0x000360, 0x00000040);
- nv_icmd(priv, 0x000366, 0x00000000);
- nv_icmd(priv, 0x000367, 0x00000000);
- nv_icmd(priv, 0x000368, 0x00000fff);
- nv_icmd(priv, 0x000370, 0x00000000);
- nv_icmd(priv, 0x000371, 0x00000000);
- nv_icmd(priv, 0x000372, 0x000fffff);
- nv_icmd(priv, 0x00037a, 0x00000012);
- nv_icmd(priv, 0x000619, 0x00000003);
- nv_icmd(priv, 0x000811, 0x00000003);
- nv_icmd(priv, 0x000812, 0x00000004);
- nv_icmd(priv, 0x000813, 0x00000006);
- nv_icmd(priv, 0x000814, 0x00000008);
- nv_icmd(priv, 0x000815, 0x0000000b);
- nv_icmd(priv, 0x000800, 0x00000001);
- nv_icmd(priv, 0x000801, 0x00000001);
- nv_icmd(priv, 0x000802, 0x00000001);
- nv_icmd(priv, 0x000803, 0x00000001);
- nv_icmd(priv, 0x000804, 0x00000001);
- nv_icmd(priv, 0x000805, 0x00000001);
- nv_icmd(priv, 0x000632, 0x00000001);
- nv_icmd(priv, 0x000633, 0x00000002);
- nv_icmd(priv, 0x000634, 0x00000003);
- nv_icmd(priv, 0x000635, 0x00000004);
- nv_icmd(priv, 0x000654, 0x3f800000);
- nv_icmd(priv, 0x000657, 0x3f800000);
- nv_icmd(priv, 0x000655, 0x3f800000);
- nv_icmd(priv, 0x000656, 0x3f800000);
- nv_icmd(priv, 0x0006cd, 0x3f800000);
- nv_icmd(priv, 0x0007f5, 0x3f800000);
- nv_icmd(priv, 0x0007dc, 0x39291909);
- nv_icmd(priv, 0x0007dd, 0x79695949);
- nv_icmd(priv, 0x0007de, 0xb9a99989);
- nv_icmd(priv, 0x0007df, 0xf9e9d9c9);
- nv_icmd(priv, 0x0007e8, 0x00003210);
- nv_icmd(priv, 0x0007e9, 0x00007654);
- nv_icmd(priv, 0x0007ea, 0x00000098);
- nv_icmd(priv, 0x0007ec, 0x39291909);
- nv_icmd(priv, 0x0007ed, 0x79695949);
- nv_icmd(priv, 0x0007ee, 0xb9a99989);
- nv_icmd(priv, 0x0007ef, 0xf9e9d9c9);
- nv_icmd(priv, 0x0007f0, 0x00003210);
- nv_icmd(priv, 0x0007f1, 0x00007654);
- nv_icmd(priv, 0x0007f2, 0x00000098);
- nv_icmd(priv, 0x0005a5, 0x00000001);
- nv_icmd(priv, 0x000980, 0x00000000);
- nv_icmd(priv, 0x000981, 0x00000000);
- nv_icmd(priv, 0x000982, 0x00000000);
- nv_icmd(priv, 0x000983, 0x00000000);
- nv_icmd(priv, 0x000984, 0x00000000);
- nv_icmd(priv, 0x000985, 0x00000000);
- nv_icmd(priv, 0x000986, 0x00000000);
- nv_icmd(priv, 0x000987, 0x00000000);
- nv_icmd(priv, 0x000988, 0x00000000);
- nv_icmd(priv, 0x000989, 0x00000000);
- nv_icmd(priv, 0x00098a, 0x00000000);
- nv_icmd(priv, 0x00098b, 0x00000000);
- nv_icmd(priv, 0x00098c, 0x00000000);
- nv_icmd(priv, 0x00098d, 0x00000000);
- nv_icmd(priv, 0x00098e, 0x00000000);
- nv_icmd(priv, 0x00098f, 0x00000000);
- nv_icmd(priv, 0x000990, 0x00000000);
- nv_icmd(priv, 0x000991, 0x00000000);
- nv_icmd(priv, 0x000992, 0x00000000);
- nv_icmd(priv, 0x000993, 0x00000000);
- nv_icmd(priv, 0x000994, 0x00000000);
- nv_icmd(priv, 0x000995, 0x00000000);
- nv_icmd(priv, 0x000996, 0x00000000);
- nv_icmd(priv, 0x000997, 0x00000000);
- nv_icmd(priv, 0x000998, 0x00000000);
- nv_icmd(priv, 0x000999, 0x00000000);
- nv_icmd(priv, 0x00099a, 0x00000000);
- nv_icmd(priv, 0x00099b, 0x00000000);
- nv_icmd(priv, 0x00099c, 0x00000000);
- nv_icmd(priv, 0x00099d, 0x00000000);
- nv_icmd(priv, 0x00099e, 0x00000000);
- nv_icmd(priv, 0x00099f, 0x00000000);
- nv_icmd(priv, 0x0009a0, 0x00000000);
- nv_icmd(priv, 0x0009a1, 0x00000000);
- nv_icmd(priv, 0x0009a2, 0x00000000);
- nv_icmd(priv, 0x0009a3, 0x00000000);
- nv_icmd(priv, 0x0009a4, 0x00000000);
- nv_icmd(priv, 0x0009a5, 0x00000000);
- nv_icmd(priv, 0x0009a6, 0x00000000);
- nv_icmd(priv, 0x0009a7, 0x00000000);
- nv_icmd(priv, 0x0009a8, 0x00000000);
- nv_icmd(priv, 0x0009a9, 0x00000000);
- nv_icmd(priv, 0x0009aa, 0x00000000);
- nv_icmd(priv, 0x0009ab, 0x00000000);
- nv_icmd(priv, 0x0009ac, 0x00000000);
- nv_icmd(priv, 0x0009ad, 0x00000000);
- nv_icmd(priv, 0x0009ae, 0x00000000);
- nv_icmd(priv, 0x0009af, 0x00000000);
- nv_icmd(priv, 0x0009b0, 0x00000000);
- nv_icmd(priv, 0x0009b1, 0x00000000);
- nv_icmd(priv, 0x0009b2, 0x00000000);
- nv_icmd(priv, 0x0009b3, 0x00000000);
- nv_icmd(priv, 0x0009b4, 0x00000000);
- nv_icmd(priv, 0x0009b5, 0x00000000);
- nv_icmd(priv, 0x0009b6, 0x00000000);
- nv_icmd(priv, 0x0009b7, 0x00000000);
- nv_icmd(priv, 0x0009b8, 0x00000000);
- nv_icmd(priv, 0x0009b9, 0x00000000);
- nv_icmd(priv, 0x0009ba, 0x00000000);
- nv_icmd(priv, 0x0009bb, 0x00000000);
- nv_icmd(priv, 0x0009bc, 0x00000000);
- nv_icmd(priv, 0x0009bd, 0x00000000);
- nv_icmd(priv, 0x0009be, 0x00000000);
- nv_icmd(priv, 0x0009bf, 0x00000000);
- nv_icmd(priv, 0x0009c0, 0x00000000);
- nv_icmd(priv, 0x0009c1, 0x00000000);
- nv_icmd(priv, 0x0009c2, 0x00000000);
- nv_icmd(priv, 0x0009c3, 0x00000000);
- nv_icmd(priv, 0x0009c4, 0x00000000);
- nv_icmd(priv, 0x0009c5, 0x00000000);
- nv_icmd(priv, 0x0009c6, 0x00000000);
- nv_icmd(priv, 0x0009c7, 0x00000000);
- nv_icmd(priv, 0x0009c8, 0x00000000);
- nv_icmd(priv, 0x0009c9, 0x00000000);
- nv_icmd(priv, 0x0009ca, 0x00000000);
- nv_icmd(priv, 0x0009cb, 0x00000000);
- nv_icmd(priv, 0x0009cc, 0x00000000);
- nv_icmd(priv, 0x0009cd, 0x00000000);
- nv_icmd(priv, 0x0009ce, 0x00000000);
- nv_icmd(priv, 0x0009cf, 0x00000000);
- nv_icmd(priv, 0x0009d0, 0x00000000);
- nv_icmd(priv, 0x0009d1, 0x00000000);
- nv_icmd(priv, 0x0009d2, 0x00000000);
- nv_icmd(priv, 0x0009d3, 0x00000000);
- nv_icmd(priv, 0x0009d4, 0x00000000);
- nv_icmd(priv, 0x0009d5, 0x00000000);
- nv_icmd(priv, 0x0009d6, 0x00000000);
- nv_icmd(priv, 0x0009d7, 0x00000000);
- nv_icmd(priv, 0x0009d8, 0x00000000);
- nv_icmd(priv, 0x0009d9, 0x00000000);
- nv_icmd(priv, 0x0009da, 0x00000000);
- nv_icmd(priv, 0x0009db, 0x00000000);
- nv_icmd(priv, 0x0009dc, 0x00000000);
- nv_icmd(priv, 0x0009dd, 0x00000000);
- nv_icmd(priv, 0x0009de, 0x00000000);
- nv_icmd(priv, 0x0009df, 0x00000000);
- nv_icmd(priv, 0x0009e0, 0x00000000);
- nv_icmd(priv, 0x0009e1, 0x00000000);
- nv_icmd(priv, 0x0009e2, 0x00000000);
- nv_icmd(priv, 0x0009e3, 0x00000000);
- nv_icmd(priv, 0x0009e4, 0x00000000);
- nv_icmd(priv, 0x0009e5, 0x00000000);
- nv_icmd(priv, 0x0009e6, 0x00000000);
- nv_icmd(priv, 0x0009e7, 0x00000000);
- nv_icmd(priv, 0x0009e8, 0x00000000);
- nv_icmd(priv, 0x0009e9, 0x00000000);
- nv_icmd(priv, 0x0009ea, 0x00000000);
- nv_icmd(priv, 0x0009eb, 0x00000000);
- nv_icmd(priv, 0x0009ec, 0x00000000);
- nv_icmd(priv, 0x0009ed, 0x00000000);
- nv_icmd(priv, 0x0009ee, 0x00000000);
- nv_icmd(priv, 0x0009ef, 0x00000000);
- nv_icmd(priv, 0x0009f0, 0x00000000);
- nv_icmd(priv, 0x0009f1, 0x00000000);
- nv_icmd(priv, 0x0009f2, 0x00000000);
- nv_icmd(priv, 0x0009f3, 0x00000000);
- nv_icmd(priv, 0x0009f4, 0x00000000);
- nv_icmd(priv, 0x0009f5, 0x00000000);
- nv_icmd(priv, 0x0009f6, 0x00000000);
- nv_icmd(priv, 0x0009f7, 0x00000000);
- nv_icmd(priv, 0x0009f8, 0x00000000);
- nv_icmd(priv, 0x0009f9, 0x00000000);
- nv_icmd(priv, 0x0009fa, 0x00000000);
- nv_icmd(priv, 0x0009fb, 0x00000000);
- nv_icmd(priv, 0x0009fc, 0x00000000);
- nv_icmd(priv, 0x0009fd, 0x00000000);
- nv_icmd(priv, 0x0009fe, 0x00000000);
- nv_icmd(priv, 0x0009ff, 0x00000000);
- nv_icmd(priv, 0x000468, 0x00000004);
- nv_icmd(priv, 0x00046c, 0x00000001);
- nv_icmd(priv, 0x000470, 0x00000000);
- nv_icmd(priv, 0x000471, 0x00000000);
- nv_icmd(priv, 0x000472, 0x00000000);
- nv_icmd(priv, 0x000473, 0x00000000);
- nv_icmd(priv, 0x000474, 0x00000000);
- nv_icmd(priv, 0x000475, 0x00000000);
- nv_icmd(priv, 0x000476, 0x00000000);
- nv_icmd(priv, 0x000477, 0x00000000);
- nv_icmd(priv, 0x000478, 0x00000000);
- nv_icmd(priv, 0x000479, 0x00000000);
- nv_icmd(priv, 0x00047a, 0x00000000);
- nv_icmd(priv, 0x00047b, 0x00000000);
- nv_icmd(priv, 0x00047c, 0x00000000);
- nv_icmd(priv, 0x00047d, 0x00000000);
- nv_icmd(priv, 0x00047e, 0x00000000);
- nv_icmd(priv, 0x00047f, 0x00000000);
- nv_icmd(priv, 0x000480, 0x00000000);
- nv_icmd(priv, 0x000481, 0x00000000);
- nv_icmd(priv, 0x000482, 0x00000000);
- nv_icmd(priv, 0x000483, 0x00000000);
- nv_icmd(priv, 0x000484, 0x00000000);
- nv_icmd(priv, 0x000485, 0x00000000);
- nv_icmd(priv, 0x000486, 0x00000000);
- nv_icmd(priv, 0x000487, 0x00000000);
- nv_icmd(priv, 0x000488, 0x00000000);
- nv_icmd(priv, 0x000489, 0x00000000);
- nv_icmd(priv, 0x00048a, 0x00000000);
- nv_icmd(priv, 0x00048b, 0x00000000);
- nv_icmd(priv, 0x00048c, 0x00000000);
- nv_icmd(priv, 0x00048d, 0x00000000);
- nv_icmd(priv, 0x00048e, 0x00000000);
- nv_icmd(priv, 0x00048f, 0x00000000);
- nv_icmd(priv, 0x000490, 0x00000000);
- nv_icmd(priv, 0x000491, 0x00000000);
- nv_icmd(priv, 0x000492, 0x00000000);
- nv_icmd(priv, 0x000493, 0x00000000);
- nv_icmd(priv, 0x000494, 0x00000000);
- nv_icmd(priv, 0x000495, 0x00000000);
- nv_icmd(priv, 0x000496, 0x00000000);
- nv_icmd(priv, 0x000497, 0x00000000);
- nv_icmd(priv, 0x000498, 0x00000000);
- nv_icmd(priv, 0x000499, 0x00000000);
- nv_icmd(priv, 0x00049a, 0x00000000);
- nv_icmd(priv, 0x00049b, 0x00000000);
- nv_icmd(priv, 0x00049c, 0x00000000);
- nv_icmd(priv, 0x00049d, 0x00000000);
- nv_icmd(priv, 0x00049e, 0x00000000);
- nv_icmd(priv, 0x00049f, 0x00000000);
- nv_icmd(priv, 0x0004a0, 0x00000000);
- nv_icmd(priv, 0x0004a1, 0x00000000);
- nv_icmd(priv, 0x0004a2, 0x00000000);
- nv_icmd(priv, 0x0004a3, 0x00000000);
- nv_icmd(priv, 0x0004a4, 0x00000000);
- nv_icmd(priv, 0x0004a5, 0x00000000);
- nv_icmd(priv, 0x0004a6, 0x00000000);
- nv_icmd(priv, 0x0004a7, 0x00000000);
- nv_icmd(priv, 0x0004a8, 0x00000000);
- nv_icmd(priv, 0x0004a9, 0x00000000);
- nv_icmd(priv, 0x0004aa, 0x00000000);
- nv_icmd(priv, 0x0004ab, 0x00000000);
- nv_icmd(priv, 0x0004ac, 0x00000000);
- nv_icmd(priv, 0x0004ad, 0x00000000);
- nv_icmd(priv, 0x0004ae, 0x00000000);
- nv_icmd(priv, 0x0004af, 0x00000000);
- nv_icmd(priv, 0x0004b0, 0x00000000);
- nv_icmd(priv, 0x0004b1, 0x00000000);
- nv_icmd(priv, 0x0004b2, 0x00000000);
- nv_icmd(priv, 0x0004b3, 0x00000000);
- nv_icmd(priv, 0x0004b4, 0x00000000);
- nv_icmd(priv, 0x0004b5, 0x00000000);
- nv_icmd(priv, 0x0004b6, 0x00000000);
- nv_icmd(priv, 0x0004b7, 0x00000000);
- nv_icmd(priv, 0x0004b8, 0x00000000);
- nv_icmd(priv, 0x0004b9, 0x00000000);
- nv_icmd(priv, 0x0004ba, 0x00000000);
- nv_icmd(priv, 0x0004bb, 0x00000000);
- nv_icmd(priv, 0x0004bc, 0x00000000);
- nv_icmd(priv, 0x0004bd, 0x00000000);
- nv_icmd(priv, 0x0004be, 0x00000000);
- nv_icmd(priv, 0x0004bf, 0x00000000);
- nv_icmd(priv, 0x0004c0, 0x00000000);
- nv_icmd(priv, 0x0004c1, 0x00000000);
- nv_icmd(priv, 0x0004c2, 0x00000000);
- nv_icmd(priv, 0x0004c3, 0x00000000);
- nv_icmd(priv, 0x0004c4, 0x00000000);
- nv_icmd(priv, 0x0004c5, 0x00000000);
- nv_icmd(priv, 0x0004c6, 0x00000000);
- nv_icmd(priv, 0x0004c7, 0x00000000);
- nv_icmd(priv, 0x0004c8, 0x00000000);
- nv_icmd(priv, 0x0004c9, 0x00000000);
- nv_icmd(priv, 0x0004ca, 0x00000000);
- nv_icmd(priv, 0x0004cb, 0x00000000);
- nv_icmd(priv, 0x0004cc, 0x00000000);
- nv_icmd(priv, 0x0004cd, 0x00000000);
- nv_icmd(priv, 0x0004ce, 0x00000000);
- nv_icmd(priv, 0x0004cf, 0x00000000);
- nv_icmd(priv, 0x000510, 0x3f800000);
- nv_icmd(priv, 0x000511, 0x3f800000);
- nv_icmd(priv, 0x000512, 0x3f800000);
- nv_icmd(priv, 0x000513, 0x3f800000);
- nv_icmd(priv, 0x000514, 0x3f800000);
- nv_icmd(priv, 0x000515, 0x3f800000);
- nv_icmd(priv, 0x000516, 0x3f800000);
- nv_icmd(priv, 0x000517, 0x3f800000);
- nv_icmd(priv, 0x000518, 0x3f800000);
- nv_icmd(priv, 0x000519, 0x3f800000);
- nv_icmd(priv, 0x00051a, 0x3f800000);
- nv_icmd(priv, 0x00051b, 0x3f800000);
- nv_icmd(priv, 0x00051c, 0x3f800000);
- nv_icmd(priv, 0x00051d, 0x3f800000);
- nv_icmd(priv, 0x00051e, 0x3f800000);
- nv_icmd(priv, 0x00051f, 0x3f800000);
- nv_icmd(priv, 0x000520, 0x000002b6);
- nv_icmd(priv, 0x000529, 0x00000001);
- nv_icmd(priv, 0x000530, 0xffff0000);
- nv_icmd(priv, 0x000531, 0xffff0000);
- nv_icmd(priv, 0x000532, 0xffff0000);
- nv_icmd(priv, 0x000533, 0xffff0000);
- nv_icmd(priv, 0x000534, 0xffff0000);
- nv_icmd(priv, 0x000535, 0xffff0000);
- nv_icmd(priv, 0x000536, 0xffff0000);
- nv_icmd(priv, 0x000537, 0xffff0000);
- nv_icmd(priv, 0x000538, 0xffff0000);
- nv_icmd(priv, 0x000539, 0xffff0000);
- nv_icmd(priv, 0x00053a, 0xffff0000);
- nv_icmd(priv, 0x00053b, 0xffff0000);
- nv_icmd(priv, 0x00053c, 0xffff0000);
- nv_icmd(priv, 0x00053d, 0xffff0000);
- nv_icmd(priv, 0x00053e, 0xffff0000);
- nv_icmd(priv, 0x00053f, 0xffff0000);
- nv_icmd(priv, 0x000585, 0x0000003f);
- nv_icmd(priv, 0x000576, 0x00000003);
- nv_icmd(priv, 0x00057b, 0x00000059);
- nv_icmd(priv, 0x000586, 0x00000040);
- nv_icmd(priv, 0x000582, 0x00000080);
- nv_icmd(priv, 0x000583, 0x00000080);
- nv_icmd(priv, 0x0005c2, 0x00000001);
- nv_icmd(priv, 0x000638, 0x00000001);
- nv_icmd(priv, 0x000639, 0x00000001);
- nv_icmd(priv, 0x00063a, 0x00000002);
- nv_icmd(priv, 0x00063b, 0x00000001);
- nv_icmd(priv, 0x00063c, 0x00000001);
- nv_icmd(priv, 0x00063d, 0x00000002);
- nv_icmd(priv, 0x00063e, 0x00000001);
- nv_icmd(priv, 0x0008b8, 0x00000001);
- nv_icmd(priv, 0x0008b9, 0x00000001);
- nv_icmd(priv, 0x0008ba, 0x00000001);
- nv_icmd(priv, 0x0008bb, 0x00000001);
- nv_icmd(priv, 0x0008bc, 0x00000001);
- nv_icmd(priv, 0x0008bd, 0x00000001);
- nv_icmd(priv, 0x0008be, 0x00000001);
- nv_icmd(priv, 0x0008bf, 0x00000001);
- nv_icmd(priv, 0x000900, 0x00000001);
- nv_icmd(priv, 0x000901, 0x00000001);
- nv_icmd(priv, 0x000902, 0x00000001);
- nv_icmd(priv, 0x000903, 0x00000001);
- nv_icmd(priv, 0x000904, 0x00000001);
- nv_icmd(priv, 0x000905, 0x00000001);
- nv_icmd(priv, 0x000906, 0x00000001);
- nv_icmd(priv, 0x000907, 0x00000001);
- nv_icmd(priv, 0x000908, 0x00000002);
- nv_icmd(priv, 0x000909, 0x00000002);
- nv_icmd(priv, 0x00090a, 0x00000002);
- nv_icmd(priv, 0x00090b, 0x00000002);
- nv_icmd(priv, 0x00090c, 0x00000002);
- nv_icmd(priv, 0x00090d, 0x00000002);
- nv_icmd(priv, 0x00090e, 0x00000002);
- nv_icmd(priv, 0x00090f, 0x00000002);
- nv_icmd(priv, 0x000910, 0x00000001);
- nv_icmd(priv, 0x000911, 0x00000001);
- nv_icmd(priv, 0x000912, 0x00000001);
- nv_icmd(priv, 0x000913, 0x00000001);
- nv_icmd(priv, 0x000914, 0x00000001);
- nv_icmd(priv, 0x000915, 0x00000001);
- nv_icmd(priv, 0x000916, 0x00000001);
- nv_icmd(priv, 0x000917, 0x00000001);
- nv_icmd(priv, 0x000918, 0x00000001);
- nv_icmd(priv, 0x000919, 0x00000001);
- nv_icmd(priv, 0x00091a, 0x00000001);
- nv_icmd(priv, 0x00091b, 0x00000001);
- nv_icmd(priv, 0x00091c, 0x00000001);
- nv_icmd(priv, 0x00091d, 0x00000001);
- nv_icmd(priv, 0x00091e, 0x00000001);
- nv_icmd(priv, 0x00091f, 0x00000001);
- nv_icmd(priv, 0x000920, 0x00000002);
- nv_icmd(priv, 0x000921, 0x00000002);
- nv_icmd(priv, 0x000922, 0x00000002);
- nv_icmd(priv, 0x000923, 0x00000002);
- nv_icmd(priv, 0x000924, 0x00000002);
- nv_icmd(priv, 0x000925, 0x00000002);
- nv_icmd(priv, 0x000926, 0x00000002);
- nv_icmd(priv, 0x000927, 0x00000002);
- nv_icmd(priv, 0x000928, 0x00000001);
- nv_icmd(priv, 0x000929, 0x00000001);
- nv_icmd(priv, 0x00092a, 0x00000001);
- nv_icmd(priv, 0x00092b, 0x00000001);
- nv_icmd(priv, 0x00092c, 0x00000001);
- nv_icmd(priv, 0x00092d, 0x00000001);
- nv_icmd(priv, 0x00092e, 0x00000001);
- nv_icmd(priv, 0x00092f, 0x00000001);
- nv_icmd(priv, 0x000648, 0x00000001);
- nv_icmd(priv, 0x000649, 0x00000001);
- nv_icmd(priv, 0x00064a, 0x00000001);
- nv_icmd(priv, 0x00064b, 0x00000001);
- nv_icmd(priv, 0x00064c, 0x00000001);
- nv_icmd(priv, 0x00064d, 0x00000001);
- nv_icmd(priv, 0x00064e, 0x00000001);
- nv_icmd(priv, 0x00064f, 0x00000001);
- nv_icmd(priv, 0x000650, 0x00000001);
- nv_icmd(priv, 0x000658, 0x0000000f);
- nv_icmd(priv, 0x0007ff, 0x0000000a);
- nv_icmd(priv, 0x00066a, 0x40000000);
- nv_icmd(priv, 0x00066b, 0x10000000);
- nv_icmd(priv, 0x00066c, 0xffff0000);
- nv_icmd(priv, 0x00066d, 0xffff0000);
- nv_icmd(priv, 0x0007af, 0x00000008);
- nv_icmd(priv, 0x0007b0, 0x00000008);
- nv_icmd(priv, 0x0007f6, 0x00000001);
- nv_icmd(priv, 0x0006b2, 0x00000055);
- nv_icmd(priv, 0x0007ad, 0x00000003);
- nv_icmd(priv, 0x000937, 0x00000001);
- nv_icmd(priv, 0x000971, 0x00000008);
- nv_icmd(priv, 0x000972, 0x00000040);
- nv_icmd(priv, 0x000973, 0x0000012c);
- nv_icmd(priv, 0x00097c, 0x00000040);
- nv_icmd(priv, 0x000979, 0x00000003);
- nv_icmd(priv, 0x000975, 0x00000020);
- nv_icmd(priv, 0x000976, 0x00000001);
- nv_icmd(priv, 0x000977, 0x00000020);
- nv_icmd(priv, 0x000978, 0x00000001);
- nv_icmd(priv, 0x000957, 0x00000003);
- nv_icmd(priv, 0x00095e, 0x20164010);
- nv_icmd(priv, 0x00095f, 0x00000020);
- nv_icmd(priv, 0x00097d, 0x00000020);
- nv_icmd(priv, 0x000683, 0x00000006);
- nv_icmd(priv, 0x000685, 0x003fffff);
- nv_icmd(priv, 0x000687, 0x003fffff);
- nv_icmd(priv, 0x0006a0, 0x00000005);
- nv_icmd(priv, 0x000840, 0x00400008);
- nv_icmd(priv, 0x000841, 0x08000080);
- nv_icmd(priv, 0x000842, 0x00400008);
- nv_icmd(priv, 0x000843, 0x08000080);
- nv_icmd(priv, 0x000818, 0x00000000);
- nv_icmd(priv, 0x000819, 0x00000000);
- nv_icmd(priv, 0x00081a, 0x00000000);
- nv_icmd(priv, 0x00081b, 0x00000000);
- nv_icmd(priv, 0x00081c, 0x00000000);
- nv_icmd(priv, 0x00081d, 0x00000000);
- nv_icmd(priv, 0x00081e, 0x00000000);
- nv_icmd(priv, 0x00081f, 0x00000000);
- nv_icmd(priv, 0x000848, 0x00000000);
- nv_icmd(priv, 0x000849, 0x00000000);
- nv_icmd(priv, 0x00084a, 0x00000000);
- nv_icmd(priv, 0x00084b, 0x00000000);
- nv_icmd(priv, 0x00084c, 0x00000000);
- nv_icmd(priv, 0x00084d, 0x00000000);
- nv_icmd(priv, 0x00084e, 0x00000000);
- nv_icmd(priv, 0x00084f, 0x00000000);
- nv_icmd(priv, 0x000850, 0x00000000);
- nv_icmd(priv, 0x000851, 0x00000000);
- nv_icmd(priv, 0x000852, 0x00000000);
- nv_icmd(priv, 0x000853, 0x00000000);
- nv_icmd(priv, 0x000854, 0x00000000);
- nv_icmd(priv, 0x000855, 0x00000000);
- nv_icmd(priv, 0x000856, 0x00000000);
- nv_icmd(priv, 0x000857, 0x00000000);
- nv_icmd(priv, 0x000738, 0x00000000);
- nv_icmd(priv, 0x0006aa, 0x00000001);
- nv_icmd(priv, 0x0006ab, 0x00000002);
- nv_icmd(priv, 0x0006ac, 0x00000080);
- nv_icmd(priv, 0x0006ad, 0x00000100);
- nv_icmd(priv, 0x0006ae, 0x00000100);
- nv_icmd(priv, 0x0006b1, 0x00000011);
- nv_icmd(priv, 0x0006bb, 0x000000cf);
- nv_icmd(priv, 0x0006ce, 0x2a712488);
- nv_icmd(priv, 0x000739, 0x4085c000);
- nv_icmd(priv, 0x00073a, 0x00000080);
- nv_icmd(priv, 0x000786, 0x80000100);
- nv_icmd(priv, 0x00073c, 0x00010100);
- nv_icmd(priv, 0x00073d, 0x02800000);
- nv_icmd(priv, 0x000787, 0x000000cf);
- nv_icmd(priv, 0x00078c, 0x00000008);
- nv_icmd(priv, 0x000792, 0x00000001);
- nv_icmd(priv, 0x000794, 0x00000001);
- nv_icmd(priv, 0x000795, 0x00000001);
- nv_icmd(priv, 0x000796, 0x00000001);
- nv_icmd(priv, 0x000797, 0x000000cf);
- nv_icmd(priv, 0x000836, 0x00000001);
- nv_icmd(priv, 0x00079a, 0x00000002);
- nv_icmd(priv, 0x000833, 0x04444480);
- nv_icmd(priv, 0x0007a1, 0x00000001);
- nv_icmd(priv, 0x0007a3, 0x00000001);
- nv_icmd(priv, 0x0007a4, 0x00000001);
- nv_icmd(priv, 0x0007a5, 0x00000001);
- nv_icmd(priv, 0x000831, 0x00000004);
- nv_icmd(priv, 0x000b07, 0x00000002);
- nv_icmd(priv, 0x000b08, 0x00000100);
- nv_icmd(priv, 0x000b09, 0x00000100);
- nv_icmd(priv, 0x000b0a, 0x00000001);
- nv_icmd(priv, 0x000a04, 0x000000ff);
- nv_icmd(priv, 0x000a0b, 0x00000040);
- nv_icmd(priv, 0x00097f, 0x00000100);
- nv_icmd(priv, 0x000a02, 0x00000001);
- nv_icmd(priv, 0x000809, 0x00000007);
- nv_icmd(priv, 0x00c221, 0x00000040);
- nv_icmd(priv, 0x00c1b0, 0x0000000f);
- nv_icmd(priv, 0x00c1b1, 0x0000000f);
- nv_icmd(priv, 0x00c1b2, 0x0000000f);
- nv_icmd(priv, 0x00c1b3, 0x0000000f);
- nv_icmd(priv, 0x00c1b4, 0x0000000f);
- nv_icmd(priv, 0x00c1b5, 0x0000000f);
- nv_icmd(priv, 0x00c1b6, 0x0000000f);
- nv_icmd(priv, 0x00c1b7, 0x0000000f);
- nv_icmd(priv, 0x00c1b8, 0x0fac6881);
- nv_icmd(priv, 0x00c1b9, 0x00fac688);
- nv_icmd(priv, 0x00c401, 0x00000001);
- nv_icmd(priv, 0x00c402, 0x00010001);
- nv_icmd(priv, 0x00c403, 0x00000001);
- nv_icmd(priv, 0x00c404, 0x00000001);
- nv_icmd(priv, 0x00c40e, 0x00000020);
- nv_icmd(priv, 0x00c500, 0x00000003);
- nv_icmd(priv, 0x01e100, 0x00000001);
- nv_icmd(priv, 0x001000, 0x00000002);
- nv_icmd(priv, 0x0006aa, 0x00000001);
- nv_icmd(priv, 0x0006ad, 0x00000100);
- nv_icmd(priv, 0x0006ae, 0x00000100);
- nv_icmd(priv, 0x0006b1, 0x00000011);
- nv_icmd(priv, 0x00078c, 0x00000008);
- nv_icmd(priv, 0x000792, 0x00000001);
- nv_icmd(priv, 0x000794, 0x00000001);
- nv_icmd(priv, 0x000795, 0x00000001);
- nv_icmd(priv, 0x000796, 0x00000001);
- nv_icmd(priv, 0x000797, 0x000000cf);
- nv_icmd(priv, 0x00079a, 0x00000002);
- nv_icmd(priv, 0x000833, 0x04444480);
- nv_icmd(priv, 0x0007a1, 0x00000001);
- nv_icmd(priv, 0x0007a3, 0x00000001);
- nv_icmd(priv, 0x0007a4, 0x00000001);
- nv_icmd(priv, 0x0007a5, 0x00000001);
- nv_icmd(priv, 0x000831, 0x00000004);
- nv_icmd(priv, 0x01e100, 0x00000001);
- nv_icmd(priv, 0x001000, 0x00000008);
- nv_icmd(priv, 0x000039, 0x00000000);
- nv_icmd(priv, 0x00003a, 0x00000000);
- nv_icmd(priv, 0x00003b, 0x00000000);
- nv_icmd(priv, 0x000380, 0x00000001);
- nv_icmd(priv, 0x000366, 0x00000000);
- nv_icmd(priv, 0x000367, 0x00000000);
- nv_icmd(priv, 0x000368, 0x00000fff);
- nv_icmd(priv, 0x000370, 0x00000000);
- nv_icmd(priv, 0x000371, 0x00000000);
- nv_icmd(priv, 0x000372, 0x000fffff);
- nv_icmd(priv, 0x000813, 0x00000006);
- nv_icmd(priv, 0x000814, 0x00000008);
- nv_icmd(priv, 0x000957, 0x00000003);
- nv_icmd(priv, 0x000818, 0x00000000);
- nv_icmd(priv, 0x000819, 0x00000000);
- nv_icmd(priv, 0x00081a, 0x00000000);
- nv_icmd(priv, 0x00081b, 0x00000000);
- nv_icmd(priv, 0x00081c, 0x00000000);
- nv_icmd(priv, 0x00081d, 0x00000000);
- nv_icmd(priv, 0x00081e, 0x00000000);
- nv_icmd(priv, 0x00081f, 0x00000000);
- nv_icmd(priv, 0x000848, 0x00000000);
- nv_icmd(priv, 0x000849, 0x00000000);
- nv_icmd(priv, 0x00084a, 0x00000000);
- nv_icmd(priv, 0x00084b, 0x00000000);
- nv_icmd(priv, 0x00084c, 0x00000000);
- nv_icmd(priv, 0x00084d, 0x00000000);
- nv_icmd(priv, 0x00084e, 0x00000000);
- nv_icmd(priv, 0x00084f, 0x00000000);
- nv_icmd(priv, 0x000850, 0x00000000);
- nv_icmd(priv, 0x000851, 0x00000000);
- nv_icmd(priv, 0x000852, 0x00000000);
- nv_icmd(priv, 0x000853, 0x00000000);
- nv_icmd(priv, 0x000854, 0x00000000);
- nv_icmd(priv, 0x000855, 0x00000000);
- nv_icmd(priv, 0x000856, 0x00000000);
- nv_icmd(priv, 0x000857, 0x00000000);
- nv_icmd(priv, 0x000738, 0x00000000);
- nv_icmd(priv, 0x000b07, 0x00000002);
- nv_icmd(priv, 0x000b08, 0x00000100);
- nv_icmd(priv, 0x000b09, 0x00000100);
- nv_icmd(priv, 0x000b0a, 0x00000001);
- nv_icmd(priv, 0x000a04, 0x000000ff);
- nv_icmd(priv, 0x00097f, 0x00000100);
- nv_icmd(priv, 0x000a02, 0x00000001);
- nv_icmd(priv, 0x000809, 0x00000007);
- nv_icmd(priv, 0x00c221, 0x00000040);
- nv_icmd(priv, 0x00c401, 0x00000001);
- nv_icmd(priv, 0x00c402, 0x00010001);
- nv_icmd(priv, 0x00c403, 0x00000001);
- nv_icmd(priv, 0x00c404, 0x00000001);
- nv_icmd(priv, 0x00c40e, 0x00000020);
- nv_icmd(priv, 0x00c500, 0x00000003);
- nv_icmd(priv, 0x01e100, 0x00000001);
- nv_icmd(priv, 0x001000, 0x00000001);
- nv_icmd(priv, 0x000b07, 0x00000002);
- nv_icmd(priv, 0x000b08, 0x00000100);
- nv_icmd(priv, 0x000b09, 0x00000100);
- nv_icmd(priv, 0x000b0a, 0x00000001);
- nv_icmd(priv, 0x01e100, 0x00000001);
- nv_wr32(priv, 0x400208, 0x00000000);
-}
-
-static void
-nve0_grctx_generate_a097(struct nvc0_graph_priv *priv)
-{
- nv_mthd(priv, 0xa097, 0x0800, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0840, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0880, 0x00000000);
- nv_mthd(priv, 0xa097, 0x08c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0900, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0940, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0980, 0x00000000);
- nv_mthd(priv, 0xa097, 0x09c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0804, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0844, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0884, 0x00000000);
- nv_mthd(priv, 0xa097, 0x08c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0904, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0944, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0984, 0x00000000);
- nv_mthd(priv, 0xa097, 0x09c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0808, 0x00000400);
- nv_mthd(priv, 0xa097, 0x0848, 0x00000400);
- nv_mthd(priv, 0xa097, 0x0888, 0x00000400);
- nv_mthd(priv, 0xa097, 0x08c8, 0x00000400);
- nv_mthd(priv, 0xa097, 0x0908, 0x00000400);
- nv_mthd(priv, 0xa097, 0x0948, 0x00000400);
- nv_mthd(priv, 0xa097, 0x0988, 0x00000400);
- nv_mthd(priv, 0xa097, 0x09c8, 0x00000400);
- nv_mthd(priv, 0xa097, 0x080c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x084c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x088c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x08cc, 0x00000300);
- nv_mthd(priv, 0xa097, 0x090c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x094c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x098c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x09cc, 0x00000300);
- nv_mthd(priv, 0xa097, 0x0810, 0x000000cf);
- nv_mthd(priv, 0xa097, 0x0850, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0890, 0x00000000);
- nv_mthd(priv, 0xa097, 0x08d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0910, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0950, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0990, 0x00000000);
- nv_mthd(priv, 0xa097, 0x09d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0814, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0854, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0894, 0x00000040);
- nv_mthd(priv, 0xa097, 0x08d4, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0914, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0954, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0994, 0x00000040);
- nv_mthd(priv, 0xa097, 0x09d4, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0818, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0858, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0898, 0x00000001);
- nv_mthd(priv, 0xa097, 0x08d8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0918, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0958, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0998, 0x00000001);
- nv_mthd(priv, 0xa097, 0x09d8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x081c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x085c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x089c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x08dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x091c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x095c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x099c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x09dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0820, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0860, 0x00000000);
- nv_mthd(priv, 0xa097, 0x08a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x08e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0920, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0960, 0x00000000);
- nv_mthd(priv, 0xa097, 0x09a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x09e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ca0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cb0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cc0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cd0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ce0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cf0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c24, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c34, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c64, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c94, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ca4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cb4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cc4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cd4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ce4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cf4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c18, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c28, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c38, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c58, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c68, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c78, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c98, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ca8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cb8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cc8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cd8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ce8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cf8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c0c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c1c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c2c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c3c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c4c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c5c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c6c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c7c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1c9c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cbc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ccc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cdc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1cfc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1da0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1db0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dc0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dd0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1de0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1df0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d24, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d34, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d64, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d94, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1da4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1db4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dc4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dd4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1de4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1df4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d18, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d28, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d38, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d58, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d68, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d78, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d98, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1da8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1db8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dc8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dd8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1de8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1df8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d0c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d1c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d2c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d3c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d4c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d5c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d6c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d7c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1d9c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dbc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dcc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ddc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1dfc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f18, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f28, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f38, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f58, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f68, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f78, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f0c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f1c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f24, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f2c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f34, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f3c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f4c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f5c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f64, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f6c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f7c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f98, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fa0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fa8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fb0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fb8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fc0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fc8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fd0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fd8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fe0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fe8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ff0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ff8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f94, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1f9c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fa4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fb4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fbc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fc4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fcc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fd4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fdc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fe4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1fec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ff4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1ffc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2000, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2040, 0x00000011);
- nv_mthd(priv, 0xa097, 0x2080, 0x00000020);
- nv_mthd(priv, 0xa097, 0x20c0, 0x00000030);
- nv_mthd(priv, 0xa097, 0x2100, 0x00000040);
- nv_mthd(priv, 0xa097, 0x2140, 0x00000051);
- nv_mthd(priv, 0xa097, 0x200c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x204c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x208c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x20cc, 0x00000001);
- nv_mthd(priv, 0xa097, 0x210c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x214c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x2010, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2050, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2090, 0x00000001);
- nv_mthd(priv, 0xa097, 0x20d0, 0x00000002);
- nv_mthd(priv, 0xa097, 0x2110, 0x00000003);
- nv_mthd(priv, 0xa097, 0x2150, 0x00000004);
- nv_mthd(priv, 0xa097, 0x0380, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0384, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0388, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x038c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x03ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0700, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0710, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0720, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0730, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0704, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0714, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0724, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0734, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0708, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0718, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0728, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0738, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2800, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2804, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2808, 0x00000000);
- nv_mthd(priv, 0xa097, 0x280c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2810, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2814, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2818, 0x00000000);
- nv_mthd(priv, 0xa097, 0x281c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2820, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2824, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2828, 0x00000000);
- nv_mthd(priv, 0xa097, 0x282c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2830, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2834, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2838, 0x00000000);
- nv_mthd(priv, 0xa097, 0x283c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2840, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2844, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2848, 0x00000000);
- nv_mthd(priv, 0xa097, 0x284c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2850, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2854, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2858, 0x00000000);
- nv_mthd(priv, 0xa097, 0x285c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2860, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2864, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2868, 0x00000000);
- nv_mthd(priv, 0xa097, 0x286c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2870, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2874, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2878, 0x00000000);
- nv_mthd(priv, 0xa097, 0x287c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2880, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2884, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2888, 0x00000000);
- nv_mthd(priv, 0xa097, 0x288c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2890, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2894, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2898, 0x00000000);
- nv_mthd(priv, 0xa097, 0x289c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28b0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28b4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28b8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28d4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28d8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28f0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x28fc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2900, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2904, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2908, 0x00000000);
- nv_mthd(priv, 0xa097, 0x290c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2910, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2914, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2918, 0x00000000);
- nv_mthd(priv, 0xa097, 0x291c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2920, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2924, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2928, 0x00000000);
- nv_mthd(priv, 0xa097, 0x292c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2930, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2934, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2938, 0x00000000);
- nv_mthd(priv, 0xa097, 0x293c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2940, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2944, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2948, 0x00000000);
- nv_mthd(priv, 0xa097, 0x294c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2950, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2954, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2958, 0x00000000);
- nv_mthd(priv, 0xa097, 0x295c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2960, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2964, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2968, 0x00000000);
- nv_mthd(priv, 0xa097, 0x296c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2970, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2974, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2978, 0x00000000);
- nv_mthd(priv, 0xa097, 0x297c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2980, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2984, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2988, 0x00000000);
- nv_mthd(priv, 0xa097, 0x298c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2990, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2994, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2998, 0x00000000);
- nv_mthd(priv, 0xa097, 0x299c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29b0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29b4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29b8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29d4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29d8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29f0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x29fc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0aa0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ac0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ae0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ba0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bc0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0be0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a24, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a64, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0aa4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ac4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ae4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b24, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b64, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ba4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bc4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0be4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a28, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a68, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0aa8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ac8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ae8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b28, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b68, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ba8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bc8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0be8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a0c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a2c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a4c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a6c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0aac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0acc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0aec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b0c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b2c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b4c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b6c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bcc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ab0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ad0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0af0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bb0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bd0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bf0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a34, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0a94, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ab4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ad4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0af4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b34, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0b94, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bb4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bd4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0bf4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ca0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cb0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cc0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cd0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ce0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cf0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c24, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c34, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c64, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c94, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ca4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cb4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cc4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cd4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ce4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cf4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c18, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c28, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c38, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c58, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c68, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c78, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c98, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ca8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cb8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cc8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cd8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ce8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0cf8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0c0c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c1c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c2c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c3c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c4c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c5c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c6c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c7c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c8c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0c9c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0cac, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0cbc, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0ccc, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0cdc, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0cec, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0cfc, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0d00, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d08, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d10, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d18, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d20, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d28, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d30, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d38, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d04, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d0c, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d14, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d1c, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d24, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d2c, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d34, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d3c, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e00, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e20, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e30, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e60, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e70, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ea0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0eb0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ec0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ed0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ee0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ef0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0e04, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e14, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e24, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e34, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e44, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e54, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e64, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e74, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e84, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e94, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ea4, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0eb4, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ec4, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ed4, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ee4, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ef4, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e08, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e18, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e28, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e38, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e48, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e58, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e68, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e78, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e88, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0e98, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ea8, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0eb8, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ec8, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ed8, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ee8, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0ef8, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d40, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d48, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d50, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d58, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d44, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d4c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d5c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1e00, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e20, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e40, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e60, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e80, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ea0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ec0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ee0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e04, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e24, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e44, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e64, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e84, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ea4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ec4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ee4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e08, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e28, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e48, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e68, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e88, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1ea8, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1ec8, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1ee8, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e0c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e2c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e4c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e6c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e8c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1eac, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ecc, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1eec, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e10, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e30, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e50, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e70, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e90, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1eb0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ed0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ef0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e14, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e34, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e54, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e74, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e94, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1eb4, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1ed4, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1ef4, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1e18, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e38, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e58, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e78, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1e98, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1eb8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ed8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1ef8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x3400, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3404, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3408, 0x00000000);
- nv_mthd(priv, 0xa097, 0x340c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3410, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3414, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3418, 0x00000000);
- nv_mthd(priv, 0xa097, 0x341c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3420, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3424, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3428, 0x00000000);
- nv_mthd(priv, 0xa097, 0x342c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3430, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3434, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3438, 0x00000000);
- nv_mthd(priv, 0xa097, 0x343c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3440, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3444, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3448, 0x00000000);
- nv_mthd(priv, 0xa097, 0x344c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3450, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3454, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3458, 0x00000000);
- nv_mthd(priv, 0xa097, 0x345c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3460, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3464, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3468, 0x00000000);
- nv_mthd(priv, 0xa097, 0x346c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3470, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3474, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3478, 0x00000000);
- nv_mthd(priv, 0xa097, 0x347c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3480, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3484, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3488, 0x00000000);
- nv_mthd(priv, 0xa097, 0x348c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3490, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3494, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3498, 0x00000000);
- nv_mthd(priv, 0xa097, 0x349c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34b0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34b4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34b8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34d4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34d8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34f0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x34fc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3500, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3504, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3508, 0x00000000);
- nv_mthd(priv, 0xa097, 0x350c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3510, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3514, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3518, 0x00000000);
- nv_mthd(priv, 0xa097, 0x351c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3520, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3524, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3528, 0x00000000);
- nv_mthd(priv, 0xa097, 0x352c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3530, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3534, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3538, 0x00000000);
- nv_mthd(priv, 0xa097, 0x353c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3540, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3544, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3548, 0x00000000);
- nv_mthd(priv, 0xa097, 0x354c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3550, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3554, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3558, 0x00000000);
- nv_mthd(priv, 0xa097, 0x355c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3560, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3564, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3568, 0x00000000);
- nv_mthd(priv, 0xa097, 0x356c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3570, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3574, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3578, 0x00000000);
- nv_mthd(priv, 0xa097, 0x357c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3580, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3584, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3588, 0x00000000);
- nv_mthd(priv, 0xa097, 0x358c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3590, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3594, 0x00000000);
- nv_mthd(priv, 0xa097, 0x3598, 0x00000000);
- nv_mthd(priv, 0xa097, 0x359c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35b0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35b4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35b8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35d4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35d8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35f0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x35fc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x030c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1944, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1514, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d68, 0x0000ffff);
- nv_mthd(priv, 0xa097, 0x121c, 0x0fac6881);
- nv_mthd(priv, 0xa097, 0x0fac, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1538, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0fe0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0fe4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0fe8, 0x00000014);
- nv_mthd(priv, 0xa097, 0x0fec, 0x00000040);
- nv_mthd(priv, 0xa097, 0x0ff0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x179c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1228, 0x00000400);
- nv_mthd(priv, 0xa097, 0x122c, 0x00000300);
- nv_mthd(priv, 0xa097, 0x1230, 0x00010001);
- nv_mthd(priv, 0xa097, 0x07f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x15b4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x15cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1534, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0fb0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x15d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x153c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x16b4, 0x00000003);
- nv_mthd(priv, 0xa097, 0x0fbc, 0x0000ffff);
- nv_mthd(priv, 0xa097, 0x0fc0, 0x0000ffff);
- nv_mthd(priv, 0xa097, 0x0fc4, 0x0000ffff);
- nv_mthd(priv, 0xa097, 0x0fc8, 0x0000ffff);
- nv_mthd(priv, 0xa097, 0x0df8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0dfc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1948, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1970, 0x00000001);
- nv_mthd(priv, 0xa097, 0x161c, 0x000009f0);
- nv_mthd(priv, 0xa097, 0x0dcc, 0x00000010);
- nv_mthd(priv, 0xa097, 0x163c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x15e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1160, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1164, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1168, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x116c, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1170, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1174, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1178, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x117c, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1180, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1184, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1188, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x118c, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1190, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1194, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1198, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x119c, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11a0, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11a4, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11a8, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11ac, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11b0, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11b4, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11b8, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11bc, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11c0, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11c4, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11c8, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11cc, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11d0, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11d4, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11d8, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x11dc, 0x25e00040);
- nv_mthd(priv, 0xa097, 0x1880, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1884, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1888, 0x00000000);
- nv_mthd(priv, 0xa097, 0x188c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1890, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1894, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1898, 0x00000000);
- nv_mthd(priv, 0xa097, 0x189c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18b0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18b4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18b8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18d0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18d4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18d8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18e0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18f0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x18fc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x17c8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x17cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x17d0, 0x000000ff);
- nv_mthd(priv, 0xa097, 0x17d4, 0xffffffff);
- nv_mthd(priv, 0xa097, 0x17d8, 0x00000002);
- nv_mthd(priv, 0xa097, 0x17dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x15f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x15f8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1434, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1438, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d74, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0dec, 0x00000001);
- nv_mthd(priv, 0xa097, 0x13a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1318, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1644, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0748, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0de8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1648, 0x00000000);
- nv_mthd(priv, 0xa097, 0x12a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1120, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1124, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1128, 0x00000000);
- nv_mthd(priv, 0xa097, 0x112c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1118, 0x00000000);
- nv_mthd(priv, 0xa097, 0x164c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1658, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1910, 0x00000290);
- nv_mthd(priv, 0xa097, 0x1518, 0x00000000);
- nv_mthd(priv, 0xa097, 0x165c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1520, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1604, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1570, 0x00000000);
- nv_mthd(priv, 0xa097, 0x13b0, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x13b4, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x020c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1670, 0x30201000);
- nv_mthd(priv, 0xa097, 0x1674, 0x70605040);
- nv_mthd(priv, 0xa097, 0x1678, 0xb8a89888);
- nv_mthd(priv, 0xa097, 0x167c, 0xf8e8d8c8);
- nv_mthd(priv, 0xa097, 0x166c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1680, 0x00ffff00);
- nv_mthd(priv, 0xa097, 0x12d0, 0x00000003);
- nv_mthd(priv, 0xa097, 0x12d4, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1684, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1688, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0dac, 0x00001b02);
- nv_mthd(priv, 0xa097, 0x0db0, 0x00001b02);
- nv_mthd(priv, 0xa097, 0x0db4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x168c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x15bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x156c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x187c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1110, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0dc0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0dc4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0dc8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1234, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1690, 0x00000000);
- nv_mthd(priv, 0xa097, 0x12ac, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0790, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0794, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0798, 0x00000000);
- nv_mthd(priv, 0xa097, 0x079c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07a0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x077c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1000, 0x00000010);
- nv_mthd(priv, 0xa097, 0x10fc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1290, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0218, 0x00000010);
- nv_mthd(priv, 0xa097, 0x12d8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x12dc, 0x00000010);
- nv_mthd(priv, 0xa097, 0x0d94, 0x00000001);
- nv_mthd(priv, 0xa097, 0x155c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1560, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1564, 0x00000fff);
- nv_mthd(priv, 0xa097, 0x1574, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1578, 0x00000000);
- nv_mthd(priv, 0xa097, 0x157c, 0x000fffff);
- nv_mthd(priv, 0xa097, 0x1354, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1610, 0x00000012);
- nv_mthd(priv, 0xa097, 0x1608, 0x00000000);
- nv_mthd(priv, 0xa097, 0x160c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x260c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x162c, 0x00000003);
- nv_mthd(priv, 0xa097, 0x0210, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0320, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0324, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0328, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x032c, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0330, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0334, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0338, 0x3f800000);
- nv_mthd(priv, 0xa097, 0x0750, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0760, 0x39291909);
- nv_mthd(priv, 0xa097, 0x0764, 0x79695949);
- nv_mthd(priv, 0xa097, 0x0768, 0xb9a99989);
- nv_mthd(priv, 0xa097, 0x076c, 0xf9e9d9c9);
- nv_mthd(priv, 0xa097, 0x0770, 0x30201000);
- nv_mthd(priv, 0xa097, 0x0774, 0x70605040);
- nv_mthd(priv, 0xa097, 0x0778, 0x00009080);
- nv_mthd(priv, 0xa097, 0x0780, 0x39291909);
- nv_mthd(priv, 0xa097, 0x0784, 0x79695949);
- nv_mthd(priv, 0xa097, 0x0788, 0xb9a99989);
- nv_mthd(priv, 0xa097, 0x078c, 0xf9e9d9c9);
- nv_mthd(priv, 0xa097, 0x07d0, 0x30201000);
- nv_mthd(priv, 0xa097, 0x07d4, 0x70605040);
- nv_mthd(priv, 0xa097, 0x07d8, 0x00009080);
- nv_mthd(priv, 0xa097, 0x037c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0740, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0744, 0x00000000);
- nv_mthd(priv, 0xa097, 0x2600, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1918, 0x00000000);
- nv_mthd(priv, 0xa097, 0x191c, 0x00000900);
- nv_mthd(priv, 0xa097, 0x1920, 0x00000405);
- nv_mthd(priv, 0xa097, 0x1308, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1924, 0x00000000);
- nv_mthd(priv, 0xa097, 0x13ac, 0x00000000);
- nv_mthd(priv, 0xa097, 0x192c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x193c, 0x00002c1c);
- nv_mthd(priv, 0xa097, 0x0d7c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x02c0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1510, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1940, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ff4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0ff8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x194c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1950, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1968, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1590, 0x0000003f);
- nv_mthd(priv, 0xa097, 0x07e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07f0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07f4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x196c, 0x00000011);
- nv_mthd(priv, 0xa097, 0x02e4, 0x0000b001);
- nv_mthd(priv, 0xa097, 0x036c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0370, 0x00000000);
- nv_mthd(priv, 0xa097, 0x197c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0fcc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0fd0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x02d8, 0x00000040);
- nv_mthd(priv, 0xa097, 0x1980, 0x00000080);
- nv_mthd(priv, 0xa097, 0x1504, 0x00000080);
- nv_mthd(priv, 0xa097, 0x1984, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0300, 0x00000001);
- nv_mthd(priv, 0xa097, 0x13a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x12ec, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1310, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1314, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1380, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1384, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1388, 0x00000001);
- nv_mthd(priv, 0xa097, 0x138c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1390, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1394, 0x00000000);
- nv_mthd(priv, 0xa097, 0x139c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1398, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1594, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1598, 0x00000001);
- nv_mthd(priv, 0xa097, 0x159c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x15a0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x15a4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0f54, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f58, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f5c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x19bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f9c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0fa0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x12cc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x12e8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x130c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1360, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1364, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1368, 0x00000000);
- nv_mthd(priv, 0xa097, 0x136c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1370, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1374, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1378, 0x00000000);
- nv_mthd(priv, 0xa097, 0x137c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x133c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1340, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1344, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1348, 0x00000001);
- nv_mthd(priv, 0xa097, 0x134c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1350, 0x00000002);
- nv_mthd(priv, 0xa097, 0x1358, 0x00000001);
- nv_mthd(priv, 0xa097, 0x12e4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x131c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1320, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1324, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1328, 0x00000000);
- nv_mthd(priv, 0xa097, 0x19c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1140, 0x00000000);
- nv_mthd(priv, 0xa097, 0x19c4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x19c8, 0x00001500);
- nv_mthd(priv, 0xa097, 0x135c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x19e0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19e4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19e8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19ec, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19f0, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19f4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19f8, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19fc, 0x00000001);
- nv_mthd(priv, 0xa097, 0x19cc, 0x00000001);
- nv_mthd(priv, 0xa097, 0x15b8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a00, 0x00001111);
- nv_mthd(priv, 0xa097, 0x1a04, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a08, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a0c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a10, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a14, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a18, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1a1c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d6c, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x0d70, 0xffff0000);
- nv_mthd(priv, 0xa097, 0x10f8, 0x00001010);
- nv_mthd(priv, 0xa097, 0x0d80, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d84, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d88, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d8c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0d90, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0da0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07a4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x07a8, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1508, 0x80000000);
- nv_mthd(priv, 0xa097, 0x150c, 0x40000000);
- nv_mthd(priv, 0xa097, 0x1668, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0318, 0x00000008);
- nv_mthd(priv, 0xa097, 0x031c, 0x00000008);
- nv_mthd(priv, 0xa097, 0x0d9c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x0374, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0378, 0x00000020);
- nv_mthd(priv, 0xa097, 0x07dc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x074c, 0x00000055);
- nv_mthd(priv, 0xa097, 0x1420, 0x00000003);
- nv_mthd(priv, 0xa097, 0x17bc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x17c0, 0x00000000);
- nv_mthd(priv, 0xa097, 0x17c4, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1008, 0x00000008);
- nv_mthd(priv, 0xa097, 0x100c, 0x00000040);
- nv_mthd(priv, 0xa097, 0x1010, 0x0000012c);
- nv_mthd(priv, 0xa097, 0x0d60, 0x00000040);
- nv_mthd(priv, 0xa097, 0x075c, 0x00000003);
- nv_mthd(priv, 0xa097, 0x1018, 0x00000020);
- nv_mthd(priv, 0xa097, 0x101c, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1020, 0x00000020);
- nv_mthd(priv, 0xa097, 0x1024, 0x00000001);
- nv_mthd(priv, 0xa097, 0x1444, 0x00000000);
- nv_mthd(priv, 0xa097, 0x1448, 0x00000000);
- nv_mthd(priv, 0xa097, 0x144c, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0360, 0x20164010);
- nv_mthd(priv, 0xa097, 0x0364, 0x00000020);
- nv_mthd(priv, 0xa097, 0x0368, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0de4, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0204, 0x00000006);
- nv_mthd(priv, 0xa097, 0x0208, 0x00000000);
- nv_mthd(priv, 0xa097, 0x02cc, 0x003fffff);
- nv_mthd(priv, 0xa097, 0x02d0, 0x003fffff);
- nv_mthd(priv, 0xa097, 0x1220, 0x00000005);
- nv_mthd(priv, 0xa097, 0x0fdc, 0x00000000);
- nv_mthd(priv, 0xa097, 0x0f98, 0x00400008);
- nv_mthd(priv, 0xa097, 0x1284, 0x08000080);
- nv_mthd(priv, 0xa097, 0x1450, 0x00400008);
- nv_mthd(priv, 0xa097, 0x1454, 0x08000080);
- nv_mthd(priv, 0xa097, 0x0214, 0x00000000);
-}
-
-static void
-nve0_grctx_generate_902d(struct nvc0_graph_priv *priv)
-{
- nv_mthd(priv, 0x902d, 0x0200, 0x000000cf);
- nv_mthd(priv, 0x902d, 0x0204, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0208, 0x00000020);
- nv_mthd(priv, 0x902d, 0x020c, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0210, 0x00000000);
- nv_mthd(priv, 0x902d, 0x0214, 0x00000080);
- nv_mthd(priv, 0x902d, 0x0218, 0x00000100);
- nv_mthd(priv, 0x902d, 0x021c, 0x00000100);
- nv_mthd(priv, 0x902d, 0x0220, 0x00000000);
- nv_mthd(priv, 0x902d, 0x0224, 0x00000000);
- nv_mthd(priv, 0x902d, 0x0230, 0x000000cf);
- nv_mthd(priv, 0x902d, 0x0234, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0238, 0x00000020);
- nv_mthd(priv, 0x902d, 0x023c, 0x00000001);
- nv_mthd(priv, 0x902d, 0x0244, 0x00000080);
- nv_mthd(priv, 0x902d, 0x0248, 0x00000100);
- nv_mthd(priv, 0x902d, 0x024c, 0x00000100);
- nv_mthd(priv, 0x902d, 0x3410, 0x00000000);
-}
-
-static void
-nve0_graph_generate_unk40xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404010, 0x0);
- nv_wr32(priv, 0x404014, 0x0);
- nv_wr32(priv, 0x404018, 0x0);
- nv_wr32(priv, 0x40401c, 0x0);
- nv_wr32(priv, 0x404020, 0x0);
- nv_wr32(priv, 0x404024, 0xe000);
- nv_wr32(priv, 0x404028, 0x0);
- nv_wr32(priv, 0x4040a8, 0x0);
- nv_wr32(priv, 0x4040ac, 0x0);
- nv_wr32(priv, 0x4040b0, 0x0);
- nv_wr32(priv, 0x4040b4, 0x0);
- nv_wr32(priv, 0x4040b8, 0x0);
- nv_wr32(priv, 0x4040bc, 0x0);
- nv_wr32(priv, 0x4040c0, 0x0);
- nv_wr32(priv, 0x4040c4, 0x0);
- nv_wr32(priv, 0x4040c8, 0xf800008f);
- nv_wr32(priv, 0x4040d0, 0x0);
- nv_wr32(priv, 0x4040d4, 0x0);
- nv_wr32(priv, 0x4040d8, 0x0);
- nv_wr32(priv, 0x4040dc, 0x0);
- nv_wr32(priv, 0x4040e0, 0x0);
- nv_wr32(priv, 0x4040e4, 0x0);
- nv_wr32(priv, 0x4040e8, 0x1000);
- nv_wr32(priv, 0x4040f8, 0x0);
- nv_wr32(priv, 0x404130, 0x0);
- nv_wr32(priv, 0x404134, 0x0);
- nv_wr32(priv, 0x404138, 0x20000040);
- nv_wr32(priv, 0x404150, 0x2e);
- nv_wr32(priv, 0x404154, 0x400);
- nv_wr32(priv, 0x404158, 0x200);
- nv_wr32(priv, 0x404164, 0x55);
- nv_wr32(priv, 0x4041a0, 0x0);
- nv_wr32(priv, 0x4041a4, 0x0);
- nv_wr32(priv, 0x4041a8, 0x0);
- nv_wr32(priv, 0x4041ac, 0x0);
- nv_wr32(priv, 0x404200, 0x0);
- nv_wr32(priv, 0x404204, 0x0);
- nv_wr32(priv, 0x404208, 0x0);
- nv_wr32(priv, 0x40420c, 0x0);
-}
-
-static void
-nve0_graph_generate_unk44xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404404, 0x0);
- nv_wr32(priv, 0x404408, 0x0);
- nv_wr32(priv, 0x40440c, 0x0);
- nv_wr32(priv, 0x404410, 0x0);
- nv_wr32(priv, 0x404414, 0x0);
- nv_wr32(priv, 0x404418, 0x0);
- nv_wr32(priv, 0x40441c, 0x0);
- nv_wr32(priv, 0x404420, 0x0);
- nv_wr32(priv, 0x404424, 0x0);
- nv_wr32(priv, 0x404428, 0x0);
- nv_wr32(priv, 0x40442c, 0x0);
- nv_wr32(priv, 0x404430, 0x0);
- nv_wr32(priv, 0x404434, 0x0);
- nv_wr32(priv, 0x404438, 0x0);
- nv_wr32(priv, 0x404460, 0x0);
- nv_wr32(priv, 0x404464, 0x0);
- nv_wr32(priv, 0x404468, 0xffffff);
- nv_wr32(priv, 0x40446c, 0x0);
- nv_wr32(priv, 0x404480, 0x1);
- nv_wr32(priv, 0x404498, 0x1);
-}
-
-static void
-nve0_graph_generate_unk46xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404604, 0x14);
- nv_wr32(priv, 0x404608, 0x0);
- nv_wr32(priv, 0x40460c, 0x3fff);
- nv_wr32(priv, 0x404610, 0x100);
- nv_wr32(priv, 0x404618, 0x0);
- nv_wr32(priv, 0x40461c, 0x0);
- nv_wr32(priv, 0x404620, 0x0);
- nv_wr32(priv, 0x404624, 0x0);
- nv_wr32(priv, 0x40462c, 0x0);
- nv_wr32(priv, 0x404630, 0x0);
- nv_wr32(priv, 0x404640, 0x0);
- nv_wr32(priv, 0x404654, 0x0);
- nv_wr32(priv, 0x404660, 0x0);
- nv_wr32(priv, 0x404678, 0x0);
- nv_wr32(priv, 0x40467c, 0x2);
- nv_wr32(priv, 0x404680, 0x0);
- nv_wr32(priv, 0x404684, 0x0);
- nv_wr32(priv, 0x404688, 0x0);
- nv_wr32(priv, 0x40468c, 0x0);
- nv_wr32(priv, 0x404690, 0x0);
- nv_wr32(priv, 0x404694, 0x0);
- nv_wr32(priv, 0x404698, 0x0);
- nv_wr32(priv, 0x40469c, 0x0);
- nv_wr32(priv, 0x4046a0, 0x7f0080);
- nv_wr32(priv, 0x4046a4, 0x0);
- nv_wr32(priv, 0x4046a8, 0x0);
- nv_wr32(priv, 0x4046ac, 0x0);
- nv_wr32(priv, 0x4046b0, 0x0);
- nv_wr32(priv, 0x4046b4, 0x0);
- nv_wr32(priv, 0x4046b8, 0x0);
- nv_wr32(priv, 0x4046bc, 0x0);
- nv_wr32(priv, 0x4046c0, 0x0);
- nv_wr32(priv, 0x4046c8, 0x0);
- nv_wr32(priv, 0x4046cc, 0x0);
- nv_wr32(priv, 0x4046d0, 0x0);
-}
-
-static void
-nve0_graph_generate_unk47xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x404700, 0x0);
- nv_wr32(priv, 0x404704, 0x0);
- nv_wr32(priv, 0x404708, 0x0);
- nv_wr32(priv, 0x404718, 0x0);
- nv_wr32(priv, 0x40471c, 0x0);
- nv_wr32(priv, 0x404720, 0x0);
- nv_wr32(priv, 0x404724, 0x0);
- nv_wr32(priv, 0x404728, 0x0);
- nv_wr32(priv, 0x40472c, 0x0);
- nv_wr32(priv, 0x404730, 0x0);
- nv_wr32(priv, 0x404734, 0x100);
- nv_wr32(priv, 0x404738, 0x0);
- nv_wr32(priv, 0x40473c, 0x0);
- nv_wr32(priv, 0x404744, 0x0);
- nv_wr32(priv, 0x404748, 0x0);
- nv_wr32(priv, 0x404754, 0x0);
-}
-
-static void
-nve0_graph_generate_unk58xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x405800, 0xf8000bf);
- nv_wr32(priv, 0x405830, 0x2180648);
- nv_wr32(priv, 0x405834, 0x8000000);
- nv_wr32(priv, 0x405838, 0x0);
- nv_wr32(priv, 0x405854, 0x0);
- nv_wr32(priv, 0x405870, 0x1);
- nv_wr32(priv, 0x405874, 0x1);
- nv_wr32(priv, 0x405878, 0x1);
- nv_wr32(priv, 0x40587c, 0x1);
- nv_wr32(priv, 0x405a00, 0x0);
- nv_wr32(priv, 0x405a04, 0x0);
- nv_wr32(priv, 0x405a18, 0x0);
- nv_wr32(priv, 0x405b00, 0x0);
- nv_wr32(priv, 0x405b10, 0x1000);
-}
-
-static void
-nve0_graph_generate_unk60xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x406020, 0x4103c1);
- nv_wr32(priv, 0x406028, 0x1);
- nv_wr32(priv, 0x40602c, 0x1);
- nv_wr32(priv, 0x406030, 0x1);
- nv_wr32(priv, 0x406034, 0x1);
-}
-
-static void
-nve0_graph_generate_unk64xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x4064a8, 0x0);
- nv_wr32(priv, 0x4064ac, 0x3fff);
- nv_wr32(priv, 0x4064b4, 0x0);
- nv_wr32(priv, 0x4064b8, 0x0);
- nv_wr32(priv, 0x4064c0, 0x801a00f0);
- nv_wr32(priv, 0x4064c4, 0x192ffff);
- nv_wr32(priv, 0x4064c8, 0x1800600);
- nv_wr32(priv, 0x4064cc, 0x0);
- nv_wr32(priv, 0x4064d0, 0x0);
- nv_wr32(priv, 0x4064d4, 0x0);
- nv_wr32(priv, 0x4064d8, 0x0);
- nv_wr32(priv, 0x4064dc, 0x0);
- nv_wr32(priv, 0x4064e0, 0x0);
- nv_wr32(priv, 0x4064e4, 0x0);
- nv_wr32(priv, 0x4064e8, 0x0);
- nv_wr32(priv, 0x4064ec, 0x0);
- nv_wr32(priv, 0x4064fc, 0x22a);
-}
-
-static void
-nve0_graph_generate_unk70xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x407040, 0x0);
-}
-
-static void
-nve0_graph_generate_unk78xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x407804, 0x23);
- nv_wr32(priv, 0x40780c, 0xa418820);
- nv_wr32(priv, 0x407810, 0x62080e6);
- nv_wr32(priv, 0x407814, 0x20398a4);
- nv_wr32(priv, 0x407818, 0xe629062);
- nv_wr32(priv, 0x40781c, 0xa418820);
- nv_wr32(priv, 0x407820, 0xe6);
- nv_wr32(priv, 0x4078bc, 0x103);
-}
-
-static void
-nve0_graph_generate_unk80xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x408000, 0x0);
- nv_wr32(priv, 0x408004, 0x0);
- nv_wr32(priv, 0x408008, 0x30);
- nv_wr32(priv, 0x40800c, 0x0);
- nv_wr32(priv, 0x408010, 0x0);
- nv_wr32(priv, 0x408014, 0x69);
- nv_wr32(priv, 0x408018, 0xe100e100);
- nv_wr32(priv, 0x408064, 0x0);
-}
-
-static void
-nve0_graph_generate_unk88xx(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x408800, 0x2802a3c);
- nv_wr32(priv, 0x408804, 0x40);
- nv_wr32(priv, 0x408808, 0x1043e005);
- nv_wr32(priv, 0x408840, 0xb);
- nv_wr32(priv, 0x408900, 0x3080b801);
- nv_wr32(priv, 0x408904, 0x62000001);
- nv_wr32(priv, 0x408908, 0xc8102f);
- nv_wr32(priv, 0x408980, 0x11d);
-}
-
-static void
-nve0_graph_generate_gpc(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x418380, 0x16);
- nv_wr32(priv, 0x418400, 0x38004e00);
- nv_wr32(priv, 0x418404, 0x71e0ffff);
- nv_wr32(priv, 0x41840c, 0x1008);
- nv_wr32(priv, 0x418410, 0xfff0fff);
- nv_wr32(priv, 0x418414, 0x2200fff);
- nv_wr32(priv, 0x418450, 0x0);
- nv_wr32(priv, 0x418454, 0x0);
- nv_wr32(priv, 0x418458, 0x0);
- nv_wr32(priv, 0x41845c, 0x0);
- nv_wr32(priv, 0x418460, 0x0);
- nv_wr32(priv, 0x418464, 0x0);
- nv_wr32(priv, 0x418468, 0x1);
- nv_wr32(priv, 0x41846c, 0x0);
- nv_wr32(priv, 0x418470, 0x0);
- nv_wr32(priv, 0x418600, 0x1f);
- nv_wr32(priv, 0x418684, 0xf);
- nv_wr32(priv, 0x418700, 0x2);
- nv_wr32(priv, 0x418704, 0x80);
- nv_wr32(priv, 0x418708, 0x0);
- nv_wr32(priv, 0x41870c, 0x0);
- nv_wr32(priv, 0x418710, 0x0);
- nv_wr32(priv, 0x418800, 0x7006860a);
- nv_wr32(priv, 0x418808, 0x0);
- nv_wr32(priv, 0x41880c, 0x0);
- nv_wr32(priv, 0x418810, 0x0);
- nv_wr32(priv, 0x418828, 0x44);
- nv_wr32(priv, 0x418830, 0x10000001);
- nv_wr32(priv, 0x4188d8, 0x8);
- nv_wr32(priv, 0x4188e0, 0x1000000);
- nv_wr32(priv, 0x4188e8, 0x0);
- nv_wr32(priv, 0x4188ec, 0x0);
- nv_wr32(priv, 0x4188f0, 0x0);
- nv_wr32(priv, 0x4188f4, 0x0);
- nv_wr32(priv, 0x4188f8, 0x0);
- nv_wr32(priv, 0x4188fc, 0x20100018);
- nv_wr32(priv, 0x41891c, 0xff00ff);
- nv_wr32(priv, 0x418924, 0x0);
- nv_wr32(priv, 0x418928, 0xffff00);
- nv_wr32(priv, 0x41892c, 0xff00);
- nv_wr32(priv, 0x418a00, 0x0);
- nv_wr32(priv, 0x418a04, 0x0);
- nv_wr32(priv, 0x418a08, 0x0);
- nv_wr32(priv, 0x418a0c, 0x10000);
- nv_wr32(priv, 0x418a10, 0x0);
- nv_wr32(priv, 0x418a14, 0x0);
- nv_wr32(priv, 0x418a18, 0x0);
- nv_wr32(priv, 0x418a20, 0x0);
- nv_wr32(priv, 0x418a24, 0x0);
- nv_wr32(priv, 0x418a28, 0x0);
- nv_wr32(priv, 0x418a2c, 0x10000);
- nv_wr32(priv, 0x418a30, 0x0);
- nv_wr32(priv, 0x418a34, 0x0);
- nv_wr32(priv, 0x418a38, 0x0);
- nv_wr32(priv, 0x418a40, 0x0);
- nv_wr32(priv, 0x418a44, 0x0);
- nv_wr32(priv, 0x418a48, 0x0);
- nv_wr32(priv, 0x418a4c, 0x10000);
- nv_wr32(priv, 0x418a50, 0x0);
- nv_wr32(priv, 0x418a54, 0x0);
- nv_wr32(priv, 0x418a58, 0x0);
- nv_wr32(priv, 0x418a60, 0x0);
- nv_wr32(priv, 0x418a64, 0x0);
- nv_wr32(priv, 0x418a68, 0x0);
- nv_wr32(priv, 0x418a6c, 0x10000);
- nv_wr32(priv, 0x418a70, 0x0);
- nv_wr32(priv, 0x418a74, 0x0);
- nv_wr32(priv, 0x418a78, 0x0);
- nv_wr32(priv, 0x418a80, 0x0);
- nv_wr32(priv, 0x418a84, 0x0);
- nv_wr32(priv, 0x418a88, 0x0);
- nv_wr32(priv, 0x418a8c, 0x10000);
- nv_wr32(priv, 0x418a90, 0x0);
- nv_wr32(priv, 0x418a94, 0x0);
- nv_wr32(priv, 0x418a98, 0x0);
- nv_wr32(priv, 0x418aa0, 0x0);
- nv_wr32(priv, 0x418aa4, 0x0);
- nv_wr32(priv, 0x418aa8, 0x0);
- nv_wr32(priv, 0x418aac, 0x10000);
- nv_wr32(priv, 0x418ab0, 0x0);
- nv_wr32(priv, 0x418ab4, 0x0);
- nv_wr32(priv, 0x418ab8, 0x0);
- nv_wr32(priv, 0x418ac0, 0x0);
- nv_wr32(priv, 0x418ac4, 0x0);
- nv_wr32(priv, 0x418ac8, 0x0);
- nv_wr32(priv, 0x418acc, 0x10000);
- nv_wr32(priv, 0x418ad0, 0x0);
- nv_wr32(priv, 0x418ad4, 0x0);
- nv_wr32(priv, 0x418ad8, 0x0);
- nv_wr32(priv, 0x418ae0, 0x0);
- nv_wr32(priv, 0x418ae4, 0x0);
- nv_wr32(priv, 0x418ae8, 0x0);
- nv_wr32(priv, 0x418aec, 0x10000);
- nv_wr32(priv, 0x418af0, 0x0);
- nv_wr32(priv, 0x418af4, 0x0);
- nv_wr32(priv, 0x418af8, 0x0);
- nv_wr32(priv, 0x418b00, 0x6);
- nv_wr32(priv, 0x418b08, 0xa418820);
- nv_wr32(priv, 0x418b0c, 0x62080e6);
- nv_wr32(priv, 0x418b10, 0x20398a4);
- nv_wr32(priv, 0x418b14, 0xe629062);
- nv_wr32(priv, 0x418b18, 0xa418820);
- nv_wr32(priv, 0x418b1c, 0xe6);
- nv_wr32(priv, 0x418bb8, 0x103);
- nv_wr32(priv, 0x418c08, 0x1);
- nv_wr32(priv, 0x418c10, 0x0);
- nv_wr32(priv, 0x418c14, 0x0);
- nv_wr32(priv, 0x418c18, 0x0);
- nv_wr32(priv, 0x418c1c, 0x0);
- nv_wr32(priv, 0x418c20, 0x0);
- nv_wr32(priv, 0x418c24, 0x0);
- nv_wr32(priv, 0x418c28, 0x0);
- nv_wr32(priv, 0x418c2c, 0x0);
- nv_wr32(priv, 0x418c40, 0xffffffff);
- nv_wr32(priv, 0x418c6c, 0x1);
- nv_wr32(priv, 0x418c80, 0x20200004);
- nv_wr32(priv, 0x418c8c, 0x1);
- nv_wr32(priv, 0x419000, 0x780);
- nv_wr32(priv, 0x419004, 0x0);
- nv_wr32(priv, 0x419008, 0x0);
- nv_wr32(priv, 0x419014, 0x4);
-}
-
-static void
-nve0_graph_generate_tpc(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x419848, 0x0);
- nv_wr32(priv, 0x419864, 0x129);
- nv_wr32(priv, 0x419888, 0x0);
- nv_wr32(priv, 0x419a00, 0xf0);
- nv_wr32(priv, 0x419a04, 0x1);
- nv_wr32(priv, 0x419a08, 0x21);
- nv_wr32(priv, 0x419a0c, 0x20000);
- nv_wr32(priv, 0x419a10, 0x0);
- nv_wr32(priv, 0x419a14, 0x200);
- nv_wr32(priv, 0x419a1c, 0xc000);
- nv_wr32(priv, 0x419a20, 0x800);
- nv_wr32(priv, 0x419a30, 0x1);
- nv_wr32(priv, 0x419ac4, 0x37f440);
- nv_wr32(priv, 0x419c00, 0xa);
- nv_wr32(priv, 0x419c04, 0x80000006);
- nv_wr32(priv, 0x419c08, 0x2);
- nv_wr32(priv, 0x419c20, 0x0);
- nv_wr32(priv, 0x419c24, 0x84210);
- nv_wr32(priv, 0x419c28, 0x3efbefbe);
- nv_wr32(priv, 0x419ce8, 0x0);
- nv_wr32(priv, 0x419cf4, 0x3203);
- nv_wr32(priv, 0x419e04, 0x0);
- nv_wr32(priv, 0x419e08, 0x0);
- nv_wr32(priv, 0x419e0c, 0x0);
- nv_wr32(priv, 0x419e10, 0x402);
- nv_wr32(priv, 0x419e44, 0x13eff2);
- nv_wr32(priv, 0x419e48, 0x0);
- nv_wr32(priv, 0x419e4c, 0x7f);
- nv_wr32(priv, 0x419e50, 0x0);
- nv_wr32(priv, 0x419e54, 0x0);
- nv_wr32(priv, 0x419e58, 0x0);
- nv_wr32(priv, 0x419e5c, 0x0);
- nv_wr32(priv, 0x419e60, 0x0);
- nv_wr32(priv, 0x419e64, 0x0);
- nv_wr32(priv, 0x419e68, 0x0);
- nv_wr32(priv, 0x419e6c, 0x0);
- nv_wr32(priv, 0x419e70, 0x0);
- nv_wr32(priv, 0x419e74, 0x0);
- nv_wr32(priv, 0x419e78, 0x0);
- nv_wr32(priv, 0x419e7c, 0x0);
- nv_wr32(priv, 0x419e80, 0x0);
- nv_wr32(priv, 0x419e84, 0x0);
- nv_wr32(priv, 0x419e88, 0x0);
- nv_wr32(priv, 0x419e8c, 0x0);
- nv_wr32(priv, 0x419e90, 0x0);
- nv_wr32(priv, 0x419e94, 0x0);
- nv_wr32(priv, 0x419e98, 0x0);
- nv_wr32(priv, 0x419eac, 0x1fcf);
- nv_wr32(priv, 0x419eb0, 0xd3f);
- nv_wr32(priv, 0x419ec8, 0x1304f);
- nv_wr32(priv, 0x419f30, 0x0);
- nv_wr32(priv, 0x419f34, 0x0);
- nv_wr32(priv, 0x419f38, 0x0);
- nv_wr32(priv, 0x419f3c, 0x0);
- nv_wr32(priv, 0x419f40, 0x0);
- nv_wr32(priv, 0x419f44, 0x0);
- nv_wr32(priv, 0x419f48, 0x0);
- nv_wr32(priv, 0x419f4c, 0x0);
- nv_wr32(priv, 0x419f58, 0x0);
- nv_wr32(priv, 0x419f78, 0xb);
-}
-
-static void
-nve0_graph_generate_tpcunk(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x41be24, 0x6);
- nv_wr32(priv, 0x41bec0, 0x12180000);
- nv_wr32(priv, 0x41bec4, 0x37f7f);
- nv_wr32(priv, 0x41bee4, 0x6480430);
- nv_wr32(priv, 0x41bf00, 0xa418820);
- nv_wr32(priv, 0x41bf04, 0x62080e6);
- nv_wr32(priv, 0x41bf08, 0x20398a4);
- nv_wr32(priv, 0x41bf0c, 0xe629062);
- nv_wr32(priv, 0x41bf10, 0xa418820);
- nv_wr32(priv, 0x41bf14, 0xe6);
- nv_wr32(priv, 0x41bfd0, 0x900103);
- nv_wr32(priv, 0x41bfe0, 0x400001);
- nv_wr32(priv, 0x41bfe4, 0x0);
-}
-
-int
-nve0_grctx_generate(struct nvc0_graph_priv *priv)
-{
- struct nvc0_grctx info;
- int ret, i, gpc, tpc, id;
- u32 data[6] = {}, data2[2] = {}, tmp;
- u32 tpc_set = 0, tpc_mask = 0;
- u32 magic[GPC_MAX][2], offset;
- u8 tpcnr[GPC_MAX], a, b;
- u8 shift, ntpcv;
-
- ret = nvc0_grctx_init(priv, &info);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x400204, 0x00000000);
- nv_wr32(priv, 0x400208, 0x00000000);
-
- nve0_graph_generate_unk40xx(priv);
- nve0_graph_generate_unk44xx(priv);
- nve0_graph_generate_unk46xx(priv);
- nve0_graph_generate_unk47xx(priv);
- nve0_graph_generate_unk58xx(priv);
- nve0_graph_generate_unk60xx(priv);
- nve0_graph_generate_unk64xx(priv);
- nve0_graph_generate_unk70xx(priv);
- nve0_graph_generate_unk78xx(priv);
- nve0_graph_generate_unk80xx(priv);
- nve0_graph_generate_unk88xx(priv);
- nve0_graph_generate_gpc(priv);
- nve0_graph_generate_tpc(priv);
- nve0_graph_generate_tpcunk(priv);
-
- nv_wr32(priv, 0x404154, 0x0);
-
- mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
- mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
- mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
- mmio_list(0x40800c, 0x00000000, 8, 1);
- mmio_list(0x408010, 0x80000000, 0, 0);
- mmio_list(0x419004, 0x00000000, 8, 1);
- mmio_list(0x419008, 0x00000000, 0, 0);
- mmio_list(0x4064cc, 0x80000000, 0, 0);
- mmio_list(0x408004, 0x00000000, 8, 0);
- mmio_list(0x408008, 0x80000030, 0, 0);
- mmio_list(0x418808, 0x00000000, 8, 0);
- mmio_list(0x41880c, 0x80000030, 0, 0);
- mmio_list(0x4064c8, 0x01800600, 0, 0);
- mmio_list(0x418810, 0x80000000, 12, 2);
- mmio_list(0x419848, 0x10000000, 12, 2);
- mmio_list(0x405830, 0x02180648, 0, 0);
- mmio_list(0x4064c4, 0x0192ffff, 0, 0);
- for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
- u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
- u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
- magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset;
- magic[gpc][1] = 0x00000000 | (magic1 << 16);
- offset += 0x0324 * priv->tpc_nr[gpc];
- }
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
- mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
- offset += 0x07ff * priv->tpc_nr[gpc];
- }
- mmio_list(0x17e91c, 0x06060609, 0, 0);
- mmio_list(0x17e920, 0x00090a05, 0, 0);
-
- nv_wr32(priv, 0x418c6c, 0x1);
- nv_wr32(priv, 0x41980c, 0x10);
- nv_wr32(priv, 0x41be08, 0x4);
- nv_wr32(priv, 0x4064c0, 0x801a00f0);
- nv_wr32(priv, 0x405800, 0xf8000bf);
- nv_wr32(priv, 0x419c00, 0xa);
-
- for (tpc = 0, id = 0; tpc < 4; tpc++) {
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- if (tpc < priv->tpc_nr[gpc]) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0698), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x04e8), id);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0088), id++);
- }
-
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
- }
- }
-
- tmp = 0;
- for (i = 0; i < priv->gpc_nr; i++)
- tmp |= priv->tpc_nr[i] << (i * 4);
- nv_wr32(priv, 0x406028, tmp);
- nv_wr32(priv, 0x405870, tmp);
-
- nv_wr32(priv, 0x40602c, 0x0);
- nv_wr32(priv, 0x405874, 0x0);
- nv_wr32(priv, 0x406030, 0x0);
- nv_wr32(priv, 0x405878, 0x0);
- nv_wr32(priv, 0x406034, 0x0);
- nv_wr32(priv, 0x40587c, 0x0);
-
- /* calculate first set of magics */
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
- gpc = -1;
- for (tpc = 0; tpc < priv->tpc_total; tpc++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpcnr[gpc]--;
-
- data[tpc / 6] |= gpc << ((tpc % 6) * 5);
- }
-
- for (; tpc < 32; tpc++)
- data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
- /* and the second... */
- shift = 0;
- ntpcv = priv->tpc_total;
- while (!(ntpcv & (1 << 4))) {
- ntpcv <<= 1;
- shift++;
- }
-
- data2[0] = ntpcv << 16;
- data2[0] |= shift << 21;
- data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
- data2[0] |= priv->tpc_total << 8;
- data2[0] |= priv->magic_not_rop_nr;
- for (i = 1; i < 7; i++)
- data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
- /* and write it all the various parts of PGRAPH */
- nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
- nv_wr32(priv, 0x41bfd0, data2[0]);
- nv_wr32(priv, 0x41bfe4, data2[1]);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
-
- nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-
-
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (gpc = 0; gpc < priv->gpc_nr; gpc++)
- tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
-
- for (i = 0, gpc = -1, b = -1; i < 32; i++) {
- a = (i * (priv->tpc_total - 1)) / 32;
- if (a != b) {
- b = a;
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- tpc_set |= 1 << ((gpc * 8) + tpc);
- }
-
- nv_wr32(priv, 0x406800 + (i * 0x20), tpc_set);
- nv_wr32(priv, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask);
- }
-
- for (i = 0; i < 8; i++)
- nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-
- nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
- if (priv->gpc_nr == 1) {
- nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
- nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
- } else {
- nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
- nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
- }
- nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
-
- nve0_grctx_generate_icmd(priv);
- nve0_grctx_generate_a097(priv);
- nve0_grctx_generate_902d(priv);
-
- nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
- nv_wr32(priv, 0x418800, 0x7026860a); //XXX
- nv_wr32(priv, 0x41be10, 0x00bb8bc7); //XXX
- return nvc0_grctx_fini(&info);
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
new file mode 100644
index 000000000000..e2de73ee5eee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
@@ -0,0 +1,1018 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+struct nvc0_graph_init
+nve4_grctx_init_icmd[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000383, 1, 0x01, 0x00000011 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 1, 0x01, 0x00000001 },
+ { 0x000639, 1, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x003fffff },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00400008 },
+ { 0x000841, 1, 0x01, 0x08000080 },
+ { 0x000842, 1, 0x01, 0x00400008 },
+ { 0x000843, 1, 0x01, 0x08000080 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 1, 0x01, 0x00000001 },
+ { 0x000795, 2, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 1, 0x01, 0x00000001 },
+ { 0x0007a4, 2, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000008 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_a097[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00000fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x000fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00260c, 1, 0x04, 0x00000000 },
+ { 0x0007ac, 1, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ { 0x00036c, 2, 0x04, 0x00000000 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 1, 0x04, 0x00000000 },
+ { 0x001320, 3, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x0007a4, 2, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x000374, 1, 0x04, 0x00000000 },
+ { 0x000378, 1, 0x04, 0x00000020 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 2, 0x04, 0x003fffff },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00400008 },
+ { 0x001284, 1, 0x04, 0x08000080 },
+ { 0x001450, 1, 0x04, 0x00400008 },
+ { 0x001454, 1, 0x04, 0x08000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk40xx[] = {
+ { 0x404010, 5, 0x04, 0x00000000 },
+ { 0x404024, 1, 0x04, 0x0000e000 },
+ { 0x404028, 1, 0x04, 0x00000000 },
+ { 0x4040a8, 1, 0x04, 0x00000000 },
+ { 0x4040ac, 7, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf800008f },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 1, 0x04, 0x00000000 },
+ { 0x404134, 1, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x4041a0, 4, 0x04, 0x00000000 },
+ { 0x404200, 4, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk46xx[] = {
+ { 0x404604, 1, 0x04, 0x00000014 },
+ { 0x404608, 1, 0x04, 0x00000000 },
+ { 0x40460c, 1, 0x04, 0x00003fff },
+ { 0x404610, 1, 0x04, 0x00000100 },
+ { 0x404618, 4, 0x04, 0x00000000 },
+ { 0x40462c, 2, 0x04, 0x00000000 },
+ { 0x404640, 1, 0x04, 0x00000000 },
+ { 0x404654, 1, 0x04, 0x00000000 },
+ { 0x404660, 1, 0x04, 0x00000000 },
+ { 0x404678, 1, 0x04, 0x00000000 },
+ { 0x40467c, 1, 0x04, 0x00000002 },
+ { 0x404680, 8, 0x04, 0x00000000 },
+ { 0x4046a0, 1, 0x04, 0x007f0080 },
+ { 0x4046a4, 8, 0x04, 0x00000000 },
+ { 0x4046c8, 3, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk47xx[] = {
+ { 0x404700, 3, 0x04, 0x00000000 },
+ { 0x404718, 7, 0x04, 0x00000000 },
+ { 0x404734, 1, 0x04, 0x00000100 },
+ { 0x404738, 2, 0x04, 0x00000000 },
+ { 0x404744, 2, 0x04, 0x00000000 },
+ { 0x404754, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk58xx[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180648 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk5bxx[] = {
+ { 0x405b00, 1, 0x04, 0x00000000 },
+ { 0x405b10, 1, 0x04, 0x00001000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk60xx[] = {
+ { 0x406020, 1, 0x04, 0x004103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk64xx[] = {
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 2, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x801a00f0 },
+ { 0x4064c4, 1, 0x04, 0x0192ffff },
+ { 0x4064c8, 1, 0x04, 0x01800600 },
+ { 0x4064cc, 9, 0x04, 0x00000000 },
+ { 0x4064fc, 1, 0x04, 0x0000022a },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk70xx[] = {
+ { 0x407040, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_grctx_init_unk80xx[] = {
+ { 0x408000, 2, 0x04, 0x00000000 },
+ { 0x408008, 1, 0x04, 0x00000030 },
+ { 0x40800c, 2, 0x04, 0x00000000 },
+ { 0x408014, 1, 0x04, 0x00000069 },
+ { 0x408018, 1, 0x04, 0xe100e100 },
+ { 0x408064, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_rop[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1043e005 },
+ { 0x408840, 1, 0x04, 0x0000000b },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_gpc_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x02200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 3, 0x04, 0x00000000 },
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00000044 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100018 },
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ { 0x418b00, 1, 0x04, 0x00000006 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c40, 1, 0x04, 0xffffffff },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_tpc[] = {
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000000f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000021 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x0000c000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419a30, 1, 0x04, 0x00000001 },
+ { 0x419ac4, 1, 0x04, 0x0037f440 },
+ { 0x419c00, 1, 0x04, 0x0000000a },
+ { 0x419c04, 1, 0x04, 0x80000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00003203 },
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000402 },
+ { 0x419e44, 1, 0x04, 0x0013eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 19, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x00001f8f },
+ { 0x419eb0, 1, 0x04, 0x00000d3f },
+ { 0x419ec8, 1, 0x04, 0x0001304f },
+ { 0x419f30, 8, 0x04, 0x00000000 },
+ { 0x419f58, 1, 0x04, 0x00000000 },
+ { 0x419f70, 1, 0x04, 0x00000000 },
+ { 0x419f78, 1, 0x04, 0x0000000b },
+ { 0x419f7c, 1, 0x04, 0x0000027a },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_grctx_init_unk[] = {
+ { 0x41be24, 1, 0x04, 0x00000006 },
+ { 0x41bec0, 1, 0x04, 0x12180000 },
+ { 0x41bec4, 1, 0x04, 0x00037f7f },
+ { 0x41bee4, 1, 0x04, 0x06480430 },
+ { 0x41bf00, 1, 0x04, 0x0a418820 },
+ { 0x41bf04, 1, 0x04, 0x062080e6 },
+ { 0x41bf08, 1, 0x04, 0x020398a4 },
+ { 0x41bf0c, 1, 0x04, 0x0e629062 },
+ { 0x41bf10, 1, 0x04, 0x0a418820 },
+ { 0x41bf14, 1, 0x04, 0x000000e6 },
+ { 0x41bfd0, 1, 0x04, 0x00900103 },
+ { 0x41bfe0, 1, 0x04, 0x00400001 },
+ { 0x41bfe4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static void
+nve4_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+ u32 magic[GPC_MAX][2];
+ u32 offset;
+ int gpc;
+
+ mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+ mmio_list(0x40800c, 0x00000000, 8, 1);
+ mmio_list(0x408010, 0x80000000, 0, 0);
+ mmio_list(0x419004, 0x00000000, 8, 1);
+ mmio_list(0x419008, 0x00000000, 0, 0);
+ mmio_list(0x4064cc, 0x80000000, 0, 0);
+ mmio_list(0x408004, 0x00000000, 8, 0);
+ mmio_list(0x408008, 0x80000030, 0, 0);
+ mmio_list(0x418808, 0x00000000, 8, 0);
+ mmio_list(0x41880c, 0x80000030, 0, 0);
+ mmio_list(0x4064c8, 0x01800600, 0, 0);
+ mmio_list(0x418810, 0x80000000, 12, 2);
+ mmio_list(0x419848, 0x10000000, 12, 2);
+
+ mmio_list(0x405830, 0x02180648, 0, 0);
+ mmio_list(0x4064c4, 0x0192ffff, 0, 0);
+
+ for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+ u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+ u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
+ magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset;
+ magic[gpc][1] = 0x00000000 | (magic1 << 16);
+ offset += 0x0324 * priv->tpc_nr[gpc];
+ }
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+ mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+ offset += 0x07ff * priv->tpc_nr[gpc];
+ }
+
+ mmio_list(0x17e91c, 0x06060609, 0, 0);
+ mmio_list(0x17e920, 0x00090a05, 0, 0);
+}
+
+void
+nve4_grctx_generate_unkn(struct nvc0_graph_priv *priv)
+{
+ nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+ nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+ nv_mask(priv, 0x41be08, 0x00000004, 0x00000004);
+ nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+ nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+ nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+void
+nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
+{
+ u32 data[6] = {}, data2[2] = {};
+ u8 tpcnr[GPC_MAX];
+ u8 shift, ntpcv;
+ int gpc, tpc, i;
+
+ /* calculate first set of magics */
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+
+ data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+ }
+
+ for (; tpc < 32; tpc++)
+ data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+ /* and the second... */
+ shift = 0;
+ ntpcv = priv->tpc_total;
+ while (!(ntpcv & (1 << 4))) {
+ ntpcv <<= 1;
+ shift++;
+ }
+
+ data2[0] = (ntpcv << 16);
+ data2[0] |= (shift << 21);
+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+ for (i = 1; i < 7; i++)
+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+ /* GPC_BROADCAST */
+ nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+ /* GPC_BROADCAST.TP_BROADCAST */
+ nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr | data2[0]);
+ nv_wr32(priv, 0x41bfe4, data2[1]);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
+
+ /* UNK78xx */
+ nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+ struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ int i;
+
+ nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
+
+ for (i = 0; oclass->hub[i]; i++)
+ nvc0_graph_mmio(priv, oclass->hub[i]);
+ for (i = 0; oclass->gpc[i]; i++)
+ nvc0_graph_mmio(priv, oclass->gpc[i]);
+
+ nv_wr32(priv, 0x404154, 0x00000000);
+
+ oclass->mods(priv, info);
+ oclass->unkn(priv);
+
+ nvc0_grctx_generate_tpcid(priv);
+ nvc0_grctx_generate_r406028(priv);
+ nve4_grctx_generate_r418bb8(priv);
+ nvc0_grctx_generate_r406800(priv);
+
+ for (i = 0; i < 8; i++)
+ nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+ nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+ if (priv->gpc_nr == 1) {
+ nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+ nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+ } else {
+ nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+ nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+ }
+ nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
+
+ nvc0_graph_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ nvc0_graph_mthd(priv, oclass->mthd);
+ nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
+
+ nv_mask(priv, 0x418800, 0x00200000, 0x00200000);
+ nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
+}
+
+static struct nvc0_graph_init *
+nve4_grctx_init_hub[] = {
+ nvc0_grctx_init_base,
+ nve4_grctx_init_unk40xx,
+ nvc0_grctx_init_unk44xx,
+ nve4_grctx_init_unk46xx,
+ nve4_grctx_init_unk47xx,
+ nve4_grctx_init_unk58xx,
+ nve4_grctx_init_unk5bxx,
+ nve4_grctx_init_unk60xx,
+ nve4_grctx_init_unk64xx,
+ nve4_grctx_init_unk70xx,
+ nvc0_grctx_init_unk78xx,
+ nve4_grctx_init_unk80xx,
+ nve4_grctx_init_rop,
+ NULL
+};
+
+struct nvc0_graph_init *
+nve4_grctx_init_gpc[] = {
+ nve4_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nve4_grctx_init_tpc,
+ nve4_grctx_init_unk,
+ NULL
+};
+
+static struct nvc0_graph_mthd
+nve4_grctx_init_mthd[] = {
+ { 0xa097, nve4_grctx_init_a097, },
+ { 0x902d, nvc0_grctx_init_902d, },
+ { 0x902d, nvc0_grctx_init_mthd_magic, },
+ {}
+};
+
+struct nouveau_oclass *
+nve4_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xe4),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nve4_grctx_generate_main,
+ .mods = nve4_grctx_generate_mods,
+ .unkn = nve4_grctx_generate_unkn,
+ .hub = nve4_grctx_init_hub,
+ .gpc = nve4_grctx_init_gpc,
+ .icmd = nve4_grctx_init_icmd,
+ .mthd = nve4_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
new file mode 100644
index 000000000000..dcb2ebb8c29d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk40xx[] = {
+ { 0x404004, 8, 0x04, 0x00000000 },
+ { 0x404024, 1, 0x04, 0x0000e000 },
+ { 0x404028, 8, 0x04, 0x00000000 },
+ { 0x4040a8, 8, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf800008f },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404100, 10, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x40417c, 2, 0x04, 0x00000000 },
+ { 0x4041a0, 4, 0x04, 0x00000000 },
+ { 0x404200, 1, 0x04, 0x0000a197 },
+ { 0x404204, 1, 0x04, 0x0000a1c0 },
+ { 0x404208, 1, 0x04, 0x0000a140 },
+ { 0x40420c, 1, 0x04, 0x0000902d },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk44xx[] = {
+ { 0x404404, 12, 0x04, 0x00000000 },
+ { 0x404438, 1, 0x04, 0x00000000 },
+ { 0x404460, 2, 0x04, 0x00000000 },
+ { 0x404468, 1, 0x04, 0x00ffffff },
+ { 0x40446c, 1, 0x04, 0x00000000 },
+ { 0x404480, 1, 0x04, 0x00000001 },
+ { 0x404498, 1, 0x04, 0x00000001 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk5bxx[] = {
+ { 0x405b00, 1, 0x04, 0x00000000 },
+ { 0x405b10, 1, 0x04, 0x00001000 },
+ { 0x405b20, 1, 0x04, 0x04000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk60xx[] = {
+ { 0x406020, 1, 0x04, 0x034103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk64xx[] = {
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b0, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x802000f0 },
+ { 0x4064c4, 1, 0x04, 0x0192ffff },
+ { 0x4064c8, 1, 0x04, 0x018007c0 },
+ { 0x4064cc, 9, 0x04, 0x00000000 },
+ { 0x4064fc, 1, 0x04, 0x0000022a },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk88xx[] = {
+ { 0x408800, 1, 0x04, 0x12802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1003e005 },
+ { 0x408840, 1, 0x04, 0x0000000b },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_gpc_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x02200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 3, 0x04, 0x00000000 },
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 1, 0x04, 0x00000000 },
+ { 0x41880c, 1, 0x04, 0x00000030 },
+ { 0x418810, 1, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00000044 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100018 },
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ { 0x418b00, 1, 0x04, 0x00000006 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c40, 1, 0x04, 0xffffffff },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ { 0x418d24, 1, 0x04, 0x00000000 },
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_tpc[] = {
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ { 0x419a00, 1, 0x04, 0x000000f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000021 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x0000c000 },
+ { 0x419a20, 1, 0x04, 0x00020800 },
+ { 0x419a30, 1, 0x04, 0x00000001 },
+ { 0x419ac4, 1, 0x04, 0x0037f440 },
+ { 0x419c00, 1, 0x04, 0x0000001a },
+ { 0x419c04, 1, 0x04, 0x80000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000203 },
+ { 0x419e04, 1, 0x04, 0x00000000 },
+ { 0x419e08, 1, 0x04, 0x0000001d },
+ { 0x419e0c, 1, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00001c02 },
+ { 0x419e44, 1, 0x04, 0x0013eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 2, 0x04, 0x00000000 },
+ { 0x419e58, 1, 0x04, 0x00000001 },
+ { 0x419e5c, 3, 0x04, 0x00000000 },
+ { 0x419e68, 1, 0x04, 0x00000002 },
+ { 0x419e6c, 12, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x00001fcf },
+ { 0x419eb0, 1, 0x04, 0x0db00da0 },
+ { 0x419eb8, 1, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0001304f },
+ { 0x419f30, 4, 0x04, 0x00000000 },
+ { 0x419f40, 1, 0x04, 0x00000018 },
+ { 0x419f44, 3, 0x04, 0x00000000 },
+ { 0x419f58, 1, 0x04, 0x00000000 },
+ { 0x419f70, 1, 0x04, 0x00007300 },
+ { 0x419f78, 1, 0x04, 0x000000eb },
+ { 0x419f7c, 1, 0x04, 0x00000404 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_grctx_init_unk[] = {
+ { 0x41be24, 1, 0x04, 0x00000006 },
+ { 0x41bec0, 1, 0x04, 0x10000000 },
+ { 0x41bec4, 1, 0x04, 0x00037f7f },
+ { 0x41bee4, 1, 0x04, 0x00000000 },
+ { 0x41bf00, 1, 0x04, 0x0a418820 },
+ { 0x41bf04, 1, 0x04, 0x062080e6 },
+ { 0x41bf08, 1, 0x04, 0x020398a4 },
+ { 0x41bf0c, 1, 0x04, 0x0e629062 },
+ { 0x41bf10, 1, 0x04, 0x0a418820 },
+ { 0x41bf14, 1, 0x04, 0x000000e6 },
+ { 0x41bfd0, 1, 0x04, 0x00900103 },
+ { 0x41bfe0, 1, 0x04, 0x00400001 },
+ { 0x41bfe4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static void
+nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+ u32 magic[GPC_MAX][4];
+ u32 offset;
+ int gpc;
+
+ mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+ mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+ mmio_list(0x40800c, 0x00000000, 8, 1);
+ mmio_list(0x408010, 0x80000000, 0, 0);
+ mmio_list(0x419004, 0x00000000, 8, 1);
+ mmio_list(0x419008, 0x00000000, 0, 0);
+ mmio_list(0x4064cc, 0x80000000, 0, 0);
+ mmio_list(0x408004, 0x00000000, 8, 0);
+ mmio_list(0x408008, 0x80000030, 0, 0);
+ mmio_list(0x418808, 0x00000000, 8, 0);
+ mmio_list(0x41880c, 0x80000030, 0, 0);
+ mmio_list(0x4064c8, 0x01800600, 0, 0);
+ mmio_list(0x418810, 0x80000000, 12, 2);
+ mmio_list(0x419848, 0x10000000, 12, 2);
+
+ mmio_list(0x405830, 0x02180648, 0, 0);
+ mmio_list(0x4064c4, 0x0192ffff, 0, 0);
+
+ for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+ u16 magic0 = 0x0218 * (priv->tpc_nr[gpc] - 1);
+ u16 magic1 = 0x0648 * (priv->tpc_nr[gpc] - 1);
+ u16 magic2 = 0x0218;
+ u16 magic3 = 0x0648;
+ magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset;
+ magic[gpc][1] = 0x00000000 | (magic1 << 16);
+ offset += 0x0324 * (priv->tpc_nr[gpc] - 1);;
+ magic[gpc][2] = 0x10000000 | (magic2 << 16) | offset;
+ magic[gpc][3] = 0x00000000 | (magic3 << 16);
+ offset += 0x0324;
+ }
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+ mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+ offset += 0x07ff * (priv->tpc_nr[gpc] - 1);
+ mmio_list(GPC_UNIT(gpc, 0x32c0), magic[gpc][2], 0, 0);
+ mmio_list(GPC_UNIT(gpc, 0x32e4), magic[gpc][3] | offset, 0, 0);
+ offset += 0x07ff;
+ }
+
+ mmio_list(0x17e91c, 0x06060609, 0, 0);
+ mmio_list(0x17e920, 0x00090a05, 0, 0);
+}
+
+static struct nvc0_graph_init *
+nvf0_grctx_init_hub[] = {
+ nvc0_grctx_init_base,
+ nvf0_grctx_init_unk40xx,
+ nvf0_grctx_init_unk44xx,
+ nve4_grctx_init_unk46xx,
+ nve4_grctx_init_unk47xx,
+ nve4_grctx_init_unk58xx,
+ nvf0_grctx_init_unk5bxx,
+ nvf0_grctx_init_unk60xx,
+ nvf0_grctx_init_unk64xx,
+ nve4_grctx_init_unk80xx,
+ nvf0_grctx_init_unk88xx,
+ nvd9_grctx_init_rop,
+ NULL
+};
+
+struct nvc0_graph_init *
+nvf0_grctx_init_gpc[] = {
+ nvf0_grctx_init_gpc_0,
+ nvc0_grctx_init_gpc_1,
+ nvf0_grctx_init_tpc,
+ nvf0_grctx_init_unk,
+ NULL
+};
+
+static struct nvc0_graph_mthd
+nvf0_grctx_init_mthd[] = {
+ { 0xa197, nvc1_grctx_init_9097, },
+ { 0x902d, nvc0_grctx_init_902d, },
+ { 0x902d, nvc0_grctx_init_mthd_magic, },
+ {}
+};
+
+struct nouveau_oclass *
+nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xf0),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_context_ctor,
+ .dtor = nvc0_graph_context_dtor,
+ .init = _nouveau_graph_context_init,
+ .fini = _nouveau_graph_context_fini,
+ .rd32 = _nouveau_graph_context_rd32,
+ .wr32 = _nouveau_graph_context_wr32,
+ },
+ .main = nve4_grctx_generate_main,
+ .mods = nvf0_grctx_generate_mods,
+ .unkn = nve4_grctx_generate_unkn,
+ .hub = nvf0_grctx_init_hub,
+ .gpc = nvf0_grctx_init_gpc,
+ .icmd = nvc0_grctx_init_icmd,
+ .mthd = nvf0_grctx_init_mthd,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
index e6b228844a32..5d24b6de16cc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
@@ -23,42 +23,7 @@
* Authors: Ben Skeggs
*/
-define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
-define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
-
-ifdef(`include_code', `
-// Error codes
-define(`E_BAD_COMMAND', 0x01)
-define(`E_CMD_OVERFLOW', 0x02)
-
-// Util macros to help with debugging ucode hangs etc
-define(`T_WAIT', 0)
-define(`T_MMCTX', 1)
-define(`T_STRWAIT', 2)
-define(`T_STRINIT', 3)
-define(`T_AUTO', 4)
-define(`T_CHAN', 5)
-define(`T_LOAD', 6)
-define(`T_SAVE', 7)
-define(`T_LCHAN', 8)
-define(`T_LCTXH', 9)
-
-define(`trace_set', `
- mov $r8 0x83c
- shl b32 $r8 6
- clear b32 $r9
- bset $r9 $1
- iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
-')
-
-define(`trace_clr', `
- mov $r8 0x85c
- shl b32 $r8 6
- clear b32 $r9
- bset $r9 $1
- iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
-')
-
+#ifdef INCLUDE_CODE
// queue_put - add request to queue
//
// In : $r13 queue pointer
@@ -178,27 +143,37 @@ watchdog_clear:
iowr I[$r8 + 0x000] $r0
ret
-// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
+// wait_donez - wait on FUC_DONE bit to become clear
+//
+// In : $r10 bit to wait on
+//
+wait_donez:
+ trace_set(T_WAIT);
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
+ wait_donez_ne:
+ nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
+ xbit $r8 $r8 $r10
+ bra ne #wait_donez_ne
+ trace_clr(T_WAIT)
+ ret
+
+// wait_doneo - wait on FUC_DONE bit to become set
//
// In : $r10 bit to wait on
//
-define(`wait_done', `
-$1:
+wait_doneo:
trace_set(T_WAIT);
mov $r8 0x818
shl b32 $r8 6
- iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit
- wait_done_$1:
+ iowr I[$r8 + 0x000] $r10
+ wait_doneo_e:
mov $r8 0x400
shl b32 $r8 6
- iord $r8 I[$r8 + 0x000] // DONE
+ iord $r8 I[$r8 + 0x000]
xbit $r8 $r8 $r10
- bra $2 #wait_done_$1
+ bra e #wait_doneo_e
trace_clr(T_WAIT)
ret
-')
-wait_done(wait_donez, ne)
-wait_done(wait_doneo, e)
// mmctx_size - determine size of a mmio list transfer
//
@@ -397,4 +372,4 @@ strand_ctx_init:
sub b32 $r15 $r14 $r15
trace_clr(T_STRINIT)
ret
-')
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
new file mode 100644
index 000000000000..5547c1b3f4f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
@@ -0,0 +1,404 @@
+/* fuc microcode for nvc0 PGRAPH/GPC
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* TODO
+ * - bracket certain functions with scratch writes, useful for debugging
+ * - watchdog timer around ctx operations
+ */
+
+#ifdef INCLUDE_DATA
+gpc_mmio_list_head: .b32 #mmio_list_base
+gpc_mmio_list_tail:
+tpc_mmio_list_head: .b32 #mmio_list_base
+tpc_mmio_list_tail:
+unk_mmio_list_head: .b32 #mmio_list_base
+unk_mmio_list_tail: .b32 #mmio_list_base
+
+gpc_id: .b32 0
+
+tpc_count: .b32 0
+tpc_mask: .b32 0
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+unk_count: .b32 0
+unk_mask: .b32 0
+#endif
+
+cmd_queue: queue_init
+
+mmio_list_base:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see nvc0.fuc)
+//
+error:
+ push $r14
+ mov $r14 -0x67ec // 0x9814
+ sethi $r14 0x400000
+ call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code
+ add b32 $r14 0x41c
+ mov $r15 1
+ call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET
+ pop $r14
+ ret
+
+// GPC fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Input:
+// CC_SCRATCH[1]: context base
+//
+// Output:
+// CC_SCRATCH[0]:
+// 31:31: set to signal completion
+// CC_SCRATCH[1]:
+// 31:0: GPC context size
+//
+init:
+ clear b32 $r0
+ mov $sp $r0
+
+ // enable fifo access
+ mov $r1 0x1200
+ mov $r2 2
+ iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
+
+ // setup i0 handler, and route all interrupts to it
+ mov $r1 #ih
+ mov $iv0 $r1
+ mov $r1 0x400
+ iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
+
+ // enable fifo interrupt
+ mov $r2 4
+ iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
+
+ // enable interrupts
+ bset $flags ie0
+
+ // figure out which GPC we are, and how many TPCs we have
+ mov $r1 0x608
+ shl b32 $r1 6
+ iord $r2 I[$r1 + 0x000] // UNITS
+ mov $r3 1
+ and $r2 0x1f
+ shl b32 $r3 $r2
+ sub b32 $r3 1
+ st b32 D[$r0 + #tpc_count] $r2
+ st b32 D[$r0 + #tpc_mask] $r3
+ add b32 $r1 0x400
+ iord $r2 I[$r1 + 0x000] // MYINDEX
+ st b32 D[$r0 + #gpc_id] $r2
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+ // figure out which, and how many, UNKs are actually present
+ mov $r14 0x0c30
+ sethi $r14 0x500000
+ clear b32 $r2
+ clear b32 $r3
+ clear b32 $r4
+ init_unk_loop:
+ call #nv_rd32
+ cmp b32 $r15 0
+ bra z #init_unk_next
+ mov $r15 1
+ shl b32 $r15 $r2
+ or $r4 $r15
+ add b32 $r3 1
+ init_unk_next:
+ add b32 $r2 1
+ add b32 $r14 4
+ cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
+ bra ne #init_unk_loop
+ init_unk_done:
+ st b32 D[$r0 + #unk_count] $r3
+ st b32 D[$r0 + #unk_mask] $r4
+#endif
+
+ // initialise context base, and size tracking
+ nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
+ clear b32 $r3 // track GPC context size here
+
+ // set mmctx base addresses now so we don't have to do it later,
+ // they don't currently ever change
+ mov $r4 0x700
+ shl b32 $r4 6
+ shr b32 $r5 $r2 8
+ iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE
+ iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE
+
+ // calculate GPC mmio context size
+ ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
+ ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
+ call #mmctx_size
+ add b32 $r2 $r15
+ add b32 $r3 $r15
+
+ // calculate per-TPC mmio context size
+ ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
+ ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
+ call #mmctx_size
+ ld b32 $r14 D[$r0 + #tpc_count]
+ mulu $r14 $r15
+ add b32 $r2 $r14
+ add b32 $r3 $r14
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+ // calculate per-UNK mmio context size
+ ld b32 $r14 D[$r0 + #unk_mmio_list_head]
+ ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
+ call #mmctx_size
+ ld b32 $r14 D[$r0 + #unk_count]
+ mulu $r14 $r15
+ add b32 $r2 $r14
+ add b32 $r3 $r14
+#endif
+
+ // round up base/size to 256 byte boundary (for strand SWBASE)
+ add b32 $r4 0x1300
+ shr b32 $r3 2
+ iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!?
+ shr b32 $r2 8
+ shr b32 $r3 6
+ add b32 $r2 1
+ add b32 $r3 1
+ shl b32 $r2 8
+ shl b32 $r3 8
+
+ // calculate size of strand context data
+ mov b32 $r15 $r2
+ call #strand_ctx_init
+ add b32 $r3 $r15
+
+ // save context size, and tell HUB we're done
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
+ clear b32 $r2
+ bset $r2 31
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+ bset $flags $p0
+ sleep $p0
+ mov $r13 #cmd_queue
+ call #queue_get
+ bra $p1 #main
+
+ // 0x0000-0x0003 are all context transfers
+ cmpu b32 $r14 0x04
+ bra nc #main_not_ctx_xfer
+ // fetch $flags and mask off $p1/$p2
+ mov $r1 $flags
+ mov $r2 0x0006
+ not b32 $r2
+ and $r1 $r2
+ // set $p1/$p2 according to transfer type
+ shl b32 $r14 1
+ or $r1 $r14
+ mov $flags $r1
+ // transfer context data
+ call #ctx_xfer
+ bra #main
+
+ main_not_ctx_xfer:
+ shl b32 $r15 $r14 16
+ or $r15 E_BAD_COMMAND
+ call #error
+ bra #main
+
+// interrupt handler
+ih:
+ push $r8
+ mov $r8 $flags
+ push $r8
+ push $r9
+ push $r10
+ push $r11
+ push $r13
+ push $r14
+ push $r15
+ clear b32 $r0
+
+ // incoming fifo command?
+ iord $r10 I[$r0 + 0x200] // INTR
+ and $r11 $r10 0x00000004
+ bra e #ih_no_fifo
+ // queue incoming fifo command for later processing
+ mov $r11 0x1900
+ mov $r13 #cmd_queue
+ iord $r14 I[$r11 + 0x100] // FIFO_CMD
+ iord $r15 I[$r11 + 0x000] // FIFO_DATA
+ call #queue_put
+ add b32 $r11 0x400
+ mov $r14 1
+ iowr I[$r11 + 0x000] $r14 // FIFO_ACK
+
+ // ack, and wake up main()
+ ih_no_fifo:
+ iowr I[$r0 + 0x100] $r10 // INTR_ACK
+
+ pop $r15
+ pop $r14
+ pop $r13
+ pop $r11
+ pop $r10
+ pop $r9
+ pop $r8
+ mov $flags $r8
+ pop $r8
+ bclr $flags $p0
+ iret
+
+// Set this GPC's bit in HUB_BAR, used to signal completion of various
+// activities to the HUB fuc
+//
+hub_barrier_done:
+ mov $r15 1
+ ld b32 $r14 D[$r0 + #gpc_id]
+ shl b32 $r15 $r14
+ mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET
+ sethi $r14 0x400000
+ call #nv_wr32
+ ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off? Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+ mov $r14 0x614
+ shl b32 $r14 6
+ mov $r15 0x020
+ iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER
+ mov $r15 8
+ ctx_redswitch_delay:
+ sub b32 $r15 1
+ bra ne #ctx_redswitch_delay
+ mov $r15 0xa20
+ iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER
+ ret
+
+// Transfer GPC context data between GPU and storage area
+//
+// In: $r15 context base address
+// $p1 clear on save, set on load
+// $p2 set if opposite direction done/will be done, so:
+// on save it means: "a load will follow this save"
+// on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+ // set context base address
+ mov $r1 0xa04
+ shl b32 $r1 6
+ iowr I[$r1 + 0x000] $r15// MEM_BASE
+ bra not $p1 #ctx_xfer_not_load
+ call #ctx_redswitch
+ ctx_xfer_not_load:
+
+ // strands
+ mov $r1 0x4afc
+ sethi $r1 0x20000
+ mov $r2 0xc
+ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
+ call #strand_wait
+ mov $r2 0x47fc
+ sethi $r2 0x20000
+ iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
+ xbit $r2 $flags $p1
+ add b32 $r2 3
+ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+
+ // mmio context
+ xbit $r10 $flags $p1 // direction
+ or $r10 2 // first
+ mov $r11 0x0000
+ sethi $r11 0x500000
+ ld b32 $r12 D[$r0 + #gpc_id]
+ shl b32 $r12 15
+ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
+ ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
+ ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
+ mov $r14 0 // not multi
+ call #mmctx_xfer
+
+ // per-TPC mmio context
+ xbit $r10 $flags $p1 // direction
+#if !NV_PGRAPH_GPCX_UNK__SIZE
+ or $r10 4 // last
+#endif
+ mov $r11 0x4000
+ sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0
+ ld b32 $r12 D[$r0 + #gpc_id]
+ shl b32 $r12 15
+ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
+ ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
+ ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
+ ld b32 $r15 D[$r0 + #tpc_mask]
+ mov $r14 0x800 // stride = 0x800
+ call #mmctx_xfer
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+ // per-UNK mmio context
+ xbit $r10 $flags $p1 // direction
+ or $r10 4 // last
+ mov $r11 0x3000
+ sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_UNK0
+ ld b32 $r12 D[$r0 + #gpc_id]
+ shl b32 $r12 15
+ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_UNK0
+ ld b32 $r12 D[$r0 + #unk_mmio_list_head]
+ ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
+ ld b32 $r15 D[$r0 + #unk_mask]
+ mov $r14 0x200 // stride = 0x200
+ call #mmctx_xfer
+#endif
+
+ // wait for strands to finish
+ call #strand_wait
+
+ // if load, or a save without a load following, do some
+ // unknown stuff that's done after finishing a block of
+ // strand commands
+ bra $p1 #ctx_xfer_post
+ bra not $p2 #ctx_xfer_done
+ ctx_xfer_post:
+ mov $r1 0x4afc
+ sethi $r1 0x20000
+ mov $r2 0xd
+ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d
+ call #strand_wait
+
+ // mark completion in HUB's barrier
+ ctx_xfer_done:
+ call #hub_barrier_done
+ ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
index f7055af0f2a6..5ae06a2d64c9 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nvc0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -20,525 +19,24 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-/* To build:
- * m4 gpcnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o gpcnvc0.fuc.h
- */
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000000
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
+#define CHIPSET GF100
+#include "macros.fuc"
.section #nvc0_grgpc_data
-include(`nvc0.fuc')
-gpc_id: .b32 0
-gpc_mmio_list_head: .b32 0
-gpc_mmio_list_tail: .b32 0
-
-tpc_count: .b32 0
-tpc_mask: .b32 0
-tpc_mmio_list_head: .b32 0
-tpc_mmio_list_tail: .b32 0
-
-cmd_queue: queue_init
-
-// chipset descriptions
-chipsets:
-.b8 0xc0 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc0_tpc_mmio_tail
-.b8 0xc1 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc1_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc1_tpc_mmio_tail
-.b8 0xc3 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc3_tpc_mmio_tail
-.b8 0xc4 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc3_tpc_mmio_tail
-.b8 0xc8 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc0_tpc_mmio_tail
-.b8 0xce 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvc3_tpc_mmio_tail
-.b8 0xcf 0 0 0
-.b16 #nvc0_gpc_mmio_head
-.b16 #nvc0_gpc_mmio_tail
-.b16 #nvc0_tpc_mmio_head
-.b16 #nvcf_tpc_mmio_tail
-.b8 0xd9 0 0 0
-.b16 #nvd9_gpc_mmio_head
-.b16 #nvd9_gpc_mmio_tail
-.b16 #nvd9_tpc_mmio_head
-.b16 #nvd9_tpc_mmio_tail
-.b8 0xd7 0 0 0
-.b16 #nvd9_gpc_mmio_head
-.b16 #nvd9_gpc_mmio_tail
-.b16 #nvd9_tpc_mmio_head
-.b16 #nvd9_tpc_mmio_tail
-.b8 0 0 0 0
-
-// GPC mmio lists
-nvc0_gpc_mmio_head:
-mmctx_data(0x000380, 1)
-mmctx_data(0x000400, 6)
-mmctx_data(0x000450, 9)
-mmctx_data(0x000600, 1)
-mmctx_data(0x000684, 1)
-mmctx_data(0x000700, 5)
-mmctx_data(0x000800, 1)
-mmctx_data(0x000808, 3)
-mmctx_data(0x000828, 1)
-mmctx_data(0x000830, 1)
-mmctx_data(0x0008d8, 1)
-mmctx_data(0x0008e0, 1)
-mmctx_data(0x0008e8, 6)
-mmctx_data(0x00091c, 1)
-mmctx_data(0x000924, 3)
-mmctx_data(0x000b00, 1)
-mmctx_data(0x000b08, 6)
-mmctx_data(0x000bb8, 1)
-mmctx_data(0x000c08, 1)
-mmctx_data(0x000c10, 8)
-mmctx_data(0x000c80, 1)
-mmctx_data(0x000c8c, 1)
-mmctx_data(0x001000, 3)
-mmctx_data(0x001014, 1)
-nvc0_gpc_mmio_tail:
-mmctx_data(0x000c6c, 1);
-nvc1_gpc_mmio_tail:
-
-nvd9_gpc_mmio_head:
-mmctx_data(0x000380, 1)
-mmctx_data(0x000400, 2)
-mmctx_data(0x00040c, 3)
-mmctx_data(0x000450, 9)
-mmctx_data(0x000600, 1)
-mmctx_data(0x000684, 1)
-mmctx_data(0x000700, 5)
-mmctx_data(0x000800, 1)
-mmctx_data(0x000808, 3)
-mmctx_data(0x000828, 1)
-mmctx_data(0x000830, 1)
-mmctx_data(0x0008d8, 1)
-mmctx_data(0x0008e0, 1)
-mmctx_data(0x0008e8, 6)
-mmctx_data(0x00091c, 1)
-mmctx_data(0x000924, 3)
-mmctx_data(0x000b00, 1)
-mmctx_data(0x000b08, 6)
-mmctx_data(0x000bb8, 1)
-mmctx_data(0x000c08, 1)
-mmctx_data(0x000c10, 8)
-mmctx_data(0x000c6c, 1)
-mmctx_data(0x000c80, 1)
-mmctx_data(0x000c8c, 1)
-mmctx_data(0x001000, 3)
-mmctx_data(0x001014, 1)
-nvd9_gpc_mmio_tail:
-
-// TPC mmio lists
-nvc0_tpc_mmio_head:
-mmctx_data(0x000018, 1)
-mmctx_data(0x00003c, 1)
-mmctx_data(0x000048, 1)
-mmctx_data(0x000064, 1)
-mmctx_data(0x000088, 1)
-mmctx_data(0x000200, 6)
-mmctx_data(0x00021c, 2)
-mmctx_data(0x000300, 6)
-mmctx_data(0x0003d0, 1)
-mmctx_data(0x0003e0, 2)
-mmctx_data(0x000400, 3)
-mmctx_data(0x000420, 1)
-mmctx_data(0x0004b0, 1)
-mmctx_data(0x0004e8, 1)
-mmctx_data(0x0004f4, 1)
-mmctx_data(0x000520, 2)
-mmctx_data(0x000604, 4)
-mmctx_data(0x000644, 20)
-mmctx_data(0x000698, 1)
-mmctx_data(0x000750, 2)
-nvc0_tpc_mmio_tail:
-mmctx_data(0x000758, 1)
-mmctx_data(0x0002c4, 1)
-mmctx_data(0x0006e0, 1)
-nvcf_tpc_mmio_tail:
-mmctx_data(0x0004bc, 1)
-nvc3_tpc_mmio_tail:
-mmctx_data(0x000544, 1)
-nvc1_tpc_mmio_tail:
-
-nvd9_tpc_mmio_head:
-mmctx_data(0x000018, 1)
-mmctx_data(0x00003c, 1)
-mmctx_data(0x000048, 1)
-mmctx_data(0x000064, 1)
-mmctx_data(0x000088, 1)
-mmctx_data(0x000200, 6)
-mmctx_data(0x00021c, 2)
-mmctx_data(0x0002c4, 1)
-mmctx_data(0x000300, 6)
-mmctx_data(0x0003d0, 1)
-mmctx_data(0x0003e0, 2)
-mmctx_data(0x000400, 3)
-mmctx_data(0x000420, 3)
-mmctx_data(0x0004b0, 1)
-mmctx_data(0x0004e8, 1)
-mmctx_data(0x0004f4, 1)
-mmctx_data(0x000520, 2)
-mmctx_data(0x000544, 1)
-mmctx_data(0x000604, 4)
-mmctx_data(0x000644, 20)
-mmctx_data(0x000698, 1)
-mmctx_data(0x0006e0, 1)
-mmctx_data(0x000750, 3)
-nvd9_tpc_mmio_tail:
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
.section #nvc0_grgpc_code
+#define INCLUDE_CODE
bra #init
-define(`include_code')
-include(`nvc0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nvc0.fuc)
-//
-error:
- push $r14
- mov $r14 -0x67ec // 0x9814
- sethi $r14 0x400000
- call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code
- add b32 $r14 0x41c
- mov $r15 1
- call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET
- pop $r14
- ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-// CC_SCRATCH[1]: context base
-//
-// Output:
-// CC_SCRATCH[0]:
-// 31:31: set to signal completion
-// CC_SCRATCH[1]:
-// 31:0: GPC context size
-//
-init:
- clear b32 $r0
- mov $sp $r0
-
- // enable fifo access
- mov $r1 0x1200
- mov $r2 2
- iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
-
- // setup i0 handler, and route all interrupts to it
- mov $r1 #ih
- mov $iv0 $r1
- mov $r1 0x400
- iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
-
- // enable fifo interrupt
- mov $r2 4
- iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
-
- // enable interrupts
- bset $flags ie0
-
- // figure out which GPC we are, and how many TPCs we have
- mov $r1 0x608
- shl b32 $r1 6
- iord $r2 I[$r1 + 0x000] // UNITS
- mov $r3 1
- and $r2 0x1f
- shl b32 $r3 $r2
- sub b32 $r3 1
- st b32 D[$r0 + #tpc_count] $r2
- st b32 D[$r0 + #tpc_mask] $r3
- add b32 $r1 0x400
- iord $r2 I[$r1 + 0x000] // MYINDEX
- st b32 D[$r0 + #gpc_id] $r2
-
- // find context data for this chipset
- mov $r2 0x800
- shl b32 $r2 6
- iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
- mov $r1 #chipsets - 12
- init_find_chipset:
- add b32 $r1 12
- ld b32 $r3 D[$r1 + 0x00]
- cmpu b32 $r3 $r2
- bra e #init_context
- cmpu b32 $r3 0
- bra ne #init_find_chipset
- // unknown chipset
- ret
-
- // initialise context base, and size tracking
- init_context:
- mov $r2 0x800
- shl b32 $r2 6
- iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base
- clear b32 $r3 // track GPC context size here
-
- // set mmctx base addresses now so we don't have to do it later,
- // they don't currently ever change
- mov $r4 0x700
- shl b32 $r4 6
- shr b32 $r5 $r2 8
- iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE
- iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE
-
- // calculate GPC mmio context size, store the chipset-specific
- // mmio list pointers somewhere we can get at them later without
- // re-parsing the chipset list
- clear b32 $r14
- clear b32 $r15
- ld b16 $r14 D[$r1 + 4]
- ld b16 $r15 D[$r1 + 6]
- st b16 D[$r0 + #gpc_mmio_list_head] $r14
- st b16 D[$r0 + #gpc_mmio_list_tail] $r15
- call #mmctx_size
- add b32 $r2 $r15
- add b32 $r3 $r15
-
- // calculate per-TPC mmio context size, store the list pointers
- ld b16 $r14 D[$r1 + 8]
- ld b16 $r15 D[$r1 + 10]
- st b16 D[$r0 + #tpc_mmio_list_head] $r14
- st b16 D[$r0 + #tpc_mmio_list_tail] $r15
- call #mmctx_size
- ld b32 $r14 D[$r0 + #tpc_count]
- mulu $r14 $r15
- add b32 $r2 $r14
- add b32 $r3 $r14
-
- // round up base/size to 256 byte boundary (for strand SWBASE)
- add b32 $r4 0x1300
- shr b32 $r3 2
- iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!?
- shr b32 $r2 8
- shr b32 $r3 6
- add b32 $r2 1
- add b32 $r3 1
- shl b32 $r2 8
- shl b32 $r3 8
-
- // calculate size of strand context data
- mov b32 $r15 $r2
- call #strand_ctx_init
- add b32 $r3 $r15
-
- // save context size, and tell HUB we're done
- mov $r1 0x800
- shl b32 $r1 6
- iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size
- add b32 $r1 0x800
- clear b32 $r2
- bset $r2 31
- iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
- bset $flags $p0
- sleep $p0
- mov $r13 #cmd_queue
- call #queue_get
- bra $p1 #main
-
- // 0x0000-0x0003 are all context transfers
- cmpu b32 $r14 0x04
- bra nc #main_not_ctx_xfer
- // fetch $flags and mask off $p1/$p2
- mov $r1 $flags
- mov $r2 0x0006
- not b32 $r2
- and $r1 $r2
- // set $p1/$p2 according to transfer type
- shl b32 $r14 1
- or $r1 $r14
- mov $flags $r1
- // transfer context data
- call #ctx_xfer
- bra #main
-
- main_not_ctx_xfer:
- shl b32 $r15 $r14 16
- or $r15 E_BAD_COMMAND
- call #error
- bra #main
-
-// interrupt handler
-ih:
- push $r8
- mov $r8 $flags
- push $r8
- push $r9
- push $r10
- push $r11
- push $r13
- push $r14
- push $r15
-
- // incoming fifo command?
- iord $r10 I[$r0 + 0x200] // INTR
- and $r11 $r10 0x00000004
- bra e #ih_no_fifo
- // queue incoming fifo command for later processing
- mov $r11 0x1900
- mov $r13 #cmd_queue
- iord $r14 I[$r11 + 0x100] // FIFO_CMD
- iord $r15 I[$r11 + 0x000] // FIFO_DATA
- call #queue_put
- add b32 $r11 0x400
- mov $r14 1
- iowr I[$r11 + 0x000] $r14 // FIFO_ACK
-
- // ack, and wake up main()
- ih_no_fifo:
- iowr I[$r0 + 0x100] $r10 // INTR_ACK
-
- pop $r15
- pop $r14
- pop $r13
- pop $r11
- pop $r10
- pop $r9
- pop $r8
- mov $flags $r8
- pop $r8
- bclr $flags $p0
- iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
- mov $r15 1
- ld b32 $r14 D[$r0 + #gpc_id]
- shl b32 $r15 $r14
- mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET
- sethi $r14 0x400000
- call #nv_wr32
- ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off? Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
- mov $r14 0x614
- shl b32 $r14 6
- mov $r15 0x020
- iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER
- mov $r15 8
- ctx_redswitch_delay:
- sub b32 $r15 1
- bra ne #ctx_redswitch_delay
- mov $r15 0xa20
- iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER
- ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-// $p1 clear on save, set on load
-// $p2 set if opposite direction done/will be done, so:
-// on save it means: "a load will follow this save"
-// on load it means: "a save preceeded this load"
-//
-ctx_xfer:
- // set context base address
- mov $r1 0xa04
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r15// MEM_BASE
- bra not $p1 #ctx_xfer_not_load
- call #ctx_redswitch
- ctx_xfer_not_load:
-
- // strands
- mov $r1 0x4afc
- sethi $r1 0x20000
- mov $r2 0xc
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
- call #strand_wait
- mov $r2 0x47fc
- sethi $r2 0x20000
- iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
- xbit $r2 $flags $p1
- add b32 $r2 3
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
- // mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 2 // first
- mov $r11 0x0000
- sethi $r11 0x500000
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
- ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
- ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
- mov $r14 0 // not multi
- call #mmctx_xfer
-
- // per-TPC mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 4 // last
- mov $r11 0x4000
- sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
- ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
- ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
- ld b32 $r15 D[$r0 + #tpc_mask]
- mov $r14 0x800 // stride = 0x800
- call #mmctx_xfer
-
- // wait for strands to finish
- call #strand_wait
-
- // if load, or a save without a load following, do some
- // unknown stuff that's done after finishing a block of
- // strand commands
- bra $p1 #ctx_xfer_post
- bra not $p2 #ctx_xfer_done
- ctx_xfer_post:
- mov $r1 0x4afc
- sethi $r1 0x20000
- mov $r2 0xd
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d
- call #strand_wait
-
- // mark completion in HUB's barrier
- ctx_xfer_done:
- call #hub_barrier_done
- ret
-
+#include "com.fuc"
+#include "gpc.fuc"
.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
index 96050ddb22ca..f2b0dea80116 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
@@ -1,17 +1,19 @@
uint32_t nvc0_grgpc_data[] = {
-/* 0x0000: gpc_id */
- 0x00000000,
-/* 0x0004: gpc_mmio_list_head */
- 0x00000000,
-/* 0x0008: gpc_mmio_list_tail */
- 0x00000000,
-/* 0x000c: tpc_count */
- 0x00000000,
-/* 0x0010: tpc_mask */
+/* 0x0000: gpc_mmio_list_head */
+ 0x00000064,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x00000064,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x00000064,
+/* 0x000c: unk_mmio_list_tail */
+ 0x00000064,
+/* 0x0010: gpc_id */
0x00000000,
-/* 0x0014: tpc_mmio_list_head */
+/* 0x0014: tpc_count */
0x00000000,
-/* 0x0018: tpc_mmio_list_tail */
+/* 0x0018: tpc_mask */
0x00000000,
/* 0x001c: cmd_queue */
0x00000000,
@@ -32,153 +34,17 @@ uint32_t nvc0_grgpc_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0064: chipsets */
- 0x000000c0,
- 0x012800c8,
- 0x01e40194,
- 0x000000c1,
- 0x012c00c8,
- 0x01f80194,
- 0x000000c3,
- 0x012800c8,
- 0x01f40194,
- 0x000000c4,
- 0x012800c8,
- 0x01f40194,
- 0x000000c8,
- 0x012800c8,
- 0x01e40194,
- 0x000000ce,
- 0x012800c8,
- 0x01f40194,
- 0x000000cf,
- 0x012800c8,
- 0x01f00194,
- 0x000000d9,
- 0x0194012c,
- 0x025401f8,
- 0x00000000,
-/* 0x00c8: nvc0_gpc_mmio_head */
- 0x00000380,
- 0x14000400,
- 0x20000450,
- 0x00000600,
- 0x00000684,
- 0x10000700,
- 0x00000800,
- 0x08000808,
- 0x00000828,
- 0x00000830,
- 0x000008d8,
- 0x000008e0,
- 0x140008e8,
- 0x0000091c,
- 0x08000924,
- 0x00000b00,
- 0x14000b08,
- 0x00000bb8,
- 0x00000c08,
- 0x1c000c10,
- 0x00000c80,
- 0x00000c8c,
- 0x08001000,
- 0x00001014,
-/* 0x0128: nvc0_gpc_mmio_tail */
- 0x00000c6c,
-/* 0x012c: nvc1_gpc_mmio_tail */
-/* 0x012c: nvd9_gpc_mmio_head */
- 0x00000380,
- 0x04000400,
- 0x0800040c,
- 0x20000450,
- 0x00000600,
- 0x00000684,
- 0x10000700,
- 0x00000800,
- 0x08000808,
- 0x00000828,
- 0x00000830,
- 0x000008d8,
- 0x000008e0,
- 0x140008e8,
- 0x0000091c,
- 0x08000924,
- 0x00000b00,
- 0x14000b08,
- 0x00000bb8,
- 0x00000c08,
- 0x1c000c10,
- 0x00000c6c,
- 0x00000c80,
- 0x00000c8c,
- 0x08001000,
- 0x00001014,
-/* 0x0194: nvd9_gpc_mmio_tail */
-/* 0x0194: nvc0_tpc_mmio_head */
- 0x00000018,
- 0x0000003c,
- 0x00000048,
- 0x00000064,
- 0x00000088,
- 0x14000200,
- 0x0400021c,
- 0x14000300,
- 0x000003d0,
- 0x040003e0,
- 0x08000400,
- 0x00000420,
- 0x000004b0,
- 0x000004e8,
- 0x000004f4,
- 0x04000520,
- 0x0c000604,
- 0x4c000644,
- 0x00000698,
- 0x04000750,
-/* 0x01e4: nvc0_tpc_mmio_tail */
- 0x00000758,
- 0x000002c4,
- 0x000006e0,
-/* 0x01f0: nvcf_tpc_mmio_tail */
- 0x000004bc,
-/* 0x01f4: nvc3_tpc_mmio_tail */
- 0x00000544,
-/* 0x01f8: nvc1_tpc_mmio_tail */
-/* 0x01f8: nvd9_tpc_mmio_head */
- 0x00000018,
- 0x0000003c,
- 0x00000048,
- 0x00000064,
- 0x00000088,
- 0x14000200,
- 0x0400021c,
- 0x000002c4,
- 0x14000300,
- 0x000003d0,
- 0x040003e0,
- 0x08000400,
- 0x08000420,
- 0x000004b0,
- 0x000004e8,
- 0x000004f4,
- 0x04000520,
- 0x00000544,
- 0x0c000604,
- 0x4c000644,
- 0x00000698,
- 0x000006e0,
- 0x08000750,
};
uint32_t nvc0_grgpc_code[] = {
- 0x03060ef5,
+ 0x03180ef5,
/* 0x0004: queue_put */
0x9800d898,
0x86f001d9,
0x0489b808,
0xf00c1bf4,
0x21f502f7,
- 0x00f802ec,
+ 0x00f802fe,
/* 0x001c: queue_put_next */
0xb60798c4,
0x8dbb0384,
@@ -210,7 +76,7 @@ uint32_t nvc0_grgpc_code[] = {
0xc800bccf,
0x1bf41fcc,
0x06a7f0fa,
- 0x010321f5,
+ 0x010921f5,
0xf840bfcf,
/* 0x008d: nv_wr32 */
0x28b7f100,
@@ -232,63 +98,66 @@ uint32_t nvc0_grgpc_code[] = {
0x0684b604,
0xf80080d0,
/* 0x00c9: wait_donez */
- 0x3c87f100,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d000,
- 0x081887f1,
- 0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
- 0x87f1008a,
- 0x84b60400,
- 0x0088cf06,
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
0xf4888aff,
- 0x87f1f31b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00099,
-/* 0x0103: wait_doneo */
- 0xf100f800,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00099f0,
- 0x87f10089,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x87f104bd,
0x84b60818,
0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
0x040087f1,
0xcf0684b6,
0x8aff0088,
0xf30bf488,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0099f094,
- 0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
- 0x9894bd00,
- 0x85b600e8,
- 0x0180b61a,
- 0xbb0284b6,
- 0xe0b60098,
- 0x04efb804,
- 0xb9eb1bf4,
- 0x00f8029f,
-/* 0x015c: mmctx_xfer */
- 0x083c87f1,
- 0xbd0684b6,
- 0x0199f094,
- 0xf10089d0,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
0xb6071087,
0x94bd0684,
0xf405bbfd,
0x8bd0090b,
0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
0xf405eefd,
0x8ed00c0b,
0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
0xb70199f0,
0xc8010080,
0xb4b600ab,
@@ -296,8 +165,8 @@ uint32_t nvc0_grgpc_code[] = {
0xb601aec8,
0xbefd11e4,
0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
0xf0008ecf,
0x0bf41fe4,
0x00ce98fa,
@@ -306,76 +175,77 @@ uint32_t nvc0_grgpc_code[] = {
0x04cdb804,
0xc8e81bf4,
0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
0x008bcf18,
0xb01fb4f0,
0x1bf410b4,
0x02a7f0f7,
0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
0xabc81b0e,
0x10b4b600,
0xf00cb9f0,
0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
0x008bcf00,
0xf412bbc8,
-/* 0x01f6: mmctx_done */
- 0x87f1fa1b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00199,
-/* 0x0207: strand_wait */
- 0xf900f800,
- 0x02a7f0a0,
- 0xfcc921f4,
-/* 0x0213: strand_pre */
- 0xf100f8a0,
- 0xf04afc87,
- 0x97f00283,
- 0x0089d00c,
- 0x020721f5,
-/* 0x0226: strand_post */
- 0x87f100f8,
- 0x83f04afc,
- 0x0d97f002,
- 0xf50089d0,
- 0xf8020721,
-/* 0x0239: strand_set */
- 0xfca7f100,
- 0x02a3f04f,
- 0x0500aba2,
- 0xd00fc7f0,
- 0xc7f000ac,
- 0x00bcd00b,
- 0x020721f5,
- 0xf000aed0,
- 0xbcd00ac7,
- 0x0721f500,
-/* 0x0263: strand_ctx_init */
- 0xf100f802,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00399f0,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
0x21f50089,
- 0xe7f00213,
- 0x3921f503,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
0xfca7f102,
0x02a3f046,
0x0400aba0,
0xf040a0d0,
0xbcd001c7,
- 0x0721f500,
+ 0x1521f500,
0x010c9202,
0xf000acd0,
0xbcd002c7,
- 0x0721f500,
- 0x2621f502,
+ 0x1521f500,
+ 0x3421f502,
0x8087f102,
0x0684b608,
0xb70089cf,
0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
0x8ed008fe,
0x408ed000,
0xb6808acf,
@@ -384,86 +254,74 @@ uint32_t nvc0_grgpc_code[] = {
0xb60480b6,
0x1bf40192,
0x08e4b6e8,
- 0xf1f2efbc,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00399f0,
- 0x00f80089,
-/* 0x02ec: error */
- 0xe7f1e0f9,
- 0xe3f09814,
- 0x8d21f440,
- 0x041ce0b7,
- 0xf401f7f0,
- 0xe0fc8d21,
-/* 0x0306: init */
- 0x04bd00f8,
- 0xf10004fe,
- 0xf0120017,
- 0x12d00227,
- 0x3e17f100,
- 0x0010fe04,
- 0x040017f1,
- 0xf0c010d0,
- 0x12d00427,
- 0x1031f400,
- 0x060817f1,
- 0xcf0614b6,
- 0x37f00012,
- 0x1f24f001,
- 0xb60432bb,
- 0x02800132,
- 0x04038003,
- 0x040010b7,
- 0x800012cf,
- 0x27f10002,
- 0x24b60800,
- 0x0022cf06,
-/* 0x035f: init_find_chipset */
- 0xb65817f0,
- 0x13980c10,
- 0x0432b800,
- 0xb00b0bf4,
- 0x1bf40034,
-/* 0x0373: init_context */
- 0xf100f8f1,
- 0xb6080027,
- 0x22cf0624,
- 0xf134bd40,
- 0xb6070047,
- 0x25950644,
- 0x0045d008,
- 0xbd4045d0,
- 0x58f4bde4,
- 0x1f58021e,
- 0x020e4003,
- 0xf5040f40,
- 0xbb013d21,
- 0x3fbb002f,
- 0x041e5800,
- 0x40051f58,
- 0x0f400a0e,
- 0x3d21f50c,
- 0x030e9801,
- 0xbb00effd,
- 0x3ebb002e,
- 0x0040b700,
- 0x0235b613,
- 0xb60043d0,
- 0x35b60825,
- 0x0120b606,
- 0xb60130b6,
- 0x34b60824,
- 0x022fb908,
- 0x026321f5,
- 0xf1003fbb,
- 0xb6080017,
- 0x13d00614,
- 0x0010b740,
- 0xf024bd08,
- 0x12d01f29,
-/* 0x0401: main */
- 0x0031f400,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0xe0f900f8,
+ 0x9814e7f1,
+ 0xf440e3f0,
+ 0xe0b78d21,
+ 0xf7f0041c,
+ 0x8d21f401,
+ 0x00f8e0fc,
+/* 0x0318: init */
+ 0x04fe04bd,
+ 0x0017f100,
+ 0x0227f012,
+ 0xf10012d0,
+ 0xfe042617,
+ 0x17f10010,
+ 0x10d00400,
+ 0x0427f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x14b60608,
+ 0x0012cf06,
+ 0xf00137f0,
+ 0x32bb1f24,
+ 0x0132b604,
+ 0x80050280,
+ 0x10b70603,
+ 0x12cf0400,
+ 0x04028000,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0x070047f1,
+ 0x950644b6,
+ 0x45d00825,
+ 0x4045d000,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x2fbb0147,
+ 0x003fbb00,
+ 0x98010e98,
+ 0x21f5020f,
+ 0x0e980147,
+ 0x00effd05,
+ 0xbb002ebb,
+ 0x40b7003e,
+ 0x35b61300,
+ 0x0043d002,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb90834,
+ 0x7121f502,
+ 0x003fbb02,
+ 0x010007f1,
+ 0xd00203f0,
+ 0x04bd0003,
+ 0x29f024bd,
+ 0x0007f11f,
+ 0x0203f008,
+ 0xbd0002d0,
+/* 0x03e9: main */
+ 0x0031f404,
0xf00028f4,
0x21f41cd7,
0xf401f439,
@@ -474,94 +332,100 @@ uint32_t nvc0_grgpc_code[] = {
0x01e4b604,
0xfe051efd,
0x21f50018,
- 0x0ef404c3,
-/* 0x0431: main_not_ctx_xfer */
+ 0x0ef404ad,
+/* 0x0419: main_not_ctx_xfer */
0x10ef94d3,
0xf501f5f0,
- 0xf402ec21,
-/* 0x043e: ih */
+ 0xf402fe21,
+/* 0x0426: ih */
0x80f9c60e,
0xf90188fe,
0xf990f980,
0xf9b0f9a0,
0xf9e0f9d0,
- 0x800acff0,
- 0xf404abc4,
- 0xb7f11d0b,
- 0xd7f01900,
- 0x40becf1c,
- 0xf400bfcf,
- 0xb0b70421,
- 0xe7f00400,
- 0x00bed001,
-/* 0x0474: ih_no_fifo */
- 0xfc400ad0,
- 0xfce0fcf0,
- 0xfcb0fcd0,
- 0xfc90fca0,
- 0x0088fe80,
- 0x32f480fc,
-/* 0x048f: hub_barrier_done */
- 0xf001f800,
- 0x0e9801f7,
- 0x04febb00,
- 0x9418e7f1,
- 0xf440e3f0,
- 0x00f88d21,
-/* 0x04a4: ctx_redswitch */
- 0x0614e7f1,
- 0xf006e4b6,
- 0xefd020f7,
- 0x08f7f000,
-/* 0x04b4: ctx_redswitch_delay */
- 0xf401f2b6,
- 0xf7f1fd1b,
- 0xefd00a20,
-/* 0x04c3: ctx_xfer */
- 0xf100f800,
- 0xb60a0417,
- 0x1fd00614,
- 0x0711f400,
- 0x04a421f5,
-/* 0x04d4: ctx_xfer_not_load */
- 0x4afc17f1,
- 0xf00213f0,
- 0x12d00c27,
- 0x0721f500,
- 0xfc27f102,
- 0x0223f047,
- 0xf00020d0,
- 0x20b6012c,
- 0x0012d003,
+ 0xcf04bdf0,
+ 0xabc4800a,
+ 0x1d0bf404,
+ 0x1900b7f1,
+ 0xcf1cd7f0,
+ 0xbfcf40be,
+ 0x0421f400,
+ 0x0400b0b7,
+ 0xd001e7f0,
+/* 0x045e: ih_no_fifo */
+ 0x0ad000be,
+ 0xfcf0fc40,
+ 0xfcd0fce0,
+ 0xfca0fcb0,
+ 0xfe80fc90,
+ 0x80fc0088,
+ 0xf80032f4,
+/* 0x0479: hub_barrier_done */
+ 0x01f7f001,
+ 0xbb040e98,
+ 0xe7f104fe,
+ 0xe3f09418,
+ 0x8d21f440,
+/* 0x048e: ctx_redswitch */
+ 0xe7f100f8,
+ 0xe4b60614,
+ 0x20f7f006,
+ 0xf000efd0,
+/* 0x049e: ctx_redswitch_delay */
+ 0xf2b608f7,
+ 0xfd1bf401,
+ 0x0a20f7f1,
+ 0xf800efd0,
+/* 0x04ad: ctx_xfer */
+ 0x0417f100,
+ 0x0614b60a,
+ 0xf4001fd0,
+ 0x21f50711,
+/* 0x04be: ctx_xfer_not_load */
+ 0x17f1048e,
+ 0x13f04afc,
+ 0x0c27f002,
+ 0xf50012d0,
+ 0xf1021521,
+ 0xf047fc27,
+ 0x20d00223,
+ 0x012cf000,
+ 0xd00320b6,
+ 0xacf00012,
+ 0x02a5f001,
+ 0xf000b7f0,
+ 0x0c9850b3,
+ 0x0fc4b604,
+ 0x9800bcbb,
+ 0x0d98000c,
+ 0x00e7f001,
+ 0x016621f5,
0xf001acf0,
- 0xb7f002a5,
- 0x50b3f000,
- 0xb6000c98,
- 0xbcbb0fc4,
- 0x010c9800,
- 0xf0020d98,
- 0x21f500e7,
- 0xacf0015c,
- 0x04a5f001,
- 0x4000b7f1,
- 0x9850b3f0,
- 0xc4b6000c,
- 0x00bcbb0f,
- 0x98050c98,
- 0x0f98060d,
- 0x00e7f104,
- 0x5c21f508,
- 0x0721f501,
- 0x0601f402,
-/* 0x054b: ctx_xfer_post */
- 0xf11412f4,
- 0xf04afc17,
- 0x27f00213,
- 0x0012d00d,
- 0x020721f5,
-/* 0x055c: ctx_xfer_done */
- 0x048f21f5,
- 0x000000f8,
+ 0xb7f104a5,
+ 0xb3f04000,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0xf1060f98,
+ 0xf50800e7,
+ 0xf5016621,
+ 0xf4021521,
+ 0x12f40601,
+/* 0x0535: ctx_xfer_post */
+ 0xfc17f114,
+ 0x0213f04a,
+ 0xd00d27f0,
+ 0x21f50012,
+/* 0x0546: ctx_xfer_done */
+ 0x21f50215,
+ 0x00f80479,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
new file mode 100644
index 000000000000..c2f754edbd7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #nvd7_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #nvd7_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
new file mode 100644
index 000000000000..dd346c2a1624
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
@@ -0,0 +1,475 @@
+uint32_t nvd7_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: unk_count */
+ 0x00000000,
+/* 0x0020: unk_mask */
+ 0x00000000,
+/* 0x0024: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t nvd7_grgpc_code[] = {
+ 0x03180ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f802fe,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0x0728b7f1,
+ 0xb906b4b6,
+ 0xc9f002ec,
+ 0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+ 0xc800bccf,
+ 0x1bf41fcc,
+ 0x06a7f0fa,
+ 0x010921f5,
+ 0xf840bfcf,
+/* 0x008d: nv_wr32 */
+ 0x28b7f100,
+ 0x06b4b607,
+ 0xb980bfd0,
+ 0xc9f002ec,
+ 0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+ 0xcf00bcd0,
+ 0xccc800bc,
+ 0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+ 0x87f100f8,
+ 0x84b60430,
+ 0x1ff9f006,
+ 0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+ 0x3087f100,
+ 0x0684b604,
+ 0xf80080d0,
+/* 0x00c9: wait_donez */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
+ 0xf4888aff,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x87f104bd,
+ 0x84b60818,
+ 0x008ad006,
+/* 0x0124: wait_doneo_e */
+ 0x040087f1,
+ 0xcf0684b6,
+ 0x8aff0088,
+ 0xf30bf488,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xb6071087,
+ 0x94bd0684,
+ 0xf405bbfd,
+ 0x8bd0090b,
+ 0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+ 0xf405eefd,
+ 0x8ed00c0b,
+ 0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+ 0xb70199f0,
+ 0xc8010080,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xb601aec8,
+ 0xbefd11e4,
+ 0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+ 0xf0008ecf,
+ 0x0bf41fe4,
+ 0x00ce98fa,
+ 0xd005e9fd,
+ 0xc0b6c08e,
+ 0x04cdb804,
+ 0xc8e81bf4,
+ 0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+ 0x008bcf18,
+ 0xb01fb4f0,
+ 0x1bf410b4,
+ 0x02a7f0f7,
+ 0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+ 0xabc81b0e,
+ 0x10b4b600,
+ 0xf00cb9f0,
+ 0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+ 0x008bcf00,
+ 0xf412bbc8,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
+ 0x21f50089,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
+ 0xfca7f102,
+ 0x02a3f046,
+ 0x0400aba0,
+ 0xf040a0d0,
+ 0xbcd001c7,
+ 0x1521f500,
+ 0x010c9202,
+ 0xf000acd0,
+ 0xbcd002c7,
+ 0x1521f500,
+ 0x3421f502,
+ 0x8087f102,
+ 0x0684b608,
+ 0xb70089cf,
+ 0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0xe0f900f8,
+ 0x9814e7f1,
+ 0xf440e3f0,
+ 0xe0b78d21,
+ 0xf7f0041c,
+ 0x8d21f401,
+ 0x00f8e0fc,
+/* 0x0318: init */
+ 0x04fe04bd,
+ 0x0017f100,
+ 0x0227f012,
+ 0xf10012d0,
+ 0xfe047017,
+ 0x17f10010,
+ 0x10d00400,
+ 0x0427f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x14b60608,
+ 0x0012cf06,
+ 0xf00137f0,
+ 0x32bb1f24,
+ 0x0132b604,
+ 0x80050280,
+ 0x10b70603,
+ 0x12cf0400,
+ 0x04028000,
+ 0x0c30e7f1,
+ 0xbd50e3f0,
+ 0xbd34bd24,
+/* 0x0371: init_unk_loop */
+ 0x6821f444,
+ 0xf400f6b0,
+ 0xf7f00f0b,
+ 0x04f2bb01,
+ 0xb6054ffd,
+/* 0x0386: init_unk_next */
+ 0x20b60130,
+ 0x04e0b601,
+ 0xf40126b0,
+/* 0x0392: init_unk_done */
+ 0x0380e21b,
+ 0x08048007,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0x070047f1,
+ 0x950644b6,
+ 0x45d00825,
+ 0x4045d000,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x2fbb0147,
+ 0x003fbb00,
+ 0x98010e98,
+ 0x21f5020f,
+ 0x0e980147,
+ 0x00effd05,
+ 0xbb002ebb,
+ 0x0e98003e,
+ 0x030f9802,
+ 0x014721f5,
+ 0xfd070e98,
+ 0x2ebb00ef,
+ 0x003ebb00,
+ 0x130040b7,
+ 0xd00235b6,
+ 0x25b60043,
+ 0x0635b608,
+ 0xb60120b6,
+ 0x24b60130,
+ 0x0834b608,
+ 0xf5022fb9,
+ 0xbb027121,
+ 0x07f1003f,
+ 0x03f00100,
+ 0x0003d002,
+ 0x24bd04bd,
+ 0xf11f29f0,
+ 0xf0080007,
+ 0x02d00203,
+/* 0x0433: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x24d7f000,
+ 0xf43921f4,
+ 0xe4b0f401,
+ 0x1e18f404,
+ 0xf00181fe,
+ 0x20bd0627,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x04f721f5,
+/* 0x0463: main_not_ctx_xfer */
+ 0x94d30ef4,
+ 0xf5f010ef,
+ 0xfe21f501,
+ 0xc60ef402,
+/* 0x0470: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x800acf04,
+ 0xf404abc4,
+ 0xb7f11d0b,
+ 0xd7f01900,
+ 0x40becf24,
+ 0xf400bfcf,
+ 0xb0b70421,
+ 0xe7f00400,
+ 0x00bed001,
+/* 0x04a8: ih_no_fifo */
+ 0xfc400ad0,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x04c3: hub_barrier_done */
+ 0xf001f800,
+ 0x0e9801f7,
+ 0x04febb04,
+ 0x9418e7f1,
+ 0xf440e3f0,
+ 0x00f88d21,
+/* 0x04d8: ctx_redswitch */
+ 0x0614e7f1,
+ 0xf006e4b6,
+ 0xefd020f7,
+ 0x08f7f000,
+/* 0x04e8: ctx_redswitch_delay */
+ 0xf401f2b6,
+ 0xf7f1fd1b,
+ 0xefd00a20,
+/* 0x04f7: ctx_xfer */
+ 0xf100f800,
+ 0xb60a0417,
+ 0x1fd00614,
+ 0x0711f400,
+ 0x04d821f5,
+/* 0x0508: ctx_xfer_not_load */
+ 0x4afc17f1,
+ 0xf00213f0,
+ 0x12d00c27,
+ 0x1521f500,
+ 0xfc27f102,
+ 0x0223f047,
+ 0xf00020d0,
+ 0x20b6012c,
+ 0x0012d003,
+ 0xf001acf0,
+ 0xb7f002a5,
+ 0x50b3f000,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xacf00166,
+ 0x00b7f101,
+ 0x50b3f040,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x010c9800,
+ 0x98020d98,
+ 0xe7f1060f,
+ 0x21f50800,
+ 0xacf00166,
+ 0x04a5f001,
+ 0x3000b7f1,
+ 0x9850b3f0,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98020c98,
+ 0x0f98030d,
+ 0x00e7f108,
+ 0x6621f502,
+ 0x1521f501,
+ 0x0601f402,
+/* 0x05a3: ctx_xfer_post */
+ 0xf11412f4,
+ 0xf04afc17,
+ 0x27f00213,
+ 0x0012d00d,
+ 0x021521f5,
+/* 0x05b4: ctx_xfer_done */
+ 0x04c321f5,
+ 0x000000f8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
index 62ab231cd6b6..6b906cd2a31f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nve0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -20,437 +19,24 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-/* To build:
- * m4 nve0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grgpc.fuc.h
- */
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
+#define CHIPSET GK100
+#include "macros.fuc"
.section #nve0_grgpc_data
-include(`nve0.fuc')
-gpc_id: .b32 0
-gpc_mmio_list_head: .b32 0
-gpc_mmio_list_tail: .b32 0
-
-tpc_count: .b32 0
-tpc_mask: .b32 0
-tpc_mmio_list_head: .b32 0
-tpc_mmio_list_tail: .b32 0
-
-cmd_queue: queue_init
-
-// chipset descriptions
-chipsets:
-.b8 0xe4 0 0 0
-.b16 #nve4_gpc_mmio_head
-.b16 #nve4_gpc_mmio_tail
-.b16 #nve4_tpc_mmio_head
-.b16 #nve4_tpc_mmio_tail
-.b8 0xe7 0 0 0
-.b16 #nve4_gpc_mmio_head
-.b16 #nve4_gpc_mmio_tail
-.b16 #nve4_tpc_mmio_head
-.b16 #nve4_tpc_mmio_tail
-.b8 0xe6 0 0 0
-.b16 #nve4_gpc_mmio_head
-.b16 #nve4_gpc_mmio_tail
-.b16 #nve4_tpc_mmio_head
-.b16 #nve4_tpc_mmio_tail
-.b8 0 0 0 0
-
-// GPC mmio lists
-nve4_gpc_mmio_head:
-mmctx_data(0x000380, 1)
-mmctx_data(0x000400, 2)
-mmctx_data(0x00040c, 3)
-mmctx_data(0x000450, 9)
-mmctx_data(0x000600, 1)
-mmctx_data(0x000684, 1)
-mmctx_data(0x000700, 5)
-mmctx_data(0x000800, 1)
-mmctx_data(0x000808, 3)
-mmctx_data(0x000828, 1)
-mmctx_data(0x000830, 1)
-mmctx_data(0x0008d8, 1)
-mmctx_data(0x0008e0, 1)
-mmctx_data(0x0008e8, 6)
-mmctx_data(0x00091c, 1)
-mmctx_data(0x000924, 3)
-mmctx_data(0x000b00, 1)
-mmctx_data(0x000b08, 6)
-mmctx_data(0x000bb8, 1)
-mmctx_data(0x000c08, 1)
-mmctx_data(0x000c10, 8)
-mmctx_data(0x000c40, 1)
-mmctx_data(0x000c6c, 1)
-mmctx_data(0x000c80, 1)
-mmctx_data(0x000c8c, 1)
-mmctx_data(0x001000, 3)
-mmctx_data(0x001014, 1)
-mmctx_data(0x003024, 1)
-mmctx_data(0x0030c0, 2)
-mmctx_data(0x0030e4, 1)
-mmctx_data(0x003100, 6)
-mmctx_data(0x0031d0, 1)
-mmctx_data(0x0031e0, 2)
-nve4_gpc_mmio_tail:
-
-// TPC mmio lists
-nve4_tpc_mmio_head:
-mmctx_data(0x000048, 1)
-mmctx_data(0x000064, 1)
-mmctx_data(0x000088, 1)
-mmctx_data(0x000200, 6)
-mmctx_data(0x00021c, 2)
-mmctx_data(0x000230, 1)
-mmctx_data(0x0002c4, 1)
-mmctx_data(0x000400, 3)
-mmctx_data(0x000420, 3)
-mmctx_data(0x0004e8, 1)
-mmctx_data(0x0004f4, 1)
-mmctx_data(0x000604, 4)
-mmctx_data(0x000644, 22)
-mmctx_data(0x0006ac, 2)
-mmctx_data(0x0006c8, 1)
-mmctx_data(0x000730, 8)
-mmctx_data(0x000758, 1)
-mmctx_data(0x000778, 1)
-nve4_tpc_mmio_tail:
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
.section #nve0_grgpc_code
+#define INCLUDE_CODE
bra #init
-define(`include_code')
-include(`nve0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nve0.fuc)
-//
-error:
- push $r14
- mov $r14 -0x67ec // 0x9814
- sethi $r14 0x400000
- call #nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code
- add b32 $r14 0x41c
- mov $r15 1
- call #nv_wr32 // HUB_CTXCTL_INTR_UP_SET
- pop $r14
- ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-// CC_SCRATCH[1]: context base
-//
-// Output:
-// CC_SCRATCH[0]:
-// 31:31: set to signal completion
-// CC_SCRATCH[1]:
-// 31:0: GPC context size
-//
-init:
- clear b32 $r0
- mov $sp $r0
-
- // enable fifo access
- mov $r1 0x1200
- mov $r2 2
- iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
-
- // setup i0 handler, and route all interrupts to it
- mov $r1 #ih
- mov $iv0 $r1
- mov $r1 0x400
- iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
-
- // enable fifo interrupt
- mov $r2 4
- iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
-
- // enable interrupts
- bset $flags ie0
-
- // figure out which GPC we are, and how many TPCs we have
- mov $r1 0x608
- shl b32 $r1 6
- iord $r2 I[$r1 + 0x000] // UNITS
- mov $r3 1
- and $r2 0x1f
- shl b32 $r3 $r2
- sub b32 $r3 1
- st b32 D[$r0 + #tpc_count] $r2
- st b32 D[$r0 + #tpc_mask] $r3
- add b32 $r1 0x400
- iord $r2 I[$r1 + 0x000] // MYINDEX
- st b32 D[$r0 + #gpc_id] $r2
-
- // find context data for this chipset
- mov $r2 0x800
- shl b32 $r2 6
- iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
- mov $r1 #chipsets - 12
- init_find_chipset:
- add b32 $r1 12
- ld b32 $r3 D[$r1 + 0x00]
- cmpu b32 $r3 $r2
- bra e #init_context
- cmpu b32 $r3 0
- bra ne #init_find_chipset
- // unknown chipset
- ret
-
- // initialise context base, and size tracking
- init_context:
- mov $r2 0x800
- shl b32 $r2 6
- iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base
- clear b32 $r3 // track GPC context size here
-
- // set mmctx base addresses now so we don't have to do it later,
- // they don't currently ever change
- mov $r4 0x700
- shl b32 $r4 6
- shr b32 $r5 $r2 8
- iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE
- iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE
-
- // calculate GPC mmio context size, store the chipset-specific
- // mmio list pointers somewhere we can get at them later without
- // re-parsing the chipset list
- clear b32 $r14
- clear b32 $r15
- ld b16 $r14 D[$r1 + 4]
- ld b16 $r15 D[$r1 + 6]
- st b16 D[$r0 + #gpc_mmio_list_head] $r14
- st b16 D[$r0 + #gpc_mmio_list_tail] $r15
- call #mmctx_size
- add b32 $r2 $r15
- add b32 $r3 $r15
-
- // calculate per-TPC mmio context size, store the list pointers
- ld b16 $r14 D[$r1 + 8]
- ld b16 $r15 D[$r1 + 10]
- st b16 D[$r0 + #tpc_mmio_list_head] $r14
- st b16 D[$r0 + #tpc_mmio_list_tail] $r15
- call #mmctx_size
- ld b32 $r14 D[$r0 + #tpc_count]
- mulu $r14 $r15
- add b32 $r2 $r14
- add b32 $r3 $r14
-
- // round up base/size to 256 byte boundary (for strand SWBASE)
- add b32 $r4 0x1300
- shr b32 $r3 2
- iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!?
- shr b32 $r2 8
- shr b32 $r3 6
- add b32 $r2 1
- add b32 $r3 1
- shl b32 $r2 8
- shl b32 $r3 8
-
- // calculate size of strand context data
- mov b32 $r15 $r2
- call #strand_ctx_init
- add b32 $r3 $r15
-
- // save context size, and tell HUB we're done
- mov $r1 0x800
- shl b32 $r1 6
- iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size
- add b32 $r1 0x800
- clear b32 $r2
- bset $r2 31
- iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
- bset $flags $p0
- sleep $p0
- mov $r13 #cmd_queue
- call #queue_get
- bra $p1 #main
-
- // 0x0000-0x0003 are all context transfers
- cmpu b32 $r14 0x04
- bra nc #main_not_ctx_xfer
- // fetch $flags and mask off $p1/$p2
- mov $r1 $flags
- mov $r2 0x0006
- not b32 $r2
- and $r1 $r2
- // set $p1/$p2 according to transfer type
- shl b32 $r14 1
- or $r1 $r14
- mov $flags $r1
- // transfer context data
- call #ctx_xfer
- bra #main
-
- main_not_ctx_xfer:
- shl b32 $r15 $r14 16
- or $r15 E_BAD_COMMAND
- call #error
- bra #main
-
-// interrupt handler
-ih:
- push $r8
- mov $r8 $flags
- push $r8
- push $r9
- push $r10
- push $r11
- push $r13
- push $r14
- push $r15
-
- // incoming fifo command?
- iord $r10 I[$r0 + 0x200] // INTR
- and $r11 $r10 0x00000004
- bra e #ih_no_fifo
- // queue incoming fifo command for later processing
- mov $r11 0x1900
- mov $r13 #cmd_queue
- iord $r14 I[$r11 + 0x100] // FIFO_CMD
- iord $r15 I[$r11 + 0x000] // FIFO_DATA
- call #queue_put
- add b32 $r11 0x400
- mov $r14 1
- iowr I[$r11 + 0x000] $r14 // FIFO_ACK
-
- // ack, and wake up main()
- ih_no_fifo:
- iowr I[$r0 + 0x100] $r10 // INTR_ACK
-
- pop $r15
- pop $r14
- pop $r13
- pop $r11
- pop $r10
- pop $r9
- pop $r8
- mov $flags $r8
- pop $r8
- bclr $flags $p0
- iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
- mov $r15 1
- ld b32 $r14 D[$r0 + #gpc_id]
- shl b32 $r15 $r14
- mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET
- sethi $r14 0x400000
- call #nv_wr32
- ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off? Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
- mov $r14 0x614
- shl b32 $r14 6
- mov $r15 0x020
- iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER
- mov $r15 8
- ctx_redswitch_delay:
- sub b32 $r15 1
- bra ne #ctx_redswitch_delay
- mov $r15 0xa20
- iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER
- ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-// $p1 clear on save, set on load
-// $p2 set if opposite direction done/will be done, so:
-// on save it means: "a load will follow this save"
-// on load it means: "a save preceeded this load"
-//
-ctx_xfer:
- // set context base address
- mov $r1 0xa04
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r15// MEM_BASE
- bra not $p1 #ctx_xfer_not_load
- call #ctx_redswitch
- ctx_xfer_not_load:
-
- // strands
- mov $r1 0x4afc
- sethi $r1 0x20000
- mov $r2 0xc
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
- call #strand_wait
- mov $r2 0x47fc
- sethi $r2 0x20000
- iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
- xbit $r2 $flags $p1
- add b32 $r2 3
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
- // mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 2 // first
- mov $r11 0x0000
- sethi $r11 0x500000
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
- ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
- ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
- mov $r14 0 // not multi
- call #mmctx_xfer
-
- // per-TPC mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 4 // last
- mov $r11 0x4000
- sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
- ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
- ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
- ld b32 $r15 D[$r0 + #tpc_mask]
- mov $r14 0x800 // stride = 0x800
- call #mmctx_xfer
-
- // wait for strands to finish
- call #strand_wait
-
- // if load, or a save without a load following, do some
- // unknown stuff that's done after finishing a block of
- // strand commands
- bra $p1 #ctx_xfer_post
- bra not $p2 #ctx_xfer_done
- ctx_xfer_post:
- mov $r1 0x4afc
- sethi $r1 0x20000
- mov $r2 0xd
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d
- call #strand_wait
-
- // mark completion in HUB's barrier
- ctx_xfer_done:
- call #hub_barrier_done
- ret
-
+#include "com.fuc"
+#include "gpc.fuc"
.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
index 09ee4702c8b2..7ff5ef6b0804 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
@@ -1,19 +1,27 @@
uint32_t nve0_grgpc_data[] = {
-/* 0x0000: gpc_id */
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
0x00000000,
-/* 0x0004: gpc_mmio_list_head */
+/* 0x0014: tpc_count */
0x00000000,
-/* 0x0008: gpc_mmio_list_tail */
+/* 0x0018: tpc_mask */
0x00000000,
-/* 0x000c: tpc_count */
+/* 0x001c: unk_count */
0x00000000,
-/* 0x0010: tpc_mask */
+/* 0x0020: unk_mask */
0x00000000,
-/* 0x0014: tpc_mmio_list_head */
+/* 0x0024: cmd_queue */
0x00000000,
-/* 0x0018: tpc_mmio_list_tail */
0x00000000,
-/* 0x001c: cmd_queue */
0x00000000,
0x00000000,
0x00000000,
@@ -30,84 +38,17 @@ uint32_t nve0_grgpc_data[] = {
0x00000000,
0x00000000,
0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0064: chipsets */
- 0x000000e4,
- 0x0110008c,
- 0x01580110,
- 0x000000e7,
- 0x0110008c,
- 0x01580110,
- 0x000000e6,
- 0x0110008c,
- 0x01580110,
- 0x00000000,
-/* 0x008c: nve4_gpc_mmio_head */
- 0x00000380,
- 0x04000400,
- 0x0800040c,
- 0x20000450,
- 0x00000600,
- 0x00000684,
- 0x10000700,
- 0x00000800,
- 0x08000808,
- 0x00000828,
- 0x00000830,
- 0x000008d8,
- 0x000008e0,
- 0x140008e8,
- 0x0000091c,
- 0x08000924,
- 0x00000b00,
- 0x14000b08,
- 0x00000bb8,
- 0x00000c08,
- 0x1c000c10,
- 0x00000c40,
- 0x00000c6c,
- 0x00000c80,
- 0x00000c8c,
- 0x08001000,
- 0x00001014,
- 0x00003024,
- 0x040030c0,
- 0x000030e4,
- 0x14003100,
- 0x000031d0,
- 0x040031e0,
-/* 0x0110: nve4_gpc_mmio_tail */
-/* 0x0110: nve4_tpc_mmio_head */
- 0x00000048,
- 0x00000064,
- 0x00000088,
- 0x14000200,
- 0x0400021c,
- 0x00000230,
- 0x000002c4,
- 0x08000400,
- 0x08000420,
- 0x000004e8,
- 0x000004f4,
- 0x0c000604,
- 0x54000644,
- 0x040006ac,
- 0x000006c8,
- 0x1c000730,
- 0x00000758,
- 0x00000778,
};
uint32_t nve0_grgpc_code[] = {
- 0x03060ef5,
+ 0x03180ef5,
/* 0x0004: queue_put */
0x9800d898,
0x86f001d9,
0x0489b808,
0xf00c1bf4,
0x21f502f7,
- 0x00f802ec,
+ 0x00f802fe,
/* 0x001c: queue_put_next */
0xb60798c4,
0x8dbb0384,
@@ -139,7 +80,7 @@ uint32_t nve0_grgpc_code[] = {
0xc800bccf,
0x1bf41fcc,
0x06a7f0fa,
- 0x010321f5,
+ 0x010921f5,
0xf840bfcf,
/* 0x008d: nv_wr32 */
0x28b7f100,
@@ -161,63 +102,66 @@ uint32_t nve0_grgpc_code[] = {
0x0684b604,
0xf80080d0,
/* 0x00c9: wait_donez */
- 0x3c87f100,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d000,
- 0x081887f1,
- 0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
- 0x87f1008a,
- 0x84b60400,
- 0x0088cf06,
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
0xf4888aff,
- 0x87f1f31b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00099,
-/* 0x0103: wait_doneo */
- 0xf100f800,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00099f0,
- 0x87f10089,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x87f104bd,
0x84b60818,
0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
0x040087f1,
0xcf0684b6,
0x8aff0088,
0xf30bf488,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0099f094,
- 0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
- 0x9894bd00,
- 0x85b600e8,
- 0x0180b61a,
- 0xbb0284b6,
- 0xe0b60098,
- 0x04efb804,
- 0xb9eb1bf4,
- 0x00f8029f,
-/* 0x015c: mmctx_xfer */
- 0x083c87f1,
- 0xbd0684b6,
- 0x0199f094,
- 0xf10089d0,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
0xb6071087,
0x94bd0684,
0xf405bbfd,
0x8bd0090b,
0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
0xf405eefd,
0x8ed00c0b,
0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
0xb70199f0,
0xc8010080,
0xb4b600ab,
@@ -225,8 +169,8 @@ uint32_t nve0_grgpc_code[] = {
0xb601aec8,
0xbefd11e4,
0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
0xf0008ecf,
0x0bf41fe4,
0x00ce98fa,
@@ -235,76 +179,77 @@ uint32_t nve0_grgpc_code[] = {
0x04cdb804,
0xc8e81bf4,
0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
0x008bcf18,
0xb01fb4f0,
0x1bf410b4,
0x02a7f0f7,
0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
0xabc81b0e,
0x10b4b600,
0xf00cb9f0,
0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
0x008bcf00,
0xf412bbc8,
-/* 0x01f6: mmctx_done */
- 0x87f1fa1b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00199,
-/* 0x0207: strand_wait */
- 0xf900f800,
- 0x02a7f0a0,
- 0xfcc921f4,
-/* 0x0213: strand_pre */
- 0xf100f8a0,
- 0xf04afc87,
- 0x97f00283,
- 0x0089d00c,
- 0x020721f5,
-/* 0x0226: strand_post */
- 0x87f100f8,
- 0x83f04afc,
- 0x0d97f002,
- 0xf50089d0,
- 0xf8020721,
-/* 0x0239: strand_set */
- 0xfca7f100,
- 0x02a3f04f,
- 0x0500aba2,
- 0xd00fc7f0,
- 0xc7f000ac,
- 0x00bcd00b,
- 0x020721f5,
- 0xf000aed0,
- 0xbcd00ac7,
- 0x0721f500,
-/* 0x0263: strand_ctx_init */
- 0xf100f802,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00399f0,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
0x21f50089,
- 0xe7f00213,
- 0x3921f503,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
0xfca7f102,
0x02a3f046,
0x0400aba0,
0xf040a0d0,
0xbcd001c7,
- 0x0721f500,
+ 0x1521f500,
0x010c9202,
0xf000acd0,
0xbcd002c7,
- 0x0721f500,
- 0x2621f502,
+ 0x1521f500,
+ 0x3421f502,
0x8087f102,
0x0684b608,
0xb70089cf,
0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
0x8ed008fe,
0x408ed000,
0xb6808acf,
@@ -313,150 +258,160 @@ uint32_t nve0_grgpc_code[] = {
0xb60480b6,
0x1bf40192,
0x08e4b6e8,
- 0xf1f2efbc,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00399f0,
- 0x00f80089,
-/* 0x02ec: error */
- 0xe7f1e0f9,
- 0xe3f09814,
- 0x8d21f440,
- 0x041ce0b7,
- 0xf401f7f0,
- 0xe0fc8d21,
-/* 0x0306: init */
- 0x04bd00f8,
- 0xf10004fe,
- 0xf0120017,
- 0x12d00227,
- 0x3e17f100,
- 0x0010fe04,
- 0x040017f1,
- 0xf0c010d0,
- 0x12d00427,
- 0x1031f400,
- 0x060817f1,
- 0xcf0614b6,
- 0x37f00012,
- 0x1f24f001,
- 0xb60432bb,
- 0x02800132,
- 0x04038003,
- 0x040010b7,
- 0x800012cf,
- 0x27f10002,
- 0x24b60800,
- 0x0022cf06,
-/* 0x035f: init_find_chipset */
- 0xb65817f0,
- 0x13980c10,
- 0x0432b800,
- 0xb00b0bf4,
- 0x1bf40034,
-/* 0x0373: init_context */
- 0xf100f8f1,
- 0xb6080027,
- 0x22cf0624,
- 0xf134bd40,
- 0xb6070047,
- 0x25950644,
- 0x0045d008,
- 0xbd4045d0,
- 0x58f4bde4,
- 0x1f58021e,
- 0x020e4003,
- 0xf5040f40,
- 0xbb013d21,
- 0x3fbb002f,
- 0x041e5800,
- 0x40051f58,
- 0x0f400a0e,
- 0x3d21f50c,
- 0x030e9801,
- 0xbb00effd,
- 0x3ebb002e,
- 0x0040b700,
- 0x0235b613,
- 0xb60043d0,
- 0x35b60825,
- 0x0120b606,
- 0xb60130b6,
- 0x34b60824,
- 0x022fb908,
- 0x026321f5,
- 0xf1003fbb,
- 0xb6080017,
- 0x13d00614,
- 0x0010b740,
- 0xf024bd08,
- 0x12d01f29,
-/* 0x0401: main */
- 0x0031f400,
- 0xf00028f4,
- 0x21f41cd7,
- 0xf401f439,
- 0xf404e4b0,
- 0x81fe1e18,
- 0x0627f001,
- 0x12fd20bd,
- 0x01e4b604,
- 0xfe051efd,
- 0x21f50018,
- 0x0ef404c3,
-/* 0x0431: main_not_ctx_xfer */
- 0x10ef94d3,
- 0xf501f5f0,
- 0xf402ec21,
-/* 0x043e: ih */
- 0x80f9c60e,
- 0xf90188fe,
- 0xf990f980,
- 0xf9b0f9a0,
- 0xf9e0f9d0,
- 0x800acff0,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0xe0f900f8,
+ 0x9814e7f1,
+ 0xf440e3f0,
+ 0xe0b78d21,
+ 0xf7f0041c,
+ 0x8d21f401,
+ 0x00f8e0fc,
+/* 0x0318: init */
+ 0x04fe04bd,
+ 0x0017f100,
+ 0x0227f012,
+ 0xf10012d0,
+ 0xfe047017,
+ 0x17f10010,
+ 0x10d00400,
+ 0x0427f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x14b60608,
+ 0x0012cf06,
+ 0xf00137f0,
+ 0x32bb1f24,
+ 0x0132b604,
+ 0x80050280,
+ 0x10b70603,
+ 0x12cf0400,
+ 0x04028000,
+ 0x0c30e7f1,
+ 0xbd50e3f0,
+ 0xbd34bd24,
+/* 0x0371: init_unk_loop */
+ 0x6821f444,
+ 0xf400f6b0,
+ 0xf7f00f0b,
+ 0x04f2bb01,
+ 0xb6054ffd,
+/* 0x0386: init_unk_next */
+ 0x20b60130,
+ 0x04e0b601,
+ 0xf40126b0,
+/* 0x0392: init_unk_done */
+ 0x0380e21b,
+ 0x08048007,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0x070047f1,
+ 0x950644b6,
+ 0x45d00825,
+ 0x4045d000,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x2fbb0147,
+ 0x003fbb00,
+ 0x98010e98,
+ 0x21f5020f,
+ 0x0e980147,
+ 0x00effd05,
+ 0xbb002ebb,
+ 0x0e98003e,
+ 0x030f9802,
+ 0x014721f5,
+ 0xfd070e98,
+ 0x2ebb00ef,
+ 0x003ebb00,
+ 0x130040b7,
+ 0xd00235b6,
+ 0x25b60043,
+ 0x0635b608,
+ 0xb60120b6,
+ 0x24b60130,
+ 0x0834b608,
+ 0xf5022fb9,
+ 0xbb027121,
+ 0x07f1003f,
+ 0x03f00100,
+ 0x0003d002,
+ 0x24bd04bd,
+ 0xf11f29f0,
+ 0xf0080007,
+ 0x02d00203,
+/* 0x0433: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x24d7f000,
+ 0xf43921f4,
+ 0xe4b0f401,
+ 0x1e18f404,
+ 0xf00181fe,
+ 0x20bd0627,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x04f721f5,
+/* 0x0463: main_not_ctx_xfer */
+ 0x94d30ef4,
+ 0xf5f010ef,
+ 0xfe21f501,
+ 0xc60ef402,
+/* 0x0470: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x800acf04,
0xf404abc4,
0xb7f11d0b,
0xd7f01900,
- 0x40becf1c,
+ 0x40becf24,
0xf400bfcf,
0xb0b70421,
0xe7f00400,
0x00bed001,
-/* 0x0474: ih_no_fifo */
+/* 0x04a8: ih_no_fifo */
0xfc400ad0,
0xfce0fcf0,
0xfcb0fcd0,
0xfc90fca0,
0x0088fe80,
0x32f480fc,
-/* 0x048f: hub_barrier_done */
+/* 0x04c3: hub_barrier_done */
0xf001f800,
0x0e9801f7,
- 0x04febb00,
+ 0x04febb04,
0x9418e7f1,
0xf440e3f0,
0x00f88d21,
-/* 0x04a4: ctx_redswitch */
+/* 0x04d8: ctx_redswitch */
0x0614e7f1,
0xf006e4b6,
0xefd020f7,
0x08f7f000,
-/* 0x04b4: ctx_redswitch_delay */
+/* 0x04e8: ctx_redswitch_delay */
0xf401f2b6,
0xf7f1fd1b,
0xefd00a20,
-/* 0x04c3: ctx_xfer */
+/* 0x04f7: ctx_xfer */
0xf100f800,
0xb60a0417,
0x1fd00614,
0x0711f400,
- 0x04a421f5,
-/* 0x04d4: ctx_xfer_not_load */
+ 0x04d821f5,
+/* 0x0508: ctx_xfer_not_load */
0x4afc17f1,
0xf00213f0,
0x12d00c27,
- 0x0721f500,
+ 0x1521f500,
0xfc27f102,
0x0223f047,
0xf00020d0,
@@ -465,31 +420,40 @@ uint32_t nve0_grgpc_code[] = {
0xf001acf0,
0xb7f002a5,
0x50b3f000,
- 0xb6000c98,
+ 0xb6040c98,
0xbcbb0fc4,
- 0x010c9800,
- 0xf0020d98,
+ 0x000c9800,
+ 0xf0010d98,
0x21f500e7,
- 0xacf0015c,
+ 0xacf00166,
+ 0x00b7f101,
+ 0x50b3f040,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x010c9800,
+ 0x98020d98,
+ 0xe7f1060f,
+ 0x21f50800,
+ 0xacf00166,
0x04a5f001,
- 0x4000b7f1,
+ 0x3000b7f1,
0x9850b3f0,
- 0xc4b6000c,
+ 0xc4b6040c,
0x00bcbb0f,
- 0x98050c98,
- 0x0f98060d,
- 0x00e7f104,
- 0x5c21f508,
- 0x0721f501,
+ 0x98020c98,
+ 0x0f98030d,
+ 0x00e7f108,
+ 0x6621f502,
+ 0x1521f501,
0x0601f402,
-/* 0x054b: ctx_xfer_post */
+/* 0x05a3: ctx_xfer_post */
0xf11412f4,
0xf04afc17,
0x27f00213,
0x0012d00d,
- 0x020721f5,
-/* 0x055c: ctx_xfer_done */
- 0x048f21f5,
+ 0x021521f5,
+/* 0x05b4: ctx_xfer_done */
+ 0x04c321f5,
0x000000f8,
0x00000000,
0x00000000,
@@ -508,26 +472,4 @@ uint32_t nve0_grgpc_code[] = {
0x00000000,
0x00000000,
0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
new file mode 100644
index 000000000000..90bbe525b626
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000002
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #nvf0_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #nvf0_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
new file mode 100644
index 000000000000..f870507be880
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
@@ -0,0 +1,475 @@
+uint32_t nvf0_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: unk_count */
+ 0x00000000,
+/* 0x0020: unk_mask */
+ 0x00000000,
+/* 0x0024: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t nvf0_grgpc_code[] = {
+ 0x03180ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f802fe,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0x0728b7f1,
+ 0xb906b4b6,
+ 0xc9f002ec,
+ 0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+ 0xc800bccf,
+ 0x1bf41fcc,
+ 0x06a7f0fa,
+ 0x010921f5,
+ 0xf840bfcf,
+/* 0x008d: nv_wr32 */
+ 0x28b7f100,
+ 0x06b4b607,
+ 0xb980bfd0,
+ 0xc9f002ec,
+ 0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+ 0xcf00bcd0,
+ 0xccc800bc,
+ 0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+ 0x87f100f8,
+ 0x84b60430,
+ 0x1ff9f006,
+ 0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+ 0x3087f100,
+ 0x0684b604,
+ 0xf80080d0,
+/* 0x00c9: wait_donez */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f03700,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
+ 0xf4888aff,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f03700,
+ 0x0009d002,
+ 0x87f104bd,
+ 0x84b60818,
+ 0x008ad006,
+/* 0x0124: wait_doneo_e */
+ 0x040087f1,
+ 0xcf0684b6,
+ 0x8aff0088,
+ 0xf30bf488,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf0370007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xb6071087,
+ 0x94bd0684,
+ 0xf405bbfd,
+ 0x8bd0090b,
+ 0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+ 0xf405eefd,
+ 0x8ed00c0b,
+ 0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+ 0xb70199f0,
+ 0xc8010080,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xb601aec8,
+ 0xbefd11e4,
+ 0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+ 0xf0008ecf,
+ 0x0bf41fe4,
+ 0x00ce98fa,
+ 0xd005e9fd,
+ 0xc0b6c08e,
+ 0x04cdb804,
+ 0xc8e81bf4,
+ 0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+ 0x008bcf18,
+ 0xb01fb4f0,
+ 0x1bf410b4,
+ 0x02a7f0f7,
+ 0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+ 0xabc81b0e,
+ 0x10b4b600,
+ 0xf00cb9f0,
+ 0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+ 0x008bcf00,
+ 0xf412bbc8,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
+ 0x21f50089,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f03700,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
+ 0xfca7f102,
+ 0x02a3f046,
+ 0x0400aba0,
+ 0xf040a0d0,
+ 0xbcd001c7,
+ 0x1521f500,
+ 0x010c9202,
+ 0xf000acd0,
+ 0xbcd002c7,
+ 0x1521f500,
+ 0x3421f502,
+ 0x8087f102,
+ 0x0684b608,
+ 0xb70089cf,
+ 0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0xe0f900f8,
+ 0x9814e7f1,
+ 0xf440e3f0,
+ 0xe0b78d21,
+ 0xf7f0041c,
+ 0x8d21f401,
+ 0x00f8e0fc,
+/* 0x0318: init */
+ 0x04fe04bd,
+ 0x0017f100,
+ 0x0227f012,
+ 0xf10012d0,
+ 0xfe047017,
+ 0x17f10010,
+ 0x10d00400,
+ 0x0427f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x14b60608,
+ 0x0012cf06,
+ 0xf00137f0,
+ 0x32bb1f24,
+ 0x0132b604,
+ 0x80050280,
+ 0x10b70603,
+ 0x12cf0400,
+ 0x04028000,
+ 0x0c30e7f1,
+ 0xbd50e3f0,
+ 0xbd34bd24,
+/* 0x0371: init_unk_loop */
+ 0x6821f444,
+ 0xf400f6b0,
+ 0xf7f00f0b,
+ 0x04f2bb01,
+ 0xb6054ffd,
+/* 0x0386: init_unk_next */
+ 0x20b60130,
+ 0x04e0b601,
+ 0xf40226b0,
+/* 0x0392: init_unk_done */
+ 0x0380e21b,
+ 0x08048007,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0x070047f1,
+ 0x950644b6,
+ 0x45d00825,
+ 0x4045d000,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x2fbb0147,
+ 0x003fbb00,
+ 0x98010e98,
+ 0x21f5020f,
+ 0x0e980147,
+ 0x00effd05,
+ 0xbb002ebb,
+ 0x0e98003e,
+ 0x030f9802,
+ 0x014721f5,
+ 0xfd070e98,
+ 0x2ebb00ef,
+ 0x003ebb00,
+ 0x130040b7,
+ 0xd00235b6,
+ 0x25b60043,
+ 0x0635b608,
+ 0xb60120b6,
+ 0x24b60130,
+ 0x0834b608,
+ 0xf5022fb9,
+ 0xbb027121,
+ 0x07f1003f,
+ 0x03f00100,
+ 0x0003d002,
+ 0x24bd04bd,
+ 0xf11f29f0,
+ 0xf0300007,
+ 0x02d00203,
+/* 0x0433: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x24d7f000,
+ 0xf43921f4,
+ 0xe4b0f401,
+ 0x1e18f404,
+ 0xf00181fe,
+ 0x20bd0627,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x04f721f5,
+/* 0x0463: main_not_ctx_xfer */
+ 0x94d30ef4,
+ 0xf5f010ef,
+ 0xfe21f501,
+ 0xc60ef402,
+/* 0x0470: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x800acf04,
+ 0xf404abc4,
+ 0xb7f11d0b,
+ 0xd7f01900,
+ 0x40becf24,
+ 0xf400bfcf,
+ 0xb0b70421,
+ 0xe7f00400,
+ 0x00bed001,
+/* 0x04a8: ih_no_fifo */
+ 0xfc400ad0,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x04c3: hub_barrier_done */
+ 0xf001f800,
+ 0x0e9801f7,
+ 0x04febb04,
+ 0x9418e7f1,
+ 0xf440e3f0,
+ 0x00f88d21,
+/* 0x04d8: ctx_redswitch */
+ 0x0614e7f1,
+ 0xf006e4b6,
+ 0xefd020f7,
+ 0x08f7f000,
+/* 0x04e8: ctx_redswitch_delay */
+ 0xf401f2b6,
+ 0xf7f1fd1b,
+ 0xefd00a20,
+/* 0x04f7: ctx_xfer */
+ 0xf100f800,
+ 0xb60a0417,
+ 0x1fd00614,
+ 0x0711f400,
+ 0x04d821f5,
+/* 0x0508: ctx_xfer_not_load */
+ 0x4afc17f1,
+ 0xf00213f0,
+ 0x12d00c27,
+ 0x1521f500,
+ 0xfc27f102,
+ 0x0223f047,
+ 0xf00020d0,
+ 0x20b6012c,
+ 0x0012d003,
+ 0xf001acf0,
+ 0xb7f002a5,
+ 0x50b3f000,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xacf00166,
+ 0x00b7f101,
+ 0x50b3f040,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x010c9800,
+ 0x98020d98,
+ 0xe7f1060f,
+ 0x21f50800,
+ 0xacf00166,
+ 0x04a5f001,
+ 0x3000b7f1,
+ 0x9850b3f0,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98020c98,
+ 0x0f98030d,
+ 0x00e7f108,
+ 0x6621f502,
+ 0x1521f501,
+ 0x0601f402,
+/* 0x05a3: ctx_xfer_post */
+ 0xf11412f4,
+ 0xf04afc17,
+ 0x27f00213,
+ 0x0012d00d,
+ 0x021521f5,
+/* 0x05b4: ctx_xfer_done */
+ 0x04c321f5,
+ 0x000000f8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
new file mode 100644
index 000000000000..b82d2ae89917
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
@@ -0,0 +1,724 @@
+/* fuc microcode for nvc0 PGRAPH/HUB
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_DATA
+hub_mmio_list_head: .b32 #hub_mmio_list_base
+hub_mmio_list_tail: .b32 #hub_mmio_list_next
+
+gpc_count: .b32 0
+rop_count: .b32 0
+cmd_queue: queue_init
+
+ctx_current: .b32 0
+
+.align 256
+chan_data:
+chan_mmio_count: .b32 0
+chan_mmio_address: .b32 0
+
+.align 256
+xfer_data: .skip 256
+
+hub_mmio_list_base:
+.b32 0x0417e91c // 0x17e91c, 2
+hub_mmio_list_next:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see nvc0.fuc)
+//
+error:
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15)
+ mov $r15 1
+ nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r15)
+ ret
+
+// HUB fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Output:
+// CC_SCRATCH[0]:
+// 31:31: set to signal completion
+// CC_SCRATCH[1]:
+// 31:0: total PGRAPH context size
+//
+init:
+ clear b32 $r0
+ mov $sp $r0
+ mov $xdbase $r0
+
+ // enable fifo access
+ mov $r1 0x1200
+ mov $r2 2
+ iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
+
+ // setup i0 handler, and route all interrupts to it
+ mov $r1 #ih
+ mov $iv0 $r1
+ mov $r1 0x400
+ iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
+
+ // route HUB_CHANNEL_SWITCH to fuc interrupt 8
+ mov $r3 0x404
+ shl b32 $r3 6
+ mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
+ iowr I[$r3 + 0x000] $r2
+
+ // not sure what these are, route them because NVIDIA does, and
+ // the IRQ handler will signal the host if we ever get one.. we
+ // may find out if/why we need to handle these if so..
+ //
+ mov $r2 0x2004
+ iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
+ mov $r2 0x200b
+ iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
+ mov $r2 0x200c
+ iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
+
+ // enable all INTR_UP interrupts
+ mov $r2 0xc24
+ shl b32 $r2 6
+ not b32 $r3 $r0
+ iowr I[$r2] $r3
+
+ // enable fifo, ctxsw, 9, 10, 15 interrupts
+ mov $r2 -0x78fc // 0x8704
+ sethi $r2 0
+ iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
+
+ // fifo level triggered, rest edge
+ sub b32 $r1 0x100
+ mov $r2 4
+ iowr I[$r1] $r2
+
+ // enable interrupts
+ bset $flags ie0
+
+ // fetch enabled GPC/ROP counts
+ mov $r14 -0x69fc // 0x409604
+ sethi $r14 0x400000
+ call #nv_rd32
+ extr $r1 $r15 16:20
+ st b32 D[$r0 + #rop_count] $r1
+ and $r15 0x1f
+ st b32 D[$r0 + #gpc_count] $r15
+
+ // set BAR_REQMASK to GPC mask
+ mov $r1 1
+ shl b32 $r1 $r15
+ sub b32 $r1 1
+ mov $r2 0x40c
+ shl b32 $r2 6
+ iowr I[$r2 + 0x000] $r1
+ iowr I[$r2 + 0x100] $r1
+
+ // context size calculation, reserve first 256 bytes for use by fuc
+ mov $r1 256
+
+ // calculate size of mmio context data
+ ld b32 $r14 D[$r0 + #hub_mmio_list_head]
+ ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
+ call #mmctx_size
+
+ // set mmctx base addresses now so we don't have to do it later,
+ // they don't (currently) ever change
+ mov $r3 0x700
+ shl b32 $r3 6
+ shr b32 $r4 $r1 8
+ iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE
+ iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE
+ add b32 $r3 0x1300
+ add b32 $r1 $r15
+ shr b32 $r15 2
+ iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!?
+
+ // strands, base offset needs to be aligned to 256 bytes
+ shr b32 $r1 8
+ add b32 $r1 1
+ shl b32 $r1 8
+ mov b32 $r15 $r1
+ call #strand_ctx_init
+ add b32 $r1 $r15
+
+ // initialise each GPC in sequence by passing in the offset of its
+ // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
+ // has previously been uploaded by the host) running.
+ //
+ // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
+ // when it has completed, and return the size of its context data
+ // in GPCn_CC_SCRATCH[1]
+ //
+ ld b32 $r3 D[$r0 + #gpc_count]
+ mov $r4 0x2000
+ sethi $r4 0x500000
+ init_gpc:
+ // setup, and start GPC ucode running
+ add b32 $r14 $r4 0x804
+ mov b32 $r15 $r1
+ call #nv_wr32 // CC_SCRATCH[1] = ctx offset
+ add b32 $r14 $r4 0x10c
+ clear b32 $r15
+ call #nv_wr32
+ add b32 $r14 $r4 0x104
+ call #nv_wr32 // ENTRY
+ add b32 $r14 $r4 0x100
+ mov $r15 2 // CTRL_START_TRIGGER
+ call #nv_wr32 // CTRL
+
+ // wait for it to complete, and adjust context size
+ add b32 $r14 $r4 0x800
+ init_gpc_wait:
+ call #nv_rd32
+ xbit $r15 $r15 31
+ bra e #init_gpc_wait
+ add b32 $r14 $r4 0x804
+ call #nv_rd32
+ add b32 $r1 $r15
+
+ // next!
+ add b32 $r4 0x8000
+ sub b32 $r3 1
+ bra ne #init_gpc
+
+ // save context size, and tell host we're ready
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
+ clear b32 $r1
+ bset $r1 31
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r1)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+ // sleep until we have something to do
+ bset $flags $p0
+ sleep $p0
+ mov $r13 #cmd_queue
+ call #queue_get
+ bra $p1 #main
+
+ // context switch, requested by GPU?
+ cmpu b32 $r14 0x4001
+ bra ne #main_not_ctx_switch
+ trace_set(T_AUTO)
+ mov $r1 0xb00
+ shl b32 $r1 6
+ iord $r2 I[$r1 + 0x100] // CHAN_NEXT
+ iord $r1 I[$r1 + 0x000] // CHAN_CUR
+
+ xbit $r3 $r1 31
+ bra e #chsw_no_prev
+ xbit $r3 $r2 31
+ bra e #chsw_prev_no_next
+ push $r2
+ mov b32 $r2 $r1
+ trace_set(T_SAVE)
+ bclr $flags $p1
+ bset $flags $p2
+ call #ctx_xfer
+ trace_clr(T_SAVE);
+ pop $r2
+ trace_set(T_LOAD);
+ bset $flags $p1
+ call #ctx_xfer
+ trace_clr(T_LOAD);
+ bra #chsw_done
+ chsw_prev_no_next:
+ push $r2
+ mov b32 $r2 $r1
+ bclr $flags $p1
+ bclr $flags $p2
+ call #ctx_xfer
+ pop $r2
+ mov $r1 0xb00
+ shl b32 $r1 6
+ iowr I[$r1] $r2
+ bra #chsw_done
+ chsw_no_prev:
+ xbit $r3 $r2 31
+ bra e #chsw_done
+ bset $flags $p1
+ bclr $flags $p2
+ call #ctx_xfer
+
+ // ack the context switch request
+ chsw_done:
+ mov $r1 0xb0c
+ shl b32 $r1 6
+ mov $r2 1
+ iowr I[$r1 + 0x000] $r2 // 0x409b0c
+ trace_clr(T_AUTO)
+ bra #main
+
+ // request to set current channel? (*not* a context switch)
+ main_not_ctx_switch:
+ cmpu b32 $r14 0x0001
+ bra ne #main_not_ctx_chan
+ mov b32 $r2 $r15
+ call #ctx_chan
+ bra #main_done
+
+ // request to store current channel context?
+ main_not_ctx_chan:
+ cmpu b32 $r14 0x0002
+ bra ne #main_not_ctx_save
+ trace_set(T_SAVE)
+ bclr $flags $p1
+ bclr $flags $p2
+ call #ctx_xfer
+ trace_clr(T_SAVE)
+ bra #main_done
+
+ main_not_ctx_save:
+ shl b32 $r15 $r14 16
+ or $r15 E_BAD_COMMAND
+ call #error
+ bra #main
+
+ main_done:
+ clear b32 $r2
+ bset $r2 31
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r2)
+ bra #main
+
+// interrupt handler
+ih:
+ push $r8
+ mov $r8 $flags
+ push $r8
+ push $r9
+ push $r10
+ push $r11
+ push $r13
+ push $r14
+ push $r15
+ clear b32 $r0
+
+ // incoming fifo command?
+ iord $r10 I[$r0 + 0x200] // INTR
+ and $r11 $r10 0x00000004
+ bra e #ih_no_fifo
+ // queue incoming fifo command for later processing
+ mov $r11 0x1900
+ mov $r13 #cmd_queue
+ iord $r14 I[$r11 + 0x100] // FIFO_CMD
+ iord $r15 I[$r11 + 0x000] // FIFO_DATA
+ call #queue_put
+ add b32 $r11 0x400
+ mov $r14 1
+ iowr I[$r11 + 0x000] $r14 // FIFO_ACK
+
+ // context switch request?
+ ih_no_fifo:
+ and $r11 $r10 0x00000100
+ bra e #ih_no_ctxsw
+ // enqueue a context switch for later processing
+ mov $r13 #cmd_queue
+ mov $r14 0x4001
+ call #queue_put
+
+ // anything we didn't handle, bring it to the host's attention
+ ih_no_ctxsw:
+ mov $r11 0x104
+ not b32 $r11
+ and $r11 $r10 $r11
+ bra e #ih_no_other
+ mov $r10 0xc1c
+ shl b32 $r10 6
+ iowr I[$r10] $r11 // INTR_UP_SET
+
+ // ack, and wake up main()
+ ih_no_other:
+ iowr I[$r0 + 0x100] $r10 // INTR_ACK
+
+ pop $r15
+ pop $r14
+ pop $r13
+ pop $r11
+ pop $r10
+ pop $r9
+ pop $r8
+ mov $flags $r8
+ pop $r8
+ bclr $flags $p0
+ iret
+
+#if CHIPSET < GK100
+// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
+ctx_4160s:
+ mov $r14 0x4160
+ sethi $r14 0x400000
+ mov $r15 1
+ call #nv_wr32
+ ctx_4160s_wait:
+ call #nv_rd32
+ xbit $r15 $r15 4
+ bra e #ctx_4160s_wait
+ ret
+
+// Without clearing again at end of xfer, some things cause PGRAPH
+// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
+// still function with it set however...
+ctx_4160c:
+ mov $r14 0x4160
+ sethi $r14 0x400000
+ clear b32 $r15
+ call #nv_wr32
+ ret
+#endif
+
+// Again, not real sure
+//
+// In: $r15 value to set 0x404170 to
+//
+ctx_4170s:
+ mov $r14 0x4170
+ sethi $r14 0x400000
+ or $r15 0x10
+ call #nv_wr32
+ ret
+
+// Waits for a ctx_4170s() call to complete
+//
+ctx_4170w:
+ mov $r14 0x4170
+ sethi $r14 0x400000
+ call #nv_rd32
+ and $r15 0x10
+ bra ne #ctx_4170w
+ ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off? Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+ mov $r14 0x614
+ shl b32 $r14 6
+ mov $r15 0x270
+ iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
+ mov $r15 8
+ ctx_redswitch_delay:
+ sub b32 $r15 1
+ bra ne #ctx_redswitch_delay
+ mov $r15 0x770
+ iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
+ ret
+
+// Not a clue what this is for, except that unless the value is 0x10, the
+// strand context is saved (and presumably restored) incorrectly..
+//
+// In: $r15 value to set to (0x00/0x10 are used)
+//
+ctx_86c:
+ mov $r14 0x86c
+ shl b32 $r14 6
+ iowr I[$r14] $r15 // HUB(0x86c) = val
+ mov $r14 -0x75ec
+ sethi $r14 0x400000
+ call #nv_wr32 // ROP(0xa14) = val
+ mov $r14 -0x5794
+ sethi $r14 0x410000
+ call #nv_wr32 // GPC(0x86c) = val
+ ret
+
+// ctx_load - load's a channel's ctxctl data, and selects its vm
+//
+// In: $r2 channel address
+//
+ctx_load:
+ trace_set(T_CHAN)
+
+ // switch to channel, somewhat magic in parts..
+ mov $r10 12 // DONE_UNK12
+ call #wait_donez
+ mov $r1 0xa24
+ shl b32 $r1 6
+ iowr I[$r1 + 0x000] $r0 // 0x409a24
+ mov $r3 0xb00
+ shl b32 $r3 6
+ iowr I[$r3 + 0x100] $r2 // CHAN_NEXT
+ mov $r1 0xa0c
+ shl b32 $r1 6
+ mov $r4 7
+ iowr I[$r1 + 0x000] $r2 // MEM_CHAN
+ iowr I[$r1 + 0x100] $r4 // MEM_CMD
+ ctx_chan_wait_0:
+ iord $r4 I[$r1 + 0x100]
+ and $r4 0x1f
+ bra ne #ctx_chan_wait_0
+ iowr I[$r3 + 0x000] $r2 // CHAN_CUR
+
+ // load channel header, fetch PGRAPH context pointer
+ mov $xtargets $r0
+ bclr $r2 31
+ shl b32 $r2 4
+ add b32 $r2 2
+
+ trace_set(T_LCHAN)
+ mov $r1 0xa04
+ shl b32 $r1 6
+ iowr I[$r1 + 0x000] $r2 // MEM_BASE
+ mov $r1 0xa20
+ shl b32 $r1 6
+ mov $r2 0x0002
+ sethi $r2 0x80000000
+ iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram
+ mov $r1 0x10 // chan + 0x0210
+ mov $r2 #xfer_data
+ sethi $r2 0x00020000 // 16 bytes
+ xdld $r1 $r2
+ xdwait
+ trace_clr(T_LCHAN)
+
+ // update current context
+ ld b32 $r1 D[$r0 + #xfer_data + 4]
+ shl b32 $r1 24
+ ld b32 $r2 D[$r0 + #xfer_data + 0]
+ shr b32 $r2 8
+ or $r1 $r2
+ st b32 D[$r0 + #ctx_current] $r1
+
+ // set transfer base to start of context, and fetch context header
+ trace_set(T_LCTXH)
+ mov $r2 0xa04
+ shl b32 $r2 6
+ iowr I[$r2 + 0x000] $r1 // MEM_BASE
+ mov $r2 1
+ mov $r1 0xa20
+ shl b32 $r1 6
+ iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm
+ mov $r1 #chan_data
+ sethi $r1 0x00060000 // 256 bytes
+ xdld $r0 $r1
+ xdwait
+ trace_clr(T_LCTXH)
+
+ trace_clr(T_CHAN)
+ ret
+
+// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
+// the active channel for ctxctl, but not actually transfer
+// any context data. intended for use only during initial
+// context construction.
+//
+// In: $r2 channel address
+//
+ctx_chan:
+#if CHIPSET < GK100
+ call #ctx_4160s
+#endif
+ call #ctx_load
+ mov $r10 12 // DONE_UNK12
+ call #wait_donez
+ mov $r1 0xa10
+ shl b32 $r1 6
+ mov $r2 5
+ iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???)
+ ctx_chan_wait:
+ iord $r2 I[$r1 + 0x000]
+ or $r2 $r2
+ bra ne #ctx_chan_wait
+#if CHIPSET < GK100
+ call #ctx_4160c
+#endif
+ ret
+
+// Execute per-context state overrides list
+//
+// Only executed on the first load of a channel. Might want to look into
+// removing this and having the host directly modify the channel's context
+// to change this state... The nouveau DRM already builds this list as
+// it's definitely needed for NVIDIA's, so we may as well use it for now
+//
+// Input: $r1 mmio list length
+//
+ctx_mmio_exec:
+ // set transfer base to be the mmio list
+ ld b32 $r3 D[$r0 + #chan_mmio_address]
+ mov $r2 0xa04
+ shl b32 $r2 6
+ iowr I[$r2 + 0x000] $r3 // MEM_BASE
+
+ clear b32 $r3
+ ctx_mmio_loop:
+ // fetch next 256 bytes of mmio list if necessary
+ and $r4 $r3 0xff
+ bra ne #ctx_mmio_pull
+ mov $r5 #xfer_data
+ sethi $r5 0x00060000 // 256 bytes
+ xdld $r3 $r5
+ xdwait
+
+ // execute a single list entry
+ ctx_mmio_pull:
+ ld b32 $r14 D[$r4 + #xfer_data + 0x00]
+ ld b32 $r15 D[$r4 + #xfer_data + 0x04]
+ call #nv_wr32
+
+ // next!
+ add b32 $r3 8
+ sub b32 $r1 1
+ bra ne #ctx_mmio_loop
+
+ // set transfer base back to the current context
+ ctx_mmio_done:
+ ld b32 $r3 D[$r0 + #ctx_current]
+ iowr I[$r2 + 0x000] $r3 // MEM_BASE
+
+ // disable the mmio list now, we don't need/want to execute it again
+ st b32 D[$r0 + #chan_mmio_count] $r0
+ mov $r1 #chan_data
+ sethi $r1 0x00060000 // 256 bytes
+ xdst $r0 $r1
+ xdwait
+ ret
+
+// Transfer HUB context data between GPU and storage area
+//
+// In: $r2 channel address
+// $p1 clear on save, set on load
+// $p2 set if opposite direction done/will be done, so:
+// on save it means: "a load will follow this save"
+// on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+ // according to mwk, some kind of wait for idle
+ mov $r15 0xc00
+ shl b32 $r15 6
+ mov $r14 4
+ iowr I[$r15 + 0x200] $r14
+ ctx_xfer_idle:
+ iord $r14 I[$r15 + 0x000]
+ and $r14 0x2000
+ bra ne #ctx_xfer_idle
+
+ bra not $p1 #ctx_xfer_pre
+ bra $p2 #ctx_xfer_pre_load
+ ctx_xfer_pre:
+ mov $r15 0x10
+ call #ctx_86c
+#if CHIPSET < GK100
+ call #ctx_4160s
+#endif
+ bra not $p1 #ctx_xfer_exec
+
+ ctx_xfer_pre_load:
+ mov $r15 2
+ call #ctx_4170s
+ call #ctx_4170w
+ call #ctx_redswitch
+ clear b32 $r15
+ call #ctx_4170s
+ call #ctx_load
+
+ // fetch context pointer, and initiate xfer on all GPCs
+ ctx_xfer_exec:
+ ld b32 $r1 D[$r0 + #ctx_current]
+ mov $r2 0x414
+ shl b32 $r2 6
+ iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset
+ mov $r14 -0x5b00
+ sethi $r14 0x410000
+ mov b32 $r15 $r1
+ call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer
+ add b32 $r14 4
+ xbit $r15 $flags $p1
+ xbit $r2 $flags $p2
+ shl b32 $r2 1
+ or $r15 $r2
+ call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
+
+ // strands
+ mov $r1 0x4afc
+ sethi $r1 0x20000
+ mov $r2 0xc
+ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
+ call #strand_wait
+ mov $r2 0x47fc
+ sethi $r2 0x20000
+ iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
+ xbit $r2 $flags $p1
+ add b32 $r2 3
+ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+
+ // mmio context
+ xbit $r10 $flags $p1 // direction
+ or $r10 6 // first, last
+ mov $r11 0 // base = 0
+ ld b32 $r12 D[$r0 + #hub_mmio_list_head]
+ ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
+ mov $r14 0 // not multi
+ call #mmctx_xfer
+
+ // wait for GPCs to all complete
+ mov $r10 8 // DONE_BAR
+ call #wait_doneo
+
+ // wait for strand xfer to complete
+ call #strand_wait
+
+ // post-op
+ bra $p1 #ctx_xfer_post
+ mov $r10 12 // DONE_UNK12
+ call #wait_donez
+ mov $r1 0xa10
+ shl b32 $r1 6
+ mov $r2 5
+ iowr I[$r1] $r2 // MEM_CMD
+ ctx_xfer_post_save_wait:
+ iord $r2 I[$r1]
+ or $r2 $r2
+ bra ne #ctx_xfer_post_save_wait
+
+ bra $p2 #ctx_xfer_done
+ ctx_xfer_post:
+ mov $r15 2
+ call #ctx_4170s
+ clear b32 $r15
+ call #ctx_86c
+ call #strand_post
+ call #ctx_4170w
+ clear b32 $r15
+ call #ctx_4170s
+
+ bra not $p1 #ctx_xfer_no_post_mmio
+ ld b32 $r1 D[$r0 + #chan_mmio_count]
+ or $r1 $r1
+ bra e #ctx_xfer_no_post_mmio
+ call #ctx_mmio_exec
+
+ ctx_xfer_no_post_mmio:
+#if CHIPSET < GK100
+ call #ctx_4160c
+#endif
+
+ ctx_xfer_done:
+ ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
index 7fbdebb2bafb..3ff52badf932 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nvc0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -20,850 +19,22 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-/* To build:
- * m4 hubnvc0.fuc | envyas -a -w -m fuc -V fuc3 -o hubnvc0.fuc.h
- */
+#define CHIPSET GF100
+#include "macros.fuc"
.section #nvc0_grhub_data
-include(`nvc0.fuc')
-gpc_count: .b32 0
-rop_count: .b32 0
-cmd_queue: queue_init
-hub_mmio_list_head: .b32 0
-hub_mmio_list_tail: .b32 0
-
-ctx_current: .b32 0
-
-chipsets:
-.b8 0xc0 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8 0xc1 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc1_hub_mmio_tail
-.b8 0xc3 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8 0xc4 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8 0xc8 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8 0xce 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8 0xcf 0 0 0
-.b16 #nvc0_hub_mmio_head
-.b16 #nvc0_hub_mmio_tail
-.b8 0xd9 0 0 0
-.b16 #nvd9_hub_mmio_head
-.b16 #nvd9_hub_mmio_tail
-.b8 0xd7 0 0 0
-.b16 #nvd9_hub_mmio_head
-.b16 #nvd9_hub_mmio_tail
-.b8 0 0 0 0
-
-nvc0_hub_mmio_head:
-mmctx_data(0x17e91c, 2)
-mmctx_data(0x400204, 2)
-mmctx_data(0x404004, 11)
-mmctx_data(0x404044, 1)
-mmctx_data(0x404094, 14)
-mmctx_data(0x4040d0, 7)
-mmctx_data(0x4040f8, 1)
-mmctx_data(0x404130, 3)
-mmctx_data(0x404150, 3)
-mmctx_data(0x404164, 2)
-mmctx_data(0x404174, 3)
-mmctx_data(0x404200, 8)
-mmctx_data(0x404404, 14)
-mmctx_data(0x404460, 4)
-mmctx_data(0x404480, 1)
-mmctx_data(0x404498, 1)
-mmctx_data(0x404604, 4)
-mmctx_data(0x404618, 32)
-mmctx_data(0x404698, 21)
-mmctx_data(0x4046f0, 2)
-mmctx_data(0x404700, 22)
-mmctx_data(0x405800, 1)
-mmctx_data(0x405830, 3)
-mmctx_data(0x405854, 1)
-mmctx_data(0x405870, 4)
-mmctx_data(0x405a00, 2)
-mmctx_data(0x405a18, 1)
-mmctx_data(0x406020, 1)
-mmctx_data(0x406028, 4)
-mmctx_data(0x4064a8, 2)
-mmctx_data(0x4064b4, 2)
-mmctx_data(0x407804, 1)
-mmctx_data(0x40780c, 6)
-mmctx_data(0x4078bc, 1)
-mmctx_data(0x408000, 7)
-mmctx_data(0x408064, 1)
-mmctx_data(0x408800, 3)
-mmctx_data(0x408900, 4)
-mmctx_data(0x408980, 1)
-nvc0_hub_mmio_tail:
-mmctx_data(0x4064c0, 2)
-nvc1_hub_mmio_tail:
-
-nvd9_hub_mmio_head:
-mmctx_data(0x17e91c, 2)
-mmctx_data(0x400204, 2)
-mmctx_data(0x404004, 10)
-mmctx_data(0x404044, 1)
-mmctx_data(0x404094, 14)
-mmctx_data(0x4040d0, 7)
-mmctx_data(0x4040f8, 1)
-mmctx_data(0x404130, 3)
-mmctx_data(0x404150, 3)
-mmctx_data(0x404164, 2)
-mmctx_data(0x404178, 2)
-mmctx_data(0x404200, 8)
-mmctx_data(0x404404, 14)
-mmctx_data(0x404460, 4)
-mmctx_data(0x404480, 1)
-mmctx_data(0x404498, 1)
-mmctx_data(0x404604, 4)
-mmctx_data(0x404618, 32)
-mmctx_data(0x404698, 21)
-mmctx_data(0x4046f0, 2)
-mmctx_data(0x404700, 22)
-mmctx_data(0x405800, 1)
-mmctx_data(0x405830, 3)
-mmctx_data(0x405854, 1)
-mmctx_data(0x405870, 4)
-mmctx_data(0x405a00, 2)
-mmctx_data(0x405a18, 1)
-mmctx_data(0x406020, 1)
-mmctx_data(0x406028, 4)
-mmctx_data(0x4064a8, 2)
-mmctx_data(0x4064b4, 5)
-mmctx_data(0x407804, 1)
-mmctx_data(0x40780c, 6)
-mmctx_data(0x4078bc, 1)
-mmctx_data(0x408000, 7)
-mmctx_data(0x408064, 1)
-mmctx_data(0x408800, 3)
-mmctx_data(0x408900, 4)
-mmctx_data(0x408980, 1)
-nvd9_hub_mmio_tail:
-
-.align 256
-chan_data:
-chan_mmio_count: .b32 0
-chan_mmio_address: .b32 0
-
-.align 256
-xfer_data: .b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
.section #nvc0_grhub_code
+#define INCLUDE_CODE
bra #init
-define(`include_code')
-include(`nvc0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nvc0.fuc)
-//
-error:
- push $r14
- mov $r14 0x814
- shl b32 $r14 6
- iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code
- mov $r14 0xc1c
- shl b32 $r14 6
- mov $r15 1
- iowr I[$r14 + 0x000] $r15 // INTR_UP_SET
- pop $r14
- ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//
-// Output:
-// CC_SCRATCH[0]:
-// 31:31: set to signal completion
-// CC_SCRATCH[1]:
-// 31:0: total PGRAPH context size
-//
-init:
- clear b32 $r0
- mov $sp $r0
- mov $xdbase $r0
-
- // enable fifo access
- mov $r1 0x1200
- mov $r2 2
- iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
-
- // setup i0 handler, and route all interrupts to it
- mov $r1 #ih
- mov $iv0 $r1
- mov $r1 0x400
- iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
-
- // route HUB_CHANNEL_SWITCH to fuc interrupt 8
- mov $r3 0x404
- shl b32 $r3 6
- mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
- iowr I[$r3 + 0x000] $r2
-
- // not sure what these are, route them because NVIDIA does, and
- // the IRQ handler will signal the host if we ever get one.. we
- // may find out if/why we need to handle these if so..
- //
- mov $r2 0x2004
- iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
- mov $r2 0x200b
- iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
- mov $r2 0x200c
- iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
-
- // enable all INTR_UP interrupts
- mov $r2 0xc24
- shl b32 $r2 6
- not b32 $r3 $r0
- iowr I[$r2] $r3
-
- // enable fifo, ctxsw, 9, 10, 15 interrupts
- mov $r2 -0x78fc // 0x8704
- sethi $r2 0
- iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
-
- // fifo level triggered, rest edge
- sub b32 $r1 0x100
- mov $r2 4
- iowr I[$r1] $r2
-
- // enable interrupts
- bset $flags ie0
-
- // fetch enabled GPC/ROP counts
- mov $r14 -0x69fc // 0x409604
- sethi $r14 0x400000
- call #nv_rd32
- extr $r1 $r15 16:20
- st b32 D[$r0 + #rop_count] $r1
- and $r15 0x1f
- st b32 D[$r0 + #gpc_count] $r15
-
- // set BAR_REQMASK to GPC mask
- mov $r1 1
- shl b32 $r1 $r15
- sub b32 $r1 1
- mov $r2 0x40c
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r1
- iowr I[$r2 + 0x100] $r1
-
- // find context data for this chipset
- mov $r2 0x800
- shl b32 $r2 6
- iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
- mov $r15 #chipsets - 8
- init_find_chipset:
- add b32 $r15 8
- ld b32 $r3 D[$r15 + 0x00]
- cmpu b32 $r3 $r2
- bra e #init_context
- cmpu b32 $r3 0
- bra ne #init_find_chipset
- // unknown chipset
- ret
-
- // context size calculation, reserve first 256 bytes for use by fuc
- init_context:
- mov $r1 256
-
- // calculate size of mmio context data
- ld b16 $r14 D[$r15 + 4]
- ld b16 $r15 D[$r15 + 6]
- sethi $r14 0
- st b32 D[$r0 + #hub_mmio_list_head] $r14
- st b32 D[$r0 + #hub_mmio_list_tail] $r15
- call #mmctx_size
-
- // set mmctx base addresses now so we don't have to do it later,
- // they don't (currently) ever change
- mov $r3 0x700
- shl b32 $r3 6
- shr b32 $r4 $r1 8
- iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE
- iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE
- add b32 $r3 0x1300
- add b32 $r1 $r15
- shr b32 $r15 2
- iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!?
-
- // strands, base offset needs to be aligned to 256 bytes
- shr b32 $r1 8
- add b32 $r1 1
- shl b32 $r1 8
- mov b32 $r15 $r1
- call #strand_ctx_init
- add b32 $r1 $r15
-
- // initialise each GPC in sequence by passing in the offset of its
- // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
- // has previously been uploaded by the host) running.
- //
- // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
- // when it has completed, and return the size of its context data
- // in GPCn_CC_SCRATCH[1]
- //
- ld b32 $r3 D[$r0 + #gpc_count]
- mov $r4 0x2000
- sethi $r4 0x500000
- init_gpc:
- // setup, and start GPC ucode running
- add b32 $r14 $r4 0x804
- mov b32 $r15 $r1
- call #nv_wr32 // CC_SCRATCH[1] = ctx offset
- add b32 $r14 $r4 0x800
- mov b32 $r15 $r2
- call #nv_wr32 // CC_SCRATCH[0] = chipset
- add b32 $r14 $r4 0x10c
- clear b32 $r15
- call #nv_wr32
- add b32 $r14 $r4 0x104
- call #nv_wr32 // ENTRY
- add b32 $r14 $r4 0x100
- mov $r15 2 // CTRL_START_TRIGGER
- call #nv_wr32 // CTRL
-
- // wait for it to complete, and adjust context size
- add b32 $r14 $r4 0x800
- init_gpc_wait:
- call #nv_rd32
- xbit $r15 $r15 31
- bra e #init_gpc_wait
- add b32 $r14 $r4 0x804
- call #nv_rd32
- add b32 $r1 $r15
-
- // next!
- add b32 $r4 0x8000
- sub b32 $r3 1
- bra ne #init_gpc
-
- // save context size, and tell host we're ready
- mov $r2 0x800
- shl b32 $r2 6
- iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size
- add b32 $r2 0x800
- clear b32 $r1
- bset $r1 31
- iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
- // sleep until we have something to do
- bset $flags $p0
- sleep $p0
- mov $r13 #cmd_queue
- call #queue_get
- bra $p1 #main
-
- // context switch, requested by GPU?
- cmpu b32 $r14 0x4001
- bra ne #main_not_ctx_switch
- trace_set(T_AUTO)
- mov $r1 0xb00
- shl b32 $r1 6
- iord $r2 I[$r1 + 0x100] // CHAN_NEXT
- iord $r1 I[$r1 + 0x000] // CHAN_CUR
-
- xbit $r3 $r1 31
- bra e #chsw_no_prev
- xbit $r3 $r2 31
- bra e #chsw_prev_no_next
- push $r2
- mov b32 $r2 $r1
- trace_set(T_SAVE)
- bclr $flags $p1
- bset $flags $p2
- call #ctx_xfer
- trace_clr(T_SAVE);
- pop $r2
- trace_set(T_LOAD);
- bset $flags $p1
- call #ctx_xfer
- trace_clr(T_LOAD);
- bra #chsw_done
- chsw_prev_no_next:
- push $r2
- mov b32 $r2 $r1
- bclr $flags $p1
- bclr $flags $p2
- call #ctx_xfer
- pop $r2
- mov $r1 0xb00
- shl b32 $r1 6
- iowr I[$r1] $r2
- bra #chsw_done
- chsw_no_prev:
- xbit $r3 $r2 31
- bra e #chsw_done
- bset $flags $p1
- bclr $flags $p2
- call #ctx_xfer
-
- // ack the context switch request
- chsw_done:
- mov $r1 0xb0c
- shl b32 $r1 6
- mov $r2 1
- iowr I[$r1 + 0x000] $r2 // 0x409b0c
- trace_clr(T_AUTO)
- bra #main
-
- // request to set current channel? (*not* a context switch)
- main_not_ctx_switch:
- cmpu b32 $r14 0x0001
- bra ne #main_not_ctx_chan
- mov b32 $r2 $r15
- call #ctx_chan
- bra #main_done
-
- // request to store current channel context?
- main_not_ctx_chan:
- cmpu b32 $r14 0x0002
- bra ne #main_not_ctx_save
- trace_set(T_SAVE)
- bclr $flags $p1
- bclr $flags $p2
- call #ctx_xfer
- trace_clr(T_SAVE)
- bra #main_done
-
- main_not_ctx_save:
- shl b32 $r15 $r14 16
- or $r15 E_BAD_COMMAND
- call #error
- bra #main
-
- main_done:
- mov $r1 0x820
- shl b32 $r1 6
- clear b32 $r2
- bset $r2 31
- iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
- bra #main
-
-// interrupt handler
-ih:
- push $r8
- mov $r8 $flags
- push $r8
- push $r9
- push $r10
- push $r11
- push $r13
- push $r14
- push $r15
-
- // incoming fifo command?
- iord $r10 I[$r0 + 0x200] // INTR
- and $r11 $r10 0x00000004
- bra e #ih_no_fifo
- // queue incoming fifo command for later processing
- mov $r11 0x1900
- mov $r13 #cmd_queue
- iord $r14 I[$r11 + 0x100] // FIFO_CMD
- iord $r15 I[$r11 + 0x000] // FIFO_DATA
- call #queue_put
- add b32 $r11 0x400
- mov $r14 1
- iowr I[$r11 + 0x000] $r14 // FIFO_ACK
-
- // context switch request?
- ih_no_fifo:
- and $r11 $r10 0x00000100
- bra e #ih_no_ctxsw
- // enqueue a context switch for later processing
- mov $r13 #cmd_queue
- mov $r14 0x4001
- call #queue_put
-
- // anything we didn't handle, bring it to the host's attention
- ih_no_ctxsw:
- mov $r11 0x104
- not b32 $r11
- and $r11 $r10 $r11
- bra e #ih_no_other
- mov $r10 0xc1c
- shl b32 $r10 6
- iowr I[$r10] $r11 // INTR_UP_SET
-
- // ack, and wake up main()
- ih_no_other:
- iowr I[$r0 + 0x100] $r10 // INTR_ACK
-
- pop $r15
- pop $r14
- pop $r13
- pop $r11
- pop $r10
- pop $r9
- pop $r8
- mov $flags $r8
- pop $r8
- bclr $flags $p0
- iret
-
-// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
-ctx_4160s:
- mov $r14 0x4160
- sethi $r14 0x400000
- mov $r15 1
- call #nv_wr32
- ctx_4160s_wait:
- call #nv_rd32
- xbit $r15 $r15 4
- bra e #ctx_4160s_wait
- ret
-
-// Without clearing again at end of xfer, some things cause PGRAPH
-// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
-// still function with it set however...
-ctx_4160c:
- mov $r14 0x4160
- sethi $r14 0x400000
- clear b32 $r15
- call #nv_wr32
- ret
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
- mov $r14 0x4170
- sethi $r14 0x400000
- or $r15 0x10
- call #nv_wr32
- ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
- mov $r14 0x4170
- sethi $r14 0x400000
- call #nv_rd32
- and $r15 0x10
- bra ne #ctx_4170w
- ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off? Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
- mov $r14 0x614
- shl b32 $r14 6
- mov $r15 0x270
- iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
- mov $r15 8
- ctx_redswitch_delay:
- sub b32 $r15 1
- bra ne #ctx_redswitch_delay
- mov $r15 0x770
- iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
- ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
- mov $r14 0x86c
- shl b32 $r14 6
- iowr I[$r14] $r15 // HUB(0x86c) = val
- mov $r14 -0x75ec
- sethi $r14 0x400000
- call #nv_wr32 // ROP(0xa14) = val
- mov $r14 -0x5794
- sethi $r14 0x410000
- call #nv_wr32 // GPC(0x86c) = val
- ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
- trace_set(T_CHAN)
-
- // switch to channel, somewhat magic in parts..
- mov $r10 12 // DONE_UNK12
- call #wait_donez
- mov $r1 0xa24
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r0 // 0x409a24
- mov $r3 0xb00
- shl b32 $r3 6
- iowr I[$r3 + 0x100] $r2 // CHAN_NEXT
- mov $r1 0xa0c
- shl b32 $r1 6
- mov $r4 7
- iowr I[$r1 + 0x000] $r2 // MEM_CHAN
- iowr I[$r1 + 0x100] $r4 // MEM_CMD
- ctx_chan_wait_0:
- iord $r4 I[$r1 + 0x100]
- and $r4 0x1f
- bra ne #ctx_chan_wait_0
- iowr I[$r3 + 0x000] $r2 // CHAN_CUR
-
- // load channel header, fetch PGRAPH context pointer
- mov $xtargets $r0
- bclr $r2 31
- shl b32 $r2 4
- add b32 $r2 2
-
- trace_set(T_LCHAN)
- mov $r1 0xa04
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r2 // MEM_BASE
- mov $r1 0xa20
- shl b32 $r1 6
- mov $r2 0x0002
- sethi $r2 0x80000000
- iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram
- mov $r1 0x10 // chan + 0x0210
- mov $r2 #xfer_data
- sethi $r2 0x00020000 // 16 bytes
- xdld $r1 $r2
- xdwait
- trace_clr(T_LCHAN)
-
- // update current context
- ld b32 $r1 D[$r0 + #xfer_data + 4]
- shl b32 $r1 24
- ld b32 $r2 D[$r0 + #xfer_data + 0]
- shr b32 $r2 8
- or $r1 $r2
- st b32 D[$r0 + #ctx_current] $r1
-
- // set transfer base to start of context, and fetch context header
- trace_set(T_LCTXH)
- mov $r2 0xa04
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r1 // MEM_BASE
- mov $r2 1
- mov $r1 0xa20
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm
- mov $r1 #chan_data
- sethi $r1 0x00060000 // 256 bytes
- xdld $r0 $r1
- xdwait
- trace_clr(T_LCTXH)
-
- trace_clr(T_CHAN)
- ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-// the active channel for ctxctl, but not actually transfer
-// any context data. intended for use only during initial
-// context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
- call #ctx_4160s
- call #ctx_load
- mov $r10 12 // DONE_UNK12
- call #wait_donez
- mov $r1 0xa10
- shl b32 $r1 6
- mov $r2 5
- iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???)
- ctx_chan_wait:
- iord $r2 I[$r1 + 0x000]
- or $r2 $r2
- bra ne #ctx_chan_wait
- call #ctx_4160c
- ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel. Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state... The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
- // set transfer base to be the mmio list
- ld b32 $r3 D[$r0 + #chan_mmio_address]
- mov $r2 0xa04
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r3 // MEM_BASE
-
- clear b32 $r3
- ctx_mmio_loop:
- // fetch next 256 bytes of mmio list if necessary
- and $r4 $r3 0xff
- bra ne #ctx_mmio_pull
- mov $r5 #xfer_data
- sethi $r5 0x00060000 // 256 bytes
- xdld $r3 $r5
- xdwait
-
- // execute a single list entry
- ctx_mmio_pull:
- ld b32 $r14 D[$r4 + #xfer_data + 0x00]
- ld b32 $r15 D[$r4 + #xfer_data + 0x04]
- call #nv_wr32
-
- // next!
- add b32 $r3 8
- sub b32 $r1 1
- bra ne #ctx_mmio_loop
-
- // set transfer base back to the current context
- ctx_mmio_done:
- ld b32 $r3 D[$r0 + #ctx_current]
- iowr I[$r2 + 0x000] $r3 // MEM_BASE
-
- // disable the mmio list now, we don't need/want to execute it again
- st b32 D[$r0 + #chan_mmio_count] $r0
- mov $r1 #chan_data
- sethi $r1 0x00060000 // 256 bytes
- xdst $r0 $r1
- xdwait
- ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-// $p1 clear on save, set on load
-// $p2 set if opposite direction done/will be done, so:
-// on save it means: "a load will follow this save"
-// on load it means: "a save preceeded this load"
-//
-ctx_xfer:
- // according to mwk, some kind of wait for idle
- mov $r15 0xc00
- shl b32 $r15 6
- mov $r14 4
- iowr I[$r15 + 0x200] $r14
- ctx_xfer_idle:
- iord $r14 I[$r15 + 0x000]
- and $r14 0x2000
- bra ne #ctx_xfer_idle
-
- bra not $p1 #ctx_xfer_pre
- bra $p2 #ctx_xfer_pre_load
- ctx_xfer_pre:
- mov $r15 0x10
- call #ctx_86c
- call #ctx_4160s
- bra not $p1 #ctx_xfer_exec
-
- ctx_xfer_pre_load:
- mov $r15 2
- call #ctx_4170s
- call #ctx_4170w
- call #ctx_redswitch
- clear b32 $r15
- call #ctx_4170s
- call #ctx_load
-
- // fetch context pointer, and initiate xfer on all GPCs
- ctx_xfer_exec:
- ld b32 $r1 D[$r0 + #ctx_current]
- mov $r2 0x414
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset
- mov $r14 -0x5b00
- sethi $r14 0x410000
- mov b32 $r15 $r1
- call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer
- add b32 $r14 4
- xbit $r15 $flags $p1
- xbit $r2 $flags $p2
- shl b32 $r2 1
- or $r15 $r2
- call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
- // strands
- mov $r1 0x4afc
- sethi $r1 0x20000
- mov $r2 0xc
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
- call #strand_wait
- mov $r2 0x47fc
- sethi $r2 0x20000
- iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
- xbit $r2 $flags $p1
- add b32 $r2 3
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
- // mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 6 // first, last
- mov $r11 0 // base = 0
- ld b32 $r12 D[$r0 + #hub_mmio_list_head]
- ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
- mov $r14 0 // not multi
- call #mmctx_xfer
-
- // wait for GPCs to all complete
- mov $r10 8 // DONE_BAR
- call #wait_doneo
-
- // wait for strand xfer to complete
- call #strand_wait
-
- // post-op
- bra $p1 #ctx_xfer_post
- mov $r10 12 // DONE_UNK12
- call #wait_donez
- mov $r1 0xa10
- shl b32 $r1 6
- mov $r2 5
- iowr I[$r1] $r2 // MEM_CMD
- ctx_xfer_post_save_wait:
- iord $r2 I[$r1]
- or $r2 $r2
- bra ne #ctx_xfer_post_save_wait
-
- bra $p2 #ctx_xfer_done
- ctx_xfer_post:
- mov $r15 2
- call #ctx_4170s
- clear b32 $r15
- call #ctx_86c
- call #strand_post
- call #ctx_4170w
- clear b32 $r15
- call #ctx_4170s
-
- bra not $p1 #ctx_xfer_no_post_mmio
- ld b32 $r1 D[$r0 + #chan_mmio_count]
- or $r1 $r1
- bra e #ctx_xfer_no_post_mmio
- call #ctx_mmio_exec
-
- ctx_xfer_no_post_mmio:
- call #ctx_4160c
-
- ctx_xfer_done:
- ret
-
+#include "com.fuc"
+#include "hub.fuc"
.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
index bb03d2a1d57b..b59f694c0423 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
@@ -1,9 +1,90 @@
uint32_t nvc0_grhub_data[] = {
-/* 0x0000: gpc_count */
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
-/* 0x0004: rop_count */
0x00000000,
-/* 0x0008: cmd_queue */
0x00000000,
0x00000000,
0x00000000,
@@ -22,114 +103,9 @@ uint32_t nvc0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0050: hub_mmio_list_head */
0x00000000,
-/* 0x0054: hub_mmio_list_tail */
0x00000000,
-/* 0x0058: ctx_current */
0x00000000,
-/* 0x005c: chipsets */
- 0x000000c0,
- 0x013c00a0,
- 0x000000c1,
- 0x014000a0,
- 0x000000c3,
- 0x013c00a0,
- 0x000000c4,
- 0x013c00a0,
- 0x000000c8,
- 0x013c00a0,
- 0x000000ce,
- 0x013c00a0,
- 0x000000cf,
- 0x013c00a0,
- 0x000000d9,
- 0x01dc0140,
- 0x00000000,
-/* 0x00a0: nvc0_hub_mmio_head */
- 0x0417e91c,
- 0x04400204,
- 0x28404004,
- 0x00404044,
- 0x34404094,
- 0x184040d0,
- 0x004040f8,
- 0x08404130,
- 0x08404150,
- 0x04404164,
- 0x08404174,
- 0x1c404200,
- 0x34404404,
- 0x0c404460,
- 0x00404480,
- 0x00404498,
- 0x0c404604,
- 0x7c404618,
- 0x50404698,
- 0x044046f0,
- 0x54404700,
- 0x00405800,
- 0x08405830,
- 0x00405854,
- 0x0c405870,
- 0x04405a00,
- 0x00405a18,
- 0x00406020,
- 0x0c406028,
- 0x044064a8,
- 0x044064b4,
- 0x00407804,
- 0x1440780c,
- 0x004078bc,
- 0x18408000,
- 0x00408064,
- 0x08408800,
- 0x0c408900,
- 0x00408980,
-/* 0x013c: nvc0_hub_mmio_tail */
- 0x044064c0,
-/* 0x0140: nvc1_hub_mmio_tail */
-/* 0x0140: nvd9_hub_mmio_head */
- 0x0417e91c,
- 0x04400204,
- 0x24404004,
- 0x00404044,
- 0x34404094,
- 0x184040d0,
- 0x004040f8,
- 0x08404130,
- 0x08404150,
- 0x04404164,
- 0x04404178,
- 0x1c404200,
- 0x34404404,
- 0x0c404460,
- 0x00404480,
- 0x00404498,
- 0x0c404604,
- 0x7c404618,
- 0x50404698,
- 0x044046f0,
- 0x54404700,
- 0x00405800,
- 0x08405830,
- 0x00405854,
- 0x0c405870,
- 0x04405a00,
- 0x00405a18,
- 0x00406020,
- 0x0c406028,
- 0x044064a8,
- 0x104064b4,
- 0x00407804,
- 0x1440780c,
- 0x004078bc,
- 0x18408000,
- 0x00408064,
- 0x08408800,
- 0x0c408900,
- 0x00408980,
-/* 0x01dc: nvd9_hub_mmio_tail */
0x00000000,
0x00000000,
0x00000000,
@@ -139,10 +115,7 @@ uint32_t nvc0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0200: chan_data */
-/* 0x0200: chan_mmio_count */
0x00000000,
-/* 0x0204: chan_mmio_address */
0x00000000,
0x00000000,
0x00000000,
@@ -163,6 +136,7 @@ uint32_t nvc0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
+/* 0x0200: xfer_data */
0x00000000,
0x00000000,
0x00000000,
@@ -206,19 +180,40 @@ uint32_t nvc0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0300: xfer_data */
0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
};
uint32_t nvc0_grhub_code[] = {
- 0x03090ef5,
+ 0x031b0ef5,
/* 0x0004: queue_put */
0x9800d898,
0x86f001d9,
0x0489b808,
0xf00c1bf4,
0x21f502f7,
- 0x00f802ec,
+ 0x00f802fe,
/* 0x001c: queue_put_next */
0xb60798c4,
0x8dbb0384,
@@ -250,7 +245,7 @@ uint32_t nvc0_grhub_code[] = {
0xc800bccf,
0x1bf41fcc,
0x06a7f0fa,
- 0x010321f5,
+ 0x010921f5,
0xf840bfcf,
/* 0x008d: nv_wr32 */
0x28b7f100,
@@ -272,63 +267,66 @@ uint32_t nvc0_grhub_code[] = {
0x0684b604,
0xf80080d0,
/* 0x00c9: wait_donez */
- 0x3c87f100,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d000,
- 0x081887f1,
- 0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
- 0x87f1008a,
- 0x84b60400,
- 0x0088cf06,
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
0xf4888aff,
- 0x87f1f31b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00099,
-/* 0x0103: wait_doneo */
- 0xf100f800,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00099f0,
- 0x87f10089,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x87f104bd,
0x84b60818,
0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
0x040087f1,
0xcf0684b6,
0x8aff0088,
0xf30bf488,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0099f094,
- 0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
- 0x9894bd00,
- 0x85b600e8,
- 0x0180b61a,
- 0xbb0284b6,
- 0xe0b60098,
- 0x04efb804,
- 0xb9eb1bf4,
- 0x00f8029f,
-/* 0x015c: mmctx_xfer */
- 0x083c87f1,
- 0xbd0684b6,
- 0x0199f094,
- 0xf10089d0,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
0xb6071087,
0x94bd0684,
0xf405bbfd,
0x8bd0090b,
0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
0xf405eefd,
0x8ed00c0b,
0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
0xb70199f0,
0xc8010080,
0xb4b600ab,
@@ -336,8 +334,8 @@ uint32_t nvc0_grhub_code[] = {
0xb601aec8,
0xbefd11e4,
0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
0xf0008ecf,
0x0bf41fe4,
0x00ce98fa,
@@ -346,76 +344,77 @@ uint32_t nvc0_grhub_code[] = {
0x04cdb804,
0xc8e81bf4,
0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
0x008bcf18,
0xb01fb4f0,
0x1bf410b4,
0x02a7f0f7,
0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
0xabc81b0e,
0x10b4b600,
0xf00cb9f0,
0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
0x008bcf00,
0xf412bbc8,
-/* 0x01f6: mmctx_done */
- 0x87f1fa1b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00199,
-/* 0x0207: strand_wait */
- 0xf900f800,
- 0x02a7f0a0,
- 0xfcc921f4,
-/* 0x0213: strand_pre */
- 0xf100f8a0,
- 0xf04afc87,
- 0x97f00283,
- 0x0089d00c,
- 0x020721f5,
-/* 0x0226: strand_post */
- 0x87f100f8,
- 0x83f04afc,
- 0x0d97f002,
- 0xf50089d0,
- 0xf8020721,
-/* 0x0239: strand_set */
- 0xfca7f100,
- 0x02a3f04f,
- 0x0500aba2,
- 0xd00fc7f0,
- 0xc7f000ac,
- 0x00bcd00b,
- 0x020721f5,
- 0xf000aed0,
- 0xbcd00ac7,
- 0x0721f500,
-/* 0x0263: strand_ctx_init */
- 0xf100f802,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00399f0,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
0x21f50089,
- 0xe7f00213,
- 0x3921f503,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
0xfca7f102,
0x02a3f046,
0x0400aba0,
0xf040a0d0,
0xbcd001c7,
- 0x0721f500,
+ 0x1521f500,
0x010c9202,
0xf000acd0,
0xbcd002c7,
- 0x0721f500,
- 0x2621f502,
+ 0x1521f500,
+ 0x3421f502,
0x8087f102,
0x0684b608,
0xb70089cf,
0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
0x8ed008fe,
0x408ed000,
0xb6808acf,
@@ -424,73 +423,61 @@ uint32_t nvc0_grhub_code[] = {
0xb60480b6,
0x1bf40192,
0x08e4b6e8,
- 0xf1f2efbc,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00399f0,
- 0x00f80089,
-/* 0x02ec: error */
- 0xe7f1e0f9,
- 0xe4b60814,
- 0x00efd006,
- 0x0c1ce7f1,
- 0xf006e4b6,
- 0xefd001f7,
- 0xf8e0fc00,
-/* 0x0309: init */
- 0xfe04bd00,
- 0x07fe0004,
- 0x0017f100,
- 0x0227f012,
- 0xf10012d0,
- 0xfe05b917,
- 0x17f10010,
- 0x10d00400,
- 0x0437f1c0,
- 0x0634b604,
- 0x200327f1,
- 0xf10032d0,
- 0xd0200427,
- 0x27f10132,
- 0x32d0200b,
- 0x0c27f102,
- 0x0732d020,
- 0x0c2427f1,
- 0xb90624b6,
- 0x23d00003,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x031b: init */
+ 0xbd00f804,
+ 0x0004fe04,
+ 0xf10007fe,
+ 0xf0120017,
+ 0x12d00227,
+ 0xb117f100,
+ 0x0010fe05,
+ 0x040017f1,
+ 0xf1c010d0,
+ 0xb6040437,
+ 0x27f10634,
+ 0x32d02003,
0x0427f100,
- 0x0023f087,
- 0xb70012d0,
- 0xf0010012,
- 0x12d00427,
- 0x1031f400,
- 0x9604e7f1,
- 0xf440e3f0,
- 0xf1c76821,
- 0x01018090,
- 0x801ff4f0,
- 0x17f0000f,
- 0x041fbb01,
- 0xf10112b6,
- 0xb6040c27,
- 0x21d00624,
- 0x4021d000,
- 0x080027f1,
- 0xcf0624b6,
- 0xf7f00022,
-/* 0x03a9: init_find_chipset */
- 0x08f0b654,
- 0xb800f398,
- 0x0bf40432,
- 0x0034b00b,
- 0xf8f11bf4,
-/* 0x03bd: init_context */
- 0x0017f100,
- 0x02fe5801,
- 0xf003ff58,
- 0x0e8000e3,
- 0x150f8014,
- 0x013d21f5,
+ 0x0132d020,
+ 0x200b27f1,
+ 0xf10232d0,
+ 0xd0200c27,
+ 0x27f10732,
+ 0x24b60c24,
+ 0x0003b906,
+ 0xf10023d0,
+ 0xf0870427,
+ 0x12d00023,
+ 0x0012b700,
+ 0x0427f001,
+ 0xf40012d0,
+ 0xe7f11031,
+ 0xe3f09604,
+ 0x6821f440,
+ 0x8090f1c7,
+ 0xf4f00301,
+ 0x020f801f,
+ 0xbb0117f0,
+ 0x12b6041f,
+ 0x0c27f101,
+ 0x0624b604,
+ 0xd00021d0,
+ 0x17f14021,
+ 0x0e980100,
+ 0x010f9800,
+ 0x014721f5,
0x070037f1,
0x950634b6,
0x34d00814,
@@ -501,208 +488,213 @@ uint32_t nvc0_grhub_code[] = {
0x0815b600,
0xb60110b6,
0x1fb90814,
- 0x6321f502,
+ 0x7121f502,
0x001fbb02,
- 0xf1000398,
+ 0xf1020398,
0xf0200047,
-/* 0x040e: init_gpc */
+/* 0x03f6: init_gpc */
0x4ea05043,
0x1fb90804,
0x8d21f402,
- 0x08004ea0,
- 0xf4022fb9,
- 0x4ea08d21,
- 0xf4bd010c,
- 0xa08d21f4,
- 0xf401044e,
+ 0x010c4ea0,
+ 0x21f4f4bd,
+ 0x044ea08d,
+ 0x8d21f401,
+ 0x01004ea0,
+ 0xf402f7f0,
0x4ea08d21,
- 0xf7f00100,
- 0x8d21f402,
- 0x08004ea0,
-/* 0x0440: init_gpc_wait */
- 0xc86821f4,
- 0x0bf41fff,
- 0x044ea0fa,
- 0x6821f408,
- 0xb7001fbb,
- 0xb6800040,
- 0x1bf40132,
- 0x0027f1b4,
- 0x0624b608,
- 0xb74021d0,
- 0xbd080020,
+/* 0x041e: init_gpc_wait */
+ 0x21f40800,
+ 0x1fffc868,
+ 0xa0fa0bf4,
+ 0xf408044e,
+ 0x1fbb6821,
+ 0x0040b700,
+ 0x0132b680,
+ 0xf1be1bf4,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
0x1f19f014,
-/* 0x0473: main */
- 0xf40021d0,
- 0x28f40031,
- 0x08d7f000,
- 0xf43921f4,
- 0xe4b1f401,
- 0x1bf54001,
- 0x87f100d1,
- 0x84b6083c,
- 0xf094bd06,
- 0x89d00499,
- 0x0017f100,
- 0x0614b60b,
- 0xcf4012cf,
- 0x13c80011,
- 0x7e0bf41f,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0458: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00de1b,
+ 0x0499f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0b0017f1,
+ 0xcf0614b6,
+ 0x11cf4012,
+ 0x1f13c800,
+ 0x00870bf5,
0xf41f23c8,
- 0x20f95a0b,
- 0xf10212b9,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00799f0,
- 0x32f40089,
- 0x0231f401,
- 0x082921f5,
- 0x085c87f1,
- 0xbd0684b6,
+ 0x20f9620b,
+ 0xbd0212b9,
0x0799f094,
- 0xfc0089d0,
- 0x3c87f120,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d006,
- 0xf50131f4,
- 0xf1082921,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00699f0,
- 0x0ef40089,
-/* 0x0509: chsw_prev_no_next */
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xf40132f4,
+ 0x21f50231,
+ 0x94bd082f,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xfc04bd00,
+ 0xf094bd20,
+ 0x07f10699,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x31f404bd,
+ 0x2f21f501,
+ 0xf094bd08,
+ 0x07f10699,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
0xb920f931,
0x32f40212,
0x0232f401,
- 0x082921f5,
+ 0x082f21f5,
0x17f120fc,
0x14b60b00,
0x0012d006,
-/* 0x0527: chsw_no_prev */
+/* 0x0517: chsw_no_prev */
0xc8130ef4,
0x0bf41f23,
0x0131f40d,
0xf50232f4,
-/* 0x0537: chsw_done */
- 0xf1082921,
+/* 0x0527: chsw_done */
+ 0xf1082f21,
0xb60b0c17,
0x27f00614,
0x0012d001,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0499f094,
- 0xf50089d0,
-/* 0x0557: main_not_ctx_switch */
- 0xb0ff200e,
- 0x1bf401e4,
- 0x02f2b90d,
- 0x07b521f5,
-/* 0x0567: main_not_ctx_chan */
- 0xb0420ef4,
- 0x1bf402e4,
- 0x3c87f12e,
- 0x0684b608,
0x99f094bd,
- 0x0089d007,
+ 0x0007f104,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+ 0x01e4b0ff,
+ 0xb90d1bf4,
+ 0x21f502f2,
+ 0x0ef407bb,
+/* 0x0559: main_not_ctx_chan */
+ 0x02e4b046,
+ 0xbd321bf4,
+ 0x0799f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
0xf40132f4,
0x21f50232,
- 0x87f10829,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00799,
- 0x110ef400,
-/* 0x0598: main_not_ctx_save */
- 0xf010ef94,
- 0x21f501f5,
- 0x0ef502ec,
-/* 0x05a6: main_done */
- 0x17f1fed1,
- 0x14b60820,
- 0xf024bd06,
- 0x12d01f29,
- 0xbe0ef500,
-/* 0x05b9: ih */
+ 0x94bd082f,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+ 0xef94110e,
+ 0x01f5f010,
+ 0x02fe21f5,
+ 0xfec00ef5,
+/* 0x059c: main_done */
+ 0x29f024bd,
+ 0x0007f11f,
+ 0x0203f008,
+ 0xbd0002d0,
+ 0xab0ef504,
+/* 0x05b1: ih */
0xfe80f9fe,
0x80f90188,
0xa0f990f9,
0xd0f9b0f9,
0xf0f9e0f9,
- 0xc4800acf,
- 0x0bf404ab,
- 0x00b7f11d,
- 0x08d7f019,
- 0xcf40becf,
- 0x21f400bf,
- 0x00b0b704,
- 0x01e7f004,
-/* 0x05ef: ih_no_fifo */
- 0xe400bed0,
- 0xf40100ab,
- 0xd7f00d0b,
- 0x01e7f108,
- 0x0421f440,
-/* 0x0600: ih_no_ctxsw */
- 0x0104b7f1,
- 0xabffb0bd,
- 0x0d0bf4b4,
- 0x0c1ca7f1,
- 0xd006a4b6,
-/* 0x0616: ih_no_other */
- 0x0ad000ab,
- 0xfcf0fc40,
- 0xfcd0fce0,
- 0xfca0fcb0,
- 0xfe80fc90,
- 0x80fc0088,
- 0xf80032f4,
-/* 0x0631: ctx_4160s */
- 0x60e7f101,
- 0x40e3f041,
- 0xf401f7f0,
-/* 0x063e: ctx_4160s_wait */
- 0x21f48d21,
- 0x04ffc868,
- 0xf8fa0bf4,
-/* 0x0649: ctx_4160c */
- 0x60e7f100,
+ 0x0acf04bd,
+ 0x04abc480,
+ 0xf11d0bf4,
+ 0xf01900b7,
+ 0xbecf10d7,
+ 0x00bfcf40,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+ 0x00abe400,
+ 0x0d0bf401,
+ 0xf110d7f0,
+ 0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+ 0xb7f10421,
+ 0xb0bd0104,
+ 0xf4b4abff,
+ 0xa7f10d0b,
+ 0xa4b60c1c,
+ 0x00abd006,
+/* 0x0610: ih_no_other */
+ 0xfc400ad0,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x062b: ctx_4160s */
+ 0xf101f800,
+ 0xf04160e7,
+ 0xf7f040e3,
+ 0x8d21f401,
+/* 0x0638: ctx_4160s_wait */
+ 0xc86821f4,
+ 0x0bf404ff,
+/* 0x0643: ctx_4160c */
+ 0xf100f8fa,
+ 0xf04160e7,
+ 0xf4bd40e3,
+ 0xf88d21f4,
+/* 0x0651: ctx_4170s */
+ 0x70e7f100,
0x40e3f041,
- 0x21f4f4bd,
-/* 0x0657: ctx_4170s */
- 0xf100f88d,
- 0xf04170e7,
- 0xf5f040e3,
- 0x8d21f410,
-/* 0x0666: ctx_4170w */
- 0xe7f100f8,
- 0xe3f04170,
- 0x6821f440,
- 0xf410f4f0,
- 0x00f8f31b,
-/* 0x0678: ctx_redswitch */
- 0x0614e7f1,
- 0xf106e4b6,
- 0xd00270f7,
- 0xf7f000ef,
-/* 0x0689: ctx_redswitch_delay */
- 0x01f2b608,
- 0xf1fd1bf4,
- 0xd00770f7,
- 0x00f800ef,
-/* 0x0698: ctx_86c */
- 0x086ce7f1,
- 0xd006e4b6,
- 0xe7f100ef,
- 0xe3f08a14,
- 0x8d21f440,
- 0xa86ce7f1,
- 0xf441e3f0,
+ 0xf410f5f0,
0x00f88d21,
-/* 0x06b8: ctx_load */
- 0x083c87f1,
- 0xbd0684b6,
- 0x0599f094,
- 0xf00089d0,
+/* 0x0660: ctx_4170w */
+ 0x4170e7f1,
+ 0xf440e3f0,
+ 0xf4f06821,
+ 0xf31bf410,
+/* 0x0672: ctx_redswitch */
+ 0xe7f100f8,
+ 0xe4b60614,
+ 0x70f7f106,
+ 0x00efd002,
+/* 0x0683: ctx_redswitch_delay */
+ 0xb608f7f0,
+ 0x1bf401f2,
+ 0x70f7f1fd,
+ 0x00efd007,
+/* 0x0692: ctx_86c */
+ 0xe7f100f8,
+ 0xe4b6086c,
+ 0x00efd006,
+ 0x8a14e7f1,
+ 0xf440e3f0,
+ 0xe7f18d21,
+ 0xe3f0a86c,
+ 0x8d21f441,
+/* 0x06b2: ctx_load */
+ 0x94bd00f8,
+ 0xf10599f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf004bd00,
0x21f40ca7,
0x2417f1c9,
0x0614b60a,
@@ -713,168 +705,169 @@ uint32_t nvc0_grhub_code[] = {
0x0614b60a,
0xd00747f0,
0x14d00012,
-/* 0x06f1: ctx_chan_wait_0 */
+/* 0x06ed: ctx_chan_wait_0 */
0x4014cf40,
0xf41f44f0,
0x32d0fa1b,
0x000bfe00,
0xb61f2af0,
0x20b60424,
- 0x3c87f102,
- 0x0684b608,
+ 0xf094bd02,
+ 0x07f10899,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x17f104bd,
+ 0x14b60a04,
+ 0x0012d006,
+ 0x0a2017f1,
+ 0xf00614b6,
+ 0x23f10227,
+ 0x12d08000,
+ 0x1017f000,
+ 0x020027f1,
+ 0xfa0223f0,
+ 0x03f80512,
0x99f094bd,
- 0x0089d008,
- 0x0a0417f1,
- 0xd00614b6,
- 0x17f10012,
- 0x14b60a20,
- 0x0227f006,
- 0x800023f1,
- 0xf00012d0,
- 0x27f11017,
- 0x23f00300,
- 0x0512fa02,
- 0x87f103f8,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00899,
- 0xc1019800,
+ 0x0007f108,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x81019804,
0x981814b6,
- 0x25b6c002,
+ 0x25b68002,
0x0512fd08,
- 0xf1160180,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00999f0,
- 0x27f10089,
- 0x24b60a04,
- 0x0021d006,
- 0xf10127f0,
- 0xb60a2017,
- 0x12d00614,
- 0x0017f100,
- 0x0613f002,
- 0xf80501fa,
- 0x5c87f103,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d009,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0599f094,
- 0xf80089d0,
-/* 0x07b5: ctx_chan */
- 0x3121f500,
- 0xb821f506,
- 0x0ca7f006,
- 0xf1c921f4,
- 0xb60a1017,
- 0x27f00614,
- 0x0012d005,
-/* 0x07d0: ctx_chan_wait */
- 0xfd0012cf,
- 0x1bf40522,
- 0x4921f5fa,
-/* 0x07df: ctx_mmio_exec */
- 0x9800f806,
- 0x27f18103,
- 0x24b60a04,
- 0x0023d006,
-/* 0x07ee: ctx_mmio_loop */
- 0x34c434bd,
- 0x0f1bf4ff,
- 0x030057f1,
- 0xfa0653f0,
- 0x03f80535,
-/* 0x0800: ctx_mmio_pull */
- 0x98c04e98,
- 0x21f4c14f,
- 0x0830b68d,
- 0xf40112b6,
-/* 0x0812: ctx_mmio_done */
- 0x0398df1b,
- 0x0023d016,
- 0xf1800080,
- 0xf0020017,
+ 0xbd160180,
+ 0x0999f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0a0427f1,
+ 0xd00624b6,
+ 0x27f00021,
+ 0x2017f101,
+ 0x0614b60a,
+ 0xf10012d0,
+ 0xf0010017,
0x01fa0613,
- 0xf803f806,
-/* 0x0829: ctx_xfer */
- 0x00f7f100,
- 0x06f4b60c,
- 0xd004e7f0,
-/* 0x0836: ctx_xfer_idle */
- 0xfecf80fe,
- 0x00e4f100,
- 0xf91bf420,
- 0xf40611f4,
-/* 0x0846: ctx_xfer_pre */
- 0xf7f01102,
- 0x9821f510,
- 0x3121f506,
- 0x1c11f406,
-/* 0x0854: ctx_xfer_pre_load */
- 0xf502f7f0,
- 0xf5065721,
- 0xf5066621,
- 0xbd067821,
- 0x5721f5f4,
- 0xb821f506,
-/* 0x086d: ctx_xfer_exec */
- 0x16019806,
- 0x041427f1,
+ 0xbd03f805,
+ 0x0999f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x99f094bd,
+ 0x0007f105,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x07bb: ctx_chan */
+ 0xf500f804,
+ 0xf5062b21,
+ 0xf006b221,
+ 0x21f40ca7,
+ 0x1017f1c9,
+ 0x0614b60a,
+ 0xd00527f0,
+/* 0x07d6: ctx_chan_wait */
+ 0x12cf0012,
+ 0x0522fd00,
+ 0xf5fa1bf4,
+ 0xf8064321,
+/* 0x07e5: ctx_mmio_exec */
+ 0x41039800,
+ 0x0a0427f1,
0xd00624b6,
- 0xe7f10020,
- 0xe3f0a500,
- 0x021fb941,
+ 0x34bd0023,
+/* 0x07f4: ctx_mmio_loop */
+ 0xf4ff34c4,
+ 0x57f10f1b,
+ 0x53f00200,
+ 0x0535fa06,
+/* 0x0806: ctx_mmio_pull */
+ 0x4e9803f8,
+ 0x814f9880,
0xb68d21f4,
- 0xfcf004e0,
- 0x022cf001,
- 0xfd0124b6,
- 0x21f405f2,
- 0xfc17f18d,
- 0x0213f04a,
- 0xd00c27f0,
- 0x21f50012,
- 0x27f10207,
- 0x23f047fc,
- 0x0020d002,
- 0xb6012cf0,
- 0x12d00320,
- 0x01acf000,
- 0xf006a5f0,
- 0x0c9800b7,
- 0x150d9814,
- 0xf500e7f0,
- 0xf0015c21,
- 0x21f508a7,
- 0x21f50103,
- 0x01f40207,
- 0x0ca7f022,
- 0xf1c921f4,
- 0xb60a1017,
- 0x27f00614,
- 0x0012d005,
-/* 0x08f4: ctx_xfer_post_save_wait */
- 0xfd0012cf,
- 0x1bf40522,
- 0x3202f4fa,
-/* 0x0900: ctx_xfer_post */
- 0xf502f7f0,
- 0xbd065721,
- 0x9821f5f4,
- 0x2621f506,
- 0x6621f502,
+ 0x12b60830,
+ 0xdf1bf401,
+/* 0x0818: ctx_mmio_done */
+ 0xd0160398,
+ 0x00800023,
+ 0x0017f140,
+ 0x0613f001,
+ 0xf80601fa,
+/* 0x082f: ctx_xfer */
+ 0xf100f803,
+ 0xb60c00f7,
+ 0xe7f006f4,
+ 0x80fed004,
+/* 0x083c: ctx_xfer_idle */
+ 0xf100fecf,
+ 0xf42000e4,
+ 0x11f4f91b,
+ 0x1102f406,
+/* 0x084c: ctx_xfer_pre */
+ 0xf510f7f0,
+ 0xf5069221,
+ 0xf4062b21,
+/* 0x085a: ctx_xfer_pre_load */
+ 0xf7f01c11,
+ 0x5121f502,
+ 0x6021f506,
+ 0x7221f506,
0xf5f4bd06,
- 0xf4065721,
- 0x01981011,
- 0x0511fd80,
- 0xf5070bf4,
-/* 0x092b: ctx_xfer_no_post_mmio */
- 0xf507df21,
-/* 0x092f: ctx_xfer_done */
- 0xf8064921,
- 0x00000000,
- 0x00000000,
+ 0xf5065121,
+/* 0x0873: ctx_xfer_exec */
+ 0x9806b221,
+ 0x27f11601,
+ 0x24b60414,
+ 0x0020d006,
+ 0xa500e7f1,
+ 0xb941e3f0,
+ 0x21f4021f,
+ 0x04e0b68d,
+ 0xf001fcf0,
+ 0x24b6022c,
+ 0x05f2fd01,
+ 0xf18d21f4,
+ 0xf04afc17,
+ 0x27f00213,
+ 0x0012d00c,
+ 0x021521f5,
+ 0x47fc27f1,
+ 0xd00223f0,
+ 0x2cf00020,
+ 0x0320b601,
+ 0xf00012d0,
+ 0xa5f001ac,
+ 0x00b7f006,
+ 0x98000c98,
+ 0xe7f0010d,
+ 0x6621f500,
+ 0x08a7f001,
+ 0x010921f5,
+ 0x021521f5,
+ 0xf02201f4,
+ 0x21f40ca7,
+ 0x1017f1c9,
+ 0x0614b60a,
+ 0xd00527f0,
+/* 0x08fa: ctx_xfer_post_save_wait */
+ 0x12cf0012,
+ 0x0522fd00,
+ 0xf4fa1bf4,
+/* 0x0906: ctx_xfer_post */
+ 0xf7f03202,
+ 0x5121f502,
+ 0xf5f4bd06,
+ 0xf5069221,
+ 0xf5023421,
+ 0xbd066021,
+ 0x5121f5f4,
+ 0x1011f406,
+ 0xfd400198,
+ 0x0bf40511,
+ 0xe521f507,
+/* 0x0931: ctx_xfer_no_post_mmio */
+ 0x4321f507,
+/* 0x0935: ctx_xfer_done */
+ 0x0000f806,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
new file mode 100644
index 000000000000..afbe03ac9077
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #nvd7_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #nvd7_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
new file mode 100644
index 000000000000..a1b9f763996a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
@@ -0,0 +1,921 @@
+uint32_t nvd7_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t nvd7_grhub_code[] = {
+ 0x031b0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f802fe,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0x0728b7f1,
+ 0xb906b4b6,
+ 0xc9f002ec,
+ 0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+ 0xc800bccf,
+ 0x1bf41fcc,
+ 0x06a7f0fa,
+ 0x010921f5,
+ 0xf840bfcf,
+/* 0x008d: nv_wr32 */
+ 0x28b7f100,
+ 0x06b4b607,
+ 0xb980bfd0,
+ 0xc9f002ec,
+ 0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+ 0xcf00bcd0,
+ 0xccc800bc,
+ 0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+ 0x87f100f8,
+ 0x84b60430,
+ 0x1ff9f006,
+ 0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+ 0x3087f100,
+ 0x0684b604,
+ 0xf80080d0,
+/* 0x00c9: wait_donez */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
+ 0xf4888aff,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x87f104bd,
+ 0x84b60818,
+ 0x008ad006,
+/* 0x0124: wait_doneo_e */
+ 0x040087f1,
+ 0xcf0684b6,
+ 0x8aff0088,
+ 0xf30bf488,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xb6071087,
+ 0x94bd0684,
+ 0xf405bbfd,
+ 0x8bd0090b,
+ 0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+ 0xf405eefd,
+ 0x8ed00c0b,
+ 0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+ 0xb70199f0,
+ 0xc8010080,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xb601aec8,
+ 0xbefd11e4,
+ 0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+ 0xf0008ecf,
+ 0x0bf41fe4,
+ 0x00ce98fa,
+ 0xd005e9fd,
+ 0xc0b6c08e,
+ 0x04cdb804,
+ 0xc8e81bf4,
+ 0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+ 0x008bcf18,
+ 0xb01fb4f0,
+ 0x1bf410b4,
+ 0x02a7f0f7,
+ 0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+ 0xabc81b0e,
+ 0x10b4b600,
+ 0xf00cb9f0,
+ 0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+ 0x008bcf00,
+ 0xf412bbc8,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
+ 0x21f50089,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
+ 0xfca7f102,
+ 0x02a3f046,
+ 0x0400aba0,
+ 0xf040a0d0,
+ 0xbcd001c7,
+ 0x1521f500,
+ 0x010c9202,
+ 0xf000acd0,
+ 0xbcd002c7,
+ 0x1521f500,
+ 0x3421f502,
+ 0x8087f102,
+ 0x0684b608,
+ 0xb70089cf,
+ 0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x031b: init */
+ 0xbd00f804,
+ 0x0004fe04,
+ 0xf10007fe,
+ 0xf0120017,
+ 0x12d00227,
+ 0xb117f100,
+ 0x0010fe05,
+ 0x040017f1,
+ 0xf1c010d0,
+ 0xb6040437,
+ 0x27f10634,
+ 0x32d02003,
+ 0x0427f100,
+ 0x0132d020,
+ 0x200b27f1,
+ 0xf10232d0,
+ 0xd0200c27,
+ 0x27f10732,
+ 0x24b60c24,
+ 0x0003b906,
+ 0xf10023d0,
+ 0xf0870427,
+ 0x12d00023,
+ 0x0012b700,
+ 0x0427f001,
+ 0xf40012d0,
+ 0xe7f11031,
+ 0xe3f09604,
+ 0x6821f440,
+ 0x8090f1c7,
+ 0xf4f00301,
+ 0x020f801f,
+ 0xbb0117f0,
+ 0x12b6041f,
+ 0x0c27f101,
+ 0x0624b604,
+ 0xd00021d0,
+ 0x17f14021,
+ 0x0e980100,
+ 0x010f9800,
+ 0x014721f5,
+ 0x070037f1,
+ 0x950634b6,
+ 0x34d00814,
+ 0x4034d000,
+ 0x130030b7,
+ 0xb6001fbb,
+ 0x3fd002f5,
+ 0x0815b600,
+ 0xb60110b6,
+ 0x1fb90814,
+ 0x7121f502,
+ 0x001fbb02,
+ 0xf1020398,
+ 0xf0200047,
+/* 0x03f6: init_gpc */
+ 0x4ea05043,
+ 0x1fb90804,
+ 0x8d21f402,
+ 0x010c4ea0,
+ 0x21f4f4bd,
+ 0x044ea08d,
+ 0x8d21f401,
+ 0x01004ea0,
+ 0xf402f7f0,
+ 0x4ea08d21,
+/* 0x041e: init_gpc_wait */
+ 0x21f40800,
+ 0x1fffc868,
+ 0xa0fa0bf4,
+ 0xf408044e,
+ 0x1fbb6821,
+ 0x0040b700,
+ 0x0132b680,
+ 0xf1be1bf4,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0458: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00de1b,
+ 0x0499f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0b0017f1,
+ 0xcf0614b6,
+ 0x11cf4012,
+ 0x1f13c800,
+ 0x00870bf5,
+ 0xf41f23c8,
+ 0x20f9620b,
+ 0xbd0212b9,
+ 0x0799f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xf40132f4,
+ 0x21f50231,
+ 0x94bd082f,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xfc04bd00,
+ 0xf094bd20,
+ 0x07f10699,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x31f404bd,
+ 0x2f21f501,
+ 0xf094bd08,
+ 0x07f10699,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
+ 0xb920f931,
+ 0x32f40212,
+ 0x0232f401,
+ 0x082f21f5,
+ 0x17f120fc,
+ 0x14b60b00,
+ 0x0012d006,
+/* 0x0517: chsw_no_prev */
+ 0xc8130ef4,
+ 0x0bf41f23,
+ 0x0131f40d,
+ 0xf50232f4,
+/* 0x0527: chsw_done */
+ 0xf1082f21,
+ 0xb60b0c17,
+ 0x27f00614,
+ 0x0012d001,
+ 0x99f094bd,
+ 0x0007f104,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+ 0x01e4b0ff,
+ 0xb90d1bf4,
+ 0x21f502f2,
+ 0x0ef407bb,
+/* 0x0559: main_not_ctx_chan */
+ 0x02e4b046,
+ 0xbd321bf4,
+ 0x0799f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xf40132f4,
+ 0x21f50232,
+ 0x94bd082f,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+ 0xef94110e,
+ 0x01f5f010,
+ 0x02fe21f5,
+ 0xfec00ef5,
+/* 0x059c: main_done */
+ 0x29f024bd,
+ 0x0007f11f,
+ 0x0203f008,
+ 0xbd0002d0,
+ 0xab0ef504,
+/* 0x05b1: ih */
+ 0xfe80f9fe,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0x0acf04bd,
+ 0x04abc480,
+ 0xf11d0bf4,
+ 0xf01900b7,
+ 0xbecf10d7,
+ 0x00bfcf40,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+ 0x00abe400,
+ 0x0d0bf401,
+ 0xf110d7f0,
+ 0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+ 0xb7f10421,
+ 0xb0bd0104,
+ 0xf4b4abff,
+ 0xa7f10d0b,
+ 0xa4b60c1c,
+ 0x00abd006,
+/* 0x0610: ih_no_other */
+ 0xfc400ad0,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x062b: ctx_4160s */
+ 0xf101f800,
+ 0xf04160e7,
+ 0xf7f040e3,
+ 0x8d21f401,
+/* 0x0638: ctx_4160s_wait */
+ 0xc86821f4,
+ 0x0bf404ff,
+/* 0x0643: ctx_4160c */
+ 0xf100f8fa,
+ 0xf04160e7,
+ 0xf4bd40e3,
+ 0xf88d21f4,
+/* 0x0651: ctx_4170s */
+ 0x70e7f100,
+ 0x40e3f041,
+ 0xf410f5f0,
+ 0x00f88d21,
+/* 0x0660: ctx_4170w */
+ 0x4170e7f1,
+ 0xf440e3f0,
+ 0xf4f06821,
+ 0xf31bf410,
+/* 0x0672: ctx_redswitch */
+ 0xe7f100f8,
+ 0xe4b60614,
+ 0x70f7f106,
+ 0x00efd002,
+/* 0x0683: ctx_redswitch_delay */
+ 0xb608f7f0,
+ 0x1bf401f2,
+ 0x70f7f1fd,
+ 0x00efd007,
+/* 0x0692: ctx_86c */
+ 0xe7f100f8,
+ 0xe4b6086c,
+ 0x00efd006,
+ 0x8a14e7f1,
+ 0xf440e3f0,
+ 0xe7f18d21,
+ 0xe3f0a86c,
+ 0x8d21f441,
+/* 0x06b2: ctx_load */
+ 0x94bd00f8,
+ 0xf10599f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf004bd00,
+ 0x21f40ca7,
+ 0x2417f1c9,
+ 0x0614b60a,
+ 0xf10010d0,
+ 0xb60b0037,
+ 0x32d00634,
+ 0x0c17f140,
+ 0x0614b60a,
+ 0xd00747f0,
+ 0x14d00012,
+/* 0x06ed: ctx_chan_wait_0 */
+ 0x4014cf40,
+ 0xf41f44f0,
+ 0x32d0fa1b,
+ 0x000bfe00,
+ 0xb61f2af0,
+ 0x20b60424,
+ 0xf094bd02,
+ 0x07f10899,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x17f104bd,
+ 0x14b60a04,
+ 0x0012d006,
+ 0x0a2017f1,
+ 0xf00614b6,
+ 0x23f10227,
+ 0x12d08000,
+ 0x1017f000,
+ 0x020027f1,
+ 0xfa0223f0,
+ 0x03f80512,
+ 0x99f094bd,
+ 0x0007f108,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x81019804,
+ 0x981814b6,
+ 0x25b68002,
+ 0x0512fd08,
+ 0xbd160180,
+ 0x0999f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0a0427f1,
+ 0xd00624b6,
+ 0x27f00021,
+ 0x2017f101,
+ 0x0614b60a,
+ 0xf10012d0,
+ 0xf0010017,
+ 0x01fa0613,
+ 0xbd03f805,
+ 0x0999f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x99f094bd,
+ 0x0007f105,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x07bb: ctx_chan */
+ 0xf500f804,
+ 0xf5062b21,
+ 0xf006b221,
+ 0x21f40ca7,
+ 0x1017f1c9,
+ 0x0614b60a,
+ 0xd00527f0,
+/* 0x07d6: ctx_chan_wait */
+ 0x12cf0012,
+ 0x0522fd00,
+ 0xf5fa1bf4,
+ 0xf8064321,
+/* 0x07e5: ctx_mmio_exec */
+ 0x41039800,
+ 0x0a0427f1,
+ 0xd00624b6,
+ 0x34bd0023,
+/* 0x07f4: ctx_mmio_loop */
+ 0xf4ff34c4,
+ 0x57f10f1b,
+ 0x53f00200,
+ 0x0535fa06,
+/* 0x0806: ctx_mmio_pull */
+ 0x4e9803f8,
+ 0x814f9880,
+ 0xb68d21f4,
+ 0x12b60830,
+ 0xdf1bf401,
+/* 0x0818: ctx_mmio_done */
+ 0xd0160398,
+ 0x00800023,
+ 0x0017f140,
+ 0x0613f001,
+ 0xf80601fa,
+/* 0x082f: ctx_xfer */
+ 0xf100f803,
+ 0xb60c00f7,
+ 0xe7f006f4,
+ 0x80fed004,
+/* 0x083c: ctx_xfer_idle */
+ 0xf100fecf,
+ 0xf42000e4,
+ 0x11f4f91b,
+ 0x1102f406,
+/* 0x084c: ctx_xfer_pre */
+ 0xf510f7f0,
+ 0xf5069221,
+ 0xf4062b21,
+/* 0x085a: ctx_xfer_pre_load */
+ 0xf7f01c11,
+ 0x5121f502,
+ 0x6021f506,
+ 0x7221f506,
+ 0xf5f4bd06,
+ 0xf5065121,
+/* 0x0873: ctx_xfer_exec */
+ 0x9806b221,
+ 0x27f11601,
+ 0x24b60414,
+ 0x0020d006,
+ 0xa500e7f1,
+ 0xb941e3f0,
+ 0x21f4021f,
+ 0x04e0b68d,
+ 0xf001fcf0,
+ 0x24b6022c,
+ 0x05f2fd01,
+ 0xf18d21f4,
+ 0xf04afc17,
+ 0x27f00213,
+ 0x0012d00c,
+ 0x021521f5,
+ 0x47fc27f1,
+ 0xd00223f0,
+ 0x2cf00020,
+ 0x0320b601,
+ 0xf00012d0,
+ 0xa5f001ac,
+ 0x00b7f006,
+ 0x98000c98,
+ 0xe7f0010d,
+ 0x6621f500,
+ 0x08a7f001,
+ 0x010921f5,
+ 0x021521f5,
+ 0xf02201f4,
+ 0x21f40ca7,
+ 0x1017f1c9,
+ 0x0614b60a,
+ 0xd00527f0,
+/* 0x08fa: ctx_xfer_post_save_wait */
+ 0x12cf0012,
+ 0x0522fd00,
+ 0xf4fa1bf4,
+/* 0x0906: ctx_xfer_post */
+ 0xf7f03202,
+ 0x5121f502,
+ 0xf5f4bd06,
+ 0xf5069221,
+ 0xf5023421,
+ 0xbd066021,
+ 0x5121f5f4,
+ 0x1011f406,
+ 0xfd400198,
+ 0x0bf40511,
+ 0xe521f507,
+/* 0x0931: ctx_xfer_no_post_mmio */
+ 0x4321f507,
+/* 0x0935: ctx_xfer_done */
+ 0x0000f806,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
index 7fe9d7cf486b..d4840f1879fd 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
@@ -1,6 +1,5 @@
-/* fuc microcode for nve0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
+/*
+ * Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -20,774 +19,22 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-/* To build:
- * m4 nve0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nve0_grhub.fuc.h
- */
+#define CHIPSET GK100
+#include "macros.fuc"
.section #nve0_grhub_data
-include(`nve0.fuc')
-gpc_count: .b32 0
-rop_count: .b32 0
-cmd_queue: queue_init
-hub_mmio_list_head: .b32 0
-hub_mmio_list_tail: .b32 0
-
-ctx_current: .b32 0
-
-chipsets:
-.b8 0xe4 0 0 0
-.b16 #nve4_hub_mmio_head
-.b16 #nve4_hub_mmio_tail
-.b8 0xe7 0 0 0
-.b16 #nve4_hub_mmio_head
-.b16 #nve4_hub_mmio_tail
-.b8 0xe6 0 0 0
-.b16 #nve4_hub_mmio_head
-.b16 #nve4_hub_mmio_tail
-.b8 0 0 0 0
-
-nve4_hub_mmio_head:
-mmctx_data(0x17e91c, 2)
-mmctx_data(0x400204, 2)
-mmctx_data(0x404010, 7)
-mmctx_data(0x4040a8, 9)
-mmctx_data(0x4040d0, 7)
-mmctx_data(0x4040f8, 1)
-mmctx_data(0x404130, 3)
-mmctx_data(0x404150, 3)
-mmctx_data(0x404164, 1)
-mmctx_data(0x4041a0, 4)
-mmctx_data(0x404200, 4)
-mmctx_data(0x404404, 14)
-mmctx_data(0x404460, 4)
-mmctx_data(0x404480, 1)
-mmctx_data(0x404498, 1)
-mmctx_data(0x404604, 4)
-mmctx_data(0x404618, 4)
-mmctx_data(0x40462c, 2)
-mmctx_data(0x404640, 1)
-mmctx_data(0x404654, 1)
-mmctx_data(0x404660, 1)
-mmctx_data(0x404678, 19)
-mmctx_data(0x4046c8, 3)
-mmctx_data(0x404700, 3)
-mmctx_data(0x404718, 10)
-mmctx_data(0x404744, 2)
-mmctx_data(0x404754, 1)
-mmctx_data(0x405800, 1)
-mmctx_data(0x405830, 3)
-mmctx_data(0x405854, 1)
-mmctx_data(0x405870, 4)
-mmctx_data(0x405a00, 2)
-mmctx_data(0x405a18, 1)
-mmctx_data(0x405b00, 1)
-mmctx_data(0x405b10, 1)
-mmctx_data(0x406020, 1)
-mmctx_data(0x406028, 4)
-mmctx_data(0x4064a8, 2)
-mmctx_data(0x4064b4, 2)
-mmctx_data(0x4064c0, 12)
-mmctx_data(0x4064fc, 1)
-mmctx_data(0x407040, 1)
-mmctx_data(0x407804, 1)
-mmctx_data(0x40780c, 6)
-mmctx_data(0x4078bc, 1)
-mmctx_data(0x408000, 7)
-mmctx_data(0x408064, 1)
-mmctx_data(0x408800, 3)
-mmctx_data(0x408840, 1)
-mmctx_data(0x408900, 3)
-mmctx_data(0x408980, 1)
-nve4_hub_mmio_tail:
-
-.align 256
-chan_data:
-chan_mmio_count: .b32 0
-chan_mmio_address: .b32 0
-
-.align 256
-xfer_data: .b32 0
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
.section #nve0_grhub_code
+#define INCLUDE_CODE
bra #init
-define(`include_code')
-include(`nve0.fuc')
-
-// reports an exception to the host
-//
-// In: $r15 error code (see nve0.fuc)
-//
-error:
- push $r14
- mov $r14 0x814
- shl b32 $r14 6
- iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code
- mov $r14 0xc1c
- shl b32 $r14 6
- mov $r15 1
- iowr I[$r14 + 0x000] $r15 // INTR_UP_SET
- pop $r14
- ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
-//
-// Output:
-// CC_SCRATCH[0]:
-// 31:31: set to signal completion
-// CC_SCRATCH[1]:
-// 31:0: total PGRAPH context size
-//
-init:
- clear b32 $r0
- mov $sp $r0
- mov $xdbase $r0
-
- // enable fifo access
- mov $r1 0x1200
- mov $r2 2
- iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
-
- // setup i0 handler, and route all interrupts to it
- mov $r1 #ih
- mov $iv0 $r1
- mov $r1 0x400
- iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
-
- // route HUB_CHANNEL_SWITCH to fuc interrupt 8
- mov $r3 0x404
- shl b32 $r3 6
- mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
- iowr I[$r3 + 0x000] $r2
-
- // not sure what these are, route them because NVIDIA does, and
- // the IRQ handler will signal the host if we ever get one.. we
- // may find out if/why we need to handle these if so..
- //
- mov $r2 0x2004
- iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
- mov $r2 0x200b
- iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
- mov $r2 0x200c
- iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
-
- // enable all INTR_UP interrupts
- mov $r2 0xc24
- shl b32 $r2 6
- not b32 $r3 $r0
- iowr I[$r2] $r3
-
- // enable fifo, ctxsw, 9, 10, 15 interrupts
- mov $r2 -0x78fc // 0x8704
- sethi $r2 0
- iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
-
- // fifo level triggered, rest edge
- sub b32 $r1 0x100
- mov $r2 4
- iowr I[$r1] $r2
-
- // enable interrupts
- bset $flags ie0
-
- // fetch enabled GPC/ROP counts
- mov $r14 -0x69fc // 0x409604
- sethi $r14 0x400000
- call #nv_rd32
- extr $r1 $r15 16:20
- st b32 D[$r0 + #rop_count] $r1
- and $r15 0x1f
- st b32 D[$r0 + #gpc_count] $r15
-
- // set BAR_REQMASK to GPC mask
- mov $r1 1
- shl b32 $r1 $r15
- sub b32 $r1 1
- mov $r2 0x40c
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r1
- iowr I[$r2 + 0x100] $r1
-
- // find context data for this chipset
- mov $r2 0x800
- shl b32 $r2 6
- iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0]
- mov $r15 #chipsets - 8
- init_find_chipset:
- add b32 $r15 8
- ld b32 $r3 D[$r15 + 0x00]
- cmpu b32 $r3 $r2
- bra e #init_context
- cmpu b32 $r3 0
- bra ne #init_find_chipset
- // unknown chipset
- ret
-
- // context size calculation, reserve first 256 bytes for use by fuc
- init_context:
- mov $r1 256
-
- // calculate size of mmio context data
- ld b16 $r14 D[$r15 + 4]
- ld b16 $r15 D[$r15 + 6]
- sethi $r14 0
- st b32 D[$r0 + #hub_mmio_list_head] $r14
- st b32 D[$r0 + #hub_mmio_list_tail] $r15
- call #mmctx_size
-
- // set mmctx base addresses now so we don't have to do it later,
- // they don't (currently) ever change
- mov $r3 0x700
- shl b32 $r3 6
- shr b32 $r4 $r1 8
- iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE
- iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE
- add b32 $r3 0x1300
- add b32 $r1 $r15
- shr b32 $r15 2
- iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!?
-
- // strands, base offset needs to be aligned to 256 bytes
- shr b32 $r1 8
- add b32 $r1 1
- shl b32 $r1 8
- mov b32 $r15 $r1
- call #strand_ctx_init
- add b32 $r1 $r15
-
- // initialise each GPC in sequence by passing in the offset of its
- // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
- // has previously been uploaded by the host) running.
- //
- // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
- // when it has completed, and return the size of its context data
- // in GPCn_CC_SCRATCH[1]
- //
- ld b32 $r3 D[$r0 + #gpc_count]
- mov $r4 0x2000
- sethi $r4 0x500000
- init_gpc:
- // setup, and start GPC ucode running
- add b32 $r14 $r4 0x804
- mov b32 $r15 $r1
- call #nv_wr32 // CC_SCRATCH[1] = ctx offset
- add b32 $r14 $r4 0x800
- mov b32 $r15 $r2
- call #nv_wr32 // CC_SCRATCH[0] = chipset
- add b32 $r14 $r4 0x10c
- clear b32 $r15
- call #nv_wr32
- add b32 $r14 $r4 0x104
- call #nv_wr32 // ENTRY
- add b32 $r14 $r4 0x100
- mov $r15 2 // CTRL_START_TRIGGER
- call #nv_wr32 // CTRL
-
- // wait for it to complete, and adjust context size
- add b32 $r14 $r4 0x800
- init_gpc_wait:
- call #nv_rd32
- xbit $r15 $r15 31
- bra e #init_gpc_wait
- add b32 $r14 $r4 0x804
- call #nv_rd32
- add b32 $r1 $r15
-
- // next!
- add b32 $r4 0x8000
- sub b32 $r3 1
- bra ne #init_gpc
-
- // save context size, and tell host we're ready
- mov $r2 0x800
- shl b32 $r2 6
- iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size
- add b32 $r2 0x800
- clear b32 $r1
- bset $r1 31
- iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
- // sleep until we have something to do
- bset $flags $p0
- sleep $p0
- mov $r13 #cmd_queue
- call #queue_get
- bra $p1 #main
-
- // context switch, requested by GPU?
- cmpu b32 $r14 0x4001
- bra ne #main_not_ctx_switch
- trace_set(T_AUTO)
- mov $r1 0xb00
- shl b32 $r1 6
- iord $r2 I[$r1 + 0x100] // CHAN_NEXT
- iord $r1 I[$r1 + 0x000] // CHAN_CUR
-
- xbit $r3 $r1 31
- bra e #chsw_no_prev
- xbit $r3 $r2 31
- bra e #chsw_prev_no_next
- push $r2
- mov b32 $r2 $r1
- trace_set(T_SAVE)
- bclr $flags $p1
- bset $flags $p2
- call #ctx_xfer
- trace_clr(T_SAVE);
- pop $r2
- trace_set(T_LOAD);
- bset $flags $p1
- call #ctx_xfer
- trace_clr(T_LOAD);
- bra #chsw_done
- chsw_prev_no_next:
- push $r2
- mov b32 $r2 $r1
- bclr $flags $p1
- bclr $flags $p2
- call #ctx_xfer
- pop $r2
- mov $r1 0xb00
- shl b32 $r1 6
- iowr I[$r1] $r2
- bra #chsw_done
- chsw_no_prev:
- xbit $r3 $r2 31
- bra e #chsw_done
- bset $flags $p1
- bclr $flags $p2
- call #ctx_xfer
-
- // ack the context switch request
- chsw_done:
- mov $r1 0xb0c
- shl b32 $r1 6
- mov $r2 1
- iowr I[$r1 + 0x000] $r2 // 0x409b0c
- trace_clr(T_AUTO)
- bra #main
-
- // request to set current channel? (*not* a context switch)
- main_not_ctx_switch:
- cmpu b32 $r14 0x0001
- bra ne #main_not_ctx_chan
- mov b32 $r2 $r15
- call #ctx_chan
- bra #main_done
-
- // request to store current channel context?
- main_not_ctx_chan:
- cmpu b32 $r14 0x0002
- bra ne #main_not_ctx_save
- trace_set(T_SAVE)
- bclr $flags $p1
- bclr $flags $p2
- call #ctx_xfer
- trace_clr(T_SAVE)
- bra #main_done
-
- main_not_ctx_save:
- shl b32 $r15 $r14 16
- or $r15 E_BAD_COMMAND
- call #error
- bra #main
-
- main_done:
- mov $r1 0x820
- shl b32 $r1 6
- clear b32 $r2
- bset $r2 31
- iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000
- bra #main
-
-// interrupt handler
-ih:
- push $r8
- mov $r8 $flags
- push $r8
- push $r9
- push $r10
- push $r11
- push $r13
- push $r14
- push $r15
-
- // incoming fifo command?
- iord $r10 I[$r0 + 0x200] // INTR
- and $r11 $r10 0x00000004
- bra e #ih_no_fifo
- // queue incoming fifo command for later processing
- mov $r11 0x1900
- mov $r13 #cmd_queue
- iord $r14 I[$r11 + 0x100] // FIFO_CMD
- iord $r15 I[$r11 + 0x000] // FIFO_DATA
- call #queue_put
- add b32 $r11 0x400
- mov $r14 1
- iowr I[$r11 + 0x000] $r14 // FIFO_ACK
-
- // context switch request?
- ih_no_fifo:
- and $r11 $r10 0x00000100
- bra e #ih_no_ctxsw
- // enqueue a context switch for later processing
- mov $r13 #cmd_queue
- mov $r14 0x4001
- call #queue_put
-
- // anything we didn't handle, bring it to the host's attention
- ih_no_ctxsw:
- mov $r11 0x104
- not b32 $r11
- and $r11 $r10 $r11
- bra e #ih_no_other
- mov $r10 0xc1c
- shl b32 $r10 6
- iowr I[$r10] $r11 // INTR_UP_SET
-
- // ack, and wake up main()
- ih_no_other:
- iowr I[$r0 + 0x100] $r10 // INTR_ACK
-
- pop $r15
- pop $r14
- pop $r13
- pop $r11
- pop $r10
- pop $r9
- pop $r8
- mov $flags $r8
- pop $r8
- bclr $flags $p0
- iret
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
- mov $r14 0x4170
- sethi $r14 0x400000
- or $r15 0x10
- call #nv_wr32
- ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
- mov $r14 0x4170
- sethi $r14 0x400000
- call #nv_rd32
- and $r15 0x10
- bra ne #ctx_4170w
- ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off? Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
- mov $r14 0x614
- shl b32 $r14 6
- mov $r15 0x270
- iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
- mov $r15 8
- ctx_redswitch_delay:
- sub b32 $r15 1
- bra ne #ctx_redswitch_delay
- mov $r15 0x770
- iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
- ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
- mov $r14 0x86c
- shl b32 $r14 6
- iowr I[$r14] $r15 // HUB(0x86c) = val
- mov $r14 -0x75ec
- sethi $r14 0x400000
- call #nv_wr32 // ROP(0xa14) = val
- mov $r14 -0x5794
- sethi $r14 0x410000
- call #nv_wr32 // GPC(0x86c) = val
- ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
- trace_set(T_CHAN)
-
- // switch to channel, somewhat magic in parts..
- mov $r10 12 // DONE_UNK12
- call #wait_donez
- mov $r1 0xa24
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r0 // 0x409a24
- mov $r3 0xb00
- shl b32 $r3 6
- iowr I[$r3 + 0x100] $r2 // CHAN_NEXT
- mov $r1 0xa0c
- shl b32 $r1 6
- mov $r4 7
- iowr I[$r1 + 0x000] $r2 // MEM_CHAN
- iowr I[$r1 + 0x100] $r4 // MEM_CMD
- ctx_chan_wait_0:
- iord $r4 I[$r1 + 0x100]
- and $r4 0x1f
- bra ne #ctx_chan_wait_0
- iowr I[$r3 + 0x000] $r2 // CHAN_CUR
-
- // load channel header, fetch PGRAPH context pointer
- mov $xtargets $r0
- bclr $r2 31
- shl b32 $r2 4
- add b32 $r2 2
-
- trace_set(T_LCHAN)
- mov $r1 0xa04
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r2 // MEM_BASE
- mov $r1 0xa20
- shl b32 $r1 6
- mov $r2 0x0002
- sethi $r2 0x80000000
- iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram
- mov $r1 0x10 // chan + 0x0210
- mov $r2 #xfer_data
- sethi $r2 0x00020000 // 16 bytes
- xdld $r1 $r2
- xdwait
- trace_clr(T_LCHAN)
-
- // update current context
- ld b32 $r1 D[$r0 + #xfer_data + 4]
- shl b32 $r1 24
- ld b32 $r2 D[$r0 + #xfer_data + 0]
- shr b32 $r2 8
- or $r1 $r2
- st b32 D[$r0 + #ctx_current] $r1
-
- // set transfer base to start of context, and fetch context header
- trace_set(T_LCTXH)
- mov $r2 0xa04
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r1 // MEM_BASE
- mov $r2 1
- mov $r1 0xa20
- shl b32 $r1 6
- iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm
- mov $r1 #chan_data
- sethi $r1 0x00060000 // 256 bytes
- xdld $r0 $r1
- xdwait
- trace_clr(T_LCTXH)
-
- trace_clr(T_CHAN)
- ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-// the active channel for ctxctl, but not actually transfer
-// any context data. intended for use only during initial
-// context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
- call #ctx_load
- mov $r10 12 // DONE_UNK12
- call #wait_donez
- mov $r1 0xa10
- shl b32 $r1 6
- mov $r2 5
- iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???)
- ctx_chan_wait:
- iord $r2 I[$r1 + 0x000]
- or $r2 $r2
- bra ne #ctx_chan_wait
- ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel. Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state... The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
- // set transfer base to be the mmio list
- ld b32 $r3 D[$r0 + #chan_mmio_address]
- mov $r2 0xa04
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r3 // MEM_BASE
-
- clear b32 $r3
- ctx_mmio_loop:
- // fetch next 256 bytes of mmio list if necessary
- and $r4 $r3 0xff
- bra ne #ctx_mmio_pull
- mov $r5 #xfer_data
- sethi $r5 0x00060000 // 256 bytes
- xdld $r3 $r5
- xdwait
-
- // execute a single list entry
- ctx_mmio_pull:
- ld b32 $r14 D[$r4 + #xfer_data + 0x00]
- ld b32 $r15 D[$r4 + #xfer_data + 0x04]
- call #nv_wr32
-
- // next!
- add b32 $r3 8
- sub b32 $r1 1
- bra ne #ctx_mmio_loop
-
- // set transfer base back to the current context
- ctx_mmio_done:
- ld b32 $r3 D[$r0 + #ctx_current]
- iowr I[$r2 + 0x000] $r3 // MEM_BASE
-
- // disable the mmio list now, we don't need/want to execute it again
- st b32 D[$r0 + #chan_mmio_count] $r0
- mov $r1 #chan_data
- sethi $r1 0x00060000 // 256 bytes
- xdst $r0 $r1
- xdwait
- ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-// $p1 clear on save, set on load
-// $p2 set if opposite direction done/will be done, so:
-// on save it means: "a load will follow this save"
-// on load it means: "a save preceeded this load"
-//
-ctx_xfer:
- // according to mwk, some kind of wait for idle
- mov $r15 0xc00
- shl b32 $r15 6
- mov $r14 4
- iowr I[$r15 + 0x200] $r14
- ctx_xfer_idle:
- iord $r14 I[$r15 + 0x000]
- and $r14 0x2000
- bra ne #ctx_xfer_idle
-
- bra not $p1 #ctx_xfer_pre
- bra $p2 #ctx_xfer_pre_load
- ctx_xfer_pre:
- mov $r15 0x10
- call #ctx_86c
- bra not $p1 #ctx_xfer_exec
-
- ctx_xfer_pre_load:
- mov $r15 2
- call #ctx_4170s
- call #ctx_4170w
- call #ctx_redswitch
- clear b32 $r15
- call #ctx_4170s
- call #ctx_load
-
- // fetch context pointer, and initiate xfer on all GPCs
- ctx_xfer_exec:
- ld b32 $r1 D[$r0 + #ctx_current]
- mov $r2 0x414
- shl b32 $r2 6
- iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset
- mov $r14 -0x5b00
- sethi $r14 0x410000
- mov b32 $r15 $r1
- call #nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer
- add b32 $r14 4
- xbit $r15 $flags $p1
- xbit $r2 $flags $p2
- shl b32 $r2 1
- or $r15 $r2
- call #nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
- // strands
- mov $r1 0x4afc
- sethi $r1 0x20000
- mov $r2 0xc
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c
- call #strand_wait
- mov $r2 0x47fc
- sethi $r2 0x20000
- iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00
- xbit $r2 $flags $p1
- add b32 $r2 3
- iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
-
- // mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 6 // first, last
- mov $r11 0 // base = 0
- ld b32 $r12 D[$r0 + #hub_mmio_list_head]
- ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
- mov $r14 0 // not multi
- call #mmctx_xfer
-
- // wait for GPCs to all complete
- mov $r10 8 // DONE_BAR
- call #wait_doneo
-
- // wait for strand xfer to complete
- call #strand_wait
-
- // post-op
- bra $p1 #ctx_xfer_post
- mov $r10 12 // DONE_UNK12
- call #wait_donez
- mov $r1 0xa10
- shl b32 $r1 6
- mov $r2 5
- iowr I[$r1] $r2 // MEM_CMD
- ctx_xfer_post_save_wait:
- iord $r2 I[$r1]
- or $r2 $r2
- bra ne #ctx_xfer_post_save_wait
-
- bra $p2 #ctx_xfer_done
- ctx_xfer_post:
- mov $r15 2
- call #ctx_4170s
- clear b32 $r15
- call #ctx_86c
- call #strand_post
- call #ctx_4170w
- clear b32 $r15
- call #ctx_4170s
-
- bra not $p1 #ctx_xfer_no_post_mmio
- ld b32 $r1 D[$r0 + #chan_mmio_count]
- or $r1 $r1
- bra e #ctx_xfer_no_post_mmio
- call #ctx_mmio_exec
-
- ctx_xfer_no_post_mmio:
-
- ctx_xfer_done:
- ret
-
+#include "com.fuc"
+#include "hub.fuc"
.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
index e3421af68ab9..eb7bc0e9576e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
@@ -1,9 +1,13 @@
uint32_t nve0_grhub_data[] = {
-/* 0x0000: gpc_count */
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
0x00000000,
-/* 0x0004: rop_count */
+/* 0x000c: rop_count */
0x00000000,
-/* 0x0008: cmd_queue */
+/* 0x0010: cmd_queue */
0x00000000,
0x00000000,
0x00000000,
@@ -22,73 +26,11 @@ uint32_t nve0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0050: hub_mmio_list_head */
+/* 0x0058: ctx_current */
0x00000000,
-/* 0x0054: hub_mmio_list_tail */
0x00000000,
-/* 0x0058: ctx_current */
0x00000000,
-/* 0x005c: chipsets */
- 0x000000e4,
- 0x01440078,
- 0x000000e7,
- 0x01440078,
- 0x000000e6,
- 0x01440078,
0x00000000,
-/* 0x0078: nve4_hub_mmio_head */
- 0x0417e91c,
- 0x04400204,
- 0x18404010,
- 0x204040a8,
- 0x184040d0,
- 0x004040f8,
- 0x08404130,
- 0x08404150,
- 0x00404164,
- 0x0c4041a0,
- 0x0c404200,
- 0x34404404,
- 0x0c404460,
- 0x00404480,
- 0x00404498,
- 0x0c404604,
- 0x0c404618,
- 0x0440462c,
- 0x00404640,
- 0x00404654,
- 0x00404660,
- 0x48404678,
- 0x084046c8,
- 0x08404700,
- 0x24404718,
- 0x04404744,
- 0x00404754,
- 0x00405800,
- 0x08405830,
- 0x00405854,
- 0x0c405870,
- 0x04405a00,
- 0x00405a18,
- 0x00405b00,
- 0x00405b10,
- 0x00406020,
- 0x0c406028,
- 0x044064a8,
- 0x044064b4,
- 0x2c4064c0,
- 0x004064fc,
- 0x00407040,
- 0x00407804,
- 0x1440780c,
- 0x004078bc,
- 0x18408000,
- 0x00408064,
- 0x08408800,
- 0x00408840,
- 0x08408900,
- 0x00408980,
-/* 0x0144: nve4_hub_mmio_tail */
0x00000000,
0x00000000,
0x00000000,
@@ -127,6 +69,47 @@ uint32_t nve0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
0x00000000,
0x00000000,
@@ -136,10 +119,7 @@ uint32_t nve0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0200: chan_data */
-/* 0x0200: chan_mmio_count */
0x00000000,
-/* 0x0204: chan_mmio_address */
0x00000000,
0x00000000,
0x00000000,
@@ -156,6 +136,7 @@ uint32_t nve0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
+/* 0x0200: xfer_data */
0x00000000,
0x00000000,
0x00000000,
@@ -203,19 +184,36 @@ uint32_t nve0_grhub_data[] = {
0x00000000,
0x00000000,
0x00000000,
-/* 0x0300: xfer_data */
0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
};
uint32_t nve0_grhub_code[] = {
- 0x03090ef5,
+ 0x031b0ef5,
/* 0x0004: queue_put */
0x9800d898,
0x86f001d9,
0x0489b808,
0xf00c1bf4,
0x21f502f7,
- 0x00f802ec,
+ 0x00f802fe,
/* 0x001c: queue_put_next */
0xb60798c4,
0x8dbb0384,
@@ -247,7 +245,7 @@ uint32_t nve0_grhub_code[] = {
0xc800bccf,
0x1bf41fcc,
0x06a7f0fa,
- 0x010321f5,
+ 0x010921f5,
0xf840bfcf,
/* 0x008d: nv_wr32 */
0x28b7f100,
@@ -269,63 +267,66 @@ uint32_t nve0_grhub_code[] = {
0x0684b604,
0xf80080d0,
/* 0x00c9: wait_donez */
- 0x3c87f100,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d000,
- 0x081887f1,
- 0xd00684b6,
-/* 0x00e2: wait_done_wait_donez */
- 0x87f1008a,
- 0x84b60400,
- 0x0088cf06,
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
0xf4888aff,
- 0x87f1f31b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00099,
-/* 0x0103: wait_doneo */
- 0xf100f800,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00099f0,
- 0x87f10089,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x87f104bd,
0x84b60818,
0x008ad006,
-/* 0x011c: wait_done_wait_doneo */
+/* 0x0124: wait_doneo_e */
0x040087f1,
0xcf0684b6,
0x8aff0088,
0xf30bf488,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0099f094,
- 0xf80089d0,
-/* 0x013d: mmctx_size */
-/* 0x013f: nv_mmctx_size_loop */
- 0x9894bd00,
- 0x85b600e8,
- 0x0180b61a,
- 0xbb0284b6,
- 0xe0b60098,
- 0x04efb804,
- 0xb9eb1bf4,
- 0x00f8029f,
-/* 0x015c: mmctx_xfer */
- 0x083c87f1,
- 0xbd0684b6,
- 0x0199f094,
- 0xf10089d0,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
0xb6071087,
0x94bd0684,
0xf405bbfd,
0x8bd0090b,
0x0099f000,
-/* 0x0180: mmctx_base_disabled */
+/* 0x018c: mmctx_base_disabled */
0xf405eefd,
0x8ed00c0b,
0xc08fd080,
-/* 0x018f: mmctx_multi_disabled */
+/* 0x019b: mmctx_multi_disabled */
0xb70199f0,
0xc8010080,
0xb4b600ab,
@@ -333,8 +334,8 @@ uint32_t nve0_grhub_code[] = {
0xb601aec8,
0xbefd11e4,
0x008bd005,
-/* 0x01a8: mmctx_exec_loop */
-/* 0x01a8: mmctx_wait_free */
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
0xf0008ecf,
0x0bf41fe4,
0x00ce98fa,
@@ -343,76 +344,77 @@ uint32_t nve0_grhub_code[] = {
0x04cdb804,
0xc8e81bf4,
0x1bf402ab,
-/* 0x01c9: mmctx_fini_wait */
+/* 0x01d5: mmctx_fini_wait */
0x008bcf18,
0xb01fb4f0,
0x1bf410b4,
0x02a7f0f7,
0xf4c921f4,
-/* 0x01de: mmctx_stop */
+/* 0x01ea: mmctx_stop */
0xabc81b0e,
0x10b4b600,
0xf00cb9f0,
0x8bd012b9,
-/* 0x01ed: mmctx_stop_wait */
+/* 0x01f9: mmctx_stop_wait */
0x008bcf00,
0xf412bbc8,
-/* 0x01f6: mmctx_done */
- 0x87f1fa1b,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00199,
-/* 0x0207: strand_wait */
- 0xf900f800,
- 0x02a7f0a0,
- 0xfcc921f4,
-/* 0x0213: strand_pre */
- 0xf100f8a0,
- 0xf04afc87,
- 0x97f00283,
- 0x0089d00c,
- 0x020721f5,
-/* 0x0226: strand_post */
- 0x87f100f8,
- 0x83f04afc,
- 0x0d97f002,
- 0xf50089d0,
- 0xf8020721,
-/* 0x0239: strand_set */
- 0xfca7f100,
- 0x02a3f04f,
- 0x0500aba2,
- 0xd00fc7f0,
- 0xc7f000ac,
- 0x00bcd00b,
- 0x020721f5,
- 0xf000aed0,
- 0xbcd00ac7,
- 0x0721f500,
-/* 0x0263: strand_ctx_init */
- 0xf100f802,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00399f0,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
0x21f50089,
- 0xe7f00213,
- 0x3921f503,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
0xfca7f102,
0x02a3f046,
0x0400aba0,
0xf040a0d0,
0xbcd001c7,
- 0x0721f500,
+ 0x1521f500,
0x010c9202,
0xf000acd0,
0xbcd002c7,
- 0x0721f500,
- 0x2621f502,
+ 0x1521f500,
+ 0x3421f502,
0x8087f102,
0x0684b608,
0xb70089cf,
0x95220080,
-/* 0x02ba: ctx_init_strand_loop */
+/* 0x02ca: ctx_init_strand_loop */
0x8ed008fe,
0x408ed000,
0xb6808acf,
@@ -421,73 +423,61 @@ uint32_t nve0_grhub_code[] = {
0xb60480b6,
0x1bf40192,
0x08e4b6e8,
- 0xf1f2efbc,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00399f0,
- 0x00f80089,
-/* 0x02ec: error */
- 0xe7f1e0f9,
- 0xe4b60814,
- 0x00efd006,
- 0x0c1ce7f1,
- 0xf006e4b6,
- 0xefd001f7,
- 0xf8e0fc00,
-/* 0x0309: init */
- 0xfe04bd00,
- 0x07fe0004,
- 0x0017f100,
- 0x0227f012,
- 0xf10012d0,
- 0xfe05b917,
- 0x17f10010,
- 0x10d00400,
- 0x0437f1c0,
- 0x0634b604,
- 0x200327f1,
- 0xf10032d0,
- 0xd0200427,
- 0x27f10132,
- 0x32d0200b,
- 0x0c27f102,
- 0x0732d020,
- 0x0c2427f1,
- 0xb90624b6,
- 0x23d00003,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x031b: init */
+ 0xbd00f804,
+ 0x0004fe04,
+ 0xf10007fe,
+ 0xf0120017,
+ 0x12d00227,
+ 0xb117f100,
+ 0x0010fe05,
+ 0x040017f1,
+ 0xf1c010d0,
+ 0xb6040437,
+ 0x27f10634,
+ 0x32d02003,
0x0427f100,
- 0x0023f087,
- 0xb70012d0,
- 0xf0010012,
- 0x12d00427,
- 0x1031f400,
- 0x9604e7f1,
- 0xf440e3f0,
- 0xf1c76821,
- 0x01018090,
- 0x801ff4f0,
- 0x17f0000f,
- 0x041fbb01,
- 0xf10112b6,
- 0xb6040c27,
- 0x21d00624,
- 0x4021d000,
- 0x080027f1,
- 0xcf0624b6,
- 0xf7f00022,
-/* 0x03a9: init_find_chipset */
- 0x08f0b654,
- 0xb800f398,
- 0x0bf40432,
- 0x0034b00b,
- 0xf8f11bf4,
-/* 0x03bd: init_context */
- 0x0017f100,
- 0x02fe5801,
- 0xf003ff58,
- 0x0e8000e3,
- 0x150f8014,
- 0x013d21f5,
+ 0x0132d020,
+ 0x200b27f1,
+ 0xf10232d0,
+ 0xd0200c27,
+ 0x27f10732,
+ 0x24b60c24,
+ 0x0003b906,
+ 0xf10023d0,
+ 0xf0870427,
+ 0x12d00023,
+ 0x0012b700,
+ 0x0427f001,
+ 0xf40012d0,
+ 0xe7f11031,
+ 0xe3f09604,
+ 0x6821f440,
+ 0x8090f1c7,
+ 0xf4f00301,
+ 0x020f801f,
+ 0xbb0117f0,
+ 0x12b6041f,
+ 0x0c27f101,
+ 0x0624b604,
+ 0xd00021d0,
+ 0x17f14021,
+ 0x0e980100,
+ 0x010f9800,
+ 0x014721f5,
0x070037f1,
0x950634b6,
0x34d00814,
@@ -498,196 +488,201 @@ uint32_t nve0_grhub_code[] = {
0x0815b600,
0xb60110b6,
0x1fb90814,
- 0x6321f502,
+ 0x7121f502,
0x001fbb02,
- 0xf1000398,
+ 0xf1020398,
0xf0200047,
-/* 0x040e: init_gpc */
+/* 0x03f6: init_gpc */
0x4ea05043,
0x1fb90804,
0x8d21f402,
- 0x08004ea0,
- 0xf4022fb9,
- 0x4ea08d21,
- 0xf4bd010c,
- 0xa08d21f4,
- 0xf401044e,
+ 0x010c4ea0,
+ 0x21f4f4bd,
+ 0x044ea08d,
+ 0x8d21f401,
+ 0x01004ea0,
+ 0xf402f7f0,
0x4ea08d21,
- 0xf7f00100,
- 0x8d21f402,
- 0x08004ea0,
-/* 0x0440: init_gpc_wait */
- 0xc86821f4,
- 0x0bf41fff,
- 0x044ea0fa,
- 0x6821f408,
- 0xb7001fbb,
- 0xb6800040,
- 0x1bf40132,
- 0x0027f1b4,
- 0x0624b608,
- 0xb74021d0,
- 0xbd080020,
+/* 0x041e: init_gpc_wait */
+ 0x21f40800,
+ 0x1fffc868,
+ 0xa0fa0bf4,
+ 0xf408044e,
+ 0x1fbb6821,
+ 0x0040b700,
+ 0x0132b680,
+ 0xf1be1bf4,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
0x1f19f014,
-/* 0x0473: main */
- 0xf40021d0,
- 0x28f40031,
- 0x08d7f000,
- 0xf43921f4,
- 0xe4b1f401,
- 0x1bf54001,
- 0x87f100d1,
- 0x84b6083c,
- 0xf094bd06,
- 0x89d00499,
- 0x0017f100,
- 0x0614b60b,
- 0xcf4012cf,
- 0x13c80011,
- 0x7e0bf41f,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0458: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00de1b,
+ 0x0499f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0b0017f1,
+ 0xcf0614b6,
+ 0x11cf4012,
+ 0x1f13c800,
+ 0x00870bf5,
0xf41f23c8,
- 0x20f95a0b,
- 0xf10212b9,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00799f0,
- 0x32f40089,
- 0x0231f401,
- 0x07fb21f5,
- 0x085c87f1,
- 0xbd0684b6,
+ 0x20f9620b,
+ 0xbd0212b9,
0x0799f094,
- 0xfc0089d0,
- 0x3c87f120,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d006,
- 0xf50131f4,
- 0xf107fb21,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00699f0,
- 0x0ef40089,
-/* 0x0509: chsw_prev_no_next */
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xf40132f4,
+ 0x21f50231,
+ 0x94bd0801,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xfc04bd00,
+ 0xf094bd20,
+ 0x07f10699,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x31f404bd,
+ 0x0121f501,
+ 0xf094bd08,
+ 0x07f10699,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
0xb920f931,
0x32f40212,
0x0232f401,
- 0x07fb21f5,
+ 0x080121f5,
0x17f120fc,
0x14b60b00,
0x0012d006,
-/* 0x0527: chsw_no_prev */
+/* 0x0517: chsw_no_prev */
0xc8130ef4,
0x0bf41f23,
0x0131f40d,
0xf50232f4,
-/* 0x0537: chsw_done */
- 0xf107fb21,
+/* 0x0527: chsw_done */
+ 0xf1080121,
0xb60b0c17,
0x27f00614,
0x0012d001,
- 0x085c87f1,
- 0xbd0684b6,
- 0x0499f094,
- 0xf50089d0,
-/* 0x0557: main_not_ctx_switch */
- 0xb0ff200e,
- 0x1bf401e4,
- 0x02f2b90d,
- 0x078f21f5,
-/* 0x0567: main_not_ctx_chan */
- 0xb0420ef4,
- 0x1bf402e4,
- 0x3c87f12e,
- 0x0684b608,
0x99f094bd,
- 0x0089d007,
+ 0x0007f104,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+ 0x01e4b0ff,
+ 0xb90d1bf4,
+ 0x21f502f2,
+ 0x0ef40795,
+/* 0x0559: main_not_ctx_chan */
+ 0x02e4b046,
+ 0xbd321bf4,
+ 0x0799f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
0xf40132f4,
0x21f50232,
- 0x87f107fb,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00799,
- 0x110ef400,
-/* 0x0598: main_not_ctx_save */
- 0xf010ef94,
- 0x21f501f5,
- 0x0ef502ec,
-/* 0x05a6: main_done */
- 0x17f1fed1,
- 0x14b60820,
- 0xf024bd06,
- 0x12d01f29,
- 0xbe0ef500,
-/* 0x05b9: ih */
+ 0x94bd0801,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+ 0xef94110e,
+ 0x01f5f010,
+ 0x02fe21f5,
+ 0xfec00ef5,
+/* 0x059c: main_done */
+ 0x29f024bd,
+ 0x0007f11f,
+ 0x0203f008,
+ 0xbd0002d0,
+ 0xab0ef504,
+/* 0x05b1: ih */
0xfe80f9fe,
0x80f90188,
0xa0f990f9,
0xd0f9b0f9,
0xf0f9e0f9,
- 0xc4800acf,
- 0x0bf404ab,
- 0x00b7f11d,
- 0x08d7f019,
- 0xcf40becf,
- 0x21f400bf,
- 0x00b0b704,
- 0x01e7f004,
-/* 0x05ef: ih_no_fifo */
- 0xe400bed0,
- 0xf40100ab,
- 0xd7f00d0b,
- 0x01e7f108,
- 0x0421f440,
-/* 0x0600: ih_no_ctxsw */
- 0x0104b7f1,
- 0xabffb0bd,
- 0x0d0bf4b4,
- 0x0c1ca7f1,
- 0xd006a4b6,
-/* 0x0616: ih_no_other */
- 0x0ad000ab,
- 0xfcf0fc40,
- 0xfcd0fce0,
- 0xfca0fcb0,
- 0xfe80fc90,
- 0x80fc0088,
- 0xf80032f4,
-/* 0x0631: ctx_4170s */
- 0x70e7f101,
- 0x40e3f041,
- 0xf410f5f0,
- 0x00f88d21,
-/* 0x0640: ctx_4170w */
- 0x4170e7f1,
- 0xf440e3f0,
- 0xf4f06821,
- 0xf31bf410,
-/* 0x0652: ctx_redswitch */
+ 0x0acf04bd,
+ 0x04abc480,
+ 0xf11d0bf4,
+ 0xf01900b7,
+ 0xbecf10d7,
+ 0x00bfcf40,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+ 0x00abe400,
+ 0x0d0bf401,
+ 0xf110d7f0,
+ 0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+ 0xb7f10421,
+ 0xb0bd0104,
+ 0xf4b4abff,
+ 0xa7f10d0b,
+ 0xa4b60c1c,
+ 0x00abd006,
+/* 0x0610: ih_no_other */
+ 0xfc400ad0,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x062b: ctx_4170s */
+ 0xf101f800,
+ 0xf04170e7,
+ 0xf5f040e3,
+ 0x8d21f410,
+/* 0x063a: ctx_4170w */
0xe7f100f8,
- 0xe4b60614,
- 0x70f7f106,
- 0x00efd002,
-/* 0x0663: ctx_redswitch_delay */
- 0xb608f7f0,
- 0x1bf401f2,
- 0x70f7f1fd,
- 0x00efd007,
-/* 0x0672: ctx_86c */
- 0xe7f100f8,
- 0xe4b6086c,
- 0x00efd006,
- 0x8a14e7f1,
- 0xf440e3f0,
- 0xe7f18d21,
- 0xe3f0a86c,
- 0x8d21f441,
-/* 0x0692: ctx_load */
- 0x87f100f8,
- 0x84b6083c,
- 0xf094bd06,
- 0x89d00599,
- 0x0ca7f000,
+ 0xe3f04170,
+ 0x6821f440,
+ 0xf410f4f0,
+ 0x00f8f31b,
+/* 0x064c: ctx_redswitch */
+ 0x0614e7f1,
+ 0xf106e4b6,
+ 0xd00270f7,
+ 0xf7f000ef,
+/* 0x065d: ctx_redswitch_delay */
+ 0x01f2b608,
+ 0xf1fd1bf4,
+ 0xd00770f7,
+ 0x00f800ef,
+/* 0x066c: ctx_86c */
+ 0x086ce7f1,
+ 0xd006e4b6,
+ 0xe7f100ef,
+ 0xe3f08a14,
+ 0x8d21f440,
+ 0xa86ce7f1,
+ 0xf441e3f0,
+ 0x00f88d21,
+/* 0x068c: ctx_load */
+ 0x99f094bd,
+ 0x0007f105,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0ca7f004,
0xf1c921f4,
0xb60a2417,
0x10d00614,
@@ -697,162 +692,227 @@ uint32_t nve0_grhub_code[] = {
0xb60a0c17,
0x47f00614,
0x0012d007,
-/* 0x06cb: ctx_chan_wait_0 */
+/* 0x06c7: ctx_chan_wait_0 */
0xcf4014d0,
0x44f04014,
0xfa1bf41f,
0xfe0032d0,
0x2af0000b,
0x0424b61f,
- 0xf10220b6,
- 0xb6083c87,
- 0x94bd0684,
- 0xd00899f0,
- 0x17f10089,
- 0x14b60a04,
- 0x0012d006,
- 0x0a2017f1,
- 0xf00614b6,
- 0x23f10227,
- 0x12d08000,
- 0x1017f000,
- 0x030027f1,
- 0xfa0223f0,
- 0x03f80512,
- 0x085c87f1,
- 0xbd0684b6,
+ 0xbd0220b6,
0x0899f094,
- 0x980089d0,
- 0x14b6c101,
- 0xc0029818,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0a0417f1,
+ 0xd00614b6,
+ 0x17f10012,
+ 0x14b60a20,
+ 0x0227f006,
+ 0x800023f1,
+ 0xf00012d0,
+ 0x27f11017,
+ 0x23f00200,
+ 0x0512fa02,
+ 0x94bd03f8,
+ 0xf10899f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0x9804bd00,
+ 0x14b68101,
+ 0x80029818,
0xfd0825b6,
0x01800512,
- 0x3c87f116,
- 0x0684b608,
- 0x99f094bd,
- 0x0089d009,
- 0x0a0427f1,
- 0xd00624b6,
- 0x27f00021,
- 0x2017f101,
- 0x0614b60a,
- 0xf10012d0,
- 0xf0020017,
+ 0xf094bd16,
+ 0x07f10999,
+ 0x03f00f00,
+ 0x0009d002,
+ 0x27f104bd,
+ 0x24b60a04,
+ 0x0021d006,
+ 0xf10127f0,
+ 0xb60a2017,
+ 0x12d00614,
+ 0x0017f100,
+ 0x0613f001,
+ 0xf80501fa,
+ 0xf094bd03,
+ 0x07f10999,
+ 0x03f01700,
+ 0x0009d002,
+ 0x94bd04bd,
+ 0xf10599f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0795: ctx_chan */
+ 0x8c21f500,
+ 0x0ca7f006,
+ 0xf1c921f4,
+ 0xb60a1017,
+ 0x27f00614,
+ 0x0012d005,
+/* 0x07ac: ctx_chan_wait */
+ 0xfd0012cf,
+ 0x1bf40522,
+/* 0x07b7: ctx_mmio_exec */
+ 0x9800f8fa,
+ 0x27f14103,
+ 0x24b60a04,
+ 0x0023d006,
+/* 0x07c6: ctx_mmio_loop */
+ 0x34c434bd,
+ 0x0f1bf4ff,
+ 0x020057f1,
+ 0xfa0653f0,
+ 0x03f80535,
+/* 0x07d8: ctx_mmio_pull */
+ 0x98804e98,
+ 0x21f4814f,
+ 0x0830b68d,
+ 0xf40112b6,
+/* 0x07ea: ctx_mmio_done */
+ 0x0398df1b,
+ 0x0023d016,
+ 0xf1400080,
+ 0xf0010017,
0x01fa0613,
- 0xf103f805,
- 0xb6085c87,
- 0x94bd0684,
- 0xd00999f0,
- 0x87f10089,
- 0x84b6085c,
- 0xf094bd06,
- 0x89d00599,
-/* 0x078f: ctx_chan */
- 0xf500f800,
- 0xf0069221,
- 0x21f40ca7,
- 0x1017f1c9,
- 0x0614b60a,
- 0xd00527f0,
-/* 0x07a6: ctx_chan_wait */
- 0x12cf0012,
- 0x0522fd00,
- 0xf8fa1bf4,
-/* 0x07b1: ctx_mmio_exec */
- 0x81039800,
- 0x0a0427f1,
+ 0xf803f806,
+/* 0x0801: ctx_xfer */
+ 0x00f7f100,
+ 0x06f4b60c,
+ 0xd004e7f0,
+/* 0x080e: ctx_xfer_idle */
+ 0xfecf80fe,
+ 0x00e4f100,
+ 0xf91bf420,
+ 0xf40611f4,
+/* 0x081e: ctx_xfer_pre */
+ 0xf7f00d02,
+ 0x6c21f510,
+ 0x1c11f406,
+/* 0x0828: ctx_xfer_pre_load */
+ 0xf502f7f0,
+ 0xf5062b21,
+ 0xf5063a21,
+ 0xbd064c21,
+ 0x2b21f5f4,
+ 0x8c21f506,
+/* 0x0841: ctx_xfer_exec */
+ 0x16019806,
+ 0x041427f1,
0xd00624b6,
- 0x34bd0023,
-/* 0x07c0: ctx_mmio_loop */
- 0xf4ff34c4,
- 0x57f10f1b,
- 0x53f00300,
- 0x0535fa06,
-/* 0x07d2: ctx_mmio_pull */
- 0x4e9803f8,
- 0xc14f98c0,
+ 0xe7f10020,
+ 0xe3f0a500,
+ 0x021fb941,
0xb68d21f4,
- 0x12b60830,
- 0xdf1bf401,
-/* 0x07e4: ctx_mmio_done */
- 0xd0160398,
- 0x00800023,
- 0x0017f180,
- 0x0613f002,
- 0xf80601fa,
-/* 0x07fb: ctx_xfer */
- 0xf100f803,
- 0xb60c00f7,
- 0xe7f006f4,
- 0x80fed004,
-/* 0x0808: ctx_xfer_idle */
- 0xf100fecf,
- 0xf42000e4,
- 0x11f4f91b,
- 0x0d02f406,
-/* 0x0818: ctx_xfer_pre */
- 0xf510f7f0,
- 0xf4067221,
-/* 0x0822: ctx_xfer_pre_load */
- 0xf7f01c11,
- 0x3121f502,
- 0x4021f506,
- 0x5221f506,
- 0xf5f4bd06,
- 0xf5063121,
-/* 0x083b: ctx_xfer_exec */
- 0x98069221,
- 0x27f11601,
- 0x24b60414,
- 0x0020d006,
- 0xa500e7f1,
- 0xb941e3f0,
- 0x21f4021f,
- 0x04e0b68d,
- 0xf001fcf0,
- 0x24b6022c,
- 0x05f2fd01,
- 0xf18d21f4,
- 0xf04afc17,
- 0x27f00213,
- 0x0012d00c,
- 0x020721f5,
- 0x47fc27f1,
- 0xd00223f0,
- 0x2cf00020,
- 0x0320b601,
- 0xf00012d0,
- 0xa5f001ac,
- 0x00b7f006,
- 0x98140c98,
- 0xe7f0150d,
- 0x5c21f500,
- 0x08a7f001,
- 0x010321f5,
- 0x020721f5,
- 0xf02201f4,
- 0x21f40ca7,
- 0x1017f1c9,
- 0x0614b60a,
- 0xd00527f0,
-/* 0x08c2: ctx_xfer_post_save_wait */
- 0x12cf0012,
- 0x0522fd00,
- 0xf4fa1bf4,
-/* 0x08ce: ctx_xfer_post */
- 0xf7f02e02,
- 0x3121f502,
+ 0xfcf004e0,
+ 0x022cf001,
+ 0xfd0124b6,
+ 0x21f405f2,
+ 0xfc17f18d,
+ 0x0213f04a,
+ 0xd00c27f0,
+ 0x21f50012,
+ 0x27f10215,
+ 0x23f047fc,
+ 0x0020d002,
+ 0xb6012cf0,
+ 0x12d00320,
+ 0x01acf000,
+ 0xf006a5f0,
+ 0x0c9800b7,
+ 0x010d9800,
+ 0xf500e7f0,
+ 0xf0016621,
+ 0x21f508a7,
+ 0x21f50109,
+ 0x01f40215,
+ 0x0ca7f022,
+ 0xf1c921f4,
+ 0xb60a1017,
+ 0x27f00614,
+ 0x0012d005,
+/* 0x08c8: ctx_xfer_post_save_wait */
+ 0xfd0012cf,
+ 0x1bf40522,
+ 0x2e02f4fa,
+/* 0x08d4: ctx_xfer_post */
+ 0xf502f7f0,
+ 0xbd062b21,
+ 0x6c21f5f4,
+ 0x3421f506,
+ 0x3a21f502,
0xf5f4bd06,
- 0xf5067221,
- 0xf5022621,
- 0xbd064021,
- 0x3121f5f4,
- 0x1011f406,
- 0xfd800198,
- 0x0bf40511,
- 0xb121f507,
-/* 0x08f9: ctx_xfer_no_post_mmio */
-/* 0x08f9: ctx_xfer_done */
- 0x0000f807,
+ 0xf4062b21,
+ 0x01981011,
+ 0x0511fd40,
+ 0xf5070bf4,
+/* 0x08ff: ctx_xfer_no_post_mmio */
+/* 0x08ff: ctx_xfer_done */
+ 0xf807b721,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
0x00000000,
};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
new file mode 100644
index 000000000000..ec42ed29b50d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #nvf0_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #nvf0_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
new file mode 100644
index 000000000000..438506d14749
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
@@ -0,0 +1,918 @@
+uint32_t nvf0_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t nvf0_grhub_code[] = {
+ 0x031b0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f802fe,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0x0728b7f1,
+ 0xb906b4b6,
+ 0xc9f002ec,
+ 0x00bcd01f,
+/* 0x0078: nv_rd32_wait */
+ 0xc800bccf,
+ 0x1bf41fcc,
+ 0x06a7f0fa,
+ 0x010921f5,
+ 0xf840bfcf,
+/* 0x008d: nv_wr32 */
+ 0x28b7f100,
+ 0x06b4b607,
+ 0xb980bfd0,
+ 0xc9f002ec,
+ 0x1ec9f01f,
+/* 0x00a3: nv_wr32_wait */
+ 0xcf00bcd0,
+ 0xccc800bc,
+ 0xfa1bf41f,
+/* 0x00ae: watchdog_reset */
+ 0x87f100f8,
+ 0x84b60430,
+ 0x1ff9f006,
+ 0xf8008fd0,
+/* 0x00bd: watchdog_clear */
+ 0x3087f100,
+ 0x0684b604,
+ 0xf80080d0,
+/* 0x00c9: wait_donez */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f03700,
+ 0x0009d002,
+ 0x07f104bd,
+ 0x03f00600,
+ 0x000ad002,
+/* 0x00e6: wait_donez_ne */
+ 0x87f104bd,
+ 0x83f00000,
+ 0x0088cf01,
+ 0xf4888aff,
+ 0x94bdf31b,
+ 0xf10099f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0109: wait_doneo */
+ 0xf094bd00,
+ 0x07f10099,
+ 0x03f03700,
+ 0x0009d002,
+ 0x87f104bd,
+ 0x84b60818,
+ 0x008ad006,
+/* 0x0124: wait_doneo_e */
+ 0x040087f1,
+ 0xcf0684b6,
+ 0x8aff0088,
+ 0xf30bf488,
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f017,
+ 0xbd0009d0,
+/* 0x0147: mmctx_size */
+ 0xbd00f804,
+/* 0x0149: nv_mmctx_size_loop */
+ 0x00e89894,
+ 0xb61a85b6,
+ 0x84b60180,
+ 0x0098bb02,
+ 0xb804e0b6,
+ 0x1bf404ef,
+ 0x029fb9eb,
+/* 0x0166: mmctx_xfer */
+ 0x94bd00f8,
+ 0xf10199f0,
+ 0xf0370007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xb6071087,
+ 0x94bd0684,
+ 0xf405bbfd,
+ 0x8bd0090b,
+ 0x0099f000,
+/* 0x018c: mmctx_base_disabled */
+ 0xf405eefd,
+ 0x8ed00c0b,
+ 0xc08fd080,
+/* 0x019b: mmctx_multi_disabled */
+ 0xb70199f0,
+ 0xc8010080,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xb601aec8,
+ 0xbefd11e4,
+ 0x008bd005,
+/* 0x01b4: mmctx_exec_loop */
+/* 0x01b4: mmctx_wait_free */
+ 0xf0008ecf,
+ 0x0bf41fe4,
+ 0x00ce98fa,
+ 0xd005e9fd,
+ 0xc0b6c08e,
+ 0x04cdb804,
+ 0xc8e81bf4,
+ 0x1bf402ab,
+/* 0x01d5: mmctx_fini_wait */
+ 0x008bcf18,
+ 0xb01fb4f0,
+ 0x1bf410b4,
+ 0x02a7f0f7,
+ 0xf4c921f4,
+/* 0x01ea: mmctx_stop */
+ 0xabc81b0e,
+ 0x10b4b600,
+ 0xf00cb9f0,
+ 0x8bd012b9,
+/* 0x01f9: mmctx_stop_wait */
+ 0x008bcf00,
+ 0xf412bbc8,
+/* 0x0202: mmctx_done */
+ 0x94bdfa1b,
+ 0xf10199f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0215: strand_wait */
+ 0xf0a0f900,
+ 0x21f402a7,
+ 0xf8a0fcc9,
+/* 0x0221: strand_pre */
+ 0xfc87f100,
+ 0x0283f04a,
+ 0xd00c97f0,
+ 0x21f50089,
+ 0x00f80215,
+/* 0x0234: strand_post */
+ 0x4afc87f1,
+ 0xf00283f0,
+ 0x89d00d97,
+ 0x1521f500,
+/* 0x0247: strand_set */
+ 0xf100f802,
+ 0xf04ffca7,
+ 0xaba202a3,
+ 0xc7f00500,
+ 0x00acd00f,
+ 0xd00bc7f0,
+ 0x21f500bc,
+ 0xaed00215,
+ 0x0ac7f000,
+ 0xf500bcd0,
+ 0xf8021521,
+/* 0x0271: strand_ctx_init */
+ 0xf094bd00,
+ 0x07f10399,
+ 0x03f03700,
+ 0x0009d002,
+ 0x21f504bd,
+ 0xe7f00221,
+ 0x4721f503,
+ 0xfca7f102,
+ 0x02a3f046,
+ 0x0400aba0,
+ 0xf040a0d0,
+ 0xbcd001c7,
+ 0x1521f500,
+ 0x010c9202,
+ 0xf000acd0,
+ 0xbcd002c7,
+ 0x1521f500,
+ 0x3421f502,
+ 0x8087f102,
+ 0x0684b608,
+ 0xb70089cf,
+ 0x95220080,
+/* 0x02ca: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x02fe: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x031b: init */
+ 0xbd00f804,
+ 0x0004fe04,
+ 0xf10007fe,
+ 0xf0120017,
+ 0x12d00227,
+ 0xb117f100,
+ 0x0010fe05,
+ 0x040017f1,
+ 0xf1c010d0,
+ 0xb6040437,
+ 0x27f10634,
+ 0x32d02003,
+ 0x0427f100,
+ 0x0132d020,
+ 0x200b27f1,
+ 0xf10232d0,
+ 0xd0200c27,
+ 0x27f10732,
+ 0x24b60c24,
+ 0x0003b906,
+ 0xf10023d0,
+ 0xf0870427,
+ 0x12d00023,
+ 0x0012b700,
+ 0x0427f001,
+ 0xf40012d0,
+ 0xe7f11031,
+ 0xe3f09604,
+ 0x6821f440,
+ 0x8090f1c7,
+ 0xf4f00301,
+ 0x020f801f,
+ 0xbb0117f0,
+ 0x12b6041f,
+ 0x0c27f101,
+ 0x0624b604,
+ 0xd00021d0,
+ 0x17f14021,
+ 0x0e980100,
+ 0x010f9800,
+ 0x014721f5,
+ 0x070037f1,
+ 0x950634b6,
+ 0x34d00814,
+ 0x4034d000,
+ 0x130030b7,
+ 0xb6001fbb,
+ 0x3fd002f5,
+ 0x0815b600,
+ 0xb60110b6,
+ 0x1fb90814,
+ 0x7121f502,
+ 0x001fbb02,
+ 0xf1020398,
+ 0xf0200047,
+/* 0x03f6: init_gpc */
+ 0x4ea05043,
+ 0x1fb90804,
+ 0x8d21f402,
+ 0x010c4ea0,
+ 0x21f4f4bd,
+ 0x044ea08d,
+ 0x8d21f401,
+ 0x01004ea0,
+ 0xf402f7f0,
+ 0x4ea08d21,
+/* 0x041e: init_gpc_wait */
+ 0x21f40800,
+ 0x1fffc868,
+ 0xa0fa0bf4,
+ 0xf408044e,
+ 0x1fbb6821,
+ 0x0040b700,
+ 0x0132b680,
+ 0xf1be1bf4,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x300007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0458: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00de1b,
+ 0x0499f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0b0017f1,
+ 0xcf0614b6,
+ 0x11cf4012,
+ 0x1f13c800,
+ 0x00870bf5,
+ 0xf41f23c8,
+ 0x20f9620b,
+ 0xbd0212b9,
+ 0x0799f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xf40132f4,
+ 0x21f50231,
+ 0x94bd0801,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xfc04bd00,
+ 0xf094bd20,
+ 0x07f10699,
+ 0x03f03700,
+ 0x0009d002,
+ 0x31f404bd,
+ 0x0121f501,
+ 0xf094bd08,
+ 0x07f10699,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x04f9: chsw_prev_no_next */
+ 0xb920f931,
+ 0x32f40212,
+ 0x0232f401,
+ 0x080121f5,
+ 0x17f120fc,
+ 0x14b60b00,
+ 0x0012d006,
+/* 0x0517: chsw_no_prev */
+ 0xc8130ef4,
+ 0x0bf41f23,
+ 0x0131f40d,
+ 0xf50232f4,
+/* 0x0527: chsw_done */
+ 0xf1080121,
+ 0xb60b0c17,
+ 0x27f00614,
+ 0x0012d001,
+ 0x99f094bd,
+ 0x0007f104,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x130ef504,
+/* 0x0549: main_not_ctx_switch */
+ 0x01e4b0ff,
+ 0xb90d1bf4,
+ 0x21f502f2,
+ 0x0ef40795,
+/* 0x0559: main_not_ctx_chan */
+ 0x02e4b046,
+ 0xbd321bf4,
+ 0x0799f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xf40132f4,
+ 0x21f50232,
+ 0x94bd0801,
+ 0xf10799f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf404bd00,
+/* 0x058e: main_not_ctx_save */
+ 0xef94110e,
+ 0x01f5f010,
+ 0x02fe21f5,
+ 0xfec00ef5,
+/* 0x059c: main_done */
+ 0x29f024bd,
+ 0x0007f11f,
+ 0x0203f030,
+ 0xbd0002d0,
+ 0xab0ef504,
+/* 0x05b1: ih */
+ 0xfe80f9fe,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0x0acf04bd,
+ 0x04abc480,
+ 0xf11d0bf4,
+ 0xf01900b7,
+ 0xbecf10d7,
+ 0x00bfcf40,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0xbed001e7,
+/* 0x05e9: ih_no_fifo */
+ 0x00abe400,
+ 0x0d0bf401,
+ 0xf110d7f0,
+ 0xf44001e7,
+/* 0x05fa: ih_no_ctxsw */
+ 0xb7f10421,
+ 0xb0bd0104,
+ 0xf4b4abff,
+ 0xa7f10d0b,
+ 0xa4b60c1c,
+ 0x00abd006,
+/* 0x0610: ih_no_other */
+ 0xfc400ad0,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x062b: ctx_4170s */
+ 0xf101f800,
+ 0xf04170e7,
+ 0xf5f040e3,
+ 0x8d21f410,
+/* 0x063a: ctx_4170w */
+ 0xe7f100f8,
+ 0xe3f04170,
+ 0x6821f440,
+ 0xf410f4f0,
+ 0x00f8f31b,
+/* 0x064c: ctx_redswitch */
+ 0x0614e7f1,
+ 0xf106e4b6,
+ 0xd00270f7,
+ 0xf7f000ef,
+/* 0x065d: ctx_redswitch_delay */
+ 0x01f2b608,
+ 0xf1fd1bf4,
+ 0xd00770f7,
+ 0x00f800ef,
+/* 0x066c: ctx_86c */
+ 0x086ce7f1,
+ 0xd006e4b6,
+ 0xe7f100ef,
+ 0xe3f08a14,
+ 0x8d21f440,
+ 0xa86ce7f1,
+ 0xf441e3f0,
+ 0x00f88d21,
+/* 0x068c: ctx_load */
+ 0x99f094bd,
+ 0x0007f105,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0ca7f004,
+ 0xf1c921f4,
+ 0xb60a2417,
+ 0x10d00614,
+ 0x0037f100,
+ 0x0634b60b,
+ 0xf14032d0,
+ 0xb60a0c17,
+ 0x47f00614,
+ 0x0012d007,
+/* 0x06c7: ctx_chan_wait_0 */
+ 0xcf4014d0,
+ 0x44f04014,
+ 0xfa1bf41f,
+ 0xfe0032d0,
+ 0x2af0000b,
+ 0x0424b61f,
+ 0xbd0220b6,
+ 0x0899f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x0a0417f1,
+ 0xd00614b6,
+ 0x17f10012,
+ 0x14b60a20,
+ 0x0227f006,
+ 0x800023f1,
+ 0xf00012d0,
+ 0x27f11017,
+ 0x23f00200,
+ 0x0512fa02,
+ 0x94bd03f8,
+ 0xf10899f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0x9804bd00,
+ 0x14b68101,
+ 0x80029818,
+ 0xfd0825b6,
+ 0x01800512,
+ 0xf094bd16,
+ 0x07f10999,
+ 0x03f03700,
+ 0x0009d002,
+ 0x27f104bd,
+ 0x24b60a04,
+ 0x0021d006,
+ 0xf10127f0,
+ 0xb60a2017,
+ 0x12d00614,
+ 0x0017f100,
+ 0x0613f001,
+ 0xf80501fa,
+ 0xf094bd03,
+ 0x07f10999,
+ 0x03f01700,
+ 0x0009d002,
+ 0x94bd04bd,
+ 0xf10599f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xf804bd00,
+/* 0x0795: ctx_chan */
+ 0x8c21f500,
+ 0x0ca7f006,
+ 0xf1c921f4,
+ 0xb60a1017,
+ 0x27f00614,
+ 0x0012d005,
+/* 0x07ac: ctx_chan_wait */
+ 0xfd0012cf,
+ 0x1bf40522,
+/* 0x07b7: ctx_mmio_exec */
+ 0x9800f8fa,
+ 0x27f14103,
+ 0x24b60a04,
+ 0x0023d006,
+/* 0x07c6: ctx_mmio_loop */
+ 0x34c434bd,
+ 0x0f1bf4ff,
+ 0x020057f1,
+ 0xfa0653f0,
+ 0x03f80535,
+/* 0x07d8: ctx_mmio_pull */
+ 0x98804e98,
+ 0x21f4814f,
+ 0x0830b68d,
+ 0xf40112b6,
+/* 0x07ea: ctx_mmio_done */
+ 0x0398df1b,
+ 0x0023d016,
+ 0xf1400080,
+ 0xf0010017,
+ 0x01fa0613,
+ 0xf803f806,
+/* 0x0801: ctx_xfer */
+ 0x00f7f100,
+ 0x06f4b60c,
+ 0xd004e7f0,
+/* 0x080e: ctx_xfer_idle */
+ 0xfecf80fe,
+ 0x00e4f100,
+ 0xf91bf420,
+ 0xf40611f4,
+/* 0x081e: ctx_xfer_pre */
+ 0xf7f00d02,
+ 0x6c21f510,
+ 0x1c11f406,
+/* 0x0828: ctx_xfer_pre_load */
+ 0xf502f7f0,
+ 0xf5062b21,
+ 0xf5063a21,
+ 0xbd064c21,
+ 0x2b21f5f4,
+ 0x8c21f506,
+/* 0x0841: ctx_xfer_exec */
+ 0x16019806,
+ 0x041427f1,
+ 0xd00624b6,
+ 0xe7f10020,
+ 0xe3f0a500,
+ 0x021fb941,
+ 0xb68d21f4,
+ 0xfcf004e0,
+ 0x022cf001,
+ 0xfd0124b6,
+ 0x21f405f2,
+ 0xfc17f18d,
+ 0x0213f04a,
+ 0xd00c27f0,
+ 0x21f50012,
+ 0x27f10215,
+ 0x23f047fc,
+ 0x0020d002,
+ 0xb6012cf0,
+ 0x12d00320,
+ 0x01acf000,
+ 0xf006a5f0,
+ 0x0c9800b7,
+ 0x010d9800,
+ 0xf500e7f0,
+ 0xf0016621,
+ 0x21f508a7,
+ 0x21f50109,
+ 0x01f40215,
+ 0x0ca7f022,
+ 0xf1c921f4,
+ 0xb60a1017,
+ 0x27f00614,
+ 0x0012d005,
+/* 0x08c8: ctx_xfer_post_save_wait */
+ 0xfd0012cf,
+ 0x1bf40522,
+ 0x2e02f4fa,
+/* 0x08d4: ctx_xfer_post */
+ 0xf502f7f0,
+ 0xbd062b21,
+ 0x6c21f5f4,
+ 0x3421f506,
+ 0x3a21f502,
+ 0xf5f4bd06,
+ 0xf4062b21,
+ 0x01981011,
+ 0x0511fd40,
+ 0xf5070bf4,
+/* 0x08ff: ctx_xfer_no_post_mmio */
+/* 0x08ff: ctx_xfer_done */
+ 0xf807b721,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
new file mode 100644
index 000000000000..33a5a82eccbd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "os.h"
+
+#define GF100 0xc0
+#define GF117 0xd7
+#define GK100 0xe0
+#define GK110 0xf0
+
+#define NV_PGRAPH_FECS_SIGNAL 0x409400
+#if CHIPSET < GK110
+#define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x409800)
+#define NV_PGRAPH_FECS_CC_SCRATCH_SET(n) ((n) * 4 + 0x409820)
+#define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x409840)
+#else
+#define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x409800)
+#define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x409840)
+#define NV_PGRAPH_FECS_CC_SCRATCH_SET(n) ((n) * 4 + 0x4098c0)
+#endif
+#define NV_PGRAPH_FECS_INTR_UP_SET 0x409c1c
+
+#if CHIPSET < GK110
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x41a800)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n) ((n) * 4 + 0x41a820)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x41a840)
+#else
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n) ((n) * 4 + 0x41a800)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n) ((n) * 4 + 0x41a840)
+#define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n) ((n) * 4 + 0x41a8c0)
+#endif
+
+#define mmctx_data(r,c) .b32 (((c - 1) << 26) | r)
+#define queue_init .skip 72 // (2 * 4) + ((8 * 4) * 2)
+
+#define T_WAIT 0
+#define T_MMCTX 1
+#define T_STRWAIT 2
+#define T_STRINIT 3
+#define T_AUTO 4
+#define T_CHAN 5
+#define T_LOAD 6
+#define T_SAVE 7
+#define T_LCHAN 8
+#define T_LCTXH 9
+
+#define nv_mkmm(rv,r) /*
+*/ movw rv ((r) & 0x0000fffc) /*
+*/ sethi rv ((r) & 0x00ff0000)
+#define nv_mkio(rv,r,i) /*
+*/ nv_mkmm(rv, (((r) & 0xffc) << 6) | ((i) << 2))
+
+#define nv_iord(rv,r,i) /*
+*/ nv_mkio(rv,r,i) /*
+*/ iord rv I[rv]
+#define nv_iowr(r,i,rv) /*
+*/ nv_mkio($r0,r,i) /*
+*/ iowr I[$r0] rv /*
+*/ clear b32 $r0
+
+#define trace_set(bit) /*
+*/ clear b32 $r9 /*
+*/ bset $r9 bit /*
+*/ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(7), 0, $r9)
+#define trace_clr(bit) /*
+*/ clear b32 $r9 /*
+*/ bset $r9 bit /*
+*/ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_CLR(7), 0, $r9)
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
deleted file mode 100644
index f16a5d53319d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/nve0.fuc
+++ /dev/null
@@ -1,400 +0,0 @@
-/* fuc microcode util functions for nve0 PGRAPH
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)')
-define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))')
-
-ifdef(`include_code', `
-// Error codes
-define(`E_BAD_COMMAND', 0x01)
-define(`E_CMD_OVERFLOW', 0x02)
-
-// Util macros to help with debugging ucode hangs etc
-define(`T_WAIT', 0)
-define(`T_MMCTX', 1)
-define(`T_STRWAIT', 2)
-define(`T_STRINIT', 3)
-define(`T_AUTO', 4)
-define(`T_CHAN', 5)
-define(`T_LOAD', 6)
-define(`T_SAVE', 7)
-define(`T_LCHAN', 8)
-define(`T_LCTXH', 9)
-
-define(`trace_set', `
- mov $r8 0x83c
- shl b32 $r8 6
- clear b32 $r9
- bset $r9 $1
- iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
-')
-
-define(`trace_clr', `
- mov $r8 0x85c
- shl b32 $r8 6
- clear b32 $r9
- bset $r9 $1
- iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7]
-')
-
-// queue_put - add request to queue
-//
-// In : $r13 queue pointer
-// $r14 command
-// $r15 data
-//
-queue_put:
- // make sure we have space..
- ld b32 $r8 D[$r13 + 0x0] // GET
- ld b32 $r9 D[$r13 + 0x4] // PUT
- xor $r8 8
- cmpu b32 $r8 $r9
- bra ne #queue_put_next
- mov $r15 E_CMD_OVERFLOW
- call #error
- ret
-
- // store cmd/data on queue
- queue_put_next:
- and $r8 $r9 7
- shl b32 $r8 3
- add b32 $r8 $r13
- add b32 $r8 8
- st b32 D[$r8 + 0x0] $r14
- st b32 D[$r8 + 0x4] $r15
-
- // update PUT
- add b32 $r9 1
- and $r9 0xf
- st b32 D[$r13 + 0x4] $r9
- ret
-
-// queue_get - fetch request from queue
-//
-// In : $r13 queue pointer
-//
-// Out: $p1 clear on success (data available)
-// $r14 command
-// $r15 data
-//
-queue_get:
- bset $flags $p1
- ld b32 $r8 D[$r13 + 0x0] // GET
- ld b32 $r9 D[$r13 + 0x4] // PUT
- cmpu b32 $r8 $r9
- bra e #queue_get_done
- // fetch first cmd/data pair
- and $r9 $r8 7
- shl b32 $r9 3
- add b32 $r9 $r13
- add b32 $r9 8
- ld b32 $r14 D[$r9 + 0x0]
- ld b32 $r15 D[$r9 + 0x4]
-
- // update GET
- add b32 $r8 1
- and $r8 0xf
- st b32 D[$r13 + 0x0] $r8
- bclr $flags $p1
-queue_get_done:
- ret
-
-// nv_rd32 - read 32-bit value from nv register
-//
-// In : $r14 register
-// Out: $r15 value
-//
-nv_rd32:
- mov $r11 0x728
- shl b32 $r11 6
- mov b32 $r12 $r14
- bset $r12 31 // MMIO_CTRL_PENDING
- iowr I[$r11 + 0x000] $r12 // MMIO_CTRL
- nv_rd32_wait:
- iord $r12 I[$r11 + 0x000]
- xbit $r12 $r12 31
- bra ne #nv_rd32_wait
- mov $r10 6 // DONE_MMIO_RD
- call #wait_doneo
- iord $r15 I[$r11 + 0x100] // MMIO_RDVAL
- ret
-
-// nv_wr32 - write 32-bit value to nv register
-//
-// In : $r14 register
-// $r15 value
-//
-nv_wr32:
- mov $r11 0x728
- shl b32 $r11 6
- iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL
- mov b32 $r12 $r14
- bset $r12 31 // MMIO_CTRL_PENDING
- bset $r12 30 // MMIO_CTRL_WRITE
- iowr I[$r11 + 0x000] $r12 // MMIO_CTRL
- nv_wr32_wait:
- iord $r12 I[$r11 + 0x000]
- xbit $r12 $r12 31
- bra ne #nv_wr32_wait
- ret
-
-// (re)set watchdog timer
-//
-// In : $r15 timeout
-//
-watchdog_reset:
- mov $r8 0x430
- shl b32 $r8 6
- bset $r15 31
- iowr I[$r8 + 0x000] $r15
- ret
-
-// clear watchdog timer
-watchdog_clear:
- mov $r8 0x430
- shl b32 $r8 6
- iowr I[$r8 + 0x000] $r0
- ret
-
-// wait_done{z,o} - wait on FUC_DONE bit to become clear/set
-//
-// In : $r10 bit to wait on
-//
-define(`wait_done', `
-$1:
- trace_set(T_WAIT);
- mov $r8 0x818
- shl b32 $r8 6
- iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit
- wait_done_$1:
- mov $r8 0x400
- shl b32 $r8 6
- iord $r8 I[$r8 + 0x000] // DONE
- xbit $r8 $r8 $r10
- bra $2 #wait_done_$1
- trace_clr(T_WAIT)
- ret
-')
-wait_done(wait_donez, ne)
-wait_done(wait_doneo, e)
-
-// mmctx_size - determine size of a mmio list transfer
-//
-// In : $r14 mmio list head
-// $r15 mmio list tail
-// Out: $r15 transfer size (in bytes)
-//
-mmctx_size:
- clear b32 $r9
- nv_mmctx_size_loop:
- ld b32 $r8 D[$r14]
- shr b32 $r8 26
- add b32 $r8 1
- shl b32 $r8 2
- add b32 $r9 $r8
- add b32 $r14 4
- cmpu b32 $r14 $r15
- bra ne #nv_mmctx_size_loop
- mov b32 $r15 $r9
- ret
-
-// mmctx_xfer - execute a list of mmio transfers
-//
-// In : $r10 flags
-// bit 0: direction (0 = save, 1 = load)
-// bit 1: set if first transfer
-// bit 2: set if last transfer
-// $r11 base
-// $r12 mmio list head
-// $r13 mmio list tail
-// $r14 multi_stride
-// $r15 multi_mask
-//
-mmctx_xfer:
- trace_set(T_MMCTX)
- mov $r8 0x710
- shl b32 $r8 6
- clear b32 $r9
- or $r11 $r11
- bra e #mmctx_base_disabled
- iowr I[$r8 + 0x000] $r11 // MMCTX_BASE
- bset $r9 0 // BASE_EN
- mmctx_base_disabled:
- or $r14 $r14
- bra e #mmctx_multi_disabled
- iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE
- iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK
- bset $r9 1 // MULTI_EN
- mmctx_multi_disabled:
- add b32 $r8 0x100
-
- xbit $r11 $r10 0
- shl b32 $r11 16 // DIR
- bset $r11 12 // QLIMIT = 0x10
- xbit $r14 $r10 1
- shl b32 $r14 17
- or $r11 $r14 // START_TRIGGER
- iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL
-
- // loop over the mmio list, and send requests to the hw
- mmctx_exec_loop:
- // wait for space in mmctx queue
- mmctx_wait_free:
- iord $r14 I[$r8 + 0x000] // MMCTX_CTRL
- and $r14 0x1f
- bra e #mmctx_wait_free
-
- // queue up an entry
- ld b32 $r14 D[$r12]
- or $r14 $r9
- iowr I[$r8 + 0x300] $r14
- add b32 $r12 4
- cmpu b32 $r12 $r13
- bra ne #mmctx_exec_loop
-
- xbit $r11 $r10 2
- bra ne #mmctx_stop
- // wait for queue to empty
- mmctx_fini_wait:
- iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
- and $r11 0x1f
- cmpu b32 $r11 0x10
- bra ne #mmctx_fini_wait
- mov $r10 2 // DONE_MMCTX
- call #wait_donez
- bra #mmctx_done
- mmctx_stop:
- xbit $r11 $r10 0
- shl b32 $r11 16 // DIR
- bset $r11 12 // QLIMIT = 0x10
- bset $r11 18 // STOP_TRIGGER
- iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL
- mmctx_stop_wait:
- // wait for STOP_TRIGGER to clear
- iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
- xbit $r11 $r11 18
- bra ne #mmctx_stop_wait
- mmctx_done:
- trace_clr(T_MMCTX)
- ret
-
-// Wait for DONE_STRAND
-//
-strand_wait:
- push $r10
- mov $r10 2
- call #wait_donez
- pop $r10
- ret
-
-// unknown - call before issuing strand commands
-//
-strand_pre:
- mov $r8 0x4afc
- sethi $r8 0x20000
- mov $r9 0xc
- iowr I[$r8] $r9
- call #strand_wait
- ret
-
-// unknown - call after issuing strand commands
-//
-strand_post:
- mov $r8 0x4afc
- sethi $r8 0x20000
- mov $r9 0xd
- iowr I[$r8] $r9
- call #strand_wait
- ret
-
-// Selects strand set?!
-//
-// In: $r14 id
-//
-strand_set:
- mov $r10 0x4ffc
- sethi $r10 0x20000
- sub b32 $r11 $r10 0x500
- mov $r12 0xf
- iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf
- mov $r12 0xb
- iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb
- call #strand_wait
- iowr I[$r10 + 0x000] $r14 // 0x93c = <id>
- mov $r12 0xa
- iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa
- call #strand_wait
- ret
-
-// Initialise strand context data
-//
-// In : $r15 context base
-// Out: $r15 context size (in bytes)
-//
-// Strandset(?) 3 hardcoded currently
-//
-strand_ctx_init:
- trace_set(T_STRINIT)
- call #strand_pre
- mov $r14 3
- call #strand_set
- mov $r10 0x46fc
- sethi $r10 0x20000
- add b32 $r11 $r10 0x400
- iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0
- mov $r12 1
- iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE
- call #strand_wait
- sub b32 $r12 $r0 1
- iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff
- mov $r12 2
- iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT
- call #strand_wait
- call #strand_post
-
- // read the size of each strand, poke the context offset of
- // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
- // about it later then.
- mov $r8 0x880
- shl b32 $r8 6
- iord $r9 I[$r8 + 0x000] // STRANDS
- add b32 $r8 0x2200
- shr b32 $r14 $r15 8
- ctx_init_strand_loop:
- iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE
- iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE
- iord $r10 I[$r8 + 0x200] // STRAND_SIZE
- shr b32 $r10 6
- add b32 $r10 1
- add b32 $r14 $r10
- add b32 $r8 4
- sub b32 $r9 1
- bra ne #ctx_init_strand_loop
-
- shl b32 $r14 8
- sub b32 $r15 $r14 $r15
- trace_clr(T_STRINIT)
- ret
-')
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
new file mode 100644
index 000000000000..fd1d380de094
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_GRAPH_OS_H__
+#define __NVKM_GRAPH_OS_H__
+
+#define E_BAD_COMMAND 0x00000001
+#define E_CMD_OVERFLOW 0x00000002
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
index 1ac36110ca19..03de5175dd9f 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
@@ -186,13 +186,6 @@ nv50_graph_cclass = {
* PGRAPH engine/subdev functions
******************************************************************************/
-static int
-nv50_graph_tlb_flush(struct nouveau_engine *engine)
-{
- nv50_vm_flush_engine(&engine->base, 0x00);
- return 0;
-}
-
static const struct nouveau_bitfield nv50_pgraph_status[] = {
{ 0x00000001, "BUSY" }, /* set when any bit is set */
{ 0x00000002, "DISPATCH" },
@@ -302,8 +295,10 @@ nv84_graph_tlb_flush(struct nouveau_engine *engine)
nv_rd32(priv, 0x400388));
}
- nv50_vm_flush_engine(&engine->base, 0x00);
+ nv_wr32(priv, 0x100c80, 0x00000001);
+ if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+ nv_error(priv, "vm flush timeout\n");
nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
spin_unlock_irqrestore(&priv->lock, flags);
return timeout ? -EBUSY : 0;
@@ -857,10 +852,9 @@ nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
};
- if (nv_device(priv)->chipset == 0x50 ||
- nv_device(priv)->chipset == 0xac)
- nv_engine(priv)->tlb_flush = nv50_graph_tlb_flush;
- else
+ /* unfortunate hw bug workaround... */
+ if (nv_device(priv)->chipset != 0x50 &&
+ nv_device(priv)->chipset != 0xac)
nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush;
spin_lock_init(&priv->lock);
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
index f9b9d82c287f..3f4f35cc3848 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
@@ -23,14 +23,12 @@
*/
#include "nvc0.h"
-#include "fuc/hubnvc0.fuc.h"
-#include "fuc/gpcnvc0.fuc.h"
/*******************************************************************************
* Graphics object classes
******************************************************************************/
-static struct nouveau_oclass
+struct nouveau_oclass
nvc0_graph_sclass[] = {
{ 0x902d, &nouveau_object_ofuncs },
{ 0x9039, &nouveau_object_ofuncs },
@@ -39,40 +37,6 @@ nvc0_graph_sclass[] = {
{}
};
-static struct nouveau_oclass
-nvc1_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0x9039, &nouveau_object_ofuncs },
- { 0x9097, &nouveau_object_ofuncs },
- { 0x90c0, &nouveau_object_ofuncs },
- { 0x9197, &nouveau_object_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nvc8_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0x9039, &nouveau_object_ofuncs },
- { 0x9097, &nouveau_object_ofuncs },
- { 0x90c0, &nouveau_object_ofuncs },
- { 0x9197, &nouveau_object_ofuncs },
- { 0x9297, &nouveau_object_ofuncs },
- {}
-};
-
-u64
-nvc0_graph_units(struct nouveau_graph *graph)
-{
- struct nvc0_graph_priv *priv = (void *)graph;
- u64 cfg;
-
- cfg = (u32)priv->gpc_nr;
- cfg |= (u32)priv->tpc_total << 8;
- cfg |= (u64)priv->rop_nr << 32;
-
- return cfg;
-}
-
/*******************************************************************************
* PGRAPH context
******************************************************************************/
@@ -181,60 +145,308 @@ nvc0_graph_context_dtor(struct nouveau_object *object)
nouveau_graph_context_destroy(&chan->base);
}
-static struct nouveau_oclass
-nvc0_graph_cclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
/*******************************************************************************
* PGRAPH engine/subdev functions
******************************************************************************/
-static void
-nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
+struct nvc0_graph_init
+nvc0_graph_init_regs[] = {
+ { 0x400080, 1, 0x04, 0x003083c2 },
+ { 0x400088, 1, 0x04, 0x00006fe7 },
+ { 0x40008c, 1, 0x04, 0x00000000 },
+ { 0x400090, 1, 0x04, 0x00000030 },
+ { 0x40013c, 1, 0x04, 0x013901f7 },
+ { 0x400140, 1, 0x04, 0x00000100 },
+ { 0x400144, 1, 0x04, 0x00000000 },
+ { 0x400148, 1, 0x04, 0x00000110 },
+ { 0x400138, 1, 0x04, 0x00000000 },
+ { 0x400130, 2, 0x04, 0x00000000 },
+ { 0x400124, 1, 0x04, 0x00000002 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk40xx[] = {
+ { 0x40415c, 1, 0x04, 0x00000000 },
+ { 0x404170, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk44xx[] = {
+ { 0x404488, 2, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk78xx[] = {
+ { 0x407808, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk60xx[] = {
+ { 0x406024, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk58xx[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk80xx[] = {
+ { 0x40803c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_gpc[] = {
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x80000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 1, 0x04, 0x80000000 },
+ { 0x4188cc, 1, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000050 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc0_graph_init_tpc[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x41980c, 3, 0x04, 0x00000000 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x06060618 },
+ { 0x419ed0, 1, 0x04, 0x0eff0e38 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_init_unk88xx[] = {
+ { 0x40880c, 1, 0x04, 0x00000000 },
+ { 0x408910, 9, 0x04, 0x00000000 },
+ { 0x408950, 1, 0x04, 0x00000000 },
+ { 0x408954, 1, 0x04, 0x0000ffff },
+ { 0x408984, 1, 0x04, 0x00000000 },
+ { 0x408988, 1, 0x04, 0x08040201 },
+ { 0x40898c, 1, 0x04, 0x80402010 },
+ {}
+};
+
+struct nvc0_graph_init
+nvc0_graph_tpc_0[] = {
+ { 0x50405c, 1, 0x04, 0x00000001 },
+ {}
+};
+
+void
+nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
{
- nv_error(priv, "%06x - done 0x%08x\n", base,
- nv_rd32(priv, base + 0x400));
- nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
- nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
- nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
- nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
- nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
- nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
+ for (; init && init->count; init++) {
+ u32 addr = init->addr, i;
+ for (i = 0; i < init->count; i++) {
+ nv_wr32(priv, addr, init->data);
+ addr += init->pitch;
+ }
+ }
}
void
-nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
+nvc0_graph_icmd(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
{
- u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
- u32 gpc;
+ u32 addr, data;
+ int i, j;
+
+ nv_wr32(priv, 0x400208, 0x80000000);
+ for (i = 0; init->count; init++, i++) {
+ if (!i || data != init->data) {
+ nv_wr32(priv, 0x400204, init->data);
+ data = init->data;
+ }
- nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
- for (gpc = 0; gpc < gpcnr; gpc++)
- nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
+ addr = init->addr;
+ for (j = 0; j < init->count; j++) {
+ nv_wr32(priv, 0x400200, addr);
+ addr += init->pitch;
+ while (nv_rd32(priv, 0x400700) & 0x00000002) {}
+ }
+ }
+ nv_wr32(priv, 0x400208, 0x00000000);
+}
+
+void
+nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds)
+{
+ struct nvc0_graph_mthd *mthd;
+ struct nvc0_graph_init *init;
+ int i = 0, j;
+ u32 data;
+
+ while ((mthd = &mthds[i++]) && (init = mthd->init)) {
+ u32 addr = 0x80000000 | mthd->oclass;
+ for (data = 0; init->count; init++) {
+ if (data != init->data) {
+ nv_wr32(priv, 0x40448c, init->data);
+ data = init->data;
+ }
+
+ addr = (addr & 0x8000ffff) | (init->addr << 14);
+ for (j = 0; j < init->count; j++) {
+ nv_wr32(priv, 0x404488, addr);
+ addr += init->pitch << 14;
+ }
+ }
+ }
+}
+
+u64
+nvc0_graph_units(struct nouveau_graph *graph)
+{
+ struct nvc0_graph_priv *priv = (void *)graph;
+ u64 cfg;
+
+ cfg = (u32)priv->gpc_nr;
+ cfg |= (u32)priv->tpc_total << 8;
+ cfg |= (u64)priv->rop_nr << 32;
+
+ return cfg;
}
+static const struct nouveau_enum nve0_sked_error[] = {
+ { 7, "CONSTANT_BUFFER_SIZE" },
+ { 9, "LOCAL_MEMORY_SIZE_POS" },
+ { 10, "LOCAL_MEMORY_SIZE_NEG" },
+ { 11, "WARP_CSTACK_SIZE" },
+ { 12, "TOTAL_TEMP_SIZE" },
+ { 13, "REGISTER_COUNT" },
+ { 18, "TOTAL_THREADS" },
+ { 20, "PROGRAM_OFFSET" },
+ { 21, "SHARED_MEMORY_SIZE" },
+ { 25, "SHARED_CONFIG_TOO_SMALL" },
+ { 26, "TOTAL_REGISTER_COUNT" },
+ {}
+};
+
+static const struct nouveau_enum nvc0_gpc_rop_error[] = {
+ { 1, "RT_PITCH_OVERRUN" },
+ { 4, "RT_WIDTH_OVERRUN" },
+ { 5, "RT_HEIGHT_OVERRUN" },
+ { 7, "ZETA_STORAGE_TYPE_MISMATCH" },
+ { 8, "RT_STORAGE_TYPE_MISMATCH" },
+ { 10, "RT_LINEAR_MISMATCH" },
+ {}
+};
+
static void
-nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
+nvc0_graph_trap_gpc_rop(struct nvc0_graph_priv *priv, int gpc)
{
- u32 ustat = nv_rd32(priv, 0x409c18);
+ u32 trap[4];
+ int i;
- if (ustat & 0x00000001)
- nv_error(priv, "CTXCTRL ucode error\n");
- if (ustat & 0x00080000)
- nv_error(priv, "CTXCTRL watchdog timeout\n");
- if (ustat & ~0x00080001)
- nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
+ trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
+ trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
+ trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
+ trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
+
+ nv_error(priv, "GPC%d/PROP trap:", gpc);
+ for (i = 0; i <= 29; ++i) {
+ if (!(trap[0] & (1 << i)))
+ continue;
+ pr_cont(" ");
+ nouveau_enum_print(nvc0_gpc_rop_error, i);
+ }
+ pr_cont("\n");
- nvc0_graph_ctxctl_debug(priv);
- nv_wr32(priv, 0x409c20, ustat);
+ nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n",
+ trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f,
+ trap[3] & 0xff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+}
+
+static const struct nouveau_enum nvc0_mp_warp_error[] = {
+ { 0x00, "NO_ERROR" },
+ { 0x01, "STACK_MISMATCH" },
+ { 0x05, "MISALIGNED_PC" },
+ { 0x08, "MISALIGNED_GPR" },
+ { 0x09, "INVALID_OPCODE" },
+ { 0x0d, "GPR_OUT_OF_BOUNDS" },
+ { 0x0e, "MEM_OUT_OF_BOUNDS" },
+ { 0x0f, "UNALIGNED_MEM_ACCESS" },
+ { 0x11, "INVALID_PARAM" },
+ {}
+};
+
+static const struct nouveau_bitfield nvc0_mp_global_error[] = {
+ { 0x00000004, "MULTIPLE_WARP_ERRORS" },
+ { 0x00000008, "OUT_OF_STACK_SPACE" },
+ {}
+};
+
+static void
+nvc0_graph_trap_mp(struct nvc0_graph_priv *priv, int gpc, int tpc)
+{
+ u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648));
+ u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650));
+
+ nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc);
+ nouveau_bitfield_print(nvc0_mp_global_error, gerr);
+ if (werr) {
+ pr_cont(" ");
+ nouveau_enum_print(nvc0_mp_warp_error, werr & 0xffff);
+ }
+ pr_cont("\n");
+
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr);
}
static void
@@ -246,18 +458,11 @@ nvc0_graph_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc)
u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224));
nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000001);
stat &= ~0x00000001;
}
if (stat & 0x00000002) {
- u32 trap0 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0644));
- u32 trap1 = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x064c));
- nv_error(priv, "GPC%d/TPC%d/MP: 0x%08x 0x%08x\n",
- gpc, tpc, trap0, trap1);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0644), 0x001ffffe);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x064c), 0x0000000f);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000002);
+ nvc0_graph_trap_mp(priv, gpc, tpc);
stat &= ~0x00000002;
}
@@ -265,7 +470,6 @@ nvc0_graph_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc)
u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084));
nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000004);
stat &= ~0x00000004;
}
@@ -273,13 +477,11 @@ nvc0_graph_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc)
u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c));
nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap);
nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), 0x00000008);
stat &= ~0x00000008;
}
if (stat) {
nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0508), stat);
}
}
@@ -290,10 +492,7 @@ nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
int tpc;
if (stat & 0x00000001) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
- nv_error(priv, "GPC%d/PROP: 0x%08x\n", gpc, trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000001);
+ nvc0_graph_trap_gpc_rop(priv, gpc);
stat &= ~0x00000001;
}
@@ -301,7 +500,6 @@ nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap);
nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000002);
stat &= ~0x00000002;
}
@@ -309,7 +507,6 @@ nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap);
nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000004);
stat &= ~0x00000004;
}
@@ -317,7 +514,6 @@ nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap);
nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0x00000008);
stat &= ~0x00000009;
}
@@ -332,7 +528,6 @@ nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
if (stat) {
nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), stat);
}
}
@@ -340,7 +535,7 @@ static void
nvc0_graph_trap_intr(struct nvc0_graph_priv *priv)
{
u32 trap = nv_rd32(priv, 0x400108);
- int rop, gpc;
+ int rop, gpc, i;
if (trap & 0x00000001) {
u32 stat = nv_rd32(priv, 0x404000);
@@ -390,6 +585,24 @@ nvc0_graph_trap_intr(struct nvc0_graph_priv *priv)
trap &= ~0x00000080;
}
+ if (trap & 0x00000100) {
+ u32 stat = nv_rd32(priv, 0x407020);
+
+ nv_error(priv, "SKED:");
+ for (i = 0; i <= 29; ++i) {
+ if (!(stat & (1 << i)))
+ continue;
+ pr_cont(" ");
+ nouveau_enum_print(nve0_sked_error, i);
+ }
+ pr_cont("\n");
+
+ if (stat & 0x3fffffff)
+ nv_wr32(priv, 0x407020, 0x40000000);
+ nv_wr32(priv, 0x400108, 0x00000100);
+ trap &= ~0x00000100;
+ }
+
if (trap & 0x01000000) {
u32 stat = nv_rd32(priv, 0x400118);
for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) {
@@ -424,6 +637,46 @@ nvc0_graph_trap_intr(struct nvc0_graph_priv *priv)
}
static void
+nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
+{
+ nv_error(priv, "%06x - done 0x%08x\n", base,
+ nv_rd32(priv, base + 0x400));
+ nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+ nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
+ nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
+ nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+ nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
+ nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
+}
+
+void
+nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
+{
+ u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
+ u32 gpc;
+
+ nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
+ for (gpc = 0; gpc < gpcnr; gpc++)
+ nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
+}
+
+static void
+nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
+{
+ u32 ustat = nv_rd32(priv, 0x409c18);
+
+ if (ustat & 0x00000001)
+ nv_error(priv, "CTXCTL ucode error\n");
+ if (ustat & 0x00080000)
+ nv_error(priv, "CTXCTL watchdog timeout\n");
+ if (ustat & ~0x00080001)
+ nv_error(priv, "CTXCTL 0x%08x\n", ustat);
+
+ nvc0_graph_ctxctl_debug(priv);
+ nv_wr32(priv, 0x409c20, ustat);
+}
+
+static void
nvc0_graph_intr(struct nouveau_subdev *subdev)
{
struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
@@ -499,290 +752,6 @@ nvc0_graph_intr(struct nouveau_subdev *subdev)
nouveau_engctx_put(engctx);
}
-int
-nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
- struct nvc0_graph_fuc *fuc)
-{
- struct nouveau_device *device = nv_device(priv);
- const struct firmware *fw;
- char f[32];
- int ret;
-
- snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
- ret = request_firmware(&fw, f, &device->pdev->dev);
- if (ret) {
- snprintf(f, sizeof(f), "nouveau/%s", fwname);
- ret = request_firmware(&fw, f, &device->pdev->dev);
- if (ret) {
- nv_error(priv, "failed to load %s\n", fwname);
- return ret;
- }
- }
-
- fuc->size = fw->size;
- fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
- release_firmware(fw);
- return (fuc->data != NULL) ? 0 : -ENOMEM;
-}
-
-static int
-nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nvc0_graph_priv *priv;
- bool enable = device->chipset != 0xd7;
- int ret, i;
-
- ret = nouveau_graph_create(parent, engine, oclass, enable, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x18001000;
- nv_subdev(priv)->intr = nvc0_graph_intr;
- nv_engine(priv)->cclass = &nvc0_graph_cclass;
-
- priv->base.units = nvc0_graph_units;
-
- if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) {
- nv_info(priv, "using external firmware\n");
- if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
- nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
- nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
- nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
- return -EINVAL;
- priv->firmware = true;
- }
-
- switch (nvc0_graph_class(priv)) {
- case 0x9097:
- nv_engine(priv)->sclass = nvc0_graph_sclass;
- break;
- case 0x9197:
- nv_engine(priv)->sclass = nvc1_graph_sclass;
- break;
- case 0x9297:
- nv_engine(priv)->sclass = nvc8_graph_sclass;
- break;
- }
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
- &priv->unk4188b4);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
- &priv->unk4188b8);
- if (ret)
- return ret;
-
- for (i = 0; i < 0x1000; i += 4) {
- nv_wo32(priv->unk4188b4, i, 0x00000010);
- nv_wo32(priv->unk4188b8, i, 0x00000010);
- }
-
- priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
- priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f;
- for (i = 0; i < priv->gpc_nr; i++) {
- priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
- priv->tpc_total += priv->tpc_nr[i];
- }
-
- /*XXX: these need figuring out... though it might not even matter */
- switch (nv_device(priv)->chipset) {
- case 0xc0:
- if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
- priv->magic_not_rop_nr = 0x07;
- } else
- if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
- priv->magic_not_rop_nr = 0x05;
- } else
- if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
- priv->magic_not_rop_nr = 0x06;
- }
- break;
- case 0xc3: /* 450, 4/0/0/0, 2 */
- priv->magic_not_rop_nr = 0x03;
- break;
- case 0xc4: /* 460, 3/4/0/0, 4 */
- priv->magic_not_rop_nr = 0x01;
- break;
- case 0xc1: /* 2/0/0/0, 1 */
- priv->magic_not_rop_nr = 0x01;
- break;
- case 0xc8: /* 4/4/3/4, 5 */
- priv->magic_not_rop_nr = 0x06;
- break;
- case 0xce: /* 4/4/0/0, 4 */
- priv->magic_not_rop_nr = 0x03;
- break;
- case 0xcf: /* 4/0/0/0, 3 */
- priv->magic_not_rop_nr = 0x03;
- break;
- case 0xd9: /* 1/0/0/0, 1 */
- priv->magic_not_rop_nr = 0x01;
- break;
- }
-
- return 0;
-}
-
-static void
-nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
-{
- kfree(fuc->data);
- fuc->data = NULL;
-}
-
-void
-nvc0_graph_dtor(struct nouveau_object *object)
-{
- struct nvc0_graph_priv *priv = (void *)object;
-
- kfree(priv->data);
-
- nvc0_graph_dtor_fw(&priv->fuc409c);
- nvc0_graph_dtor_fw(&priv->fuc409d);
- nvc0_graph_dtor_fw(&priv->fuc41ac);
- nvc0_graph_dtor_fw(&priv->fuc41ad);
-
- nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
- nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
- nouveau_graph_destroy(&priv->base);
-}
-
-static void
-nvc0_graph_init_obj418880(struct nvc0_graph_priv *priv)
-{
- int i;
-
- nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
- nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nvc0_graph_init_regs(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x400080, 0x003083c2);
- nv_wr32(priv, 0x400088, 0x00006fe7);
- nv_wr32(priv, 0x40008c, 0x00000000);
- nv_wr32(priv, 0x400090, 0x00000030);
- nv_wr32(priv, 0x40013c, 0x013901f7);
- nv_wr32(priv, 0x400140, 0x00000100);
- nv_wr32(priv, 0x400144, 0x00000000);
- nv_wr32(priv, 0x400148, 0x00000110);
- nv_wr32(priv, 0x400138, 0x00000000);
- nv_wr32(priv, 0x400130, 0x00000000);
- nv_wr32(priv, 0x400134, 0x00000000);
- nv_wr32(priv, 0x400124, 0x00000002);
-}
-
-static void
-nvc0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
-{
- const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
- u32 data[TPC_MAX / 8];
- u8 tpcnr[GPC_MAX];
- int i, gpc, tpc;
-
- nv_wr32(priv, TPC_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */
-
- /*
- * TP ROP UNKVAL(magic_not_rop_nr)
- * 450: 4/0/0/0 2 3
- * 460: 3/4/0/0 4 1
- * 465: 3/4/4/0 4 7
- * 470: 3/3/4/4 5 5
- * 480: 3/4/4/4 6 6
- */
-
- memset(data, 0x00, sizeof(data));
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- data[i / 8] |= tpc << ((i % 8) * 4);
- }
-
- nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
- nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
- nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
- nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
- priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
- }
-
- nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
- nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-}
-
-static void
-nvc0_graph_init_units(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x409c24, 0x000f0000);
- nv_wr32(priv, 0x404000, 0xc0000000); /* DISPATCH */
- nv_wr32(priv, 0x404600, 0xc0000000); /* M2MF */
- nv_wr32(priv, 0x408030, 0xc0000000);
- nv_wr32(priv, 0x40601c, 0xc0000000);
- nv_wr32(priv, 0x404490, 0xc0000000); /* MACRO */
- nv_wr32(priv, 0x406018, 0xc0000000);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x405844, 0x00ffffff);
- nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
- nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-}
-
-static void
-nvc0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
-{
- int gpc, tpc;
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
- }
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
- }
-}
-
-static void
-nvc0_graph_init_rop(struct nvc0_graph_priv *priv)
-{
- int rop;
-
- for (rop = 0; rop < priv->rop_nr; rop++) {
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
- nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
- }
-}
-
void
nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
@@ -801,9 +770,46 @@ nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
}
}
-static int
+static void
+nvc0_graph_init_csdata(struct nvc0_graph_priv *priv,
+ struct nvc0_graph_init *init,
+ u32 falcon, u32 starstar, u32 base)
+{
+ u32 addr = init->addr;
+ u32 next = addr;
+ u32 star, temp;
+
+ nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
+ star = nv_rd32(priv, falcon + 0x01c4);
+ temp = nv_rd32(priv, falcon + 0x01c4);
+ if (temp > star)
+ star = temp;
+ nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
+
+ do {
+ if (init->addr != next) {
+ while (addr < next) {
+ u32 nr = min((int)(next - addr) / 4, 32);
+ nv_wr32(priv, falcon + 0x01c4,
+ ((nr - 1) << 26) | (addr - base));
+ addr += nr * 4;
+ star += 4;
+ }
+ addr = next = init->addr;
+ }
+ next += init->count * 4;
+ } while ((init++)->count);
+
+ nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
+ nv_wr32(priv, falcon + 0x01c4, star);
+}
+
+int
nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
{
+ struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass;
+ struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
+ struct nvc0_graph_init *init;
u32 r000260;
int i;
@@ -854,6 +860,38 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
return -EBUSY;
}
+ if (nv_device(priv)->chipset >= 0xe0) {
+ nv_wr32(priv, 0x409800, 0x00000000);
+ nv_wr32(priv, 0x409500, 0x00000001);
+ nv_wr32(priv, 0x409504, 0x00000030);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x30 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409810, 0xb00095c8);
+ nv_wr32(priv, 0x409800, 0x00000000);
+ nv_wr32(priv, 0x409500, 0x00000001);
+ nv_wr32(priv, 0x409504, 0x00000031);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x31 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409810, 0x00080420);
+ nv_wr32(priv, 0x409800, 0x00000000);
+ nv_wr32(priv, 0x409500, 0x00000001);
+ nv_wr32(priv, 0x409504, 0x00000032);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x32 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409614, 0x00000070);
+ nv_wr32(priv, 0x409614, 0x00000770);
+ nv_wr32(priv, 0x40802c, 0x00000001);
+ }
+
if (priv->data == NULL) {
int ret = nvc0_grctx_generate(priv);
if (ret) {
@@ -868,31 +906,41 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
/* load HUB microcode */
r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
nv_wr32(priv, 0x4091c0, 0x01000000);
- for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++)
- nv_wr32(priv, 0x4091c4, nvc0_grhub_data[i]);
+ for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
+ nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]);
nv_wr32(priv, 0x409180, 0x01000000);
- for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) {
+ for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(priv, 0x409188, i >> 6);
- nv_wr32(priv, 0x409184, nvc0_grhub_code[i]);
+ nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
+ }
+
+ for (i = 0; (init = cclass->hub[i]); i++) {
+ nvc0_graph_init_csdata(priv, init, 0x409000, 0x000, 0x000000);
}
/* load GPC microcode */
nv_wr32(priv, 0x41a1c0, 0x01000000);
- for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++)
- nv_wr32(priv, 0x41a1c4, nvc0_grgpc_data[i]);
+ for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
+ nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
nv_wr32(priv, 0x41a180, 0x01000000);
- for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) {
+ for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(priv, 0x41a188, i >> 6);
- nv_wr32(priv, 0x41a184, nvc0_grgpc_code[i]);
+ nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]);
}
nv_wr32(priv, 0x000260, r000260);
+ if ((init = cclass->gpc[0]))
+ nvc0_graph_init_csdata(priv, init, 0x41a000, 0x000, 0x418000);
+ if ((init = cclass->gpc[2]))
+ nvc0_graph_init_csdata(priv, init, 0x41a000, 0x004, 0x419800);
+ if ((init = cclass->gpc[3]))
+ nvc0_graph_init_csdata(priv, init, 0x41a000, 0x008, 0x41be00);
+
/* start HUB ucode running, it'll init the GPCs */
- nv_wr32(priv, 0x409800, nv_device(priv)->chipset);
nv_wr32(priv, 0x40910c, 0x00000000);
nv_wr32(priv, 0x409100, 0x00000002);
if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
@@ -913,29 +961,104 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
return 0;
}
-static int
+int
nvc0_graph_init(struct nouveau_object *object)
{
+ struct nvc0_graph_oclass *oclass = (void *)object->oclass;
struct nvc0_graph_priv *priv = (void *)object;
- int ret;
+ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+ u32 data[TPC_MAX / 8] = {};
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc, rop;
+ int ret, i;
ret = nouveau_graph_init(&priv->base);
if (ret)
return ret;
- nvc0_graph_init_obj418880(priv);
- nvc0_graph_init_regs(priv);
- /*nvc0_graph_init_unitplemented_magics(priv);*/
- nvc0_graph_init_gpc_0(priv);
- /*nvc0_graph_init_unitplemented_c242(priv);*/
+ nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+ nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+ for (i = 0; oclass->mmio[i]; i++)
+ nvc0_graph_mmio(priv, oclass->mmio[i]);
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+ priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+ priv->tpc_total);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+ }
+
+ if (nv_device(priv)->chipset != 0xd7)
+ nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
+ else
+ nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+
+ nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
nv_wr32(priv, 0x400500, 0x00010001);
+
nv_wr32(priv, 0x400100, 0xffffffff);
nv_wr32(priv, 0x40013c, 0xffffffff);
- nvc0_graph_init_units(priv);
- nvc0_graph_init_gpc_1(priv);
- nvc0_graph_init_rop(priv);
+ nv_wr32(priv, 0x409c24, 0x000f0000);
+ nv_wr32(priv, 0x404000, 0xc0000000);
+ nv_wr32(priv, 0x404600, 0xc0000000);
+ nv_wr32(priv, 0x408030, 0xc0000000);
+ nv_wr32(priv, 0x40601c, 0xc0000000);
+ nv_wr32(priv, 0x404490, 0xc0000000);
+ nv_wr32(priv, 0x406018, 0xc0000000);
+ nv_wr32(priv, 0x405840, 0xc0000000);
+ nv_wr32(priv, 0x405844, 0x00ffffff);
+ nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+ nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+ }
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
nv_wr32(priv, 0x400108, 0xffffffff);
nv_wr32(priv, 0x400138, 0xffffffff);
@@ -943,22 +1066,205 @@ nvc0_graph_init(struct nouveau_object *object)
nv_wr32(priv, 0x400130, 0xffffffff);
nv_wr32(priv, 0x40011c, 0xffffffff);
nv_wr32(priv, 0x400134, 0xffffffff);
+
nv_wr32(priv, 0x400054, 0x34ce3464);
+ return nvc0_graph_init_ctxctl(priv);
+}
- ret = nvc0_graph_init_ctxctl(priv);
+static void
+nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
+{
+ kfree(fuc->data);
+ fuc->data = NULL;
+}
+
+int
+nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
+ struct nvc0_graph_fuc *fuc)
+{
+ struct nouveau_device *device = nv_device(priv);
+ const struct firmware *fw;
+ char f[32];
+ int ret;
+
+ snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
+ ret = request_firmware(&fw, f, &device->pdev->dev);
+ if (ret) {
+ snprintf(f, sizeof(f), "nouveau/%s", fwname);
+ ret = request_firmware(&fw, f, &device->pdev->dev);
+ if (ret) {
+ nv_error(priv, "failed to load %s\n", fwname);
+ return ret;
+ }
+ }
+
+ fuc->size = fw->size;
+ fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+ release_firmware(fw);
+ return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+void
+nvc0_graph_dtor(struct nouveau_object *object)
+{
+ struct nvc0_graph_priv *priv = (void *)object;
+
+ kfree(priv->data);
+
+ nvc0_graph_dtor_fw(&priv->fuc409c);
+ nvc0_graph_dtor_fw(&priv->fuc409d);
+ nvc0_graph_dtor_fw(&priv->fuc41ac);
+ nvc0_graph_dtor_fw(&priv->fuc41ad);
+
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+ nouveau_graph_destroy(&priv->base);
+}
+
+int
+nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *bclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nvc0_graph_oclass *oclass = (void *)bclass;
+ struct nouveau_device *device = nv_device(parent);
+ struct nvc0_graph_priv *priv;
+ int ret, i;
+
+ ret = nouveau_graph_create(parent, engine, bclass,
+ (oclass->fecs.ucode != NULL), &priv);
+ *pobject = nv_object(priv);
if (ret)
return ret;
+ nv_subdev(priv)->unit = 0x18001000;
+ nv_subdev(priv)->intr = nvc0_graph_intr;
+
+ priv->base.units = nvc0_graph_units;
+
+ if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) {
+ nv_info(priv, "using external firmware\n");
+ if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
+ nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
+ nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
+ nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
+ return -EINVAL;
+ priv->firmware = true;
+ }
+
+ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
+ &priv->unk4188b4);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
+ &priv->unk4188b8);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 0x1000; i += 4) {
+ nv_wo32(priv->unk4188b4, i, 0x00000010);
+ nv_wo32(priv->unk4188b8, i, 0x00000010);
+ }
+
+ priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
+ priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f;
+ for (i = 0; i < priv->gpc_nr; i++) {
+ priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
+ priv->tpc_total += priv->tpc_nr[i];
+ }
+
+ /*XXX: these need figuring out... though it might not even matter */
+ switch (nv_device(priv)->chipset) {
+ case 0xc0:
+ if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
+ priv->magic_not_rop_nr = 0x07;
+ } else
+ if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
+ priv->magic_not_rop_nr = 0x05;
+ } else
+ if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
+ priv->magic_not_rop_nr = 0x06;
+ }
+ break;
+ case 0xc3: /* 450, 4/0/0/0, 2 */
+ priv->magic_not_rop_nr = 0x03;
+ break;
+ case 0xc4: /* 460, 3/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x01;
+ break;
+ case 0xc1: /* 2/0/0/0, 1 */
+ priv->magic_not_rop_nr = 0x01;
+ break;
+ case 0xc8: /* 4/4/3/4, 5 */
+ priv->magic_not_rop_nr = 0x06;
+ break;
+ case 0xce: /* 4/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x03;
+ break;
+ case 0xcf: /* 4/0/0/0, 3 */
+ priv->magic_not_rop_nr = 0x03;
+ break;
+ case 0xd7:
+ case 0xd9: /* 1/0/0/0, 1 */
+ priv->magic_not_rop_nr = 0x01;
+ break;
+ }
+
+ nv_engine(priv)->cclass = *oclass->cclass;
+ nv_engine(priv)->sclass = oclass->sclass;
return 0;
}
-struct nouveau_oclass
-nvc0_graph_oclass = {
- .handle = NV_ENGINE(GR, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
+struct nvc0_graph_init *
+nvc0_graph_init_mmio[] = {
+ nvc0_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvc0_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvc0_graph_init_gpc,
+ nvc0_graph_init_tpc,
+ nvc0_graph_init_unk88xx,
+ nvc0_graph_tpc_0,
+ NULL
+};
+
+#include "fuc/hubnvc0.fuc.h"
+
+struct nvc0_graph_ucode
+nvc0_graph_fecs_ucode = {
+ .code.data = nvc0_grhub_code,
+ .code.size = sizeof(nvc0_grhub_code),
+ .data.data = nvc0_grhub_data,
+ .data.size = sizeof(nvc0_grhub_data),
+};
+
+#include "fuc/gpcnvc0.fuc.h"
+
+struct nvc0_graph_ucode
+nvc0_graph_gpccs_ucode = {
+ .code.data = nvc0_grgpc_code,
+ .code.size = sizeof(nvc0_grgpc_code),
+ .data.data = nvc0_grgpc_data,
+ .data.size = sizeof(nvc0_grgpc_data),
+};
+
+struct nouveau_oclass *
+nvc0_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc0),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nvc0_graph_ctor,
.dtor = nvc0_graph_dtor,
.init = nvc0_graph_init,
.fini = _nouveau_graph_fini,
},
-};
+ .cclass = &nvc0_grctx_oclass,
+ .sclass = nvc0_graph_sclass,
+ .mmio = nvc0_graph_init_mmio,
+ .fecs.ucode = &nvc0_graph_fecs_ucode,
+ .gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
index c870dad0f670..ea17a80ad7fc 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
@@ -38,8 +38,8 @@
#include <engine/fifo.h>
#include <engine/graph.h>
-#define GPC_MAX 4
-#define TPC_MAX 32
+#define GPC_MAX 32
+#define TPC_MAX (GPC_MAX * 8)
#define ROP_BCAST(r) (0x408800 + (r))
#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r))
@@ -102,74 +102,187 @@ struct nvc0_graph_chan {
} data[4];
};
-static inline u32
-nvc0_graph_class(void *obj)
-{
- struct nouveau_device *device = nv_device(obj);
-
- switch (device->chipset) {
- case 0xc0:
- case 0xc3:
- case 0xc4:
- case 0xce: /* guess, mmio trace shows only 0x9097 state */
- case 0xcf: /* guess, mmio trace shows only 0x9097 state */
- return 0x9097;
- case 0xc1:
- return 0x9197;
- case 0xc8:
- case 0xd9:
- case 0xd7:
- return 0x9297;
- case 0xe4:
- case 0xe7:
- case 0xe6:
- return 0xa097;
- default:
- return 0;
- }
-}
-
-void nv_icmd(struct nvc0_graph_priv *priv, u32 icmd, u32 data);
-
-static inline void
-nv_mthd(struct nvc0_graph_priv *priv, u32 class, u32 mthd, u32 data)
-{
- nv_wr32(priv, 0x40448c, data);
- nv_wr32(priv, 0x404488, 0x80000000 | (mthd << 14) | class);
-}
+int nvc0_grctx_generate(struct nvc0_graph_priv *);
+
+int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *, u32,
+ struct nouveau_object **);
+void nvc0_graph_context_dtor(struct nouveau_object *);
+
+void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
+
+u64 nvc0_graph_units(struct nouveau_graph *);
+int nvc0_graph_ctor(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, void *data, u32 size,
+ struct nouveau_object **);
+void nvc0_graph_dtor(struct nouveau_object *);
+int nvc0_graph_init(struct nouveau_object *);
+int nve4_graph_init(struct nouveau_object *);
+
+extern struct nouveau_oclass nvc0_graph_sclass[];
+
+extern struct nouveau_oclass nvc8_graph_sclass[];
+
+struct nvc0_graph_init {
+ u32 addr;
+ u8 count;
+ u8 pitch;
+ u32 data;
+};
+
+struct nvc0_graph_mthd {
+ u16 oclass;
+ struct nvc0_graph_init *init;
+};
struct nvc0_grctx {
struct nvc0_graph_priv *priv;
struct nvc0_graph_data *data;
struct nvc0_graph_mmio *mmio;
- struct nouveau_gpuobj *chan;
int buffer_nr;
u64 buffer[4];
u64 addr;
};
+struct nvc0_grctx_oclass {
+ struct nouveau_oclass base;
+ /* main context generation function */
+ void (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *);
+ /* context-specific modify-on-first-load list generation function */
+ void (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *);
+ void (*unkn)(struct nvc0_graph_priv *);
+ /* mmio context data */
+ struct nvc0_graph_init **hub;
+ struct nvc0_graph_init **gpc;
+ /* indirect context data, generated with icmds/mthds */
+ struct nvc0_graph_init *icmd;
+ struct nvc0_graph_mthd *mthd;
+};
+
+struct nvc0_graph_ucode {
+ struct nvc0_graph_fuc code;
+ struct nvc0_graph_fuc data;
+};
+
+extern struct nvc0_graph_ucode nvc0_graph_fecs_ucode;
+extern struct nvc0_graph_ucode nvc0_graph_gpccs_ucode;
+
+struct nvc0_graph_oclass {
+ struct nouveau_oclass base;
+ struct nouveau_oclass **cclass;
+ struct nouveau_oclass *sclass;
+ struct nvc0_graph_init **mmio;
+ struct {
+ struct nvc0_graph_ucode *ucode;
+ } fecs;
+ struct {
+ struct nvc0_graph_ucode *ucode;
+ } gpccs;
+};
+
+void nvc0_graph_mmio(struct nvc0_graph_priv *, struct nvc0_graph_init *);
+void nvc0_graph_icmd(struct nvc0_graph_priv *, struct nvc0_graph_init *);
+void nvc0_graph_mthd(struct nvc0_graph_priv *, struct nvc0_graph_mthd *);
+int nvc0_graph_init_ctxctl(struct nvc0_graph_priv *);
+
+extern struct nvc0_graph_init nvc0_graph_init_regs[];
+extern struct nvc0_graph_init nvc0_graph_init_unk40xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk44xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk78xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk60xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk58xx[];
+extern struct nvc0_graph_init nvc0_graph_init_unk80xx[];
+extern struct nvc0_graph_init nvc0_graph_init_gpc[];
+extern struct nvc0_graph_init nvc0_graph_init_unk88xx[];
+extern struct nvc0_graph_init nvc0_graph_tpc_0[];
+
+extern struct nvc0_graph_init nvc3_graph_init_unk58xx[];
+
+extern struct nvc0_graph_init nvd9_graph_init_unk58xx[];
+extern struct nvc0_graph_init nvd9_graph_init_unk64xx[];
+
+extern struct nvc0_graph_init nve4_graph_init_regs[];
+extern struct nvc0_graph_init nve4_graph_init_unk[];
+extern struct nvc0_graph_init nve4_graph_init_unk88xx[];
+
int nvc0_grctx_generate(struct nvc0_graph_priv *);
-int nvc0_grctx_init(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc0_grctx_data(struct nvc0_grctx *, u32, u32, u32);
-void nvc0_grctx_mmio(struct nvc0_grctx *, u32, u32, u32, u32);
-int nvc0_grctx_fini(struct nvc0_grctx *);
+void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *);
+void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *);
-int nve0_grctx_generate(struct nvc0_graph_priv *);
+extern struct nouveau_oclass *nvc0_grctx_oclass;
+extern struct nvc0_graph_init *nvc0_grctx_init_hub[];
+extern struct nvc0_graph_init nvc0_grctx_init_base[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk40xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk44xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk46xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk47xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk60xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk64xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk78xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_unk80xx[];
+extern struct nvc0_graph_init nvc0_grctx_init_gpc_0[];
+extern struct nvc0_graph_init nvc0_grctx_init_gpc_1[];
+extern struct nvc0_graph_init nvc0_grctx_init_tpc[];
+extern struct nvc0_graph_init nvc0_grctx_init_icmd[];
+extern struct nvc0_graph_init nvd9_grctx_init_icmd[]; //
-#define mmio_data(s,a,p) nvc0_grctx_data(&info, (s), (a), (p))
-#define mmio_list(r,d,s,b) nvc0_grctx_mmio(&info, (r), (d), (s), (b))
+extern struct nvc0_graph_mthd nvc0_grctx_init_mthd[];
+extern struct nvc0_graph_init nvc0_grctx_init_902d[];
+extern struct nvc0_graph_init nvc0_grctx_init_9039[];
+extern struct nvc0_graph_init nvc0_grctx_init_90c0[];
+extern struct nvc0_graph_init nvc0_grctx_init_mthd_magic[];
-void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
-int nvc0_graph_ctor_fw(struct nvc0_graph_priv *, const char *,
- struct nvc0_graph_fuc *);
-void nvc0_graph_dtor(struct nouveau_object *);
-void nvc0_graph_init_fw(struct nvc0_graph_priv *, u32 base,
- struct nvc0_graph_fuc *, struct nvc0_graph_fuc *);
-int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nvc0_graph_context_dtor(struct nouveau_object *);
+void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *);
+extern struct nouveau_oclass *nvc1_grctx_oclass;
+extern struct nvc0_graph_init nvc1_grctx_init_9097[];
+
+extern struct nouveau_oclass *nvc3_grctx_oclass;
+
+extern struct nouveau_oclass *nvc8_grctx_oclass;
+extern struct nvc0_graph_init nvc8_grctx_init_9197[];
+extern struct nvc0_graph_init nvc8_grctx_init_9297[];
+
+extern struct nouveau_oclass *nvd7_grctx_oclass;
+
+extern struct nouveau_oclass *nvd9_grctx_oclass;
+extern struct nvc0_graph_init nvd9_grctx_init_rop[];
+extern struct nvc0_graph_mthd nvd9_grctx_init_mthd[];
+
+void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nve4_grctx_generate_unkn(struct nvc0_graph_priv *);
+extern struct nouveau_oclass *nve4_grctx_oclass;
+extern struct nvc0_graph_init nve4_grctx_init_unk46xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk47xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk58xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk80xx[];
+extern struct nvc0_graph_init nve4_grctx_init_unk90xx[];
+
+extern struct nouveau_oclass *nvf0_grctx_oclass;
+
+#define mmio_data(s,a,p) do { \
+ info->buffer[info->buffer_nr] = round_up(info->addr, (a)); \
+ info->addr = info->buffer[info->buffer_nr++] + (s); \
+ info->data->size = (s); \
+ info->data->align = (a); \
+ info->data->access = (p); \
+ info->data++; \
+} while(0)
-u64 nvc0_graph_units(struct nouveau_graph *);
+#define mmio_list(r,d,s,b) do { \
+ info->mmio->addr = (r); \
+ info->mmio->data = (d); \
+ info->mmio->shift = (s); \
+ info->mmio->buffer = (b); \
+ info->mmio++; \
+ nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0)); \
+} while(0)
#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
new file mode 100644
index 000000000000..bc4a469b86cb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nvc1_graph_sclass[] = {
+ { 0x902d, &nouveau_object_ofuncs },
+ { 0x9039, &nouveau_object_ofuncs },
+ { 0x9097, &nouveau_object_ofuncs },
+ { 0x90c0, &nouveau_object_ofuncs },
+ { 0x9197, &nouveau_object_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nvc1_graph_init_gpc[] = {
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000003 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc1_graph_init_tpc[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x41980c, 2, 0x04, 0x00000000 },
+ { 0x419814, 1, 0x04, 0x00000004 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419880, 1, 0x04, 0x00000002 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0e063818 },
+ { 0x419ecc, 1, 0x04, 0x0e060e06 },
+ { 0x419ed0, 1, 0x04, 0x00003818 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init *
+nvc1_graph_init_mmio[] = {
+ nvc0_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvc3_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvc1_graph_init_gpc,
+ nvc1_graph_init_tpc,
+ nvc0_graph_init_unk88xx,
+ nvc0_graph_tpc_0,
+ NULL
+};
+
+struct nouveau_oclass *
+nvc1_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc1),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nvc0_graph_init,
+ .fini = _nouveau_graph_fini,
+ },
+ .cclass = &nvc1_grctx_oclass,
+ .sclass = nvc1_graph_sclass,
+ .mmio = nvc1_graph_init_mmio,
+ .fecs.ucode = &nvc0_graph_fecs_ucode,
+ .gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c
new file mode 100644
index 000000000000..d44b3b3ee800
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvc0_graph_init
+nvc3_graph_init_unk58xx[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x00002834 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc3_graph_init_tpc[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x41980c, 3, 0x04, 0x00000000 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419880, 1, 0x04, 0x00000002 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0e063818 },
+ { 0x419ecc, 1, 0x04, 0x0e060e06 },
+ { 0x419ed0, 1, 0x04, 0x00003818 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init *
+nvc3_graph_init_mmio[] = {
+ nvc0_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvc3_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvc0_graph_init_gpc,
+ nvc3_graph_init_tpc,
+ nvc0_graph_init_unk88xx,
+ nvc0_graph_tpc_0,
+ NULL
+};
+
+struct nouveau_oclass *
+nvc3_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc3),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nvc0_graph_init,
+ .fini = _nouveau_graph_fini,
+ },
+ .cclass = &nvc3_grctx_oclass,
+ .sclass = nvc0_graph_sclass,
+ .mmio = nvc3_graph_init_mmio,
+ .fecs.ucode = &nvc0_graph_fecs_ucode,
+ .gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
new file mode 100644
index 000000000000..02845e567314
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nouveau_oclass
+nvc8_graph_sclass[] = {
+ { 0x902d, &nouveau_object_ofuncs },
+ { 0x9039, &nouveau_object_ofuncs },
+ { 0x9097, &nouveau_object_ofuncs },
+ { 0x90c0, &nouveau_object_ofuncs },
+ { 0x9197, &nouveau_object_ofuncs },
+ { 0x9297, &nouveau_object_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nvc8_graph_init_gpc[] = {
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x80000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000050 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvc8_graph_init_tpc[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x41980c, 3, 0x04, 0x00000000 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100f02 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x06060618 },
+ { 0x419ed0, 1, 0x04, 0x0eff0e38 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init *
+nvc8_graph_init_mmio[] = {
+ nvc0_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvc0_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvc8_graph_init_gpc,
+ nvc8_graph_init_tpc,
+ nvc0_graph_init_unk88xx,
+ nvc0_graph_tpc_0,
+ NULL
+};
+
+struct nouveau_oclass *
+nvc8_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc8),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nvc0_graph_init,
+ .fini = _nouveau_graph_fini,
+ },
+ .cclass = &nvc8_grctx_oclass,
+ .sclass = nvc8_graph_sclass,
+ .mmio = nvc8_graph_init_mmio,
+ .fecs.ucode = &nvc0_graph_fecs_ucode,
+ .gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
new file mode 100644
index 000000000000..5052d7ab4d72
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+#include "fuc/hubnvd7.fuc.h"
+
+struct nvc0_graph_ucode
+nvd7_graph_fecs_ucode = {
+ .code.data = nvd7_grhub_code,
+ .code.size = sizeof(nvd7_grhub_code),
+ .data.data = nvd7_grhub_data,
+ .data.size = sizeof(nvd7_grhub_data),
+};
+
+#include "fuc/gpcnvd7.fuc.h"
+
+struct nvc0_graph_ucode
+nvd7_graph_gpccs_ucode = {
+ .code.data = nvd7_grgpc_code,
+ .code.size = sizeof(nvd7_grgpc_code),
+ .data.data = nvd7_grgpc_data,
+ .data.size = sizeof(nvd7_grgpc_data),
+};
+
+static struct nvc0_graph_init
+nvd7_graph_init_gpc[] = {
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x4184a4, 2, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c64, 1, 0x04, 0x00000000 },
+ { 0x418c68, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418cb4, 2, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 1, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 2, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000003 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 1, 0x04, 0x00000000 },
+ { 0x418e20, 1, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_graph_init_tpc[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc8 },
+ { 0x419850, 2, 0x04, 0x00000000 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x02001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0e063818 },
+ { 0x419ecc, 1, 0x04, 0x0e060e06 },
+ { 0x419ed0, 1, 0x04, 0x00003818 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd7_graph_init_tpc_0[] = {
+ { 0x40402c, 1, 0x04, 0x00000000 },
+ { 0x4040f0, 1, 0x04, 0x00000000 },
+ { 0x404174, 1, 0x04, 0x00000000 },
+ { 0x503018, 1, 0x04, 0x00000001 },
+ {}
+};
+
+static struct nvc0_graph_init *
+nvd7_graph_init_mmio[] = {
+ nvc0_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvd9_graph_init_unk64xx,
+ nvd9_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvd7_graph_init_gpc,
+ nvd7_graph_init_tpc,
+ nve4_graph_init_unk,
+ nvc0_graph_init_unk88xx,
+ nvd7_graph_init_tpc_0,
+ NULL
+};
+
+struct nouveau_oclass *
+nvd7_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xd7),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nvc0_graph_init,
+ .fini = _nouveau_graph_fini,
+ },
+ .cclass = &nvd7_grctx_oclass,
+ .sclass = nvc8_graph_sclass,
+ .mmio = nvd7_graph_init_mmio,
+ .fecs.ucode = &nvd7_graph_fecs_ucode,
+ .gpccs.ucode = &nvd7_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
new file mode 100644
index 000000000000..652098e0df3f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvc0_graph_init
+nvd9_graph_init_unk64xx[] = {
+ { 0x4064f0, 3, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nvd9_graph_init_unk58xx[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x00002834 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 1, 0x04, 0x00000000 },
+ { 0x40592c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd9_graph_init_gpc[] = {
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x4184a4, 2, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c64, 1, 0x04, 0x00000000 },
+ { 0x418c68, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418cb4, 2, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 1, 0x04, 0x00000000 },
+ { 0x418d2c, 1, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 2, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000003 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 1, 0x04, 0x00000000 },
+ { 0x418e20, 1, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvd9_graph_init_tpc[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419810, 1, 0x04, 0x00000000 },
+ { 0x419814, 1, 0x04, 0x00000004 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x0000a918 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419880, 1, 0x04, 0x00000002 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ { 0x419bf8, 1, 0x04, 0x00000000 },
+ { 0x419bfc, 1, 0x04, 0x00000000 },
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ { 0x419d48, 1, 0x04, 0x00000000 },
+ { 0x419d4c, 1, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x02001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0e063818 },
+ { 0x419ecc, 1, 0x04, 0x0e060e06 },
+ { 0x419ed0, 1, 0x04, 0x00003818 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init *
+nvd9_graph_init_mmio[] = {
+ nvc0_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvd9_graph_init_unk64xx,
+ nvd9_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvd9_graph_init_gpc,
+ nvd9_graph_init_tpc,
+ nvc0_graph_init_unk88xx,
+ nvc0_graph_tpc_0,
+ NULL
+};
+
+struct nouveau_oclass *
+nvd9_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xd9),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nvc0_graph_init,
+ .fini = _nouveau_graph_fini,
+ },
+ .cclass = &nvd9_grctx_oclass,
+ .sclass = nvc8_graph_sclass,
+ .mmio = nvd9_graph_init_mmio,
+ .fecs.ucode = &nvc0_graph_fecs_ucode,
+ .gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
deleted file mode 100644
index 678c16f63055..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nve0.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-#include "fuc/hubnve0.fuc.h"
-#include "fuc/gpcnve0.fuc.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0xa040, &nouveau_object_ofuncs },
- { 0xa097, &nouveau_object_ofuncs },
- { 0xa0c0, &nouveau_object_ofuncs },
- { 0xa0b5, &nouveau_object_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-nve0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
-{
- u32 ustat = nv_rd32(priv, 0x409c18);
-
- if (ustat & 0x00000001)
- nv_error(priv, "CTXCTRL ucode error\n");
- if (ustat & 0x00080000)
- nv_error(priv, "CTXCTRL watchdog timeout\n");
- if (ustat & ~0x00080001)
- nv_error(priv, "CTXCTRL 0x%08x\n", ustat);
-
- nvc0_graph_ctxctl_debug(priv);
- nv_wr32(priv, 0x409c20, ustat);
-}
-
-static const struct nouveau_enum nve0_mp_warp_error[] = {
- { 0x00, "NO_ERROR" },
- { 0x01, "STACK_MISMATCH" },
- { 0x05, "MISALIGNED_PC" },
- { 0x08, "MISALIGNED_GPR" },
- { 0x09, "INVALID_OPCODE" },
- { 0x0d, "GPR_OUT_OF_BOUNDS" },
- { 0x0e, "MEM_OUT_OF_BOUNDS" },
- { 0x0f, "UNALIGNED_MEM_ACCESS" },
- { 0x11, "INVALID_PARAM" },
- {}
-};
-
-static const struct nouveau_enum nve0_mp_global_error[] = {
- { 2, "MULTIPLE_WARP_ERRORS" },
- { 3, "OUT_OF_STACK_SPACE" },
- {}
-};
-
-static const struct nouveau_enum nve0_gpc_rop_error[] = {
- { 1, "RT_PITCH_OVERRUN" },
- { 4, "RT_WIDTH_OVERRUN" },
- { 5, "RT_HEIGHT_OVERRUN" },
- { 7, "ZETA_STORAGE_TYPE_MISMATCH" },
- { 8, "RT_STORAGE_TYPE_MISMATCH" },
- { 10, "RT_LINEAR_MISMATCH" },
- {}
-};
-
-static const struct nouveau_enum nve0_sked_error[] = {
- { 7, "CONSTANT_BUFFER_SIZE" },
- { 9, "LOCAL_MEMORY_SIZE_POS" },
- { 10, "LOCAL_MEMORY_SIZE_NEG" },
- { 11, "WARP_CSTACK_SIZE" },
- { 12, "TOTAL_TEMP_SIZE" },
- { 13, "REGISTER_COUNT" },
- { 18, "TOTAL_THREADS" },
- { 20, "PROGRAM_OFFSET" },
- { 21, "SHARED_MEMORY_SIZE" },
- { 25, "SHARED_CONFIG_TOO_SMALL" },
- { 26, "TOTAL_REGISTER_COUNT" },
- {}
-};
-
-static void
-nve0_graph_mp_trap(struct nvc0_graph_priv *priv, int gpc, int tp)
-{
- int i;
- u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x648));
- u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x650));
-
- nv_error(priv, "GPC%i/TP%i/MP trap:", gpc, tp);
-
- for (i = 0; i <= 31; ++i) {
- if (!(gerr & (1 << i)))
- continue;
- pr_cont(" ");
- nouveau_enum_print(nve0_mp_global_error, i);
- }
- if (werr) {
- pr_cont(" ");
- nouveau_enum_print(nve0_mp_warp_error, werr & 0xffff);
- }
- pr_cont("\n");
-
- /* disable MP trap to avoid spam */
- nv_mask(priv, TPC_UNIT(gpc, tp, 0x50c), 0x2, 0x0);
-
- /* TODO: figure out how to resume after an MP trap */
-}
-
-static void
-nve0_graph_tp_trap(struct nvc0_graph_priv *priv, int gpc, int tp)
-{
- u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x508));
-
- if (stat & 0x1) {
- u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x224));
- nv_error(priv, "GPC%i/TP%i/TEX trap: %08x\n",
- gpc, tp, trap);
-
- nv_wr32(priv, TPC_UNIT(gpc, tp, 0x224), 0xc0000000);
- stat &= ~0x1;
- }
-
- if (stat & 0x2) {
- nve0_graph_mp_trap(priv, gpc, tp);
- stat &= ~0x2;
- }
-
- if (stat & 0x4) {
- u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x084));
- nv_error(priv, "GPC%i/TP%i/POLY trap: %08x\n",
- gpc, tp, trap);
-
- nv_wr32(priv, TPC_UNIT(gpc, tp, 0x084), 0xc0000000);
- stat &= ~0x4;
- }
-
- if (stat & 0x8) {
- u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tp, 0x48c));
- nv_error(priv, "GPC%i/TP%i/L1C trap: %08x\n",
- gpc, tp, trap);
-
- nv_wr32(priv, TPC_UNIT(gpc, tp, 0x48c), 0xc0000000);
- stat &= ~0x8;
- }
-
- if (stat) {
- nv_error(priv, "GPC%i/TP%i: unknown stat %08x\n",
- gpc, tp, stat);
- }
-}
-
-static void
-nve0_graph_gpc_trap(struct nvc0_graph_priv *priv)
-{
- const u32 mask = nv_rd32(priv, 0x400118);
- int gpc;
-
- for (gpc = 0; gpc < 4; ++gpc) {
- u32 stat;
- int tp;
-
- if (!(mask & (1 << gpc)))
- continue;
- stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90));
-
- if (stat & 0x0001) {
- u32 trap[4];
- int i;
-
- trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
- trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
- trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
- trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
-
- nv_error(priv, "GPC%i/PROP trap:", gpc);
- for (i = 0; i <= 29; ++i) {
- if (!(trap[0] & (1 << i)))
- continue;
- pr_cont(" ");
- nouveau_enum_print(nve0_gpc_rop_error, i);
- }
- pr_cont("\n");
-
- nv_error(priv, "x = %u, y = %u, "
- "format = %x, storage type = %x\n",
- trap[1] & 0xffff,
- trap[1] >> 16,
- (trap[2] >> 8) & 0x3f,
- trap[3] & 0xff);
-
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- stat &= ~0x0001;
- }
-
- if (stat & 0x0002) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
- nv_error(priv, "GPC%i/ZCULL trap: %08x\n", gpc,
- trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- stat &= ~0x0002;
- }
-
- if (stat & 0x0004) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
- nv_error(priv, "GPC%i/CCACHE trap: %08x\n", gpc,
- trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- stat &= ~0x0004;
- }
-
- if (stat & 0x0008) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
- nv_error(priv, "GPC%i/ESETUP trap %08x\n", gpc,
- trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- stat &= ~0x0008;
- }
-
- for (tp = 0; tp < 8; ++tp) {
- if (stat & (1 << (16 + tp)))
- nve0_graph_tp_trap(priv, gpc, tp);
- }
- stat &= ~0xff0000;
-
- if (stat) {
- nv_error(priv, "GPC%i: unknown stat %08x\n",
- gpc, stat);
- }
- }
-}
-
-
-static void
-nve0_graph_trap_isr(struct nvc0_graph_priv *priv, int chid, u64 inst,
- struct nouveau_object *engctx)
-{
- u32 trap = nv_rd32(priv, 0x400108);
- int i;
- int rop;
-
- if (trap & 0x00000001) {
- u32 stat = nv_rd32(priv, 0x404000);
- nv_error(priv, "DISPATCH ch %d [0x%010llx %s] 0x%08x\n",
- chid, inst, nouveau_client_name(engctx), stat);
- nv_wr32(priv, 0x404000, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000001);
- trap &= ~0x00000001;
- }
-
- if (trap & 0x00000010) {
- u32 stat = nv_rd32(priv, 0x405840);
- nv_error(priv, "SHADER ch %d [0x%010llx %s] 0x%08x\n",
- chid, inst, nouveau_client_name(engctx), stat);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000010);
- trap &= ~0x00000010;
- }
-
- if (trap & 0x00000100) {
- u32 stat = nv_rd32(priv, 0x407020);
- nv_error(priv, "SKED ch %d [0x%010llx %s]:",
- chid, inst, nouveau_client_name(engctx));
-
- for (i = 0; i <= 29; ++i) {
- if (!(stat & (1 << i)))
- continue;
- pr_cont(" ");
- nouveau_enum_print(nve0_sked_error, i);
- }
- pr_cont("\n");
-
- if (stat & 0x3fffffff)
- nv_wr32(priv, 0x407020, 0x40000000);
- nv_wr32(priv, 0x400108, 0x00000100);
- trap &= ~0x00000100;
- }
-
- if (trap & 0x01000000) {
- nv_error(priv, "GPC ch %d [0x%010llx %s]:\n",
- chid, inst, nouveau_client_name(engctx));
- nve0_graph_gpc_trap(priv);
- trap &= ~0x01000000;
- }
-
- if (trap & 0x02000000) {
- for (rop = 0; rop < priv->rop_nr; rop++) {
- u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
- u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
- nv_error(priv,
- "ROP%d ch %d [0x%010llx %s] 0x%08x 0x%08x\n",
- rop, chid, inst, nouveau_client_name(engctx),
- statz, statc);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
- }
- nv_wr32(priv, 0x400108, 0x02000000);
- trap &= ~0x02000000;
- }
-
- if (trap) {
- nv_error(priv, "TRAP ch %d [0x%010llx %s] 0x%08x\n",
- chid, inst, nouveau_client_name(engctx), trap);
- nv_wr32(priv, 0x400108, trap);
- }
-}
-
-static void
-nve0_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nouveau_handle *handle;
- struct nvc0_graph_priv *priv = (void *)subdev;
- u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff;
- u32 stat = nv_rd32(priv, 0x400100);
- u32 addr = nv_rd32(priv, 0x400704);
- u32 mthd = (addr & 0x00003ffc);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 data = nv_rd32(priv, 0x400708);
- u32 code = nv_rd32(priv, 0x400110);
- u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & 0x00000010) {
- handle = nouveau_handle_get_class(engctx, class);
- if (!handle || nv_call(handle->object, mthd, data)) {
- nv_error(priv,
- "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst, nouveau_client_name(engctx), subc,
- class, mthd, data);
- }
- nouveau_handle_put(handle);
- nv_wr32(priv, 0x400100, 0x00000010);
- stat &= ~0x00000010;
- }
-
- if (stat & 0x00000020) {
- nv_error(priv,
- "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst, nouveau_client_name(engctx), subc, class,
- mthd, data);
- nv_wr32(priv, 0x400100, 0x00000020);
- stat &= ~0x00000020;
- }
-
- if (stat & 0x00100000) {
- nv_error(priv, "DATA_ERROR [");
- nouveau_enum_print(nv50_data_error_names, code);
- pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst, nouveau_client_name(engctx), subc, class,
- mthd, data);
- nv_wr32(priv, 0x400100, 0x00100000);
- stat &= ~0x00100000;
- }
-
- if (stat & 0x00200000) {
- nve0_graph_trap_isr(priv, chid, inst, engctx);
- nv_wr32(priv, 0x400100, 0x00200000);
- stat &= ~0x00200000;
- }
-
- if (stat & 0x00080000) {
- nve0_graph_ctxctl_isr(priv);
- nv_wr32(priv, 0x400100, 0x00080000);
- stat &= ~0x00080000;
- }
-
- if (stat) {
- nv_error(priv, "unknown stat 0x%08x\n", stat);
- nv_wr32(priv, 0x400100, stat);
- }
-
- nv_wr32(priv, 0x400500, 0x00010001);
- nouveau_engctx_put(engctx);
-}
-
-static int
-nve0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nvc0_graph_priv *priv;
- int ret, i;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x18001000;
- nv_subdev(priv)->intr = nve0_graph_intr;
- nv_engine(priv)->cclass = &nve0_graph_cclass;
- nv_engine(priv)->sclass = nve0_graph_sclass;
-
- priv->base.units = nvc0_graph_units;
-
- if (nouveau_boolopt(device->cfgopt, "NvGrUseFW", false)) {
- nv_info(priv, "using external firmware\n");
- if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
- nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
- nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
- nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
- return -EINVAL;
- priv->firmware = true;
- }
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
- &priv->unk4188b4);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
- &priv->unk4188b8);
- if (ret)
- return ret;
-
- for (i = 0; i < 0x1000; i += 4) {
- nv_wo32(priv->unk4188b4, i, 0x00000010);
- nv_wo32(priv->unk4188b8, i, 0x00000010);
- }
-
- priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f;
- priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
- for (i = 0; i < priv->gpc_nr; i++) {
- priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
- priv->tpc_total += priv->tpc_nr[i];
- }
-
- switch (nv_device(priv)->chipset) {
- case 0xe4:
- if (priv->tpc_total == 8)
- priv->magic_not_rop_nr = 3;
- else
- if (priv->tpc_total == 7)
- priv->magic_not_rop_nr = 1;
- break;
- case 0xe7:
- case 0xe6:
- priv->magic_not_rop_nr = 1;
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static void
-nve0_graph_init_obj418880(struct nvc0_graph_priv *priv)
-{
- int i;
-
- nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
- nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-}
-
-static void
-nve0_graph_init_regs(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x400080, 0x003083c2);
- nv_wr32(priv, 0x400088, 0x0001ffe7);
- nv_wr32(priv, 0x40008c, 0x00000000);
- nv_wr32(priv, 0x400090, 0x00000030);
- nv_wr32(priv, 0x40013c, 0x003901f7);
- nv_wr32(priv, 0x400140, 0x00000100);
- nv_wr32(priv, 0x400144, 0x00000000);
- nv_wr32(priv, 0x400148, 0x00000110);
- nv_wr32(priv, 0x400138, 0x00000000);
- nv_wr32(priv, 0x400130, 0x00000000);
- nv_wr32(priv, 0x400134, 0x00000000);
- nv_wr32(priv, 0x400124, 0x00000002);
-}
-
-static void
-nve0_graph_init_units(struct nvc0_graph_priv *priv)
-{
- nv_wr32(priv, 0x409ffc, 0x00000000);
- nv_wr32(priv, 0x409c14, 0x00003e3e);
- nv_wr32(priv, 0x409c24, 0x000f0000);
-
- nv_wr32(priv, 0x404000, 0xc0000000);
- nv_wr32(priv, 0x404600, 0xc0000000);
- nv_wr32(priv, 0x408030, 0xc0000000);
- nv_wr32(priv, 0x404490, 0xc0000000);
- nv_wr32(priv, 0x406018, 0xc0000000);
- nv_wr32(priv, 0x407020, 0xc0000000);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x405844, 0x00ffffff);
-
- nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
- nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-
-}
-
-static void
-nve0_graph_init_gpc_0(struct nvc0_graph_priv *priv)
-{
- const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
- u32 data[TPC_MAX / 8];
- u8 tpcnr[GPC_MAX];
- int i, gpc, tpc;
-
- nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
-
- memset(data, 0x00, sizeof(data));
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- data[i / 8] |= tpc << ((i % 8) * 4);
- }
-
- nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
- nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
- nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
- nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
- priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
- }
-
- nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
- nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-}
-
-static void
-nve0_graph_init_gpc_1(struct nvc0_graph_priv *priv)
-{
- int gpc, tpc;
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
- }
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
- }
-}
-
-static void
-nve0_graph_init_rop(struct nvc0_graph_priv *priv)
-{
- int rop;
-
- for (rop = 0; rop < priv->rop_nr; rop++) {
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
- nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
- }
-}
-
-static int
-nve0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
-{
- u32 r000260;
- int i;
-
- if (priv->firmware) {
- /* load fuc microcode */
- r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
- nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c, &priv->fuc409d);
- nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
- nv_wr32(priv, 0x000260, r000260);
-
- /* start both of them running */
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x41a10c, 0x00000000);
- nv_wr32(priv, 0x40910c, 0x00000000);
- nv_wr32(priv, 0x41a100, 0x00000002);
- nv_wr32(priv, 0x409100, 0x00000002);
- if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
- nv_error(priv, "0x409800 wait failed\n");
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x7fffffff);
- nv_wr32(priv, 0x409504, 0x00000021);
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x00000000);
- nv_wr32(priv, 0x409504, 0x00000010);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x10 timeout\n");
- return -EBUSY;
- }
- priv->size = nv_rd32(priv, 0x409800);
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x00000000);
- nv_wr32(priv, 0x409504, 0x00000016);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x16 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x00000000);
- nv_wr32(priv, 0x409504, 0x00000025);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x25 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409800, 0x00000000);
- nv_wr32(priv, 0x409500, 0x00000001);
- nv_wr32(priv, 0x409504, 0x00000030);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x30 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409810, 0xb00095c8);
- nv_wr32(priv, 0x409800, 0x00000000);
- nv_wr32(priv, 0x409500, 0x00000001);
- nv_wr32(priv, 0x409504, 0x00000031);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x31 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409810, 0x00080420);
- nv_wr32(priv, 0x409800, 0x00000000);
- nv_wr32(priv, 0x409500, 0x00000001);
- nv_wr32(priv, 0x409504, 0x00000032);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x32 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409614, 0x00000070);
- nv_wr32(priv, 0x409614, 0x00000770);
- nv_wr32(priv, 0x40802c, 0x00000001);
-
- if (priv->data == NULL) {
- int ret = nve0_grctx_generate(priv);
- if (ret) {
- nv_error(priv, "failed to construct context\n");
- return ret;
- }
- }
-
- return 0;
- }
-
- /* load HUB microcode */
- r000260 = nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x4091c0, 0x01000000);
- for (i = 0; i < sizeof(nve0_grhub_data) / 4; i++)
- nv_wr32(priv, 0x4091c4, nve0_grhub_data[i]);
-
- nv_wr32(priv, 0x409180, 0x01000000);
- for (i = 0; i < sizeof(nve0_grhub_code) / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wr32(priv, 0x409188, i >> 6);
- nv_wr32(priv, 0x409184, nve0_grhub_code[i]);
- }
-
- /* load GPC microcode */
- nv_wr32(priv, 0x41a1c0, 0x01000000);
- for (i = 0; i < sizeof(nve0_grgpc_data) / 4; i++)
- nv_wr32(priv, 0x41a1c4, nve0_grgpc_data[i]);
-
- nv_wr32(priv, 0x41a180, 0x01000000);
- for (i = 0; i < sizeof(nve0_grgpc_code) / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wr32(priv, 0x41a188, i >> 6);
- nv_wr32(priv, 0x41a184, nve0_grgpc_code[i]);
- }
- nv_wr32(priv, 0x000260, r000260);
-
- /* start HUB ucode running, it'll init the GPCs */
- nv_wr32(priv, 0x409800, nv_device(priv)->chipset);
- nv_wr32(priv, 0x40910c, 0x00000000);
- nv_wr32(priv, 0x409100, 0x00000002);
- if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
- nv_error(priv, "HUB_INIT timed out\n");
- nvc0_graph_ctxctl_debug(priv);
- return -EBUSY;
- }
-
- priv->size = nv_rd32(priv, 0x409804);
- if (priv->data == NULL) {
- int ret = nve0_grctx_generate(priv);
- if (ret) {
- nv_error(priv, "failed to construct context\n");
- return ret;
- }
- }
-
- return 0;
-}
-
-static int
-nve0_graph_init(struct nouveau_object *object)
-{
- struct nvc0_graph_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nve0_graph_init_obj418880(priv);
- nve0_graph_init_regs(priv);
- nve0_graph_init_gpc_0(priv);
-
- nv_wr32(priv, 0x400500, 0x00010001);
- nv_wr32(priv, 0x400100, 0xffffffff);
- nv_wr32(priv, 0x40013c, 0xffffffff);
-
- nve0_graph_init_units(priv);
- nve0_graph_init_gpc_1(priv);
- nve0_graph_init_rop(priv);
-
- nv_wr32(priv, 0x400108, 0xffffffff);
- nv_wr32(priv, 0x400138, 0xffffffff);
- nv_wr32(priv, 0x400118, 0xffffffff);
- nv_wr32(priv, 0x400130, 0xffffffff);
- nv_wr32(priv, 0x40011c, 0xffffffff);
- nv_wr32(priv, 0x400134, 0xffffffff);
- nv_wr32(priv, 0x400054, 0x34ce3464);
-
- ret = nve0_graph_init_ctxctl(priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass
-nve0_graph_oclass = {
- .handle = NV_ENGINE(GR, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nve0_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
new file mode 100644
index 000000000000..05ec09c88517
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nve4_graph_sclass[] = {
+ { 0x902d, &nouveau_object_ofuncs },
+ { 0xa040, &nouveau_object_ofuncs },
+ { 0xa097, &nouveau_object_ofuncs },
+ { 0xa0c0, &nouveau_object_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvc0_graph_init
+nve4_graph_init_regs[] = {
+ { 0x400080, 1, 0x04, 0x003083c2 },
+ { 0x400088, 1, 0x04, 0x0001ffe7 },
+ { 0x40008c, 1, 0x04, 0x00000000 },
+ { 0x400090, 1, 0x04, 0x00000030 },
+ { 0x40013c, 1, 0x04, 0x003901f7 },
+ { 0x400140, 1, 0x04, 0x00000100 },
+ { 0x400144, 1, 0x04, 0x00000000 },
+ { 0x400148, 1, 0x04, 0x00000110 },
+ { 0x400138, 1, 0x04, 0x00000000 },
+ { 0x400130, 2, 0x04, 0x00000000 },
+ { 0x400124, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_unk58xx[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x0000ff34 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 1, 0x04, 0x00000000 },
+ { 0x40592c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_unk70xx[] = {
+ { 0x407010, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_graph_init_unk5bxx[] = {
+ { 0x405b50, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_gpc[] = {
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x4184a4, 2, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c64, 1, 0x04, 0x00000000 },
+ { 0x418c68, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418cb4, 2, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 1, 0x04, 0x00000000 },
+ { 0x418d2c, 1, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 2, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000060 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 1, 0x04, 0x00000000 },
+ { 0x418e20, 1, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nve4_graph_init_tpc[] = {
+ { 0x419d0c, 1, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x419850, 1, 0x04, 0x00000004 },
+ { 0x419854, 2, 0x04, 0x00000000 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x01000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00b08bea },
+ { 0x419c84, 1, 0x04, 0x00010384 },
+ { 0x419cbc, 1, 0x04, 0x28137646 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x00020232 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ee4, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00000000 },
+ { 0x419eb4, 1, 0x04, 0x00000000 },
+ { 0x419eb8, 3, 0x04, 0x00000000 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f74, 1, 0x04, 0x00000555 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_graph_init_unk[] = {
+ { 0x41be04, 1, 0x04, 0x00000000 },
+ { 0x41be08, 1, 0x04, 0x00000004 },
+ { 0x41be0c, 1, 0x04, 0x00000000 },
+ { 0x41be10, 1, 0x04, 0x003b8bc7 },
+ { 0x41be14, 2, 0x04, 0x00000000 },
+ { 0x41bfd4, 1, 0x04, 0x00800000 },
+ { 0x41bfdc, 1, 0x04, 0x00000000 },
+ { 0x41bff8, 1, 0x04, 0x00000000 },
+ { 0x41bffc, 1, 0x04, 0x00000000 },
+ { 0x41becc, 1, 0x04, 0x00000000 },
+ { 0x41bee8, 1, 0x04, 0x00000000 },
+ { 0x41beec, 1, 0x04, 0x00000000 },
+ {}
+};
+
+struct nvc0_graph_init
+nve4_graph_init_unk88xx[] = {
+ { 0x40880c, 1, 0x04, 0x00000000 },
+ { 0x408850, 1, 0x04, 0x00000004 },
+ { 0x408910, 9, 0x04, 0x00000000 },
+ { 0x408950, 1, 0x04, 0x00000000 },
+ { 0x408954, 1, 0x04, 0x0000ffff },
+ { 0x408958, 1, 0x04, 0x00000034 },
+ { 0x408984, 1, 0x04, 0x00000000 },
+ { 0x408988, 1, 0x04, 0x08040201 },
+ { 0x40898c, 1, 0x04, 0x80402010 },
+ {}
+};
+
+int
+nve4_graph_init(struct nouveau_object *object)
+{
+ struct nvc0_graph_oclass *oclass = (void *)object->oclass;
+ struct nvc0_graph_priv *priv = (void *)object;
+ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+ u32 data[TPC_MAX / 8] = {};
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc, rop;
+ int ret, i;
+
+ ret = nouveau_graph_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+ nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+ for (i = 0; oclass->mmio[i]; i++)
+ nvc0_graph_mmio(priv, oclass->mmio[i]);
+
+ nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+ memset(data, 0x00, sizeof(data));
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+ priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+ priv->tpc_total);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+ nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+ nv_wr32(priv, 0x400500, 0x00010001);
+
+ nv_wr32(priv, 0x400100, 0xffffffff);
+ nv_wr32(priv, 0x40013c, 0xffffffff);
+
+ nv_wr32(priv, 0x409ffc, 0x00000000);
+ nv_wr32(priv, 0x409c14, 0x00003e3e);
+ nv_wr32(priv, 0x409c24, 0x000f0001);
+ nv_wr32(priv, 0x404000, 0xc0000000);
+ nv_wr32(priv, 0x404600, 0xc0000000);
+ nv_wr32(priv, 0x408030, 0xc0000000);
+ nv_wr32(priv, 0x404490, 0xc0000000);
+ nv_wr32(priv, 0x406018, 0xc0000000);
+ nv_wr32(priv, 0x407020, 0x40000000);
+ nv_wr32(priv, 0x405840, 0xc0000000);
+ nv_wr32(priv, 0x405844, 0x00ffffff);
+ nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+ nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+ }
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+
+ nv_wr32(priv, 0x400108, 0xffffffff);
+ nv_wr32(priv, 0x400138, 0xffffffff);
+ nv_wr32(priv, 0x400118, 0xffffffff);
+ nv_wr32(priv, 0x400130, 0xffffffff);
+ nv_wr32(priv, 0x40011c, 0xffffffff);
+ nv_wr32(priv, 0x400134, 0xffffffff);
+
+ nv_wr32(priv, 0x400054, 0x34ce3464);
+ return nvc0_graph_init_ctxctl(priv);
+}
+
+static struct nvc0_graph_init *
+nve4_graph_init_mmio[] = {
+ nve4_graph_init_regs,
+ nvc0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvd9_graph_init_unk64xx,
+ nve4_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nve4_graph_init_unk70xx,
+ nve4_graph_init_unk5bxx,
+ nve4_graph_init_gpc,
+ nve4_graph_init_tpc,
+ nve4_graph_init_unk,
+ nve4_graph_init_unk88xx,
+ NULL
+};
+
+#include "fuc/hubnve0.fuc.h"
+
+static struct nvc0_graph_ucode
+nve4_graph_fecs_ucode = {
+ .code.data = nve0_grhub_code,
+ .code.size = sizeof(nve0_grhub_code),
+ .data.data = nve0_grhub_data,
+ .data.size = sizeof(nve0_grhub_data),
+};
+
+#include "fuc/gpcnve0.fuc.h"
+
+static struct nvc0_graph_ucode
+nve4_graph_gpccs_ucode = {
+ .code.data = nve0_grgpc_code,
+ .code.size = sizeof(nve0_grgpc_code),
+ .data.data = nve0_grgpc_data,
+ .data.size = sizeof(nve0_grgpc_data),
+};
+
+struct nouveau_oclass *
+nve4_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xe4),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nve4_graph_init,
+ .fini = _nouveau_graph_fini,
+ },
+ .cclass = &nve4_grctx_oclass,
+ .sclass = nve4_graph_sclass,
+ .mmio = nve4_graph_init_mmio,
+ .fecs.ucode = &nve4_graph_fecs_ucode,
+ .gpccs.ucode = &nve4_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
new file mode 100644
index 000000000000..2f0ac7832234
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nvf0_graph_sclass[] = {
+ { 0x902d, &nouveau_object_ofuncs },
+ { 0xa140, &nouveau_object_ofuncs },
+ { 0xa197, &nouveau_object_ofuncs },
+ { 0xa1c0, &nouveau_object_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk40xx[] = {
+ { 0x40415c, 1, 0x04, 0x00000000 },
+ { 0x404170, 1, 0x04, 0x00000000 },
+ { 0x4041b4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk58xx[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x0000ff00 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 1, 0x04, 0x00000000 },
+ { 0x40592c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk70xx[] = {
+ { 0x407010, 1, 0x04, 0x00000000 },
+ { 0x407040, 1, 0x04, 0x80440424 },
+ { 0x407048, 1, 0x04, 0x0000000a },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_unk5bxx[] = {
+ { 0x405b44, 1, 0x04, 0x00000000 },
+ { 0x405b50, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_gpc[] = {
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ { 0x4184a4, 2, 0x04, 0x00000000 },
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ { 0x418814, 3, 0x04, 0x00000000 },
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c64, 1, 0x04, 0x00000000 },
+ { 0x418c68, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418cb4, 2, 0x04, 0x00000000 },
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 1, 0x04, 0x00000000 },
+ { 0x418d2c, 1, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000400 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 1, 0x04, 0x00000000 },
+ { 0x418f24, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000000 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 2, 0x04, 0x00000000 },
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static struct nvc0_graph_init
+nvf0_graph_init_tpc[] = {
+ { 0x419d0c, 1, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419aec, 1, 0x04, 0x00000000 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ { 0x419aa8, 2, 0x04, 0x00000000 },
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x419850, 1, 0x04, 0x00000004 },
+ { 0x419854, 2, 0x04, 0x00000000 },
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x01000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00b08bea },
+ { 0x419c84, 1, 0x04, 0x00010384 },
+ { 0x419cbc, 1, 0x04, 0x281b3646 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x00020230 },
+ { 0x419ccc, 2, 0x04, 0x00000000 },
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ { 0x419e00, 1, 0x04, 0x00000080 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ee4, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00000000 },
+ { 0x419eb4, 1, 0x04, 0x00000000 },
+ { 0x419ebc, 2, 0x04, 0x00000000 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419ed0, 1, 0x04, 0x00003234 },
+ { 0x419f74, 1, 0x04, 0x00015555 },
+ { 0x419f80, 4, 0x04, 0x00000000 },
+ {}
+};
+
+static int
+nvf0_graph_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nvc0_graph_priv *priv = (void *)object;
+ static const struct {
+ u32 addr;
+ u32 data;
+ } magic[] = {
+ { 0x020520, 0xfffffffc },
+ { 0x020524, 0xfffffffe },
+ { 0x020524, 0xfffffffc },
+ { 0x020524, 0xfffffff8 },
+ { 0x020524, 0xffffffe0 },
+ { 0x020530, 0xfffffffe },
+ { 0x02052c, 0xfffffffa },
+ { 0x02052c, 0xfffffff0 },
+ { 0x02052c, 0xffffffc0 },
+ { 0x02052c, 0xffffff00 },
+ { 0x02052c, 0xfffffc00 },
+ { 0x02052c, 0xfffcfc00 },
+ { 0x02052c, 0xfff0fc00 },
+ { 0x02052c, 0xff80fc00 },
+ { 0x020528, 0xfffffffe },
+ { 0x020528, 0xfffffffc },
+ };
+ int i;
+
+ nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+ nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+ for (i = 0; i < ARRAY_SIZE(magic); i++) {
+ nv_wr32(priv, magic[i].addr, magic[i].data);
+ nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+ }
+
+ return nouveau_graph_fini(&priv->base, suspend);
+}
+
+static struct nvc0_graph_init *
+nvf0_graph_init_mmio[] = {
+ nve4_graph_init_regs,
+ nvf0_graph_init_unk40xx,
+ nvc0_graph_init_unk44xx,
+ nvc0_graph_init_unk78xx,
+ nvc0_graph_init_unk60xx,
+ nvd9_graph_init_unk64xx,
+ nvf0_graph_init_unk58xx,
+ nvc0_graph_init_unk80xx,
+ nvf0_graph_init_unk70xx,
+ nvf0_graph_init_unk5bxx,
+ nvf0_graph_init_gpc,
+ nvf0_graph_init_tpc,
+ nve4_graph_init_unk,
+ nve4_graph_init_unk88xx,
+ NULL
+};
+
+#include "fuc/hubnvf0.fuc.h"
+
+static struct nvc0_graph_ucode
+nvf0_graph_fecs_ucode = {
+ .code.data = nvf0_grhub_code,
+ .code.size = sizeof(nvf0_grhub_code),
+ .data.data = nvf0_grhub_data,
+ .data.size = sizeof(nvf0_grhub_data),
+};
+
+#include "fuc/gpcnvf0.fuc.h"
+
+static struct nvc0_graph_ucode
+nvf0_graph_gpccs_ucode = {
+ .code.data = nvf0_grgpc_code,
+ .code.size = sizeof(nvf0_grgpc_code),
+ .data.data = nvf0_grgpc_data,
+ .data.size = sizeof(nvf0_grgpc_data),
+};
+
+struct nouveau_oclass *
+nvf0_graph_oclass = &(struct nvc0_graph_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xf0),
+ .base.ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_graph_ctor,
+ .dtor = nvc0_graph_dtor,
+ .init = nve4_graph_init,
+ .fini = nvf0_graph_fini,
+ },
+ .cclass = &nvf0_grctx_oclass,
+ .sclass = nvf0_graph_sclass,
+ .mmio = nvf0_graph_init_mmio,
+ .fecs.ucode = 0 ? &nvf0_graph_fecs_ucode : NULL,
+ .gpccs.ucode = &nvf0_graph_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
index bc7d12b30fc1..37a2bd9e8078 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
@@ -125,13 +125,6 @@ nv50_mpeg_cclass = {
* PMPEG engine/subdev functions
******************************************************************************/
-int
-nv50_mpeg_tlb_flush(struct nouveau_engine *engine)
-{
- nv50_vm_flush_engine(&engine->base, 0x08);
- return 0;
-}
-
void
nv50_mpeg_intr(struct nouveau_subdev *subdev)
{
@@ -191,7 +184,6 @@ nv50_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->intr = nv50_vpe_intr;
nv_engine(priv)->cclass = &nv50_mpeg_cclass;
nv_engine(priv)->sclass = nv50_mpeg_sclass;
- nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
index 8f805b44d59e..96f5aa92677b 100644
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
@@ -88,7 +88,6 @@ nv84_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->intr = nv50_mpeg_intr;
nv_engine(priv)->cclass = &nv84_mpeg_cclass;
nv_engine(priv)->sclass = nv84_mpeg_sclass;
- nv_engine(priv)->tlb_flush = nv50_mpeg_tlb_flush;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
index ebf0d860e2dd..98072c1ff360 100644
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
@@ -22,8 +22,7 @@
* Authors: Maarten Lankhorst
*/
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
#include <engine/ppp.h>
struct nvc0_ppp_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
index 261cd96e6951..fd6272b8cdb2 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
@@ -19,24 +19,19 @@
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors: Ben Skeggs
+ * Authors: Ben Skeggs, Ilia Mirkin
*/
-#include <core/engctx.h>
-#include <core/class.h>
-
+#include <engine/xtensa.h>
#include <engine/vp.h>
-struct nv84_vp_priv {
- struct nouveau_engine base;
-};
-
/*******************************************************************************
* VP object classes
******************************************************************************/
static struct nouveau_oclass
nv84_vp_sclass[] = {
+ { 0x7476, &nouveau_object_ofuncs },
{},
};
@@ -48,7 +43,7 @@ static struct nouveau_oclass
nv84_vp_cclass = {
.handle = NV_ENGCTX(VP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
+ .ctor = _nouveau_xtensa_engctx_ctor,
.dtor = _nouveau_engctx_dtor,
.init = _nouveau_engctx_init,
.fini = _nouveau_engctx_fini,
@@ -66,10 +61,10 @@ nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
{
- struct nv84_vp_priv *priv;
+ struct nouveau_xtensa *priv;
int ret;
- ret = nouveau_engine_create(parent, engine, oclass, true,
+ ret = nouveau_xtensa_create(parent, engine, oclass, 0xf000, true,
"PVP", "vp", &priv);
*pobject = nv_object(priv);
if (ret)
@@ -78,6 +73,8 @@ nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
nv_subdev(priv)->unit = 0x01020000;
nv_engine(priv)->cclass = &nv84_vp_cclass;
nv_engine(priv)->sclass = nv84_vp_sclass;
+ priv->fifo_val = 0x111;
+ priv->unkd28 = 0x9c544;
return 0;
}
@@ -86,8 +83,10 @@ nv84_vp_oclass = {
.handle = NV_ENGINE(VP, 0x84),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv84_vp_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
+ .dtor = _nouveau_xtensa_dtor,
+ .init = _nouveau_xtensa_init,
+ .fini = _nouveau_xtensa_fini,
+ .rd32 = _nouveau_xtensa_rd32,
+ .wr32 = _nouveau_xtensa_wr32,
},
};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
new file mode 100644
index 000000000000..8a8236bc84de
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <core/engctx.h>
+#include <core/class.h>
+
+#include <engine/vp.h>
+
+struct nv98_vp_priv {
+ struct nouveau_engine base;
+};
+
+/*******************************************************************************
+ * VP object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_vp_sclass[] = {
+ {},
+};
+
+/*******************************************************************************
+ * PVP context
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv98_vp_cclass = {
+ .handle = NV_ENGCTX(VP, 0x98),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = _nouveau_engctx_ctor,
+ .dtor = _nouveau_engctx_dtor,
+ .init = _nouveau_engctx_init,
+ .fini = _nouveau_engctx_fini,
+ .rd32 = _nouveau_engctx_rd32,
+ .wr32 = _nouveau_engctx_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PVP engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv98_vp_priv *priv;
+ int ret;
+
+ ret = nouveau_engine_create(parent, engine, oclass, true,
+ "PVP", "vp", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x01020000;
+ nv_engine(priv)->cclass = &nv98_vp_cclass;
+ nv_engine(priv)->sclass = nv98_vp_sclass;
+ return 0;
+}
+
+struct nouveau_oclass
+nv98_vp_oclass = {
+ .handle = NV_ENGINE(VP, 0x98),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv98_vp_ctor,
+ .dtor = _nouveau_engine_dtor,
+ .init = _nouveau_engine_init,
+ .fini = _nouveau_engine_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
index f761949d7039..1879229b60eb 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
@@ -22,8 +22,7 @@
* Authors: Maarten Lankhorst
*/
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
#include <engine/vp.h>
struct nvc0_vp_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
index 2384ce5dbe16..d28ecbf7bc49 100644
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
+++ b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
@@ -22,8 +22,7 @@
* Authors: Ben Skeggs
*/
-#include <core/falcon.h>
-
+#include <engine/falcon.h>
#include <engine/vp.h>
struct nve0_vp_priv {
diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
new file mode 100644
index 000000000000..0639bc59d0a5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2013 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION 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 <engine/xtensa.h>
+
+u32
+_nouveau_xtensa_rd32(struct nouveau_object *object, u64 addr)
+{
+ struct nouveau_xtensa *xtensa = (void *)object;
+ return nv_rd32(xtensa, xtensa->addr + addr);
+}
+
+void
+_nouveau_xtensa_wr32(struct nouveau_object *object, u64 addr, u32 data)
+{
+ struct nouveau_xtensa *xtensa = (void *)object;
+ nv_wr32(xtensa, xtensa->addr + addr, data);
+}
+
+int
+_nouveau_xtensa_engctx_ctor(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_engctx *engctx;
+ int ret;
+
+ ret = nouveau_engctx_create(parent, engine, oclass, NULL,
+ 0x10000, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &engctx);
+ *pobject = nv_object(engctx);
+ return ret;
+}
+
+void
+_nouveau_xtensa_intr(struct nouveau_subdev *subdev)
+{
+ struct nouveau_xtensa *xtensa = (void *)subdev;
+ u32 unk104 = nv_ro32(xtensa, 0xd04);
+ u32 intr = nv_ro32(xtensa, 0xc20);
+ u32 chan = nv_ro32(xtensa, 0xc28);
+ u32 unk10c = nv_ro32(xtensa, 0xd0c);
+
+ if (intr & 0x10)
+ nv_warn(xtensa, "Watchdog interrupt, engine hung.\n");
+ nv_wo32(xtensa, 0xc20, intr);
+ intr = nv_ro32(xtensa, 0xc20);
+ if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
+ nv_debug(xtensa, "Enabling FIFO_CTRL\n");
+ nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
+ }
+}
+
+int
+nouveau_xtensa_create_(struct nouveau_object *parent,
+ struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, u32 addr, bool enable,
+ const char *iname, const char *fname,
+ int length, void **pobject)
+{
+ struct nouveau_xtensa *xtensa;
+ int ret;
+
+ ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
+ fname, length, pobject);
+ xtensa = *pobject;
+ if (ret)
+ return ret;
+
+ nv_subdev(xtensa)->intr = _nouveau_xtensa_intr;
+
+ xtensa->addr = addr;
+
+ return 0;
+}
+
+int
+_nouveau_xtensa_init(struct nouveau_object *object)
+{
+ struct nouveau_device *device = nv_device(object);
+ struct nouveau_xtensa *xtensa = (void *)object;
+ const struct firmware *fw;
+ char name[32];
+ int i, ret;
+ u32 tmp;
+
+ ret = nouveau_engine_init(&xtensa->base);
+ if (ret)
+ return ret;
+
+ if (!xtensa->gpu_fw) {
+ snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
+ xtensa->addr >> 12);
+
+ ret = request_firmware(&fw, name, &device->pdev->dev);
+ if (ret) {
+ nv_warn(xtensa, "unable to load firmware %s\n", name);
+ return ret;
+ }
+
+ ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+ &xtensa->gpu_fw);
+ if (ret) {
+ release_firmware(fw);
+ return ret;
+ }
+
+ nv_debug(xtensa, "Loading firmware to address: 0x%llx\n",
+ xtensa->gpu_fw->addr);
+
+ for (i = 0; i < fw->size / 4; i++)
+ nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
+ release_firmware(fw);
+ }
+
+ nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
+ nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */
+
+ nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
+ nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+ nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+
+ nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
+ nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
+ nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */
+
+ tmp = nv_rd32(xtensa, 0x0);
+ nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */
+
+ nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */
+
+ nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+ nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+
+ return 0;
+}
+
+int
+_nouveau_xtensa_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nouveau_xtensa *xtensa = (void *)object;
+
+ nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
+ nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */
+
+ if (!suspend)
+ nouveau_gpuobj_ref(NULL, &xtensa->gpu_fw);
+
+ return nouveau_engine_fini(&xtensa->base, suspend);
+}
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
index 05840f3eee98..99b6600fe80a 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/device.h
@@ -17,8 +17,7 @@ enum nv_subdev_type {
NVDEV_SUBDEV_DEVINIT,
NVDEV_SUBDEV_GPIO,
NVDEV_SUBDEV_I2C,
- NVDEV_SUBDEV_CLOCK,
- NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_CLOCK,
+ NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
/* This grouping of subdevs are initialised right after they've
* been created, and are allowed to assume any subdevs in the
@@ -35,6 +34,7 @@ enum nv_subdev_type {
NVDEV_SUBDEV_VM,
NVDEV_SUBDEV_BAR,
NVDEV_SUBDEV_VOLT,
+ NVDEV_SUBDEV_CLOCK,
NVDEV_SUBDEV_THERM,
NVDEV_ENGINE_DMAOBJ,
@@ -49,6 +49,7 @@ enum nv_subdev_type {
NVDEV_ENGINE_PPP,
NVDEV_ENGINE_COPY0,
NVDEV_ENGINE_COPY1,
+ NVDEV_ENGINE_COPY2,
NVDEV_ENGINE_UNK1C1,
NVDEV_ENGINE_VENC,
NVDEV_ENGINE_DISP,
diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h
index 2514e81ade02..2bf7d0e32261 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/mm.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h
@@ -15,8 +15,6 @@ struct nouveau_mm {
struct list_head nodes;
struct list_head free;
- struct mutex mutex;
-
u32 block_size;
int heap_nodes;
};
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
index 13ccdf54dfad..67662e2c4547 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
@@ -2,6 +2,7 @@
#define __NOUVEAU_BSP_H__
extern struct nouveau_oclass nv84_bsp_oclass;
+extern struct nouveau_oclass nv98_bsp_oclass;
extern struct nouveau_oclass nvc0_bsp_oclass;
extern struct nouveau_oclass nve0_bsp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
index 8cad2cf28cef..316a28ae5f5c 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/copy.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
@@ -8,5 +8,6 @@ extern struct nouveau_oclass nvc0_copy0_oclass;
extern struct nouveau_oclass nvc0_copy1_oclass;
extern struct nouveau_oclass nve0_copy0_oclass;
extern struct nouveau_oclass nve0_copy1_oclass;
+extern struct nouveau_oclass nve0_copy2_oclass;
#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/falcon.h b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
index 1edec386ab36..1edec386ab36 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/falcon.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
index 5d392439f2ac..8e1b52312ddc 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
@@ -61,8 +61,14 @@ extern struct nouveau_oclass nv34_graph_oclass;
extern struct nouveau_oclass nv35_graph_oclass;
extern struct nouveau_oclass nv40_graph_oclass;
extern struct nouveau_oclass nv50_graph_oclass;
-extern struct nouveau_oclass nvc0_graph_oclass;
-extern struct nouveau_oclass nve0_graph_oclass;
+extern struct nouveau_oclass *nvc0_graph_oclass;
+extern struct nouveau_oclass *nvc1_graph_oclass;
+extern struct nouveau_oclass *nvc3_graph_oclass;
+extern struct nouveau_oclass *nvc8_graph_oclass;
+extern struct nouveau_oclass *nvd7_graph_oclass;
+extern struct nouveau_oclass *nvd9_graph_oclass;
+extern struct nouveau_oclass *nve4_graph_oclass;
+extern struct nouveau_oclass *nvf0_graph_oclass;
extern const struct nouveau_bitfield nv04_graph_nsource[];
extern struct nouveau_ofuncs nv04_graph_ofuncs;
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
index bbf0d4a5bbd7..1d1a89a06ee4 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
@@ -54,7 +54,6 @@ extern struct nouveau_ofuncs nv50_mpeg_ofuncs;
int nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, void *, u32,
struct nouveau_object **);
-int nv50_mpeg_tlb_flush(struct nouveau_engine *);
void nv50_mpeg_intr(struct nouveau_subdev *);
int nv50_mpeg_init(struct nouveau_object *);
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
index d7b287b115bf..39baebec7fbb 100644
--- a/drivers/gpu/drm/nouveau/core/include/engine/vp.h
+++ b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
@@ -2,6 +2,7 @@
#define __NOUVEAU_VP_H__
extern struct nouveau_oclass nv84_vp_oclass;
+extern struct nouveau_oclass nv98_vp_oclass;
extern struct nouveau_oclass nvc0_vp_oclass;
extern struct nouveau_oclass nve0_vp_oclass;
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h b/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
new file mode 100644
index 000000000000..306100f31f02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
@@ -0,0 +1,38 @@
+#ifndef __NOUVEAU_XTENSA_H__
+#define __NOUVEAU_XTENSA_H__
+
+#include <core/engine.h>
+#include <core/engctx.h>
+#include <core/gpuobj.h>
+
+struct nouveau_xtensa {
+ struct nouveau_engine base;
+
+ u32 addr;
+ struct nouveau_gpuobj *gpu_fw;
+ u32 fifo_val;
+ u32 unkd28;
+};
+
+#define nouveau_xtensa_create(p,e,c,b,d,i,f,r) \
+ nouveau_xtensa_create_((p), (e), (c), (b), (d), (i), (f), \
+ sizeof(**r),(void **)r)
+
+int _nouveau_xtensa_engctx_ctor(struct nouveau_object *,
+ struct nouveau_object *,
+ struct nouveau_oclass *, void *, u32,
+ struct nouveau_object **);
+
+void _nouveau_xtensa_intr(struct nouveau_subdev *);
+int nouveau_xtensa_create_(struct nouveau_object *,
+ struct nouveau_object *,
+ struct nouveau_oclass *, u32, bool,
+ const char *, const char *,
+ int, void **);
+#define _nouveau_xtensa_dtor _nouveau_engine_dtor
+int _nouveau_xtensa_init(struct nouveau_object *);
+int _nouveau_xtensa_fini(struct nouveau_object *, bool);
+u32 _nouveau_xtensa_rd32(struct nouveau_object *, u64);
+void _nouveau_xtensa_wr32(struct nouveau_object *, u64, u32);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
index 41b7a6a76f19..89ee289097a6 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
@@ -10,8 +10,6 @@ struct nvbios_pll;
struct nouveau_clock {
struct nouveau_subdev base;
- int (*pll_set)(struct nouveau_clock *, u32 type, u32 freq);
-
/*XXX: die, these are here *only* to support the completely
* bat-shit insane what-was-nouveau_hw.c code
*/
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
index 29e4cc1f6cc0..685c9b12ee4c 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
@@ -8,6 +8,8 @@ struct nouveau_devinit {
struct nouveau_subdev base;
bool post;
void (*meminit)(struct nouveau_devinit *);
+ int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
+
};
static inline struct nouveau_devinit *
@@ -20,11 +22,20 @@ nouveau_devinit(void *obj)
nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nouveau_devinit_destroy(p) \
nouveau_subdev_destroy(&(p)->base)
+#define nouveau_devinit_init(p) ({ \
+ struct nouveau_devinit *d = (p); \
+ _nouveau_devinit_init(nv_object(d)); \
+})
+#define nouveau_devinit_fini(p,s) ({ \
+ struct nouveau_devinit *d = (p); \
+ _nouveau_devinit_fini(nv_object(d), (s)); \
+})
int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, void **);
-int nouveau_devinit_init(struct nouveau_devinit *);
-int nouveau_devinit_fini(struct nouveau_devinit *, bool suspend);
+#define _nouveau_devinit_dtor _nouveau_subdev_dtor
+int _nouveau_devinit_init(struct nouveau_object *);
+int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
extern struct nouveau_oclass nv04_devinit_oclass;
extern struct nouveau_oclass nv05_devinit_oclass;
@@ -32,9 +43,7 @@ extern struct nouveau_oclass nv10_devinit_oclass;
extern struct nouveau_oclass nv1a_devinit_oclass;
extern struct nouveau_oclass nv20_devinit_oclass;
extern struct nouveau_oclass nv50_devinit_oclass;
-
-void nv04_devinit_dtor(struct nouveau_object *);
-int nv04_devinit_init(struct nouveau_object *);
-int nv04_devinit_fini(struct nouveau_object *, bool);
+extern struct nouveau_oclass nva3_devinit_oclass;
+extern struct nouveau_oclass nvc0_devinit_oclass;
#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
index da470e6851b1..2e7405084261 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
@@ -53,31 +53,7 @@ struct nouveau_fb {
bool (*memtype_valid)(struct nouveau_fb *, u32 memtype);
- struct {
- enum {
- NV_MEM_TYPE_UNKNOWN = 0,
- NV_MEM_TYPE_STOLEN,
- NV_MEM_TYPE_SGRAM,
- NV_MEM_TYPE_SDRAM,
- NV_MEM_TYPE_DDR1,
- NV_MEM_TYPE_DDR2,
- NV_MEM_TYPE_DDR3,
- NV_MEM_TYPE_GDDR2,
- NV_MEM_TYPE_GDDR3,
- NV_MEM_TYPE_GDDR4,
- NV_MEM_TYPE_GDDR5
- } type;
- u64 stolen;
- u64 size;
-
- int ranks;
- int parts;
-
- int (*init)(struct nouveau_fb *);
- int (*get)(struct nouveau_fb *, u64 size, u32 align,
- u32 size_nc, u32 type, struct nouveau_mem **);
- void (*put)(struct nouveau_fb *, struct nouveau_mem **);
- } ram;
+ struct nouveau_ram *ram;
struct nouveau_mm vram;
struct nouveau_mm tags;
@@ -102,18 +78,6 @@ nouveau_fb(void *obj)
return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB];
}
-#define nouveau_fb_create(p,e,c,d) \
- nouveau_subdev_create((p), (e), (c), 0, "PFB", "fb", (d))
-int nouveau_fb_preinit(struct nouveau_fb *);
-void nouveau_fb_destroy(struct nouveau_fb *);
-int nouveau_fb_init(struct nouveau_fb *);
-#define nouveau_fb_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-void _nouveau_fb_dtor(struct nouveau_object *);
-int _nouveau_fb_init(struct nouveau_object *);
-#define _nouveau_fb_fini _nouveau_subdev_fini
-
extern struct nouveau_oclass nv04_fb_oclass;
extern struct nouveau_oclass nv10_fb_oclass;
extern struct nouveau_oclass nv1a_fb_oclass;
@@ -132,40 +96,31 @@ extern struct nouveau_oclass nv4e_fb_oclass;
extern struct nouveau_oclass nv50_fb_oclass;
extern struct nouveau_oclass nvc0_fb_oclass;
-struct nouveau_bios;
-int nouveau_fb_bios_memtype(struct nouveau_bios *);
-
-bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
-
-void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv20_fb_vram_init(struct nouveau_fb *);
-void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv30_fb_init(struct nouveau_object *);
-void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *);
-
-int nv41_fb_vram_init(struct nouveau_fb *);
-int nv41_fb_init(struct nouveau_object *);
-void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv44_fb_vram_init(struct nouveau_fb *);
-int nv44_fb_init(struct nouveau_object *);
-void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+struct nouveau_ram {
+ struct nouveau_object base;
+ enum {
+ NV_MEM_TYPE_UNKNOWN = 0,
+ NV_MEM_TYPE_STOLEN,
+ NV_MEM_TYPE_SGRAM,
+ NV_MEM_TYPE_SDRAM,
+ NV_MEM_TYPE_DDR1,
+ NV_MEM_TYPE_DDR2,
+ NV_MEM_TYPE_DDR3,
+ NV_MEM_TYPE_GDDR2,
+ NV_MEM_TYPE_GDDR3,
+ NV_MEM_TYPE_GDDR4,
+ NV_MEM_TYPE_GDDR5
+ } type;
+ u64 stolen;
+ u64 size;
+ u32 tags;
-void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
+ int ranks;
+ int parts;
-void nv50_fb_vram_del(struct nouveau_fb *, struct nouveau_mem **);
+ int (*get)(struct nouveau_fb *, u64 size, u32 align,
+ u32 size_nc, u32 type, struct nouveau_mem **);
+ void (*put)(struct nouveau_fb *, struct nouveau_mem **);
+};
#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
index 9d595efe667a..f2e87b105666 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
@@ -58,7 +58,7 @@ struct nouveau_vm {
int refcount;
struct list_head pgd_list;
- atomic_t engref[64]; //NVDEV_SUBDEV_NR];
+ atomic_t engref[NVDEV_SUBDEV_NR];
struct nouveau_vm_pgt *pgt;
u32 fpde;
@@ -117,9 +117,6 @@ int nv04_vm_create(struct nouveau_vmmgr *, u64, u64, u64,
struct nouveau_vm **);
void nv04_vmmgr_dtor(struct nouveau_object *);
-void nv50_vm_flush_engine(struct nouveau_subdev *, int engine);
-void nvc0_vm_flush_engine(struct nouveau_subdev *, u64 addr, int type);
-
/* nouveau_vm.c */
int nouveau_vm_create(struct nouveau_vmmgr *, u64 offset, u64 length,
u64 mm_offset, u32 block, struct nouveau_vm **);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
index 649f1ced1fe0..160d27f3c7b4 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
@@ -53,7 +53,6 @@ nv50_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem,
return ret;
nouveau_vm_map(vma, mem);
- nv50_vm_flush_engine(nv_subdev(bar), 6);
return 0;
}
@@ -69,7 +68,6 @@ nv50_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem,
return ret;
nouveau_vm_map(vma, mem);
- nv50_vm_flush_engine(nv_subdev(bar), 6);
return 0;
}
@@ -77,7 +75,6 @@ static void
nv50_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
{
nouveau_vm_unmap(vma);
- nv50_vm_flush_engine(nv_subdev(bar), 6);
nouveau_vm_put(vma);
}
@@ -147,6 +144,8 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
ret = nouveau_gpuobj_new(nv_object(priv), heap,
((limit-- - start) >> 12) * 8, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]);
@@ -179,6 +178,8 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd);
nouveau_vm_ref(NULL, &vm, NULL);
if (ret)
@@ -237,7 +238,11 @@ nv50_bar_init(struct nouveau_object *object)
nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
- nv50_vm_flush_engine(nv_subdev(priv), 6);
+ nv_wr32(priv, 0x100c80, 0x00060001);
+ if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) {
+ nv_error(priv, "vm flush timeout\n");
+ return -EBUSY;
+ }
nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12);
nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
index f8a44956dec1..b2ec7411eb2e 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
@@ -51,7 +51,6 @@ nvc0_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem,
return ret;
nouveau_vm_map(vma, mem);
- nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[0].pgd->addr, 5);
return 0;
}
@@ -68,18 +67,13 @@ nvc0_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem,
return ret;
nouveau_vm_map(vma, mem);
- nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[1].pgd->addr, 5);
return 0;
}
static void
nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
{
- struct nvc0_bar_priv *priv = (void *)bar;
- int i = !(vma->vm == priv->bar[0].vm);
-
nouveau_vm_unmap(vma);
- nvc0_vm_flush_engine(nv_subdev(bar), priv->bar[i].pgd->addr, 5);
nouveau_vm_put(vma);
}
@@ -116,6 +110,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
ret = nouveau_gpuobj_new(nv_object(priv), NULL,
(pci_resource_len(pdev, 3) >> 12) * 8,
0x1000, NVOBJ_FLAG_ZERO_ALLOC,
@@ -150,6 +146,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
ret = nouveau_vm_ref(vm, &priv->bar[1].vm, priv->bar[1].pgd);
nouveau_vm_ref(NULL, &vm, NULL);
if (ret)
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
index 0e2c1a4f1659..aa0fbbec7f08 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
@@ -85,11 +85,15 @@ static void
nouveau_bios_shadow_pramin(struct nouveau_bios *bios)
{
struct nouveau_device *device = nv_device(bios);
+ u64 addr = 0;
u32 bar0 = 0;
int i;
if (device->card_type >= NV_50) {
- u64 addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8;
+ if ( device->card_type < NV_C0 ||
+ !(nv_rd32(bios, 0x022500) & 0x00000001))
+ addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8;
+
if (!addr) {
addr = (u64)nv_rd32(bios, 0x001700) << 16;
addr += 0xf0000;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
index c434d398d16f..0687e6481438 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
@@ -10,7 +10,6 @@
#include <subdev/bios/gpio.h>
#include <subdev/bios/init.h>
#include <subdev/devinit.h>
-#include <subdev/clock.h>
#include <subdev/i2c.h>
#include <subdev/vga.h>
#include <subdev/gpio.h>
@@ -300,9 +299,9 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
static void
init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
{
- struct nouveau_clock *clk = nouveau_clock(init->bios);
- if (clk && clk->pll_set && init_exec(init)) {
- int ret = clk->pll_set(clk, id, freq);
+ struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
+ if (devinit->pll_set && init_exec(init)) {
+ int ret = devinit->pll_set(devinit, id, freq);
if (ret)
warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
index b7fd1151166e..a14277586595 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
@@ -22,9 +22,10 @@
* Authors: Ben Skeggs
*/
-#include <subdev/clock.h>
#include <subdev/bios.h>
#include <subdev/bios/pll.h>
+#include <subdev/clock.h>
+#include <subdev/devinit/priv.h>
#include "pll.h"
@@ -32,272 +33,12 @@ struct nv04_clock_priv {
struct nouveau_clock base;
};
-static int
-powerctrl_1_shift(int chip_version, int reg)
-{
- int shift = -4;
-
- if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
- return shift;
-
- switch (reg) {
- case 0x680520:
- shift += 4;
- case 0x680508:
- shift += 4;
- case 0x680504:
- shift += 4;
- case 0x680500:
- shift += 4;
- }
-
- /*
- * the shift for vpll regs is only used for nv3x chips with a single
- * stage pll
- */
- if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
- chip_version == 0x36 || chip_version >= 0x40))
- shift = -4;
-
- return shift;
-}
-
-static void
-setPLL_single(struct nv04_clock_priv *priv, u32 reg,
- struct nouveau_pll_vals *pv)
-{
- int chip_version = nouveau_bios(priv)->version.chip;
- uint32_t oldpll = nv_rd32(priv, reg);
- int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
- uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
- uint32_t saved_powerctrl_1 = 0;
- int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
-
- if (oldpll == pll)
- return; /* already set */
-
- if (shift_powerctrl_1 >= 0) {
- saved_powerctrl_1 = nv_rd32(priv, 0x001584);
- nv_wr32(priv, 0x001584,
- (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
- 1 << shift_powerctrl_1);
- }
-
- if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
- /* upclock -- write new post divider first */
- nv_wr32(priv, reg, pv->log2P << 16 | (oldpll & 0xffff));
- else
- /* downclock -- write new NM first */
- nv_wr32(priv, reg, (oldpll & 0xffff0000) | pv->NM1);
-
- if (chip_version < 0x17 && chip_version != 0x11)
- /* wait a bit on older chips */
- msleep(64);
- nv_rd32(priv, reg);
-
- /* then write the other half as well */
- nv_wr32(priv, reg, pll);
-
- if (shift_powerctrl_1 >= 0)
- nv_wr32(priv, 0x001584, saved_powerctrl_1);
-}
-
-static uint32_t
-new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
-{
- bool head_a = (reg1 == 0x680508);
-
- if (ss) /* single stage pll mode */
- ramdac580 |= head_a ? 0x00000100 : 0x10000000;
- else
- ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
-
- return ramdac580;
-}
-
-static void
-setPLL_double_highregs(struct nv04_clock_priv *priv, u32 reg1,
- struct nouveau_pll_vals *pv)
-{
- int chip_version = nouveau_bios(priv)->version.chip;
- bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
- uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
- uint32_t oldpll1 = nv_rd32(priv, reg1);
- uint32_t oldpll2 = !nv3035 ? nv_rd32(priv, reg2) : 0;
- uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
- uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
- uint32_t oldramdac580 = 0, ramdac580 = 0;
- bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */
- uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
- int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
-
- /* model specific additions to generic pll1 and pll2 set up above */
- if (nv3035) {
- pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
- (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
- pll2 = 0;
- }
- if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
- oldramdac580 = nv_rd32(priv, 0x680580);
- ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
- if (oldramdac580 != ramdac580)
- oldpll1 = ~0; /* force mismatch */
- if (single_stage)
- /* magic value used by nvidia in single stage mode */
- pll2 |= 0x011f;
- }
- if (chip_version > 0x70)
- /* magic bits set by the blob (but not the bios) on g71-73 */
- pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
-
- if (oldpll1 == pll1 && oldpll2 == pll2)
- return; /* already set */
-
- if (shift_powerctrl_1 >= 0) {
- saved_powerctrl_1 = nv_rd32(priv, 0x001584);
- nv_wr32(priv, 0x001584,
- (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
- 1 << shift_powerctrl_1);
- }
-
- if (chip_version >= 0x40) {
- int shift_c040 = 14;
-
- switch (reg1) {
- case 0x680504:
- shift_c040 += 2;
- case 0x680500:
- shift_c040 += 2;
- case 0x680520:
- shift_c040 += 2;
- case 0x680508:
- shift_c040 += 2;
- }
-
- savedc040 = nv_rd32(priv, 0xc040);
- if (shift_c040 != 14)
- nv_wr32(priv, 0xc040, savedc040 & ~(3 << shift_c040));
- }
-
- if (oldramdac580 != ramdac580)
- nv_wr32(priv, 0x680580, ramdac580);
-
- if (!nv3035)
- nv_wr32(priv, reg2, pll2);
- nv_wr32(priv, reg1, pll1);
-
- if (shift_powerctrl_1 >= 0)
- nv_wr32(priv, 0x001584, saved_powerctrl_1);
- if (chip_version >= 0x40)
- nv_wr32(priv, 0xc040, savedc040);
-}
-
-static void
-setPLL_double_lowregs(struct nv04_clock_priv *priv, u32 NMNMreg,
- struct nouveau_pll_vals *pv)
-{
- /* When setting PLLs, there is a merry game of disabling and enabling
- * various bits of hardware during the process. This function is a
- * synthesis of six nv4x traces, nearly each card doing a subtly
- * different thing. With luck all the necessary bits for each card are
- * combined herein. Without luck it deviates from each card's formula
- * so as to not work on any :)
- */
-
- uint32_t Preg = NMNMreg - 4;
- bool mpll = Preg == 0x4020;
- uint32_t oldPval = nv_rd32(priv, Preg);
- uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
- uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
- 0xc << 28 | pv->log2P << 16;
- uint32_t saved4600 = 0;
- /* some cards have different maskc040s */
- uint32_t maskc040 = ~(3 << 14), savedc040;
- bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
-
- if (nv_rd32(priv, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
- return;
-
- if (Preg == 0x4000)
- maskc040 = ~0x333;
- if (Preg == 0x4058)
- maskc040 = ~(0xc << 24);
-
- if (mpll) {
- struct nvbios_pll info;
- uint8_t Pval2;
-
- if (nvbios_pll_parse(nouveau_bios(priv), Preg, &info))
- return;
-
- Pval2 = pv->log2P + info.bias_p;
- if (Pval2 > info.max_p)
- Pval2 = info.max_p;
- Pval |= 1 << 28 | Pval2 << 20;
-
- saved4600 = nv_rd32(priv, 0x4600);
- nv_wr32(priv, 0x4600, saved4600 | 8 << 28);
- }
- if (single_stage)
- Pval |= mpll ? 1 << 12 : 1 << 8;
-
- nv_wr32(priv, Preg, oldPval | 1 << 28);
- nv_wr32(priv, Preg, Pval & ~(4 << 28));
- if (mpll) {
- Pval |= 8 << 20;
- nv_wr32(priv, 0x4020, Pval & ~(0xc << 28));
- nv_wr32(priv, 0x4038, Pval & ~(0xc << 28));
- }
-
- savedc040 = nv_rd32(priv, 0xc040);
- nv_wr32(priv, 0xc040, savedc040 & maskc040);
-
- nv_wr32(priv, NMNMreg, NMNM);
- if (NMNMreg == 0x4024)
- nv_wr32(priv, 0x403c, NMNM);
-
- nv_wr32(priv, Preg, Pval);
- if (mpll) {
- Pval &= ~(8 << 20);
- nv_wr32(priv, 0x4020, Pval);
- nv_wr32(priv, 0x4038, Pval);
- nv_wr32(priv, 0x4600, saved4600);
- }
-
- nv_wr32(priv, 0xc040, savedc040);
-
- if (mpll) {
- nv_wr32(priv, 0x4020, Pval & ~(1 << 28));
- nv_wr32(priv, 0x4038, Pval & ~(1 << 28));
- }
-}
-
-int
-nv04_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
- struct nv04_clock_priv *priv = (void *)clk;
- struct nouveau_pll_vals pv;
- struct nvbios_pll info;
- int ret;
-
- ret = nvbios_pll_parse(nouveau_bios(priv), type > 0x405c ?
- type : type - 4, &info);
- if (ret)
- return ret;
-
- ret = clk->pll_calc(clk, &info, freq, &pv);
- if (!ret)
- return ret;
-
- return clk->pll_prog(clk, type, &pv);
-}
-
int
nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
int clk, struct nouveau_pll_vals *pv)
{
int N1, M1, N2, M2, P;
- int ret = nv04_pll_calc(clock, info, clk, &N1, &M1, &N2, &M2, &P);
+ int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P);
if (ret) {
pv->refclk = info->refclk;
pv->N1 = N1;
@@ -313,17 +54,17 @@ int
nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1,
struct nouveau_pll_vals *pv)
{
- struct nv04_clock_priv *priv = (void *)clk;
+ struct nouveau_devinit *devinit = nouveau_devinit(clk);
int cv = nouveau_bios(clk)->version.chip;
if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
cv >= 0x40) {
if (reg1 > 0x405c)
- setPLL_double_highregs(priv, reg1, pv);
+ setPLL_double_highregs(devinit, reg1, pv);
else
- setPLL_double_lowregs(priv, reg1, pv);
+ setPLL_double_lowregs(devinit, reg1, pv);
} else
- setPLL_single(priv, reg1, pv);
+ setPLL_single(devinit, reg1, pv);
return 0;
}
@@ -341,7 +82,6 @@ nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- priv->base.pll_set = nv04_clock_pll_set;
priv->base.pll_calc = nv04_clock_pll_calc;
priv->base.pll_prog = nv04_clock_pll_prog;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
index a4b2b7ebf9af..0db5dbfd91b5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
@@ -41,7 +41,6 @@ nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- priv->base.pll_set = nv04_clock_pll_set;
priv->base.pll_calc = nv04_clock_pll_calc;
priv->base.pll_prog = nv04_clock_pll_prog;
return 0;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
index f4147f67eda6..d09d3e78040c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
@@ -33,50 +33,6 @@ struct nv50_clock_priv {
};
static int
-nv50_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
- struct nv50_clock_priv *priv = (void *)clk;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll info;
- int N1, M1, N2, M2, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type, &info);
- if (ret) {
- nv_error(clk, "failed to retrieve pll data, %d\n", ret);
- return ret;
- }
-
- ret = nv04_pll_calc(clk, &info, freq, &N1, &M1, &N2, &M2, &P);
- if (!ret) {
- nv_error(clk, "failed pll calculation\n");
- return ret;
- }
-
- switch (info.type) {
- case PLL_VPLL0:
- case PLL_VPLL1:
- nv_wr32(priv, info.reg + 0, 0x10000611);
- nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
- nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) |
- (M2 << 16) | N2);
- break;
- case PLL_MEMORY:
- nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
- (info.bias_p << 19) |
- (P << 16));
- nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
- break;
- default:
- nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
- nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
- break;
- }
-
- return 0;
-}
-
-static int
nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -89,7 +45,6 @@ nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- priv->base.pll_set = nv50_clock_pll_set;
priv->base.pll_calc = nv04_clock_pll_calc;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
index 9068c98b96f6..f074cd20bc9c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
@@ -32,47 +32,13 @@ struct nva3_clock_priv {
struct nouveau_clock base;
};
-static int
-nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
- struct nva3_clock_priv *priv = (void *)clk;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll info;
- int N, fN, M, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type, &info);
- if (ret)
- return ret;
-
- ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P);
- if (ret < 0)
- return ret;
-
- switch (info.type) {
- case PLL_VPLL0:
- case PLL_VPLL1:
- nv_wr32(priv, info.reg + 0, 0x50000610);
- nv_mask(priv, info.reg + 4, 0x003fffff,
- (P << 16) | (M << 8) | N);
- nv_wr32(priv, info.reg + 8, fN);
- break;
- default:
- nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
int
nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
int clk, struct nouveau_pll_vals *pv)
{
int ret, N, M, P;
- ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P);
+ ret = nva3_pll_calc(nv_subdev(clock), info, clk, &N, NULL, &M, &P);
if (ret > 0) {
pv->refclk = info->refclk;
@@ -97,7 +63,6 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- priv->base.pll_set = nva3_clock_pll_set;
priv->base.pll_calc = nva3_clock_pll_calc;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
index 7c9626258a46..439d81c26130 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
@@ -33,41 +33,6 @@ struct nvc0_clock_priv {
};
static int
-nvc0_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
-{
- struct nvc0_clock_priv *priv = (void *)clk;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll info;
- int N, fN, M, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type, &info);
- if (ret)
- return ret;
-
- ret = nva3_pll_calc(clk, &info, freq, &N, &fN, &M, &P);
- if (ret < 0)
- return ret;
-
- switch (info.type) {
- case PLL_VPLL0:
- case PLL_VPLL1:
- case PLL_VPLL2:
- case PLL_VPLL3:
- nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
- nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
- nv_wr32(priv, info.reg + 0x10, fN << 16);
- break;
- default:
- nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static int
nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -80,7 +45,6 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- priv->base.pll_set = nvc0_clock_pll_set;
priv->base.pll_calc = nva3_clock_pll_calc;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
index ef2c0078f337..445b14c33a98 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
@@ -1,9 +1,9 @@
#ifndef __NOUVEAU_PLL_H__
#define __NOUVEAU_PLL_H__
-int nv04_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq,
+int nv04_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
int *N1, int *M1, int *N2, int *M2, int *P);
-int nva3_pll_calc(struct nouveau_clock *, struct nvbios_pll *, u32 freq,
+int nva3_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
int *N, int *fN, int *M, int *P);
#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
index a2ab6d051ba8..cf1ed0dc9bc9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
@@ -21,14 +21,13 @@
* SOFTWARE.
*/
-#include <subdev/clock.h>
#include <subdev/bios.h>
#include <subdev/bios/pll.h>
#include "pll.h"
static int
-getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
+getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
int *pN, int *pM, int *pP)
{
/* Find M, N and P for a single stage PLL
@@ -39,7 +38,7 @@ getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
* "clk" parameter in kHz
* returns calculated clock
*/
- int cv = nouveau_bios(clock)->version.chip;
+ int cv = nouveau_bios(subdev)->version.chip;
int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
int minM = info->vco1.min_m, maxM = info->vco1.max_m;
int minN = info->vco1.min_n, maxN = info->vco1.max_n;
@@ -124,7 +123,7 @@ getMNP_single(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
}
static int
-getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
+getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
{
/* Find M, N and P for a two stage PLL
@@ -135,7 +134,7 @@ getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
* "clk" parameter in kHz
* returns calculated clock
*/
- int chip_version = nouveau_bios(clock)->version.chip;
+ int chip_version = nouveau_bios(subdev)->version.chip;
int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
@@ -223,20 +222,20 @@ getMNP_double(struct nouveau_clock *clock, struct nvbios_pll *info, int clk,
}
int
-nv04_pll_calc(struct nouveau_clock *clk, struct nvbios_pll *info, u32 freq,
+nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq,
int *N1, int *M1, int *N2, int *M2, int *P)
{
int ret;
if (!info->vco2.max_freq) {
- ret = getMNP_single(clk, info, freq, N1, M1, P);
+ ret = getMNP_single(subdev, info, freq, N1, M1, P);
*N2 = 1;
*M2 = 1;
} else {
- ret = getMNP_double(clk, info, freq, N1, M1, N2, M2, P);
+ ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
}
if (!ret)
- nv_error(clk, "unable to compute acceptable pll values\n");
+ nv_error(subdev, "unable to compute acceptable pll values\n");
return ret;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
index eed5c16cf610..2fe1f712eefa 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
@@ -29,7 +29,7 @@
#include "pll.h"
int
-nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
+nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info,
u32 freq, int *pN, int *pfN, int *pM, int *P)
{
u32 best_err = ~0, err;
@@ -50,8 +50,15 @@ nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
u32 tmp = freq * *P * M;
N = tmp / info->refclk;
fN = tmp % info->refclk;
- if (!pfN && fN >= info->refclk / 2)
- N++;
+
+ if (!pfN) {
+ if (fN >= info->refclk / 2)
+ N++;
+ } else {
+ if (fN < info->refclk / 2)
+ N--;
+ fN = tmp - (N * info->refclk);
+ }
if (N < info->vco1.min_n)
continue;
@@ -66,13 +73,14 @@ nva3_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
}
if (pfN) {
- *pfN = (((fN << 13) / info->refclk) - 4096) & 0xffff;
+ *pfN = ((fN << 13) + info->refclk / 2) / info->refclk;
+ *pfN = (*pfN - 4096) & 0xffff;
return freq;
}
}
if (unlikely(best_err == ~0)) {
- nv_error(clock, "unable to find matching pll values\n");
+ nv_error(subdev, "unable to find matching pll values\n");
return -EINVAL;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
index 5a07a39c1735..79c81d3d9bac 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
@@ -29,18 +29,10 @@
#include <subdev/bios/init.h>
int
-nouveau_devinit_init(struct nouveau_devinit *devinit)
+_nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
{
- int ret = nouveau_subdev_init(&devinit->base);
- if (ret)
- return ret;
+ struct nouveau_devinit *devinit = (void *)object;
- return nvbios_init(&devinit->base, devinit->post);
-}
-
-int
-nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend)
-{
/* force full reinit on resume */
if (suspend)
devinit->post = true;
@@ -49,6 +41,17 @@ nouveau_devinit_fini(struct nouveau_devinit *devinit, bool suspend)
}
int
+_nouveau_devinit_init(struct nouveau_object *object)
+{
+ struct nouveau_devinit *devinit = (void *)object;
+ int ret = nouveau_subdev_init(&devinit->base);
+ if (ret)
+ return ret;
+
+ return nvbios_init(&devinit->base, devinit->post);
+}
+
+int
nouveau_devinit_create_(struct nouveau_object *parent,
struct nouveau_object *engine,
struct nouveau_oclass *oclass,
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
index 7a72d9394340..b22357d9b821 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
@@ -24,10 +24,10 @@
*
*/
-#include <subdev/devinit.h>
#include <subdev/vga.h>
#include "fbmem.h"
+#include "priv.h"
struct nv04_devinit_priv {
struct nouveau_devinit base;
@@ -111,33 +111,298 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit)
}
static int
-nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
+powerctrl_1_shift(int chip_version, int reg)
{
- struct nv04_devinit_priv *priv;
+ int shift = -4;
+
+ if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
+ return shift;
+
+ switch (reg) {
+ case 0x680520:
+ shift += 4;
+ case 0x680508:
+ shift += 4;
+ case 0x680504:
+ shift += 4;
+ case 0x680500:
+ shift += 4;
+ }
+
+ /*
+ * the shift for vpll regs is only used for nv3x chips with a single
+ * stage pll
+ */
+ if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
+ chip_version == 0x36 || chip_version >= 0x40))
+ shift = -4;
+
+ return shift;
+}
+
+void
+setPLL_single(struct nouveau_devinit *devinit, u32 reg,
+ struct nouveau_pll_vals *pv)
+{
+ int chip_version = nouveau_bios(devinit)->version.chip;
+ uint32_t oldpll = nv_rd32(devinit, reg);
+ int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
+ uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+ uint32_t saved_powerctrl_1 = 0;
+ int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
+
+ if (oldpll == pll)
+ return; /* already set */
+
+ if (shift_powerctrl_1 >= 0) {
+ saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+ nv_wr32(devinit, 0x001584,
+ (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+ 1 << shift_powerctrl_1);
+ }
+
+ if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
+ /* upclock -- write new post divider first */
+ nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
+ else
+ /* downclock -- write new NM first */
+ nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
+
+ if (chip_version < 0x17 && chip_version != 0x11)
+ /* wait a bit on older chips */
+ msleep(64);
+ nv_rd32(devinit, reg);
+
+ /* then write the other half as well */
+ nv_wr32(devinit, reg, pll);
+
+ if (shift_powerctrl_1 >= 0)
+ nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+}
+
+static uint32_t
+new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
+{
+ bool head_a = (reg1 == 0x680508);
+
+ if (ss) /* single stage pll mode */
+ ramdac580 |= head_a ? 0x00000100 : 0x10000000;
+ else
+ ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
+
+ return ramdac580;
+}
+
+void
+setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1,
+ struct nouveau_pll_vals *pv)
+{
+ int chip_version = nouveau_bios(devinit)->version.chip;
+ bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
+ uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
+ uint32_t oldpll1 = nv_rd32(devinit, reg1);
+ uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0;
+ uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+ uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
+ uint32_t oldramdac580 = 0, ramdac580 = 0;
+ bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */
+ uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
+ int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
+
+ /* model specific additions to generic pll1 and pll2 set up above */
+ if (nv3035) {
+ pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
+ (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
+ pll2 = 0;
+ }
+ if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
+ oldramdac580 = nv_rd32(devinit, 0x680580);
+ ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
+ if (oldramdac580 != ramdac580)
+ oldpll1 = ~0; /* force mismatch */
+ if (single_stage)
+ /* magic value used by nvidia in single stage mode */
+ pll2 |= 0x011f;
+ }
+ if (chip_version > 0x70)
+ /* magic bits set by the blob (but not the bios) on g71-73 */
+ pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
+
+ if (oldpll1 == pll1 && oldpll2 == pll2)
+ return; /* already set */
+
+ if (shift_powerctrl_1 >= 0) {
+ saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+ nv_wr32(devinit, 0x001584,
+ (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+ 1 << shift_powerctrl_1);
+ }
+
+ if (chip_version >= 0x40) {
+ int shift_c040 = 14;
+
+ switch (reg1) {
+ case 0x680504:
+ shift_c040 += 2;
+ case 0x680500:
+ shift_c040 += 2;
+ case 0x680520:
+ shift_c040 += 2;
+ case 0x680508:
+ shift_c040 += 2;
+ }
+
+ savedc040 = nv_rd32(devinit, 0xc040);
+ if (shift_c040 != 14)
+ nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
+ }
+
+ if (oldramdac580 != ramdac580)
+ nv_wr32(devinit, 0x680580, ramdac580);
+
+ if (!nv3035)
+ nv_wr32(devinit, reg2, pll2);
+ nv_wr32(devinit, reg1, pll1);
+
+ if (shift_powerctrl_1 >= 0)
+ nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+ if (chip_version >= 0x40)
+ nv_wr32(devinit, 0xc040, savedc040);
+}
+
+void
+setPLL_double_lowregs(struct nouveau_devinit *devinit, u32 NMNMreg,
+ struct nouveau_pll_vals *pv)
+{
+ /* When setting PLLs, there is a merry game of disabling and enabling
+ * various bits of hardware during the process. This function is a
+ * synthesis of six nv4x traces, nearly each card doing a subtly
+ * different thing. With luck all the necessary bits for each card are
+ * combined herein. Without luck it deviates from each card's formula
+ * so as to not work on any :)
+ */
+
+ uint32_t Preg = NMNMreg - 4;
+ bool mpll = Preg == 0x4020;
+ uint32_t oldPval = nv_rd32(devinit, Preg);
+ uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
+ uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
+ 0xc << 28 | pv->log2P << 16;
+ uint32_t saved4600 = 0;
+ /* some cards have different maskc040s */
+ uint32_t maskc040 = ~(3 << 14), savedc040;
+ bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
+
+ if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
+ return;
+
+ if (Preg == 0x4000)
+ maskc040 = ~0x333;
+ if (Preg == 0x4058)
+ maskc040 = ~(0xc << 24);
+
+ if (mpll) {
+ struct nvbios_pll info;
+ uint8_t Pval2;
+
+ if (nvbios_pll_parse(nouveau_bios(devinit), Preg, &info))
+ return;
+
+ Pval2 = pv->log2P + info.bias_p;
+ if (Pval2 > info.max_p)
+ Pval2 = info.max_p;
+ Pval |= 1 << 28 | Pval2 << 20;
+
+ saved4600 = nv_rd32(devinit, 0x4600);
+ nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
+ }
+ if (single_stage)
+ Pval |= mpll ? 1 << 12 : 1 << 8;
+
+ nv_wr32(devinit, Preg, oldPval | 1 << 28);
+ nv_wr32(devinit, Preg, Pval & ~(4 << 28));
+ if (mpll) {
+ Pval |= 8 << 20;
+ nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
+ nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
+ }
+
+ savedc040 = nv_rd32(devinit, 0xc040);
+ nv_wr32(devinit, 0xc040, savedc040 & maskc040);
+
+ nv_wr32(devinit, NMNMreg, NMNM);
+ if (NMNMreg == 0x4024)
+ nv_wr32(devinit, 0x403c, NMNM);
+
+ nv_wr32(devinit, Preg, Pval);
+ if (mpll) {
+ Pval &= ~(8 << 20);
+ nv_wr32(devinit, 0x4020, Pval);
+ nv_wr32(devinit, 0x4038, Pval);
+ nv_wr32(devinit, 0x4600, saved4600);
+ }
+
+ nv_wr32(devinit, 0xc040, savedc040);
+
+ if (mpll) {
+ nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
+ nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
+ }
+}
+
+int
+nv04_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
+{
+ struct nouveau_bios *bios = nouveau_bios(devinit);
+ struct nouveau_pll_vals pv;
+ struct nvbios_pll info;
+ int cv = bios->version.chip;
+ int N1, M1, N2, M2, P;
int ret;
- ret = nouveau_devinit_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
+ ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
if (ret)
return ret;
- priv->base.meminit = nv04_devinit_meminit;
- priv->owner = -1;
+ ret = nv04_pll_calc(nv_subdev(devinit), &info, freq,
+ &N1, &M1, &N2, &M2, &P);
+ if (!ret)
+ return -EINVAL;
+
+ pv.refclk = info.refclk;
+ pv.N1 = N1;
+ pv.M1 = M1;
+ pv.N2 = N2;
+ pv.M2 = M2;
+ pv.log2P = P;
+
+ if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
+ cv >= 0x40) {
+ if (type > 0x405c)
+ setPLL_double_highregs(devinit, type, &pv);
+ else
+ setPLL_double_lowregs(devinit, type, &pv);
+ } else
+ setPLL_single(devinit, type, &pv);
+
return 0;
}
-void
-nv04_devinit_dtor(struct nouveau_object *object)
+int
+nv04_devinit_fini(struct nouveau_object *object, bool suspend)
{
struct nv04_devinit_priv *priv = (void *)object;
- /* restore vga owner saved at first init, and lock crtc regs */
- nv_wrvgaowner(priv, priv->owner);
- nv_lockvgac(priv, true);
+ /* make i2c busses accessible */
+ nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
- nouveau_devinit_destroy(&priv->base);
+ /* unlock extended vga crtc regs, and unslave crtcs */
+ nv_lockvgac(priv, false);
+ if (priv->owner < 0)
+ priv->owner = nv_rdvgaowner(priv);
+ nv_wrvgaowner(priv, 0);
+
+ return nouveau_devinit_fini(&priv->base, suspend);
}
int
@@ -160,21 +425,35 @@ nv04_devinit_init(struct nouveau_object *object)
return nouveau_devinit_init(&priv->base);
}
-int
-nv04_devinit_fini(struct nouveau_object *object, bool suspend)
+void
+nv04_devinit_dtor(struct nouveau_object *object)
{
struct nv04_devinit_priv *priv = (void *)object;
- /* make i2c busses accessible */
- nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
+ /* restore vga owner saved at first init, and lock crtc regs */
+ nv_wrvgaowner(priv, priv->owner);
+ nv_lockvgac(priv, true);
- /* unlock extended vga crtc regs, and unslave crtcs */
- nv_lockvgac(priv, false);
- if (priv->owner < 0)
- priv->owner = nv_rdvgaowner(priv);
- nv_wrvgaowner(priv, 0);
+ nouveau_devinit_destroy(&priv->base);
+}
- return nouveau_devinit_fini(&priv->base, suspend);
+static int
+nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv04_devinit_priv *priv;
+ int ret;
+
+ ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.meminit = nv04_devinit_meminit;
+ priv->base.pll_set = nv04_devinit_pll_set;
+ priv->owner = -1;
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
index 191447d0d252..b1912a8a8942 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
@@ -24,12 +24,12 @@
*
*/
-#include <subdev/devinit.h>
#include <subdev/bios.h>
#include <subdev/bios/bmp.h>
#include <subdev/vga.h>
#include "fbmem.h"
+#include "priv.h"
struct nv05_devinit_priv {
struct nouveau_devinit base;
@@ -144,6 +144,7 @@ nv05_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.meminit = nv05_devinit_meminit;
+ priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
index eb76ffab6b0c..463b08fa0968 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
@@ -24,10 +24,10 @@
*
*/
-#include <subdev/devinit.h>
#include <subdev/vga.h>
#include "fbmem.h"
+#include "priv.h"
struct nv10_devinit_priv {
struct nouveau_devinit base;
@@ -109,6 +109,7 @@ nv10_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.meminit = nv10_devinit_meminit;
+ priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
index 5b2ba630d913..e9743cdabe75 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
@@ -22,8 +22,7 @@
* Authors: Ben Skeggs
*/
-#include <subdev/devinit.h>
-#include <subdev/vga.h>
+#include "priv.h"
struct nv1a_devinit_priv {
struct nouveau_devinit base;
@@ -43,6 +42,7 @@ nv1a_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
+ priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
index eb32e99005e4..6cc6080d3bc0 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
@@ -24,9 +24,7 @@
*
*/
-#include <subdev/devinit.h>
-#include <subdev/vga.h>
-
+#include "priv.h"
#include "fbmem.h"
struct nv20_devinit_priv {
@@ -81,6 +79,7 @@ nv20_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.meminit = nv20_devinit_meminit;
+ priv->base.pll_set = nv04_devinit_pll_set;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
index 4a8577838417..6df72247c477 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2012 Red Hat Inc.
+ * Copyright 2013 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -26,37 +26,55 @@
#include <subdev/bios/dcb.h>
#include <subdev/bios/disp.h>
#include <subdev/bios/init.h>
-#include <subdev/devinit.h>
#include <subdev/vga.h>
-struct nv50_devinit_priv {
- struct nouveau_devinit base;
-};
+#include "priv.h"
static int
-nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
+nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
{
- struct nv50_devinit_priv *priv;
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ struct nouveau_bios *bios = nouveau_bios(priv);
+ struct nvbios_pll info;
+ int N1, M1, N2, M2, P;
int ret;
- ret = nouveau_devinit_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
+ ret = nvbios_pll_parse(bios, type, &info);
+ if (ret) {
+ nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
return ret;
+ }
- return 0;
-}
+ ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P);
+ if (!ret) {
+ nv_error(devinit, "failed pll calculation\n");
+ return ret;
+ }
-static void
-nv50_devinit_dtor(struct nouveau_object *object)
-{
- struct nv50_devinit_priv *priv = (void *)object;
- nouveau_devinit_destroy(&priv->base);
+ switch (info.type) {
+ case PLL_VPLL0:
+ case PLL_VPLL1:
+ nv_wr32(priv, info.reg + 0, 0x10000611);
+ nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
+ nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) |
+ (M2 << 16) | N2);
+ break;
+ case PLL_MEMORY:
+ nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
+ (info.bias_p << 19) |
+ (P << 16));
+ nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+ break;
+ default:
+ nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
+ nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+ break;
+ }
+
+ return 0;
}
-static int
+int
nv50_devinit_init(struct nouveau_object *object)
{
struct nouveau_bios *bios = nouveau_bios(object);
@@ -103,10 +121,20 @@ nv50_devinit_init(struct nouveau_object *object)
}
static int
-nv50_devinit_fini(struct nouveau_object *object, bool suspend)
+nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
{
- struct nv50_devinit_priv *priv = (void *)object;
- return nouveau_devinit_fini(&priv->base, suspend);
+ struct nv50_devinit_priv *priv;
+ int ret;
+
+ ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.pll_set = nv50_devinit_pll_set;
+ return 0;
}
struct nouveau_oclass
@@ -114,8 +142,8 @@ nv50_devinit_oclass = {
.handle = NV_SUBDEV(DEVINIT, 0x50),
.ofuncs = &(struct nouveau_ofuncs) {
.ctor = nv50_devinit_ctor,
- .dtor = nv50_devinit_dtor,
+ .dtor = _nouveau_devinit_dtor,
.init = nv50_devinit_init,
- .fini = nv50_devinit_fini,
+ .fini = _nouveau_devinit_fini,
},
};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
new file mode 100644
index 000000000000..76a68b290141
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
+{
+ struct nva3_devinit_priv *priv = (void *)devinit;
+ struct nouveau_bios *bios = nouveau_bios(priv);
+ struct nvbios_pll info;
+ int N, fN, M, P;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, type, &info);
+ if (ret)
+ return ret;
+
+ ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+ if (ret < 0)
+ return ret;
+
+ switch (info.type) {
+ case PLL_VPLL0:
+ case PLL_VPLL1:
+ nv_wr32(priv, info.reg + 0, 0x50000610);
+ nv_mask(priv, info.reg + 4, 0x003fffff,
+ (P << 16) | (M << 8) | N);
+ nv_wr32(priv, info.reg + 8, fN);
+ break;
+ default:
+ nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+nva3_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv50_devinit_priv *priv;
+ int ret;
+
+ ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.pll_set = nva3_devinit_pll_set;
+ return 0;
+}
+
+struct nouveau_oclass
+nva3_devinit_oclass = {
+ .handle = NV_SUBDEV(DEVINIT, 0xa3),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nva3_devinit_ctor,
+ .dtor = _nouveau_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nouveau_devinit_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
new file mode 100644
index 000000000000..19e265bf4574
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
+{
+ struct nvc0_devinit_priv *priv = (void *)devinit;
+ struct nouveau_bios *bios = nouveau_bios(priv);
+ struct nvbios_pll info;
+ int N, fN, M, P;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, type, &info);
+ if (ret)
+ return ret;
+
+ ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+ if (ret < 0)
+ return ret;
+
+ switch (info.type) {
+ case PLL_VPLL0:
+ case PLL_VPLL1:
+ case PLL_VPLL2:
+ case PLL_VPLL3:
+ nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
+ nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
+ nv_wr32(priv, info.reg + 0x10, fN << 16);
+ break;
+ default:
+ nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nv50_devinit_priv *priv;
+ int ret;
+
+ ret = nouveau_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.pll_set = nvc0_devinit_pll_set;
+ if (nv_rd32(priv, 0x022500) & 0x00000001)
+ priv->base.post = true;
+ return 0;
+}
+
+struct nouveau_oclass
+nvc0_devinit_oclass = {
+ .handle = NV_SUBDEV(DEVINIT, 0xc0),
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_devinit_ctor,
+ .dtor = _nouveau_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nouveau_devinit_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
new file mode 100644
index 000000000000..7d622e2b0171
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
@@ -0,0 +1,25 @@
+#ifndef __NVKM_DEVINIT_PRIV_H__
+#define __NVKM_DEVINIT_PRIV_H__
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clock/pll.h>
+#include <subdev/devinit.h>
+
+void nv04_devinit_dtor(struct nouveau_object *);
+int nv04_devinit_init(struct nouveau_object *);
+int nv04_devinit_fini(struct nouveau_object *, bool);
+int nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
+
+void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+
+
+struct nv50_devinit_priv {
+ struct nouveau_devinit base;
+};
+
+int nv50_devinit_init(struct nouveau_object *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
index d62045f454b2..821cd75b86a3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
@@ -57,7 +57,57 @@ nouveau_fb_bios_memtype(struct nouveau_bios *bios)
}
int
-nouveau_fb_preinit(struct nouveau_fb *pfb)
+_nouveau_fb_fini(struct nouveau_object *object, bool suspend)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ int ret;
+
+ ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
+ if (ret && suspend)
+ return ret;
+
+ return nouveau_subdev_fini(&pfb->base, suspend);
+}
+
+int
+_nouveau_fb_init(struct nouveau_object *object)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ int ret, i;
+
+ ret = nouveau_subdev_init(&pfb->base);
+ if (ret)
+ return ret;
+
+ ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
+
+ return 0;
+}
+
+void
+_nouveau_fb_dtor(struct nouveau_object *object)
+{
+ struct nouveau_fb *pfb = (void *)object;
+ int i;
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
+ nouveau_mm_fini(&pfb->tags);
+ nouveau_mm_fini(&pfb->vram);
+
+ nouveau_object_ref(NULL, (struct nouveau_object **)&pfb->ram);
+ nouveau_subdev_destroy(&pfb->base);
+}
+
+int
+nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, struct nouveau_oclass *ramcls,
+ int length, void **pobject)
{
static const char *name[] = {
[NV_MEM_TYPE_UNKNOWN] = "unknown",
@@ -72,69 +122,42 @@ nouveau_fb_preinit(struct nouveau_fb *pfb)
[NV_MEM_TYPE_GDDR4 ] = "GDDR4",
[NV_MEM_TYPE_GDDR5 ] = "GDDR5",
};
- int ret, tags;
+ struct nouveau_object *ram;
+ struct nouveau_fb *pfb;
+ int ret;
- tags = pfb->ram.init(pfb);
- if (tags < 0 || !pfb->ram.size) {
+ ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
+ length, pobject);
+ pfb = *pobject;
+ if (ret)
+ return ret;
+
+ ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb),
+ ramcls, NULL, 0, &ram);
+ if (ret) {
nv_fatal(pfb, "error detecting memory configuration!!\n");
- return (tags < 0) ? tags : -ERANGE;
+ return ret;
}
+ atomic_dec(&ram->parent->refcount);
+ atomic_dec(&ram->engine->refcount);
+ pfb->ram = (void *)ram;
+
if (!nouveau_mm_initialised(&pfb->vram)) {
- ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram.size >> 12, 1);
+ ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
if (ret)
return ret;
}
if (!nouveau_mm_initialised(&pfb->tags)) {
- ret = nouveau_mm_init(&pfb->tags, 0, tags ? ++tags : 0, 1);
+ ret = nouveau_mm_init(&pfb->tags, 0, pfb->ram->tags ?
+ ++pfb->ram->tags : 0, 1);
if (ret)
return ret;
}
- nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]);
- nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20));
- nv_info(pfb, " ZCOMP: %d tags\n", tags);
+ nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
+ nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
+ nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags);
return 0;
}
-
-void
-nouveau_fb_destroy(struct nouveau_fb *pfb)
-{
- int i;
-
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
- nouveau_mm_fini(&pfb->tags);
- nouveau_mm_fini(&pfb->vram);
-
- nouveau_subdev_destroy(&pfb->base);
-}
-
-void
-_nouveau_fb_dtor(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- nouveau_fb_destroy(pfb);
-}
-int
-nouveau_fb_init(struct nouveau_fb *pfb)
-{
- int ret, i;
-
- ret = nouveau_subdev_init(&pfb->base);
- if (ret)
- return ret;
-
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
-
- return 0;
-}
-
-int
-_nouveau_fb_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- return nouveau_fb_init(pfb);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
index 6e369f85361e..1f103c7b89fa 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
@@ -22,24 +22,8 @@
* Authors: Ben Skeggs
*/
-#include <subdev/fb.h>
+#include "priv.h"
-#define NV04_PFB_BOOT_0 0x00100000
-# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
-# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
-# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
-# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
-# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
#define NV04_PFB_CFG0 0x00100200
struct nv04_fb_priv {
@@ -56,37 +40,6 @@ nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
}
static int
-nv04_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
- if (boot0 & 0x00000100) {
- pfb->ram.size = ((boot0 >> 12) & 0xf) * 2 + 2;
- pfb->ram.size *= 1024 * 1024;
- } else {
- switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
- case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
- pfb->ram.size = 32 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
- pfb->ram.size = 16 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
- pfb->ram.size = 8 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
- pfb->ram.size = 4 * 1024 * 1024;
- break;
- }
- }
-
- if ((boot0 & 0x00000038) <= 0x10)
- pfb->ram.type = NV_MEM_TYPE_SGRAM;
- else
- pfb->ram.type = NV_MEM_TYPE_SDRAM;
- return 0;
-}
-
-static int
nv04_fb_init(struct nouveau_object *object)
{
struct nv04_fb_priv *priv = (void *)object;
@@ -112,14 +65,13 @@ nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv04_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv04_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv04_fb_vram_init;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
index edbbe26e858d..be069b5306b6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
@@ -24,25 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv10_fb_priv {
struct nouveau_fb base;
};
-static int
-nv10_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 cfg0 = nv_rd32(pfb, 0x100200);
- if (cfg0 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
- else
- pfb->ram.type = NV_MEM_TYPE_SDRAM;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
void
nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
@@ -78,18 +65,17 @@ nv10_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv10_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv10_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv10_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv10_fb_tile_init;
priv->base.tile.fini = nv10_fb_tile_fini;
priv->base.tile.prog = nv10_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
index 48366841db4a..57a2af0079b3 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
@@ -24,38 +24,13 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv1a_fb_priv {
struct nouveau_fb base;
};
static int
-nv1a_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct pci_dev *bridge;
- u32 mem, mib;
-
- bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
- if (!bridge) {
- nv_fatal(pfb, "no bridge device\n");
- return -ENODEV;
- }
-
- if (nv_device(pfb)->chipset == 0x1a) {
- pci_read_config_dword(bridge, 0x7c, &mem);
- mib = ((mem >> 6) & 31) + 1;
- } else {
- pci_read_config_dword(bridge, 0x84, &mem);
- mib = ((mem >> 4) & 127) + 1;
- }
-
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- pfb->ram.size = mib * 1024 * 1024;
- return 0;
-}
-
-static int
nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -63,18 +38,17 @@ nv1a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv1a_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv1a_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv1a_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv10_fb_tile_init;
priv->base.tile.fini = nv10_fb_tile_fini;
priv->base.tile.prog = nv10_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
index 5d14612a2c8e..b18c4e63bb47 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
@@ -24,29 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv20_fb_priv {
struct nouveau_fb base;
};
-int
-nv20_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
-
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: pfb->ram.type = NV_MEM_TYPE_GDDR2; break;
- }
- pfb->ram.size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
-
- return nv_rd32(pfb, 0x100320);
-}
-
void
nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
@@ -65,7 +48,7 @@ nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
else tile->zcomp = 0x04000000; /* Z24S8 */
@@ -105,19 +88,18 @@ nv20_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv20_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv20_fb_tile_init;
priv->base.tile.comp = nv20_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
index 0042ace6bef9..32ccabf10c45 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv25_fb_priv {
struct nouveau_fb base;
@@ -35,7 +35,7 @@ nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
else tile->zcomp = 0x00200000; /* Z24S8 */
@@ -54,19 +54,18 @@ nv25_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv25_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv20_fb_tile_init;
priv->base.tile.comp = nv25_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
index a7ba0d048aec..bef756d43d33 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv30_fb_priv {
struct nouveau_fb base;
@@ -54,7 +54,7 @@ nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
else tile->zcomp |= 0x02000000; /* Z24S8 */
@@ -132,19 +132,18 @@ nv30_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv30_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv30_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
index 092f6f4f3521..097d8e3824f2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv35_fb_priv {
struct nouveau_fb base;
@@ -35,7 +35,7 @@ nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
else tile->zcomp |= 0x08000000; /* Z24S8 */
@@ -55,19 +55,18 @@ nv35_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv35_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv35_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
index 797ab3b821b9..9d6d9df896d9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv36_fb_priv {
struct nouveau_fb base;
@@ -35,7 +35,7 @@ nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
if (!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
else tile->zcomp |= 0x20000000; /* Z24S8 */
@@ -55,19 +55,18 @@ nv36_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv36_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv20_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv20_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv36_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
index 65e131b90f37..33b4393a7829 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
@@ -24,34 +24,18 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv40_fb_priv {
struct nouveau_fb base;
};
-static int
-nv40_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
- }
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
void
nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
struct nouveau_fb_tile *tile)
{
u32 tiles = DIV_ROUND_UP(size, 0x80);
- u32 tags = round_up(tiles / pfb->ram.parts, 0x100);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x100);
if ( (flags & 2) &&
!nouveau_mm_head(&pfb->tags, 1, tags, tags, 1, &tile->tag)) {
tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
@@ -85,19 +69,18 @@ nv40_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv40_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv40_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv40_fb_vram_init;
priv->base.tile.regions = 8;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv20_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
index e9e5a08c41a1..02cd83789cd4 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
@@ -24,28 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv41_fb_priv {
struct nouveau_fb base;
};
-int
-nv41_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- if (pfb474 & 0x00000004)
- pfb->ram.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
void
nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
{
@@ -78,19 +62,18 @@ nv41_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv41_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv41_fb_vram_init;
priv->base.tile.regions = 12;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
index ae89b5006f7a..c5246c29f293 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
@@ -24,27 +24,12 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv44_fb_priv {
struct nouveau_fb base;
};
-int
-nv44_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- if (pfb474 & 0x00000004)
- pfb->ram.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- pfb->ram.type = NV_MEM_TYPE_DDR1;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
static void
nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
u32 flags, struct nouveau_fb_tile *tile)
@@ -87,18 +72,17 @@ nv44_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv44_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv44_fb_vram_init;
priv->base.tile.regions = 12;
priv->base.tile.init = nv44_fb_tile_init;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
index 589b93ea2994..e2b57909bfca 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv46_fb_priv {
struct nouveau_fb base;
@@ -52,18 +52,17 @@ nv46_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv46_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv44_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv44_fb_vram_init;
priv->base.tile.regions = 15;
priv->base.tile.init = nv46_fb_tile_init;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
index 818bba35b368..fe6a2278621d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
@@ -24,7 +24,7 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv47_fb_priv {
struct nouveau_fb base;
@@ -38,19 +38,18 @@ nv47_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv47_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv41_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv41_fb_vram_init;
priv->base.tile.regions = 15;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
index 84a31af16ab4..5eca99b8c7e2 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
@@ -24,30 +24,13 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv49_fb_priv {
struct nouveau_fb base;
};
static int
-nv49_fb_vram_init(struct nouveau_fb *pfb)
-{
- u32 pfb914 = nv_rd32(pfb, 0x100914);
-
- switch (pfb914 & 0x00000003) {
- case 0x00000000: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000001: pfb->ram.type = NV_MEM_TYPE_DDR2; break;
- case 0x00000002: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000003: break;
- }
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- return nv_rd32(pfb, 0x100320);
-}
-
-static int
nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -55,20 +38,18 @@ nv49_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv49_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv49_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv49_fb_vram_init;
priv->base.tile.regions = 15;
priv->base.tile.init = nv30_fb_tile_init;
priv->base.tile.comp = nv40_fb_tile_comp;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv41_fb_tile_prog;
-
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
index 797fd558170b..1190b78a1e91 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
@@ -24,21 +24,13 @@
*
*/
-#include <subdev/fb.h>
+#include "priv.h"
struct nv4e_fb_priv {
struct nouveau_fb base;
};
static int
-nv4e_fb_vram_init(struct nouveau_fb *pfb)
-{
- pfb->ram.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- return 0;
-}
-
-static int
nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
struct nouveau_object **pobject)
@@ -46,18 +38,17 @@ nv4e_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv4e_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv4e_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nv04_fb_memtype_valid;
- priv->base.ram.init = nv4e_fb_vram_init;
priv->base.tile.regions = 12;
priv->base.tile.init = nv46_fb_tile_init;
priv->base.tile.fini = nv20_fb_tile_fini;
priv->base.tile.prog = nv44_fb_tile_prog;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index 0772ec978165..da614ec5564b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -27,7 +27,7 @@
#include <core/engctx.h>
#include <core/object.h>
-#include <subdev/fb.h>
+#include "priv.h"
#include <subdev/bios.h>
struct nv50_fb_priv {
@@ -36,7 +36,8 @@ struct nv50_fb_priv {
dma_addr_t r100c08;
};
-static int types[0x80] = {
+int
+nv50_fb_memtype[0x80] = {
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
@@ -50,192 +51,7 @@ static int types[0x80] = {
static bool
nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
{
- return types[(memtype & 0xff00) >> 8] != 0;
-}
-
-static u32
-nv50_fb_vram_rblock(struct nouveau_fb *pfb)
-{
- int i, parts, colbits, rowbitsa, rowbitsb, banks;
- u64 rowsize, predicted;
- u32 r0, r4, rt, ru, rblock_size;
-
- r0 = nv_rd32(pfb, 0x100200);
- r4 = nv_rd32(pfb, 0x100204);
- rt = nv_rd32(pfb, 0x100250);
- ru = nv_rd32(pfb, 0x001540);
- nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
-
- for (i = 0, parts = 0; i < 8; i++) {
- if (ru & (0x00010000 << i))
- parts++;
- }
-
- colbits = (r4 & 0x0000f000) >> 12;
- rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
- rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
- banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
-
- rowsize = parts * banks * (1 << colbits) * 8;
- predicted = rowsize << rowbitsa;
- if (r0 & 0x00000004)
- predicted += rowsize << rowbitsb;
-
- if (predicted != pfb->ram.size) {
- nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
- (u32)(pfb->ram.size >> 20));
- }
-
- rblock_size = rowsize;
- if (rt & 1)
- rblock_size *= 3;
-
- nv_debug(pfb, "rblock %d bytes\n", rblock_size);
- return rblock_size;
-}
-
-static int
-nv50_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nouveau_bios *bios = nouveau_bios(device);
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 size, tags = 0;
- int ret;
-
- pfb->ram.size = nv_rd32(pfb, 0x10020c);
- pfb->ram.size = (pfb->ram.size & 0xffffff00) |
- ((pfb->ram.size & 0x000000ff) << 32);
-
- size = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
- switch (device->chipset) {
- case 0xaa:
- case 0xac:
- case 0xaf: /* IGPs, no reordering, no real VRAM */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
- if (ret)
- return ret;
-
- pfb->ram.type = NV_MEM_TYPE_STOLEN;
- pfb->ram.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
- break;
- default:
- switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
- case 0: pfb->ram.type = NV_MEM_TYPE_DDR1; break;
- case 1:
- if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
- pfb->ram.type = NV_MEM_TYPE_DDR3;
- else
- pfb->ram.type = NV_MEM_TYPE_DDR2;
- break;
- case 2: pfb->ram.type = NV_MEM_TYPE_GDDR3; break;
- case 3: pfb->ram.type = NV_MEM_TYPE_GDDR4; break;
- case 4: pfb->ram.type = NV_MEM_TYPE_GDDR5; break;
- default:
- break;
- }
-
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
- nv50_fb_vram_rblock(pfb) >> 12);
- if (ret)
- return ret;
-
- pfb->ram.ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
- tags = nv_rd32(pfb, 0x100320);
- break;
- }
-
- return tags;
-}
-
-static int
-nv50_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct nv50_fb_priv *priv = (void *)pfb;
- struct nouveau_mm *heap = &priv->base.vram;
- struct nouveau_mm *tags = &priv->base.tags;
- struct nouveau_mm_node *r;
- struct nouveau_mem *mem;
- int comp = (memtype & 0x300) >> 8;
- int type = (memtype & 0x07f);
- int back = (memtype & 0x800);
- int min, max, ret;
-
- max = (size >> 12);
- min = ncmin ? (ncmin >> 12) : max;
- align >>= 12;
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- mutex_lock(&pfb->base.mutex);
- if (comp) {
- if (align == 16) {
- int n = (max >> 4) * comp;
-
- ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
- if (ret)
- mem->tag = NULL;
- }
-
- if (unlikely(!mem->tag))
- comp = 0;
- }
-
- INIT_LIST_HEAD(&mem->regions);
- mem->memtype = (comp << 7) | type;
- mem->size = max;
-
- type = types[type];
- do {
- if (back)
- ret = nouveau_mm_tail(heap, type, max, min, align, &r);
- else
- ret = nouveau_mm_head(heap, type, max, min, align, &r);
- if (ret) {
- mutex_unlock(&pfb->base.mutex);
- pfb->ram.put(pfb, &mem);
- return ret;
- }
-
- list_add_tail(&r->rl_entry, &mem->regions);
- max -= r->length;
- } while (max);
- mutex_unlock(&pfb->base.mutex);
-
- r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
- mem->offset = (u64)r->offset << 12;
- *pmem = mem;
- return 0;
-}
-
-void
-nv50_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct nv50_fb_priv *priv = (void *)pfb;
- struct nouveau_mm_node *this;
- struct nouveau_mem *mem;
-
- mem = *pmem;
- *pmem = NULL;
- if (unlikely(mem == NULL))
- return;
-
- mutex_lock(&pfb->base.mutex);
- while (!list_empty(&mem->regions)) {
- this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
-
- list_del(&this->rl_entry);
- nouveau_mm_free(&priv->base.vram, &this);
- }
-
- nouveau_mm_free(&priv->base.tags, &mem->tag);
- mutex_unlock(&pfb->base.mutex);
-
- kfree(mem);
+ return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
}
static const struct nouveau_enum vm_dispatch_subclients[] = {
@@ -432,7 +248,7 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nv50_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nv50_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
@@ -449,11 +265,8 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
}
priv->base.memtype_valid = nv50_fb_memtype_valid;
- priv->base.ram.init = nv50_fb_vram_init;
- priv->base.ram.get = nv50_fb_vram_new;
- priv->base.ram.put = nv50_fb_vram_del;
nv_subdev(priv)->intr = nv50_fb_intr;
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
static void
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
index 86ad59203c8b..f35d76fd746d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
@@ -22,9 +22,7 @@
* Authors: Ben Skeggs
*/
-#include <subdev/fb.h>
-#include <subdev/ltcg.h>
-#include <subdev/bios.h>
+#include "priv.h"
struct nvc0_fb_priv {
struct nouveau_fb base;
@@ -34,7 +32,6 @@ struct nvc0_fb_priv {
extern const u8 nvc0_pte_storage_type_map[256];
-
static bool
nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
{
@@ -43,137 +40,6 @@ nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
}
static int
-nvc0_fb_vram_init(struct nouveau_fb *pfb)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 parts = nv_rd32(pfb, 0x022438);
- u32 pmask = nv_rd32(pfb, 0x022554);
- u32 bsize = nv_rd32(pfb, 0x10f20c);
- u32 offset, length;
- bool uniform = true;
- int ret, part;
-
- nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
- nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
-
- pfb->ram.type = nouveau_fb_bios_memtype(bios);
- pfb->ram.ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
-
- /* read amount of vram attached to each memory controller */
- for (part = 0; part < parts; part++) {
- if (!(pmask & (1 << part))) {
- u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
- if (psize != bsize) {
- if (psize < bsize)
- bsize = psize;
- uniform = false;
- }
-
- nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
- pfb->ram.size += (u64)psize << 20;
- }
- }
-
- /* if all controllers have the same amount attached, there's no holes */
- if (uniform) {
- offset = rsvd_head;
- length = (pfb->ram.size >> 12) - rsvd_head - rsvd_tail;
- return nouveau_mm_init(&pfb->vram, offset, length, 1);
- }
-
- /* otherwise, address lowest common amount from 0GiB */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, (bsize << 8) * parts, 1);
- if (ret)
- return ret;
-
- /* and the rest starting from (8GiB + common_size) */
- offset = (0x0200000000ULL >> 12) + (bsize << 8);
- length = (pfb->ram.size >> 12) - (bsize << 8) - rsvd_tail;
-
- ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
- if (ret) {
- nouveau_mm_fini(&pfb->vram);
- return ret;
- }
-
- return 0;
-}
-
-static int
-nvc0_fb_vram_new(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct nouveau_mm *mm = &pfb->vram;
- struct nouveau_mm_node *r;
- struct nouveau_mem *mem;
- int type = (memtype & 0x0ff);
- int back = (memtype & 0x800);
- int ret;
- const bool comp = nvc0_pte_storage_type_map[type] != type;
-
- size >>= 12;
- align >>= 12;
- ncmin >>= 12;
- if (!ncmin)
- ncmin = size;
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&mem->regions);
- mem->size = size;
-
- mutex_lock(&pfb->base.mutex);
- if (comp) {
- struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent);
-
- /* compression only works with lpages */
- if (align == (1 << (17 - 12))) {
- int n = size >> 5;
- ltcg->tags_alloc(ltcg, n, &mem->tag);
- }
- if (unlikely(!mem->tag))
- type = nvc0_pte_storage_type_map[type];
- }
- mem->memtype = type;
-
- do {
- if (back)
- ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
- else
- ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
- if (ret) {
- mutex_unlock(&pfb->base.mutex);
- pfb->ram.put(pfb, &mem);
- return ret;
- }
-
- list_add_tail(&r->rl_entry, &mem->regions);
- size -= r->length;
- } while (size);
- mutex_unlock(&pfb->base.mutex);
-
- r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
- mem->offset = (u64)r->offset << 12;
- *pmem = mem;
- return 0;
-}
-
-static void
-nvc0_fb_vram_del(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb->base.base.parent);
-
- if ((*pmem)->tag)
- ltcg->tags_free(ltcg, &(*pmem)->tag);
-
- nv50_fb_vram_del(pfb, pmem);
-}
-
-static int
nvc0_fb_init(struct nouveau_object *object)
{
struct nvc0_fb_priv *priv = (void *)object;
@@ -212,15 +78,12 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nvc0_fb_priv *priv;
int ret;
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
+ ret = nouveau_fb_create(parent, engine, oclass, &nvc0_ram_oclass, &priv);
*pobject = nv_object(priv);
if (ret)
return ret;
priv->base.memtype_valid = nvc0_fb_memtype_valid;
- priv->base.ram.init = nvc0_fb_vram_init;
- priv->base.ram.get = nvc0_fb_vram_new;
- priv->base.ram.put = nvc0_fb_vram_del;
priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
if (priv->r100c10_page) {
@@ -231,7 +94,7 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return -EFAULT;
}
- return nouveau_fb_preinit(&priv->base);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
new file mode 100644
index 000000000000..6c974dd83e8b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
@@ -0,0 +1,87 @@
+#ifndef __NVKM_FB_PRIV_H__
+#define __NVKM_FB_PRIV_H__
+
+#include <subdev/fb.h>
+
+#define nouveau_ram_create(p,e,o,d) \
+ nouveau_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
+#define nouveau_ram_destroy(p) \
+ nouveau_object_destroy(&(p)->base)
+#define nouveau_ram_init(p) \
+ nouveau_object_init(&(p)->base)
+#define nouveau_ram_fini(p,s) \
+ nouveau_object_fini(&(p)->base, (s))
+
+#define _nouveau_ram_dtor nouveau_object_destroy
+#define _nouveau_ram_init nouveau_object_init
+#define _nouveau_ram_fini nouveau_object_fini
+
+extern struct nouveau_oclass nv04_ram_oclass;
+extern struct nouveau_oclass nv10_ram_oclass;
+extern struct nouveau_oclass nv1a_ram_oclass;
+extern struct nouveau_oclass nv20_ram_oclass;
+extern struct nouveau_oclass nv40_ram_oclass;
+extern struct nouveau_oclass nv41_ram_oclass;
+extern struct nouveau_oclass nv44_ram_oclass;
+extern struct nouveau_oclass nv49_ram_oclass;
+extern struct nouveau_oclass nv4e_ram_oclass;
+extern struct nouveau_oclass nv50_ram_oclass;
+extern struct nouveau_oclass nvc0_ram_oclass;
+
+#define nouveau_fb_create(p,e,c,r,d) \
+ nouveau_fb_create_((p), (e), (c), (r), sizeof(**d), (void **)d)
+#define nouveau_fb_destroy(p) ({ \
+ struct nouveau_fb *pfb = (p); \
+ _nouveau_fb_dtor(nv_object(pfb)); \
+})
+#define nouveau_fb_init(p) ({ \
+ struct nouveau_fb *pfb = (p); \
+ _nouveau_fb_init(nv_object(pfb)); \
+})
+#define nouveau_fb_fini(p,s) ({ \
+ struct nouveau_fb *pfb = (p); \
+ _nouveau_fb_fini(nv_object(pfb), (s)); \
+})
+
+int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *,
+ struct nouveau_oclass *, struct nouveau_oclass *,
+ int length, void **pobject);
+void _nouveau_fb_dtor(struct nouveau_object *);
+int _nouveau_fb_init(struct nouveau_object *);
+int _nouveau_fb_fini(struct nouveau_object *, bool);
+
+struct nouveau_bios;
+int nouveau_fb_bios_memtype(struct nouveau_bios *);
+
+bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
+
+void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
+void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int nv30_fb_init(struct nouveau_object *);
+void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
+ struct nouveau_fb_tile *);
+
+int nv41_fb_init(struct nouveau_object *);
+void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+int nv44_fb_init(struct nouveau_object *);
+void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
+
+void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nouveau_fb_tile *);
+
+void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+extern int nv50_fb_memtype[0x80];
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
new file mode 100644
index 000000000000..e781080d3327
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NV04_PFB_BOOT_0 0x00100000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
+# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
+# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
+# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
+# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
+
+#include "priv.h"
+
+static int
+nv04_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (boot0 & 0x00000100) {
+ ram->size = ((boot0 >> 12) & 0xf) * 2 + 2;
+ ram->size *= 1024 * 1024;
+ } else {
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+ ram->size = 32 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+ ram->size = 16 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+ ram->size = 8 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+ ram->size = 4 * 1024 * 1024;
+ break;
+ }
+ }
+
+ if ((boot0 & 0x00000038) <= 0x10)
+ ram->type = NV_MEM_TYPE_SGRAM;
+ else
+ ram->type = NV_MEM_TYPE_SDRAM;
+ return 0;
+}
+
+struct nouveau_oclass
+nv04_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv04_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
new file mode 100644
index 000000000000..8311f3774edf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv10_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 cfg0 = nv_rd32(pfb, 0x100200);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (cfg0 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+ else
+ ram->type = NV_MEM_TYPE_SDRAM;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ return 0;
+}
+
+
+struct nouveau_oclass
+nv10_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv10_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
new file mode 100644
index 000000000000..d0caddfb9db0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv1a_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ struct pci_dev *bridge;
+ u32 mem, mib;
+ int ret;
+
+ bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+ if (!bridge) {
+ nv_fatal(pfb, "no bridge device\n");
+ return -ENODEV;
+ }
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (nv_device(pfb)->chipset == 0x1a) {
+ pci_read_config_dword(bridge, 0x7c, &mem);
+ mib = ((mem >> 6) & 31) + 1;
+ } else {
+ pci_read_config_dword(bridge, 0x84, &mem);
+ mib = ((mem >> 4) & 127) + 1;
+ }
+
+ ram->type = NV_MEM_TYPE_STOLEN;
+ ram->size = mib * 1024 * 1024;
+ return 0;
+}
+
+struct nouveau_oclass
+nv1a_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv1a_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
new file mode 100644
index 000000000000..fdc11bba226d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv20_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pbus1218 = nv_rd32(pfb, 0x001218);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
+ }
+ ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nouveau_oclass
+nv20_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv20_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
new file mode 100644
index 000000000000..ee49ac4dbdb6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pbus1218 = nv_rd32(pfb, 0x001218);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: ram->type = NV_MEM_TYPE_DDR2; break;
+ }
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+
+struct nouveau_oclass
+nv40_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv40_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
new file mode 100644
index 000000000000..1dab7e12abab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pfb474 = nv_rd32(pfb, 0x100474);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (pfb474 & 0x00000004)
+ ram->type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ ram->type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nouveau_oclass
+nv41_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv41_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
new file mode 100644
index 000000000000..25fff842e5c1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pfb474 = nv_rd32(pfb, 0x100474);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (pfb474 & 0x00000004)
+ ram->type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ ram->type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ return 0;
+}
+
+struct nouveau_oclass
+nv44_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv44_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
new file mode 100644
index 000000000000..19e3a9a63a02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ u32 pfb914 = nv_rd32(pfb, 0x100914);
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pfb914 & 0x00000003) {
+ case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break;
+ case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000003: break;
+ }
+
+ pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ pfb->ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nouveau_oclass
+nv49_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv49_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
new file mode 100644
index 000000000000..7192aa6e5577
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "priv.h"
+
+static int
+nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_ram *ram;
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ pfb->ram->type = NV_MEM_TYPE_STOLEN;
+ return 0;
+}
+
+struct nouveau_oclass
+nv4e_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv4e_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
new file mode 100644
index 000000000000..af5aa7ee8ad9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <core/mm.h>
+#include "priv.h"
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+ struct nouveau_mm_node *this;
+ struct nouveau_mem *mem;
+
+ mem = *pmem;
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
+
+ mutex_lock(&pfb->base.mutex);
+ while (!list_empty(&mem->regions)) {
+ this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
+
+ list_del(&this->rl_entry);
+ nouveau_mm_free(&pfb->vram, &this);
+ }
+
+ nouveau_mm_free(&pfb->tags, &mem->tag);
+ mutex_unlock(&pfb->base.mutex);
+
+ kfree(mem);
+}
+
+static int
+nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nouveau_mem **pmem)
+{
+ struct nouveau_mm *heap = &pfb->vram;
+ struct nouveau_mm *tags = &pfb->tags;
+ struct nouveau_mm_node *r;
+ struct nouveau_mem *mem;
+ int comp = (memtype & 0x300) >> 8;
+ int type = (memtype & 0x07f);
+ int back = (memtype & 0x800);
+ int min, max, ret;
+
+ max = (size >> 12);
+ min = ncmin ? (ncmin >> 12) : max;
+ align >>= 12;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ mutex_lock(&pfb->base.mutex);
+ if (comp) {
+ if (align == 16) {
+ int n = (max >> 4) * comp;
+
+ ret = nouveau_mm_head(tags, 1, n, n, 1, &mem->tag);
+ if (ret)
+ mem->tag = NULL;
+ }
+
+ if (unlikely(!mem->tag))
+ comp = 0;
+ }
+
+ INIT_LIST_HEAD(&mem->regions);
+ mem->memtype = (comp << 7) | type;
+ mem->size = max;
+
+ type = nv50_fb_memtype[type];
+ do {
+ if (back)
+ ret = nouveau_mm_tail(heap, type, max, min, align, &r);
+ else
+ ret = nouveau_mm_head(heap, type, max, min, align, &r);
+ if (ret) {
+ mutex_unlock(&pfb->base.mutex);
+ pfb->ram->put(pfb, &mem);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &mem->regions);
+ max -= r->length;
+ } while (max);
+ mutex_unlock(&pfb->base.mutex);
+
+ r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
+ mem->offset = (u64)r->offset << 12;
+ *pmem = mem;
+ return 0;
+}
+
+static u32
+nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
+{
+ int i, parts, colbits, rowbitsa, rowbitsb, banks;
+ u64 rowsize, predicted;
+ u32 r0, r4, rt, ru, rblock_size;
+
+ r0 = nv_rd32(pfb, 0x100200);
+ r4 = nv_rd32(pfb, 0x100204);
+ rt = nv_rd32(pfb, 0x100250);
+ ru = nv_rd32(pfb, 0x001540);
+ nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru);
+
+ for (i = 0, parts = 0; i < 8; i++) {
+ if (ru & (0x00010000 << i))
+ parts++;
+ }
+
+ colbits = (r4 & 0x0000f000) >> 12;
+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+ banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
+
+ rowsize = parts * banks * (1 << colbits) * 8;
+ predicted = rowsize << rowbitsa;
+ if (r0 & 0x00000004)
+ predicted += rowsize << rowbitsb;
+
+ if (predicted != ram->size) {
+ nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
+ (u32)(ram->size >> 20));
+ }
+
+ rblock_size = rowsize;
+ if (rt & 1)
+ rblock_size *= 3;
+
+ nv_debug(pfb, "rblock %d bytes\n", rblock_size);
+ return rblock_size;
+}
+
+static int
+nv50_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 datasize,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_device *device = nv_device(pfb);
+ struct nouveau_bios *bios = nouveau_bios(device);
+ struct nouveau_ram *ram;
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 size;
+ int ret;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ ram->size = nv_rd32(pfb, 0x10020c);
+ ram->size = (ram->size & 0xffffff00) |
+ ((ram->size & 0x000000ff) << 32);
+
+ size = (ram->size >> 12) - rsvd_head - rsvd_tail;
+ switch (device->chipset) {
+ case 0xaa:
+ case 0xac:
+ case 0xaf: /* IGPs, no reordering, no real VRAM */
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head, size, 1);
+ if (ret)
+ return ret;
+
+ ram->type = NV_MEM_TYPE_STOLEN;
+ ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+ break;
+ default:
+ switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
+ case 0: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 1:
+ if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+ ram->type = NV_MEM_TYPE_DDR3;
+ else
+ ram->type = NV_MEM_TYPE_DDR2;
+ break;
+ case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
+ case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
+ default:
+ break;
+ }
+
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head, size,
+ nv50_fb_vram_rblock(pfb, ram) >> 12);
+ if (ret)
+ return ret;
+
+ ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ break;
+ }
+
+ ram->get = nv50_ram_get;
+ ram->put = nv50_ram_put;
+ return 0;
+}
+
+struct nouveau_oclass
+nv50_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nv50_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
new file mode 100644
index 000000000000..9c3634acbb9d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/ltcg.h>
+
+#include "priv.h"
+
+extern const u8 nvc0_pte_storage_type_map[256];
+
+void
+nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+ struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+
+ if ((*pmem)->tag)
+ ltcg->tags_free(ltcg, &(*pmem)->tag);
+
+ nv50_ram_put(pfb, pmem);
+}
+
+int
+nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nouveau_mem **pmem)
+{
+ struct nouveau_mm *mm = &pfb->vram;
+ struct nouveau_mm_node *r;
+ struct nouveau_mem *mem;
+ int type = (memtype & 0x0ff);
+ int back = (memtype & 0x800);
+ const bool comp = nvc0_pte_storage_type_map[type] != type;
+ int ret;
+
+ size >>= 12;
+ align >>= 12;
+ ncmin >>= 12;
+ if (!ncmin)
+ ncmin = size;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&mem->regions);
+ mem->size = size;
+
+ mutex_lock(&pfb->base.mutex);
+ if (comp) {
+ struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+
+ /* compression only works with lpages */
+ if (align == (1 << (17 - 12))) {
+ int n = size >> 5;
+ ltcg->tags_alloc(ltcg, n, &mem->tag);
+ }
+
+ if (unlikely(!mem->tag))
+ type = nvc0_pte_storage_type_map[type];
+ }
+ mem->memtype = type;
+
+ do {
+ if (back)
+ ret = nouveau_mm_tail(mm, 1, size, ncmin, align, &r);
+ else
+ ret = nouveau_mm_head(mm, 1, size, ncmin, align, &r);
+ if (ret) {
+ mutex_unlock(&pfb->base.mutex);
+ pfb->ram->put(pfb, &mem);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &mem->regions);
+ size -= r->length;
+ } while (size);
+ mutex_unlock(&pfb->base.mutex);
+
+ r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
+ mem->offset = (u64)r->offset << 12;
+ *pmem = mem;
+ return 0;
+}
+
+static int
+nvc0_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
+ struct nouveau_oclass *oclass, void *data, u32 size,
+ struct nouveau_object **pobject)
+{
+ struct nouveau_fb *pfb = nouveau_fb(parent);
+ struct nouveau_bios *bios = nouveau_bios(pfb);
+ struct nouveau_ram *ram;
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 parts = nv_rd32(pfb, 0x022438);
+ u32 pmask = nv_rd32(pfb, 0x022554);
+ u32 bsize = nv_rd32(pfb, 0x10f20c);
+ u32 offset, length;
+ bool uniform = true;
+ int ret, part;
+
+ ret = nouveau_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
+ nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+ ram->type = nouveau_fb_bios_memtype(bios);
+ ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
+
+ /* read amount of vram attached to each memory controller */
+ for (part = 0; part < parts; part++) {
+ if (!(pmask & (1 << part))) {
+ u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
+ if (psize != bsize) {
+ if (psize < bsize)
+ bsize = psize;
+ uniform = false;
+ }
+
+ nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
+ ram->size += (u64)psize << 20;
+ }
+ }
+
+ /* if all controllers have the same amount attached, there's no holes */
+ if (uniform) {
+ offset = rsvd_head;
+ length = (ram->size >> 12) - rsvd_head - rsvd_tail;
+ ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
+ } else {
+ /* otherwise, address lowest common amount from 0GiB */
+ ret = nouveau_mm_init(&pfb->vram, rsvd_head,
+ (bsize << 8) * parts, 1);
+ if (ret)
+ return ret;
+
+ /* and the rest starting from (8GiB + common_size) */
+ offset = (0x0200000000ULL >> 12) + (bsize << 8);
+ length = (ram->size >> 12) - (bsize << 8) - rsvd_tail;
+
+ ret = nouveau_mm_init(&pfb->vram, offset, length, 0);
+ if (ret)
+ nouveau_mm_fini(&pfb->vram);
+ }
+
+ if (ret)
+ return ret;
+
+ ram->get = nvc0_ram_get;
+ ram->put = nvc0_ram_put;
+ return 0;
+}
+
+struct nouveau_oclass
+nvc0_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nouveau_ofuncs) {
+ .ctor = nvc0_ram_create,
+ .dtor = _nouveau_ram_dtor,
+ .init = _nouveau_ram_init,
+ .fini = _nouveau_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
index cfc7e31461de..97bc5dff93e7 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
@@ -56,7 +56,7 @@ nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (ret)
return ret;
- ret = pfb->ram.get(pfb, size, align, 0, 0x800, &node->mem);
+ ret = pfb->ram->get(pfb, size, align, 0, 0x800, &node->mem);
if (ret)
return ret;
@@ -71,7 +71,7 @@ nv50_instobj_dtor(struct nouveau_object *object)
{
struct nv50_instobj_priv *node = (void *)object;
struct nouveau_fb *pfb = nouveau_fb(object);
- pfb->ram.put(pfb, &node->mem);
+ pfb->ram->put(pfb, &node->mem);
nouveau_instobj_destroy(&node->base);
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
index fb794e997fbc..bcca883018f4 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
@@ -122,7 +122,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
nv_wr32(priv, 0x17e000, priv->part_nr);
/* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
- priv->num_tags = (pfb->ram.size >> 17) / 4;
+ priv->num_tags = (pfb->ram->size >> 17) / 4;
if (priv->num_tags > (1 << 17))
priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
index d796924f9930..0cb322a5e72c 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
@@ -35,6 +35,7 @@ nv50_mc_intr[] = {
{ 0x00001000, NVDEV_ENGINE_GR },
{ 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84- */
{ 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */
+ { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */
{ 0x00100000, NVDEV_SUBDEV_TIMER },
{ 0x00200000, NVDEV_SUBDEV_GPIO },
{ 0x04000000, NVDEV_ENGINE_DISP },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
index 737bd4b682e1..c5da3babbc62 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
@@ -33,6 +33,7 @@ nvc0_mc_intr[] = {
{ 0x00000001, NVDEV_ENGINE_PPP },
{ 0x00000020, NVDEV_ENGINE_COPY0 },
{ 0x00000040, NVDEV_ENGINE_COPY1 },
+ { 0x00000080, NVDEV_ENGINE_COPY2 },
{ 0x00000100, NVDEV_ENGINE_FIFO },
{ 0x00001000, NVDEV_ENGINE_GR },
{ 0x00008000, NVDEV_ENGINE_BSP },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
index 77c67fc970e6..67fcb6c852ac 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
@@ -236,9 +236,9 @@ nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde)
vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
}
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
nouveau_gpuobj_ref(NULL, &pgt);
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
}
}
@@ -256,18 +256,18 @@ nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type)
pgt_size = (1 << (vmm->pgt_bits + 12)) >> type;
pgt_size *= 8;
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000,
NVOBJ_FLAG_ZERO_ALLOC, &pgt);
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
if (unlikely(ret))
return ret;
/* someone beat us to filling the PDE while we didn't have the lock */
if (unlikely(vpgt->refcount[big]++)) {
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
nouveau_gpuobj_ref(NULL, &pgt);
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
return 0;
}
@@ -289,11 +289,11 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
u32 fpde, lpde, pde;
int ret;
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
ret = nouveau_mm_head(&vm->mm, page_shift, msize, msize, align,
&vma->node);
if (unlikely(ret != 0)) {
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
return ret;
}
@@ -314,13 +314,14 @@ nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
if (pde != fpde)
nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
nouveau_mm_free(&vm->mm, &vma->node);
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
return ret;
}
}
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
- vma->vm = vm;
+ vma->vm = NULL;
+ nouveau_vm_ref(vm, &vma->vm, NULL);
vma->offset = (u64)vma->node->offset << 12;
vma->access = access;
return 0;
@@ -338,10 +339,12 @@ nouveau_vm_put(struct nouveau_vma *vma)
fpde = (vma->node->offset >> vmm->pgt_bits);
lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde);
nouveau_mm_free(&vm->mm, &vma->node);
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
+
+ nouveau_vm_ref(NULL, &vma->vm, NULL);
}
int
@@ -362,7 +365,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
vm->fpde = offset >> (vmm->pgt_bits + 12);
vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
- vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL);
+ vm->pgt = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt));
if (!vm->pgt) {
kfree(vm);
return -ENOMEM;
@@ -371,7 +374,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
block >> 12);
if (ret) {
- kfree(vm->pgt);
+ vfree(vm->pgt);
kfree(vm);
return ret;
}
@@ -405,24 +408,25 @@ nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
nouveau_gpuobj_ref(pgd, &vpgd->obj);
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
for (i = vm->fpde; i <= vm->lpde; i++)
vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
list_add(&vpgd->head, &vm->pgd_list);
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
return 0;
}
static void
nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
{
+ struct nouveau_vmmgr *vmm = vm->vmm;
struct nouveau_vm_pgd *vpgd, *tmp;
struct nouveau_gpuobj *pgd = NULL;
if (!mpgd)
return;
- mutex_lock(&vm->mm.mutex);
+ mutex_lock(&nv_subdev(vmm)->mutex);
list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
if (vpgd->obj == mpgd) {
pgd = vpgd->obj;
@@ -431,7 +435,7 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
break;
}
}
- mutex_unlock(&vm->mm.mutex);
+ mutex_unlock(&nv_subdev(vmm)->mutex);
nouveau_gpuobj_ref(NULL, &pgd);
}
@@ -446,7 +450,7 @@ nouveau_vm_del(struct nouveau_vm *vm)
}
nouveau_mm_fini(&vm->mm);
- kfree(vm->pgt);
+ vfree(vm->pgt);
kfree(vm);
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
index e067f81c97b3..07dd1fe2d6fb 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
@@ -27,11 +27,11 @@
#include <subdev/timer.h>
#include <subdev/fb.h>
+#include <subdev/bar.h>
#include <subdev/vm.h>
struct nv50_vmmgr_priv {
struct nouveau_vmmgr base;
- spinlock_t lock;
};
static void
@@ -86,8 +86,8 @@ nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
/* IGPs don't have real VRAM, re-target to stolen system memory */
target = 0;
- if (nouveau_fb(vma->vm->vmm)->ram.stolen) {
- phys += nouveau_fb(vma->vm->vmm)->ram.stolen;
+ if (nouveau_fb(vma->vm->vmm)->ram->stolen) {
+ phys += nouveau_fb(vma->vm->vmm)->ram->stolen;
target = 3;
}
@@ -151,29 +151,42 @@ nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
static void
nv50_vm_flush(struct nouveau_vm *vm)
{
+ struct nv50_vmmgr_priv *priv = (void *)vm->vmm;
+ struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_engine *engine;
- int i;
+ int i, vme;
+
+ bar->flush(bar);
+ mutex_lock(&nv_subdev(priv)->mutex);
for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
- if (atomic_read(&vm->engref[i])) {
- engine = nouveau_engine(vm->vmm, i);
- if (engine && engine->tlb_flush)
- engine->tlb_flush(engine);
+ if (!atomic_read(&vm->engref[i]))
+ continue;
+
+ /* unfortunate hw bug workaround... */
+ engine = nouveau_engine(priv, i);
+ if (engine && engine->tlb_flush) {
+ engine->tlb_flush(engine);
+ continue;
}
- }
-}
-void
-nv50_vm_flush_engine(struct nouveau_subdev *subdev, int engine)
-{
- struct nv50_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- nv_wr32(subdev, 0x100c80, (engine << 16) | 1);
- if (!nv_wait(subdev, 0x100c80, 0x00000001, 0x00000000))
- nv_error(subdev, "vm flush timeout: engine %d\n", engine);
- spin_unlock_irqrestore(&priv->lock, flags);
+ switch (i) {
+ case NVDEV_ENGINE_GR : vme = 0x00; break;
+ case NVDEV_ENGINE_VP : vme = 0x01; break;
+ case NVDEV_SUBDEV_BAR : vme = 0x06; break;
+ case NVDEV_ENGINE_MPEG : vme = 0x08; break;
+ case NVDEV_ENGINE_BSP : vme = 0x09; break;
+ case NVDEV_ENGINE_CRYPT: vme = 0x0a; break;
+ case NVDEV_ENGINE_COPY0: vme = 0x0d; break;
+ default:
+ continue;
+ }
+
+ nv_wr32(priv, 0x100c80, (vme << 16) | 1);
+ if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+ nv_error(priv, "vm flush timeout: engine %d\n", vme);
+ }
+ mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
@@ -211,7 +224,6 @@ nv50_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->base.map_sg = nv50_vm_map_sg;
priv->base.unmap = nv50_vm_unmap;
priv->base.flush = nv50_vm_flush;
- spin_lock_init(&priv->lock);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
index 4c3b0a23b9d6..668cf964e4a9 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
@@ -29,10 +29,10 @@
#include <subdev/fb.h>
#include <subdev/vm.h>
#include <subdev/ltcg.h>
+#include <subdev/bar.h>
struct nvc0_vmmgr_priv {
struct nouveau_vmmgr base;
- spinlock_t lock;
};
@@ -160,40 +160,40 @@ nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
}
}
-void
-nvc0_vm_flush_engine(struct nouveau_subdev *subdev, u64 addr, int type)
-{
- struct nvc0_vmmgr_priv *priv = (void *)nouveau_vmmgr(subdev);
- unsigned long flags;
-
- /* looks like maybe a "free flush slots" counter, the
- * faster you write to 0x100cbc to more it decreases
- */
- spin_lock_irqsave(&priv->lock, flags);
- if (!nv_wait_ne(subdev, 0x100c80, 0x00ff0000, 0x00000000)) {
- nv_error(subdev, "vm timeout 0: 0x%08x %d\n",
- nv_rd32(subdev, 0x100c80), type);
- }
-
- nv_wr32(subdev, 0x100cb8, addr >> 8);
- nv_wr32(subdev, 0x100cbc, 0x80000000 | type);
-
- /* wait for flush to be queued? */
- if (!nv_wait(subdev, 0x100c80, 0x00008000, 0x00008000)) {
- nv_error(subdev, "vm timeout 1: 0x%08x %d\n",
- nv_rd32(subdev, 0x100c80), type);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
static void
nvc0_vm_flush(struct nouveau_vm *vm)
{
+ struct nvc0_vmmgr_priv *priv = (void *)vm->vmm;
+ struct nouveau_bar *bar = nouveau_bar(priv);
struct nouveau_vm_pgd *vpgd;
+ u32 type;
+
+ bar->flush(bar);
+
+ type = 0x00000001; /* PAGE_ALL */
+ if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR]))
+ type |= 0x00000004; /* HUB_ONLY */
+ mutex_lock(&nv_subdev(priv)->mutex);
list_for_each_entry(vpgd, &vm->pgd_list, head) {
- nvc0_vm_flush_engine(nv_subdev(vm->vmm), vpgd->obj->addr, 1);
+ /* looks like maybe a "free flush slots" counter, the
+ * faster you write to 0x100cbc to more it decreases
+ */
+ if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) {
+ nv_error(priv, "vm timeout 0: 0x%08x %d\n",
+ nv_rd32(priv, 0x100c80), type);
+ }
+
+ nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8);
+ nv_wr32(priv, 0x100cbc, 0x80000000 | type);
+
+ /* wait for flush to be queued? */
+ if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) {
+ nv_error(priv, "vm timeout 1: 0x%08x %d\n",
+ nv_rd32(priv, 0x100c80), type);
+ }
}
+ mutex_unlock(&nv_subdev(priv)->mutex);
}
static int
@@ -227,7 +227,6 @@ nvc0_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
priv->base.map_sg = nvc0_vm_map_sg;
priv->base.unmap = nvc0_vm_unmap;
priv->base.flush = nvc0_vm_flush;
- spin_lock_init(&priv->lock);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 1c4c6c9161ac..8f467e7bfd19 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -129,6 +129,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
if (chan->ntfy) {
nouveau_bo_vma_del(chan->ntfy, &chan->ntfy_vma);
+ nouveau_bo_unpin(chan->ntfy);
drm_gem_object_unreference_unlocked(chan->ntfy->gem);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 6aa2137e093a..3e7287675ecf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -1878,9 +1878,6 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios)
if (dcb->version < 0x21)
merge_like_dcb_entries(dev, dcb);
- if (!dcb->entries)
- return -ENXIO;
-
/* dump connector table entries to log, if any exist */
idx = -1;
while ((conn = olddcb_conn(dev, ++idx))) {
@@ -2054,19 +2051,14 @@ nouveau_bios_posted(struct drm_device *dev)
struct nouveau_drm *drm = nouveau_drm(dev);
unsigned htotal;
- if (nv_device(drm->device)->card_type >= NV_50) {
- if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
- NVReadVgaCrtc(dev, 0, 0x1a) == 0)
- return false;
+ if (nv_device(drm->device)->card_type >= NV_50)
return true;
- }
htotal = NVReadVgaCrtc(dev, 0, 0x06);
htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8;
htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4;
htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10;
htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11;
-
return (htotal != 0);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 7ff10711a4d0..4b1afb131380 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -255,7 +255,7 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
{
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct nouveau_fb *pfb = nouveau_fb(drm->device);
- u32 vram_pages = pfb->ram.size >> PAGE_SHIFT;
+ u32 vram_pages = pfb->ram->size >> PAGE_SHIFT;
if (nv_device(drm->device)->card_type == NV_10 &&
nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) &&
@@ -968,7 +968,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
bool no_wait_gpu, struct ttm_mem_reg *new_mem)
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
- struct nouveau_channel *chan = chan = drm->channel;
+ struct nouveau_channel *chan = chan = drm->ttm.chan;
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct ttm_mem_reg *old_mem = &bo->mem;
int ret;
@@ -1052,6 +1052,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm)
}
drm->ttm.move = mthd->exec;
+ drm->ttm.chan = chan;
name = mthd->name;
break;
}
@@ -1550,13 +1551,8 @@ void
nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
{
if (vma->node) {
- if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM) {
- spin_lock(&nvbo->bo.bdev->fence_lock);
- ttm_bo_wait(&nvbo->bo, false, false, false);
- spin_unlock(&nvbo->bo.bdev->fence_lock);
+ if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM)
nouveau_vm_unmap(vma);
- }
-
nouveau_vm_put(vma);
list_del(&vma->head);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index eaa80a2b81ee..e84f4c32331b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -147,7 +147,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli,
args.limit = client->vm->vmm->limit - 1;
} else
if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
- u64 limit = pfb->ram.size - imem->reserved - 1;
+ u64 limit = pfb->ram->size - imem->reserved - 1;
if (device->card_type == NV_04) {
/* nv04 vram pushbuf hack, retarget to its location in
* the framebuffer bar rather than direct vram access..
@@ -282,7 +282,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
} else {
args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
args.start = 0;
- args.limit = pfb->ram.size - imem->reserved - 1;
+ args.limit = pfb->ram->size - imem->reserved - 1;
}
ret = nouveau_object_new(nv_object(client), chan->handle, vram,
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index f17dc2ab03ec..708b2d1c0037 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -26,6 +26,7 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
+#include <drm/ttm/ttm_execbuf_util.h>
#include "nouveau_fbcon.h"
#include "dispnv04/hw.h"
@@ -332,10 +333,15 @@ nouveau_display_create(struct drm_device *dev)
if (nouveau_modeset == 1 ||
(nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) {
- if (nv_device(drm->device)->card_type < NV_50)
- ret = nv04_display_create(dev);
- else
- ret = nv50_display_create(dev);
+ if (drm->vbios.dcb.entries) {
+ if (nv_device(drm->device)->card_type < NV_50)
+ ret = nv04_display_create(dev);
+ else
+ ret = nv50_display_create(dev);
+ } else {
+ ret = 0;
+ }
+
if (ret)
goto disp_create_err;
@@ -457,51 +463,6 @@ nouveau_display_resume(struct drm_device *dev)
}
static int
-nouveau_page_flip_reserve(struct nouveau_bo *old_bo,
- struct nouveau_bo *new_bo)
-{
- int ret;
-
- ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
- if (ret)
- return ret;
-
- ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
- if (ret)
- goto fail;
-
- if (likely(old_bo != new_bo)) {
- ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0);
- if (ret)
- goto fail_unreserve;
- }
-
- return 0;
-
-fail_unreserve:
- ttm_bo_unreserve(&new_bo->bo);
-fail:
- nouveau_bo_unpin(new_bo);
- return ret;
-}
-
-static void
-nouveau_page_flip_unreserve(struct nouveau_bo *old_bo,
- struct nouveau_bo *new_bo,
- struct nouveau_fence *fence)
-{
- nouveau_bo_fence(new_bo, fence);
- ttm_bo_unreserve(&new_bo->bo);
-
- if (likely(old_bo != new_bo)) {
- nouveau_bo_fence(old_bo, fence);
- ttm_bo_unreserve(&old_bo->bo);
- }
-
- nouveau_bo_unpin(old_bo);
-}
-
-static int
nouveau_page_flip_emit(struct nouveau_channel *chan,
struct nouveau_bo *old_bo,
struct nouveau_bo *new_bo,
@@ -563,6 +524,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_page_flip_state *s;
struct nouveau_channel *chan = NULL;
struct nouveau_fence *fence;
+ struct list_head res;
+ struct ttm_validate_buffer res_val[2];
+ struct ww_acquire_ctx ticket;
int ret;
if (!drm->channel)
@@ -572,25 +536,43 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
if (!s)
return -ENOMEM;
- /* Don't let the buffers go away while we flip */
- ret = nouveau_page_flip_reserve(old_bo, new_bo);
- if (ret)
- goto fail_free;
-
- /* Initialize a page flip struct */
- *s = (struct nouveau_page_flip_state)
- { { }, event, nouveau_crtc(crtc)->index,
- fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
- new_bo->bo.offset };
-
/* Choose the channel the flip will be handled in */
+ spin_lock(&old_bo->bo.bdev->fence_lock);
fence = new_bo->bo.sync_obj;
if (fence)
chan = fence->channel;
if (!chan)
chan = drm->channel;
+ spin_unlock(&old_bo->bo.bdev->fence_lock);
+
mutex_lock(&chan->cli->mutex);
+ if (new_bo != old_bo) {
+ ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
+ if (likely(!ret)) {
+ res_val[0].bo = &old_bo->bo;
+ res_val[1].bo = &new_bo->bo;
+ INIT_LIST_HEAD(&res);
+ list_add_tail(&res_val[0].head, &res);
+ list_add_tail(&res_val[1].head, &res);
+ ret = ttm_eu_reserve_buffers(&ticket, &res);
+ if (ret)
+ nouveau_bo_unpin(new_bo);
+ }
+ } else
+ ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0);
+
+ if (ret) {
+ mutex_unlock(&chan->cli->mutex);
+ goto fail_free;
+ }
+
+ /* Initialize a page flip struct */
+ *s = (struct nouveau_page_flip_state)
+ { { }, event, nouveau_crtc(crtc)->index,
+ fb->bits_per_pixel, fb->pitches[0], crtc->x, crtc->y,
+ new_bo->bo.offset };
+
/* Emit a page flip */
if (nv_device(drm->device)->card_type >= NV_50) {
ret = nv50_display_flip_next(crtc, fb, chan, 0);
@@ -608,12 +590,22 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
/* Update the crtc struct and cleanup */
crtc->fb = fb;
- nouveau_page_flip_unreserve(old_bo, new_bo, fence);
+ if (old_bo != new_bo) {
+ ttm_eu_fence_buffer_objects(&ticket, &res, fence);
+ nouveau_bo_unpin(old_bo);
+ } else {
+ nouveau_bo_fence(new_bo, fence);
+ ttm_bo_unreserve(&new_bo->bo);
+ }
nouveau_fence_unref(&fence);
return 0;
fail_unreserve:
- nouveau_page_flip_unreserve(old_bo, new_bo, NULL);
+ if (old_bo != new_bo) {
+ ttm_eu_backoff_reservation(&ticket, &res);
+ nouveau_bo_unpin(new_bo);
+ } else
+ ttm_bo_unreserve(&new_bo->bo);
fail_free:
kfree(s);
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 383f4e6ea9d1..218a4b522fe5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -702,6 +702,7 @@ driver = {
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_pin = nouveau_gem_prime_pin,
+ .gem_prime_unpin = nouveau_gem_prime_unpin,
.gem_prime_get_sg_table = nouveau_gem_prime_get_sg_table,
.gem_prime_import_sg_table = nouveau_gem_prime_import_sg_table,
.gem_prime_vmap = nouveau_gem_prime_vmap,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index f2b30f89dee0..41ff7e0d403a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -96,6 +96,7 @@ struct nouveau_drm {
int (*move)(struct nouveau_channel *,
struct ttm_buffer_object *,
struct ttm_mem_reg *, struct ttm_mem_reg *);
+ struct nouveau_channel *chan;
int mtrr;
} ttm;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index b03531781580..9352010030e9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -289,16 +289,13 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM);
if (ret) {
NV_ERROR(drm, "failed to pin fb: %d\n", ret);
- nouveau_bo_ref(NULL, &nvbo);
- goto out;
+ goto out_unref;
}
ret = nouveau_bo_map(nvbo);
if (ret) {
NV_ERROR(drm, "failed to map fb: %d\n", ret);
- nouveau_bo_unpin(nvbo);
- nouveau_bo_ref(NULL, &nvbo);
- goto out;
+ goto out_unpin;
}
chan = nouveau_nofbaccel ? NULL : drm->channel;
@@ -316,13 +313,14 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
info = framebuffer_alloc(0, &pdev->dev);
if (!info) {
ret = -ENOMEM;
- goto out_unref;
+ goto out_unlock;
}
ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret) {
ret = -ENOMEM;
- goto out_unref;
+ framebuffer_release(info);
+ goto out_unlock;
}
info->par = fbcon;
@@ -337,7 +335,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
fbcon->helper.fbdev = info;
strcpy(info->fix.id, "nouveaufb");
- if (nouveau_nofbaccel)
+ if (!chan)
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_DISABLED;
else
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
@@ -383,8 +381,14 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
vga_switcheroo_client_fb_set(dev->pdev, info);
return 0;
-out_unref:
+out_unlock:
mutex_unlock(&dev->struct_mutex);
+ if (chan)
+ nouveau_bo_vma_del(nvbo, &fbcon->nouveau_fb.vma);
+out_unpin:
+ nouveau_bo_unpin(nvbo);
+out_unref:
+ nouveau_bo_ref(NULL, &nvbo);
out:
return ret;
}
@@ -413,6 +417,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
if (nouveau_fb->nvbo) {
nouveau_bo_unmap(nouveau_fb->nvbo);
nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma);
+ nouveau_bo_unpin(nouveau_fb->nvbo);
drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
nouveau_fb->nvbo = NULL;
}
@@ -467,10 +472,10 @@ nouveau_fbcon_init(struct drm_device *dev)
drm_fb_helper_single_add_all_connectors(&fbcon->helper);
- if (pfb->ram.size <= 32 * 1024 * 1024)
+ if (pfb->ram->size <= 32 * 1024 * 1024)
preferred_bpp = 8;
else
- if (pfb->ram.size <= 64 * 1024 * 1024)
+ if (pfb->ram->size <= 64 * 1024 * 1024)
preferred_bpp = 16;
else
preferred_bpp = 32;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 6c946837a0aa..1680d9187bab 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -35,15 +35,34 @@
#include <engine/fifo.h>
+struct fence_work {
+ struct work_struct base;
+ struct list_head head;
+ void (*func)(void *);
+ void *data;
+};
+
+static void
+nouveau_fence_signal(struct nouveau_fence *fence)
+{
+ struct fence_work *work, *temp;
+
+ list_for_each_entry_safe(work, temp, &fence->work, head) {
+ schedule_work(&work->base);
+ list_del(&work->head);
+ }
+
+ fence->channel = NULL;
+ list_del(&fence->head);
+}
+
void
nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
struct nouveau_fence *fence, *fnext;
spin_lock(&fctx->lock);
list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
- fence->channel = NULL;
- list_del(&fence->head);
- nouveau_fence_unref(&fence);
+ nouveau_fence_signal(fence);
}
spin_unlock(&fctx->lock);
}
@@ -57,6 +76,50 @@ nouveau_fence_context_new(struct nouveau_fence_chan *fctx)
}
static void
+nouveau_fence_work_handler(struct work_struct *kwork)
+{
+ struct fence_work *work = container_of(kwork, typeof(*work), base);
+ work->func(work->data);
+ kfree(work);
+}
+
+void
+nouveau_fence_work(struct nouveau_fence *fence,
+ void (*func)(void *), void *data)
+{
+ struct nouveau_channel *chan = fence->channel;
+ struct nouveau_fence_chan *fctx;
+ struct fence_work *work = NULL;
+
+ if (nouveau_fence_done(fence)) {
+ func(data);
+ return;
+ }
+
+ fctx = chan->fence;
+ work = kmalloc(sizeof(*work), GFP_KERNEL);
+ if (!work) {
+ WARN_ON(nouveau_fence_wait(fence, false, false));
+ func(data);
+ return;
+ }
+
+ spin_lock(&fctx->lock);
+ if (!fence->channel) {
+ spin_unlock(&fctx->lock);
+ kfree(work);
+ func(data);
+ return;
+ }
+
+ INIT_WORK(&work->base, nouveau_fence_work_handler);
+ work->func = func;
+ work->data = data;
+ list_add(&work->head, &fence->work);
+ spin_unlock(&fctx->lock);
+}
+
+static void
nouveau_fence_update(struct nouveau_channel *chan)
{
struct nouveau_fence_chan *fctx = chan->fence;
@@ -67,8 +130,7 @@ nouveau_fence_update(struct nouveau_channel *chan)
if (fctx->read(chan) < fence->sequence)
break;
- fence->channel = NULL;
- list_del(&fence->head);
+ nouveau_fence_signal(fence);
nouveau_fence_unref(&fence);
}
spin_unlock(&fctx->lock);
@@ -265,6 +327,7 @@ nouveau_fence_new(struct nouveau_channel *chan, bool sysmem,
if (!fence)
return -ENOMEM;
+ INIT_LIST_HEAD(&fence->work);
fence->sysmem = sysmem;
kref_init(&fence->kref);
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index c89943407b52..c57bb61da58c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -5,6 +5,7 @@ struct nouveau_drm;
struct nouveau_fence {
struct list_head head;
+ struct list_head work;
struct kref kref;
bool sysmem;
@@ -22,6 +23,7 @@ void nouveau_fence_unref(struct nouveau_fence **);
int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
bool nouveau_fence_done(struct nouveau_fence *);
+void nouveau_fence_work(struct nouveau_fence *, void (*)(void *), void *);
int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index b4b4d0c1f4af..e72d09c068a8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -50,7 +50,8 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
return;
nvbo->gem = NULL;
- if (unlikely(nvbo->pin_refcnt)) {
+ /* Lockdep hates you for doing reserve with gem object lock held */
+ if (WARN_ON_ONCE(nvbo->pin_refcnt)) {
nvbo->pin_refcnt = 1;
nouveau_bo_unpin(nvbo);
}
@@ -101,6 +102,41 @@ out:
return ret;
}
+static void
+nouveau_gem_object_delete(void *data)
+{
+ struct nouveau_vma *vma = data;
+ nouveau_vm_unmap(vma);
+ nouveau_vm_put(vma);
+ kfree(vma);
+}
+
+static void
+nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+{
+ const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM;
+ struct nouveau_fence *fence = NULL;
+
+ list_del(&vma->head);
+
+ if (mapped) {
+ spin_lock(&nvbo->bo.bdev->fence_lock);
+ if (nvbo->bo.sync_obj)
+ fence = nouveau_fence_ref(nvbo->bo.sync_obj);
+ spin_unlock(&nvbo->bo.bdev->fence_lock);
+ }
+
+ if (fence) {
+ nouveau_fence_work(fence, nouveau_gem_object_delete, vma);
+ } else {
+ if (mapped)
+ nouveau_vm_unmap(vma);
+ nouveau_vm_put(vma);
+ kfree(vma);
+ }
+ nouveau_fence_unref(&fence);
+}
+
void
nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
{
@@ -118,10 +154,8 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
vma = nouveau_bo_vma_find(nvbo, cli->base.vm);
if (vma) {
- if (--vma->refcount == 0) {
- nouveau_bo_vma_del(nvbo, vma);
- kfree(vma);
- }
+ if (--vma->refcount == 0)
+ nouveau_gem_object_unmap(nvbo, vma);
}
ttm_bo_unreserve(&nvbo->bo);
}
@@ -276,10 +310,12 @@ struct validate_op {
struct list_head vram_list;
struct list_head gart_list;
struct list_head both_list;
+ struct ww_acquire_ctx ticket;
};
static void
-validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
+validate_fini_list(struct list_head *list, struct nouveau_fence *fence,
+ struct ww_acquire_ctx *ticket)
{
struct list_head *entry, *tmp;
struct nouveau_bo *nvbo;
@@ -296,17 +332,24 @@ validate_fini_list(struct list_head *list, struct nouveau_fence *fence)
list_del(&nvbo->entry);
nvbo->reserved_by = NULL;
- ttm_bo_unreserve(&nvbo->bo);
+ ttm_bo_unreserve_ticket(&nvbo->bo, ticket);
drm_gem_object_unreference_unlocked(nvbo->gem);
}
}
static void
-validate_fini(struct validate_op *op, struct nouveau_fence* fence)
+validate_fini_no_ticket(struct validate_op *op, struct nouveau_fence *fence)
{
- validate_fini_list(&op->vram_list, fence);
- validate_fini_list(&op->gart_list, fence);
- validate_fini_list(&op->both_list, fence);
+ validate_fini_list(&op->vram_list, fence, &op->ticket);
+ validate_fini_list(&op->gart_list, fence, &op->ticket);
+ validate_fini_list(&op->both_list, fence, &op->ticket);
+}
+
+static void
+validate_fini(struct validate_op *op, struct nouveau_fence *fence)
+{
+ validate_fini_no_ticket(op, fence);
+ ww_acquire_fini(&op->ticket);
}
static int
@@ -316,13 +359,11 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv,
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct drm_device *dev = chan->drm->dev;
- struct nouveau_drm *drm = nouveau_drm(dev);
- uint32_t sequence;
int trycnt = 0;
int ret, i;
struct nouveau_bo *res_bo = NULL;
- sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
+ ww_acquire_init(&op->ticket, &reservation_ww_class);
retry:
if (++trycnt > 100000) {
NV_ERROR(cli, "%s failed and gave up.\n", __func__);
@@ -337,6 +378,7 @@ retry:
gem = drm_gem_object_lookup(dev, file_priv, b->handle);
if (!gem) {
NV_ERROR(cli, "Unknown handle 0x%08x\n", b->handle);
+ ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -ENOENT;
}
@@ -351,21 +393,23 @@ retry:
NV_ERROR(cli, "multiple instances of buffer %d on "
"validation list\n", b->handle);
drm_gem_object_unreference_unlocked(gem);
+ ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -EINVAL;
}
- ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence);
+ ret = ttm_bo_reserve(&nvbo->bo, true, false, true, &op->ticket);
if (ret) {
- validate_fini(op, NULL);
- if (unlikely(ret == -EAGAIN)) {
- sequence = atomic_add_return(1, &drm->ttm.validate_sequence);
+ validate_fini_no_ticket(op, NULL);
+ if (unlikely(ret == -EDEADLK)) {
ret = ttm_bo_reserve_slowpath(&nvbo->bo, true,
- sequence);
+ &op->ticket);
if (!ret)
res_bo = nvbo;
}
if (unlikely(ret)) {
+ ww_acquire_done(&op->ticket);
+ ww_acquire_fini(&op->ticket);
drm_gem_object_unreference_unlocked(gem);
if (ret != -ERESTARTSYS)
NV_ERROR(cli, "fail reserve\n");
@@ -389,6 +433,7 @@ retry:
NV_ERROR(cli, "invalid valid domains: 0x%08x\n",
b->valid_domains);
list_add_tail(&nvbo->entry, &op->both_list);
+ ww_acquire_done(&op->ticket);
validate_fini(op, NULL);
return -EINVAL;
}
@@ -396,6 +441,7 @@ retry:
goto retry;
}
+ ww_acquire_done(&op->ticket);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.h b/drivers/gpu/drm/nouveau/nouveau_gem.h
index 8d7a3f0aeb86..502e4290aa8f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.h
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.h
@@ -36,6 +36,7 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *);
extern int nouveau_gem_prime_pin(struct drm_gem_object *);
+extern void nouveau_gem_prime_unpin(struct drm_gem_object *);
extern struct sg_table *nouveau_gem_prime_get_sg_table(struct drm_gem_object *);
extern struct drm_gem_object *nouveau_gem_prime_import_sg_table(
struct drm_device *, size_t size, struct sg_table *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 7e0ff10a2759..4f6a572f2258 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -125,7 +125,7 @@ nv50_mem_timing_calc(struct drm_device *dev, u32 freq,
t->reg[7] = 0x4000202 | (e->tCL - 1) << 16;
/* XXX: P.version == 1 only has DDR2 and GDDR3? */
- if (pfb->ram.type == NV_MEM_TYPE_DDR2) {
+ if (pfb->ram->type == NV_MEM_TYPE_DDR2) {
t->reg[5] |= (e->tCL + 3) << 8;
t->reg[6] |= (t->tCWL - 2) << 8;
t->reg[8] |= (e->tCL - 4);
@@ -428,7 +428,7 @@ nouveau_mem_timing_calc(struct drm_device *dev, u32 freq,
break;
}
- switch (pfb->ram.type * !ret) {
+ switch (pfb->ram->type * !ret) {
case NV_MEM_TYPE_GDDR3:
ret = nouveau_mem_gddr3_mr(dev, freq, e, len, boot, t);
break;
@@ -455,7 +455,7 @@ nouveau_mem_timing_calc(struct drm_device *dev, u32 freq,
else
dll_off = !!(ramcfg[2] & 0x40);
- switch (pfb->ram.type) {
+ switch (pfb->ram->type) {
case NV_MEM_TYPE_GDDR3:
t->mr[1] &= ~0x00000040;
t->mr[1] |= 0x00000040 * dll_off;
@@ -522,7 +522,7 @@ nouveau_mem_timing_read(struct drm_device *dev, struct nouveau_pm_memtiming *t)
t->odt = 0;
t->drive_strength = 0;
- switch (pfb->ram.type) {
+ switch (pfb->ram->type) {
case NV_MEM_TYPE_DDR3:
t->odt |= (t->mr[1] & 0x200) >> 7;
case NV_MEM_TYPE_DDR2:
@@ -551,7 +551,7 @@ nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
u32 mr[3] = { info->mr[0], info->mr[1], info->mr[2] };
u32 mr1_dlloff;
- switch (pfb->ram.type) {
+ switch (pfb->ram->type) {
case NV_MEM_TYPE_DDR2:
tDLLK = 2000;
mr1_dlloff = 0x00000001;
@@ -572,7 +572,7 @@ nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
}
/* fetch current MRs */
- switch (pfb->ram.type) {
+ switch (pfb->ram->type) {
case NV_MEM_TYPE_GDDR3:
case NV_MEM_TYPE_DDR3:
mr[2] = exec->mrg(exec, 2);
@@ -639,7 +639,7 @@ nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
exec->mrs (exec, 0, info->mr[0] | 0x00000000);
exec->wait(exec, tMRD);
exec->wait(exec, tDLLK);
- if (pfb->ram.type == NV_MEM_TYPE_GDDR3)
+ if (pfb->ram->type == NV_MEM_TYPE_GDDR3)
exec->precharge(exec);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
index f53e10874cae..e90468d5e5c0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_prime.c
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -84,7 +84,7 @@ struct drm_gem_object *nouveau_gem_prime_import_sg_table(struct drm_device *dev,
int nouveau_gem_prime_pin(struct drm_gem_object *obj)
{
struct nouveau_bo *nvbo = nouveau_gem_object(obj);
- int ret = 0;
+ int ret;
/* pin buffer into GTT */
ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT);
@@ -93,3 +93,10 @@ int nouveau_gem_prime_pin(struct drm_gem_object *obj)
return 0;
}
+
+void nouveau_gem_prime_unpin(struct drm_gem_object *obj)
+{
+ struct nouveau_bo *nvbo = nouveau_gem_object(obj);
+
+ nouveau_bo_unpin(nvbo);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index f19a15a3bc03..19e3757291fb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -69,7 +69,7 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
struct nouveau_drm *drm = nouveau_bdev(man->bdev);
struct nouveau_fb *pfb = nouveau_fb(drm->device);
nouveau_mem_node_cleanup(mem->mm_node);
- pfb->ram.put(pfb, (struct nouveau_mem **)&mem->mm_node);
+ pfb->ram->put(pfb, (struct nouveau_mem **)&mem->mm_node);
}
static int
@@ -88,7 +88,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)
size_nc = 1 << nvbo->page_shift;
- ret = pfb->ram.get(pfb, mem->num_pages << PAGE_SHIFT,
+ ret = pfb->ram->get(pfb, mem->num_pages << PAGE_SHIFT,
mem->page_alignment << PAGE_SHIFT, size_nc,
(nvbo->tile_flags >> 8) & 0x3ff, &node);
if (ret) {
@@ -111,7 +111,7 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
struct nouveau_mm_node *r;
u32 total = 0, free = 0;
- mutex_lock(&mm->mutex);
+ mutex_lock(&nv_subdev(pfb)->mutex);
list_for_each_entry(r, &mm->nodes, nl_entry) {
printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n",
prefix, r->type, ((u64)r->offset << 12),
@@ -121,7 +121,7 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
if (!r->type)
free += r->length;
}
- mutex_unlock(&mm->mutex);
+ mutex_unlock(&nv_subdev(pfb)->mutex);
printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n",
prefix, (u64)total << 12, (u64)free << 12);
@@ -168,9 +168,6 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nouveau_mem *node;
- if (unlikely((mem->num_pages << PAGE_SHIFT) >= 512 * 1024 * 1024))
- return -ENOMEM;
-
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return -ENOMEM;
@@ -386,7 +383,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
}
/* VRAM init */
- drm->gem.vram_available = nouveau_fb(drm->device)->ram.size;
+ drm->gem.vram_available = nouveau_fb(drm->device)->ram->size;
drm->gem.vram_available -= nouveau_instmem(drm->device)->reserved;
ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM,
@@ -396,15 +393,12 @@ nouveau_ttm_init(struct nouveau_drm *drm)
return ret;
}
- drm->ttm.mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1),
- pci_resource_len(dev->pdev, 1),
- DRM_MTRR_WC);
+ drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1),
+ pci_resource_len(dev->pdev, 1));
/* GART init */
if (drm->agp.stat != ENABLED) {
drm->gem.gart_available = nouveau_vmmgr(drm->device)->limit;
- if (drm->gem.gart_available > 512 * 1024 * 1024)
- drm->gem.gart_available = 512 * 1024 * 1024;
} else {
drm->gem.gart_available = drm->agp.size;
}
@@ -433,10 +427,6 @@ nouveau_ttm_fini(struct nouveau_drm *drm)
nouveau_ttm_global_release(drm);
- if (drm->ttm.mtrr >= 0) {
- drm_mtrr_del(drm->ttm.mtrr,
- pci_resource_start(drm->dev->pdev, 1),
- pci_resource_len(drm->dev->pdev, 1), DRM_MTRR_WC);
- drm->ttm.mtrr = -1;
- }
+ arch_phys_wc_del(drm->ttm.mtrr);
+ drm->ttm.mtrr = 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index dd5e01f89f28..54dc6355b0c2 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -159,7 +159,7 @@ nv50_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NV50_DMA_CONF0_ENABLE |
NV50_DMA_CONF0_PART_256,
}, sizeof(struct nv_dma_class), &object);
@@ -172,7 +172,7 @@ nv50_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NV50_DMA_CONF0_ENABLE | 0x70 |
NV50_DMA_CONF0_PART_256,
}, sizeof(struct nv_dma_class), &object);
@@ -185,7 +185,7 @@ nv50_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NV50_DMA_CONF0_ENABLE | 0x7a |
NV50_DMA_CONF0_PART_256,
}, sizeof(struct nv_dma_class), &object);
@@ -204,7 +204,7 @@ nvc0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NVC0_DMA_CONF0_ENABLE,
}, sizeof(struct nv_dma_class), &object);
if (ret)
@@ -216,7 +216,7 @@ nvc0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
}, sizeof(struct nv_dma_class), &object);
if (ret)
@@ -228,7 +228,7 @@ nvc0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NVC0_DMA_CONF0_ENABLE | 0xfe,
}, sizeof(struct nv_dma_class), &object);
return ret;
@@ -246,7 +246,7 @@ nvd0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NVD0_DMA_CONF0_ENABLE |
NVD0_DMA_CONF0_PAGE_LP,
}, sizeof(struct nv_dma_class), &object);
@@ -259,7 +259,7 @@ nvd0_dmac_create_fbdma(struct nouveau_object *core, u32 parent)
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
.conf0 = NVD0_DMA_CONF0_ENABLE | 0xfe |
NVD0_DMA_CONF0_PAGE_LP,
}, sizeof(struct nv_dma_class), &object);
@@ -316,7 +316,7 @@ nv50_dmac_create(struct nouveau_object *core, u32 bclass, u8 head,
.flags = NV_DMA_TARGET_VRAM |
NV_DMA_ACCESS_RDWR,
.start = 0,
- .limit = pfb->ram.size - 1,
+ .limit = pfb->ram->size - 1,
}, sizeof(struct nv_dma_class), &object);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 69620e39c90c..4efc33fa73fc 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -493,12 +493,12 @@ mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
struct hwsq_ucode *hwsq = &info->mclk_hwsq;
if (mr <= 1) {
- if (pfb->ram.ranks > 1)
+ if (pfb->ram->ranks > 1)
hwsq_wr32(hwsq, 0x1002c8 + ((mr - 0) * 4), data);
hwsq_wr32(hwsq, 0x1002c0 + ((mr - 0) * 4), data);
} else
if (mr <= 3) {
- if (pfb->ram.ranks > 1)
+ if (pfb->ram->ranks > 1)
hwsq_wr32(hwsq, 0x1002e8 + ((mr - 2) * 4), data);
hwsq_wr32(hwsq, 0x1002e0 + ((mr - 2) * 4), data);
}
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
index 863f010fafeb..0d0ed597fea8 100644
--- a/drivers/gpu/drm/nouveau/nva3_pm.c
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -389,12 +389,12 @@ mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
struct nouveau_device *device = nouveau_dev(exec->dev);
struct nouveau_fb *pfb = nouveau_fb(device);
if (mr <= 1) {
- if (pfb->ram.ranks > 1)
+ if (pfb->ram->ranks > 1)
nv_wr32(device, 0x1002c8 + ((mr - 0) * 4), data);
nv_wr32(device, 0x1002c0 + ((mr - 0) * 4), data);
} else
if (mr <= 3) {
- if (pfb->ram.ranks > 1)
+ if (pfb->ram->ranks > 1)
nv_wr32(device, 0x1002e8 + ((mr - 2) * 4), data);
nv_wr32(device, 0x1002e0 + ((mr - 2) * 4), data);
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
index 0d34eb581179..3b7041cb013f 100644
--- a/drivers/gpu/drm/nouveau/nvc0_pm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_pm.c
@@ -477,7 +477,7 @@ mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
{
struct nouveau_device *device = nouveau_dev(exec->dev);
struct nouveau_fb *pfb = nouveau_fb(device);
- if (pfb->ram.type != NV_MEM_TYPE_GDDR5) {
+ if (pfb->ram->type != NV_MEM_TYPE_GDDR5) {
if (mr <= 1)
return nv_rd32(device, 0x10f300 + ((mr - 0) * 4));
return nv_rd32(device, 0x10f320 + ((mr - 2) * 4));
@@ -496,15 +496,15 @@ mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
{
struct nouveau_device *device = nouveau_dev(exec->dev);
struct nouveau_fb *pfb = nouveau_fb(device);
- if (pfb->ram.type != NV_MEM_TYPE_GDDR5) {
+ if (pfb->ram->type != NV_MEM_TYPE_GDDR5) {
if (mr <= 1) {
nv_wr32(device, 0x10f300 + ((mr - 0) * 4), data);
- if (pfb->ram.ranks > 1)
+ if (pfb->ram->ranks > 1)
nv_wr32(device, 0x10f308 + ((mr - 0) * 4), data);
} else
if (mr <= 3) {
nv_wr32(device, 0x10f320 + ((mr - 2) * 4), data);
- if (pfb->ram.ranks > 1)
+ if (pfb->ram->ranks > 1)
nv_wr32(device, 0x10f328 + ((mr - 2) * 4), data);
}
} else {
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig
index 09f65dc3d2c8..20c41e73d448 100644
--- a/drivers/gpu/drm/omapdrm/Kconfig
+++ b/drivers/gpu/drm/omapdrm/Kconfig
@@ -1,7 +1,7 @@
config DRM_OMAP
tristate "OMAP DRM"
- depends on DRM && !CONFIG_FB_OMAP2
+ depends on DRM
depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM
depends on OMAP2_DSS
select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 79b200aee18a..11a5263a5e9f 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -40,7 +40,7 @@ struct omap_crtc {
* mgr->id.) Eventually this will be replaced w/ something
* more common-panel-framework-y
*/
- struct omap_overlay_manager mgr;
+ struct omap_overlay_manager *mgr;
struct omap_video_timings timings;
bool enabled;
@@ -90,7 +90,32 @@ uint32_t pipe2vbl(struct drm_crtc *crtc)
* job of sequencing the setup of the video pipe in the proper order
*/
+/* ovl-mgr-id -> crtc */
+static struct omap_crtc *omap_crtcs[8];
+
/* we can probably ignore these until we support command-mode panels: */
+static int omap_crtc_connect(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *dst)
+{
+ if (mgr->output)
+ return -EINVAL;
+
+ if ((mgr->supported_outputs & dst->id) == 0)
+ return -EINVAL;
+
+ dst->manager = mgr;
+ mgr->output = dst;
+
+ return 0;
+}
+
+static void omap_crtc_disconnect(struct omap_overlay_manager *mgr,
+ struct omap_dss_device *dst)
+{
+ mgr->output->manager = NULL;
+ mgr->output = NULL;
+}
+
static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
{
}
@@ -107,7 +132,7 @@ static void omap_crtc_disable(struct omap_overlay_manager *mgr)
static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
const struct omap_video_timings *timings)
{
- struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
+ struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
DBG("%s", omap_crtc->name);
omap_crtc->timings = *timings;
omap_crtc->full_update = true;
@@ -116,7 +141,7 @@ static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
const struct dss_lcd_mgr_config *config)
{
- struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
+ struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
DBG("%s", omap_crtc->name);
dispc_mgr_set_lcd_config(omap_crtc->channel, config);
}
@@ -135,6 +160,8 @@ static void omap_crtc_unregister_framedone_handler(
}
static const struct dss_mgr_ops mgr_ops = {
+ .connect = omap_crtc_connect,
+ .disconnect = omap_crtc_disconnect,
.start_update = omap_crtc_start_update,
.enable = omap_crtc_enable,
.disable = omap_crtc_disable,
@@ -253,10 +280,6 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
NULL, NULL);
}
-static void omap_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
static void vblank_cb(void *arg)
{
struct drm_crtc *crtc = arg;
@@ -366,7 +389,6 @@ static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
.prepare = omap_crtc_prepare,
.commit = omap_crtc_commit,
.mode_set_base = omap_crtc_mode_set_base,
- .load_lut = omap_crtc_load_lut,
};
const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
@@ -569,7 +591,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
} else {
if (encoder) {
omap_encoder_set_enabled(encoder, false);
- omap_encoder_update(encoder, &omap_crtc->mgr,
+ omap_encoder_update(encoder, omap_crtc->mgr,
&omap_crtc->timings);
omap_encoder_set_enabled(encoder, true);
omap_crtc->full_update = false;
@@ -595,6 +617,11 @@ static const char *channel_names[] = {
[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
};
+void omap_crtc_pre_init(void)
+{
+ dss_install_mgr_ops(&mgr_ops);
+}
+
/* initialize crtc */
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, enum omap_channel channel, int id)
@@ -635,9 +662,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_irq_register(dev, &omap_crtc->error_irq);
/* temporary: */
- omap_crtc->mgr.id = channel;
-
- dss_install_mgr_ops(&mgr_ops);
+ omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
/* TODO: fix hard-coded setup.. add properties! */
info = &omap_crtc->info;
@@ -651,6 +676,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
omap_plane_install_properties(omap_crtc->plane, &crtc->base);
+ omap_crtcs[channel] = omap_crtc;
+
return crtc;
fail:
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 826586ffbe83..a3004f12b9a3 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -65,10 +65,8 @@ static int get_connector_type(struct omap_dss_device *dssdev)
switch (dssdev->type) {
case OMAP_DISPLAY_TYPE_HDMI:
return DRM_MODE_CONNECTOR_HDMIA;
- case OMAP_DISPLAY_TYPE_DPI:
- if (!strcmp(dssdev->name, "dvi"))
- return DRM_MODE_CONNECTOR_DVID;
- /* fallthrough */
+ case OMAP_DISPLAY_TYPE_DVI:
+ return DRM_MODE_CONNECTOR_DVID;
default:
return DRM_MODE_CONNECTOR_Unknown;
}
@@ -97,6 +95,9 @@ static int omap_modeset_init(struct drm_device *dev)
int num_mgrs = dss_feat_get_num_mgrs();
int num_crtcs;
int i, id = 0;
+ int r;
+
+ omap_crtc_pre_init();
drm_mode_config_init(dev);
@@ -116,6 +117,7 @@ static int omap_modeset_init(struct drm_device *dev)
struct drm_connector *connector;
struct drm_encoder *encoder;
enum omap_channel channel;
+ struct omap_overlay_manager *mgr;
if (!dssdev->driver) {
dev_warn(dev->dev, "%s has no driver.. skipping it\n",
@@ -131,6 +133,13 @@ static int omap_modeset_init(struct drm_device *dev)
continue;
}
+ r = dssdev->driver->connect(dssdev);
+ if (r) {
+ dev_err(dev->dev, "could not connect display: %s\n",
+ dssdev->name);
+ continue;
+ }
+
encoder = omap_encoder_init(dev, dssdev);
if (!encoder) {
@@ -172,8 +181,9 @@ static int omap_modeset_init(struct drm_device *dev)
* other possible channels to which the encoder can connect are
* not considered.
*/
- channel = dssdev->output->dispc_channel;
+ mgr = omapdss_find_mgr_from_display(dssdev);
+ channel = mgr->id;
/*
* if this channel hasn't already been taken by a previously
* allocated crtc, we create a new crtc for it
@@ -247,6 +257,9 @@ static int omap_modeset_init(struct drm_device *dev)
struct drm_encoder *encoder = priv->encoders[i];
struct omap_dss_device *dssdev =
omap_encoder_get_dssdev(encoder);
+ struct omap_dss_device *output;
+
+ output = omapdss_find_output_from_display(dssdev);
/* figure out which crtc's we can connect the encoder to: */
encoder->possible_crtcs = 0;
@@ -259,9 +272,11 @@ static int omap_modeset_init(struct drm_device *dev)
supported_outputs =
dss_feat_get_supported_outputs(crtc_channel);
- if (supported_outputs & dssdev->output->id)
+ if (supported_outputs & output->id)
encoder->possible_crtcs |= (1 << id);
}
+
+ omap_dss_put_device(output);
}
DBG("registered %d planes, %d crtcs, %d encoders and %d connectors\n",
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 215a20dd340c..14f17da2ce25 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -157,6 +157,7 @@ const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc);
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
int omap_crtc_apply(struct drm_crtc *crtc,
struct omap_drm_apply *apply);
+void omap_crtc_pre_init(void);
struct drm_crtc *omap_crtc_init(struct drm_device *dev,
struct drm_plane *plane, enum omap_channel channel, int id);
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index b11ce609fcc2..002988d09021 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -281,21 +281,7 @@ fail:
return ret;
}
-static void omap_crtc_fb_gamma_set(struct drm_crtc *crtc,
- u16 red, u16 green, u16 blue, int regno)
-{
- DBG("fbdev: set gamma");
-}
-
-static void omap_crtc_fb_gamma_get(struct drm_crtc *crtc,
- u16 *red, u16 *green, u16 *blue, int regno)
-{
- DBG("fbdev: get gamma");
-}
-
static struct drm_fb_helper_funcs omap_fb_helper_funcs = {
- .gamma_set = omap_crtc_fb_gamma_set,
- .gamma_get = omap_crtc_fb_gamma_get,
.fb_probe = omap_fbdev_create,
};
diff --git a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
index be7cd97a0db0..4fcca8d42796 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c
@@ -136,44 +136,21 @@ static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer,
kunmap(pages[page_num]);
}
-/*
- * TODO maybe we can split up drm_gem_mmap to avoid duplicating
- * some here.. or at least have a drm_dmabuf_mmap helper.
- */
static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
struct vm_area_struct *vma)
{
struct drm_gem_object *obj = buffer->priv;
+ struct drm_device *dev = obj->dev;
int ret = 0;
if (WARN_ON(!obj->filp))
return -EINVAL;
- /* Check for valid size. */
- if (omap_gem_mmap_size(obj) < vma->vm_end - vma->vm_start) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- if (!obj->dev->driver->gem_vm_ops) {
- ret = -EINVAL;
- goto out_unlock;
- }
-
- vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_ops = obj->dev->driver->gem_vm_ops;
- vma->vm_private_data = obj;
- vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
-
- /* Take a ref for this mapping of the object, so that the fault
- * handler can dereference the mmap offset's pointer to the object.
- * This reference is cleaned up by the corresponding vm_close
- * (which should happen whether the vma was created by this call, or
- * by a vm_open due to mremap or partial unmap or whatever).
- */
- vma->vm_ops->open(vma);
-
-out_unlock:
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma);
+ mutex_unlock(&dev->struct_mutex);
+ if (ret < 0)
+ return ret;
return omap_gem_mmap_obj(obj, vma);
}
diff --git a/drivers/gpu/drm/qxl/qxl_cmd.c b/drivers/gpu/drm/qxl/qxl_cmd.c
index f86771481317..93c2f2cceb51 100644
--- a/drivers/gpu/drm/qxl/qxl_cmd.c
+++ b/drivers/gpu/drm/qxl/qxl_cmd.c
@@ -49,6 +49,11 @@ void qxl_ring_free(struct qxl_ring *ring)
kfree(ring);
}
+void qxl_ring_init_hdr(struct qxl_ring *ring)
+{
+ ring->ring->header.notify_on_prod = ring->n_elements;
+}
+
struct qxl_ring *
qxl_ring_create(struct qxl_ring_header *header,
int element_size,
@@ -69,7 +74,7 @@ qxl_ring_create(struct qxl_ring_header *header,
ring->prod_notify = prod_notify;
ring->push_event = push_event;
if (set_prod_notify)
- header->notify_on_prod = ring->n_elements;
+ qxl_ring_init_hdr(ring);
spin_lock_init(&ring->lock);
return ring;
}
@@ -87,7 +92,7 @@ static int qxl_check_header(struct qxl_ring *ring)
return ret;
}
-static int qxl_check_idle(struct qxl_ring *ring)
+int qxl_check_idle(struct qxl_ring *ring)
{
int ret;
struct qxl_ring_header *header = &(ring->ring->header);
@@ -375,8 +380,8 @@ void qxl_io_destroy_primary(struct qxl_device *qdev)
wait_for_io_cmd(qdev, 0, QXL_IO_DESTROY_PRIMARY_ASYNC);
}
-void qxl_io_create_primary(struct qxl_device *qdev, unsigned width,
- unsigned height, unsigned offset, struct qxl_bo *bo)
+void qxl_io_create_primary(struct qxl_device *qdev,
+ unsigned offset, struct qxl_bo *bo)
{
struct qxl_surface_create *create;
@@ -384,8 +389,8 @@ void qxl_io_create_primary(struct qxl_device *qdev, unsigned width,
qdev->ram_header);
create = &qdev->ram_header->create_surface;
create->format = bo->surf.format;
- create->width = width;
- create->height = height;
+ create->width = bo->surf.width;
+ create->height = bo->surf.height;
create->stride = bo->surf.stride;
create->mem = qxl_bo_physical_address(qdev, bo, offset);
diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c
index 823d29e926ec..f76f5dd7bfc4 100644
--- a/drivers/gpu/drm/qxl/qxl_display.c
+++ b/drivers/gpu/drm/qxl/qxl_display.c
@@ -30,53 +30,9 @@
#include "qxl_object.h"
#include "drm_crtc_helper.h"
-static void qxl_crtc_set_to_mode(struct qxl_device *qdev,
- struct drm_connector *connector,
- struct qxl_head *head)
+static bool qxl_head_enabled(struct qxl_head *head)
{
- struct drm_device *dev = connector->dev;
- struct drm_display_mode *mode, *t;
- int width = head->width;
- int height = head->height;
-
- if (width < 320 || height < 240) {
- qxl_io_log(qdev, "%s: bad head: %dx%d", width, height);
- width = 1024;
- height = 768;
- }
- if (width * height * 4 > 16*1024*1024) {
- width = 1024;
- height = 768;
- }
- /* TODO: go over regular modes and removed preferred? */
- list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
- drm_mode_remove(connector, mode);
- mode = drm_cvt_mode(dev, width, height, 60, false, false, false);
- mode->type |= DRM_MODE_TYPE_PREFERRED;
- mode->status = MODE_OK;
- drm_mode_probed_add(connector, mode);
- qxl_io_log(qdev, "%s: %d x %d\n", __func__, width, height);
-}
-
-void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev)
-{
- struct drm_connector *connector;
- int i;
- struct drm_device *dev = qdev->ddev;
-
- i = 0;
- qxl_io_log(qdev, "%s: %d, %d\n", __func__,
- dev->mode_config.num_connector,
- qdev->monitors_config->count);
- list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (i > qdev->monitors_config->count) {
- /* crtc will be reported as disabled */
- continue;
- }
- qxl_crtc_set_to_mode(qdev, connector,
- &qdev->monitors_config->heads[i]);
- ++i;
- }
+ return head->width && head->height;
}
void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count)
@@ -106,7 +62,6 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
int num_monitors;
uint32_t crc;
- BUG_ON(!qdev->monitors_config);
num_monitors = qdev->rom->client_monitors_config.count;
crc = crc32(0, (const uint8_t *)&qdev->rom->client_monitors_config,
sizeof(qdev->rom->client_monitors_config));
@@ -117,8 +72,8 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
return 1;
}
if (num_monitors > qdev->monitors_config->max_allowed) {
- DRM_INFO("client monitors list will be truncated: %d < %d\n",
- qdev->monitors_config->max_allowed, num_monitors);
+ DRM_DEBUG_KMS("client monitors list will be truncated: %d < %d\n",
+ qdev->monitors_config->max_allowed, num_monitors);
num_monitors = qdev->monitors_config->max_allowed;
} else {
num_monitors = qdev->rom->client_monitors_config.count;
@@ -132,18 +87,15 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
&qdev->rom->client_monitors_config.heads[i];
struct qxl_head *client_head =
&qdev->client_monitors_config->heads[i];
- struct qxl_head *head = &qdev->monitors_config->heads[i];
- client_head->x = head->x = c_rect->left;
- client_head->y = head->y = c_rect->top;
- client_head->width = head->width =
- c_rect->right - c_rect->left;
- client_head->height = head->height =
- c_rect->bottom - c_rect->top;
- client_head->surface_id = head->surface_id = 0;
- client_head->id = head->id = i;
- client_head->flags = head->flags = 0;
- QXL_DEBUG(qdev, "read %dx%d+%d+%d\n", head->width, head->height,
- head->x, head->y);
+ client_head->x = c_rect->left;
+ client_head->y = c_rect->top;
+ client_head->width = c_rect->right - c_rect->left;
+ client_head->height = c_rect->bottom - c_rect->top;
+ client_head->surface_id = 0;
+ client_head->id = i;
+ client_head->flags = 0;
+ DRM_DEBUG_KMS("read %dx%d+%d+%d\n", client_head->width, client_head->height,
+ client_head->x, client_head->y);
}
return 0;
}
@@ -155,10 +107,7 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
qxl_io_log(qdev, "failed crc check for client_monitors_config,"
" retrying\n");
}
- qxl_crtc_set_from_monitors_config(qdev);
- /* fire off a uevent and let userspace tell us what to do */
- qxl_io_log(qdev, "calling drm_sysfs_hotplug_event\n");
- drm_sysfs_hotplug_event(qdev->ddev);
+ drm_helper_hpd_irq_event(qdev->ddev);
}
static int qxl_add_monitors_config_modes(struct drm_connector *connector)
@@ -170,9 +119,9 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector)
struct drm_display_mode *mode = NULL;
struct qxl_head *head;
- if (!qdev->monitors_config)
+ if (!qdev->client_monitors_config)
return 0;
- head = &qdev->monitors_config->heads[h];
+ head = &qdev->client_monitors_config->heads[h];
mode = drm_cvt_mode(dev, head->width, head->height, 60, false, false,
false);
@@ -222,12 +171,6 @@ static int qxl_add_common_modes(struct drm_connector *connector)
return i - 1;
}
-static void qxl_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, uint32_t start, uint32_t size)
-{
- /* TODO */
-}
-
static void qxl_crtc_destroy(struct drm_crtc *crtc)
{
struct qxl_crtc *qxl_crtc = to_qxl_crtc(crtc);
@@ -255,11 +198,11 @@ qxl_hide_cursor(struct qxl_device *qdev)
qxl_release_unreserve(qdev, release);
}
-static int qxl_crtc_cursor_set(struct drm_crtc *crtc,
- struct drm_file *file_priv,
- uint32_t handle,
- uint32_t width,
- uint32_t height)
+static int qxl_crtc_cursor_set2(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height, int32_t hot_x, int32_t hot_y)
{
struct drm_device *dev = crtc->dev;
struct qxl_device *qdev = dev->dev_private;
@@ -315,8 +258,8 @@ static int qxl_crtc_cursor_set(struct drm_crtc *crtc,
cursor->header.type = SPICE_CURSOR_TYPE_ALPHA;
cursor->header.width = 64;
cursor->header.height = 64;
- cursor->header.hot_spot_x = 0;
- cursor->header.hot_spot_y = 0;
+ cursor->header.hot_spot_x = hot_x;
+ cursor->header.hot_spot_y = hot_y;
cursor->data_size = size;
cursor->chunk.next_chunk = 0;
cursor->chunk.prev_chunk = 0;
@@ -397,9 +340,8 @@ static int qxl_crtc_cursor_move(struct drm_crtc *crtc,
static const struct drm_crtc_funcs qxl_crtc_funcs = {
- .cursor_set = qxl_crtc_cursor_set,
+ .cursor_set2 = qxl_crtc_cursor_set2,
.cursor_move = qxl_crtc_cursor_move,
- .gamma_set = qxl_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
.destroy = qxl_crtc_destroy,
};
@@ -506,7 +448,7 @@ qxl_send_monitors_config(struct qxl_device *qdev)
for (i = 0 ; i < qdev->monitors_config->count ; ++i) {
struct qxl_head *head = &qdev->monitors_config->heads[i];
- if (head->y > 8192 || head->y < head->x ||
+ if (head->y > 8192 || head->x > 8192 ||
head->width > 8192 || head->height > 8192) {
DRM_ERROR("head %d wrong: %dx%d+%d+%d\n",
i, head->width, head->height,
@@ -517,16 +459,19 @@ qxl_send_monitors_config(struct qxl_device *qdev)
qxl_io_monitors_config(qdev);
}
-static void qxl_monitors_config_set_single(struct qxl_device *qdev,
- unsigned x, unsigned y,
- unsigned width, unsigned height)
+static void qxl_monitors_config_set(struct qxl_device *qdev,
+ int index,
+ unsigned x, unsigned y,
+ unsigned width, unsigned height,
+ unsigned surf_id)
{
- DRM_DEBUG("%dx%d+%d+%d\n", width, height, x, y);
- qdev->monitors_config->count = 1;
- qdev->monitors_config->heads[0].x = x;
- qdev->monitors_config->heads[0].y = y;
- qdev->monitors_config->heads[0].width = width;
- qdev->monitors_config->heads[0].height = height;
+ DRM_DEBUG_KMS("%d:%dx%d+%d+%d\n", index, width, height, x, y);
+ qdev->monitors_config->heads[index].x = x;
+ qdev->monitors_config->heads[index].y = y;
+ qdev->monitors_config->heads[index].width = width;
+ qdev->monitors_config->heads[index].height = height;
+ qdev->monitors_config->heads[index].surface_id = surf_id;
+
}
static int qxl_crtc_mode_set(struct drm_crtc *crtc,
@@ -540,10 +485,11 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
struct qxl_mode *m = (void *)mode->private;
struct qxl_framebuffer *qfb;
struct qxl_bo *bo, *old_bo = NULL;
+ struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
uint32_t width, height, base_offset;
bool recreate_primary = false;
int ret;
-
+ int surf_id;
if (!crtc->fb) {
DRM_DEBUG_KMS("No FB bound\n");
return 0;
@@ -567,7 +513,8 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
adjusted_mode->hdisplay,
adjusted_mode->vdisplay);
- recreate_primary = true;
+ if (qcrtc->index == 0)
+ recreate_primary = true;
width = mode->hdisplay;
height = mode->vdisplay;
@@ -588,8 +535,11 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
"recreate primary: %dx%d (was %dx%d,%d,%d)\n",
width, height, bo->surf.width,
bo->surf.height, bo->surf.stride, bo->surf.format);
- qxl_io_create_primary(qdev, width, height, base_offset, bo);
+ qxl_io_create_primary(qdev, base_offset, bo);
bo->is_primary = true;
+ surf_id = 0;
+ } else {
+ surf_id = bo->surface_id;
}
if (old_bo && old_bo != bo) {
@@ -599,11 +549,9 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
qxl_bo_unreserve(old_bo);
}
- if (qdev->monitors_config->count == 0) {
- qxl_monitors_config_set_single(qdev, x, y,
- mode->hdisplay,
- mode->vdisplay);
- }
+ qxl_monitors_config_set(qdev, qcrtc->index, x, y,
+ mode->hdisplay,
+ mode->vdisplay, surf_id);
return 0;
}
@@ -619,21 +567,36 @@ static void qxl_crtc_commit(struct drm_crtc *crtc)
DRM_DEBUG("\n");
}
-static void qxl_crtc_load_lut(struct drm_crtc *crtc)
+static void qxl_crtc_disable(struct drm_crtc *crtc)
{
- DRM_DEBUG("\n");
+ struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct qxl_device *qdev = dev->dev_private;
+ if (crtc->fb) {
+ struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
+ struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
+ int ret;
+ ret = qxl_bo_reserve(bo, false);
+ qxl_bo_unpin(bo);
+ qxl_bo_unreserve(bo);
+ crtc->fb = NULL;
+ }
+
+ qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
+
+ qxl_send_monitors_config(qdev);
}
static const struct drm_crtc_helper_funcs qxl_crtc_helper_funcs = {
.dpms = qxl_crtc_dpms,
+ .disable = qxl_crtc_disable,
.mode_fixup = qxl_crtc_mode_fixup,
.mode_set = qxl_crtc_mode_set,
.prepare = qxl_crtc_prepare,
.commit = qxl_crtc_commit,
- .load_lut = qxl_crtc_load_lut,
};
-static int qdev_crtc_init(struct drm_device *dev, int num_crtc)
+static int qdev_crtc_init(struct drm_device *dev, int crtc_id)
{
struct qxl_crtc *qxl_crtc;
@@ -642,7 +605,7 @@ static int qdev_crtc_init(struct drm_device *dev, int num_crtc)
return -ENOMEM;
drm_crtc_init(dev, &qxl_crtc->base, &qxl_crtc_funcs);
-
+ qxl_crtc->index = crtc_id;
drm_mode_crtc_set_gamma_size(&qxl_crtc->base, 256);
drm_crtc_helper_add(&qxl_crtc->base, &qxl_crtc_helper_funcs);
return 0;
@@ -670,18 +633,13 @@ static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev,
struct drm_encoder *encoder)
{
int i;
+ struct qxl_output *output = drm_encoder_to_qxl_output(encoder);
struct qxl_head *head;
struct drm_display_mode *mode;
BUG_ON(!encoder);
/* TODO: ugly, do better */
- for (i = 0 ; (encoder->possible_crtcs != (1 << i)) && i < 32; ++i)
- ;
- if (encoder->possible_crtcs != (1 << i)) {
- DRM_ERROR("encoder has wrong possible_crtcs: %x\n",
- encoder->possible_crtcs);
- return;
- }
+ i = output->index;
if (!qdev->monitors_config ||
qdev->monitors_config->max_allowed <= i) {
DRM_ERROR(
@@ -699,7 +657,6 @@ static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev,
DRM_DEBUG("missing for multiple monitors: no head holes\n");
head = &qdev->monitors_config->heads[i];
head->id = i;
- head->surface_id = 0;
if (encoder->crtc->enabled) {
mode = &encoder->crtc->mode;
head->width = mode->hdisplay;
@@ -714,8 +671,8 @@ static void qxl_write_monitors_config_for_encoder(struct qxl_device *qdev,
head->x = 0;
head->y = 0;
}
- DRM_DEBUG("setting head %d to +%d+%d %dx%d\n",
- i, head->x, head->y, head->width, head->height);
+ DRM_DEBUG_KMS("setting head %d to +%d+%d %dx%d out of %d\n",
+ i, head->x, head->y, head->width, head->height, qdev->monitors_config->count);
head->flags = 0;
/* TODO - somewhere else to call this for multiple monitors
* (config_commit?) */
@@ -810,8 +767,9 @@ static enum drm_connector_status qxl_conn_detect(
/* The first monitor is always connected */
connected = (output->index == 0) ||
- (qdev->monitors_config &&
- qdev->monitors_config->count > output->index);
+ (qdev->client_monitors_config &&
+ qdev->client_monitors_config->count > output->index &&
+ qxl_head_enabled(&qdev->client_monitors_config->heads[output->index]));
DRM_DEBUG("\n");
return connected ? connector_status_connected
@@ -875,6 +833,8 @@ static int qdev_output_init(struct drm_device *dev, int num_output)
drm_encoder_init(dev, &qxl_output->enc, &qxl_enc_funcs,
DRM_MODE_ENCODER_VIRTUAL);
+ /* we get HPD via client monitors config */
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
encoder->possible_crtcs = 1 << num_output;
drm_mode_connector_attach_encoder(&qxl_output->base,
&qxl_output->enc);
@@ -914,16 +874,14 @@ static const struct drm_mode_config_funcs qxl_mode_funcs = {
.fb_create = qxl_user_framebuffer_create,
};
-int qxl_modeset_init(struct qxl_device *qdev)
+int qxl_create_monitors_object(struct qxl_device *qdev)
{
- int i;
int ret;
struct drm_gem_object *gobj;
- int max_allowed = QXL_NUM_OUTPUTS;
+ int max_allowed = qxl_num_crtc;
int monitors_config_size = sizeof(struct qxl_monitors_config) +
- max_allowed * sizeof(struct qxl_head);
+ max_allowed * sizeof(struct qxl_head);
- drm_mode_config_init(qdev->ddev);
ret = qxl_gem_object_create(qdev, monitors_config_size, 0,
QXL_GEM_DOMAIN_VRAM,
false, false, NULL, &gobj);
@@ -932,13 +890,59 @@ int qxl_modeset_init(struct qxl_device *qdev)
return -ENOMEM;
}
qdev->monitors_config_bo = gem_to_qxl_bo(gobj);
+
+ ret = qxl_bo_reserve(qdev->monitors_config_bo, false);
+ if (ret)
+ return ret;
+
+ ret = qxl_bo_pin(qdev->monitors_config_bo, QXL_GEM_DOMAIN_VRAM, NULL);
+ if (ret) {
+ qxl_bo_unreserve(qdev->monitors_config_bo);
+ return ret;
+ }
+
+ qxl_bo_unreserve(qdev->monitors_config_bo);
+
qxl_bo_kmap(qdev->monitors_config_bo, NULL);
+
qdev->monitors_config = qdev->monitors_config_bo->kptr;
qdev->ram_header->monitors_config =
qxl_bo_physical_address(qdev, qdev->monitors_config_bo, 0);
memset(qdev->monitors_config, 0, monitors_config_size);
qdev->monitors_config->max_allowed = max_allowed;
+ return 0;
+}
+
+int qxl_destroy_monitors_object(struct qxl_device *qdev)
+{
+ int ret;
+
+ qdev->monitors_config = NULL;
+ qdev->ram_header->monitors_config = 0;
+
+ qxl_bo_kunmap(qdev->monitors_config_bo);
+ ret = qxl_bo_reserve(qdev->monitors_config_bo, false);
+ if (ret)
+ return ret;
+
+ qxl_bo_unpin(qdev->monitors_config_bo);
+ qxl_bo_unreserve(qdev->monitors_config_bo);
+
+ qxl_bo_unref(&qdev->monitors_config_bo);
+ return 0;
+}
+
+int qxl_modeset_init(struct qxl_device *qdev)
+{
+ int i;
+ int ret;
+
+ drm_mode_config_init(qdev->ddev);
+
+ ret = qxl_create_monitors_object(qdev);
+ if (ret)
+ return ret;
qdev->ddev->mode_config.funcs = (void *)&qxl_mode_funcs;
@@ -949,7 +953,7 @@ int qxl_modeset_init(struct qxl_device *qdev)
qdev->ddev->mode_config.max_height = 8192;
qdev->ddev->mode_config.fb_base = qdev->vram_base;
- for (i = 0 ; i < QXL_NUM_OUTPUTS; ++i) {
+ for (i = 0 ; i < qxl_num_crtc; ++i) {
qdev_crtc_init(qdev->ddev, i);
qdev_output_init(qdev->ddev, i);
}
@@ -966,6 +970,8 @@ int qxl_modeset_init(struct qxl_device *qdev)
void qxl_modeset_fini(struct qxl_device *qdev)
{
qxl_fbdev_fini(qdev);
+
+ qxl_destroy_monitors_object(qdev);
if (qdev->mode_info.mode_config_initialized) {
drm_mode_config_cleanup(qdev->ddev);
qdev->mode_info.mode_config_initialized = false;
diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
index aa291d8a98a2..df0b577a6608 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.c
+++ b/drivers/gpu/drm/qxl/qxl_drv.c
@@ -33,8 +33,9 @@
#include "drmP.h"
#include "drm/drm.h"
-
+#include "drm_crtc_helper.h"
#include "qxl_drv.h"
+#include "qxl_object.h"
extern int qxl_max_ioctls;
static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
@@ -47,10 +48,14 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
MODULE_DEVICE_TABLE(pci, pciidlist);
static int qxl_modeset = -1;
+int qxl_num_crtc = 4;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, qxl_modeset, int, 0400);
+MODULE_PARM_DESC(num_heads, "Number of virtual crtcs to expose (default 4)");
+module_param_named(num_heads, qxl_num_crtc, int, 0400);
+
static struct drm_driver qxl_driver;
static struct pci_driver qxl_pci_driver;
@@ -73,13 +78,6 @@ qxl_pci_remove(struct pci_dev *pdev)
drm_put_dev(dev);
}
-static struct pci_driver qxl_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = pciidlist,
- .probe = qxl_pci_probe,
- .remove = qxl_pci_remove,
-};
-
static const struct file_operations qxl_fops = {
.owner = THIS_MODULE,
.open = drm_open,
@@ -90,6 +88,130 @@ static const struct file_operations qxl_fops = {
.mmap = qxl_mmap,
};
+static int qxl_drm_freeze(struct drm_device *dev)
+{
+ struct pci_dev *pdev = dev->pdev;
+ struct qxl_device *qdev = dev->dev_private;
+ struct drm_crtc *crtc;
+
+ drm_kms_helper_poll_disable(dev);
+
+ console_lock();
+ qxl_fbdev_set_suspend(qdev, 1);
+ console_unlock();
+
+ /* unpin the front buffers */
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ if (crtc->enabled)
+ (*crtc_funcs->disable)(crtc);
+ }
+
+ qxl_destroy_monitors_object(qdev);
+ qxl_surf_evict(qdev);
+ qxl_vram_evict(qdev);
+
+ while (!qxl_check_idle(qdev->command_ring));
+ while (!qxl_check_idle(qdev->release_ring))
+ qxl_queue_garbage_collect(qdev, 1);
+
+ pci_save_state(pdev);
+
+ return 0;
+}
+
+static int qxl_drm_resume(struct drm_device *dev, bool thaw)
+{
+ struct qxl_device *qdev = dev->dev_private;
+
+ qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
+ if (!thaw) {
+ qxl_reinit_memslots(qdev);
+ qxl_ring_init_hdr(qdev->release_ring);
+ }
+
+ qxl_create_monitors_object(qdev);
+ drm_helper_resume_force_mode(dev);
+
+ console_lock();
+ qxl_fbdev_set_suspend(qdev, 0);
+ console_unlock();
+
+ drm_kms_helper_poll_enable(dev);
+ return 0;
+}
+
+static int qxl_pm_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ int error;
+
+ error = qxl_drm_freeze(drm_dev);
+ if (error)
+ return error;
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
+}
+
+static int qxl_pm_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ if (pci_enable_device(pdev)) {
+ return -EIO;
+ }
+
+ return qxl_drm_resume(drm_dev, false);
+}
+
+static int qxl_pm_thaw(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+ return qxl_drm_resume(drm_dev, true);
+}
+
+static int qxl_pm_freeze(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+ return qxl_drm_freeze(drm_dev);
+}
+
+static int qxl_pm_restore(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct qxl_device *qdev = drm_dev->dev_private;
+
+ qxl_io_reset(qdev);
+ return qxl_drm_resume(drm_dev, false);
+}
+
+static const struct dev_pm_ops qxl_pm_ops = {
+ .suspend = qxl_pm_suspend,
+ .resume = qxl_pm_resume,
+ .freeze = qxl_pm_freeze,
+ .thaw = qxl_pm_thaw,
+ .poweroff = qxl_pm_freeze,
+ .restore = qxl_pm_restore,
+};
+static struct pci_driver qxl_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = qxl_pci_probe,
+ .remove = qxl_pci_remove,
+ .driver.pm = &qxl_pm_ops,
+};
+
static struct drm_driver qxl_driver = {
.driver_features = DRIVER_GEM | DRIVER_MODESET |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED,
diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h
index 43d06ab28a21..aacb791464a3 100644
--- a/drivers/gpu/drm/qxl/qxl_drv.h
+++ b/drivers/gpu/drm/qxl/qxl_drv.h
@@ -55,11 +55,10 @@
#define DRIVER_MINOR 1
#define DRIVER_PATCHLEVEL 0
-#define QXL_NUM_OUTPUTS 1
-
#define QXL_DEBUGFS_MAX_COMPONENTS 32
extern int qxl_log_level;
+extern int qxl_num_crtc;
enum {
QXL_INFO_LEVEL = 1,
@@ -139,6 +138,7 @@ struct qxl_reloc_list {
struct qxl_crtc {
struct drm_crtc base;
+ int index;
int cur_x;
int cur_y;
};
@@ -156,7 +156,7 @@ struct qxl_framebuffer {
#define to_qxl_crtc(x) container_of(x, struct qxl_crtc, base)
#define drm_connector_to_qxl_output(x) container_of(x, struct qxl_output, base)
-#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, base)
+#define drm_encoder_to_qxl_output(x) container_of(x, struct qxl_output, enc)
#define to_qxl_framebuffer(x) container_of(x, struct qxl_framebuffer, base)
struct qxl_mman {
@@ -331,6 +331,10 @@ void qxl_modeset_fini(struct qxl_device *qdev);
int qxl_bo_init(struct qxl_device *qdev);
void qxl_bo_fini(struct qxl_device *qdev);
+void qxl_reinit_memslots(struct qxl_device *qdev);
+int qxl_surf_evict(struct qxl_device *qdev);
+int qxl_vram_evict(struct qxl_device *qdev);
+
struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
int element_size,
int n_elements,
@@ -338,6 +342,8 @@ struct qxl_ring *qxl_ring_create(struct qxl_ring_header *header,
bool set_prod_notify,
wait_queue_head_t *push_event);
void qxl_ring_free(struct qxl_ring *ring);
+void qxl_ring_init_hdr(struct qxl_ring *ring);
+int qxl_check_idle(struct qxl_ring *ring);
static inline void *
qxl_fb_virtual_address(struct qxl_device *qdev, unsigned long physical)
@@ -365,6 +371,7 @@ void qxl_fbdev_fini(struct qxl_device *qdev);
int qxl_get_handle_for_primary_fb(struct qxl_device *qdev,
struct drm_file *file_priv,
uint32_t *handle);
+void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state);
/* qxl_display.c */
int
@@ -374,6 +381,8 @@ qxl_framebuffer_init(struct drm_device *dev,
struct drm_gem_object *obj);
void qxl_display_read_client_monitors_config(struct qxl_device *qdev);
void qxl_send_monitors_config(struct qxl_device *qdev);
+int qxl_create_monitors_object(struct qxl_device *qdev);
+int qxl_destroy_monitors_object(struct qxl_device *qdev);
/* used by qxl_debugfs only */
void qxl_crtc_set_from_monitors_config(struct qxl_device *qdev);
@@ -435,7 +444,7 @@ void qxl_update_screen(struct qxl_device *qxl);
/* qxl io operations (qxl_cmd.c) */
void qxl_io_create_primary(struct qxl_device *qdev,
- unsigned width, unsigned height, unsigned offset,
+ unsigned offset,
struct qxl_bo *bo);
void qxl_io_destroy_primary(struct qxl_device *qdev);
void qxl_io_memslot_add(struct qxl_device *qdev, uint8_t id);
@@ -528,6 +537,7 @@ irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS);
/* qxl_fb.c */
int qxl_fb_init(struct qxl_device *qdev);
+bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj);
int qxl_debugfs_add_files(struct qxl_device *qdev,
struct drm_info_list *files,
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index b3c51275df5c..76f39d88d684 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -520,10 +520,6 @@ static int qxl_fbdev_destroy(struct drm_device *dev, struct qxl_fbdev *qfbdev)
}
static struct drm_fb_helper_funcs qxl_fb_helper_funcs = {
- /* TODO
- .gamma_set = qxl_crtc_fb_gamma_set,
- .gamma_get = qxl_crtc_fb_gamma_get,
- */
.fb_probe = qxl_fb_find_or_create_single,
};
@@ -542,7 +538,7 @@ int qxl_fbdev_init(struct qxl_device *qdev)
qfbdev->helper.funcs = &qxl_fb_helper_funcs;
ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
- 1 /* num_crtc - QXL supports just 1 */,
+ qxl_num_crtc /* num_crtc - QXL supports just 1 */,
QXLFB_CONN_LIMIT);
if (ret) {
kfree(qfbdev);
@@ -564,4 +560,14 @@ void qxl_fbdev_fini(struct qxl_device *qdev)
qdev->mode_info.qfbdev = NULL;
}
+void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state)
+{
+ fb_set_suspend(qdev->mode_info.qfbdev->helper.fbdev, state);
+}
+bool qxl_fbdev_qobj_is_fb(struct qxl_device *qdev, struct qxl_bo *qobj)
+{
+ if (qobj == gem_to_qxl_bo(qdev->mode_info.qfbdev->qfb.obj))
+ return true;
+ return false;
+}
diff --git a/drivers/gpu/drm/qxl/qxl_ioctl.c b/drivers/gpu/drm/qxl/qxl_ioctl.c
index a30f29425c21..27f45e49250d 100644
--- a/drivers/gpu/drm/qxl/qxl_ioctl.c
+++ b/drivers/gpu/drm/qxl/qxl_ioctl.c
@@ -188,6 +188,12 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
/* TODO copy slow path code from i915 */
fb_cmd = qxl_bo_kmap_atomic_page(qdev, cmd_bo, (release->release_offset & PAGE_SIZE));
unwritten = __copy_from_user_inatomic_nocache(fb_cmd + sizeof(union qxl_release_info) + (release->release_offset & ~PAGE_SIZE), (void *)(unsigned long)user_cmd.command, user_cmd.command_size);
+
+ {
+ struct qxl_drawable *draw = fb_cmd;
+
+ draw->mm_time = qdev->rom->mm_clock;
+ }
qxl_bo_kunmap_atomic_page(qdev, cmd_bo, fb_cmd);
if (unwritten) {
DRM_ERROR("got unwritten %d\n", unwritten);
diff --git a/drivers/gpu/drm/qxl/qxl_kms.c b/drivers/gpu/drm/qxl/qxl_kms.c
index e27ce2a907cf..9e8da9ee9731 100644
--- a/drivers/gpu/drm/qxl/qxl_kms.c
+++ b/drivers/gpu/drm/qxl/qxl_kms.c
@@ -26,6 +26,7 @@
#include "qxl_drv.h"
#include "qxl_object.h"
+#include <drm/drm_crtc_helper.h>
#include <linux/io-mapping.h>
int qxl_log_level;
@@ -72,21 +73,28 @@ static bool qxl_check_device(struct qxl_device *qdev)
return true;
}
+static void setup_hw_slot(struct qxl_device *qdev, int slot_index,
+ struct qxl_memslot *slot)
+{
+ qdev->ram_header->mem_slot.mem_start = slot->start_phys_addr;
+ qdev->ram_header->mem_slot.mem_end = slot->end_phys_addr;
+ qxl_io_memslot_add(qdev, slot_index);
+}
+
static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset,
unsigned long start_phys_addr, unsigned long end_phys_addr)
{
uint64_t high_bits;
struct qxl_memslot *slot;
uint8_t slot_index;
- struct qxl_ram_header *ram_header = qdev->ram_header;
slot_index = qdev->rom->slots_start + slot_index_offset;
slot = &qdev->mem_slots[slot_index];
slot->start_phys_addr = start_phys_addr;
slot->end_phys_addr = end_phys_addr;
- ram_header->mem_slot.mem_start = slot->start_phys_addr;
- ram_header->mem_slot.mem_end = slot->end_phys_addr;
- qxl_io_memslot_add(qdev, slot_index);
+
+ setup_hw_slot(qdev, slot_index, slot);
+
slot->generation = qdev->rom->slot_generation;
high_bits = slot_index << qdev->slot_gen_bits;
high_bits |= slot->generation;
@@ -95,6 +103,12 @@ static uint8_t setup_slot(struct qxl_device *qdev, uint8_t slot_index_offset,
return slot_index;
}
+void qxl_reinit_memslots(struct qxl_device *qdev)
+{
+ setup_hw_slot(qdev, qdev->main_mem_slot, &qdev->mem_slots[qdev->main_mem_slot]);
+ setup_hw_slot(qdev, qdev->surfaces_mem_slot, &qdev->mem_slots[qdev->surfaces_mem_slot]);
+}
+
static void qxl_gc_work(struct work_struct *work)
{
struct qxl_device *qdev = container_of(work, struct qxl_device, gc_work);
@@ -294,6 +308,8 @@ int qxl_driver_load(struct drm_device *dev, unsigned long flags)
goto out;
}
+ drm_kms_helper_poll_init(qdev->ddev);
+
return 0;
out:
kfree(qdev);
diff --git a/drivers/gpu/drm/qxl/qxl_object.c b/drivers/gpu/drm/qxl/qxl_object.c
index d9b12e7bc6e1..1191fe7788c9 100644
--- a/drivers/gpu/drm/qxl/qxl_object.c
+++ b/drivers/gpu/drm/qxl/qxl_object.c
@@ -363,3 +363,13 @@ int qxl_bo_list_add(struct qxl_reloc_list *reloc_list, struct qxl_bo *bo)
return ret;
return 0;
}
+
+int qxl_surf_evict(struct qxl_device *qdev)
+{
+ return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_PRIV0);
+}
+
+int qxl_vram_evict(struct qxl_device *qdev)
+{
+ return ttm_bo_evict_mm(&qdev->mman.bdev, TTM_PL_VRAM);
+}
diff --git a/drivers/gpu/drm/qxl/qxl_object.h b/drivers/gpu/drm/qxl/qxl_object.h
index b4fd89fbd8b7..ee7ad79ce781 100644
--- a/drivers/gpu/drm/qxl/qxl_object.h
+++ b/drivers/gpu/drm/qxl/qxl_object.h
@@ -57,11 +57,6 @@ static inline unsigned long qxl_bo_size(struct qxl_bo *bo)
return bo->tbo.num_pages << PAGE_SHIFT;
}
-static inline bool qxl_bo_is_reserved(struct qxl_bo *bo)
-{
- return !!atomic_read(&bo->tbo.reserved);
-}
-
static inline u64 qxl_bo_mmap_offset(struct qxl_bo *bo)
{
return bo->tbo.addr_space_offset;
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 86c5e3611892..c3df52c1a60c 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -76,7 +76,10 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
- si_blit_shaders.o radeon_prime.o radeon_uvd.o
+ si_blit_shaders.o radeon_prime.o radeon_uvd.o cik.o cik_blit_shaders.o \
+ r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
+ rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
+ trinity_smc.o ni_dpm.o si_smc.o si_dpm.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h
index ca4b038050d2..06192698bd96 100644
--- a/drivers/gpu/drm/radeon/ObjectID.h
+++ b/drivers/gpu/drm/radeon/ObjectID.h
@@ -69,6 +69,8 @@
#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
@@ -86,6 +88,8 @@
#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
@@ -364,6 +368,14 @@
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)
@@ -392,6 +404,10 @@
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 */
/****************************************************/
@@ -461,6 +477,14 @@
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)
@@ -473,6 +497,10 @@
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)
@@ -541,6 +569,18 @@
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)
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 0ee573743de9..16b120c3f144 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -74,6 +74,8 @@
#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
@@ -259,7 +261,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
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 ASIC_StaticPwrMgtStatusChange; //Obsolete , 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
@@ -271,7 +273,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
USHORT TVEncoderControl; //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 TV1OutputControl; //Atomic Table, Obsolete from Ry6xx, use DAC2 Output instead
+ 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
@@ -328,7 +330,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
#define UNIPHYTransmitterControl DIG1TransmitterControl
#define LVTMATransmitterControl DIG2TransmitterControl
#define SetCRTC_DPM_State GetConditionalGoldenSetting
-#define SetUniphyInstance ASIC_StaticPwrMgtStatusChange
+#define ASIC_StaticPwrMgtStatusChange SetUniphyInstance
#define HPDInterruptService ReadHWAssistedI2CStatus
#define EnableVGA_Access GetSCLKOverMCLKRatio
#define EnableYUV GetDispObjectInfo
@@ -338,7 +340,7 @@ typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{
#define TMDSAEncoderControl PatchMCSetting
#define LVDSEncoderControl MC_SEQ_Control
#define LCD1OutputControl HW_Misc_Operation
-
+#define TV1OutputControl Gfx_Harvesting
typedef struct _ATOM_MASTER_COMMAND_TABLE
{
@@ -478,11 +480,11 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3
typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4
{
#if ATOM_BIG_ENDIAN
- ULONG ucPostDiv; //return parameter: post divider which is used to program to register directly
+ 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; //return parameter: post divider which is used to program to register directly
+ ULONG ucPostDiv:8; //return parameter: post divider which is used to program to register directly
#endif
}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4;
@@ -504,6 +506,32 @@ typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5
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
@@ -1686,6 +1714,7 @@ typedef struct _PIXEL_CLOCK_PARAMETERS_V6
#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP 0x08
#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
typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2
{
@@ -2102,6 +2131,17 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
}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
@@ -2165,7 +2205,7 @@ typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3
#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_GPIOVAL 0x1
#define SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK 0x2
typedef struct _SET_VOLTAGE_PARAMETERS
@@ -2200,15 +2240,20 @@ typedef struct _SET_VOLTAGE_PARAMETERS_V1_3
//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
-#define ATOM_GET_MAX_VOLTAGE 6 //Get Max Voltage, not used in SetVoltageTable v1.3
-#define ATOM_GET_VOLTAGE_LEVEL 6 //Get Voltage level from vitual voltage ID
+#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
{
@@ -2628,7 +2673,8 @@ typedef struct _ATOM_FIRMWARE_INFO_V2_2
ULONG ulFirmwareRevision;
ULONG ulDefaultEngineClock; //In 10Khz unit
ULONG ulDefaultMemoryClock; //In 10Khz unit
- ULONG ulReserved[2];
+ 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
@@ -3813,6 +3859,12 @@ typedef struct _ATOM_GPIO_PIN_ASSIGNMENT
UCHAR ucGPIO_ID;
}ATOM_GPIO_PIN_ASSIGNMENT;
+//ucGPIO_ID pre-define id for multiple usage
+//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
+
typedef struct _ATOM_GPIO_PIN_LUT
{
ATOM_COMMON_TABLE_HEADER sHeader;
@@ -4074,17 +4126,19 @@ typedef struct _EXT_DISPLAY_PATH
//usCaps
#define EXT_DISPLAY_PATH_CAPS__HBR2_DISABLE 0x01
+#define EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN 0x02
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 ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0.
UCHAR uc3DStereoPinId; // use for eDP panel
UCHAR ucRemoteDisplayConfig;
UCHAR uceDPToLVDSRxId;
- UCHAR Reserved[4]; // for potential expansion
+ 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 different but they have a commond header
@@ -4416,6 +4470,13 @@ typedef struct _ATOM_VOLTAGE_CONTROL
#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
typedef struct _ATOM_VOLTAGE_OBJECT
{
@@ -4458,6 +4519,15 @@ typedef struct _ATOM_VOLTAGE_OBJECT_HEADER_V3{
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_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
@@ -4473,7 +4543,7 @@ typedef struct _LEAKAGE_VOLTAGE_LUT_ENTRY_V2
typedef struct _ATOM_I2C_VOLTAGE_OBJECT_V3
{
- ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+ ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader; // voltage mode = VOLTAGE_OBJ_VR_I2C_INIT_SEQ
UCHAR ucVoltageRegulatorId; //Indicate Voltage Regulator Id
UCHAR ucVoltageControlI2cLine;
UCHAR ucVoltageControlAddress;
@@ -4484,7 +4554,7 @@ typedef struct _ATOM_I2C_VOLTAGE_OBJECT_V3
typedef struct _ATOM_GPIO_VOLTAGE_OBJECT_V3
{
- ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+ 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
@@ -4495,7 +4565,7 @@ typedef struct _ATOM_GPIO_VOLTAGE_OBJECT_V3
typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
{
- ATOM_VOLTAGE_OBJECT_HEADER_V3 sHeader;
+ 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];
@@ -4503,10 +4573,26 @@ typedef struct _ATOM_LEAKAGE_VOLTAGE_OBJECT_V3
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 ucReserved[2];
+ 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
@@ -4536,6 +4622,21 @@ typedef struct _ATOM_ASIC_PROFILING_INFO
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;
+
typedef struct _ATOM_POWER_SOURCE_OBJECT
{
UCHAR ucPwrSrcId; // Power source
@@ -4652,6 +4753,8 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6
#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
@@ -4752,6 +4855,29 @@ 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.
@@ -4784,7 +4910,8 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
UCHAR ucMemoryType;
UCHAR ucUMAChannelNumber;
UCHAR strVBIOSMsg[40];
- ULONG ulReserved[20];
+ ATOM_TDP_CONFIG asTdpConfig;
+ ULONG ulReserved[19];
ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5];
ULONG ulGMCRestoreResetTime;
ULONG ulMinimumNClk;
@@ -4809,7 +4936,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
USHORT GnbTdpLimit;
USHORT usMaxLVDSPclkFreqInSingleLink;
UCHAR ucLvdsMisc;
- UCHAR ucLVDSReserved;
+ UCHAR ucTravisLVDSVolAdjust;
UCHAR ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
UCHAR ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
UCHAR ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
@@ -4817,7 +4944,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
UCHAR ucLVDSOffToOnDelay_in4Ms;
UCHAR ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
UCHAR ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
- UCHAR ucLVDSReserved1;
+ UCHAR ucMinAllowedBL_Level;
ULONG ulLCDBitDepthControlVal;
ULONG ulNbpStateMemclkFreq[4];
USHORT usNBP2Voltage;
@@ -4846,6 +4973,7 @@ typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7
#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
/**********************************************************************************************************************
ATOM_INTEGRATED_SYSTEM_INFO_V1_7 Description
@@ -4945,6 +5073,9 @@ ucLVDSMisc: [bit0] LVDS 888bit panel mode =0: LVDS 888 pan
[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.
@@ -4964,18 +5095,241 @@ ucLVDSOffToOnDelay_in4Ms: LVDS power down sequence time in unit of 4ms.
=0 means to use VBIOS default delay which is 125 ( 500ms ).
This parameter is used by VBIOS only. VBIOS will patch LVDS_InfoTable.
-ucLVDSPwrOnVARY_BLtoBLON_in4Ms: LVDS power up sequence time in unit of 4ms. Time delay from VARY_BL signal on to DLON signal active.
+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.
-ucLVDSPwrOffBLONtoVARY_BL_in4Ms: LVDS power down sequence time in unit of 4ms. Time delay from BLON signal off to VARY_BL signal off.
+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;
+ 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];
+ ULONG ulReserved6;
+ 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;
+
+
/**************************************************************************/
// This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design
//Memory SS Info Table
@@ -5026,22 +5380,24 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT
//Define ucClockIndication, SW uses the IDs below to search if the SS is required/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_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 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
@@ -5079,6 +5435,11 @@ typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V3
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;
@@ -5719,6 +6080,7 @@ typedef struct _INDIRECT_IO_ACCESS
#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
@@ -5730,6 +6092,8 @@ typedef struct _INDIRECT_IO_ACCESS
#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
{
@@ -5875,6 +6239,7 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
#define _64Mx32 0x43
#define _128Mx8 0x51
#define _128Mx16 0x52
+#define _128Mx32 0x53
#define _256Mx8 0x61
#define _256Mx16 0x62
@@ -5893,6 +6258,8 @@ typedef struct _ATOM_MC_INIT_PARAM_TABLE
#define PROMOS MOSEL
#define KRETON INFINEON
#define ELIXIR NANYA
+#define MEZZA ELPIDA
+
/////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM/////////////
@@ -6625,6 +6992,10 @@ typedef struct _ATOM_DISP_OUT_INFO_V3
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,
@@ -6829,6 +7200,17 @@ typedef struct _DIG_TRANSMITTER_INFO_HEADER_V3_1{
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 _CLOCK_CONDITION_REGESTER_INFO{
USHORT usRegisterIndex;
UCHAR ucStartBit;
@@ -6852,12 +7234,24 @@ typedef struct _PHY_CONDITION_REG_VAL{
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;
@@ -6865,6 +7259,25 @@ typedef struct _PHY_ANALOG_SETTING_INFO{
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
+
/****************************************************************************/
//Portion VI: Definitinos for vbios MC scratch registers that driver used
/****************************************************************************/
@@ -6875,8 +7288,17 @@ typedef struct _PHY_ANALOG_SETTING_INFO{
#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 VI: Definitinos being oboselete
/****************************************************************************/
@@ -7274,6 +7696,7 @@ typedef struct _ATOM_PPLIB_THERMALCONTROLLER
#define ATOM_PP_THERMALCONTROLLER_NISLANDS 15
#define ATOM_PP_THERMALCONTROLLER_SISLANDS 16
#define ATOM_PP_THERMALCONTROLLER_LM96163 17
+#define ATOM_PP_THERMALCONTROLLER_CISLANDS 18
// Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal.
// We probably should reserve the bit 0x80 for this use.
@@ -7316,6 +7739,8 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
// Add extra system parameters here, always adjust size to include all fields.
USHORT usVCETableOffset; //points to ATOM_PPLIB_VCE_Table
USHORT usUVDTableOffset; //points to ATOM_PPLIB_UVD_Table
+ USHORT usSAMUTableOffset; //points to ATOM_PPLIB_SAMU_Table
+ USHORT usPPMTableOffset; //points to ATOM_PPLIB_PPM_Table
} ATOM_PPLIB_EXTENDEDHEADER;
//// ATOM_PPLIB_POWERPLAYTABLE::ulPlatformCaps
@@ -7337,7 +7762,10 @@ typedef struct _ATOM_PPLIB_EXTENDEDHEADER
#define ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL 0x8000 // Does the driver control VDDCI independently from VDDC.
#define ATOM_PP_PLATFORM_CAP_REGULATOR_HOT 0x00010000 // Enable the 'regulator hot' feature.
#define ATOM_PP_PLATFORM_CAP_BACO 0x00020000 // Does the driver supports BACO state.
-
+#define ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE 0x00040000 // Does the driver supports new CAC voltage table.
+#define ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY 0x00080000 // Does the driver supports revert GPIO5 polarity.
+#define ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17 0x00100000 // Does the driver supports thermal2GPIO17.
+#define ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE 0x00200000 // Does the driver supports VR HOT GPIO Configurable.
typedef struct _ATOM_PPLIB_POWERPLAYTABLE
{
@@ -7398,7 +7826,7 @@ typedef struct _ATOM_PPLIB_POWERPLAYTABLE4
USHORT usVddcDependencyOnMCLKOffset;
USHORT usMaxClockVoltageOnDCOffset;
USHORT usVddcPhaseShedLimitsTableOffset; // Points to ATOM_PPLIB_PhaseSheddingLimits_Table
- USHORT usReserved;
+ USHORT usMvddDependencyOnMCLKOffset;
} ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4;
typedef struct _ATOM_PPLIB_POWERPLAYTABLE5
@@ -7563,6 +7991,17 @@ typedef struct _ATOM_PPLIB_SI_CLOCK_INFO
} ATOM_PPLIB_SI_CLOCK_INFO;
+typedef struct _ATOM_PPLIB_CI_CLOCK_INFO
+{
+ USHORT usEngineClockLow;
+ UCHAR ucEngineClockHigh;
+
+ USHORT usMemoryClockLow;
+ UCHAR ucMemoryClockHigh;
+
+ UCHAR ucPCIEGen;
+ USHORT usPCIELane;
+} ATOM_PPLIB_CI_CLOCK_INFO;
typedef struct _ATOM_PPLIB_RS780_CLOCK_INFO
@@ -7680,8 +8119,8 @@ typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table
typedef struct _ATOM_PPLIB_CAC_Leakage_Record
{
- USHORT usVddc; // We use this field for the "fake" standardized VDDC for power calculations
- ULONG ulLeakageValue;
+ USHORT usVddc; // We use this field for the "fake" standardized VDDC for power calculations; For CI and newer, we use this as the real VDDC value.
+ ULONG ulLeakageValue; // For CI and newer we use this as the "fake" standar VDDC value.
}ATOM_PPLIB_CAC_Leakage_Record;
typedef struct _ATOM_PPLIB_CAC_Leakage_Table
@@ -7796,6 +8235,42 @@ typedef struct _ATOM_PPLIB_UVD_Table
// ATOM_PPLIB_UVD_State_Table states;
}ATOM_PPLIB_UVD_Table;
+
+typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Record
+{
+ USHORT usVoltage;
+ USHORT usSAMClockLow;
+ UCHAR ucSAMClockHigh;
+}ATOM_PPLIB_SAMClk_Voltage_Limit_Record;
+
+typedef struct _ATOM_PPLIB_SAMClk_Voltage_Limit_Table{
+ UCHAR numEntries;
+ ATOM_PPLIB_SAMClk_Voltage_Limit_Record entries[1];
+}ATOM_PPLIB_SAMClk_Voltage_Limit_Table;
+
+typedef struct _ATOM_PPLIB_SAMU_Table
+{
+ UCHAR revid;
+ ATOM_PPLIB_SAMClk_Voltage_Limit_Table limits;
+}ATOM_PPLIB_SAMU_Table;
+
+#define ATOM_PPM_A_A 1
+#define ATOM_PPM_A_I 2
+typedef struct _ATOM_PPLIB_PPM_Table
+{
+ UCHAR ucRevId;
+ UCHAR ucPpmDesign; //A+I or A+A
+ USHORT usCpuCoreNumber;
+ ULONG ulPlatformTDP;
+ ULONG ulSmallACPlatformTDP;
+ ULONG ulPlatformTDC;
+ ULONG ulSmallACPlatformTDC;
+ ULONG ulApuTDP;
+ ULONG ulDGpuTDP;
+ ULONG ulDGpuUlvPower;
+ ULONG ulTjmax;
+} ATOM_PPLIB_PPM_Table;
+
/**************************************************************************/
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index d5df8fd10217..b9d3b43f19c0 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -555,7 +555,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
if (rdev->family < CHIP_RV770)
radeon_crtc->pll_flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP;
/* use frac fb div on APUs */
- if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev))
+ if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
radeon_crtc->pll_flags |= RADEON_PLL_USE_FRAC_FB_DIV;
/* use frac fb div on RS780/RS880 */
if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
@@ -743,7 +743,7 @@ static void atombios_crtc_set_disp_eng_pll(struct radeon_device *rdev,
* SetPixelClock provides the dividers
*/
args.v6.ulDispEngClkFreq = cpu_to_le32(dispclk);
- if (ASIC_IS_DCE61(rdev))
+ if (ASIC_IS_DCE61(rdev) || ASIC_IS_DCE8(rdev))
args.v6.ucPpll = ATOM_EXT_PLL1;
else if (ASIC_IS_DCE6(rdev))
args.v6.ucPpll = ATOM_PPLL0;
@@ -1143,7 +1143,9 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
}
if (tiling_flags & RADEON_TILING_MACRO) {
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ tmp = rdev->config.cik.tile_config;
+ else if (rdev->family >= CHIP_TAHITI)
tmp = rdev->config.si.tile_config;
else if (rdev->family >= CHIP_CAYMAN)
tmp = rdev->config.cayman.tile_config;
@@ -1170,11 +1172,29 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw);
fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh);
fb_format |= EVERGREEN_GRPH_MACRO_TILE_ASPECT(mtaspect);
+ if (rdev->family >= CHIP_BONAIRE) {
+ /* XXX need to know more about the surface tiling mode */
+ fb_format |= CIK_GRPH_MICRO_TILE_MODE(CIK_DISPLAY_MICRO_TILING);
+ }
} else if (tiling_flags & RADEON_TILING_MICRO)
fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1);
- if ((rdev->family == CHIP_TAHITI) ||
- (rdev->family == CHIP_PITCAIRN))
+ if (rdev->family >= CHIP_BONAIRE) {
+ u32 num_pipe_configs = rdev->config.cik.max_tile_pipes;
+ u32 num_rb = rdev->config.cik.max_backends_per_se;
+ if (num_pipe_configs > 8)
+ num_pipe_configs = 8;
+ if (num_pipe_configs == 8)
+ fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P8_32x32_16x16);
+ else if (num_pipe_configs == 4) {
+ if (num_rb == 4)
+ fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_16x16);
+ else if (num_rb < 4)
+ fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_8x16);
+ } else if (num_pipe_configs == 2)
+ fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P2);
+ } else if ((rdev->family == CHIP_TAHITI) ||
+ (rdev->family == CHIP_PITCAIRN))
fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16);
else if (rdev->family == CHIP_VERDE)
fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P4_8x16);
@@ -1224,8 +1244,12 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
WREG32(EVERGREEN_GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
- WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
- target_fb->height);
+ if (rdev->family >= CHIP_BONAIRE)
+ WREG32(CIK_LB_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+ target_fb->height);
+ else
+ WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+ target_fb->height);
x &= ~3;
y &= ~1;
WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset,
@@ -1597,6 +1621,12 @@ static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc)
*
* Asic specific PLL information
*
+ * DCE 8.x
+ * KB/KV
+ * - 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
+ *
* DCE 6.1
* - PPLL2 is only available to UNIPHYA (both DP and non-DP)
* - PPLL0, PPLL1 are available for UNIPHYB/C/D/E/F (both DP and non-DP)
@@ -1623,7 +1653,47 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
u32 pll_in_use;
int pll;
- if (ASIC_IS_DCE61(rdev)) {
+ if (ASIC_IS_DCE8(rdev)) {
+ if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
+ if (rdev->clock.dp_extclk)
+ /* skip PPLL programming if using ext clock */
+ return ATOM_PPLL_INVALID;
+ else {
+ /* use the same PPLL for all DP monitors */
+ pll = radeon_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 = radeon_get_shared_nondp_ppll(crtc);
+ if (pll != ATOM_PPLL_INVALID)
+ return pll;
+ }
+ /* otherwise, pick one of the plls */
+ if ((rdev->family == CHIP_KAVERI) ||
+ (rdev->family == CHIP_KABINI)) {
+ /* KB/KV has PPLL1 and PPLL2 */
+ pll_in_use = radeon_get_pll_use_mask(crtc);
+ if (!(pll_in_use & (1 << ATOM_PPLL2)))
+ return ATOM_PPLL2;
+ if (!(pll_in_use & (1 << ATOM_PPLL1)))
+ return ATOM_PPLL1;
+ DRM_ERROR("unable to allocate a PPLL\n");
+ return ATOM_PPLL_INVALID;
+ } else {
+ /* CI has PPLL0, PPLL1, and PPLL2 */
+ pll_in_use = radeon_get_pll_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;
+ }
+ } else if (ASIC_IS_DCE61(rdev)) {
struct radeon_encoder_atom_dig *dig =
radeon_encoder->enc_priv;
@@ -1771,6 +1841,9 @@ int atombios_crtc_mode_set(struct drm_crtc *crtc,
atombios_crtc_set_base(crtc, x, y, old_fb);
atombios_overscan_setup(crtc, mode, adjusted_mode);
atombios_scaler_setup(crtc);
+ /* update the hw version fpr dpm */
+ radeon_crtc->hw_mode = *adjusted_mode;
+
return 0;
}
@@ -1861,7 +1934,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
break;
case ATOM_PPLL0:
/* disable the ppll */
- if (ASIC_IS_DCE61(rdev))
+ if ((rdev->family == CHIP_ARUBA) || (rdev->family == CHIP_BONAIRE))
atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
break;
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 8406c8251fbf..092275d53d4a 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -186,6 +186,13 @@ void radeon_atom_backlight_init(struct radeon_encoder *radeon_encoder,
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 ((rdev->pdev->subsystem_vendor == PCI_VENDOR_ID_APPLE) &&
+ (rdev->pdev->device == 0x6741))
+ return;
+
if (!radeon_encoder->enc_priv)
return;
@@ -296,6 +303,7 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
return true;
default:
return false;
@@ -479,11 +487,11 @@ static u8 radeon_atom_get_bpc(struct drm_encoder *encoder)
}
}
-
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;
};
void
@@ -533,6 +541,13 @@ atombios_dvo_setup(struct drm_encoder *encoder, int action)
args.dvo_v3.usPixelClock = cpu_to_le16(radeon_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(radeon_encoder->pixel_clock / 10);
+ args.dvo_v4.ucDVOConfig = 0; /* XXX */
+ args.dvo_v4.ucBitPerColor = radeon_atom_get_bpc(encoder);
+ break;
default:
DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
break;
@@ -915,10 +930,14 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
args.v4.ucLaneNum = 4;
if (ENCODER_MODE_IS_DP(args.v4.ucEncoderMode)) {
- if (dp_clock == 270000)
- args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
- else if (dp_clock == 540000)
+ 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 = radeon_atom_get_bpc(encoder);
@@ -1012,6 +1031,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
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:
@@ -1271,6 +1291,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
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;
@@ -1735,6 +1758,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
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:
radeon_atom_encoder_dpms_dig(encoder, mode);
break;
@@ -1872,6 +1896,7 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
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 = radeon_encoder->enc_priv;
switch (dig->dig_encoder) {
@@ -1893,6 +1918,9 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
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:
@@ -1955,7 +1983,13 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
/* set scaler clears this on some chips */
if (ASIC_IS_AVIVO(rdev) &&
(!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
- if (ASIC_IS_DCE4(rdev)) {
+ if (ASIC_IS_DCE8(rdev)) {
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset,
+ CIK_INTERLEAVE_EN);
+ else
+ WREG32(CIK_LB_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+ } else if (ASIC_IS_DCE4(rdev)) {
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
EVERGREEN_INTERLEAVE_EN);
@@ -2002,6 +2036,9 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
else
return 4;
break;
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
+ return 6;
+ break;
}
} else if (ASIC_IS_DCE4(rdev)) {
/* DCE4/5 */
@@ -2086,6 +2123,7 @@ radeon_atom_encoder_init(struct radeon_device *rdev)
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:
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
break;
@@ -2130,6 +2168,7 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
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:
/* handled in dpms */
break;
@@ -2395,6 +2434,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
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:
/* handled in dpms */
break;
@@ -2626,6 +2666,7 @@ radeon_add_atom_encoder(struct drm_device *dev,
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
radeon_encoder->rmx_type = RMX_FULL;
drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
new file mode 100644
index 000000000000..0bfd55e08820
--- /dev/null
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -0,0 +1,2751 @@
+/*
+ * 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 "radeon.h"
+#include "btcd.h"
+#include "r600_dpm.h"
+#include "cypress_dpm.h"
+#include "btc_dpm.h"
+#include "atom.h"
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0 0x05
+#define MC_CG_SEQ_DRAMCONF_S1 0x06
+#define MC_CG_SEQ_YCLK_SUSPEND 0x04
+#define MC_CG_SEQ_YCLK_RESUME 0x0a
+
+#define SMC_RAM_END 0x8000
+
+#ifndef BTC_MGCG_SEQUENCE
+#define BTC_MGCG_SEQUENCE 300
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+
+
+//********* BARTS **************//
+static const u32 barts_cgcg_cgls_default[] =
+{
+ /* Register, Value, Mask bits */
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define BARTS_CGCG_CGLS_DEFAULT_LENGTH sizeof(barts_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 barts_cgcg_cgls_disable[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00000644, 0x000f7912, 0x001f4180,
+ 0x00000644, 0x000f3812, 0x001f4180
+};
+#define BARTS_CGCG_CGLS_DISABLE_LENGTH sizeof(barts_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 barts_cgcg_cgls_enable[] =
+{
+ /* 0x0000c124, 0x84180000, 0x00180000, */
+ 0x00000644, 0x000f7892, 0x001f4080,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff
+};
+#define BARTS_CGCG_CGLS_ENABLE_LENGTH sizeof(barts_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+static const u32 barts_mgcg_default[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00005448, 0x00000100, 0xffffffff,
+ 0x000055e4, 0x00600100, 0xffffffff,
+ 0x0000160c, 0x00000100, 0xffffffff,
+ 0x0000c164, 0x00000100, 0xffffffff,
+ 0x00008a18, 0x00000100, 0xffffffff,
+ 0x0000897c, 0x06000100, 0xffffffff,
+ 0x00008b28, 0x00000100, 0xffffffff,
+ 0x00009144, 0x00000100, 0xffffffff,
+ 0x00009a60, 0x00000100, 0xffffffff,
+ 0x00009868, 0x00000100, 0xffffffff,
+ 0x00008d58, 0x00000100, 0xffffffff,
+ 0x00009510, 0x00000100, 0xffffffff,
+ 0x0000949c, 0x00000100, 0xffffffff,
+ 0x00009654, 0x00000100, 0xffffffff,
+ 0x00009030, 0x00000100, 0xffffffff,
+ 0x00009034, 0x00000100, 0xffffffff,
+ 0x00009038, 0x00000100, 0xffffffff,
+ 0x0000903c, 0x00000100, 0xffffffff,
+ 0x00009040, 0x00000100, 0xffffffff,
+ 0x0000a200, 0x00000100, 0xffffffff,
+ 0x0000a204, 0x00000100, 0xffffffff,
+ 0x0000a208, 0x00000100, 0xffffffff,
+ 0x0000a20c, 0x00000100, 0xffffffff,
+ 0x0000977c, 0x00000100, 0xffffffff,
+ 0x00003f80, 0x00000100, 0xffffffff,
+ 0x0000a210, 0x00000100, 0xffffffff,
+ 0x0000a214, 0x00000100, 0xffffffff,
+ 0x000004d8, 0x00000100, 0xffffffff,
+ 0x00009784, 0x00000100, 0xffffffff,
+ 0x00009698, 0x00000100, 0xffffffff,
+ 0x000004d4, 0x00000200, 0xffffffff,
+ 0x000004d0, 0x00000000, 0xffffffff,
+ 0x000030cc, 0x00000100, 0xffffffff,
+ 0x0000d0c0, 0xff000100, 0xffffffff,
+ 0x0000802c, 0x40000000, 0xffffffff,
+ 0x0000915c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091b0, 0x00070000, 0xffffffff,
+ 0x000091b4, 0x00030002, 0xffffffff,
+ 0x000091b8, 0x00050004, 0xffffffff,
+ 0x000091c4, 0x00010006, 0xffffffff,
+ 0x000091c8, 0x00090008, 0xffffffff,
+ 0x000091cc, 0x00070000, 0xffffffff,
+ 0x000091d0, 0x00030002, 0xffffffff,
+ 0x000091d4, 0x00050004, 0xffffffff,
+ 0x000091e0, 0x00010006, 0xffffffff,
+ 0x000091e4, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x000091ec, 0x00070000, 0xffffffff,
+ 0x000091f0, 0x00030002, 0xffffffff,
+ 0x000091f4, 0x00050004, 0xffffffff,
+ 0x00009200, 0x00010006, 0xffffffff,
+ 0x00009204, 0x00090008, 0xffffffff,
+ 0x00009208, 0x00070000, 0xffffffff,
+ 0x0000920c, 0x00030002, 0xffffffff,
+ 0x00009210, 0x00050004, 0xffffffff,
+ 0x0000921c, 0x00010006, 0xffffffff,
+ 0x00009220, 0x00090008, 0xffffffff,
+ 0x00009224, 0x00070000, 0xffffffff,
+ 0x00009228, 0x00030002, 0xffffffff,
+ 0x0000922c, 0x00050004, 0xffffffff,
+ 0x00009238, 0x00010006, 0xffffffff,
+ 0x0000923c, 0x00090008, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff,
+ 0x0000802c, 0x40010000, 0xffffffff,
+ 0x0000915c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091b0, 0x00070000, 0xffffffff,
+ 0x000091b4, 0x00030002, 0xffffffff,
+ 0x000091b8, 0x00050004, 0xffffffff,
+ 0x000091c4, 0x00010006, 0xffffffff,
+ 0x000091c8, 0x00090008, 0xffffffff,
+ 0x000091cc, 0x00070000, 0xffffffff,
+ 0x000091d0, 0x00030002, 0xffffffff,
+ 0x000091d4, 0x00050004, 0xffffffff,
+ 0x000091e0, 0x00010006, 0xffffffff,
+ 0x000091e4, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x000091ec, 0x00070000, 0xffffffff,
+ 0x000091f0, 0x00030002, 0xffffffff,
+ 0x000091f4, 0x00050004, 0xffffffff,
+ 0x00009200, 0x00010006, 0xffffffff,
+ 0x00009204, 0x00090008, 0xffffffff,
+ 0x00009208, 0x00070000, 0xffffffff,
+ 0x0000920c, 0x00030002, 0xffffffff,
+ 0x00009210, 0x00050004, 0xffffffff,
+ 0x0000921c, 0x00010006, 0xffffffff,
+ 0x00009220, 0x00090008, 0xffffffff,
+ 0x00009224, 0x00070000, 0xffffffff,
+ 0x00009228, 0x00030002, 0xffffffff,
+ 0x0000922c, 0x00050004, 0xffffffff,
+ 0x00009238, 0x00010006, 0xffffffff,
+ 0x0000923c, 0x00090008, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff,
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define BARTS_MGCG_DEFAULT_LENGTH sizeof(barts_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 barts_mgcg_disable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x00009150, 0x00600000, 0xffffffff
+};
+#define BARTS_MGCG_DISABLE_LENGTH sizeof(barts_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 barts_mgcg_enable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00009150, 0x81944000, 0xffffffff
+};
+#define BARTS_MGCG_ENABLE_LENGTH sizeof(barts_mgcg_enable) / (3 * sizeof(u32))
+
+//********* CAICOS **************//
+static const u32 caicos_cgcg_cgls_default[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAICOS_CGCG_CGLS_DEFAULT_LENGTH sizeof(caicos_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 caicos_cgcg_cgls_disable[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00000644, 0x000f7912, 0x001f4180,
+ 0x00000644, 0x000f3812, 0x001f4180
+};
+#define CAICOS_CGCG_CGLS_DISABLE_LENGTH sizeof(caicos_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 caicos_cgcg_cgls_enable[] =
+{
+ /* 0x0000c124, 0x84180000, 0x00180000, */
+ 0x00000644, 0x000f7892, 0x001f4080,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff
+};
+#define CAICOS_CGCG_CGLS_ENABLE_LENGTH sizeof(caicos_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+static const u32 caicos_mgcg_default[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00005448, 0x00000100, 0xffffffff,
+ 0x000055e4, 0x00600100, 0xffffffff,
+ 0x0000160c, 0x00000100, 0xffffffff,
+ 0x0000c164, 0x00000100, 0xffffffff,
+ 0x00008a18, 0x00000100, 0xffffffff,
+ 0x0000897c, 0x06000100, 0xffffffff,
+ 0x00008b28, 0x00000100, 0xffffffff,
+ 0x00009144, 0x00000100, 0xffffffff,
+ 0x00009a60, 0x00000100, 0xffffffff,
+ 0x00009868, 0x00000100, 0xffffffff,
+ 0x00008d58, 0x00000100, 0xffffffff,
+ 0x00009510, 0x00000100, 0xffffffff,
+ 0x0000949c, 0x00000100, 0xffffffff,
+ 0x00009654, 0x00000100, 0xffffffff,
+ 0x00009030, 0x00000100, 0xffffffff,
+ 0x00009034, 0x00000100, 0xffffffff,
+ 0x00009038, 0x00000100, 0xffffffff,
+ 0x0000903c, 0x00000100, 0xffffffff,
+ 0x00009040, 0x00000100, 0xffffffff,
+ 0x0000a200, 0x00000100, 0xffffffff,
+ 0x0000a204, 0x00000100, 0xffffffff,
+ 0x0000a208, 0x00000100, 0xffffffff,
+ 0x0000a20c, 0x00000100, 0xffffffff,
+ 0x0000977c, 0x00000100, 0xffffffff,
+ 0x00003f80, 0x00000100, 0xffffffff,
+ 0x0000a210, 0x00000100, 0xffffffff,
+ 0x0000a214, 0x00000100, 0xffffffff,
+ 0x000004d8, 0x00000100, 0xffffffff,
+ 0x00009784, 0x00000100, 0xffffffff,
+ 0x00009698, 0x00000100, 0xffffffff,
+ 0x000004d4, 0x00000200, 0xffffffff,
+ 0x000004d0, 0x00000000, 0xffffffff,
+ 0x000030cc, 0x00000100, 0xffffffff,
+ 0x0000d0c0, 0xff000100, 0xffffffff,
+ 0x0000915c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAICOS_MGCG_DEFAULT_LENGTH sizeof(caicos_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 caicos_mgcg_disable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x00009150, 0x00600000, 0xffffffff
+};
+#define CAICOS_MGCG_DISABLE_LENGTH sizeof(caicos_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 caicos_mgcg_enable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00009150, 0x46944040, 0xffffffff
+};
+#define CAICOS_MGCG_ENABLE_LENGTH sizeof(caicos_mgcg_enable) / (3 * sizeof(u32))
+
+//********* TURKS **************//
+static const u32 turks_cgcg_cgls_default[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define TURKS_CGCG_CGLS_DEFAULT_LENGTH sizeof(turks_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 turks_cgcg_cgls_disable[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00000644, 0x000f7912, 0x001f4180,
+ 0x00000644, 0x000f3812, 0x001f4180
+};
+#define TURKS_CGCG_CGLS_DISABLE_LENGTH sizeof(turks_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 turks_cgcg_cgls_enable[] =
+{
+ /* 0x0000c124, 0x84180000, 0x00180000, */
+ 0x00000644, 0x000f7892, 0x001f4080,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff
+};
+#define TURKS_CGCG_CGLS_ENABLE_LENGTH sizeof(turks_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+// These are the sequences for turks_mgcg_shls
+static const u32 turks_mgcg_default[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00005448, 0x00000100, 0xffffffff,
+ 0x000055e4, 0x00600100, 0xffffffff,
+ 0x0000160c, 0x00000100, 0xffffffff,
+ 0x0000c164, 0x00000100, 0xffffffff,
+ 0x00008a18, 0x00000100, 0xffffffff,
+ 0x0000897c, 0x06000100, 0xffffffff,
+ 0x00008b28, 0x00000100, 0xffffffff,
+ 0x00009144, 0x00000100, 0xffffffff,
+ 0x00009a60, 0x00000100, 0xffffffff,
+ 0x00009868, 0x00000100, 0xffffffff,
+ 0x00008d58, 0x00000100, 0xffffffff,
+ 0x00009510, 0x00000100, 0xffffffff,
+ 0x0000949c, 0x00000100, 0xffffffff,
+ 0x00009654, 0x00000100, 0xffffffff,
+ 0x00009030, 0x00000100, 0xffffffff,
+ 0x00009034, 0x00000100, 0xffffffff,
+ 0x00009038, 0x00000100, 0xffffffff,
+ 0x0000903c, 0x00000100, 0xffffffff,
+ 0x00009040, 0x00000100, 0xffffffff,
+ 0x0000a200, 0x00000100, 0xffffffff,
+ 0x0000a204, 0x00000100, 0xffffffff,
+ 0x0000a208, 0x00000100, 0xffffffff,
+ 0x0000a20c, 0x00000100, 0xffffffff,
+ 0x0000977c, 0x00000100, 0xffffffff,
+ 0x00003f80, 0x00000100, 0xffffffff,
+ 0x0000a210, 0x00000100, 0xffffffff,
+ 0x0000a214, 0x00000100, 0xffffffff,
+ 0x000004d8, 0x00000100, 0xffffffff,
+ 0x00009784, 0x00000100, 0xffffffff,
+ 0x00009698, 0x00000100, 0xffffffff,
+ 0x000004d4, 0x00000200, 0xffffffff,
+ 0x000004d0, 0x00000000, 0xffffffff,
+ 0x000030cc, 0x00000100, 0xffffffff,
+ 0x0000d0c0, 0x00000100, 0xffffffff,
+ 0x0000915c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091b0, 0x00070000, 0xffffffff,
+ 0x000091b4, 0x00030002, 0xffffffff,
+ 0x000091b8, 0x00050004, 0xffffffff,
+ 0x000091c4, 0x00010006, 0xffffffff,
+ 0x000091c8, 0x00090008, 0xffffffff,
+ 0x000091cc, 0x00070000, 0xffffffff,
+ 0x000091d0, 0x00030002, 0xffffffff,
+ 0x000091d4, 0x00050004, 0xffffffff,
+ 0x000091e0, 0x00010006, 0xffffffff,
+ 0x000091e4, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x000091ec, 0x00070000, 0xffffffff,
+ 0x000091f0, 0x00030002, 0xffffffff,
+ 0x000091f4, 0x00050004, 0xffffffff,
+ 0x00009200, 0x00010006, 0xffffffff,
+ 0x00009204, 0x00090008, 0xffffffff,
+ 0x00009208, 0x00070000, 0xffffffff,
+ 0x0000920c, 0x00030002, 0xffffffff,
+ 0x00009210, 0x00050004, 0xffffffff,
+ 0x0000921c, 0x00010006, 0xffffffff,
+ 0x00009220, 0x00090008, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define TURKS_MGCG_DEFAULT_LENGTH sizeof(turks_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 turks_mgcg_disable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x00009150, 0x00600000, 0xffffffff
+};
+#define TURKS_MGCG_DISABLE_LENGTH sizeof(turks_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 turks_mgcg_enable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00009150, 0x6e944000, 0xffffffff
+};
+#define TURKS_MGCG_ENABLE_LENGTH sizeof(turks_mgcg_enable) / (3 * sizeof(u32))
+
+#endif
+
+#ifndef BTC_SYSLS_SEQUENCE
+#define BTC_SYSLS_SEQUENCE 100
+
+
+//********* BARTS **************//
+static const u32 barts_sysls_default[] =
+{
+ /* Register, Value, Mask bits */
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+#define BARTS_SYSLS_DEFAULT_LENGTH sizeof(barts_sysls_default) / (3 * sizeof(u32))
+
+static const u32 barts_sysls_disable[] =
+{
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x00041401, 0xffffffff,
+ 0x0000264c, 0x00040400, 0xffffffff,
+ 0x00002648, 0x00040400, 0xffffffff,
+ 0x00002650, 0x00040400, 0xffffffff,
+ 0x000020b8, 0x00040400, 0xffffffff,
+ 0x000020bc, 0x00040400, 0xffffffff,
+ 0x000020c0, 0x00040c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680000, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00007ffd, 0xffffffff,
+ 0x00000c7c, 0x0000ff00, 0xffffffff,
+ 0x00006dfc, 0x0000007f, 0xffffffff
+};
+#define BARTS_SYSLS_DISABLE_LENGTH sizeof(barts_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 barts_sysls_enable[] =
+{
+ 0x000055e8, 0x00000001, 0xffffffff,
+ 0x0000d0bc, 0x00000100, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x000004c8, 0x00000000, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+#define BARTS_SYSLS_ENABLE_LENGTH sizeof(barts_sysls_enable) / (3 * sizeof(u32))
+
+//********* CAICOS **************//
+static const u32 caicos_sysls_default[] =
+{
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+#define CAICOS_SYSLS_DEFAULT_LENGTH sizeof(caicos_sysls_default) / (3 * sizeof(u32))
+
+static const u32 caicos_sysls_disable[] =
+{
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x00041401, 0xffffffff,
+ 0x0000264c, 0x00040400, 0xffffffff,
+ 0x00002648, 0x00040400, 0xffffffff,
+ 0x00002650, 0x00040400, 0xffffffff,
+ 0x000020b8, 0x00040400, 0xffffffff,
+ 0x000020bc, 0x00040400, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680000, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00007ffd, 0xffffffff,
+ 0x00000c7c, 0x0000ff00, 0xffffffff,
+ 0x00006dfc, 0x0000007f, 0xffffffff
+};
+#define CAICOS_SYSLS_DISABLE_LENGTH sizeof(caicos_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 caicos_sysls_enable[] =
+{
+ 0x000055e8, 0x00000001, 0xffffffff,
+ 0x0000d0bc, 0x00000100, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff,
+ 0x000004c8, 0x00000000, 0xffffffff
+};
+#define CAICOS_SYSLS_ENABLE_LENGTH sizeof(caicos_sysls_enable) / (3 * sizeof(u32))
+
+//********* TURKS **************//
+static const u32 turks_sysls_default[] =
+{
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+#define TURKS_SYSLS_DEFAULT_LENGTH sizeof(turks_sysls_default) / (3 * sizeof(u32))
+
+static const u32 turks_sysls_disable[] =
+{
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x00041401, 0xffffffff,
+ 0x0000264c, 0x00040400, 0xffffffff,
+ 0x00002648, 0x00040400, 0xffffffff,
+ 0x00002650, 0x00040400, 0xffffffff,
+ 0x000020b8, 0x00040400, 0xffffffff,
+ 0x000020bc, 0x00040400, 0xffffffff,
+ 0x000020c0, 0x00040c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680000, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00007ffd, 0xffffffff,
+ 0x00000c7c, 0x0000ff00, 0xffffffff,
+ 0x00006dfc, 0x0000007f, 0xffffffff
+};
+#define TURKS_SYSLS_DISABLE_LENGTH sizeof(turks_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 turks_sysls_enable[] =
+{
+ 0x000055e8, 0x00000001, 0xffffffff,
+ 0x0000d0bc, 0x00000100, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x000004c8, 0x00000000, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+#define TURKS_SYSLS_ENABLE_LENGTH sizeof(turks_sysls_enable) / (3 * sizeof(u32))
+
+#endif
+
+u32 btc_valid_sclk[40] =
+{
+ 5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000, 45000, 50000,
+ 55000, 60000, 65000, 70000, 75000, 80000, 85000, 90000, 95000, 100000,
+ 105000, 110000, 11500, 120000, 125000, 130000, 135000, 140000, 145000, 150000,
+ 155000, 160000, 165000, 170000, 175000, 180000, 185000, 190000, 195000, 200000
+};
+
+static const struct radeon_blacklist_clocks btc_blacklist_clocks[] =
+{
+ { 10000, 30000, RADEON_SCLK_UP },
+ { 15000, 30000, RADEON_SCLK_UP },
+ { 20000, 30000, RADEON_SCLK_UP },
+ { 25000, 30000, RADEON_SCLK_UP }
+};
+
+void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
+ u32 clock, u16 max_voltage, u16 *voltage)
+{
+ u32 i;
+
+ if ((table == NULL) || (table->count == 0))
+ return;
+
+ for (i= 0; i < table->count; i++) {
+ if (clock <= table->entries[i].clk) {
+ if (*voltage < table->entries[i].v)
+ *voltage = (u16)((table->entries[i].v < max_voltage) ?
+ table->entries[i].v : max_voltage);
+ return;
+ }
+ }
+
+ *voltage = (*voltage > max_voltage) ? *voltage : max_voltage;
+}
+
+static u32 btc_find_valid_clock(struct radeon_clock_array *clocks,
+ u32 max_clock, u32 requested_clock)
+{
+ unsigned int i;
+
+ if ((clocks == NULL) || (clocks->count == 0))
+ return (requested_clock < max_clock) ? requested_clock : max_clock;
+
+ for (i = 0; i < clocks->count; i++) {
+ if (clocks->values[i] >= requested_clock)
+ return (clocks->values[i] < max_clock) ? clocks->values[i] : max_clock;
+ }
+
+ return (clocks->values[clocks->count - 1] < max_clock) ?
+ clocks->values[clocks->count - 1] : max_clock;
+}
+
+static u32 btc_get_valid_mclk(struct radeon_device *rdev,
+ u32 max_mclk, u32 requested_mclk)
+{
+ return btc_find_valid_clock(&rdev->pm.dpm.dyn_state.valid_mclk_values,
+ max_mclk, requested_mclk);
+}
+
+static u32 btc_get_valid_sclk(struct radeon_device *rdev,
+ u32 max_sclk, u32 requested_sclk)
+{
+ return btc_find_valid_clock(&rdev->pm.dpm.dyn_state.valid_sclk_values,
+ max_sclk, requested_sclk);
+}
+
+void btc_skip_blacklist_clocks(struct radeon_device *rdev,
+ const u32 max_sclk, const u32 max_mclk,
+ u32 *sclk, u32 *mclk)
+{
+ int i, num_blacklist_clocks;
+
+ if ((sclk == NULL) || (mclk == NULL))
+ return;
+
+ num_blacklist_clocks = ARRAY_SIZE(btc_blacklist_clocks);
+
+ for (i = 0; i < num_blacklist_clocks; i++) {
+ if ((btc_blacklist_clocks[i].sclk == *sclk) &&
+ (btc_blacklist_clocks[i].mclk == *mclk))
+ break;
+ }
+
+ if (i < num_blacklist_clocks) {
+ if (btc_blacklist_clocks[i].action == RADEON_SCLK_UP) {
+ *sclk = btc_get_valid_sclk(rdev, max_sclk, *sclk + 1);
+
+ if (*sclk < max_sclk)
+ btc_skip_blacklist_clocks(rdev, max_sclk, max_mclk, sclk, mclk);
+ }
+ }
+}
+
+void btc_adjust_clock_combinations(struct radeon_device *rdev,
+ const struct radeon_clock_and_voltage_limits *max_limits,
+ struct rv7xx_pl *pl)
+{
+
+ if ((pl->mclk == 0) || (pl->sclk == 0))
+ return;
+
+ if (pl->mclk == pl->sclk)
+ return;
+
+ if (pl->mclk > pl->sclk) {
+ if (((pl->mclk + (pl->sclk - 1)) / pl->sclk) > rdev->pm.dpm.dyn_state.mclk_sclk_ratio)
+ pl->sclk = btc_get_valid_sclk(rdev,
+ max_limits->sclk,
+ (pl->mclk +
+ (rdev->pm.dpm.dyn_state.mclk_sclk_ratio - 1)) /
+ rdev->pm.dpm.dyn_state.mclk_sclk_ratio);
+ } else {
+ if ((pl->sclk - pl->mclk) > rdev->pm.dpm.dyn_state.sclk_mclk_delta)
+ pl->mclk = btc_get_valid_mclk(rdev,
+ max_limits->mclk,
+ pl->sclk -
+ rdev->pm.dpm.dyn_state.sclk_mclk_delta);
+ }
+}
+
+static u16 btc_find_voltage(struct atom_voltage_table *table, u16 voltage)
+{
+ unsigned int i;
+
+ for (i = 0; i < table->count; i++) {
+ if (voltage <= table->entries[i].value)
+ return table->entries[i].value;
+ }
+
+ return table->entries[table->count - 1].value;
+}
+
+void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
+ u16 max_vddc, u16 max_vddci,
+ u16 *vddc, u16 *vddci)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u16 new_voltage;
+
+ if ((0 == *vddc) || (0 == *vddci))
+ return;
+
+ if (*vddc > *vddci) {
+ if ((*vddc - *vddci) > rdev->pm.dpm.dyn_state.vddc_vddci_delta) {
+ new_voltage = btc_find_voltage(&eg_pi->vddci_voltage_table,
+ (*vddc - rdev->pm.dpm.dyn_state.vddc_vddci_delta));
+ *vddci = (new_voltage < max_vddci) ? new_voltage : max_vddci;
+ }
+ } else {
+ if ((*vddci - *vddc) > rdev->pm.dpm.dyn_state.vddc_vddci_delta) {
+ new_voltage = btc_find_voltage(&eg_pi->vddc_voltage_table,
+ (*vddci - rdev->pm.dpm.dyn_state.vddc_vddci_delta));
+ *vddc = (new_voltage < max_vddc) ? new_voltage : max_vddc;
+ }
+ }
+}
+
+static void btc_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp, bif;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ if (enable) {
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+ if (!pi->boot_in_gen2) {
+ bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+ bif |= CG_CLIENT_REQ(0xd);
+ WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+ tmp |= LC_GEN2_EN_STRAP;
+
+ tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ udelay(10);
+ tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ }
+ }
+ } else {
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+ if (!pi->boot_in_gen2) {
+ bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+ bif |= CG_CLIENT_REQ(0xd);
+ WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp &= ~LC_GEN2_EN_STRAP;
+ }
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ }
+ }
+}
+
+static void btc_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ btc_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+static int btc_disable_ulv(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (eg_pi->ulv.supported) {
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int btc_populate_ulv_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ int ret = -EINVAL;
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl;
+
+ if (ulv_pl->vddc) {
+ ret = cypress_convert_power_level_to_smc(rdev,
+ ulv_pl,
+ &table->ULVState.levels[0],
+ PPSMC_DISPLAY_WATERMARK_LOW);
+ if (ret == 0) {
+ table->ULVState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+ table->ULVState.levels[0].ACIndex = 1;
+
+ table->ULVState.levels[1] = table->ULVState.levels[0];
+ table->ULVState.levels[2] = table->ULVState.levels[0];
+
+ table->ULVState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ WREG32(CG_ULV_CONTROL, BTC_CGULVCONTROL_DFLT);
+ WREG32(CG_ULV_PARAMETER, BTC_CGULVPARAMETER_DFLT);
+ }
+ }
+
+ return ret;
+}
+
+static int btc_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ int ret = cypress_populate_smc_acpi_state(rdev, table);
+
+ if (ret == 0) {
+ table->ACPIState.levels[0].ACIndex = 0;
+ table->ACPIState.levels[1].ACIndex = 0;
+ table->ACPIState.levels[2].ACIndex = 0;
+ }
+
+ return ret;
+}
+
+void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
+ const u32 *sequence, u32 count)
+{
+ u32 i, length = count * 3;
+ u32 tmp;
+
+ for (i = 0; i < length; i+=3) {
+ tmp = RREG32(sequence[i]);
+ tmp &= ~sequence[i+2];
+ tmp |= sequence[i+1] & sequence[i+2];
+ WREG32(sequence[i], tmp);
+ }
+}
+
+static void btc_cg_clock_gating_default(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *p = NULL;
+
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_cgcg_cgls_default;
+ count = BARTS_CGCG_CGLS_DEFAULT_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_cgcg_cgls_default;
+ count = TURKS_CGCG_CGLS_DEFAULT_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_cgcg_cgls_default;
+ count = CAICOS_CGCG_CGLS_DEFAULT_LENGTH;
+ } else
+ return;
+
+ btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_cg_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *p = NULL;
+
+ if (enable) {
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_cgcg_cgls_enable;
+ count = BARTS_CGCG_CGLS_ENABLE_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_cgcg_cgls_enable;
+ count = TURKS_CGCG_CGLS_ENABLE_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_cgcg_cgls_enable;
+ count = CAICOS_CGCG_CGLS_ENABLE_LENGTH;
+ } else
+ return;
+ } else {
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_cgcg_cgls_disable;
+ count = BARTS_CGCG_CGLS_DISABLE_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_cgcg_cgls_disable;
+ count = TURKS_CGCG_CGLS_DISABLE_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_cgcg_cgls_disable;
+ count = CAICOS_CGCG_CGLS_DISABLE_LENGTH;
+ } else
+ return;
+ }
+
+ btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_mg_clock_gating_default(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *p = NULL;
+
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_mgcg_default;
+ count = BARTS_MGCG_DEFAULT_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_mgcg_default;
+ count = TURKS_MGCG_DEFAULT_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_mgcg_default;
+ count = CAICOS_MGCG_DEFAULT_LENGTH;
+ } else
+ return;
+
+ btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_mg_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *p = NULL;
+
+ if (enable) {
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_mgcg_enable;
+ count = BARTS_MGCG_ENABLE_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_mgcg_enable;
+ count = TURKS_MGCG_ENABLE_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_mgcg_enable;
+ count = CAICOS_MGCG_ENABLE_LENGTH;
+ } else
+ return;
+ } else {
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_mgcg_disable[0];
+ count = BARTS_MGCG_DISABLE_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_mgcg_disable[0];
+ count = TURKS_MGCG_DISABLE_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_mgcg_disable[0];
+ count = CAICOS_MGCG_DISABLE_LENGTH;
+ } else
+ return;
+ }
+
+ btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_ls_clock_gating_default(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *p = NULL;
+
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_sysls_default;
+ count = BARTS_SYSLS_DEFAULT_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_sysls_default;
+ count = TURKS_SYSLS_DEFAULT_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_sysls_default;
+ count = CAICOS_SYSLS_DEFAULT_LENGTH;
+ } else
+ return;
+
+ btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+static void btc_ls_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *p = NULL;
+
+ if (enable) {
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_sysls_enable;
+ count = BARTS_SYSLS_ENABLE_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_sysls_enable;
+ count = TURKS_SYSLS_ENABLE_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_sysls_enable;
+ count = CAICOS_SYSLS_ENABLE_LENGTH;
+ } else
+ return;
+ } else {
+ if (rdev->family == CHIP_BARTS) {
+ p = (const u32 *)&barts_sysls_disable;
+ count = BARTS_SYSLS_DISABLE_LENGTH;
+ } else if (rdev->family == CHIP_TURKS) {
+ p = (const u32 *)&turks_sysls_disable;
+ count = TURKS_SYSLS_DISABLE_LENGTH;
+ } else if (rdev->family == CHIP_CAICOS) {
+ p = (const u32 *)&caicos_sysls_disable;
+ count = CAICOS_SYSLS_DISABLE_LENGTH;
+ } else
+ return;
+ }
+
+ btc_program_mgcg_hw_sequence(rdev, p, count);
+}
+
+bool btc_dpm_enabled(struct radeon_device *rdev)
+{
+ if (rv770_is_smc_running(rdev))
+ return true;
+ else
+ return false;
+}
+
+static int btc_init_smc_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ RV770_SMC_STATETABLE *table = &pi->smc_statetable;
+ int ret;
+
+ memset(table, 0, sizeof(RV770_SMC_STATETABLE));
+
+ cypress_populate_smc_voltage_tables(rdev, table);
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_EVERGREEN:
+ case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+ break;
+ case THERMAL_TYPE_NONE:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+ break;
+ default:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+ break;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (pi->mem_gddr5)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ ret = cypress_populate_smc_initial_state(rdev, radeon_boot_state, table);
+ if (ret)
+ return ret;
+
+ if (eg_pi->sclk_deep_sleep)
+ WREG32_P(SCLK_PSKIP_CNTL, PSKIP_ON_ALLOW_STOP_HI(32),
+ ~PSKIP_ON_ALLOW_STOP_HI_MASK);
+
+ ret = btc_populate_smc_acpi_state(rdev, table);
+ if (ret)
+ return ret;
+
+ if (eg_pi->ulv.supported) {
+ ret = btc_populate_ulv_state(rdev, table);
+ if (ret)
+ eg_pi->ulv.supported = false;
+ }
+
+ table->driverState = table->initialState;
+
+ return rv770_copy_bytes_to_smc(rdev,
+ pi->state_table_start,
+ (u8 *)table,
+ sizeof(RV770_SMC_STATETABLE),
+ pi->sram_end);
+}
+
+static void btc_set_at_for_uvd(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ int idx = 0;
+
+ if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2))
+ idx = 1;
+
+ if ((idx == 1) && !eg_pi->smu_uvd_hs) {
+ pi->rlp = 10;
+ pi->rmp = 100;
+ pi->lhp = 100;
+ pi->lmp = 10;
+ } else {
+ pi->rlp = eg_pi->ats[idx].rlp;
+ pi->rmp = eg_pi->ats[idx].rmp;
+ pi->lhp = eg_pi->ats[idx].lhp;
+ pi->lmp = eg_pi->ats[idx].lmp;
+ }
+
+}
+
+void btc_notify_uvd_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_uvd_enabled, 1);
+ eg_pi->uvd_enabled = true;
+ } else {
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_uvd_enabled, 0);
+ eg_pi->uvd_enabled = false;
+ }
+}
+
+int btc_reset_to_default(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void btc_stop_smc(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (((RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK) >> LB_SYNC_RESET_SEL_SHIFT) != 1)
+ break;
+ udelay(1);
+ }
+ udelay(100);
+
+ r7xx_stop_smc(rdev);
+}
+
+void btc_read_arb_registers(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct evergreen_arb_registers *arb_registers =
+ &eg_pi->bootup_arb_registers;
+
+ arb_registers->mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ arb_registers->mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+ arb_registers->mc_arb_rfsh_rate = RREG32(MC_ARB_RFSH_RATE);
+ arb_registers->mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME);
+}
+
+
+static void btc_set_arb0_registers(struct radeon_device *rdev,
+ struct evergreen_arb_registers *arb_registers)
+{
+ u32 val;
+
+ WREG32(MC_ARB_DRAM_TIMING, arb_registers->mc_arb_dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2, arb_registers->mc_arb_dram_timing2);
+
+ val = (arb_registers->mc_arb_rfsh_rate & POWERMODE0_MASK) >>
+ POWERMODE0_SHIFT;
+ WREG32_P(MC_ARB_RFSH_RATE, POWERMODE0(val), ~POWERMODE0_MASK);
+
+ val = (arb_registers->mc_arb_burst_time & STATE0_MASK) >>
+ STATE0_SHIFT;
+ WREG32_P(MC_ARB_BURST_TIME, STATE0(val), ~STATE0_MASK);
+}
+
+static void btc_set_boot_state_timing(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (eg_pi->ulv.supported)
+ btc_set_arb0_registers(rdev, &eg_pi->bootup_arb_registers);
+}
+
+static bool btc_is_state_ulv_compatible(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl;
+
+ if (state->low.mclk != ulv_pl->mclk)
+ return false;
+
+ if (state->low.vddci != ulv_pl->vddci)
+ return false;
+
+ /* XXX check minclocks, etc. */
+
+ return true;
+}
+
+
+static int btc_set_ulv_dram_timing(struct radeon_device *rdev)
+{
+ u32 val;
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_pl *ulv_pl = eg_pi->ulv.pl;
+
+ radeon_atom_set_engine_dram_timings(rdev,
+ ulv_pl->sclk,
+ ulv_pl->mclk);
+
+ val = rv770_calculate_memory_refresh_rate(rdev, ulv_pl->sclk);
+ WREG32_P(MC_ARB_RFSH_RATE, POWERMODE0(val), ~POWERMODE0_MASK);
+
+ val = cypress_calculate_burst_time(rdev, ulv_pl->sclk, ulv_pl->mclk);
+ WREG32_P(MC_ARB_BURST_TIME, STATE0(val), ~STATE0_MASK);
+
+ return 0;
+}
+
+static int btc_enable_ulv(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int btc_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ int ret = 0;
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (eg_pi->ulv.supported) {
+ if (btc_is_state_ulv_compatible(rdev, radeon_new_state)) {
+ // Set ARB[0] to reflect the DRAM timing needed for ULV.
+ ret = btc_set_ulv_dram_timing(rdev);
+ if (ret == 0)
+ ret = btc_enable_ulv(rdev);
+ }
+ }
+
+ return ret;
+}
+
+static bool btc_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+ bool result = true;
+
+ switch (in_reg) {
+ case MC_SEQ_RAS_TIMING >> 2:
+ *out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_CAS_TIMING >> 2:
+ *out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_MISC_TIMING >> 2:
+ *out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_MISC_TIMING2 >> 2:
+ *out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
+ break;
+ case MC_SEQ_RD_CTL_D0 >> 2:
+ *out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
+ break;
+ case MC_SEQ_RD_CTL_D1 >> 2:
+ *out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_D0 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_D1 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
+ break;
+ case MC_PMG_CMD_EMRS >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS1 >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static void btc_set_valid_flag(struct evergreen_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 int btc_set_mc_special_registers(struct radeon_device *rdev,
+ struct evergreen_mc_reg_table *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 i, j, k;
+ u32 tmp;
+
+ for (i = 0, j = table->last; i < table->last; i++) {
+ switch (table->mc_reg_address[i].s1) {
+ case MC_SEQ_MISC1 >> 2:
+ tmp = RREG32(MC_PMG_CMD_EMRS);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ ((tmp & 0xffff0000)) |
+ ((table->mc_reg_table_entry[k].mc_data[i] & 0xffff0000) >> 16);
+ }
+ j++;
+
+ if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ tmp = RREG32(MC_PMG_CMD_MRS);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ (tmp & 0xffff0000) |
+ (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+ if (!pi->mem_gddr5)
+ table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+ }
+ j++;
+
+ if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ break;
+ case MC_SEQ_RESERVE_M >> 2:
+ tmp = RREG32(MC_PMG_CMD_MRS1);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ for (k = 0; k < table->num_entries; k++) {
+ table->mc_reg_table_entry[k].mc_data[j] =
+ (tmp & 0xffff0000) |
+ (table->mc_reg_table_entry[k].mc_data[i] & 0x0000ffff);
+ }
+ j++;
+
+ if (j > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ table->last = j;
+
+ return 0;
+}
+
+static void btc_set_s0_mc_reg_index(struct evergreen_mc_reg_table *table)
+{
+ u32 i;
+ u16 address;
+
+ for (i = 0; i < table->last; i++) {
+ table->mc_reg_address[i].s0 =
+ btc_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+ address : table->mc_reg_address[i].s1;
+ }
+}
+
+static int btc_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
+ struct evergreen_mc_reg_table *eg_table)
+{
+ u8 i, j;
+
+ if (table->last > SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+ return -EINVAL;
+
+ for (i = 0; i < table->last; i++)
+ eg_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+ eg_table->last = table->last;
+
+ for (i = 0; i < table->num_entries; i++) {
+ eg_table->mc_reg_table_entry[i].mclk_max =
+ table->mc_reg_table_entry[i].mclk_max;
+ for(j = 0; j < table->last; j++)
+ eg_table->mc_reg_table_entry[i].mc_data[j] =
+ table->mc_reg_table_entry[i].mc_data[j];
+ }
+ eg_table->num_entries = table->num_entries;
+
+ return 0;
+}
+
+static int btc_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+ int ret;
+ struct atom_mc_reg_table *table;
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct evergreen_mc_reg_table *eg_table = &eg_pi->mc_reg_table;
+ u8 module_index = rv770_get_memory_module_index(rdev);
+
+ table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ /* Program additional LP registers that are no longer programmed by VBIOS */
+ WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
+ WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
+ WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
+ WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
+ WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
+ WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
+ WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
+ WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
+ WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
+ WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
+ WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
+
+ ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
+
+ if (ret)
+ goto init_mc_done;
+
+ ret = btc_copy_vbios_mc_reg_table(table, eg_table);
+
+ if (ret)
+ goto init_mc_done;
+
+ btc_set_s0_mc_reg_index(eg_table);
+ ret = btc_set_mc_special_registers(rdev, eg_table);
+
+ if (ret)
+ goto init_mc_done;
+
+ btc_set_valid_flag(eg_table);
+
+init_mc_done:
+ kfree(table);
+
+ return ret;
+}
+
+static void btc_init_stutter_mode(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp;
+
+ if (pi->mclk_stutter_mode_threshold) {
+ if (pi->mem_gddr5) {
+ tmp = RREG32(MC_PMG_AUTO_CFG);
+ if ((0x200 & tmp) == 0) {
+ tmp = (tmp & 0xfffffc0b) | 0x204;
+ WREG32(MC_PMG_AUTO_CFG, tmp);
+ }
+ }
+ }
+}
+
+bool btc_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+ u32 switch_limit = pi->mem_gddr5 ? 450 : 100;
+
+ if (vblank_time < switch_limit)
+ return true;
+ else
+ return false;
+
+}
+
+static void btc_apply_state_adjust_rules(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct rv7xx_ps *ps = rv770_get_ps(rps);
+ struct radeon_clock_and_voltage_limits *max_limits;
+ bool disable_mclk_switching;
+ u32 mclk, sclk;
+ u16 vddc, vddci;
+
+ if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
+ btc_dpm_vblank_too_short(rdev))
+ disable_mclk_switching = true;
+ else
+ disable_mclk_switching = false;
+
+ if (rdev->pm.dpm.ac_power)
+ max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (rdev->pm.dpm.ac_power == false) {
+ if (ps->high.mclk > max_limits->mclk)
+ ps->high.mclk = max_limits->mclk;
+ if (ps->high.sclk > max_limits->sclk)
+ ps->high.sclk = max_limits->sclk;
+ if (ps->high.vddc > max_limits->vddc)
+ ps->high.vddc = max_limits->vddc;
+ if (ps->high.vddci > max_limits->vddci)
+ ps->high.vddci = max_limits->vddci;
+
+ if (ps->medium.mclk > max_limits->mclk)
+ ps->medium.mclk = max_limits->mclk;
+ if (ps->medium.sclk > max_limits->sclk)
+ ps->medium.sclk = max_limits->sclk;
+ if (ps->medium.vddc > max_limits->vddc)
+ ps->medium.vddc = max_limits->vddc;
+ if (ps->medium.vddci > max_limits->vddci)
+ ps->medium.vddci = max_limits->vddci;
+
+ if (ps->low.mclk > max_limits->mclk)
+ ps->low.mclk = max_limits->mclk;
+ if (ps->low.sclk > max_limits->sclk)
+ ps->low.sclk = max_limits->sclk;
+ if (ps->low.vddc > max_limits->vddc)
+ ps->low.vddc = max_limits->vddc;
+ if (ps->low.vddci > max_limits->vddci)
+ ps->low.vddci = max_limits->vddci;
+ }
+
+ /* XXX validate the min clocks required for display */
+
+ if (disable_mclk_switching) {
+ sclk = ps->low.sclk;
+ mclk = ps->high.mclk;
+ vddc = ps->low.vddc;
+ vddci = ps->high.vddci;
+ } else {
+ sclk = ps->low.sclk;
+ mclk = ps->low.mclk;
+ vddc = ps->low.vddc;
+ vddci = ps->low.vddci;
+ }
+
+ /* adjusted low state */
+ ps->low.sclk = sclk;
+ ps->low.mclk = mclk;
+ ps->low.vddc = vddc;
+ ps->low.vddci = vddci;
+
+ btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+ &ps->low.sclk, &ps->low.mclk);
+
+ /* adjusted medium, high states */
+ if (ps->medium.sclk < ps->low.sclk)
+ ps->medium.sclk = ps->low.sclk;
+ if (ps->medium.vddc < ps->low.vddc)
+ ps->medium.vddc = ps->low.vddc;
+ if (ps->high.sclk < ps->medium.sclk)
+ ps->high.sclk = ps->medium.sclk;
+ if (ps->high.vddc < ps->medium.vddc)
+ ps->high.vddc = ps->medium.vddc;
+
+ if (disable_mclk_switching) {
+ mclk = ps->low.mclk;
+ if (mclk < ps->medium.mclk)
+ mclk = ps->medium.mclk;
+ if (mclk < ps->high.mclk)
+ mclk = ps->high.mclk;
+ ps->low.mclk = mclk;
+ ps->low.vddci = vddci;
+ ps->medium.mclk = mclk;
+ ps->medium.vddci = vddci;
+ ps->high.mclk = mclk;
+ ps->high.vddci = vddci;
+ } else {
+ if (ps->medium.mclk < ps->low.mclk)
+ ps->medium.mclk = ps->low.mclk;
+ if (ps->medium.vddci < ps->low.vddci)
+ ps->medium.vddci = ps->low.vddci;
+ if (ps->high.mclk < ps->medium.mclk)
+ ps->high.mclk = ps->medium.mclk;
+ if (ps->high.vddci < ps->medium.vddci)
+ ps->high.vddci = ps->medium.vddci;
+ }
+
+ btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+ &ps->medium.sclk, &ps->medium.mclk);
+ btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+ &ps->high.sclk, &ps->high.mclk);
+
+ btc_adjust_clock_combinations(rdev, max_limits, &ps->low);
+ btc_adjust_clock_combinations(rdev, max_limits, &ps->medium);
+ btc_adjust_clock_combinations(rdev, max_limits, &ps->high);
+
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ ps->low.sclk, max_limits->vddc, &ps->low.vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ ps->low.mclk, max_limits->vddci, &ps->low.vddci);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ ps->low.mclk, max_limits->vddc, &ps->low.vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
+ rdev->clock.current_dispclk, max_limits->vddc, &ps->low.vddc);
+
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ ps->medium.sclk, max_limits->vddc, &ps->medium.vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ ps->medium.mclk, max_limits->vddci, &ps->medium.vddci);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ ps->medium.mclk, max_limits->vddc, &ps->medium.vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
+ rdev->clock.current_dispclk, max_limits->vddc, &ps->medium.vddc);
+
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ ps->high.sclk, max_limits->vddc, &ps->high.vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ ps->high.mclk, max_limits->vddci, &ps->high.vddci);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ ps->high.mclk, max_limits->vddc, &ps->high.vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
+ rdev->clock.current_dispclk, max_limits->vddc, &ps->high.vddc);
+
+ btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci,
+ &ps->low.vddc, &ps->low.vddci);
+ btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci,
+ &ps->medium.vddc, &ps->medium.vddci);
+ btc_apply_voltage_delta_rules(rdev, max_limits->vddc, max_limits->vddci,
+ &ps->high.vddc, &ps->high.vddci);
+
+ if ((ps->high.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) &&
+ (ps->medium.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc) &&
+ (ps->low.vddc <= rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc))
+ ps->dc_compatible = true;
+ else
+ ps->dc_compatible = false;
+
+ if (ps->low.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+ ps->low.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+ if (ps->medium.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+ ps->medium.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+ if (ps->high.vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+ ps->high.flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+}
+
+static void btc_update_current_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct rv7xx_ps *new_ps = rv770_get_ps(rps);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ eg_pi->current_rps = *rps;
+ eg_pi->current_ps = *new_ps;
+ eg_pi->current_rps.ps_priv = &eg_pi->current_ps;
+}
+
+static void btc_update_requested_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct rv7xx_ps *new_ps = rv770_get_ps(rps);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ eg_pi->requested_rps = *rps;
+ eg_pi->requested_ps = *new_ps;
+ eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps;
+}
+
+void btc_dpm_reset_asic(struct radeon_device *rdev)
+{
+ rv770_restrict_performance_levels_before_switch(rdev);
+ btc_disable_ulv(rdev);
+ btc_set_boot_state_timing(rdev);
+ rv770_set_boot_state(rdev);
+}
+
+int btc_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+ struct radeon_ps *new_ps = &requested_ps;
+
+ btc_update_requested_ps(rdev, new_ps);
+
+ btc_apply_state_adjust_rules(rdev, &eg_pi->requested_rps);
+
+ return 0;
+}
+
+int btc_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = &eg_pi->requested_rps;
+ struct radeon_ps *old_ps = &eg_pi->current_rps;
+ int ret;
+
+ ret = btc_disable_ulv(rdev);
+ btc_set_boot_state_timing(rdev);
+ ret = rv770_restrict_performance_levels_before_switch(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n");
+ return ret;
+ }
+ if (eg_pi->pcie_performance_request)
+ cypress_notify_link_speed_change_before_state_change(rdev, new_ps, old_ps);
+
+ rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ ret = rv770_halt_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_halt_smc failed\n");
+ return ret;
+ }
+ btc_set_at_for_uvd(rdev, new_ps);
+ if (eg_pi->smu_uvd_hs)
+ btc_notify_uvd_to_smc(rdev, new_ps);
+ ret = cypress_upload_sw_state(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("cypress_upload_sw_state failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = cypress_upload_mc_reg_table(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("cypress_upload_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+
+ cypress_program_memory_timing_parameters(rdev, new_ps);
+
+ ret = rv770_resume_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_resume_smc failed\n");
+ return ret;
+ }
+ ret = rv770_set_sw_state(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_set_sw_state failed\n");
+ return ret;
+ }
+ rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+
+ if (eg_pi->pcie_performance_request)
+ cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
+
+ ret = btc_set_power_state_conditionally_enable_ulv(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("btc_set_power_state_conditionally_enable_ulv failed\n");
+ return ret;
+ }
+
+ ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
+ if (ret) {
+ DRM_ERROR("rv770_dpm_force_performance_level failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void btc_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = &eg_pi->requested_rps;
+
+ btc_update_current_ps(rdev, new_ps);
+}
+
+int btc_dpm_enable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ if (pi->gfx_clock_gating)
+ btc_cg_clock_gating_default(rdev);
+
+ if (btc_dpm_enabled(rdev))
+ return -EINVAL;
+
+ if (pi->mg_clock_gating)
+ btc_mg_clock_gating_default(rdev);
+
+ if (eg_pi->ls_clock_gating)
+ btc_ls_clock_gating_default(rdev);
+
+ if (pi->voltage_control) {
+ rv770_enable_voltage_control(rdev, true);
+ ret = cypress_construct_voltage_tables(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_construct_voltage_tables failed\n");
+ return ret;
+ }
+ }
+
+ if (pi->mvdd_control) {
+ ret = cypress_get_mvdd_configuration(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_get_mvdd_configuration failed\n");
+ return ret;
+ }
+ }
+
+ if (eg_pi->dynamic_ac_timing) {
+ ret = btc_initialize_mc_reg_table(rdev);
+ if (ret)
+ eg_pi->dynamic_ac_timing = false;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv770_enable_backbias(rdev, true);
+
+ if (pi->dynamic_ss)
+ cypress_enable_spread_spectrum(rdev, true);
+
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, true);
+
+ rv770_setup_bsp(rdev);
+ rv770_program_git(rdev);
+ rv770_program_tp(rdev);
+ rv770_program_tpp(rdev);
+ rv770_program_sstp(rdev);
+ rv770_program_engine_speed_parameters(rdev);
+ cypress_enable_display_gap(rdev);
+ rv770_program_vc(rdev);
+
+ if (pi->dynamic_pcie_gen2)
+ btc_enable_dynamic_pcie_gen2(rdev, true);
+
+ ret = rv770_upload_firmware(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_upload_firmware failed\n");
+ return ret;
+ }
+ ret = cypress_get_table_locations(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_get_table_locations failed\n");
+ return ret;
+ }
+ ret = btc_init_smc_table(rdev, boot_ps);
+ if (ret)
+ return ret;
+
+ if (eg_pi->dynamic_ac_timing) {
+ ret = cypress_populate_mc_reg_table(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("cypress_populate_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+
+ cypress_program_response_times(rdev);
+ r7xx_start_smc(rdev);
+ ret = cypress_notify_smc_display_change(rdev, false);
+ if (ret) {
+ DRM_ERROR("cypress_notify_smc_display_change failed\n");
+ return ret;
+ }
+ cypress_enable_sclk_control(rdev, true);
+
+ if (eg_pi->memory_transition)
+ cypress_enable_mclk_control(rdev, true);
+
+ cypress_start_dpm(rdev);
+
+ if (pi->gfx_clock_gating)
+ btc_cg_clock_gating_enable(rdev, true);
+
+ if (pi->mg_clock_gating)
+ btc_mg_clock_gating_enable(rdev, true);
+
+ if (eg_pi->ls_clock_gating)
+ btc_ls_clock_gating_enable(rdev, true);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ PPSMC_Result result;
+
+ ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+ if (result != PPSMC_Result_OK)
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+ }
+
+ rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ btc_init_stutter_mode(rdev);
+
+ btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
+ return 0;
+};
+
+void btc_dpm_disable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (!btc_dpm_enabled(rdev))
+ return;
+
+ rv770_clear_vc(rdev);
+
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, false);
+
+ if (pi->dynamic_pcie_gen2)
+ btc_enable_dynamic_pcie_gen2(rdev, false);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ if (pi->gfx_clock_gating)
+ btc_cg_clock_gating_enable(rdev, false);
+
+ if (pi->mg_clock_gating)
+ btc_mg_clock_gating_enable(rdev, false);
+
+ if (eg_pi->ls_clock_gating)
+ btc_ls_clock_gating_enable(rdev, false);
+
+ rv770_stop_dpm(rdev);
+ btc_reset_to_default(rdev);
+ btc_stop_smc(rdev);
+ cypress_enable_spread_spectrum(rdev, false);
+
+ btc_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+}
+
+void btc_dpm_setup_asic(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ rv770_get_memory_type(rdev);
+ rv740_read_clock_registers(rdev);
+ btc_read_arb_registers(rdev);
+ rv770_read_voltage_smio_registers(rdev);
+
+ if (eg_pi->pcie_performance_request)
+ cypress_advertise_gen2_capability(rdev);
+
+ rv770_get_pcie_gen2_status(rdev);
+ rv770_enable_acpi_pm(rdev);
+}
+
+int btc_dpm_init(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi;
+ struct evergreen_power_info *eg_pi;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ u16 data_offset, size;
+ u8 frev, crev;
+ struct atom_clock_dividers dividers;
+ int ret;
+
+ eg_pi = kzalloc(sizeof(struct evergreen_power_info), GFP_KERNEL);
+ if (eg_pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = eg_pi;
+ pi = &eg_pi->rv7xx;
+
+ rv770_get_max_vddc(rdev);
+
+ eg_pi->ulv.supported = false;
+ pi->acpi_vddc = 0;
+ eg_pi->acpi_vddci = 0;
+ pi->min_vddc_in_table = 0;
+ pi->max_vddc_in_table = 0;
+
+ ret = rv7xx_parse_power_table(rdev);
+ if (ret)
+ return ret;
+ ret = r600_parse_extended_power_table(rdev);
+ if (ret)
+ return ret;
+
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
+ kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL);
+ if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
+ r600_free_extended_power_table(rdev);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 800;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 800;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 800;
+
+ if (rdev->pm.dpm.voltage_response_time == 0)
+ rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+ if (rdev->pm.dpm.backbias_response_time == 0)
+ rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->ref_div = dividers.ref_div + 1;
+ else
+ pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ pi->mclk_strobe_mode_threshold = 40000;
+ pi->mclk_edc_enable_threshold = 40000;
+ eg_pi->mclk_edc_wr_enable_threshold = 40000;
+
+ pi->rlp = RV770_RLP_DFLT;
+ pi->rmp = RV770_RMP_DFLT;
+ pi->lhp = RV770_LHP_DFLT;
+ pi->lmp = RV770_LMP_DFLT;
+
+ eg_pi->ats[0].rlp = RV770_RLP_DFLT;
+ eg_pi->ats[0].rmp = RV770_RMP_DFLT;
+ eg_pi->ats[0].lhp = RV770_LHP_DFLT;
+ eg_pi->ats[0].lmp = RV770_LMP_DFLT;
+
+ eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT;
+ eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT;
+ eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT;
+ eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT;
+
+ eg_pi->smu_uvd_hs = true;
+
+ pi->voltage_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0);
+
+ pi->mvdd_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
+
+ eg_pi->vddci_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->sclk_ss = true;
+ pi->mclk_ss = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->sclk_ss = false;
+ pi->mclk_ss = false;
+ pi->dynamic_ss = true;
+ }
+
+ pi->asi = RV770_ASI_DFLT;
+ pi->pasi = CYPRESS_HASI_DFLT;
+ pi->vrc = CYPRESS_VRC_DFLT;
+
+ pi->power_gating = false;
+
+ pi->gfx_clock_gating = true;
+
+ pi->mg_clock_gating = true;
+ pi->mgcgtssm = true;
+ eg_pi->ls_clock_gating = false;
+ eg_pi->sclk_deep_sleep = false;
+
+ pi->dynamic_pcie_gen2 = true;
+
+ if (pi->gfx_clock_gating &&
+ (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ pi->display_gap = true;
+
+ if (rdev->flags & RADEON_IS_MOBILITY)
+ pi->dcodt = true;
+ else
+ pi->dcodt = false;
+
+ pi->ulps = true;
+
+ eg_pi->dynamic_ac_timing = true;
+ eg_pi->abm = true;
+ eg_pi->mcls = true;
+ eg_pi->light_sleep = true;
+ eg_pi->memory_transition = true;
+#if defined(CONFIG_ACPI)
+ eg_pi->pcie_performance_request =
+ radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+ eg_pi->pcie_performance_request = false;
+#endif
+
+ if (rdev->family == CHIP_BARTS)
+ eg_pi->dll_default_on = true;
+ else
+ eg_pi->dll_default_on = false;
+
+ eg_pi->sclk_deep_sleep = false;
+ if (ASIC_IS_LOMBOK(rdev))
+ pi->mclk_stutter_mode_threshold = 30000;
+ else
+ pi->mclk_stutter_mode_threshold = 0;
+
+ pi->sram_end = SMC_RAM_END;
+
+ rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
+ rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+ rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900;
+ rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk);
+ rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk;
+ rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+ rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+
+ if (rdev->family == CHIP_TURKS)
+ rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
+ else
+ rdev->pm.dpm.dyn_state.sclk_mclk_delta = 10000;
+
+ return 0;
+}
+
+void btc_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
+ r600_free_extended_power_table(rdev);
+}
+
+u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps);
+
+ if (low)
+ return requested_state->low.sclk;
+ else
+ return requested_state->high.sclk;
+}
+
+u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_ps *requested_state = rv770_get_ps(&eg_pi->requested_rps);
+
+ if (low)
+ return requested_state->low.mclk;
+ else
+ return requested_state->high.mclk;
+}
diff --git a/drivers/gpu/drm/radeon/btc_dpm.h b/drivers/gpu/drm/radeon/btc_dpm.h
new file mode 100644
index 000000000000..1a15e0e41950
--- /dev/null
+++ b/drivers/gpu/drm/radeon/btc_dpm.h
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __BTC_DPM_H__
+#define __BTC_DPM_H__
+
+#define BTC_RLP_UVD_DFLT 20
+#define BTC_RMP_UVD_DFLT 50
+#define BTC_LHP_UVD_DFLT 50
+#define BTC_LMP_UVD_DFLT 20
+#define BARTS_MGCGCGTSSMCTRL_DFLT 0x81944000
+#define TURKS_MGCGCGTSSMCTRL_DFLT 0x6e944000
+#define CAICOS_MGCGCGTSSMCTRL_DFLT 0x46944040
+#define BTC_CGULVPARAMETER_DFLT 0x00040035
+#define BTC_CGULVCONTROL_DFLT 0x00001450
+
+extern u32 btc_valid_sclk[40];
+
+void btc_read_arb_registers(struct radeon_device *rdev);
+void btc_program_mgcg_hw_sequence(struct radeon_device *rdev,
+ const u32 *sequence, u32 count);
+void btc_skip_blacklist_clocks(struct radeon_device *rdev,
+ const u32 max_sclk, const u32 max_mclk,
+ u32 *sclk, u32 *mclk);
+void btc_adjust_clock_combinations(struct radeon_device *rdev,
+ const struct radeon_clock_and_voltage_limits *max_limits,
+ struct rv7xx_pl *pl);
+void btc_apply_voltage_dependency_rules(struct radeon_clock_voltage_dependency_table *table,
+ u32 clock, u16 max_voltage, u16 *voltage);
+void btc_apply_voltage_delta_rules(struct radeon_device *rdev,
+ u16 max_vddc, u16 max_vddci,
+ u16 *vddc, u16 *vddci);
+bool btc_dpm_enabled(struct radeon_device *rdev);
+int btc_reset_to_default(struct radeon_device *rdev);
+void btc_notify_uvd_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/btcd.h b/drivers/gpu/drm/radeon/btcd.h
new file mode 100644
index 000000000000..29e32de7e025
--- /dev/null
+++ b/drivers/gpu/drm/radeon/btcd.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2010 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 _BTCD_H_
+#define _BTCD_H_
+
+/* pm registers */
+
+#define GENERAL_PWRMGT 0x63c
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define THERMAL_PROTECTION_DIS (1 << 2)
+# define THERMAL_PROTECTION_TYPE (1 << 3)
+# define ENABLE_GEN2PCIE (1 << 4)
+# define ENABLE_GEN2XSP (1 << 5)
+# define SW_SMIO_INDEX(x) ((x) << 6)
+# define SW_SMIO_INDEX_MASK (3 << 6)
+# define SW_SMIO_INDEX_SHIFT 6
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+# define BACKBIAS_PAD_EN (1 << 18)
+# define BACKBIAS_VALUE (1 << 19)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
+# define AC_DC_SW (1 << 24)
+
+#define CG_BIF_REQ_AND_RSP 0x7f4
+#define CG_CLIENT_REQ(x) ((x) << 0)
+#define CG_CLIENT_REQ_MASK (0xff << 0)
+#define CG_CLIENT_REQ_SHIFT 0
+#define CG_CLIENT_RESP(x) ((x) << 8)
+#define CG_CLIENT_RESP_MASK (0xff << 8)
+#define CG_CLIENT_RESP_SHIFT 8
+#define CLIENT_CG_REQ(x) ((x) << 16)
+#define CLIENT_CG_REQ_MASK (0xff << 16)
+#define CLIENT_CG_REQ_SHIFT 16
+#define CLIENT_CG_RESP(x) ((x) << 24)
+#define CLIENT_CG_RESP_MASK (0xff << 24)
+#define CLIENT_CG_RESP_SHIFT 24
+
+#define SCLK_PSKIP_CNTL 0x8c0
+#define PSKIP_ON_ALLOW_STOP_HI(x) ((x) << 16)
+#define PSKIP_ON_ALLOW_STOP_HI_MASK (0xff << 16)
+#define PSKIP_ON_ALLOW_STOP_HI_SHIFT 16
+
+#define CG_ULV_CONTROL 0x8c8
+#define CG_ULV_PARAMETER 0x8cc
+
+#define MC_ARB_DRAM_TIMING 0x2774
+#define MC_ARB_DRAM_TIMING2 0x2778
+
+#define MC_ARB_RFSH_RATE 0x27b0
+#define POWERMODE0(x) ((x) << 0)
+#define POWERMODE0_MASK (0xff << 0)
+#define POWERMODE0_SHIFT 0
+#define POWERMODE1(x) ((x) << 8)
+#define POWERMODE1_MASK (0xff << 8)
+#define POWERMODE1_SHIFT 8
+#define POWERMODE2(x) ((x) << 16)
+#define POWERMODE2_MASK (0xff << 16)
+#define POWERMODE2_SHIFT 16
+#define POWERMODE3(x) ((x) << 24)
+#define POWERMODE3_MASK (0xff << 24)
+#define POWERMODE3_SHIFT 24
+
+#define MC_ARB_BURST_TIME 0x2808
+#define STATE0(x) ((x) << 0)
+#define STATE0_MASK (0x1f << 0)
+#define STATE0_SHIFT 0
+#define STATE1(x) ((x) << 5)
+#define STATE1_MASK (0x1f << 5)
+#define STATE1_SHIFT 5
+#define STATE2(x) ((x) << 10)
+#define STATE2_MASK (0x1f << 10)
+#define STATE2_SHIFT 10
+#define STATE3(x) ((x) << 15)
+#define STATE3_MASK (0x1f << 15)
+#define STATE3_SHIFT 15
+
+#define MC_SEQ_RAS_TIMING 0x28a0
+#define MC_SEQ_CAS_TIMING 0x28a4
+#define MC_SEQ_MISC_TIMING 0x28a8
+#define MC_SEQ_MISC_TIMING2 0x28ac
+
+#define MC_SEQ_RD_CTL_D0 0x28b4
+#define MC_SEQ_RD_CTL_D1 0x28b8
+#define MC_SEQ_WR_CTL_D0 0x28bc
+#define MC_SEQ_WR_CTL_D1 0x28c0
+
+#define MC_PMG_AUTO_CFG 0x28d4
+
+#define MC_SEQ_STATUS_M 0x29f4
+# define PMG_PWRSTATE (1 << 16)
+
+#define MC_SEQ_MISC0 0x2a00
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+#define MC_SEQ_MISC1 0x2a04
+#define MC_SEQ_RESERVE_M 0x2a08
+#define MC_PMG_CMD_EMRS 0x2a0c
+
+#define MC_SEQ_MISC3 0x2a2c
+
+#define MC_SEQ_MISC5 0x2a54
+#define MC_SEQ_MISC6 0x2a58
+
+#define MC_SEQ_MISC7 0x2a64
+
+#define MC_SEQ_CG 0x2a68
+#define CG_SEQ_REQ(x) ((x) << 0)
+#define CG_SEQ_REQ_MASK (0xff << 0)
+#define CG_SEQ_REQ_SHIFT 0
+#define CG_SEQ_RESP(x) ((x) << 8)
+#define CG_SEQ_RESP_MASK (0xff << 8)
+#define CG_SEQ_RESP_SHIFT 8
+#define SEQ_CG_REQ(x) ((x) << 16)
+#define SEQ_CG_REQ_MASK (0xff << 16)
+#define SEQ_CG_REQ_SHIFT 16
+#define SEQ_CG_RESP(x) ((x) << 24)
+#define SEQ_CG_RESP_MASK (0xff << 24)
+#define SEQ_CG_RESP_SHIFT 24
+#define MC_SEQ_RAS_TIMING_LP 0x2a6c
+#define MC_SEQ_CAS_TIMING_LP 0x2a70
+#define MC_SEQ_MISC_TIMING_LP 0x2a74
+#define MC_SEQ_MISC_TIMING2_LP 0x2a78
+#define MC_SEQ_WR_CTL_D0_LP 0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP 0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88
+
+#define MC_PMG_CMD_MRS 0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP 0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP 0x2b20
+
+#define MC_PMG_CMD_MRS1 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48
+
+#define LB_SYNC_RESET_SEL 0x6b28
+#define LB_SYNC_RESET_SEL_MASK (3 << 0)
+#define LB_SYNC_RESET_SEL_SHIFT 0
+
+/* PCIE link stuff */
+#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
+# define LC_GEN2_EN_STRAP (1 << 0)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1)
+# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5)
+# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
+# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12
+# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
+# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
new file mode 100644
index 000000000000..ed1d91025928
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -0,0 +1,6987 @@
+/*
+ * 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/platform_device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "drmP.h"
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "cikd.h"
+#include "atom.h"
+#include "cik_blit_shaders.h"
+
+/* GFX */
+#define CIK_PFP_UCODE_SIZE 2144
+#define CIK_ME_UCODE_SIZE 2144
+#define CIK_CE_UCODE_SIZE 2144
+/* compute */
+#define CIK_MEC_UCODE_SIZE 4192
+/* interrupts */
+#define BONAIRE_RLC_UCODE_SIZE 2048
+#define KB_RLC_UCODE_SIZE 2560
+#define KV_RLC_UCODE_SIZE 2560
+/* gddr controller */
+#define CIK_MC_UCODE_SIZE 7866
+/* sdma */
+#define CIK_SDMA_UCODE_SIZE 1050
+#define CIK_SDMA_UCODE_VERSION 64
+
+MODULE_FIRMWARE("radeon/BONAIRE_pfp.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_me.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_ce.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_mec.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_mc.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_rlc.bin");
+MODULE_FIRMWARE("radeon/BONAIRE_sdma.bin");
+MODULE_FIRMWARE("radeon/KAVERI_pfp.bin");
+MODULE_FIRMWARE("radeon/KAVERI_me.bin");
+MODULE_FIRMWARE("radeon/KAVERI_ce.bin");
+MODULE_FIRMWARE("radeon/KAVERI_mec.bin");
+MODULE_FIRMWARE("radeon/KAVERI_rlc.bin");
+MODULE_FIRMWARE("radeon/KAVERI_sdma.bin");
+MODULE_FIRMWARE("radeon/KABINI_pfp.bin");
+MODULE_FIRMWARE("radeon/KABINI_me.bin");
+MODULE_FIRMWARE("radeon/KABINI_ce.bin");
+MODULE_FIRMWARE("radeon/KABINI_mec.bin");
+MODULE_FIRMWARE("radeon/KABINI_rlc.bin");
+MODULE_FIRMWARE("radeon/KABINI_sdma.bin");
+
+extern int r600_ih_ring_alloc(struct radeon_device *rdev);
+extern void r600_ih_ring_fini(struct radeon_device *rdev);
+extern void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *save);
+extern bool evergreen_is_display_hung(struct radeon_device *rdev);
+extern void si_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
+extern void si_rlc_fini(struct radeon_device *rdev);
+extern int si_rlc_init(struct radeon_device *rdev);
+static void cik_rlc_stop(struct radeon_device *rdev);
+
+/*
+ * Indirect registers accessor
+ */
+u32 cik_pciep_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(PCIE_INDEX, reg);
+ (void)RREG32(PCIE_INDEX);
+ r = RREG32(PCIE_DATA);
+ return r;
+}
+
+void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(PCIE_INDEX, reg);
+ (void)RREG32(PCIE_INDEX);
+ WREG32(PCIE_DATA, v);
+ (void)RREG32(PCIE_DATA);
+}
+
+static const u32 bonaire_golden_spm_registers[] =
+{
+ 0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 bonaire_golden_common_registers[] =
+{
+ 0xc770, 0xffffffff, 0x00000800,
+ 0xc774, 0xffffffff, 0x00000800,
+ 0xc798, 0xffffffff, 0x00007fbf,
+ 0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 bonaire_golden_registers[] =
+{
+ 0x3354, 0x00000333, 0x00000333,
+ 0x3350, 0x000c0fc0, 0x00040200,
+ 0x9a10, 0x00010000, 0x00058208,
+ 0x3c000, 0xffff1fff, 0x00140000,
+ 0x3c200, 0xfdfc0fff, 0x00000100,
+ 0x3c234, 0x40000000, 0x40000200,
+ 0x9830, 0xffffffff, 0x00000000,
+ 0x9834, 0xf00fffff, 0x00000400,
+ 0x9838, 0x0002021c, 0x00020200,
+ 0xc78, 0x00000080, 0x00000000,
+ 0x5bb0, 0x000000f0, 0x00000070,
+ 0x5bc0, 0xf0311fff, 0x80300000,
+ 0x98f8, 0x73773777, 0x12010001,
+ 0x350c, 0x00810000, 0x408af000,
+ 0x7030, 0x31000111, 0x00000011,
+ 0x2f48, 0x73773777, 0x12010001,
+ 0x220c, 0x00007fb6, 0x0021a1b1,
+ 0x2210, 0x00007fb6, 0x002021b1,
+ 0x2180, 0x00007fb6, 0x00002191,
+ 0x2218, 0x00007fb6, 0x002121b1,
+ 0x221c, 0x00007fb6, 0x002021b1,
+ 0x21dc, 0x00007fb6, 0x00002191,
+ 0x21e0, 0x00007fb6, 0x00002191,
+ 0x3628, 0x0000003f, 0x0000000a,
+ 0x362c, 0x0000003f, 0x0000000a,
+ 0x2ae4, 0x00073ffe, 0x000022a2,
+ 0x240c, 0x000007ff, 0x00000000,
+ 0x8a14, 0xf000003f, 0x00000007,
+ 0x8bf0, 0x00002001, 0x00000001,
+ 0x8b24, 0xffffffff, 0x00ffffff,
+ 0x30a04, 0x0000ff0f, 0x00000000,
+ 0x28a4c, 0x07ffffff, 0x06000000,
+ 0x4d8, 0x00000fff, 0x00000100,
+ 0x3e78, 0x00000001, 0x00000002,
+ 0x9100, 0x03000000, 0x0362c688,
+ 0x8c00, 0x000000ff, 0x00000001,
+ 0xe40, 0x00001fff, 0x00001fff,
+ 0x9060, 0x0000007f, 0x00000020,
+ 0x9508, 0x00010000, 0x00010000,
+ 0xac14, 0x000003ff, 0x000000f3,
+ 0xac0c, 0xffffffff, 0x00001032
+};
+
+static const u32 bonaire_mgcg_cgcg_init[] =
+{
+ 0xc420, 0xffffffff, 0xfffffffc,
+ 0x30800, 0xffffffff, 0xe0000000,
+ 0x3c2a0, 0xffffffff, 0x00000100,
+ 0x3c208, 0xffffffff, 0x00000100,
+ 0x3c2c0, 0xffffffff, 0xc0000100,
+ 0x3c2c8, 0xffffffff, 0xc0000100,
+ 0x3c2c4, 0xffffffff, 0xc0000100,
+ 0x55e4, 0xffffffff, 0x00600100,
+ 0x3c280, 0xffffffff, 0x00000100,
+ 0x3c214, 0xffffffff, 0x06000100,
+ 0x3c220, 0xffffffff, 0x00000100,
+ 0x3c218, 0xffffffff, 0x06000100,
+ 0x3c204, 0xffffffff, 0x00000100,
+ 0x3c2e0, 0xffffffff, 0x00000100,
+ 0x3c224, 0xffffffff, 0x00000100,
+ 0x3c200, 0xffffffff, 0x00000100,
+ 0x3c230, 0xffffffff, 0x00000100,
+ 0x3c234, 0xffffffff, 0x00000100,
+ 0x3c250, 0xffffffff, 0x00000100,
+ 0x3c254, 0xffffffff, 0x00000100,
+ 0x3c258, 0xffffffff, 0x00000100,
+ 0x3c25c, 0xffffffff, 0x00000100,
+ 0x3c260, 0xffffffff, 0x00000100,
+ 0x3c27c, 0xffffffff, 0x00000100,
+ 0x3c278, 0xffffffff, 0x00000100,
+ 0x3c210, 0xffffffff, 0x06000100,
+ 0x3c290, 0xffffffff, 0x00000100,
+ 0x3c274, 0xffffffff, 0x00000100,
+ 0x3c2b4, 0xffffffff, 0x00000100,
+ 0x3c2b0, 0xffffffff, 0x00000100,
+ 0x3c270, 0xffffffff, 0x00000100,
+ 0x30800, 0xffffffff, 0xe0000000,
+ 0x3c020, 0xffffffff, 0x00010000,
+ 0x3c024, 0xffffffff, 0x00030002,
+ 0x3c028, 0xffffffff, 0x00040007,
+ 0x3c02c, 0xffffffff, 0x00060005,
+ 0x3c030, 0xffffffff, 0x00090008,
+ 0x3c034, 0xffffffff, 0x00010000,
+ 0x3c038, 0xffffffff, 0x00030002,
+ 0x3c03c, 0xffffffff, 0x00040007,
+ 0x3c040, 0xffffffff, 0x00060005,
+ 0x3c044, 0xffffffff, 0x00090008,
+ 0x3c048, 0xffffffff, 0x00010000,
+ 0x3c04c, 0xffffffff, 0x00030002,
+ 0x3c050, 0xffffffff, 0x00040007,
+ 0x3c054, 0xffffffff, 0x00060005,
+ 0x3c058, 0xffffffff, 0x00090008,
+ 0x3c05c, 0xffffffff, 0x00010000,
+ 0x3c060, 0xffffffff, 0x00030002,
+ 0x3c064, 0xffffffff, 0x00040007,
+ 0x3c068, 0xffffffff, 0x00060005,
+ 0x3c06c, 0xffffffff, 0x00090008,
+ 0x3c070, 0xffffffff, 0x00010000,
+ 0x3c074, 0xffffffff, 0x00030002,
+ 0x3c078, 0xffffffff, 0x00040007,
+ 0x3c07c, 0xffffffff, 0x00060005,
+ 0x3c080, 0xffffffff, 0x00090008,
+ 0x3c084, 0xffffffff, 0x00010000,
+ 0x3c088, 0xffffffff, 0x00030002,
+ 0x3c08c, 0xffffffff, 0x00040007,
+ 0x3c090, 0xffffffff, 0x00060005,
+ 0x3c094, 0xffffffff, 0x00090008,
+ 0x3c098, 0xffffffff, 0x00010000,
+ 0x3c09c, 0xffffffff, 0x00030002,
+ 0x3c0a0, 0xffffffff, 0x00040007,
+ 0x3c0a4, 0xffffffff, 0x00060005,
+ 0x3c0a8, 0xffffffff, 0x00090008,
+ 0x3c000, 0xffffffff, 0x96e00200,
+ 0x8708, 0xffffffff, 0x00900100,
+ 0xc424, 0xffffffff, 0x0020003f,
+ 0x38, 0xffffffff, 0x0140001c,
+ 0x3c, 0x000f0000, 0x000f0000,
+ 0x220, 0xffffffff, 0xC060000C,
+ 0x224, 0xc0000fff, 0x00000100,
+ 0xf90, 0xffffffff, 0x00000100,
+ 0xf98, 0x00000101, 0x00000000,
+ 0x20a8, 0xffffffff, 0x00000104,
+ 0x55e4, 0xff000fff, 0x00000100,
+ 0x30cc, 0xc0000fff, 0x00000104,
+ 0xc1e4, 0x00000001, 0x00000001,
+ 0xd00c, 0xff000ff0, 0x00000100,
+ 0xd80c, 0xff000ff0, 0x00000100
+};
+
+static const u32 spectre_golden_spm_registers[] =
+{
+ 0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 spectre_golden_common_registers[] =
+{
+ 0xc770, 0xffffffff, 0x00000800,
+ 0xc774, 0xffffffff, 0x00000800,
+ 0xc798, 0xffffffff, 0x00007fbf,
+ 0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 spectre_golden_registers[] =
+{
+ 0x3c000, 0xffff1fff, 0x96940200,
+ 0x3c00c, 0xffff0001, 0xff000000,
+ 0x3c200, 0xfffc0fff, 0x00000100,
+ 0x6ed8, 0x00010101, 0x00010000,
+ 0x9834, 0xf00fffff, 0x00000400,
+ 0x9838, 0xfffffffc, 0x00020200,
+ 0x5bb0, 0x000000f0, 0x00000070,
+ 0x5bc0, 0xf0311fff, 0x80300000,
+ 0x98f8, 0x73773777, 0x12010001,
+ 0x9b7c, 0x00ff0000, 0x00fc0000,
+ 0x2f48, 0x73773777, 0x12010001,
+ 0x8a14, 0xf000003f, 0x00000007,
+ 0x8b24, 0xffffffff, 0x00ffffff,
+ 0x28350, 0x3f3f3fff, 0x00000082,
+ 0x28355, 0x0000003f, 0x00000000,
+ 0x3e78, 0x00000001, 0x00000002,
+ 0x913c, 0xffff03df, 0x00000004,
+ 0xc768, 0x00000008, 0x00000008,
+ 0x8c00, 0x000008ff, 0x00000800,
+ 0x9508, 0x00010000, 0x00010000,
+ 0xac0c, 0xffffffff, 0x54763210,
+ 0x214f8, 0x01ff01ff, 0x00000002,
+ 0x21498, 0x007ff800, 0x00200000,
+ 0x2015c, 0xffffffff, 0x00000f40,
+ 0x30934, 0xffffffff, 0x00000001
+};
+
+static const u32 spectre_mgcg_cgcg_init[] =
+{
+ 0xc420, 0xffffffff, 0xfffffffc,
+ 0x30800, 0xffffffff, 0xe0000000,
+ 0x3c2a0, 0xffffffff, 0x00000100,
+ 0x3c208, 0xffffffff, 0x00000100,
+ 0x3c2c0, 0xffffffff, 0x00000100,
+ 0x3c2c8, 0xffffffff, 0x00000100,
+ 0x3c2c4, 0xffffffff, 0x00000100,
+ 0x55e4, 0xffffffff, 0x00600100,
+ 0x3c280, 0xffffffff, 0x00000100,
+ 0x3c214, 0xffffffff, 0x06000100,
+ 0x3c220, 0xffffffff, 0x00000100,
+ 0x3c218, 0xffffffff, 0x06000100,
+ 0x3c204, 0xffffffff, 0x00000100,
+ 0x3c2e0, 0xffffffff, 0x00000100,
+ 0x3c224, 0xffffffff, 0x00000100,
+ 0x3c200, 0xffffffff, 0x00000100,
+ 0x3c230, 0xffffffff, 0x00000100,
+ 0x3c234, 0xffffffff, 0x00000100,
+ 0x3c250, 0xffffffff, 0x00000100,
+ 0x3c254, 0xffffffff, 0x00000100,
+ 0x3c258, 0xffffffff, 0x00000100,
+ 0x3c25c, 0xffffffff, 0x00000100,
+ 0x3c260, 0xffffffff, 0x00000100,
+ 0x3c27c, 0xffffffff, 0x00000100,
+ 0x3c278, 0xffffffff, 0x00000100,
+ 0x3c210, 0xffffffff, 0x06000100,
+ 0x3c290, 0xffffffff, 0x00000100,
+ 0x3c274, 0xffffffff, 0x00000100,
+ 0x3c2b4, 0xffffffff, 0x00000100,
+ 0x3c2b0, 0xffffffff, 0x00000100,
+ 0x3c270, 0xffffffff, 0x00000100,
+ 0x30800, 0xffffffff, 0xe0000000,
+ 0x3c020, 0xffffffff, 0x00010000,
+ 0x3c024, 0xffffffff, 0x00030002,
+ 0x3c028, 0xffffffff, 0x00040007,
+ 0x3c02c, 0xffffffff, 0x00060005,
+ 0x3c030, 0xffffffff, 0x00090008,
+ 0x3c034, 0xffffffff, 0x00010000,
+ 0x3c038, 0xffffffff, 0x00030002,
+ 0x3c03c, 0xffffffff, 0x00040007,
+ 0x3c040, 0xffffffff, 0x00060005,
+ 0x3c044, 0xffffffff, 0x00090008,
+ 0x3c048, 0xffffffff, 0x00010000,
+ 0x3c04c, 0xffffffff, 0x00030002,
+ 0x3c050, 0xffffffff, 0x00040007,
+ 0x3c054, 0xffffffff, 0x00060005,
+ 0x3c058, 0xffffffff, 0x00090008,
+ 0x3c05c, 0xffffffff, 0x00010000,
+ 0x3c060, 0xffffffff, 0x00030002,
+ 0x3c064, 0xffffffff, 0x00040007,
+ 0x3c068, 0xffffffff, 0x00060005,
+ 0x3c06c, 0xffffffff, 0x00090008,
+ 0x3c070, 0xffffffff, 0x00010000,
+ 0x3c074, 0xffffffff, 0x00030002,
+ 0x3c078, 0xffffffff, 0x00040007,
+ 0x3c07c, 0xffffffff, 0x00060005,
+ 0x3c080, 0xffffffff, 0x00090008,
+ 0x3c084, 0xffffffff, 0x00010000,
+ 0x3c088, 0xffffffff, 0x00030002,
+ 0x3c08c, 0xffffffff, 0x00040007,
+ 0x3c090, 0xffffffff, 0x00060005,
+ 0x3c094, 0xffffffff, 0x00090008,
+ 0x3c098, 0xffffffff, 0x00010000,
+ 0x3c09c, 0xffffffff, 0x00030002,
+ 0x3c0a0, 0xffffffff, 0x00040007,
+ 0x3c0a4, 0xffffffff, 0x00060005,
+ 0x3c0a8, 0xffffffff, 0x00090008,
+ 0x3c0ac, 0xffffffff, 0x00010000,
+ 0x3c0b0, 0xffffffff, 0x00030002,
+ 0x3c0b4, 0xffffffff, 0x00040007,
+ 0x3c0b8, 0xffffffff, 0x00060005,
+ 0x3c0bc, 0xffffffff, 0x00090008,
+ 0x3c000, 0xffffffff, 0x96e00200,
+ 0x8708, 0xffffffff, 0x00900100,
+ 0xc424, 0xffffffff, 0x0020003f,
+ 0x38, 0xffffffff, 0x0140001c,
+ 0x3c, 0x000f0000, 0x000f0000,
+ 0x220, 0xffffffff, 0xC060000C,
+ 0x224, 0xc0000fff, 0x00000100,
+ 0xf90, 0xffffffff, 0x00000100,
+ 0xf98, 0x00000101, 0x00000000,
+ 0x20a8, 0xffffffff, 0x00000104,
+ 0x55e4, 0xff000fff, 0x00000100,
+ 0x30cc, 0xc0000fff, 0x00000104,
+ 0xc1e4, 0x00000001, 0x00000001,
+ 0xd00c, 0xff000ff0, 0x00000100,
+ 0xd80c, 0xff000ff0, 0x00000100
+};
+
+static const u32 kalindi_golden_spm_registers[] =
+{
+ 0x30800, 0xe0ffffff, 0xe0000000
+};
+
+static const u32 kalindi_golden_common_registers[] =
+{
+ 0xc770, 0xffffffff, 0x00000800,
+ 0xc774, 0xffffffff, 0x00000800,
+ 0xc798, 0xffffffff, 0x00007fbf,
+ 0xc79c, 0xffffffff, 0x00007faf
+};
+
+static const u32 kalindi_golden_registers[] =
+{
+ 0x3c000, 0xffffdfff, 0x6e944040,
+ 0x55e4, 0xff607fff, 0xfc000100,
+ 0x3c220, 0xff000fff, 0x00000100,
+ 0x3c224, 0xff000fff, 0x00000100,
+ 0x3c200, 0xfffc0fff, 0x00000100,
+ 0x6ed8, 0x00010101, 0x00010000,
+ 0x9830, 0xffffffff, 0x00000000,
+ 0x9834, 0xf00fffff, 0x00000400,
+ 0x5bb0, 0x000000f0, 0x00000070,
+ 0x5bc0, 0xf0311fff, 0x80300000,
+ 0x98f8, 0x73773777, 0x12010001,
+ 0x98fc, 0xffffffff, 0x00000010,
+ 0x9b7c, 0x00ff0000, 0x00fc0000,
+ 0x8030, 0x00001f0f, 0x0000100a,
+ 0x2f48, 0x73773777, 0x12010001,
+ 0x2408, 0x000fffff, 0x000c007f,
+ 0x8a14, 0xf000003f, 0x00000007,
+ 0x8b24, 0x3fff3fff, 0x00ffcfff,
+ 0x30a04, 0x0000ff0f, 0x00000000,
+ 0x28a4c, 0x07ffffff, 0x06000000,
+ 0x4d8, 0x00000fff, 0x00000100,
+ 0x3e78, 0x00000001, 0x00000002,
+ 0xc768, 0x00000008, 0x00000008,
+ 0x8c00, 0x000000ff, 0x00000003,
+ 0x214f8, 0x01ff01ff, 0x00000002,
+ 0x21498, 0x007ff800, 0x00200000,
+ 0x2015c, 0xffffffff, 0x00000f40,
+ 0x88c4, 0x001f3ae3, 0x00000082,
+ 0x88d4, 0x0000001f, 0x00000010,
+ 0x30934, 0xffffffff, 0x00000000
+};
+
+static const u32 kalindi_mgcg_cgcg_init[] =
+{
+ 0xc420, 0xffffffff, 0xfffffffc,
+ 0x30800, 0xffffffff, 0xe0000000,
+ 0x3c2a0, 0xffffffff, 0x00000100,
+ 0x3c208, 0xffffffff, 0x00000100,
+ 0x3c2c0, 0xffffffff, 0x00000100,
+ 0x3c2c8, 0xffffffff, 0x00000100,
+ 0x3c2c4, 0xffffffff, 0x00000100,
+ 0x55e4, 0xffffffff, 0x00600100,
+ 0x3c280, 0xffffffff, 0x00000100,
+ 0x3c214, 0xffffffff, 0x06000100,
+ 0x3c220, 0xffffffff, 0x00000100,
+ 0x3c218, 0xffffffff, 0x06000100,
+ 0x3c204, 0xffffffff, 0x00000100,
+ 0x3c2e0, 0xffffffff, 0x00000100,
+ 0x3c224, 0xffffffff, 0x00000100,
+ 0x3c200, 0xffffffff, 0x00000100,
+ 0x3c230, 0xffffffff, 0x00000100,
+ 0x3c234, 0xffffffff, 0x00000100,
+ 0x3c250, 0xffffffff, 0x00000100,
+ 0x3c254, 0xffffffff, 0x00000100,
+ 0x3c258, 0xffffffff, 0x00000100,
+ 0x3c25c, 0xffffffff, 0x00000100,
+ 0x3c260, 0xffffffff, 0x00000100,
+ 0x3c27c, 0xffffffff, 0x00000100,
+ 0x3c278, 0xffffffff, 0x00000100,
+ 0x3c210, 0xffffffff, 0x06000100,
+ 0x3c290, 0xffffffff, 0x00000100,
+ 0x3c274, 0xffffffff, 0x00000100,
+ 0x3c2b4, 0xffffffff, 0x00000100,
+ 0x3c2b0, 0xffffffff, 0x00000100,
+ 0x3c270, 0xffffffff, 0x00000100,
+ 0x30800, 0xffffffff, 0xe0000000,
+ 0x3c020, 0xffffffff, 0x00010000,
+ 0x3c024, 0xffffffff, 0x00030002,
+ 0x3c028, 0xffffffff, 0x00040007,
+ 0x3c02c, 0xffffffff, 0x00060005,
+ 0x3c030, 0xffffffff, 0x00090008,
+ 0x3c034, 0xffffffff, 0x00010000,
+ 0x3c038, 0xffffffff, 0x00030002,
+ 0x3c03c, 0xffffffff, 0x00040007,
+ 0x3c040, 0xffffffff, 0x00060005,
+ 0x3c044, 0xffffffff, 0x00090008,
+ 0x3c000, 0xffffffff, 0x96e00200,
+ 0x8708, 0xffffffff, 0x00900100,
+ 0xc424, 0xffffffff, 0x0020003f,
+ 0x38, 0xffffffff, 0x0140001c,
+ 0x3c, 0x000f0000, 0x000f0000,
+ 0x220, 0xffffffff, 0xC060000C,
+ 0x224, 0xc0000fff, 0x00000100,
+ 0x20a8, 0xffffffff, 0x00000104,
+ 0x55e4, 0xff000fff, 0x00000100,
+ 0x30cc, 0xc0000fff, 0x00000104,
+ 0xc1e4, 0x00000001, 0x00000001,
+ 0xd00c, 0xff000ff0, 0x00000100,
+ 0xd80c, 0xff000ff0, 0x00000100
+};
+
+static void cik_init_golden_registers(struct radeon_device *rdev)
+{
+ switch (rdev->family) {
+ case CHIP_BONAIRE:
+ radeon_program_register_sequence(rdev,
+ bonaire_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(bonaire_mgcg_cgcg_init));
+ radeon_program_register_sequence(rdev,
+ bonaire_golden_registers,
+ (const u32)ARRAY_SIZE(bonaire_golden_registers));
+ radeon_program_register_sequence(rdev,
+ bonaire_golden_common_registers,
+ (const u32)ARRAY_SIZE(bonaire_golden_common_registers));
+ radeon_program_register_sequence(rdev,
+ bonaire_golden_spm_registers,
+ (const u32)ARRAY_SIZE(bonaire_golden_spm_registers));
+ break;
+ case CHIP_KABINI:
+ radeon_program_register_sequence(rdev,
+ kalindi_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(kalindi_mgcg_cgcg_init));
+ radeon_program_register_sequence(rdev,
+ kalindi_golden_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_registers));
+ radeon_program_register_sequence(rdev,
+ kalindi_golden_common_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_common_registers));
+ radeon_program_register_sequence(rdev,
+ kalindi_golden_spm_registers,
+ (const u32)ARRAY_SIZE(kalindi_golden_spm_registers));
+ break;
+ case CHIP_KAVERI:
+ radeon_program_register_sequence(rdev,
+ spectre_mgcg_cgcg_init,
+ (const u32)ARRAY_SIZE(spectre_mgcg_cgcg_init));
+ radeon_program_register_sequence(rdev,
+ spectre_golden_registers,
+ (const u32)ARRAY_SIZE(spectre_golden_registers));
+ radeon_program_register_sequence(rdev,
+ spectre_golden_common_registers,
+ (const u32)ARRAY_SIZE(spectre_golden_common_registers));
+ radeon_program_register_sequence(rdev,
+ spectre_golden_spm_registers,
+ (const u32)ARRAY_SIZE(spectre_golden_spm_registers));
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * cik_get_xclk - get the xclk
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Returns the reference clock used by the gfx engine
+ * (CIK).
+ */
+u32 cik_get_xclk(struct radeon_device *rdev)
+{
+ u32 reference_clock = rdev->clock.spll.reference_freq;
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ if (RREG32_SMC(GENERAL_PWRMGT) & GPU_COUNTER_CLK)
+ return reference_clock / 2;
+ } else {
+ if (RREG32_SMC(CG_CLKPIN_CNTL) & XTALIN_DIVIDE)
+ return reference_clock / 4;
+ }
+ return reference_clock;
+}
+
+/**
+ * cik_mm_rdoorbell - read a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ *
+ * Returns the value in the doorbell aperture at the
+ * requested offset (CIK).
+ */
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
+{
+ if (offset < rdev->doorbell.size) {
+ return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
+ } else {
+ DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
+ return 0;
+ }
+}
+
+/**
+ * cik_mm_wdoorbell - write a doorbell dword
+ *
+ * @rdev: radeon_device pointer
+ * @offset: byte offset into the aperture
+ * @v: value to write
+ *
+ * Writes @v to the doorbell aperture at the
+ * requested offset (CIK).
+ */
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
+{
+ if (offset < rdev->doorbell.size) {
+ writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
+ } else {
+ DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
+ }
+}
+
+#define BONAIRE_IO_MC_REGS_SIZE 36
+
+static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
+{
+ {0x00000070, 0x04400000},
+ {0x00000071, 0x80c01803},
+ {0x00000072, 0x00004004},
+ {0x00000073, 0x00000100},
+ {0x00000074, 0x00ff0000},
+ {0x00000075, 0x34000000},
+ {0x00000076, 0x08000014},
+ {0x00000077, 0x00cc08ec},
+ {0x00000078, 0x00000400},
+ {0x00000079, 0x00000000},
+ {0x0000007a, 0x04090000},
+ {0x0000007c, 0x00000000},
+ {0x0000007e, 0x4408a8e8},
+ {0x0000007f, 0x00000304},
+ {0x00000080, 0x00000000},
+ {0x00000082, 0x00000001},
+ {0x00000083, 0x00000002},
+ {0x00000084, 0xf3e4f400},
+ {0x00000085, 0x052024e3},
+ {0x00000087, 0x00000000},
+ {0x00000088, 0x01000000},
+ {0x0000008a, 0x1c0a0000},
+ {0x0000008b, 0xff010000},
+ {0x0000008d, 0xffffefff},
+ {0x0000008e, 0xfff3efff},
+ {0x0000008f, 0xfff3efbf},
+ {0x00000092, 0xf7ffffff},
+ {0x00000093, 0xffffff7f},
+ {0x00000095, 0x00101101},
+ {0x00000096, 0x00000fff},
+ {0x00000097, 0x00116fff},
+ {0x00000098, 0x60010000},
+ {0x00000099, 0x10010000},
+ {0x0000009a, 0x00006000},
+ {0x0000009b, 0x00001000},
+ {0x0000009f, 0x00b48000}
+};
+
+/**
+ * cik_srbm_select - select specific register instances
+ *
+ * @rdev: radeon_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.
+ */
+static void cik_srbm_select(struct radeon_device *rdev,
+ u32 me, u32 pipe, u32 queue, u32 vmid)
+{
+ u32 srbm_gfx_cntl = (PIPEID(pipe & 0x3) |
+ MEID(me & 0x3) |
+ VMID(vmid & 0xf) |
+ QUEUEID(queue & 0x7));
+ WREG32(SRBM_GFX_CNTL, srbm_gfx_cntl);
+}
+
+/* ucode loading */
+/**
+ * ci_mc_load_microcode - load MC ucode into the hw
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Load the GDDR MC ucode into the hw (CIK).
+ * Returns 0 on success, error on failure.
+ */
+static int ci_mc_load_microcode(struct radeon_device *rdev)
+{
+ const __be32 *fw_data;
+ u32 running, blackout = 0;
+ u32 *io_mc_regs;
+ int i, ucode_size, regs_size;
+
+ if (!rdev->mc_fw)
+ return -EINVAL;
+
+ switch (rdev->family) {
+ case CHIP_BONAIRE:
+ default:
+ io_mc_regs = (u32 *)&bonaire_io_mc_regs;
+ ucode_size = CIK_MC_UCODE_SIZE;
+ regs_size = BONAIRE_IO_MC_REGS_SIZE;
+ break;
+ }
+
+ running = RREG32(MC_SEQ_SUP_CNTL) & RUN_MASK;
+
+ if (running == 0) {
+ if (running) {
+ blackout = RREG32(MC_SHARED_BLACKOUT_CNTL);
+ WREG32(MC_SHARED_BLACKOUT_CNTL, blackout | 1);
+ }
+
+ /* reset the engine and set to writable */
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000010);
+
+ /* load mc io regs */
+ for (i = 0; i < regs_size; i++) {
+ WREG32(MC_SEQ_IO_DEBUG_INDEX, io_mc_regs[(i << 1)]);
+ WREG32(MC_SEQ_IO_DEBUG_DATA, io_mc_regs[(i << 1) + 1]);
+ }
+ /* load the MC ucode */
+ fw_data = (const __be32 *)rdev->mc_fw->data;
+ for (i = 0; i < ucode_size; i++)
+ WREG32(MC_SEQ_SUP_PGM, be32_to_cpup(fw_data++));
+
+ /* put the engine back into the active state */
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000008);
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000004);
+ WREG32(MC_SEQ_SUP_CNTL, 0x00000001);
+
+ /* wait for training to complete */
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D0)
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(MC_SEQ_TRAIN_WAKEUP_CNTL) & TRAIN_DONE_D1)
+ break;
+ udelay(1);
+ }
+
+ if (running)
+ WREG32(MC_SHARED_BLACKOUT_CNTL, blackout);
+ }
+
+ return 0;
+}
+
+/**
+ * cik_init_microcode - load ucode images from disk
+ *
+ * @rdev: radeon_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_init_microcode(struct radeon_device *rdev)
+{
+ struct platform_device *pdev;
+ const char *chip_name;
+ size_t pfp_req_size, me_req_size, ce_req_size,
+ mec_req_size, rlc_req_size, mc_req_size,
+ sdma_req_size;
+ char fw_name[30];
+ int err;
+
+ DRM_DEBUG("\n");
+
+ pdev = platform_device_register_simple("radeon_cp", 0, NULL, 0);
+ err = IS_ERR(pdev);
+ if (err) {
+ printk(KERN_ERR "radeon_cp: Failed to register firmware\n");
+ return -EINVAL;
+ }
+
+ switch (rdev->family) {
+ case CHIP_BONAIRE:
+ chip_name = "BONAIRE";
+ pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+ me_req_size = CIK_ME_UCODE_SIZE * 4;
+ ce_req_size = CIK_CE_UCODE_SIZE * 4;
+ mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+ rlc_req_size = BONAIRE_RLC_UCODE_SIZE * 4;
+ mc_req_size = CIK_MC_UCODE_SIZE * 4;
+ sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
+ break;
+ case CHIP_KAVERI:
+ chip_name = "KAVERI";
+ pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+ me_req_size = CIK_ME_UCODE_SIZE * 4;
+ ce_req_size = CIK_CE_UCODE_SIZE * 4;
+ mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+ rlc_req_size = KV_RLC_UCODE_SIZE * 4;
+ sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
+ break;
+ case CHIP_KABINI:
+ chip_name = "KABINI";
+ pfp_req_size = CIK_PFP_UCODE_SIZE * 4;
+ me_req_size = CIK_ME_UCODE_SIZE * 4;
+ ce_req_size = CIK_CE_UCODE_SIZE * 4;
+ mec_req_size = CIK_MEC_UCODE_SIZE * 4;
+ rlc_req_size = KB_RLC_UCODE_SIZE * 4;
+ sdma_req_size = CIK_SDMA_UCODE_SIZE * 4;
+ break;
+ default: BUG();
+ }
+
+ DRM_INFO("Loading %s Microcode\n", chip_name);
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", chip_name);
+ err = request_firmware(&rdev->pfp_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->pfp_fw->size != pfp_req_size) {
+ printk(KERN_ERR
+ "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+ rdev->pfp_fw->size, fw_name);
+ err = -EINVAL;
+ goto out;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_me.bin", chip_name);
+ err = request_firmware(&rdev->me_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->me_fw->size != me_req_size) {
+ printk(KERN_ERR
+ "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+ rdev->me_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_ce.bin", chip_name);
+ err = request_firmware(&rdev->ce_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->ce_fw->size != ce_req_size) {
+ printk(KERN_ERR
+ "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+ rdev->ce_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mec.bin", chip_name);
+ err = request_firmware(&rdev->mec_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->mec_fw->size != mec_req_size) {
+ printk(KERN_ERR
+ "cik_cp: Bogus length %zu in firmware \"%s\"\n",
+ rdev->mec_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_rlc.bin", chip_name);
+ err = request_firmware(&rdev->rlc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->rlc_fw->size != rlc_req_size) {
+ printk(KERN_ERR
+ "cik_rlc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->rlc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_sdma.bin", chip_name);
+ err = request_firmware(&rdev->sdma_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->sdma_fw->size != sdma_req_size) {
+ printk(KERN_ERR
+ "cik_sdma: Bogus length %zu in firmware \"%s\"\n",
+ rdev->sdma_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
+ /* No MC ucode on APUs */
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+ err = request_firmware(&rdev->mc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->mc_fw->size != mc_req_size) {
+ printk(KERN_ERR
+ "cik_mc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->mc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+ }
+
+out:
+ platform_device_unregister(pdev);
+
+ if (err) {
+ if (err != -EINVAL)
+ printk(KERN_ERR
+ "cik_cp: Failed to load firmware \"%s\"\n",
+ fw_name);
+ release_firmware(rdev->pfp_fw);
+ rdev->pfp_fw = NULL;
+ release_firmware(rdev->me_fw);
+ rdev->me_fw = NULL;
+ release_firmware(rdev->ce_fw);
+ rdev->ce_fw = NULL;
+ release_firmware(rdev->rlc_fw);
+ rdev->rlc_fw = NULL;
+ release_firmware(rdev->mc_fw);
+ rdev->mc_fw = NULL;
+ }
+ return err;
+}
+
+/*
+ * Core functions
+ */
+/**
+ * cik_tiling_mode_table_init - init the hw tiling table
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Starting with SI, the tiling setup is done globally in a
+ * set of 32 tiling modes. Rather than selecting each set of
+ * parameters per surface as on older asics, we just select
+ * which index in the tiling table we want to use, and the
+ * surface uses those parameters (CIK).
+ */
+static void cik_tiling_mode_table_init(struct radeon_device *rdev)
+{
+ const u32 num_tile_mode_states = 32;
+ const u32 num_secondary_tile_mode_states = 16;
+ u32 reg_offset, gb_tile_moden, split_equal_to_row_size;
+ u32 num_pipe_configs;
+ u32 num_rbs = rdev->config.cik.max_backends_per_se *
+ rdev->config.cik.max_shader_engines;
+
+ switch (rdev->config.cik.mem_row_size_in_kb) {
+ case 1:
+ split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_1KB;
+ break;
+ case 2:
+ default:
+ split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_2KB;
+ break;
+ case 4:
+ split_equal_to_row_size = ADDR_SURF_TILE_SPLIT_4KB;
+ break;
+ }
+
+ num_pipe_configs = rdev->config.cik.max_tile_pipes;
+ if (num_pipe_configs > 8)
+ num_pipe_configs = 8; /* ??? */
+
+ if (num_pipe_configs == 8) {
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+ break;
+ case 1:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+ break;
+ case 2:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 3:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+ break;
+ case 4:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 5:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 6:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 7:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 8:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16));
+ break;
+ case 9:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+ break;
+ case 10:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 11:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 12:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 13:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+ break;
+ case 14:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 16:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 17:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 27:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+ break;
+ case 28:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 29:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 30:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
+ WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 1:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 2:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 3:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 4:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 5:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+ break;
+ case 6:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_2_BANK));
+ break;
+ case 8:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 9:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 10:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 11:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 12:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 13:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+ break;
+ case 14:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_2_BANK));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ } else if (num_pipe_configs == 4) {
+ if (num_rbs == 4) {
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+ break;
+ case 1:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+ break;
+ case 2:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 3:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+ break;
+ case 4:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 5:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 6:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 7:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 8:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16));
+ break;
+ case 9:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+ break;
+ case 10:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 11:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 12:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 13:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+ break;
+ case 14:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 16:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 17:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 27:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+ break;
+ case 28:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 29:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 30:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
+ WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ } else if (num_rbs < 4) {
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+ break;
+ case 1:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+ break;
+ case 2:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 3:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+ break;
+ case 4:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 5:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 6:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 7:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 8:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16));
+ break;
+ case 9:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+ break;
+ case 10:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 11:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 12:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 13:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+ break;
+ case 14:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 16:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 17:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 27:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+ break;
+ case 28:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 29:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 30:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P4_8x16) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
+ WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ }
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 1:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 2:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 3:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 4:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 5:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 6:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+ break;
+ case 8:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 9:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 10:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 11:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 12:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 13:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 14:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ } else if (num_pipe_configs == 2) {
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B));
+ break;
+ case 1:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B));
+ break;
+ case 2:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 3:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B));
+ break;
+ case 4:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 5:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 6:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B));
+ break;
+ case 7:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ TILE_SPLIT(split_equal_to_row_size));
+ break;
+ case 8:
+ gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED);
+ break;
+ case 9:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+ break;
+ case 10:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 11:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 12:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 13:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
+ break;
+ case 14:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 16:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 17:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 27:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+ break;
+ case 28:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 29:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 30:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ PIPE_CONFIG(ADDR_SURF_P2) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ rdev->config.cik.tile_mode_array[reg_offset] = gb_tile_moden;
+ WREG32(GB_TILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 1:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 2:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 3:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 4:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 5:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 6:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 8:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 9:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_4) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 10:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 11:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 12:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 13:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) |
+ NUM_BANKS(ADDR_SURF_16_BANK));
+ break;
+ case 14:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ WREG32(GB_MACROTILE_MODE0 + (reg_offset * 4), gb_tile_moden);
+ }
+ } else
+ DRM_ERROR("unknown num pipe config: 0x%x\n", num_pipe_configs);
+}
+
+/**
+ * cik_select_se_sh - select which SE, SH to address
+ *
+ * @rdev: radeon_device pointer
+ * @se_num: shader engine to address
+ * @sh_num: sh block to address
+ *
+ * Select which SE, SH combinations to address. Certain
+ * registers are instanced per SE or SH. 0xffffffff means
+ * broadcast to all SEs or SHs (CIK).
+ */
+static void cik_select_se_sh(struct radeon_device *rdev,
+ u32 se_num, u32 sh_num)
+{
+ u32 data = INSTANCE_BROADCAST_WRITES;
+
+ if ((se_num == 0xffffffff) && (sh_num == 0xffffffff))
+ data |= SH_BROADCAST_WRITES | SE_BROADCAST_WRITES;
+ else if (se_num == 0xffffffff)
+ data |= SE_BROADCAST_WRITES | SH_INDEX(sh_num);
+ else if (sh_num == 0xffffffff)
+ data |= SH_BROADCAST_WRITES | SE_INDEX(se_num);
+ else
+ data |= SH_INDEX(sh_num) | SE_INDEX(se_num);
+ WREG32(GRBM_GFX_INDEX, data);
+}
+
+/**
+ * cik_create_bitmask - create a bitmask
+ *
+ * @bit_width: length of the mask
+ *
+ * create a variable length bit mask (CIK).
+ * Returns the bitmask.
+ */
+static u32 cik_create_bitmask(u32 bit_width)
+{
+ u32 i, mask = 0;
+
+ for (i = 0; i < bit_width; i++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ return mask;
+}
+
+/**
+ * cik_select_se_sh - select which SE, SH to address
+ *
+ * @rdev: radeon_device pointer
+ * @max_rb_num: max RBs (render backends) for the asic
+ * @se_num: number of SEs (shader engines) for the asic
+ * @sh_per_se: number of SH blocks per SE for the asic
+ *
+ * Calculates the bitmask of disabled RBs (CIK).
+ * Returns the disabled RB bitmask.
+ */
+static u32 cik_get_rb_disabled(struct radeon_device *rdev,
+ u32 max_rb_num, u32 se_num,
+ u32 sh_per_se)
+{
+ u32 data, mask;
+
+ data = RREG32(CC_RB_BACKEND_DISABLE);
+ if (data & 1)
+ data &= BACKEND_DISABLE_MASK;
+ else
+ data = 0;
+ data |= RREG32(GC_USER_RB_BACKEND_DISABLE);
+
+ data >>= BACKEND_DISABLE_SHIFT;
+
+ mask = cik_create_bitmask(max_rb_num / se_num / sh_per_se);
+
+ return data & mask;
+}
+
+/**
+ * cik_setup_rb - setup the RBs on the asic
+ *
+ * @rdev: radeon_device pointer
+ * @se_num: number of SEs (shader engines) for the asic
+ * @sh_per_se: number of SH blocks per SE for the asic
+ * @max_rb_num: max RBs (render backends) for the asic
+ *
+ * Configures per-SE/SH RB registers (CIK).
+ */
+static void cik_setup_rb(struct radeon_device *rdev,
+ u32 se_num, u32 sh_per_se,
+ u32 max_rb_num)
+{
+ int i, j;
+ u32 data, mask;
+ u32 disabled_rbs = 0;
+ u32 enabled_rbs = 0;
+
+ for (i = 0; i < se_num; i++) {
+ for (j = 0; j < sh_per_se; j++) {
+ cik_select_se_sh(rdev, i, j);
+ data = cik_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se);
+ disabled_rbs |= data << ((i * sh_per_se + j) * CIK_RB_BITMAP_WIDTH_PER_SH);
+ }
+ }
+ cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+
+ mask = 1;
+ for (i = 0; i < max_rb_num; i++) {
+ if (!(disabled_rbs & mask))
+ enabled_rbs |= mask;
+ mask <<= 1;
+ }
+
+ for (i = 0; i < se_num; i++) {
+ cik_select_se_sh(rdev, i, 0xffffffff);
+ data = 0;
+ for (j = 0; j < sh_per_se; j++) {
+ switch (enabled_rbs & 3) {
+ case 1:
+ data |= (RASTER_CONFIG_RB_MAP_0 << (i * sh_per_se + j) * 2);
+ break;
+ case 2:
+ data |= (RASTER_CONFIG_RB_MAP_3 << (i * sh_per_se + j) * 2);
+ break;
+ case 3:
+ default:
+ data |= (RASTER_CONFIG_RB_MAP_2 << (i * sh_per_se + j) * 2);
+ break;
+ }
+ enabled_rbs >>= 2;
+ }
+ WREG32(PA_SC_RASTER_CONFIG, data);
+ }
+ cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+}
+
+/**
+ * cik_gpu_init - setup the 3D engine
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Configures the 3D engine and tiling configuration
+ * registers so that the 3D engine is usable.
+ */
+static void cik_gpu_init(struct radeon_device *rdev)
+{
+ u32 gb_addr_config = RREG32(GB_ADDR_CONFIG);
+ u32 mc_shared_chmap, mc_arb_ramcfg;
+ u32 hdp_host_path_cntl;
+ u32 tmp;
+ int i, j;
+
+ switch (rdev->family) {
+ case CHIP_BONAIRE:
+ rdev->config.cik.max_shader_engines = 2;
+ rdev->config.cik.max_tile_pipes = 4;
+ rdev->config.cik.max_cu_per_sh = 7;
+ rdev->config.cik.max_sh_per_se = 1;
+ rdev->config.cik.max_backends_per_se = 2;
+ rdev->config.cik.max_texture_channel_caches = 4;
+ rdev->config.cik.max_gprs = 256;
+ rdev->config.cik.max_gs_threads = 32;
+ rdev->config.cik.max_hw_contexts = 8;
+
+ rdev->config.cik.sc_prim_fifo_size_frontend = 0x20;
+ rdev->config.cik.sc_prim_fifo_size_backend = 0x100;
+ rdev->config.cik.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;
+ gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;
+ break;
+ case CHIP_KAVERI:
+ /* TODO */
+ break;
+ case CHIP_KABINI:
+ default:
+ rdev->config.cik.max_shader_engines = 1;
+ rdev->config.cik.max_tile_pipes = 2;
+ rdev->config.cik.max_cu_per_sh = 2;
+ rdev->config.cik.max_sh_per_se = 1;
+ rdev->config.cik.max_backends_per_se = 1;
+ rdev->config.cik.max_texture_channel_caches = 2;
+ rdev->config.cik.max_gprs = 256;
+ rdev->config.cik.max_gs_threads = 16;
+ rdev->config.cik.max_hw_contexts = 8;
+
+ rdev->config.cik.sc_prim_fifo_size_frontend = 0x20;
+ rdev->config.cik.sc_prim_fifo_size_backend = 0x100;
+ rdev->config.cik.sc_hiz_tile_fifo_size = 0x30;
+ rdev->config.cik.sc_earlyz_tile_fifo_size = 0x130;
+ gb_addr_config = BONAIRE_GB_ADDR_CONFIG_GOLDEN;
+ break;
+ }
+
+ /* Initialize HDP */
+ for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+ WREG32((0x2c14 + j), 0x00000000);
+ WREG32((0x2c18 + j), 0x00000000);
+ WREG32((0x2c1c + j), 0x00000000);
+ WREG32((0x2c20 + j), 0x00000000);
+ WREG32((0x2c24 + j), 0x00000000);
+ }
+
+ WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+
+ WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
+
+ mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
+ mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
+
+ rdev->config.cik.num_tile_pipes = rdev->config.cik.max_tile_pipes;
+ rdev->config.cik.mem_max_burst_length_bytes = 256;
+ tmp = (mc_arb_ramcfg & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT;
+ rdev->config.cik.mem_row_size_in_kb = (4 * (1 << (8 + tmp))) / 1024;
+ if (rdev->config.cik.mem_row_size_in_kb > 4)
+ rdev->config.cik.mem_row_size_in_kb = 4;
+ /* XXX use MC settings? */
+ rdev->config.cik.shader_engine_tile_size = 32;
+ rdev->config.cik.num_gpus = 1;
+ rdev->config.cik.multi_gpu_tile_size = 64;
+
+ /* fix up row size */
+ gb_addr_config &= ~ROW_SIZE_MASK;
+ switch (rdev->config.cik.mem_row_size_in_kb) {
+ case 1:
+ default:
+ gb_addr_config |= ROW_SIZE(0);
+ break;
+ case 2:
+ gb_addr_config |= ROW_SIZE(1);
+ break;
+ case 4:
+ gb_addr_config |= ROW_SIZE(2);
+ break;
+ }
+
+ /* setup tiling info dword. gb_addr_config is not adequate since it does
+ * not have bank info, so create a custom tiling dword.
+ * bits 3:0 num_pipes
+ * bits 7:4 num_banks
+ * bits 11:8 group_size
+ * bits 15:12 row_size
+ */
+ rdev->config.cik.tile_config = 0;
+ switch (rdev->config.cik.num_tile_pipes) {
+ case 1:
+ rdev->config.cik.tile_config |= (0 << 0);
+ break;
+ case 2:
+ rdev->config.cik.tile_config |= (1 << 0);
+ break;
+ case 4:
+ rdev->config.cik.tile_config |= (2 << 0);
+ break;
+ case 8:
+ default:
+ /* XXX what about 12? */
+ rdev->config.cik.tile_config |= (3 << 0);
+ break;
+ }
+ if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
+ rdev->config.cik.tile_config |= 1 << 4;
+ else
+ rdev->config.cik.tile_config |= 0 << 4;
+ rdev->config.cik.tile_config |=
+ ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
+ rdev->config.cik.tile_config |=
+ ((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12;
+
+ WREG32(GB_ADDR_CONFIG, gb_addr_config);
+ WREG32(HDP_ADDR_CONFIG, gb_addr_config);
+ WREG32(DMIF_ADDR_CALC, gb_addr_config);
+ WREG32(SDMA0_TILING_CONFIG + SDMA0_REGISTER_OFFSET, gb_addr_config & 0x70);
+ WREG32(SDMA0_TILING_CONFIG + SDMA1_REGISTER_OFFSET, gb_addr_config & 0x70);
+ WREG32(UVD_UDEC_ADDR_CONFIG, gb_addr_config);
+ WREG32(UVD_UDEC_DB_ADDR_CONFIG, gb_addr_config);
+ WREG32(UVD_UDEC_DBW_ADDR_CONFIG, gb_addr_config);
+
+ cik_tiling_mode_table_init(rdev);
+
+ cik_setup_rb(rdev, rdev->config.cik.max_shader_engines,
+ rdev->config.cik.max_sh_per_se,
+ rdev->config.cik.max_backends_per_se);
+
+ /* set HW defaults for 3D engine */
+ WREG32(CP_MEQ_THRESHOLDS, MEQ1_START(0x30) | MEQ2_START(0x60));
+
+ WREG32(SX_DEBUG_1, 0x20);
+
+ WREG32(TA_CNTL_AUX, 0x00010000);
+
+ tmp = RREG32(SPI_CONFIG_CNTL);
+ tmp |= 0x03000000;
+ WREG32(SPI_CONFIG_CNTL, tmp);
+
+ WREG32(SQ_CONFIG, 1);
+
+ WREG32(DB_DEBUG, 0);
+
+ tmp = RREG32(DB_DEBUG2) & ~0xf00fffff;
+ tmp |= 0x00000400;
+ WREG32(DB_DEBUG2, tmp);
+
+ tmp = RREG32(DB_DEBUG3) & ~0x0002021c;
+ tmp |= 0x00020200;
+ WREG32(DB_DEBUG3, tmp);
+
+ tmp = RREG32(CB_HW_CONTROL) & ~0x00010000;
+ tmp |= 0x00018208;
+ WREG32(CB_HW_CONTROL, tmp);
+
+ WREG32(SPI_CONFIG_CNTL_1, VTX_DONE_DELAY(4));
+
+ WREG32(PA_SC_FIFO_SIZE, (SC_FRONTEND_PRIM_FIFO_SIZE(rdev->config.cik.sc_prim_fifo_size_frontend) |
+ SC_BACKEND_PRIM_FIFO_SIZE(rdev->config.cik.sc_prim_fifo_size_backend) |
+ SC_HIZ_TILE_FIFO_SIZE(rdev->config.cik.sc_hiz_tile_fifo_size) |
+ SC_EARLYZ_TILE_FIFO_SIZE(rdev->config.cik.sc_earlyz_tile_fifo_size)));
+
+ WREG32(VGT_NUM_INSTANCES, 1);
+
+ WREG32(CP_PERFMON_CNTL, 0);
+
+ WREG32(SQ_CONFIG, 0);
+
+ WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) |
+ FORCE_EOV_MAX_REZ_CNT(255)));
+
+ WREG32(VGT_CACHE_INVALIDATION, CACHE_INVALIDATION(VC_AND_TC) |
+ AUTO_INVLD_EN(ES_AND_GS_AUTO));
+
+ WREG32(VGT_GS_VERTEX_REUSE, 16);
+ WREG32(PA_SC_LINE_STIPPLE_STATE, 0);
+
+ tmp = RREG32(HDP_MISC_CNTL);
+ tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+ WREG32(HDP_MISC_CNTL, tmp);
+
+ hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
+ WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
+
+ WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
+ WREG32(PA_SC_ENHANCE, ENABLE_PA_SC_OUT_OF_ORDER);
+
+ udelay(50);
+}
+
+/*
+ * GPU scratch registers helpers function.
+ */
+/**
+ * cik_scratch_init - setup driver info for CP scratch regs
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the number and offset of the CP scratch registers.
+ * NOTE: use of CP scratch registers is a legacy inferface and
+ * is not used by default on newer asics (r6xx+). On newer asics,
+ * memory buffers are used for fences rather than scratch regs.
+ */
+static void cik_scratch_init(struct radeon_device *rdev)
+{
+ int i;
+
+ rdev->scratch.num_reg = 7;
+ rdev->scratch.reg_base = SCRATCH_REG0;
+ for (i = 0; i < rdev->scratch.num_reg; i++) {
+ rdev->scratch.free[i] = true;
+ rdev->scratch.reg[i] = rdev->scratch.reg_base + (i * 4);
+ }
+}
+
+/**
+ * cik_ring_test - basic gfx ring test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Allocate a scratch register and write to it using the gfx ring (CIK).
+ * Provides a basic gfx ring test to verify that the ring is working.
+ * Used by cik_cp_gfx_resume();
+ * Returns 0 on success, error on failure.
+ */
+int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ uint32_t scratch;
+ uint32_t tmp = 0;
+ unsigned i;
+ int r;
+
+ r = radeon_scratch_get(rdev, &scratch);
+ if (r) {
+ DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r);
+ return r;
+ }
+ WREG32(scratch, 0xCAFEDEAD);
+ r = radeon_ring_lock(rdev, ring, 3);
+ if (r) {
+ DRM_ERROR("radeon: cp failed to lock ring %d (%d).\n", ring->idx, r);
+ radeon_scratch_free(rdev, scratch);
+ return r;
+ }
+ radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+ radeon_ring_write(ring, ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2));
+ radeon_ring_write(ring, 0xDEADBEEF);
+ radeon_ring_unlock_commit(rdev, ring);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = RREG32(scratch);
+ if (tmp == 0xDEADBEEF)
+ break;
+ DRM_UDELAY(1);
+ }
+ if (i < rdev->usec_timeout) {
+ DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+ } else {
+ DRM_ERROR("radeon: ring %d test failed (scratch(0x%04X)=0x%08X)\n",
+ ring->idx, scratch, tmp);
+ r = -EINVAL;
+ }
+ radeon_scratch_free(rdev, scratch);
+ return r;
+}
+
+/**
+ * cik_fence_gfx_ring_emit - emit a fence on the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Emits a fence sequnce number on the gfx ring and flushes
+ * GPU caches.
+ */
+void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence)
+{
+ struct radeon_ring *ring = &rdev->ring[fence->ring];
+ u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+ /* EVENT_WRITE_EOP - flush caches, send int */
+ radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+ radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+ EOP_TC_ACTION_EN |
+ EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+ EVENT_INDEX(5)));
+ radeon_ring_write(ring, addr & 0xfffffffc);
+ radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | DATA_SEL(1) | INT_SEL(2));
+ radeon_ring_write(ring, fence->seq);
+ radeon_ring_write(ring, 0);
+ /* HDP flush */
+ /* We should be using the new WAIT_REG_MEM special op packet here
+ * but it causes the CP to hang
+ */
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, 0);
+}
+
+/**
+ * cik_fence_compute_ring_emit - emit a fence on the compute ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon fence object
+ *
+ * Emits a fence sequnce number on the compute ring and flushes
+ * GPU caches.
+ */
+void cik_fence_compute_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence)
+{
+ struct radeon_ring *ring = &rdev->ring[fence->ring];
+ u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+ /* RELEASE_MEM - flush caches, send int */
+ radeon_ring_write(ring, PACKET3(PACKET3_RELEASE_MEM, 5));
+ radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+ EOP_TC_ACTION_EN |
+ EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+ EVENT_INDEX(5)));
+ radeon_ring_write(ring, DATA_SEL(1) | INT_SEL(2));
+ radeon_ring_write(ring, addr & 0xfffffffc);
+ radeon_ring_write(ring, upper_32_bits(addr));
+ radeon_ring_write(ring, fence->seq);
+ radeon_ring_write(ring, 0);
+ /* HDP flush */
+ /* We should be using the new WAIT_REG_MEM special op packet here
+ * but it causes the CP to hang
+ */
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, 0);
+}
+
+void cik_semaphore_ring_emit(struct radeon_device *rdev,
+ struct radeon_ring *ring,
+ struct radeon_semaphore *semaphore,
+ bool emit_wait)
+{
+ uint64_t addr = semaphore->gpu_addr;
+ unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
+
+ radeon_ring_write(ring, PACKET3(PACKET3_MEM_SEMAPHORE, 1));
+ radeon_ring_write(ring, addr & 0xffffffff);
+ radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel);
+}
+
+/*
+ * IB stuff
+ */
+/**
+ * cik_ring_ib_execute - emit an IB (Indirect Buffer) on the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ * @ib: radeon indirect buffer object
+ *
+ * Emits an DE (drawing engine) or CE (constant engine) IB
+ * on the gfx ring. IBs are usually generated by userspace
+ * acceleration drivers and submitted to the kernel for
+ * sheduling on the ring. This function schedules the IB
+ * on the gfx ring for execution by the GPU.
+ */
+void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+ struct radeon_ring *ring = &rdev->ring[ib->ring];
+ u32 header, control = INDIRECT_BUFFER_VALID;
+
+ if (ib->is_const_ib) {
+ /* set switch buffer packet before const IB */
+ radeon_ring_write(ring, PACKET3(PACKET3_SWITCH_BUFFER, 0));
+ radeon_ring_write(ring, 0);
+
+ header = PACKET3(PACKET3_INDIRECT_BUFFER_CONST, 2);
+ } else {
+ u32 next_rptr;
+ if (ring->rptr_save_reg) {
+ next_rptr = ring->wptr + 3 + 4;
+ radeon_ring_write(ring, PACKET3(PACKET3_SET_UCONFIG_REG, 1));
+ radeon_ring_write(ring, ((ring->rptr_save_reg -
+ PACKET3_SET_UCONFIG_REG_START) >> 2));
+ radeon_ring_write(ring, next_rptr);
+ } else if (rdev->wb.enabled) {
+ next_rptr = ring->wptr + 5 + 4;
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, WRITE_DATA_DST_SEL(1));
+ radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+ radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+ radeon_ring_write(ring, next_rptr);
+ }
+
+ header = PACKET3(PACKET3_INDIRECT_BUFFER, 2);
+ }
+
+ control |= ib->length_dw |
+ (ib->vm ? (ib->vm->id << 24) : 0);
+
+ radeon_ring_write(ring, header);
+ radeon_ring_write(ring,
+#ifdef __BIG_ENDIAN
+ (2 << 0) |
+#endif
+ (ib->gpu_addr & 0xFFFFFFFC));
+ radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
+ radeon_ring_write(ring, control);
+}
+
+/**
+ * cik_ib_test - basic gfx ring IB test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Allocate an IB and execute it on the gfx ring (CIK).
+ * Provides a basic gfx ring test to verify that IBs are working.
+ * Returns 0 on success, error on failure.
+ */
+int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ struct radeon_ib ib;
+ uint32_t scratch;
+ uint32_t tmp = 0;
+ unsigned i;
+ int r;
+
+ r = radeon_scratch_get(rdev, &scratch);
+ if (r) {
+ DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r);
+ return r;
+ }
+ WREG32(scratch, 0xCAFEDEAD);
+ r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
+ if (r) {
+ DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+ return r;
+ }
+ ib.ptr[0] = PACKET3(PACKET3_SET_UCONFIG_REG, 1);
+ ib.ptr[1] = ((scratch - PACKET3_SET_UCONFIG_REG_START) >> 2);
+ ib.ptr[2] = 0xDEADBEEF;
+ ib.length_dw = 3;
+ r = radeon_ib_schedule(rdev, &ib, NULL);
+ if (r) {
+ radeon_scratch_free(rdev, scratch);
+ radeon_ib_free(rdev, &ib);
+ DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+ return r;
+ }
+ r = radeon_fence_wait(ib.fence, false);
+ if (r) {
+ DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+ return r;
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = RREG32(scratch);
+ if (tmp == 0xDEADBEEF)
+ break;
+ DRM_UDELAY(1);
+ }
+ if (i < rdev->usec_timeout) {
+ DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
+ } else {
+ DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
+ scratch, tmp);
+ r = -EINVAL;
+ }
+ radeon_scratch_free(rdev, scratch);
+ radeon_ib_free(rdev, &ib);
+ return r;
+}
+
+/*
+ * CP.
+ * On CIK, gfx and compute now have independant command processors.
+ *
+ * GFX
+ * Gfx consists of a single ring and can process both gfx jobs and
+ * compute jobs. The gfx CP consists of three microengines (ME):
+ * PFP - Pre-Fetch Parser
+ * ME - Micro Engine
+ * CE - Constant Engine
+ * The PFP and ME make up what is considered the Drawing Engine (DE).
+ * The CE is an asynchronous engine used for updating buffer desciptors
+ * used by the DE so that they can be loaded into cache in parallel
+ * while the DE is processing state update packets.
+ *
+ * Compute
+ * The compute CP consists of two microengines (ME):
+ * MEC1 - Compute MicroEngine 1
+ * MEC2 - Compute MicroEngine 2
+ * Each MEC supports 4 compute pipes and each pipe supports 8 queues.
+ * The queues are exposed to userspace and are programmed directly
+ * by the compute runtime.
+ */
+/**
+ * cik_cp_gfx_enable - enable/disable the gfx CP MEs
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable or disable the MEs
+ *
+ * Halts or unhalts the gfx MEs.
+ */
+static void cik_cp_gfx_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32(CP_ME_CNTL, 0);
+ else {
+ WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
+ rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
+ }
+ udelay(50);
+}
+
+/**
+ * cik_cp_gfx_load_microcode - load the gfx CP ME ucode
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Loads the gfx PFP, ME, and CE ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_cp_gfx_load_microcode(struct radeon_device *rdev)
+{
+ const __be32 *fw_data;
+ int i;
+
+ if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw)
+ return -EINVAL;
+
+ cik_cp_gfx_enable(rdev, false);
+
+ /* PFP */
+ fw_data = (const __be32 *)rdev->pfp_fw->data;
+ WREG32(CP_PFP_UCODE_ADDR, 0);
+ for (i = 0; i < CIK_PFP_UCODE_SIZE; i++)
+ WREG32(CP_PFP_UCODE_DATA, be32_to_cpup(fw_data++));
+ WREG32(CP_PFP_UCODE_ADDR, 0);
+
+ /* CE */
+ fw_data = (const __be32 *)rdev->ce_fw->data;
+ WREG32(CP_CE_UCODE_ADDR, 0);
+ for (i = 0; i < CIK_CE_UCODE_SIZE; i++)
+ WREG32(CP_CE_UCODE_DATA, be32_to_cpup(fw_data++));
+ WREG32(CP_CE_UCODE_ADDR, 0);
+
+ /* ME */
+ fw_data = (const __be32 *)rdev->me_fw->data;
+ WREG32(CP_ME_RAM_WADDR, 0);
+ for (i = 0; i < CIK_ME_UCODE_SIZE; i++)
+ WREG32(CP_ME_RAM_DATA, be32_to_cpup(fw_data++));
+ WREG32(CP_ME_RAM_WADDR, 0);
+
+ WREG32(CP_PFP_UCODE_ADDR, 0);
+ WREG32(CP_CE_UCODE_ADDR, 0);
+ WREG32(CP_ME_RAM_WADDR, 0);
+ WREG32(CP_ME_RAM_RADDR, 0);
+ return 0;
+}
+
+/**
+ * cik_cp_gfx_start - start the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enables the ring and loads the clear state context and other
+ * packets required to init the ring.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_gfx_start(struct radeon_device *rdev)
+{
+ struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+ int r, i;
+
+ /* init the CP */
+ WREG32(CP_MAX_CONTEXT, rdev->config.cik.max_hw_contexts - 1);
+ WREG32(CP_ENDIAN_SWAP, 0);
+ WREG32(CP_DEVICE_ID, 1);
+
+ cik_cp_gfx_enable(rdev, true);
+
+ r = radeon_ring_lock(rdev, ring, cik_default_size + 17);
+ if (r) {
+ DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
+ return r;
+ }
+
+ /* init the CE partitions. CE only used for gfx on CIK */
+ radeon_ring_write(ring, PACKET3(PACKET3_SET_BASE, 2));
+ radeon_ring_write(ring, PACKET3_BASE_INDEX(CE_PARTITION_BASE));
+ radeon_ring_write(ring, 0xc000);
+ radeon_ring_write(ring, 0xc000);
+
+ /* setup clear context state */
+ radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+ radeon_ring_write(ring, PACKET3_PREAMBLE_BEGIN_CLEAR_STATE);
+
+ radeon_ring_write(ring, PACKET3(PACKET3_CONTEXT_CONTROL, 1));
+ radeon_ring_write(ring, 0x80000000);
+ radeon_ring_write(ring, 0x80000000);
+
+ for (i = 0; i < cik_default_size; i++)
+ radeon_ring_write(ring, cik_default_state[i]);
+
+ radeon_ring_write(ring, PACKET3(PACKET3_PREAMBLE_CNTL, 0));
+ radeon_ring_write(ring, PACKET3_PREAMBLE_END_CLEAR_STATE);
+
+ /* set clear context state */
+ radeon_ring_write(ring, PACKET3(PACKET3_CLEAR_STATE, 0));
+ radeon_ring_write(ring, 0);
+
+ radeon_ring_write(ring, PACKET3(PACKET3_SET_CONTEXT_REG, 2));
+ radeon_ring_write(ring, 0x00000316);
+ radeon_ring_write(ring, 0x0000000e); /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+ radeon_ring_write(ring, 0x00000010); /* VGT_OUT_DEALLOC_CNTL */
+
+ radeon_ring_unlock_commit(rdev, ring);
+
+ return 0;
+}
+
+/**
+ * cik_cp_gfx_fini - stop the gfx ring
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the gfx ring and tear down the driver ring
+ * info.
+ */
+static void cik_cp_gfx_fini(struct radeon_device *rdev)
+{
+ cik_cp_gfx_enable(rdev, false);
+ radeon_ring_fini(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+}
+
+/**
+ * cik_cp_gfx_resume - setup the gfx ring buffer registers
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Program the location and size of the gfx ring buffer
+ * and test it to make sure it's working.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_gfx_resume(struct radeon_device *rdev)
+{
+ struct radeon_ring *ring;
+ u32 tmp;
+ u32 rb_bufsz;
+ u64 rb_addr;
+ int r;
+
+ WREG32(CP_SEM_WAIT_TIMER, 0x0);
+ WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
+
+ /* Set the write pointer delay */
+ WREG32(CP_RB_WPTR_DELAY, 0);
+
+ /* set the RB to use vmid 0 */
+ WREG32(CP_RB_VMID, 0);
+
+ WREG32(SCRATCH_ADDR, ((rdev->wb.gpu_addr + RADEON_WB_SCRATCH_OFFSET) >> 8) & 0xFFFFFFFF);
+
+ /* ring 0 - compute and gfx */
+ /* Set ring buffer size */
+ ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+ rb_bufsz = drm_order(ring->ring_size / 8);
+ tmp = (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8) | rb_bufsz;
+#ifdef __BIG_ENDIAN
+ tmp |= BUF_SWAP_32BIT;
+#endif
+ WREG32(CP_RB0_CNTL, tmp);
+
+ /* Initialize the ring buffer's read and write pointers */
+ WREG32(CP_RB0_CNTL, tmp | RB_RPTR_WR_ENA);
+ ring->wptr = 0;
+ WREG32(CP_RB0_WPTR, ring->wptr);
+
+ /* set the wb address wether it's enabled or not */
+ WREG32(CP_RB0_RPTR_ADDR, (rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFFFFFFFC);
+ WREG32(CP_RB0_RPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + RADEON_WB_CP_RPTR_OFFSET) & 0xFF);
+
+ /* scratch register shadowing is no longer supported */
+ WREG32(SCRATCH_UMSK, 0);
+
+ if (!rdev->wb.enabled)
+ tmp |= RB_NO_UPDATE;
+
+ mdelay(1);
+ WREG32(CP_RB0_CNTL, tmp);
+
+ rb_addr = ring->gpu_addr >> 8;
+ WREG32(CP_RB0_BASE, rb_addr);
+ WREG32(CP_RB0_BASE_HI, upper_32_bits(rb_addr));
+
+ ring->rptr = RREG32(CP_RB0_RPTR);
+
+ /* start the ring */
+ cik_cp_gfx_start(rdev);
+ rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true;
+ r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+ if (r) {
+ rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
+ return r;
+ }
+ return 0;
+}
+
+u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ u32 rptr;
+
+
+
+ if (rdev->wb.enabled) {
+ rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+ } else {
+ cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+ rptr = RREG32(CP_HQD_PQ_RPTR);
+ cik_srbm_select(rdev, 0, 0, 0, 0);
+ }
+ rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+ return rptr;
+}
+
+u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ u32 wptr;
+
+ if (rdev->wb.enabled) {
+ wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
+ } else {
+ cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
+ wptr = RREG32(CP_HQD_PQ_WPTR);
+ cik_srbm_select(rdev, 0, 0, 0, 0);
+ }
+ wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+ return wptr;
+}
+
+void cik_compute_ring_set_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ u32 wptr = (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask;
+
+ rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(wptr);
+ WDOORBELL32(ring->doorbell_offset, wptr);
+}
+
+/**
+ * cik_cp_compute_enable - enable/disable the compute CP MEs
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable or disable the MEs
+ *
+ * Halts or unhalts the compute MEs.
+ */
+static void cik_cp_compute_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32(CP_MEC_CNTL, 0);
+ else
+ WREG32(CP_MEC_CNTL, (MEC_ME1_HALT | MEC_ME2_HALT));
+ udelay(50);
+}
+
+/**
+ * cik_cp_compute_load_microcode - load the compute CP ME ucode
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Loads the compute MEC1&2 ucode.
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_cp_compute_load_microcode(struct radeon_device *rdev)
+{
+ const __be32 *fw_data;
+ int i;
+
+ if (!rdev->mec_fw)
+ return -EINVAL;
+
+ cik_cp_compute_enable(rdev, false);
+
+ /* MEC1 */
+ fw_data = (const __be32 *)rdev->mec_fw->data;
+ WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
+ for (i = 0; i < CIK_MEC_UCODE_SIZE; i++)
+ WREG32(CP_MEC_ME1_UCODE_DATA, be32_to_cpup(fw_data++));
+ WREG32(CP_MEC_ME1_UCODE_ADDR, 0);
+
+ if (rdev->family == CHIP_KAVERI) {
+ /* MEC2 */
+ fw_data = (const __be32 *)rdev->mec_fw->data;
+ WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
+ for (i = 0; i < CIK_MEC_UCODE_SIZE; i++)
+ WREG32(CP_MEC_ME2_UCODE_DATA, be32_to_cpup(fw_data++));
+ WREG32(CP_MEC_ME2_UCODE_ADDR, 0);
+ }
+
+ return 0;
+}
+
+/**
+ * cik_cp_compute_start - start the compute queues
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable the compute queues.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_compute_start(struct radeon_device *rdev)
+{
+ cik_cp_compute_enable(rdev, true);
+
+ return 0;
+}
+
+/**
+ * cik_cp_compute_fini - stop the compute queues
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the compute queues and tear down the driver queue
+ * info.
+ */
+static void cik_cp_compute_fini(struct radeon_device *rdev)
+{
+ int i, idx, r;
+
+ cik_cp_compute_enable(rdev, false);
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0)
+ idx = CAYMAN_RING_TYPE_CP1_INDEX;
+ else
+ idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+ if (rdev->ring[idx].mqd_obj) {
+ r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+ if (unlikely(r != 0))
+ dev_warn(rdev->dev, "(%d) reserve MQD bo failed\n", r);
+
+ radeon_bo_unpin(rdev->ring[idx].mqd_obj);
+ radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+ radeon_bo_unref(&rdev->ring[idx].mqd_obj);
+ rdev->ring[idx].mqd_obj = NULL;
+ }
+ }
+}
+
+static void cik_mec_fini(struct radeon_device *rdev)
+{
+ int r;
+
+ if (rdev->mec.hpd_eop_obj) {
+ r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+ if (unlikely(r != 0))
+ dev_warn(rdev->dev, "(%d) reserve HPD EOP bo failed\n", r);
+ radeon_bo_unpin(rdev->mec.hpd_eop_obj);
+ radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+ radeon_bo_unref(&rdev->mec.hpd_eop_obj);
+ rdev->mec.hpd_eop_obj = NULL;
+ }
+}
+
+#define MEC_HPD_SIZE 2048
+
+static int cik_mec_init(struct radeon_device *rdev)
+{
+ int r;
+ u32 *hpd;
+
+ /*
+ * KV: 2 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 64 Queues total
+ * CI/KB: 1 MEC, 4 Pipes/MEC, 8 Queues/Pipe - 32 Queues total
+ */
+ if (rdev->family == CHIP_KAVERI)
+ rdev->mec.num_mec = 2;
+ else
+ rdev->mec.num_mec = 1;
+ rdev->mec.num_pipe = 4;
+ rdev->mec.num_queue = rdev->mec.num_mec * rdev->mec.num_pipe * 8;
+
+ if (rdev->mec.hpd_eop_obj == NULL) {
+ r = radeon_bo_create(rdev,
+ rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2,
+ PAGE_SIZE, true,
+ RADEON_GEM_DOMAIN_GTT, NULL,
+ &rdev->mec.hpd_eop_obj);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) create HDP EOP bo failed\n", r);
+ return r;
+ }
+ }
+
+ r = radeon_bo_reserve(rdev->mec.hpd_eop_obj, false);
+ if (unlikely(r != 0)) {
+ cik_mec_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_pin(rdev->mec.hpd_eop_obj, RADEON_GEM_DOMAIN_GTT,
+ &rdev->mec.hpd_eop_gpu_addr);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) pin HDP EOP bo failed\n", r);
+ cik_mec_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_kmap(rdev->mec.hpd_eop_obj, (void **)&hpd);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map HDP EOP bo failed\n", r);
+ cik_mec_fini(rdev);
+ return r;
+ }
+
+ /* clear memory. Not sure if this is required or not */
+ memset(hpd, 0, rdev->mec.num_mec *rdev->mec.num_pipe * MEC_HPD_SIZE * 2);
+
+ radeon_bo_kunmap(rdev->mec.hpd_eop_obj);
+ radeon_bo_unreserve(rdev->mec.hpd_eop_obj);
+
+ return 0;
+}
+
+struct hqd_registers
+{
+ u32 cp_mqd_base_addr;
+ u32 cp_mqd_base_addr_hi;
+ u32 cp_hqd_active;
+ u32 cp_hqd_vmid;
+ u32 cp_hqd_persistent_state;
+ u32 cp_hqd_pipe_priority;
+ u32 cp_hqd_queue_priority;
+ u32 cp_hqd_quantum;
+ u32 cp_hqd_pq_base;
+ u32 cp_hqd_pq_base_hi;
+ u32 cp_hqd_pq_rptr;
+ u32 cp_hqd_pq_rptr_report_addr;
+ u32 cp_hqd_pq_rptr_report_addr_hi;
+ u32 cp_hqd_pq_wptr_poll_addr;
+ u32 cp_hqd_pq_wptr_poll_addr_hi;
+ u32 cp_hqd_pq_doorbell_control;
+ u32 cp_hqd_pq_wptr;
+ u32 cp_hqd_pq_control;
+ u32 cp_hqd_ib_base_addr;
+ u32 cp_hqd_ib_base_addr_hi;
+ u32 cp_hqd_ib_rptr;
+ u32 cp_hqd_ib_control;
+ u32 cp_hqd_iq_timer;
+ u32 cp_hqd_iq_rptr;
+ u32 cp_hqd_dequeue_request;
+ u32 cp_hqd_dma_offload;
+ u32 cp_hqd_sema_cmd;
+ u32 cp_hqd_msg_type;
+ u32 cp_hqd_atomic0_preop_lo;
+ u32 cp_hqd_atomic0_preop_hi;
+ u32 cp_hqd_atomic1_preop_lo;
+ u32 cp_hqd_atomic1_preop_hi;
+ u32 cp_hqd_hq_scheduler0;
+ u32 cp_hqd_hq_scheduler1;
+ u32 cp_mqd_control;
+};
+
+struct bonaire_mqd
+{
+ u32 header;
+ u32 dispatch_initiator;
+ u32 dimensions[3];
+ u32 start_idx[3];
+ u32 num_threads[3];
+ u32 pipeline_stat_enable;
+ u32 perf_counter_enable;
+ u32 pgm[2];
+ u32 tba[2];
+ u32 tma[2];
+ u32 pgm_rsrc[2];
+ u32 vmid;
+ u32 resource_limits;
+ u32 static_thread_mgmt01[2];
+ u32 tmp_ring_size;
+ u32 static_thread_mgmt23[2];
+ u32 restart[3];
+ u32 thread_trace_enable;
+ u32 reserved1;
+ u32 user_data[16];
+ u32 vgtcs_invoke_count[2];
+ struct hqd_registers queue_state;
+ u32 dequeue_cntr;
+ u32 interrupt_queue[64];
+};
+
+/**
+ * cik_cp_compute_resume - setup the compute queue registers
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Program the compute queues and test them to make sure they
+ * are working.
+ * Returns 0 for success, error for failure.
+ */
+static int cik_cp_compute_resume(struct radeon_device *rdev)
+{
+ int r, i, idx;
+ u32 tmp;
+ bool use_doorbell = true;
+ u64 hqd_gpu_addr;
+ u64 mqd_gpu_addr;
+ u64 eop_gpu_addr;
+ u64 wb_gpu_addr;
+ u32 *buf;
+ struct bonaire_mqd *mqd;
+
+ r = cik_cp_compute_start(rdev);
+ if (r)
+ return r;
+
+ /* fix up chicken bits */
+ tmp = RREG32(CP_CPF_DEBUG);
+ tmp |= (1 << 23);
+ WREG32(CP_CPF_DEBUG, tmp);
+
+ /* init the pipes */
+ for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
+ int me = (i < 4) ? 1 : 2;
+ int pipe = (i < 4) ? i : (i - 4);
+
+ eop_gpu_addr = rdev->mec.hpd_eop_gpu_addr + (i * MEC_HPD_SIZE * 2);
+
+ cik_srbm_select(rdev, me, pipe, 0, 0);
+
+ /* write the EOP addr */
+ WREG32(CP_HPD_EOP_BASE_ADDR, eop_gpu_addr >> 8);
+ WREG32(CP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(eop_gpu_addr) >> 8);
+
+ /* set the VMID assigned */
+ WREG32(CP_HPD_EOP_VMID, 0);
+
+ /* set the EOP size, register value is 2^(EOP_SIZE+1) dwords */
+ tmp = RREG32(CP_HPD_EOP_CONTROL);
+ tmp &= ~EOP_SIZE_MASK;
+ tmp |= drm_order(MEC_HPD_SIZE / 8);
+ WREG32(CP_HPD_EOP_CONTROL, tmp);
+ }
+ cik_srbm_select(rdev, 0, 0, 0, 0);
+
+ /* init the queues. Just two for now. */
+ for (i = 0; i < 2; i++) {
+ if (i == 0)
+ idx = CAYMAN_RING_TYPE_CP1_INDEX;
+ else
+ idx = CAYMAN_RING_TYPE_CP2_INDEX;
+
+ if (rdev->ring[idx].mqd_obj == NULL) {
+ r = radeon_bo_create(rdev,
+ sizeof(struct bonaire_mqd),
+ PAGE_SIZE, true,
+ RADEON_GEM_DOMAIN_GTT, NULL,
+ &rdev->ring[idx].mqd_obj);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) create MQD bo failed\n", r);
+ return r;
+ }
+ }
+
+ r = radeon_bo_reserve(rdev->ring[idx].mqd_obj, false);
+ if (unlikely(r != 0)) {
+ cik_cp_compute_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_pin(rdev->ring[idx].mqd_obj, RADEON_GEM_DOMAIN_GTT,
+ &mqd_gpu_addr);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) pin MQD bo failed\n", r);
+ cik_cp_compute_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_kmap(rdev->ring[idx].mqd_obj, (void **)&buf);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map MQD bo failed\n", r);
+ cik_cp_compute_fini(rdev);
+ return r;
+ }
+
+ /* doorbell offset */
+ rdev->ring[idx].doorbell_offset =
+ (rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
+
+ /* init the mqd struct */
+ memset(buf, 0, sizeof(struct bonaire_mqd));
+
+ mqd = (struct bonaire_mqd *)buf;
+ mqd->header = 0xC0310800;
+ mqd->static_thread_mgmt01[0] = 0xffffffff;
+ mqd->static_thread_mgmt01[1] = 0xffffffff;
+ mqd->static_thread_mgmt23[0] = 0xffffffff;
+ mqd->static_thread_mgmt23[1] = 0xffffffff;
+
+ cik_srbm_select(rdev, rdev->ring[idx].me,
+ rdev->ring[idx].pipe,
+ rdev->ring[idx].queue, 0);
+
+ /* disable wptr polling */
+ tmp = RREG32(CP_PQ_WPTR_POLL_CNTL);
+ tmp &= ~WPTR_POLL_EN;
+ WREG32(CP_PQ_WPTR_POLL_CNTL, tmp);
+
+ /* enable doorbell? */
+ mqd->queue_state.cp_hqd_pq_doorbell_control =
+ RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+ if (use_doorbell)
+ mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+ else
+ mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_EN;
+ WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+ mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+ /* disable the queue if it's active */
+ mqd->queue_state.cp_hqd_dequeue_request = 0;
+ mqd->queue_state.cp_hqd_pq_rptr = 0;
+ mqd->queue_state.cp_hqd_pq_wptr= 0;
+ if (RREG32(CP_HQD_ACTIVE) & 1) {
+ WREG32(CP_HQD_DEQUEUE_REQUEST, 1);
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32(CP_HQD_ACTIVE) & 1))
+ break;
+ udelay(1);
+ }
+ WREG32(CP_HQD_DEQUEUE_REQUEST, mqd->queue_state.cp_hqd_dequeue_request);
+ WREG32(CP_HQD_PQ_RPTR, mqd->queue_state.cp_hqd_pq_rptr);
+ WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+ }
+
+ /* set the pointer to the MQD */
+ mqd->queue_state.cp_mqd_base_addr = mqd_gpu_addr & 0xfffffffc;
+ mqd->queue_state.cp_mqd_base_addr_hi = upper_32_bits(mqd_gpu_addr);
+ WREG32(CP_MQD_BASE_ADDR, mqd->queue_state.cp_mqd_base_addr);
+ WREG32(CP_MQD_BASE_ADDR_HI, mqd->queue_state.cp_mqd_base_addr_hi);
+ /* set MQD vmid to 0 */
+ mqd->queue_state.cp_mqd_control = RREG32(CP_MQD_CONTROL);
+ mqd->queue_state.cp_mqd_control &= ~MQD_VMID_MASK;
+ WREG32(CP_MQD_CONTROL, mqd->queue_state.cp_mqd_control);
+
+ /* set the pointer to the HQD, this is similar CP_RB0_BASE/_HI */
+ hqd_gpu_addr = rdev->ring[idx].gpu_addr >> 8;
+ mqd->queue_state.cp_hqd_pq_base = hqd_gpu_addr;
+ mqd->queue_state.cp_hqd_pq_base_hi = upper_32_bits(hqd_gpu_addr);
+ WREG32(CP_HQD_PQ_BASE, mqd->queue_state.cp_hqd_pq_base);
+ WREG32(CP_HQD_PQ_BASE_HI, mqd->queue_state.cp_hqd_pq_base_hi);
+
+ /* set up the HQD, this is similar to CP_RB0_CNTL */
+ mqd->queue_state.cp_hqd_pq_control = RREG32(CP_HQD_PQ_CONTROL);
+ mqd->queue_state.cp_hqd_pq_control &=
+ ~(QUEUE_SIZE_MASK | RPTR_BLOCK_SIZE_MASK);
+
+ mqd->queue_state.cp_hqd_pq_control |=
+ drm_order(rdev->ring[idx].ring_size / 8);
+ mqd->queue_state.cp_hqd_pq_control |=
+ (drm_order(RADEON_GPU_PAGE_SIZE/8) << 8);
+#ifdef __BIG_ENDIAN
+ mqd->queue_state.cp_hqd_pq_control |= BUF_SWAP_32BIT;
+#endif
+ mqd->queue_state.cp_hqd_pq_control &=
+ ~(UNORD_DISPATCH | ROQ_PQ_IB_FLIP | PQ_VOLATILE);
+ mqd->queue_state.cp_hqd_pq_control |=
+ PRIV_STATE | KMD_QUEUE; /* assuming kernel queue control */
+ WREG32(CP_HQD_PQ_CONTROL, mqd->queue_state.cp_hqd_pq_control);
+
+ /* only used if CP_PQ_WPTR_POLL_CNTL.WPTR_POLL_EN=1 */
+ if (i == 0)
+ wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP1_WPTR_OFFSET;
+ else
+ wb_gpu_addr = rdev->wb.gpu_addr + CIK_WB_CP2_WPTR_OFFSET;
+ mqd->queue_state.cp_hqd_pq_wptr_poll_addr = wb_gpu_addr & 0xfffffffc;
+ mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi = upper_32_bits(wb_gpu_addr) & 0xffff;
+ WREG32(CP_HQD_PQ_WPTR_POLL_ADDR, mqd->queue_state.cp_hqd_pq_wptr_poll_addr);
+ WREG32(CP_HQD_PQ_WPTR_POLL_ADDR_HI,
+ mqd->queue_state.cp_hqd_pq_wptr_poll_addr_hi);
+
+ /* set the wb address wether it's enabled or not */
+ if (i == 0)
+ wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP1_RPTR_OFFSET;
+ else
+ wb_gpu_addr = rdev->wb.gpu_addr + RADEON_WB_CP2_RPTR_OFFSET;
+ mqd->queue_state.cp_hqd_pq_rptr_report_addr = wb_gpu_addr & 0xfffffffc;
+ mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi =
+ upper_32_bits(wb_gpu_addr) & 0xffff;
+ WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR,
+ mqd->queue_state.cp_hqd_pq_rptr_report_addr);
+ WREG32(CP_HQD_PQ_RPTR_REPORT_ADDR_HI,
+ mqd->queue_state.cp_hqd_pq_rptr_report_addr_hi);
+
+ /* enable the doorbell if requested */
+ if (use_doorbell) {
+ mqd->queue_state.cp_hqd_pq_doorbell_control =
+ RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
+ mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;
+ mqd->queue_state.cp_hqd_pq_doorbell_control |=
+ DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4);
+ mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
+ mqd->queue_state.cp_hqd_pq_doorbell_control &=
+ ~(DOORBELL_SOURCE | DOORBELL_HIT);
+
+ } else {
+ mqd->queue_state.cp_hqd_pq_doorbell_control = 0;
+ }
+ WREG32(CP_HQD_PQ_DOORBELL_CONTROL,
+ mqd->queue_state.cp_hqd_pq_doorbell_control);
+
+ /* read and write pointers, similar to CP_RB0_WPTR/_RPTR */
+ rdev->ring[idx].wptr = 0;
+ mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;
+ WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
+ rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR);
+ mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr;
+
+ /* set the vmid for the queue */
+ mqd->queue_state.cp_hqd_vmid = 0;
+ WREG32(CP_HQD_VMID, mqd->queue_state.cp_hqd_vmid);
+
+ /* activate the queue */
+ mqd->queue_state.cp_hqd_active = 1;
+ WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
+
+ cik_srbm_select(rdev, 0, 0, 0, 0);
+
+ radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
+ radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
+
+ rdev->ring[idx].ready = true;
+ r = radeon_ring_test(rdev, idx, &rdev->ring[idx]);
+ if (r)
+ rdev->ring[idx].ready = false;
+ }
+
+ return 0;
+}
+
+static void cik_cp_enable(struct radeon_device *rdev, bool enable)
+{
+ cik_cp_gfx_enable(rdev, enable);
+ cik_cp_compute_enable(rdev, enable);
+}
+
+static int cik_cp_load_microcode(struct radeon_device *rdev)
+{
+ int r;
+
+ r = cik_cp_gfx_load_microcode(rdev);
+ if (r)
+ return r;
+ r = cik_cp_compute_load_microcode(rdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void cik_cp_fini(struct radeon_device *rdev)
+{
+ cik_cp_gfx_fini(rdev);
+ cik_cp_compute_fini(rdev);
+}
+
+static int cik_cp_resume(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Reset all cp blocks */
+ WREG32(GRBM_SOFT_RESET, SOFT_RESET_CP);
+ RREG32(GRBM_SOFT_RESET);
+ mdelay(15);
+ WREG32(GRBM_SOFT_RESET, 0);
+ RREG32(GRBM_SOFT_RESET);
+
+ r = cik_cp_load_microcode(rdev);
+ if (r)
+ return r;
+
+ r = cik_cp_gfx_resume(rdev);
+ if (r)
+ return r;
+ r = cik_cp_compute_resume(rdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+/*
+ * 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_ring_ib_execute - Schedule an IB on the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @ib: IB object to schedule
+ *
+ * Schedule an IB in the DMA ring (CIK).
+ */
+void cik_sdma_ring_ib_execute(struct radeon_device *rdev,
+ struct radeon_ib *ib)
+{
+ struct radeon_ring *ring = &rdev->ring[ib->ring];
+ u32 extra_bits = (ib->vm ? ib->vm->id : 0) & 0xf;
+
+ if (rdev->wb.enabled) {
+ u32 next_rptr = ring->wptr + 5;
+ while ((next_rptr & 7) != 4)
+ next_rptr++;
+ next_rptr += 4;
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+ radeon_ring_write(ring, ring->next_rptr_gpu_addr & 0xfffffffc);
+ radeon_ring_write(ring, upper_32_bits(ring->next_rptr_gpu_addr) & 0xffffffff);
+ radeon_ring_write(ring, 1); /* number of DWs to follow */
+ radeon_ring_write(ring, next_rptr);
+ }
+
+ /* IB packet must end on a 8 DW boundary */
+ while ((ring->wptr & 7) != 4)
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits));
+ radeon_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */
+ radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff);
+ radeon_ring_write(ring, ib->length_dw);
+
+}
+
+/**
+ * cik_sdma_fence_ring_emit - emit a fence on the DMA ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: radeon 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).
+ */
+void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence)
+{
+ struct radeon_ring *ring = &rdev->ring[fence->ring];
+ u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+ u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+ SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+ u32 ref_and_mask;
+
+ if (fence->ring == R600_RING_TYPE_DMA_INDEX)
+ ref_and_mask = SDMA0;
+ else
+ ref_and_mask = SDMA1;
+
+ /* write the fence */
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_FENCE, 0, 0));
+ radeon_ring_write(ring, addr & 0xffffffff);
+ radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+ radeon_ring_write(ring, fence->seq);
+ /* generate an interrupt */
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));
+ /* flush HDP */
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+ radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+ radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+ radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
+ radeon_ring_write(ring, ref_and_mask); /* MASK */
+ radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+}
+
+/**
+ * cik_sdma_semaphore_ring_emit - emit a semaphore on the dma ring
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ * @semaphore: radeon semaphore object
+ * @emit_wait: wait or signal semaphore
+ *
+ * Add a DMA semaphore packet to the ring wait on or signal
+ * other rings (CIK).
+ */
+void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
+ struct radeon_ring *ring,
+ struct radeon_semaphore *semaphore,
+ bool emit_wait)
+{
+ u64 addr = semaphore->gpu_addr;
+ u32 extra_bits = emit_wait ? 0 : SDMA_SEMAPHORE_EXTRA_S;
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SEMAPHORE, 0, extra_bits));
+ radeon_ring_write(ring, addr & 0xfffffff8);
+ radeon_ring_write(ring, upper_32_bits(addr) & 0xffffffff);
+}
+
+/**
+ * cik_sdma_gfx_stop - stop the gfx async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the gfx async dma ring buffers (CIK).
+ */
+static void cik_sdma_gfx_stop(struct radeon_device *rdev)
+{
+ u32 rb_cntl, reg_offset;
+ int i;
+
+ radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0)
+ reg_offset = SDMA0_REGISTER_OFFSET;
+ else
+ reg_offset = SDMA1_REGISTER_OFFSET;
+ rb_cntl = RREG32(SDMA0_GFX_RB_CNTL + reg_offset);
+ rb_cntl &= ~SDMA_RB_ENABLE;
+ WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
+ WREG32(SDMA0_GFX_IB_CNTL + reg_offset, 0);
+ }
+}
+
+/**
+ * cik_sdma_rlc_stop - stop the compute async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the compute async dma queues (CIK).
+ */
+static void cik_sdma_rlc_stop(struct radeon_device *rdev)
+{
+ /* XXX todo */
+}
+
+/**
+ * cik_sdma_enable - stop the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable/disable the DMA MEs.
+ *
+ * Halt or unhalt the async dma engines (CIK).
+ */
+static void cik_sdma_enable(struct radeon_device *rdev, bool enable)
+{
+ u32 me_cntl, reg_offset;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0)
+ reg_offset = SDMA0_REGISTER_OFFSET;
+ else
+ reg_offset = SDMA1_REGISTER_OFFSET;
+ me_cntl = RREG32(SDMA0_ME_CNTL + reg_offset);
+ if (enable)
+ me_cntl &= ~SDMA_HALT;
+ else
+ me_cntl |= SDMA_HALT;
+ WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl);
+ }
+}
+
+/**
+ * cik_sdma_gfx_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_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 radeon_device *rdev)
+{
+ struct radeon_ring *ring;
+ u32 rb_cntl, ib_cntl;
+ u32 rb_bufsz;
+ u32 reg_offset, wb_offset;
+ int i, r;
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+ reg_offset = SDMA0_REGISTER_OFFSET;
+ wb_offset = R600_WB_DMA_RPTR_OFFSET;
+ } else {
+ ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+ reg_offset = SDMA1_REGISTER_OFFSET;
+ wb_offset = CAYMAN_WB_DMA1_RPTR_OFFSET;
+ }
+
+ WREG32(SDMA0_SEM_INCOMPLETE_TIMER_CNTL + reg_offset, 0);
+ WREG32(SDMA0_SEM_WAIT_FAIL_TIMER_CNTL + reg_offset, 0);
+
+ /* Set ring buffer size in dwords */
+ rb_bufsz = drm_order(ring->ring_size / 4);
+ rb_cntl = rb_bufsz << 1;
+#ifdef __BIG_ENDIAN
+ rb_cntl |= SDMA_RB_SWAP_ENABLE | SDMA_RPTR_WRITEBACK_SWAP_ENABLE;
+#endif
+ WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl);
+
+ /* Initialize the ring buffer's read and write pointers */
+ WREG32(SDMA0_GFX_RB_RPTR + reg_offset, 0);
+ WREG32(SDMA0_GFX_RB_WPTR + reg_offset, 0);
+
+ /* set the wb address whether it's enabled or not */
+ WREG32(SDMA0_GFX_RB_RPTR_ADDR_HI + reg_offset,
+ upper_32_bits(rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFF);
+ WREG32(SDMA0_GFX_RB_RPTR_ADDR_LO + reg_offset,
+ ((rdev->wb.gpu_addr + wb_offset) & 0xFFFFFFFC));
+
+ if (rdev->wb.enabled)
+ rb_cntl |= SDMA_RPTR_WRITEBACK_ENABLE;
+
+ WREG32(SDMA0_GFX_RB_BASE + reg_offset, ring->gpu_addr >> 8);
+ WREG32(SDMA0_GFX_RB_BASE_HI + reg_offset, ring->gpu_addr >> 40);
+
+ ring->wptr = 0;
+ WREG32(SDMA0_GFX_RB_WPTR + reg_offset, ring->wptr << 2);
+
+ ring->rptr = RREG32(SDMA0_GFX_RB_RPTR + reg_offset) >> 2;
+
+ /* enable DMA RB */
+ WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl | SDMA_RB_ENABLE);
+
+ ib_cntl = SDMA_IB_ENABLE;
+#ifdef __BIG_ENDIAN
+ ib_cntl |= SDMA_IB_SWAP_ENABLE;
+#endif
+ /* enable DMA IBs */
+ WREG32(SDMA0_GFX_IB_CNTL + reg_offset, ib_cntl);
+
+ ring->ready = true;
+
+ r = radeon_ring_test(rdev, ring->idx, ring);
+ if (r) {
+ ring->ready = false;
+ return r;
+ }
+ }
+
+ radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
+ return 0;
+}
+
+/**
+ * cik_sdma_rlc_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_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 radeon_device *rdev)
+{
+ /* XXX todo */
+ return 0;
+}
+
+/**
+ * cik_sdma_load_microcode - load the sDMA ME ucode
+ *
+ * @rdev: radeon_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 radeon_device *rdev)
+{
+ const __be32 *fw_data;
+ int i;
+
+ if (!rdev->sdma_fw)
+ return -EINVAL;
+
+ /* stop the gfx rings and rlc compute queues */
+ cik_sdma_gfx_stop(rdev);
+ cik_sdma_rlc_stop(rdev);
+
+ /* halt the MEs */
+ cik_sdma_enable(rdev, false);
+
+ /* sdma0 */
+ fw_data = (const __be32 *)rdev->sdma_fw->data;
+ WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0);
+ for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++)
+ WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, be32_to_cpup(fw_data++));
+ WREG32(SDMA0_UCODE_DATA + SDMA0_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION);
+
+ /* sdma1 */
+ fw_data = (const __be32 *)rdev->sdma_fw->data;
+ WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0);
+ for (i = 0; i < CIK_SDMA_UCODE_SIZE; i++)
+ WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, be32_to_cpup(fw_data++));
+ WREG32(SDMA0_UCODE_DATA + SDMA1_REGISTER_OFFSET, CIK_SDMA_UCODE_VERSION);
+
+ WREG32(SDMA0_UCODE_ADDR + SDMA0_REGISTER_OFFSET, 0);
+ WREG32(SDMA0_UCODE_ADDR + SDMA1_REGISTER_OFFSET, 0);
+ return 0;
+}
+
+/**
+ * cik_sdma_resume - setup and start the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set up the DMA engines and enable them (CIK).
+ * Returns 0 for success, error for failure.
+ */
+static int cik_sdma_resume(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Reset dma */
+ WREG32(SRBM_SOFT_RESET, SOFT_RESET_SDMA | SOFT_RESET_SDMA1);
+ RREG32(SRBM_SOFT_RESET);
+ udelay(50);
+ WREG32(SRBM_SOFT_RESET, 0);
+ RREG32(SRBM_SOFT_RESET);
+
+ r = cik_sdma_load_microcode(rdev);
+ if (r)
+ return r;
+
+ /* unhalt the MEs */
+ cik_sdma_enable(rdev, true);
+
+ /* start the gfx rings and rlc compute queues */
+ r = cik_sdma_gfx_resume(rdev);
+ if (r)
+ return r;
+ r = cik_sdma_rlc_resume(rdev);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+/**
+ * cik_sdma_fini - tear down the async dma engines
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Stop the async dma engines and free the rings (CIK).
+ */
+static void cik_sdma_fini(struct radeon_device *rdev)
+{
+ /* stop the gfx rings and rlc compute queues */
+ cik_sdma_gfx_stop(rdev);
+ cik_sdma_rlc_stop(rdev);
+ /* halt the MEs */
+ cik_sdma_enable(rdev, false);
+ radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX]);
+ radeon_ring_fini(rdev, &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]);
+ /* XXX - compute dma queue tear down */
+}
+
+/**
+ * cik_copy_dma - copy pages using the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @src_offset: src GPU address
+ * @dst_offset: dst GPU address
+ * @num_gpu_pages: number of GPU pages to xfer
+ * @fence: radeon fence object
+ *
+ * Copy GPU paging using the DMA engine (CIK).
+ * Used by the radeon ttm implementation to move pages if
+ * registered as the asic copy callback.
+ */
+int cik_copy_dma(struct radeon_device *rdev,
+ uint64_t src_offset, uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence **fence)
+{
+ struct radeon_semaphore *sem = NULL;
+ int ring_index = rdev->asic->copy.dma_ring_index;
+ struct radeon_ring *ring = &rdev->ring[ring_index];
+ u32 size_in_bytes, cur_size_in_bytes;
+ int i, num_loops;
+ int r = 0;
+
+ r = radeon_semaphore_create(rdev, &sem);
+ if (r) {
+ DRM_ERROR("radeon: moving bo (%d).\n", r);
+ return r;
+ }
+
+ size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
+ num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
+ r = radeon_ring_lock(rdev, ring, num_loops * 7 + 14);
+ if (r) {
+ DRM_ERROR("radeon: moving bo (%d).\n", r);
+ radeon_semaphore_free(rdev, &sem, NULL);
+ return r;
+ }
+
+ if (radeon_fence_need_sync(*fence, ring->idx)) {
+ radeon_semaphore_sync_rings(rdev, sem, (*fence)->ring,
+ ring->idx);
+ radeon_fence_note_sync(*fence, ring->idx);
+ } else {
+ radeon_semaphore_free(rdev, &sem, NULL);
+ }
+
+ for (i = 0; i < num_loops; i++) {
+ cur_size_in_bytes = size_in_bytes;
+ if (cur_size_in_bytes > 0x1fffff)
+ cur_size_in_bytes = 0x1fffff;
+ size_in_bytes -= cur_size_in_bytes;
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0));
+ radeon_ring_write(ring, cur_size_in_bytes);
+ radeon_ring_write(ring, 0); /* src/dst endian swap */
+ radeon_ring_write(ring, src_offset & 0xffffffff);
+ radeon_ring_write(ring, upper_32_bits(src_offset) & 0xffffffff);
+ radeon_ring_write(ring, dst_offset & 0xfffffffc);
+ radeon_ring_write(ring, upper_32_bits(dst_offset) & 0xffffffff);
+ src_offset += cur_size_in_bytes;
+ dst_offset += cur_size_in_bytes;
+ }
+
+ r = radeon_fence_emit(rdev, fence, ring->idx);
+ if (r) {
+ radeon_ring_unlock_undo(rdev, ring);
+ return r;
+ }
+
+ radeon_ring_unlock_commit(rdev, ring);
+ radeon_semaphore_free(rdev, &sem, *fence);
+
+ return r;
+}
+
+/**
+ * cik_sdma_ring_test - simple async dma engine test
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_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.
+ */
+int cik_sdma_ring_test(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ unsigned i;
+ int r;
+ void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+ u32 tmp;
+
+ if (!ptr) {
+ DRM_ERROR("invalid vram scratch pointer\n");
+ return -EINVAL;
+ }
+
+ tmp = 0xCAFEDEAD;
+ writel(tmp, ptr);
+
+ r = radeon_ring_lock(rdev, ring, 4);
+ if (r) {
+ DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);
+ return r;
+ }
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_WRITE, SDMA_WRITE_SUB_OPCODE_LINEAR, 0));
+ radeon_ring_write(ring, rdev->vram_scratch.gpu_addr & 0xfffffffc);
+ radeon_ring_write(ring, upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff);
+ radeon_ring_write(ring, 1); /* number of DWs to follow */
+ radeon_ring_write(ring, 0xDEADBEEF);
+ radeon_ring_unlock_commit(rdev, ring);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = readl(ptr);
+ if (tmp == 0xDEADBEEF)
+ break;
+ DRM_UDELAY(1);
+ }
+
+ if (i < rdev->usec_timeout) {
+ DRM_INFO("ring test on %d succeeded in %d usecs\n", ring->idx, i);
+ } else {
+ DRM_ERROR("radeon: ring %d test failed (0x%08X)\n",
+ ring->idx, tmp);
+ r = -EINVAL;
+ }
+ return r;
+}
+
+/**
+ * cik_sdma_ib_test - test an IB on the DMA engine
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Test a simple IB in the DMA ring (CIK).
+ * Returns 0 on success, error on failure.
+ */
+int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ struct radeon_ib ib;
+ unsigned i;
+ int r;
+ void __iomem *ptr = (void *)rdev->vram_scratch.ptr;
+ u32 tmp = 0;
+
+ if (!ptr) {
+ DRM_ERROR("invalid vram scratch pointer\n");
+ return -EINVAL;
+ }
+
+ tmp = 0xCAFEDEAD;
+ writel(tmp, ptr);
+
+ r = radeon_ib_get(rdev, ring->idx, &ib, NULL, 256);
+ if (r) {
+ DRM_ERROR("radeon: 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] = rdev->vram_scratch.gpu_addr & 0xfffffffc;
+ ib.ptr[2] = upper_32_bits(rdev->vram_scratch.gpu_addr) & 0xffffffff;
+ ib.ptr[3] = 1;
+ ib.ptr[4] = 0xDEADBEEF;
+ ib.length_dw = 5;
+
+ r = radeon_ib_schedule(rdev, &ib, NULL);
+ if (r) {
+ radeon_ib_free(rdev, &ib);
+ DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+ return r;
+ }
+ r = radeon_fence_wait(ib.fence, false);
+ if (r) {
+ DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+ return r;
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = readl(ptr);
+ if (tmp == 0xDEADBEEF)
+ break;
+ DRM_UDELAY(1);
+ }
+ if (i < rdev->usec_timeout) {
+ DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
+ } else {
+ DRM_ERROR("radeon: ib test failed (0x%08X)\n", tmp);
+ r = -EINVAL;
+ }
+ radeon_ib_free(rdev, &ib);
+ return r;
+}
+
+
+static void cik_print_gpu_status_regs(struct radeon_device *rdev)
+{
+ dev_info(rdev->dev, " GRBM_STATUS=0x%08X\n",
+ RREG32(GRBM_STATUS));
+ dev_info(rdev->dev, " GRBM_STATUS2=0x%08X\n",
+ RREG32(GRBM_STATUS2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE0=0x%08X\n",
+ RREG32(GRBM_STATUS_SE0));
+ dev_info(rdev->dev, " GRBM_STATUS_SE1=0x%08X\n",
+ RREG32(GRBM_STATUS_SE1));
+ dev_info(rdev->dev, " GRBM_STATUS_SE2=0x%08X\n",
+ RREG32(GRBM_STATUS_SE2));
+ dev_info(rdev->dev, " GRBM_STATUS_SE3=0x%08X\n",
+ RREG32(GRBM_STATUS_SE3));
+ dev_info(rdev->dev, " SRBM_STATUS=0x%08X\n",
+ RREG32(SRBM_STATUS));
+ dev_info(rdev->dev, " SRBM_STATUS2=0x%08X\n",
+ RREG32(SRBM_STATUS2));
+ dev_info(rdev->dev, " SDMA0_STATUS_REG = 0x%08X\n",
+ RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET));
+ dev_info(rdev->dev, " SDMA1_STATUS_REG = 0x%08X\n",
+ RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET));
+ dev_info(rdev->dev, " CP_STAT = 0x%08x\n", RREG32(CP_STAT));
+ dev_info(rdev->dev, " CP_STALLED_STAT1 = 0x%08x\n",
+ RREG32(CP_STALLED_STAT1));
+ dev_info(rdev->dev, " CP_STALLED_STAT2 = 0x%08x\n",
+ RREG32(CP_STALLED_STAT2));
+ dev_info(rdev->dev, " CP_STALLED_STAT3 = 0x%08x\n",
+ RREG32(CP_STALLED_STAT3));
+ dev_info(rdev->dev, " CP_CPF_BUSY_STAT = 0x%08x\n",
+ RREG32(CP_CPF_BUSY_STAT));
+ dev_info(rdev->dev, " CP_CPF_STALLED_STAT1 = 0x%08x\n",
+ RREG32(CP_CPF_STALLED_STAT1));
+ dev_info(rdev->dev, " CP_CPF_STATUS = 0x%08x\n", RREG32(CP_CPF_STATUS));
+ dev_info(rdev->dev, " CP_CPC_BUSY_STAT = 0x%08x\n", RREG32(CP_CPC_BUSY_STAT));
+ dev_info(rdev->dev, " CP_CPC_STALLED_STAT1 = 0x%08x\n",
+ RREG32(CP_CPC_STALLED_STAT1));
+ dev_info(rdev->dev, " CP_CPC_STATUS = 0x%08x\n", RREG32(CP_CPC_STATUS));
+}
+
+/**
+ * cik_gpu_check_soft_reset - check which blocks are busy
+ *
+ * @rdev: radeon_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.
+ */
+static u32 cik_gpu_check_soft_reset(struct radeon_device *rdev)
+{
+ u32 reset_mask = 0;
+ u32 tmp;
+
+ /* GRBM_STATUS */
+ tmp = RREG32(GRBM_STATUS);
+ if (tmp & (PA_BUSY | SC_BUSY |
+ BCI_BUSY | SX_BUSY |
+ TA_BUSY | VGT_BUSY |
+ DB_BUSY | CB_BUSY |
+ GDS_BUSY | SPI_BUSY |
+ IA_BUSY | IA_BUSY_NO_DMA))
+ reset_mask |= RADEON_RESET_GFX;
+
+ if (tmp & (CP_BUSY | CP_COHERENCY_BUSY))
+ reset_mask |= RADEON_RESET_CP;
+
+ /* GRBM_STATUS2 */
+ tmp = RREG32(GRBM_STATUS2);
+ if (tmp & RLC_BUSY)
+ reset_mask |= RADEON_RESET_RLC;
+
+ /* SDMA0_STATUS_REG */
+ tmp = RREG32(SDMA0_STATUS_REG + SDMA0_REGISTER_OFFSET);
+ if (!(tmp & SDMA_IDLE))
+ reset_mask |= RADEON_RESET_DMA;
+
+ /* SDMA1_STATUS_REG */
+ tmp = RREG32(SDMA0_STATUS_REG + SDMA1_REGISTER_OFFSET);
+ if (!(tmp & SDMA_IDLE))
+ reset_mask |= RADEON_RESET_DMA1;
+
+ /* SRBM_STATUS2 */
+ tmp = RREG32(SRBM_STATUS2);
+ if (tmp & SDMA_BUSY)
+ reset_mask |= RADEON_RESET_DMA;
+
+ if (tmp & SDMA1_BUSY)
+ reset_mask |= RADEON_RESET_DMA1;
+
+ /* SRBM_STATUS */
+ tmp = RREG32(SRBM_STATUS);
+
+ if (tmp & IH_BUSY)
+ reset_mask |= RADEON_RESET_IH;
+
+ if (tmp & SEM_BUSY)
+ reset_mask |= RADEON_RESET_SEM;
+
+ if (tmp & GRBM_RQ_PENDING)
+ reset_mask |= RADEON_RESET_GRBM;
+
+ if (tmp & VMC_BUSY)
+ reset_mask |= RADEON_RESET_VMC;
+
+ if (tmp & (MCB_BUSY | MCB_NON_DISPLAY_BUSY |
+ MCC_BUSY | MCD_BUSY))
+ reset_mask |= RADEON_RESET_MC;
+
+ if (evergreen_is_display_hung(rdev))
+ reset_mask |= RADEON_RESET_DISPLAY;
+
+ /* Skip MC reset as it's mostly likely not hung, just busy */
+ if (reset_mask & RADEON_RESET_MC) {
+ DRM_DEBUG("MC busy: 0x%08X, clearing.\n", reset_mask);
+ reset_mask &= ~RADEON_RESET_MC;
+ }
+
+ return reset_mask;
+}
+
+/**
+ * cik_gpu_soft_reset - soft reset GPU
+ *
+ * @rdev: radeon_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 radeon_device *rdev, u32 reset_mask)
+{
+ struct evergreen_mc_save save;
+ u32 grbm_soft_reset = 0, srbm_soft_reset = 0;
+ u32 tmp;
+
+ if (reset_mask == 0)
+ return;
+
+ dev_info(rdev->dev, "GPU softreset: 0x%08X\n", reset_mask);
+
+ cik_print_gpu_status_regs(rdev);
+ dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
+ RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+ dev_info(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+ RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+
+ /* stop the rlc */
+ cik_rlc_stop(rdev);
+
+ /* Disable GFX parsing/prefetching */
+ WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+ /* Disable MEC parsing/prefetching */
+ WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+ if (reset_mask & RADEON_RESET_DMA) {
+ /* sdma0 */
+ tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET);
+ tmp |= SDMA_HALT;
+ WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+ }
+ if (reset_mask & RADEON_RESET_DMA1) {
+ /* sdma1 */
+ tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET);
+ tmp |= SDMA_HALT;
+ WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+ }
+
+ evergreen_mc_stop(rdev, &save);
+ if (evergreen_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+
+ if (reset_mask & (RADEON_RESET_GFX | RADEON_RESET_COMPUTE | RADEON_RESET_CP))
+ grbm_soft_reset = SOFT_RESET_CP | SOFT_RESET_GFX;
+
+ if (reset_mask & RADEON_RESET_CP) {
+ grbm_soft_reset |= SOFT_RESET_CP;
+
+ srbm_soft_reset |= SOFT_RESET_GRBM;
+ }
+
+ if (reset_mask & RADEON_RESET_DMA)
+ srbm_soft_reset |= SOFT_RESET_SDMA;
+
+ if (reset_mask & RADEON_RESET_DMA1)
+ srbm_soft_reset |= SOFT_RESET_SDMA1;
+
+ if (reset_mask & RADEON_RESET_DISPLAY)
+ srbm_soft_reset |= SOFT_RESET_DC;
+
+ if (reset_mask & RADEON_RESET_RLC)
+ grbm_soft_reset |= SOFT_RESET_RLC;
+
+ if (reset_mask & RADEON_RESET_SEM)
+ srbm_soft_reset |= SOFT_RESET_SEM;
+
+ if (reset_mask & RADEON_RESET_IH)
+ srbm_soft_reset |= SOFT_RESET_IH;
+
+ if (reset_mask & RADEON_RESET_GRBM)
+ srbm_soft_reset |= SOFT_RESET_GRBM;
+
+ if (reset_mask & RADEON_RESET_VMC)
+ srbm_soft_reset |= SOFT_RESET_VMC;
+
+ if (!(rdev->flags & RADEON_IS_IGP)) {
+ if (reset_mask & RADEON_RESET_MC)
+ srbm_soft_reset |= SOFT_RESET_MC;
+ }
+
+ if (grbm_soft_reset) {
+ tmp = RREG32(GRBM_SOFT_RESET);
+ tmp |= grbm_soft_reset;
+ dev_info(rdev->dev, "GRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(GRBM_SOFT_RESET, tmp);
+ tmp = RREG32(GRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~grbm_soft_reset;
+ WREG32(GRBM_SOFT_RESET, tmp);
+ tmp = RREG32(GRBM_SOFT_RESET);
+ }
+
+ if (srbm_soft_reset) {
+ tmp = RREG32(SRBM_SOFT_RESET);
+ tmp |= srbm_soft_reset;
+ dev_info(rdev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(SRBM_SOFT_RESET, tmp);
+ tmp = RREG32(SRBM_SOFT_RESET);
+
+ udelay(50);
+
+ tmp &= ~srbm_soft_reset;
+ WREG32(SRBM_SOFT_RESET, tmp);
+ tmp = RREG32(SRBM_SOFT_RESET);
+ }
+
+ /* Wait a little for things to settle down */
+ udelay(50);
+
+ evergreen_mc_resume(rdev, &save);
+ udelay(50);
+
+ cik_print_gpu_status_regs(rdev);
+}
+
+/**
+ * cik_asic_reset - soft reset GPU
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Look up which blocks are hung and attempt
+ * to reset them.
+ * Returns 0 for success.
+ */
+int cik_asic_reset(struct radeon_device *rdev)
+{
+ u32 reset_mask;
+
+ reset_mask = cik_gpu_check_soft_reset(rdev);
+
+ if (reset_mask)
+ r600_set_bios_scratch_engine_hung(rdev, true);
+
+ cik_gpu_soft_reset(rdev, reset_mask);
+
+ reset_mask = cik_gpu_check_soft_reset(rdev);
+
+ if (!reset_mask)
+ r600_set_bios_scratch_engine_hung(rdev, false);
+
+ return 0;
+}
+
+/**
+ * cik_gfx_is_lockup - check if the 3D engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring structure holding ring information
+ *
+ * Check if the 3D engine is locked up (CIK).
+ * Returns true if the engine is locked, false if not.
+ */
+bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ u32 reset_mask = cik_gpu_check_soft_reset(rdev);
+
+ if (!(reset_mask & (RADEON_RESET_GFX |
+ RADEON_RESET_COMPUTE |
+ RADEON_RESET_CP))) {
+ radeon_ring_lockup_update(ring);
+ return false;
+ }
+ /* force CP activities */
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
+}
+
+/**
+ * cik_sdma_is_lockup - Check if the DMA engine is locked up
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_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.
+ */
+bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ u32 reset_mask = cik_gpu_check_soft_reset(rdev);
+ u32 mask;
+
+ if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+ mask = RADEON_RESET_DMA;
+ else
+ mask = RADEON_RESET_DMA1;
+
+ if (!(reset_mask & mask)) {
+ radeon_ring_lockup_update(ring);
+ return false;
+ }
+ /* force ring activities */
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
+}
+
+/* MC */
+/**
+ * cik_mc_program - program the GPU memory controller
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Set the location of vram, gart, and AGP in the GPU's
+ * physical address space (CIK).
+ */
+static void cik_mc_program(struct radeon_device *rdev)
+{
+ struct evergreen_mc_save save;
+ u32 tmp;
+ int i, j;
+
+ /* Initialize HDP */
+ for (i = 0, j = 0; i < 32; i++, j += 0x18) {
+ WREG32((0x2c14 + j), 0x00000000);
+ WREG32((0x2c18 + j), 0x00000000);
+ WREG32((0x2c1c + j), 0x00000000);
+ WREG32((0x2c20 + j), 0x00000000);
+ WREG32((0x2c24 + j), 0x00000000);
+ }
+ WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
+
+ evergreen_mc_stop(rdev, &save);
+ if (radeon_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+ /* Lockout access through VGA aperture*/
+ WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
+ /* Update configuration */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.vram_end >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR,
+ rdev->vram_scratch.gpu_addr >> 12);
+ tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
+ tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
+ WREG32(MC_VM_FB_LOCATION, tmp);
+ /* XXX double check these! */
+ WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
+ WREG32(HDP_NONSURFACE_INFO, (2 << 7) | (1 << 30));
+ WREG32(HDP_NONSURFACE_SIZE, 0x3FFFFFFF);
+ WREG32(MC_VM_AGP_BASE, 0);
+ WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
+ WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
+ if (radeon_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
+ evergreen_mc_resume(rdev, &save);
+ /* we need to own VRAM, so turn off the VGA renderer here
+ * to stop it overwriting our objects */
+ rv515_vga_render_disable(rdev);
+}
+
+/**
+ * cik_mc_init - initialize the memory controller driver params
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Look up the amount of vram, vram width, and decide how to place
+ * vram and gart within the GPU's physical address space (CIK).
+ * Returns 0 for success.
+ */
+static int cik_mc_init(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int chansize, numchan;
+
+ /* Get VRAM informations */
+ rdev->mc.vram_is_ddr = true;
+ tmp = RREG32(MC_ARB_RAMCFG);
+ if (tmp & CHANSIZE_MASK) {
+ chansize = 64;
+ } else {
+ chansize = 32;
+ }
+ tmp = RREG32(MC_SHARED_CHMAP);
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ case 0:
+ default:
+ numchan = 1;
+ break;
+ case 1:
+ numchan = 2;
+ break;
+ case 2:
+ numchan = 4;
+ break;
+ case 3:
+ numchan = 8;
+ break;
+ case 4:
+ numchan = 3;
+ break;
+ case 5:
+ numchan = 6;
+ break;
+ case 6:
+ numchan = 10;
+ break;
+ case 7:
+ numchan = 12;
+ break;
+ case 8:
+ numchan = 16;
+ break;
+ }
+ rdev->mc.vram_width = numchan * chansize;
+ /* Could aper size report 0 ? */
+ rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0);
+ rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0);
+ /* size in MB on si */
+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024;
+ rdev->mc.visible_vram_size = rdev->mc.aper_size;
+ si_vram_gtt_location(rdev, &rdev->mc);
+ radeon_update_bandwidth_info(rdev);
+
+ return 0;
+}
+
+/*
+ * GART
+ * VMID 0 is the physical GPU addresses as used by the kernel.
+ * VMIDs 1-15 are used for userspace clients and are handled
+ * by the radeon vm/hsa code.
+ */
+/**
+ * cik_pcie_gart_tlb_flush - gart tlb flush callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Flush the TLB for the VMID 0 page table (CIK).
+ */
+void cik_pcie_gart_tlb_flush(struct radeon_device *rdev)
+{
+ /* flush hdp cache */
+ WREG32(HDP_MEM_COHERENCY_FLUSH_CNTL, 0);
+
+ /* bits 0-15 are the VM contexts0-15 */
+ WREG32(VM_INVALIDATE_REQUEST, 0x1);
+}
+
+/**
+ * cik_pcie_gart_enable - gart enable
+ *
+ * @rdev: radeon_device pointer
+ *
+ * This sets up the TLBs, programs the page tables for VMID0,
+ * sets up the hw for VMIDs 1-15 which are allocated on
+ * demand, and sets up the global locations for the LDS, GDS,
+ * and GPUVM for FSA64 clients (CIK).
+ * Returns 0 for success, errors for failure.
+ */
+static int cik_pcie_gart_enable(struct radeon_device *rdev)
+{
+ int r, i;
+
+ if (rdev->gart.robj == NULL) {
+ dev_err(rdev->dev, "No VRAM object for PCIE GART.\n");
+ return -EINVAL;
+ }
+ r = radeon_gart_table_vram_pin(rdev);
+ if (r)
+ return r;
+ radeon_gart_restore(rdev);
+ /* Setup TLB control */
+ WREG32(MC_VM_MX_L1_TLB_CNTL,
+ (0xA << 7) |
+ ENABLE_L1_TLB |
+ SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+ ENABLE_ADVANCED_DRIVER_MODEL |
+ SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE |
+ ENABLE_L2_FRAGMENT_PROCESSING |
+ ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+ ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+ EFFECTIVE_L2_QUEUE_SIZE(7) |
+ CONTEXT1_IDENTITY_ACCESS_MODE(1));
+ WREG32(VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS | INVALIDATE_L2_CACHE);
+ WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+ L2_CACHE_BIGK_FRAGMENT_SIZE(6));
+ /* setup context0 */
+ WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
+ WREG32(VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
+ (u32)(rdev->dummy_page.addr >> 12));
+ WREG32(VM_CONTEXT0_CNTL2, 0);
+ WREG32(VM_CONTEXT0_CNTL, (ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
+ RANGE_PROTECTION_FAULT_ENABLE_DEFAULT));
+
+ WREG32(0x15D4, 0);
+ WREG32(0x15D8, 0);
+ WREG32(0x15DC, 0);
+
+ /* empty context1-15 */
+ /* FIXME start with 4G, once using 2 level pt switch to full
+ * vm size space
+ */
+ /* set vm size, must be a multiple of 4 */
+ WREG32(VM_CONTEXT1_PAGE_TABLE_START_ADDR, 0);
+ WREG32(VM_CONTEXT1_PAGE_TABLE_END_ADDR, rdev->vm_manager.max_pfn);
+ for (i = 1; i < 16; i++) {
+ if (i < 8)
+ WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (i << 2),
+ rdev->gart.table_addr >> 12);
+ else
+ WREG32(VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((i - 8) << 2),
+ rdev->gart.table_addr >> 12);
+ }
+
+ /* enable context1-15 */
+ WREG32(VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR,
+ (u32)(rdev->dummy_page.addr >> 12));
+ WREG32(VM_CONTEXT1_CNTL2, 4);
+ WREG32(VM_CONTEXT1_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(1) |
+ RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+ RANGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+ DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+ DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT |
+ PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT |
+ PDE0_PROTECTION_FAULT_ENABLE_DEFAULT |
+ VALID_PROTECTION_FAULT_ENABLE_INTERRUPT |
+ VALID_PROTECTION_FAULT_ENABLE_DEFAULT |
+ READ_PROTECTION_FAULT_ENABLE_INTERRUPT |
+ READ_PROTECTION_FAULT_ENABLE_DEFAULT |
+ WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
+ WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
+
+ /* TC cache setup ??? */
+ WREG32(TC_CFG_L1_LOAD_POLICY0, 0);
+ WREG32(TC_CFG_L1_LOAD_POLICY1, 0);
+ WREG32(TC_CFG_L1_STORE_POLICY, 0);
+
+ WREG32(TC_CFG_L2_LOAD_POLICY0, 0);
+ WREG32(TC_CFG_L2_LOAD_POLICY1, 0);
+ WREG32(TC_CFG_L2_STORE_POLICY0, 0);
+ WREG32(TC_CFG_L2_STORE_POLICY1, 0);
+ WREG32(TC_CFG_L2_ATOMIC_POLICY, 0);
+
+ WREG32(TC_CFG_L1_VOLATILE, 0);
+ WREG32(TC_CFG_L2_VOLATILE, 0);
+
+ if (rdev->family == CHIP_KAVERI) {
+ u32 tmp = RREG32(CHUB_CONTROL);
+ tmp &= ~BYPASS_VM;
+ WREG32(CHUB_CONTROL, tmp);
+ }
+
+ /* XXX SH_MEM regs */
+ /* where to put LDS, scratch, GPUVM in FSA64 space */
+ for (i = 0; i < 16; i++) {
+ cik_srbm_select(rdev, 0, 0, 0, i);
+ /* CP and shaders */
+ WREG32(SH_MEM_CONFIG, 0);
+ WREG32(SH_MEM_APE1_BASE, 1);
+ WREG32(SH_MEM_APE1_LIMIT, 0);
+ WREG32(SH_MEM_BASES, 0);
+ /* SDMA GFX */
+ WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA0_REGISTER_OFFSET, 0);
+ WREG32(SDMA0_GFX_APE1_CNTL + SDMA0_REGISTER_OFFSET, 0);
+ WREG32(SDMA0_GFX_VIRTUAL_ADDR + SDMA1_REGISTER_OFFSET, 0);
+ WREG32(SDMA0_GFX_APE1_CNTL + SDMA1_REGISTER_OFFSET, 0);
+ /* XXX SDMA RLC - todo */
+ }
+ cik_srbm_select(rdev, 0, 0, 0, 0);
+
+ cik_pcie_gart_tlb_flush(rdev);
+ DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
+ (unsigned)(rdev->mc.gtt_size >> 20),
+ (unsigned long long)rdev->gart.table_addr);
+ rdev->gart.ready = true;
+ return 0;
+}
+
+/**
+ * cik_pcie_gart_disable - gart disable
+ *
+ * @rdev: radeon_device pointer
+ *
+ * This disables all VM page table (CIK).
+ */
+static void cik_pcie_gart_disable(struct radeon_device *rdev)
+{
+ /* Disable all tables */
+ WREG32(VM_CONTEXT0_CNTL, 0);
+ WREG32(VM_CONTEXT1_CNTL, 0);
+ /* Setup TLB control */
+ WREG32(MC_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+ SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU);
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL,
+ ENABLE_L2_FRAGMENT_PROCESSING |
+ ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+ ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE |
+ EFFECTIVE_L2_QUEUE_SIZE(7) |
+ CONTEXT1_IDENTITY_ACCESS_MODE(1));
+ WREG32(VM_L2_CNTL2, 0);
+ WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY |
+ L2_CACHE_BIGK_FRAGMENT_SIZE(6));
+ radeon_gart_table_vram_unpin(rdev);
+}
+
+/**
+ * cik_pcie_gart_fini - vm fini callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tears down the driver GART/VM setup (CIK).
+ */
+static void cik_pcie_gart_fini(struct radeon_device *rdev)
+{
+ cik_pcie_gart_disable(rdev);
+ radeon_gart_table_vram_free(rdev);
+ radeon_gart_fini(rdev);
+}
+
+/* vm parser */
+/**
+ * cik_ib_parse - vm ib_parse callback
+ *
+ * @rdev: radeon_device pointer
+ * @ib: indirect buffer pointer
+ *
+ * CIK uses hw IB checking so this is a nop (CIK).
+ */
+int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+ return 0;
+}
+
+/*
+ * vm
+ * VMID 0 is the physical GPU addresses as used by the kernel.
+ * VMIDs 1-15 are used for userspace clients and are handled
+ * by the radeon vm/hsa code.
+ */
+/**
+ * cik_vm_init - cik vm init callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Inits cik specific vm parameters (number of VMs, base of vram for
+ * VMIDs 1-15) (CIK).
+ * Returns 0 for success.
+ */
+int cik_vm_init(struct radeon_device *rdev)
+{
+ /* number of VMs */
+ rdev->vm_manager.nvm = 16;
+ /* base offset of vram pages */
+ if (rdev->flags & RADEON_IS_IGP) {
+ u64 tmp = RREG32(MC_VM_FB_OFFSET);
+ tmp <<= 22;
+ rdev->vm_manager.vram_base_offset = tmp;
+ } else
+ rdev->vm_manager.vram_base_offset = 0;
+
+ return 0;
+}
+
+/**
+ * cik_vm_fini - cik vm fini callback
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down any asic specific VM setup (CIK).
+ */
+void cik_vm_fini(struct radeon_device *rdev)
+{
+}
+
+/**
+ * cik_vm_flush - cik vm flush using the CP
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using the CP (CIK).
+ */
+void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+{
+ struct radeon_ring *ring = &rdev->ring[ridx];
+
+ if (vm == NULL)
+ return;
+
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ if (vm->id < 8) {
+ radeon_ring_write(ring,
+ (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+ } else {
+ radeon_ring_write(ring,
+ (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+ }
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+
+ /* update SH_MEM_* regs */
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, VMID(vm->id));
+
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 6));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, SH_MEM_BASES >> 2);
+ radeon_ring_write(ring, 0);
+
+ radeon_ring_write(ring, 0); /* SH_MEM_BASES */
+ radeon_ring_write(ring, 0); /* SH_MEM_CONFIG */
+ radeon_ring_write(ring, 1); /* SH_MEM_APE1_BASE */
+ radeon_ring_write(ring, 0); /* SH_MEM_APE1_LIMIT */
+
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, VMID(0));
+
+ /* HDP flush */
+ /* We should be using the WAIT_REG_MEM packet here like in
+ * cik_fence_ring_emit(), but it causes the CP to hang in this
+ * context...
+ */
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, 0);
+
+ /* bits 0-15 are the VM contexts0-15 */
+ radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(0)));
+ radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+ radeon_ring_write(ring, 0);
+ radeon_ring_write(ring, 1 << vm->id);
+
+ /* compute doesn't have PFP */
+ if (ridx == RADEON_RING_TYPE_GFX_INDEX) {
+ /* sync PFP to ME, otherwise we might get invalid PFP reads */
+ radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
+ radeon_ring_write(ring, 0x0);
+ }
+}
+
+/**
+ * cik_vm_set_page - update the page tables using sDMA
+ *
+ * @rdev: radeon_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: access flags
+ *
+ * Update the page tables using CP or sDMA (CIK).
+ */
+void cik_vm_set_page(struct radeon_device *rdev,
+ struct radeon_ib *ib,
+ uint64_t pe,
+ uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags)
+{
+ uint32_t r600_flags = cayman_vm_page_flags(rdev, flags);
+ uint64_t value;
+ unsigned ndw;
+
+ if (rdev->asic->vm.pt_ring_index == RADEON_RING_TYPE_GFX_INDEX) {
+ /* CP */
+ while (count) {
+ ndw = 2 + count * 2;
+ if (ndw > 0x3FFE)
+ ndw = 0x3FFE;
+
+ ib->ptr[ib->length_dw++] = PACKET3(PACKET3_WRITE_DATA, ndw);
+ ib->ptr[ib->length_dw++] = (WRITE_DATA_ENGINE_SEL(0) |
+ WRITE_DATA_DST_SEL(1));
+ ib->ptr[ib->length_dw++] = pe;
+ ib->ptr[ib->length_dw++] = upper_32_bits(pe);
+ for (; ndw > 2; ndw -= 2, --count, pe += 8) {
+ if (flags & RADEON_VM_PAGE_SYSTEM) {
+ value = radeon_vm_map_gart(rdev, addr);
+ value &= 0xFFFFFFFFFFFFF000ULL;
+ } else if (flags & RADEON_VM_PAGE_VALID) {
+ value = addr;
+ } else {
+ value = 0;
+ }
+ addr += incr;
+ value |= r600_flags;
+ ib->ptr[ib->length_dw++] = value;
+ ib->ptr[ib->length_dw++] = upper_32_bits(value);
+ }
+ }
+ } else {
+ /* DMA */
+ if (flags & RADEON_VM_PAGE_SYSTEM) {
+ 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 & RADEON_VM_PAGE_SYSTEM) {
+ value = radeon_vm_map_gart(rdev, addr);
+ value &= 0xFFFFFFFFFFFFF000ULL;
+ } else if (flags & RADEON_VM_PAGE_VALID) {
+ value = addr;
+ } else {
+ value = 0;
+ }
+ addr += incr;
+ value |= r600_flags;
+ ib->ptr[ib->length_dw++] = value;
+ ib->ptr[ib->length_dw++] = upper_32_bits(value);
+ }
+ }
+ } else {
+ while (count) {
+ ndw = count;
+ if (ndw > 0x7FFFF)
+ ndw = 0x7FFFF;
+
+ if (flags & RADEON_VM_PAGE_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++] = r600_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;
+ }
+ }
+ while (ib->length_dw & 0x7)
+ ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0);
+ }
+}
+
+/**
+ * cik_dma_vm_flush - cik vm flush using sDMA
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Update the page table base and flush the VM TLB
+ * using sDMA (CIK).
+ */
+void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
+{
+ struct radeon_ring *ring = &rdev->ring[ridx];
+ u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+ SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+ u32 ref_and_mask;
+
+ if (vm == NULL)
+ return;
+
+ if (ridx == R600_RING_TYPE_DMA_INDEX)
+ ref_and_mask = SDMA0;
+ else
+ ref_and_mask = SDMA1;
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ if (vm->id < 8) {
+ radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm->id << 2)) >> 2);
+ } else {
+ radeon_ring_write(ring, (VM_CONTEXT8_PAGE_TABLE_BASE_ADDR + ((vm->id - 8) << 2)) >> 2);
+ }
+ radeon_ring_write(ring, vm->pd_gpu_addr >> 12);
+
+ /* update SH_MEM_* regs */
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+ radeon_ring_write(ring, VMID(vm->id));
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, SH_MEM_BASES >> 2);
+ radeon_ring_write(ring, 0);
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, SH_MEM_CONFIG >> 2);
+ radeon_ring_write(ring, 0);
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, SH_MEM_APE1_BASE >> 2);
+ radeon_ring_write(ring, 1);
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, SH_MEM_APE1_LIMIT >> 2);
+ radeon_ring_write(ring, 0);
+
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, SRBM_GFX_CNTL >> 2);
+ radeon_ring_write(ring, VMID(0));
+
+ /* flush HDP */
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+ radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+ radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+ radeon_ring_write(ring, ref_and_mask); /* REFERENCE */
+ radeon_ring_write(ring, ref_and_mask); /* MASK */
+ radeon_ring_write(ring, (4 << 16) | 10); /* RETRY_COUNT, POLL_INTERVAL */
+
+ /* flush TLB */
+ radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
+ radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+ radeon_ring_write(ring, 1 << vm->id);
+}
+
+/*
+ * RLC
+ * The RLC is a multi-purpose microengine that handles a
+ * variety of functions, the most important of which is
+ * the interrupt controller.
+ */
+/**
+ * cik_rlc_stop - stop the RLC ME
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Halt the RLC ME (MicroEngine) (CIK).
+ */
+static void cik_rlc_stop(struct radeon_device *rdev)
+{
+ int i, j, k;
+ u32 mask, tmp;
+
+ tmp = RREG32(CP_INT_CNTL_RING0);
+ tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+ WREG32(CP_INT_CNTL_RING0, tmp);
+
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+
+ tmp = RREG32(RLC_CGCG_CGLS_CTRL) & 0xfffffffc;
+ WREG32(RLC_CGCG_CGLS_CTRL, tmp);
+
+ WREG32(RLC_CNTL, 0);
+
+ for (i = 0; i < rdev->config.cik.max_shader_engines; i++) {
+ for (j = 0; j < rdev->config.cik.max_sh_per_se; j++) {
+ cik_select_se_sh(rdev, i, j);
+ for (k = 0; k < rdev->usec_timeout; k++) {
+ if (RREG32(RLC_SERDES_CU_MASTER_BUSY) == 0)
+ break;
+ udelay(1);
+ }
+ }
+ }
+ cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+
+ mask = SE_MASTER_BUSY_MASK | GC_MASTER_BUSY | TC0_MASTER_BUSY | TC1_MASTER_BUSY;
+ for (k = 0; k < rdev->usec_timeout; k++) {
+ if ((RREG32(RLC_SERDES_NONCU_MASTER_BUSY) & mask) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+/**
+ * cik_rlc_start - start the RLC ME
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Unhalt the RLC ME (MicroEngine) (CIK).
+ */
+static void cik_rlc_start(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ WREG32(RLC_CNTL, RLC_ENABLE);
+
+ tmp = RREG32(CP_INT_CNTL_RING0);
+ tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+ WREG32(CP_INT_CNTL_RING0, tmp);
+
+ udelay(50);
+}
+
+/**
+ * cik_rlc_resume - setup the RLC hw
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Initialize the RLC registers, load the ucode,
+ * and start the RLC (CIK).
+ * Returns 0 for success, -EINVAL if the ucode is not available.
+ */
+static int cik_rlc_resume(struct radeon_device *rdev)
+{
+ u32 i, size;
+ u32 clear_state_info[3];
+ const __be32 *fw_data;
+
+ if (!rdev->rlc_fw)
+ return -EINVAL;
+
+ switch (rdev->family) {
+ case CHIP_BONAIRE:
+ default:
+ size = BONAIRE_RLC_UCODE_SIZE;
+ break;
+ case CHIP_KAVERI:
+ size = KV_RLC_UCODE_SIZE;
+ break;
+ case CHIP_KABINI:
+ size = KB_RLC_UCODE_SIZE;
+ break;
+ }
+
+ cik_rlc_stop(rdev);
+
+ WREG32(GRBM_SOFT_RESET, SOFT_RESET_RLC);
+ RREG32(GRBM_SOFT_RESET);
+ udelay(50);
+ WREG32(GRBM_SOFT_RESET, 0);
+ RREG32(GRBM_SOFT_RESET);
+ udelay(50);
+
+ WREG32(RLC_LB_CNTR_INIT, 0);
+ WREG32(RLC_LB_CNTR_MAX, 0x00008000);
+
+ cik_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+ WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
+ WREG32(RLC_LB_PARAMS, 0x00600408);
+ WREG32(RLC_LB_CNTL, 0x80000004);
+
+ WREG32(RLC_MC_CNTL, 0);
+ WREG32(RLC_UCODE_CNTL, 0);
+
+ fw_data = (const __be32 *)rdev->rlc_fw->data;
+ WREG32(RLC_GPM_UCODE_ADDR, 0);
+ for (i = 0; i < size; i++)
+ WREG32(RLC_GPM_UCODE_DATA, be32_to_cpup(fw_data++));
+ WREG32(RLC_GPM_UCODE_ADDR, 0);
+
+ /* XXX */
+ clear_state_info[0] = 0;//upper_32_bits(rdev->rlc.save_restore_gpu_addr);
+ clear_state_info[1] = 0;//rdev->rlc.save_restore_gpu_addr;
+ clear_state_info[2] = 0;//cik_default_size;
+ WREG32(RLC_GPM_SCRATCH_ADDR, 0x3d);
+ for (i = 0; i < 3; i++)
+ WREG32(RLC_GPM_SCRATCH_DATA, clear_state_info[i]);
+ WREG32(RLC_DRIVER_DMA_STATUS, 0);
+
+ cik_rlc_start(rdev);
+
+ return 0;
+}
+
+/*
+ * 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.
+ */
+
+/**
+ * cik_enable_interrupts - Enable the interrupt ring buffer
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable the interrupt ring buffer (CIK).
+ */
+static void cik_enable_interrupts(struct radeon_device *rdev)
+{
+ u32 ih_cntl = RREG32(IH_CNTL);
+ u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+
+ ih_cntl |= ENABLE_INTR;
+ ih_rb_cntl |= IH_RB_ENABLE;
+ WREG32(IH_CNTL, ih_cntl);
+ WREG32(IH_RB_CNTL, ih_rb_cntl);
+ rdev->ih.enabled = true;
+}
+
+/**
+ * cik_disable_interrupts - Disable the interrupt ring buffer
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable the interrupt ring buffer (CIK).
+ */
+static void cik_disable_interrupts(struct radeon_device *rdev)
+{
+ u32 ih_rb_cntl = RREG32(IH_RB_CNTL);
+ u32 ih_cntl = RREG32(IH_CNTL);
+
+ ih_rb_cntl &= ~IH_RB_ENABLE;
+ ih_cntl &= ~ENABLE_INTR;
+ WREG32(IH_RB_CNTL, ih_rb_cntl);
+ WREG32(IH_CNTL, ih_cntl);
+ /* set rptr, wptr to 0 */
+ WREG32(IH_RB_RPTR, 0);
+ WREG32(IH_RB_WPTR, 0);
+ rdev->ih.enabled = false;
+ rdev->ih.rptr = 0;
+}
+
+/**
+ * cik_disable_interrupt_state - Disable all interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Clear all interrupt enable bits used by the driver (CIK).
+ */
+static void cik_disable_interrupt_state(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ /* gfx ring */
+ WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+ /* sdma */
+ tmp = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
+ WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+ tmp = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+ WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+ /* compute queues */
+ WREG32(CP_ME1_PIPE0_INT_CNTL, 0);
+ WREG32(CP_ME1_PIPE1_INT_CNTL, 0);
+ WREG32(CP_ME1_PIPE2_INT_CNTL, 0);
+ WREG32(CP_ME1_PIPE3_INT_CNTL, 0);
+ WREG32(CP_ME2_PIPE0_INT_CNTL, 0);
+ WREG32(CP_ME2_PIPE1_INT_CNTL, 0);
+ WREG32(CP_ME2_PIPE2_INT_CNTL, 0);
+ WREG32(CP_ME2_PIPE3_INT_CNTL, 0);
+ /* grbm */
+ WREG32(GRBM_INT_CNTL, 0);
+ /* vline/vblank, etc. */
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
+ if (rdev->num_crtc >= 4) {
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
+ }
+ if (rdev->num_crtc >= 6) {
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
+ }
+
+ /* dac hotplug */
+ WREG32(DAC_AUTODETECT_INT_CONTROL, 0);
+
+ /* digital hotplug */
+ tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD1_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD2_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD2_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD3_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD3_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD4_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD4_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD5_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD5_INT_CONTROL, tmp);
+ tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
+ WREG32(DC_HPD6_INT_CONTROL, tmp);
+
+}
+
+/**
+ * cik_irq_init - init and enable the interrupt ring
+ *
+ * @rdev: radeon_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_irq_init(struct radeon_device *rdev)
+{
+ int ret = 0;
+ int rb_bufsz;
+ u32 interrupt_cntl, ih_cntl, ih_rb_cntl;
+
+ /* allocate ring */
+ ret = r600_ih_ring_alloc(rdev);
+ if (ret)
+ return ret;
+
+ /* disable irqs */
+ cik_disable_interrupts(rdev);
+
+ /* init rlc */
+ ret = cik_rlc_resume(rdev);
+ if (ret) {
+ r600_ih_ring_fini(rdev);
+ return ret;
+ }
+
+ /* setup interrupt control */
+ /* XXX this should actually be a bus address, not an MC address. same on older asics */
+ WREG32(INTERRUPT_CNTL2, rdev->ih.gpu_addr >> 8);
+ interrupt_cntl = RREG32(INTERRUPT_CNTL);
+ /* IH_DUMMY_RD_OVERRIDE=0 - dummy read disabled with msi, enabled without msi
+ * IH_DUMMY_RD_OVERRIDE=1 - dummy read controlled by IH_DUMMY_RD_EN
+ */
+ interrupt_cntl &= ~IH_DUMMY_RD_OVERRIDE;
+ /* IH_REQ_NONSNOOP_EN=1 if ring is in non-cacheable memory, e.g., vram */
+ interrupt_cntl &= ~IH_REQ_NONSNOOP_EN;
+ WREG32(INTERRUPT_CNTL, interrupt_cntl);
+
+ WREG32(IH_RB_BASE, rdev->ih.gpu_addr >> 8);
+ rb_bufsz = drm_order(rdev->ih.ring_size / 4);
+
+ ih_rb_cntl = (IH_WPTR_OVERFLOW_ENABLE |
+ IH_WPTR_OVERFLOW_CLEAR |
+ (rb_bufsz << 1));
+
+ if (rdev->wb.enabled)
+ ih_rb_cntl |= IH_WPTR_WRITEBACK_ENABLE;
+
+ /* set the writeback address whether it's enabled or not */
+ WREG32(IH_RB_WPTR_ADDR_LO, (rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFFFFFFFC);
+ WREG32(IH_RB_WPTR_ADDR_HI, upper_32_bits(rdev->wb.gpu_addr + R600_WB_IH_WPTR_OFFSET) & 0xFF);
+
+ WREG32(IH_RB_CNTL, ih_rb_cntl);
+
+ /* set rptr, wptr to 0 */
+ WREG32(IH_RB_RPTR, 0);
+ WREG32(IH_RB_WPTR, 0);
+
+ /* Default settings for IH_CNTL (disabled at first) */
+ ih_cntl = MC_WRREQ_CREDIT(0x10) | MC_WR_CLEAN_CNT(0x10) | MC_VMID(0);
+ /* RPTR_REARM only works if msi's are enabled */
+ if (rdev->msi_enabled)
+ ih_cntl |= RPTR_REARM;
+ WREG32(IH_CNTL, ih_cntl);
+
+ /* force the active interrupt state to all disabled */
+ cik_disable_interrupt_state(rdev);
+
+ pci_set_master(rdev->pdev);
+
+ /* enable irqs */
+ cik_enable_interrupts(rdev);
+
+ return ret;
+}
+
+/**
+ * cik_irq_set - enable/disable interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Enable interrupt sources on the GPU (vblanks, hpd,
+ * etc.) (CIK).
+ * Returns 0 for success, errors for failure.
+ */
+int cik_irq_set(struct radeon_device *rdev)
+{
+ u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE |
+ PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+ u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3;
+ u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3;
+ u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
+ u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
+ u32 grbm_int_cntl = 0;
+ u32 dma_cntl, dma_cntl1;
+
+ if (!rdev->irq.installed) {
+ WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
+ return -EINVAL;
+ }
+ /* don't enable anything if the ih is disabled */
+ if (!rdev->ih.enabled) {
+ cik_disable_interrupts(rdev);
+ /* force the active interrupt state to all disabled */
+ cik_disable_interrupt_state(rdev);
+ return 0;
+ }
+
+ hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+
+ dma_cntl = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
+ dma_cntl1 = RREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+
+ cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m1p1 = RREG32(CP_ME1_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m1p2 = RREG32(CP_ME1_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m1p3 = RREG32(CP_ME1_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m2p0 = RREG32(CP_ME2_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m2p1 = RREG32(CP_ME2_PIPE1_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m2p2 = RREG32(CP_ME2_PIPE2_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+ cp_m2p3 = RREG32(CP_ME2_PIPE3_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
+
+ /* enable CP interrupts on all rings */
+ if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
+ DRM_DEBUG("cik_irq_set: sw int gfx\n");
+ cp_int_cntl |= TIME_STAMP_INT_ENABLE;
+ }
+ if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP1_INDEX])) {
+ struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+ DRM_DEBUG("si_irq_set: sw int cp1\n");
+ if (ring->me == 1) {
+ switch (ring->pipe) {
+ case 0:
+ cp_m1p0 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 1:
+ cp_m1p1 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 2:
+ cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 3:
+ cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ default:
+ DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
+ break;
+ }
+ } else if (ring->me == 2) {
+ switch (ring->pipe) {
+ case 0:
+ cp_m2p0 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 1:
+ cp_m2p1 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 2:
+ cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 3:
+ cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ default:
+ DRM_DEBUG("si_irq_set: sw int cp1 invalid pipe %d\n", ring->pipe);
+ break;
+ }
+ } else {
+ DRM_DEBUG("si_irq_set: sw int cp1 invalid me %d\n", ring->me);
+ }
+ }
+ if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_CP2_INDEX])) {
+ struct radeon_ring *ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+ DRM_DEBUG("si_irq_set: sw int cp2\n");
+ if (ring->me == 1) {
+ switch (ring->pipe) {
+ case 0:
+ cp_m1p0 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 1:
+ cp_m1p1 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 2:
+ cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 3:
+ cp_m1p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ default:
+ DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
+ break;
+ }
+ } else if (ring->me == 2) {
+ switch (ring->pipe) {
+ case 0:
+ cp_m2p0 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 1:
+ cp_m2p1 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 2:
+ cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ case 3:
+ cp_m2p2 |= TIME_STAMP_INT_ENABLE;
+ break;
+ default:
+ DRM_DEBUG("si_irq_set: sw int cp2 invalid pipe %d\n", ring->pipe);
+ break;
+ }
+ } else {
+ DRM_DEBUG("si_irq_set: sw int cp2 invalid me %d\n", ring->me);
+ }
+ }
+
+ if (atomic_read(&rdev->irq.ring_int[R600_RING_TYPE_DMA_INDEX])) {
+ DRM_DEBUG("cik_irq_set: sw int dma\n");
+ dma_cntl |= TRAP_ENABLE;
+ }
+
+ if (atomic_read(&rdev->irq.ring_int[CAYMAN_RING_TYPE_DMA1_INDEX])) {
+ DRM_DEBUG("cik_irq_set: sw int dma1\n");
+ dma_cntl1 |= TRAP_ENABLE;
+ }
+
+ if (rdev->irq.crtc_vblank_int[0] ||
+ atomic_read(&rdev->irq.pflip[0])) {
+ DRM_DEBUG("cik_irq_set: vblank 0\n");
+ crtc1 |= VBLANK_INTERRUPT_MASK;
+ }
+ if (rdev->irq.crtc_vblank_int[1] ||
+ atomic_read(&rdev->irq.pflip[1])) {
+ DRM_DEBUG("cik_irq_set: vblank 1\n");
+ crtc2 |= VBLANK_INTERRUPT_MASK;
+ }
+ if (rdev->irq.crtc_vblank_int[2] ||
+ atomic_read(&rdev->irq.pflip[2])) {
+ DRM_DEBUG("cik_irq_set: vblank 2\n");
+ crtc3 |= VBLANK_INTERRUPT_MASK;
+ }
+ if (rdev->irq.crtc_vblank_int[3] ||
+ atomic_read(&rdev->irq.pflip[3])) {
+ DRM_DEBUG("cik_irq_set: vblank 3\n");
+ crtc4 |= VBLANK_INTERRUPT_MASK;
+ }
+ if (rdev->irq.crtc_vblank_int[4] ||
+ atomic_read(&rdev->irq.pflip[4])) {
+ DRM_DEBUG("cik_irq_set: vblank 4\n");
+ crtc5 |= VBLANK_INTERRUPT_MASK;
+ }
+ if (rdev->irq.crtc_vblank_int[5] ||
+ atomic_read(&rdev->irq.pflip[5])) {
+ DRM_DEBUG("cik_irq_set: vblank 5\n");
+ crtc6 |= VBLANK_INTERRUPT_MASK;
+ }
+ if (rdev->irq.hpd[0]) {
+ DRM_DEBUG("cik_irq_set: hpd 1\n");
+ hpd1 |= DC_HPDx_INT_EN;
+ }
+ if (rdev->irq.hpd[1]) {
+ DRM_DEBUG("cik_irq_set: hpd 2\n");
+ hpd2 |= DC_HPDx_INT_EN;
+ }
+ if (rdev->irq.hpd[2]) {
+ DRM_DEBUG("cik_irq_set: hpd 3\n");
+ hpd3 |= DC_HPDx_INT_EN;
+ }
+ if (rdev->irq.hpd[3]) {
+ DRM_DEBUG("cik_irq_set: hpd 4\n");
+ hpd4 |= DC_HPDx_INT_EN;
+ }
+ if (rdev->irq.hpd[4]) {
+ DRM_DEBUG("cik_irq_set: hpd 5\n");
+ hpd5 |= DC_HPDx_INT_EN;
+ }
+ if (rdev->irq.hpd[5]) {
+ DRM_DEBUG("cik_irq_set: hpd 6\n");
+ hpd6 |= DC_HPDx_INT_EN;
+ }
+
+ WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
+
+ WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
+ WREG32(SDMA0_CNTL + SDMA1_REGISTER_OFFSET, dma_cntl1);
+
+ WREG32(CP_ME1_PIPE0_INT_CNTL, cp_m1p0);
+ WREG32(CP_ME1_PIPE1_INT_CNTL, cp_m1p1);
+ WREG32(CP_ME1_PIPE2_INT_CNTL, cp_m1p2);
+ WREG32(CP_ME1_PIPE3_INT_CNTL, cp_m1p3);
+ WREG32(CP_ME2_PIPE0_INT_CNTL, cp_m2p0);
+ WREG32(CP_ME2_PIPE1_INT_CNTL, cp_m2p1);
+ WREG32(CP_ME2_PIPE2_INT_CNTL, cp_m2p2);
+ WREG32(CP_ME2_PIPE3_INT_CNTL, cp_m2p3);
+
+ WREG32(GRBM_INT_CNTL, grbm_int_cntl);
+
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
+ if (rdev->num_crtc >= 4) {
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3);
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4);
+ }
+ if (rdev->num_crtc >= 6) {
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5);
+ WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6);
+ }
+
+ WREG32(DC_HPD1_INT_CONTROL, hpd1);
+ WREG32(DC_HPD2_INT_CONTROL, hpd2);
+ WREG32(DC_HPD3_INT_CONTROL, hpd3);
+ WREG32(DC_HPD4_INT_CONTROL, hpd4);
+ WREG32(DC_HPD5_INT_CONTROL, hpd5);
+ WREG32(DC_HPD6_INT_CONTROL, hpd6);
+
+ return 0;
+}
+
+/**
+ * cik_irq_ack - ack interrupt sources
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Ack interrupt sources on the GPU (vblanks, hpd,
+ * etc.) (CIK). Certain interrupts sources are sw
+ * generated and do not require an explicit ack.
+ */
+static inline void cik_irq_ack(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ rdev->irq.stat_regs.cik.disp_int = RREG32(DISP_INTERRUPT_STATUS);
+ rdev->irq.stat_regs.cik.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
+ rdev->irq.stat_regs.cik.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2);
+ rdev->irq.stat_regs.cik.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3);
+ rdev->irq.stat_regs.cik.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4);
+ rdev->irq.stat_regs.cik.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5);
+ rdev->irq.stat_regs.cik.disp_int_cont6 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE6);
+
+ if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT)
+ WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT)
+ WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT)
+ WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT)
+ WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK);
+
+ if (rdev->num_crtc >= 4) {
+ if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT)
+ WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT)
+ WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT)
+ WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT)
+ WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK);
+ }
+
+ if (rdev->num_crtc >= 6) {
+ if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT)
+ WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT)
+ WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT)
+ WREG32(LB_VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK);
+ if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT)
+ WREG32(LB_VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK);
+ }
+
+ if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
+ tmp = RREG32(DC_HPD1_INT_CONTROL);
+ tmp |= DC_HPDx_INT_ACK;
+ WREG32(DC_HPD1_INT_CONTROL, tmp);
+ }
+ if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
+ tmp = RREG32(DC_HPD2_INT_CONTROL);
+ tmp |= DC_HPDx_INT_ACK;
+ WREG32(DC_HPD2_INT_CONTROL, tmp);
+ }
+ if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+ tmp = RREG32(DC_HPD3_INT_CONTROL);
+ tmp |= DC_HPDx_INT_ACK;
+ WREG32(DC_HPD3_INT_CONTROL, tmp);
+ }
+ if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+ tmp = RREG32(DC_HPD4_INT_CONTROL);
+ tmp |= DC_HPDx_INT_ACK;
+ WREG32(DC_HPD4_INT_CONTROL, tmp);
+ }
+ if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+ tmp = RREG32(DC_HPD5_INT_CONTROL);
+ tmp |= DC_HPDx_INT_ACK;
+ WREG32(DC_HPD5_INT_CONTROL, tmp);
+ }
+ if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+ tmp = RREG32(DC_HPD5_INT_CONTROL);
+ tmp |= DC_HPDx_INT_ACK;
+ WREG32(DC_HPD6_INT_CONTROL, tmp);
+ }
+}
+
+/**
+ * cik_irq_disable - disable interrupts
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts on the hw (CIK).
+ */
+static void cik_irq_disable(struct radeon_device *rdev)
+{
+ cik_disable_interrupts(rdev);
+ /* Wait and acknowledge irq */
+ mdelay(1);
+ cik_irq_ack(rdev);
+ cik_disable_interrupt_state(rdev);
+}
+
+/**
+ * cik_irq_disable - disable interrupts for suspend
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts and stop the RLC (CIK).
+ * Used for suspend.
+ */
+static void cik_irq_suspend(struct radeon_device *rdev)
+{
+ cik_irq_disable(rdev);
+ cik_rlc_stop(rdev);
+}
+
+/**
+ * cik_irq_fini - tear down interrupt support
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Disable interrupts on the hw and free the IH ring
+ * buffer (CIK).
+ * Used for driver unload.
+ */
+static void cik_irq_fini(struct radeon_device *rdev)
+{
+ cik_irq_suspend(rdev);
+ r600_ih_ring_fini(rdev);
+}
+
+/**
+ * cik_get_ih_wptr - get the IH ring buffer wptr
+ *
+ * @rdev: radeon_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 inline u32 cik_get_ih_wptr(struct radeon_device *rdev)
+{
+ u32 wptr, tmp;
+
+ if (rdev->wb.enabled)
+ wptr = le32_to_cpu(rdev->wb.wb[R600_WB_IH_WPTR_OFFSET/4]);
+ else
+ wptr = RREG32(IH_RB_WPTR);
+
+ if (wptr & RB_OVERFLOW) {
+ /* 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(rdev->dev, "IH ring buffer overflow (0x%08X, %d, %d)\n",
+ wptr, rdev->ih.rptr, (wptr + 16) + rdev->ih.ptr_mask);
+ rdev->ih.rptr = (wptr + 16) & rdev->ih.ptr_mask;
+ tmp = RREG32(IH_RB_CNTL);
+ tmp |= IH_WPTR_OVERFLOW_CLEAR;
+ WREG32(IH_RB_CNTL, tmp);
+ }
+ return (wptr & rdev->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_irq_process - interrupt handler
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Interrupt hander (CIK). Walk the IH ring,
+ * ack interrupts and schedule work to handle
+ * interrupt events.
+ * Returns irq process return code.
+ */
+int cik_irq_process(struct radeon_device *rdev)
+{
+ struct radeon_ring *cp1_ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+ struct radeon_ring *cp2_ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+ u32 wptr;
+ u32 rptr;
+ u32 src_id, src_data, ring_id;
+ u8 me_id, pipe_id, queue_id;
+ u32 ring_index;
+ bool queue_hotplug = false;
+ bool queue_reset = false;
+
+ if (!rdev->ih.enabled || rdev->shutdown)
+ return IRQ_NONE;
+
+ wptr = cik_get_ih_wptr(rdev);
+
+restart_ih:
+ /* is somebody else already processing irqs? */
+ if (atomic_xchg(&rdev->ih.lock, 1))
+ return IRQ_NONE;
+
+ rptr = rdev->ih.rptr;
+ DRM_DEBUG("cik_irq_process start: rptr %d, wptr %d\n", rptr, wptr);
+
+ /* Order reading of wptr vs. reading of IH ring data */
+ rmb();
+
+ /* display interrupts */
+ cik_irq_ack(rdev);
+
+ while (rptr != wptr) {
+ /* wptr/rptr are in bytes! */
+ ring_index = rptr / 4;
+ src_id = le32_to_cpu(rdev->ih.ring[ring_index]) & 0xff;
+ src_data = le32_to_cpu(rdev->ih.ring[ring_index + 1]) & 0xfffffff;
+ ring_id = le32_to_cpu(rdev->ih.ring[ring_index + 2]) & 0xff;
+
+ switch (src_id) {
+ case 1: /* D1 vblank/vline */
+ switch (src_data) {
+ case 0: /* D1 vblank */
+ if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[0]) {
+ drm_handle_vblank(rdev->ddev, 0);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (atomic_read(&rdev->irq.pflip[0]))
+ radeon_crtc_handle_flip(rdev, 0);
+ rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VBLANK_INTERRUPT;
+ DRM_DEBUG("IH: D1 vblank\n");
+ }
+ break;
+ case 1: /* D1 vline */
+ if (rdev->irq.stat_regs.cik.disp_int & LB_D1_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int &= ~LB_D1_VLINE_INTERRUPT;
+ DRM_DEBUG("IH: D1 vline\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 2: /* D2 vblank/vline */
+ switch (src_data) {
+ case 0: /* D2 vblank */
+ if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[1]) {
+ drm_handle_vblank(rdev->ddev, 1);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (atomic_read(&rdev->irq.pflip[1]))
+ radeon_crtc_handle_flip(rdev, 1);
+ rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT;
+ DRM_DEBUG("IH: D2 vblank\n");
+ }
+ break;
+ case 1: /* D2 vline */
+ if (rdev->irq.stat_regs.cik.disp_int_cont & LB_D2_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT;
+ DRM_DEBUG("IH: D2 vline\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 3: /* D3 vblank/vline */
+ switch (src_data) {
+ case 0: /* D3 vblank */
+ if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[2]) {
+ drm_handle_vblank(rdev->ddev, 2);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (atomic_read(&rdev->irq.pflip[2]))
+ radeon_crtc_handle_flip(rdev, 2);
+ rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT;
+ DRM_DEBUG("IH: D3 vblank\n");
+ }
+ break;
+ case 1: /* D3 vline */
+ if (rdev->irq.stat_regs.cik.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT;
+ DRM_DEBUG("IH: D3 vline\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 4: /* D4 vblank/vline */
+ switch (src_data) {
+ case 0: /* D4 vblank */
+ if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[3]) {
+ drm_handle_vblank(rdev->ddev, 3);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (atomic_read(&rdev->irq.pflip[3]))
+ radeon_crtc_handle_flip(rdev, 3);
+ rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT;
+ DRM_DEBUG("IH: D4 vblank\n");
+ }
+ break;
+ case 1: /* D4 vline */
+ if (rdev->irq.stat_regs.cik.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT;
+ DRM_DEBUG("IH: D4 vline\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 5: /* D5 vblank/vline */
+ switch (src_data) {
+ case 0: /* D5 vblank */
+ if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[4]) {
+ drm_handle_vblank(rdev->ddev, 4);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (atomic_read(&rdev->irq.pflip[4]))
+ radeon_crtc_handle_flip(rdev, 4);
+ rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT;
+ DRM_DEBUG("IH: D5 vblank\n");
+ }
+ break;
+ case 1: /* D5 vline */
+ if (rdev->irq.stat_regs.cik.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT;
+ DRM_DEBUG("IH: D5 vline\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 6: /* D6 vblank/vline */
+ switch (src_data) {
+ case 0: /* D6 vblank */
+ if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) {
+ if (rdev->irq.crtc_vblank_int[5]) {
+ drm_handle_vblank(rdev->ddev, 5);
+ rdev->pm.vblank_sync = true;
+ wake_up(&rdev->irq.vblank_queue);
+ }
+ if (atomic_read(&rdev->irq.pflip[5]))
+ radeon_crtc_handle_flip(rdev, 5);
+ rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT;
+ DRM_DEBUG("IH: D6 vblank\n");
+ }
+ break;
+ case 1: /* D6 vline */
+ if (rdev->irq.stat_regs.cik.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT;
+ DRM_DEBUG("IH: D6 vline\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 42: /* HPD hotplug */
+ switch (src_data) {
+ case 0:
+ if (rdev->irq.stat_regs.cik.disp_int & DC_HPD1_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int &= ~DC_HPD1_INTERRUPT;
+ queue_hotplug = true;
+ DRM_DEBUG("IH: HPD1\n");
+ }
+ break;
+ case 1:
+ if (rdev->irq.stat_regs.cik.disp_int_cont & DC_HPD2_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont &= ~DC_HPD2_INTERRUPT;
+ queue_hotplug = true;
+ DRM_DEBUG("IH: HPD2\n");
+ }
+ break;
+ case 2:
+ if (rdev->irq.stat_regs.cik.disp_int_cont2 & DC_HPD3_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont2 &= ~DC_HPD3_INTERRUPT;
+ queue_hotplug = true;
+ DRM_DEBUG("IH: HPD3\n");
+ }
+ break;
+ case 3:
+ if (rdev->irq.stat_regs.cik.disp_int_cont3 & DC_HPD4_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont3 &= ~DC_HPD4_INTERRUPT;
+ queue_hotplug = true;
+ DRM_DEBUG("IH: HPD4\n");
+ }
+ break;
+ case 4:
+ if (rdev->irq.stat_regs.cik.disp_int_cont4 & DC_HPD5_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont4 &= ~DC_HPD5_INTERRUPT;
+ queue_hotplug = true;
+ DRM_DEBUG("IH: HPD5\n");
+ }
+ break;
+ case 5:
+ if (rdev->irq.stat_regs.cik.disp_int_cont5 & DC_HPD6_INTERRUPT) {
+ rdev->irq.stat_regs.cik.disp_int_cont5 &= ~DC_HPD6_INTERRUPT;
+ queue_hotplug = true;
+ DRM_DEBUG("IH: HPD6\n");
+ }
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
+ case 146:
+ case 147:
+ dev_err(rdev->dev, "GPU fault detected: %d 0x%08x\n", src_id, src_data);
+ dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x%08X\n",
+ RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR));
+ dev_err(rdev->dev, " VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x%08X\n",
+ RREG32(VM_CONTEXT1_PROTECTION_FAULT_STATUS));
+ /* reset addr and status */
+ WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
+ break;
+ case 176: /* GFX RB CP_INT */
+ case 177: /* GFX IB CP_INT */
+ radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ break;
+ case 181: /* CP EOP event */
+ DRM_DEBUG("IH: CP EOP\n");
+ /* XXX check the bitfield order! */
+ me_id = (ring_id & 0x60) >> 5;
+ pipe_id = (ring_id & 0x18) >> 3;
+ queue_id = (ring_id & 0x7) >> 0;
+ switch (me_id) {
+ case 0:
+ radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ break;
+ case 1:
+ case 2:
+ if ((cp1_ring->me == me_id) & (cp1_ring->pipe == pipe_id))
+ radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+ if ((cp2_ring->me == me_id) & (cp2_ring->pipe == pipe_id))
+ radeon_fence_process(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+ break;
+ }
+ break;
+ case 184: /* CP Privileged reg access */
+ DRM_ERROR("Illegal register access in command stream\n");
+ /* XXX check the bitfield order! */
+ me_id = (ring_id & 0x60) >> 5;
+ pipe_id = (ring_id & 0x18) >> 3;
+ queue_id = (ring_id & 0x7) >> 0;
+ switch (me_id) {
+ case 0:
+ /* This results in a full GPU reset, but all we need to do is soft
+ * reset the CP for gfx
+ */
+ queue_reset = true;
+ break;
+ case 1:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ case 2:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ }
+ break;
+ case 185: /* CP Privileged inst */
+ DRM_ERROR("Illegal instruction in command stream\n");
+ /* XXX check the bitfield order! */
+ me_id = (ring_id & 0x60) >> 5;
+ pipe_id = (ring_id & 0x18) >> 3;
+ queue_id = (ring_id & 0x7) >> 0;
+ switch (me_id) {
+ case 0:
+ /* This results in a full GPU reset, but all we need to do is soft
+ * reset the CP for gfx
+ */
+ queue_reset = true;
+ break;
+ case 1:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ case 2:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ }
+ break;
+ case 224: /* SDMA trap event */
+ /* XXX check the bitfield order! */
+ me_id = (ring_id & 0x3) >> 0;
+ queue_id = (ring_id & 0xc) >> 2;
+ DRM_DEBUG("IH: SDMA trap\n");
+ switch (me_id) {
+ case 0:
+ switch (queue_id) {
+ case 0:
+ radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
+ break;
+ case 1:
+ /* XXX compute */
+ break;
+ case 2:
+ /* XXX compute */
+ break;
+ }
+ break;
+ case 1:
+ switch (queue_id) {
+ case 0:
+ radeon_fence_process(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+ break;
+ case 1:
+ /* XXX compute */
+ break;
+ case 2:
+ /* XXX compute */
+ break;
+ }
+ break;
+ }
+ break;
+ case 241: /* SDMA Privileged inst */
+ case 247: /* SDMA Privileged inst */
+ DRM_ERROR("Illegal instruction in SDMA command stream\n");
+ /* XXX check the bitfield order! */
+ me_id = (ring_id & 0x3) >> 0;
+ queue_id = (ring_id & 0xc) >> 2;
+ switch (me_id) {
+ case 0:
+ switch (queue_id) {
+ case 0:
+ queue_reset = true;
+ break;
+ case 1:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ case 2:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ }
+ break;
+ case 1:
+ switch (queue_id) {
+ case 0:
+ queue_reset = true;
+ break;
+ case 1:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ case 2:
+ /* XXX compute */
+ queue_reset = true;
+ break;
+ }
+ break;
+ }
+ break;
+ case 233: /* GUI IDLE */
+ DRM_DEBUG("IH: GUI idle\n");
+ break;
+ default:
+ DRM_DEBUG("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+
+ /* wptr/rptr are in bytes! */
+ rptr += 16;
+ rptr &= rdev->ih.ptr_mask;
+ }
+ if (queue_hotplug)
+ schedule_work(&rdev->hotplug_work);
+ if (queue_reset)
+ schedule_work(&rdev->reset_work);
+ rdev->ih.rptr = rptr;
+ WREG32(IH_RB_RPTR, rdev->ih.rptr);
+ atomic_set(&rdev->ih.lock, 0);
+
+ /* make sure wptr hasn't changed while processing */
+ wptr = cik_get_ih_wptr(rdev);
+ if (wptr != rptr)
+ goto restart_ih;
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * startup/shutdown callbacks
+ */
+/**
+ * cik_startup - program the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called by cik_init() and cik_resume().
+ * Returns 0 for success, error for failure.
+ */
+static int cik_startup(struct radeon_device *rdev)
+{
+ struct radeon_ring *ring;
+ int r;
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+ !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
+ r = cik_init_microcode(rdev);
+ if (r) {
+ DRM_ERROR("Failed to load firmware!\n");
+ return r;
+ }
+ }
+ } else {
+ if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+ !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
+ !rdev->mc_fw) {
+ r = cik_init_microcode(rdev);
+ if (r) {
+ DRM_ERROR("Failed to load firmware!\n");
+ return r;
+ }
+ }
+
+ r = ci_mc_load_microcode(rdev);
+ if (r) {
+ DRM_ERROR("Failed to load MC firmware!\n");
+ return r;
+ }
+ }
+
+ r = r600_vram_scratch_init(rdev);
+ if (r)
+ return r;
+
+ cik_mc_program(rdev);
+ r = cik_pcie_gart_enable(rdev);
+ if (r)
+ return r;
+ cik_gpu_init(rdev);
+
+ /* allocate rlc buffers */
+ r = si_rlc_init(rdev);
+ if (r) {
+ DRM_ERROR("Failed to init rlc BOs!\n");
+ return r;
+ }
+
+ /* allocate wb buffer */
+ r = radeon_wb_init(rdev);
+ if (r)
+ return r;
+
+ /* allocate mec buffers */
+ r = cik_mec_init(rdev);
+ if (r) {
+ DRM_ERROR("Failed to init MEC BOs!\n");
+ return r;
+ }
+
+ r = radeon_fence_driver_start_ring(rdev, RADEON_RING_TYPE_GFX_INDEX);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+ return r;
+ }
+
+ r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP1_INDEX);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+ return r;
+ }
+
+ r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_CP2_INDEX);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing CP fences (%d).\n", r);
+ return r;
+ }
+
+ r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+ return r;
+ }
+
+ r = radeon_fence_driver_start_ring(rdev, CAYMAN_RING_TYPE_DMA1_INDEX);
+ if (r) {
+ dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
+ return r;
+ }
+
+ r = cik_uvd_resume(rdev);
+ if (!r) {
+ r = radeon_fence_driver_start_ring(rdev,
+ R600_RING_TYPE_UVD_INDEX);
+ if (r)
+ dev_err(rdev->dev, "UVD fences init error (%d).\n", r);
+ }
+ if (r)
+ rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
+
+ /* Enable IRQ */
+ if (!rdev->irq.installed) {
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ }
+
+ r = cik_irq_init(rdev);
+ if (r) {
+ DRM_ERROR("radeon: IH init failed (%d).\n", r);
+ radeon_irq_kms_fini(rdev);
+ return r;
+ }
+ cik_irq_set(rdev);
+
+ ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+ r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
+ CP_RB0_RPTR, CP_RB0_WPTR,
+ 0, 0xfffff, RADEON_CP_PACKET2);
+ if (r)
+ return r;
+
+ /* set up the compute queues */
+ /* type-2 packets are deprecated on MEC, use type-3 instead */
+ ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+ r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
+ CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+ 0, 0xfffff, PACKET3(PACKET3_NOP, 0x3FFF));
+ if (r)
+ return r;
+ ring->me = 1; /* first MEC */
+ ring->pipe = 0; /* first pipe */
+ ring->queue = 0; /* first queue */
+ ring->wptr_offs = CIK_WB_CP1_WPTR_OFFSET;
+
+ /* type-2 packets are deprecated on MEC, use type-3 instead */
+ ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+ r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
+ CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
+ 0, 0xffffffff, PACKET3(PACKET3_NOP, 0x3FFF));
+ if (r)
+ return r;
+ /* dGPU only have 1 MEC */
+ ring->me = 1; /* first MEC */
+ ring->pipe = 0; /* first pipe */
+ ring->queue = 1; /* second queue */
+ ring->wptr_offs = CIK_WB_CP2_WPTR_OFFSET;
+
+ ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+ r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
+ SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
+ SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
+ 2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+ if (r)
+ return r;
+
+ ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+ r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
+ SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
+ SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
+ 2, 0xfffffffc, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
+ if (r)
+ return r;
+
+ r = cik_cp_resume(rdev);
+ if (r)
+ return r;
+
+ r = cik_sdma_resume(rdev);
+ if (r)
+ return r;
+
+ ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+ if (ring->ring_size) {
+ r = radeon_ring_init(rdev, ring, ring->ring_size,
+ R600_WB_UVD_RPTR_OFFSET,
+ UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
+ 0, 0xfffff, RADEON_CP_PACKET2);
+ if (!r)
+ r = r600_uvd_init(rdev);
+ if (r)
+ DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
+ }
+
+ r = radeon_ib_pool_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
+ return r;
+ }
+
+ r = radeon_vm_manager_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "vm manager initialization failed (%d).\n", r);
+ return r;
+ }
+
+ return 0;
+}
+
+/**
+ * cik_resume - resume the asic to a functional state
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Programs the asic to a functional state (CIK).
+ * Called at resume.
+ * Returns 0 for success, error for failure.
+ */
+int cik_resume(struct radeon_device *rdev)
+{
+ int r;
+
+ /* post card */
+ atom_asic_init(rdev->mode_info.atom_context);
+
+ /* init golden registers */
+ cik_init_golden_registers(rdev);
+
+ rdev->accel_working = true;
+ r = cik_startup(rdev);
+ if (r) {
+ DRM_ERROR("cik startup failed on resume\n");
+ rdev->accel_working = false;
+ return r;
+ }
+
+ return r;
+
+}
+
+/**
+ * cik_suspend - suspend the asic
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Bring the chip into a state suitable for suspend (CIK).
+ * Called at suspend.
+ * Returns 0 for success.
+ */
+int cik_suspend(struct radeon_device *rdev)
+{
+ radeon_vm_manager_fini(rdev);
+ cik_cp_enable(rdev, false);
+ cik_sdma_enable(rdev, false);
+ r600_uvd_rbc_stop(rdev);
+ radeon_uvd_suspend(rdev);
+ cik_irq_suspend(rdev);
+ radeon_wb_disable(rdev);
+ cik_pcie_gart_disable(rdev);
+ return 0;
+}
+
+/* Plan is to move initialization in that function and use
+ * helper function so that radeon_device_init pretty much
+ * do nothing more than calling asic specific function. This
+ * should also allow to remove a bunch of callback function
+ * like vram_info.
+ */
+/**
+ * cik_init - asic specific driver and hw init
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup asic specific driver variables and program the hw
+ * to a functional state (CIK).
+ * Called at driver startup.
+ * Returns 0 for success, errors for failure.
+ */
+int cik_init(struct radeon_device *rdev)
+{
+ struct radeon_ring *ring;
+ int r;
+
+ /* Read BIOS */
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ /* Must be an ATOMBIOS */
+ if (!rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting atombios for cayman GPU\n");
+ return -EINVAL;
+ }
+ r = radeon_atombios_init(rdev);
+ if (r)
+ return r;
+
+ /* Post card if necessary */
+ if (!radeon_card_posted(rdev)) {
+ if (!rdev->bios) {
+ dev_err(rdev->dev, "Card not posted and no BIOS - ignoring\n");
+ return -EINVAL;
+ }
+ DRM_INFO("GPU not posted. posting now...\n");
+ atom_asic_init(rdev->mode_info.atom_context);
+ }
+ /* init golden registers */
+ cik_init_golden_registers(rdev);
+ /* Initialize scratch registers */
+ cik_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+
+ /* initialize memory controller */
+ r = cik_mc_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_bo_init(rdev);
+ if (r)
+ return r;
+
+ ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 1024 * 1024);
+
+ ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 1024 * 1024);
+ r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+ if (r)
+ return r;
+
+ ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 1024 * 1024);
+ r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+ if (r)
+ return r;
+
+ ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 256 * 1024);
+
+ ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 256 * 1024);
+
+ r = radeon_uvd_init(rdev);
+ if (!r) {
+ ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
+ ring->ring_obj = NULL;
+ r600_ring_init(rdev, ring, 4096);
+ }
+
+ rdev->ih.ring_obj = NULL;
+ r600_ih_ring_init(rdev, 64 * 1024);
+
+ r = r600_pcie_gart_init(rdev);
+ if (r)
+ return r;
+
+ rdev->accel_working = true;
+ r = cik_startup(rdev);
+ if (r) {
+ dev_err(rdev->dev, "disabling GPU acceleration\n");
+ cik_cp_fini(rdev);
+ cik_sdma_fini(rdev);
+ cik_irq_fini(rdev);
+ si_rlc_fini(rdev);
+ cik_mec_fini(rdev);
+ radeon_wb_fini(rdev);
+ radeon_ib_pool_fini(rdev);
+ radeon_vm_manager_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ cik_pcie_gart_fini(rdev);
+ rdev->accel_working = false;
+ }
+
+ /* Don't start up if the MC ucode is missing.
+ * The default clocks and voltages before the MC ucode
+ * is loaded are not suffient for advanced operations.
+ */
+ if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) {
+ DRM_ERROR("radeon: MC ucode required for NI+.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * cik_fini - asic specific driver and hw fini
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down the asic specific driver variables and program the hw
+ * to an idle state (CIK).
+ * Called at driver unload.
+ */
+void cik_fini(struct radeon_device *rdev)
+{
+ cik_cp_fini(rdev);
+ cik_sdma_fini(rdev);
+ cik_irq_fini(rdev);
+ si_rlc_fini(rdev);
+ cik_mec_fini(rdev);
+ radeon_wb_fini(rdev);
+ radeon_vm_manager_fini(rdev);
+ radeon_ib_pool_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_uvd_fini(rdev);
+ cik_pcie_gart_fini(rdev);
+ r600_vram_scratch_fini(rdev);
+ radeon_gem_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_bo_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+}
+
+/* display watermark setup */
+/**
+ * dce8_line_buffer_adjust - Set up the line buffer
+ *
+ * @rdev: radeon_device pointer
+ * @radeon_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 dce8_line_buffer_adjust(struct radeon_device *rdev,
+ struct radeon_crtc *radeon_crtc,
+ struct drm_display_mode *mode)
+{
+ u32 tmp;
+
+ /*
+ * 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 (radeon_crtc->base.enabled && mode) {
+ if (mode->crtc_hdisplay < 1920)
+ tmp = 1;
+ else if (mode->crtc_hdisplay < 2560)
+ tmp = 2;
+ else if (mode->crtc_hdisplay < 4096)
+ tmp = 0;
+ else {
+ DRM_DEBUG_KMS("Mode too big for LB!\n");
+ tmp = 0;
+ }
+ } else
+ tmp = 1;
+
+ WREG32(LB_MEMORY_CTRL + radeon_crtc->crtc_offset,
+ LB_MEMORY_CONFIG(tmp) | LB_MEMORY_SIZE(0x6B0));
+
+ if (radeon_crtc->base.enabled && mode) {
+ switch (tmp) {
+ 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
+ *
+ * @rdev: radeon_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 radeon_device *rdev)
+{
+ u32 tmp = RREG32(MC_SHARED_CHMAP);
+
+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) {
+ 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 dce8_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 */
+};
+
+/**
+ * dce8_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 dce8_dram_bandwidth(struct dce8_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);
+}
+
+/**
+ * dce8_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 dce8_dram_bandwidth_for_display(struct dce8_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);
+}
+
+/**
+ * dce8_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 dce8_data_return_bandwidth(struct dce8_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);
+}
+
+/**
+ * dce8_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 dce8_dmif_request_bandwidth(struct dce8_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);
+}
+
+/**
+ * dce8_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 dce8_available_bandwidth(struct dce8_wm_params *wm)
+{
+ /* Calculate the Available bandwidth. Display can use this temporarily but not in average. */
+ u32 dram_bandwidth = dce8_dram_bandwidth(wm);
+ u32 data_return_bandwidth = dce8_data_return_bandwidth(wm);
+ u32 dmif_req_bandwidth = dce8_dmif_request_bandwidth(wm);
+
+ return min(dram_bandwidth, min(data_return_bandwidth, dmif_req_bandwidth));
+}
+
+/**
+ * dce8_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 dce8_average_bandwidth(struct dce8_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);
+}
+
+/**
+ * dce8_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 dce8_latency_watermark(struct dce8_wm_params *wm)
+{
+ /* First calculate the latency in ns */
+ u32 mc_latency = 2000; /* 2000 ns. */
+ u32 available_bandwidth = dce8_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);
+
+}
+
+/**
+ * dce8_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 dce8_average_bandwidth_vs_dram_bandwidth_for_display(struct dce8_wm_params *wm)
+{
+ if (dce8_average_bandwidth(wm) <=
+ (dce8_dram_bandwidth_for_display(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce8_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 dce8_average_bandwidth_vs_available_bandwidth(struct dce8_wm_params *wm)
+{
+ if (dce8_average_bandwidth(wm) <=
+ (dce8_available_bandwidth(wm) / wm->num_heads))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce8_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 dce8_check_latency_hiding(struct dce8_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 (dce8_latency_watermark(wm) <= latency_hiding)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * dce8_program_watermarks - program display watermarks
+ *
+ * @rdev: radeon_device pointer
+ * @radeon_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 dce8_program_watermarks(struct radeon_device *rdev,
+ struct radeon_crtc *radeon_crtc,
+ u32 lb_size, u32 num_heads)
+{
+ struct drm_display_mode *mode = &radeon_crtc->base.mode;
+ struct dce8_wm_params wm;
+ u32 pixel_period;
+ u32 line_time = 0;
+ u32 latency_watermark_a = 0, latency_watermark_b = 0;
+ u32 tmp, wm_mask;
+
+ if (radeon_crtc->base.enabled && num_heads && mode) {
+ pixel_period = 1000000 / (u32)mode->clock;
+ line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
+
+ wm.yclk = rdev->pm.current_mclk * 10;
+ wm.sclk = rdev->pm.current_sclk * 10;
+ wm.disp_clk = mode->clock;
+ wm.src_width = mode->crtc_hdisplay;
+ wm.active_time = mode->crtc_hdisplay * pixel_period;
+ wm.blank_time = line_time - wm.active_time;
+ wm.interlaced = false;
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ wm.interlaced = true;
+ wm.vsc = radeon_crtc->vsc;
+ wm.vtaps = 1;
+ if (radeon_crtc->rmx_type != RMX_OFF)
+ wm.vtaps = 2;
+ wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
+ wm.lb_size = lb_size;
+ wm.dram_channels = cik_get_number_of_dram_channels(rdev);
+ wm.num_heads = num_heads;
+
+ /* set for high clocks */
+ latency_watermark_a = min(dce8_latency_watermark(&wm), (u32)65535);
+ /* set for low clocks */
+ /* wm.yclk = low clk; wm.sclk = low clk */
+ latency_watermark_b = min(dce8_latency_watermark(&wm), (u32)65535);
+
+ /* possibly force display priority to high */
+ /* should really do this at mode validation time... */
+ if (!dce8_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
+ !dce8_average_bandwidth_vs_available_bandwidth(&wm) ||
+ !dce8_check_latency_hiding(&wm) ||
+ (rdev->disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority to high\n");
+ }
+ }
+
+ /* select wm A */
+ wm_mask = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset);
+ tmp = wm_mask;
+ tmp &= ~LATENCY_WATERMARK_MASK(3);
+ tmp |= LATENCY_WATERMARK_MASK(1);
+ WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp);
+ WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+ (LATENCY_LOW_WATERMARK(latency_watermark_a) |
+ LATENCY_HIGH_WATERMARK(line_time)));
+ /* select wm B */
+ tmp = RREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset);
+ tmp &= ~LATENCY_WATERMARK_MASK(3);
+ tmp |= LATENCY_WATERMARK_MASK(2);
+ WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, tmp);
+ WREG32(DPG_PIPE_LATENCY_CONTROL + radeon_crtc->crtc_offset,
+ (LATENCY_LOW_WATERMARK(latency_watermark_b) |
+ LATENCY_HIGH_WATERMARK(line_time)));
+ /* restore original selection */
+ WREG32(DPG_WATERMARK_MASK_CONTROL + radeon_crtc->crtc_offset, wm_mask);
+}
+
+/**
+ * dce8_bandwidth_update - program display watermarks
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Calculate and program the display watermarks and line
+ * buffer allocation (CIK).
+ */
+void dce8_bandwidth_update(struct radeon_device *rdev)
+{
+ struct drm_display_mode *mode = NULL;
+ u32 num_heads = 0, lb_size;
+ int i;
+
+ radeon_update_display_priority(rdev);
+
+ for (i = 0; i < rdev->num_crtc; i++) {
+ if (rdev->mode_info.crtcs[i]->base.enabled)
+ num_heads++;
+ }
+ for (i = 0; i < rdev->num_crtc; i++) {
+ mode = &rdev->mode_info.crtcs[i]->base.mode;
+ lb_size = dce8_line_buffer_adjust(rdev, rdev->mode_info.crtcs[i], mode);
+ dce8_program_watermarks(rdev, rdev->mode_info.crtcs[i], lb_size, num_heads);
+ }
+}
+
+/**
+ * cik_get_gpu_clock_counter - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (SI).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev)
+{
+ uint64_t clock;
+
+ mutex_lock(&rdev->gpu_clock_mutex);
+ WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+ clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+ ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+ mutex_unlock(&rdev->gpu_clock_mutex);
+ return clock;
+}
+
+static int cik_set_uvd_clock(struct radeon_device *rdev, u32 clock,
+ u32 cntl_reg, u32 status_reg)
+{
+ int r, i;
+ struct atom_clock_dividers dividers;
+ uint32_t tmp;
+
+ r = radeon_atom_get_clock_dividers(rdev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+ clock, false, &dividers);
+ if (r)
+ return r;
+
+ tmp = RREG32_SMC(cntl_reg);
+ tmp &= ~(DCLK_DIR_CNTL_EN|DCLK_DIVIDER_MASK);
+ tmp |= dividers.post_divider;
+ WREG32_SMC(cntl_reg, tmp);
+
+ for (i = 0; i < 100; i++) {
+ if (RREG32_SMC(status_reg) & DCLK_STATUS)
+ break;
+ mdelay(10);
+ }
+ if (i == 100)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
+{
+ int r = 0;
+
+ r = cik_set_uvd_clock(rdev, vclk, CG_VCLK_CNTL, CG_VCLK_STATUS);
+ if (r)
+ return r;
+
+ r = cik_set_uvd_clock(rdev, dclk, CG_DCLK_CNTL, CG_DCLK_STATUS);
+ return r;
+}
+
+int cik_uvd_resume(struct radeon_device *rdev)
+{
+ uint64_t addr;
+ uint32_t size;
+ int r;
+
+ r = radeon_uvd_resume(rdev);
+ if (r)
+ return r;
+
+ /* programm the VCPU memory controller bits 0-27 */
+ addr = rdev->uvd.gpu_addr >> 3;
+ size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
+ WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
+ WREG32(UVD_VCPU_CACHE_SIZE0, size);
+
+ addr += size;
+ size = RADEON_UVD_STACK_SIZE >> 3;
+ WREG32(UVD_VCPU_CACHE_OFFSET1, addr);
+ WREG32(UVD_VCPU_CACHE_SIZE1, size);
+
+ addr += size;
+ size = RADEON_UVD_HEAP_SIZE >> 3;
+ WREG32(UVD_VCPU_CACHE_OFFSET2, addr);
+ WREG32(UVD_VCPU_CACHE_SIZE2, size);
+
+ /* bits 28-31 */
+ addr = (rdev->uvd.gpu_addr >> 28) & 0xF;
+ WREG32(UVD_LMI_ADDR_EXT, (addr << 12) | (addr << 0));
+
+ /* bits 32-39 */
+ addr = (rdev->uvd.gpu_addr >> 32) & 0xFF;
+ WREG32(UVD_LMI_EXT40_ADDR, addr | (0x9 << 16) | (0x1 << 31));
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/cik_blit_shaders.c b/drivers/gpu/drm/radeon/cik_blit_shaders.c
new file mode 100644
index 000000000000..ff1311806e91
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik_blit_shaders.c
@@ -0,0 +1,246 @@
+/*
+ * 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 (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Alex Deucher <alexander.deucher@amd.com>
+ */
+
+#include <linux/types.h>
+#include <linux/bug.h>
+#include <linux/kernel.h>
+
+const u32 cik_default_state[] =
+{
+ 0xc0066900,
+ 0x00000000,
+ 0x00000060, /* DB_RENDER_CONTROL */
+ 0x00000000, /* DB_COUNT_CONTROL */
+ 0x00000000, /* DB_DEPTH_VIEW */
+ 0x0000002a, /* DB_RENDER_OVERRIDE */
+ 0x00000000, /* DB_RENDER_OVERRIDE2 */
+ 0x00000000, /* DB_HTILE_DATA_BASE */
+
+ 0xc0046900,
+ 0x00000008,
+ 0x00000000, /* DB_DEPTH_BOUNDS_MIN */
+ 0x00000000, /* DB_DEPTH_BOUNDS_MAX */
+ 0x00000000, /* DB_STENCIL_CLEAR */
+ 0x00000000, /* DB_DEPTH_CLEAR */
+
+ 0xc0036900,
+ 0x0000000f,
+ 0x00000000, /* DB_DEPTH_INFO */
+ 0x00000000, /* DB_Z_INFO */
+ 0x00000000, /* DB_STENCIL_INFO */
+
+ 0xc0016900,
+ 0x00000080,
+ 0x00000000, /* PA_SC_WINDOW_OFFSET */
+
+ 0xc00d6900,
+ 0x00000083,
+ 0x0000ffff, /* PA_SC_CLIPRECT_RULE */
+ 0x00000000, /* PA_SC_CLIPRECT_0_TL */
+ 0x20002000, /* PA_SC_CLIPRECT_0_BR */
+ 0x00000000,
+ 0x20002000,
+ 0x00000000,
+ 0x20002000,
+ 0x00000000,
+ 0x20002000,
+ 0xaaaaaaaa, /* PA_SC_EDGERULE */
+ 0x00000000, /* PA_SU_HARDWARE_SCREEN_OFFSET */
+ 0x0000000f, /* CB_TARGET_MASK */
+ 0x0000000f, /* CB_SHADER_MASK */
+
+ 0xc0226900,
+ 0x00000094,
+ 0x80000000, /* PA_SC_VPORT_SCISSOR_0_TL */
+ 0x20002000, /* PA_SC_VPORT_SCISSOR_0_BR */
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x80000000,
+ 0x20002000,
+ 0x00000000, /* PA_SC_VPORT_ZMIN_0 */
+ 0x3f800000, /* PA_SC_VPORT_ZMAX_0 */
+
+ 0xc0046900,
+ 0x00000100,
+ 0xffffffff, /* VGT_MAX_VTX_INDX */
+ 0x00000000, /* VGT_MIN_VTX_INDX */
+ 0x00000000, /* VGT_INDX_OFFSET */
+ 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_INDX */
+
+ 0xc0046900,
+ 0x00000105,
+ 0x00000000, /* CB_BLEND_RED */
+ 0x00000000, /* CB_BLEND_GREEN */
+ 0x00000000, /* CB_BLEND_BLUE */
+ 0x00000000, /* CB_BLEND_ALPHA */
+
+ 0xc0016900,
+ 0x000001e0,
+ 0x00000000, /* CB_BLEND0_CONTROL */
+
+ 0xc00c6900,
+ 0x00000200,
+ 0x00000000, /* DB_DEPTH_CONTROL */
+ 0x00000000, /* DB_EQAA */
+ 0x00cc0010, /* CB_COLOR_CONTROL */
+ 0x00000210, /* DB_SHADER_CONTROL */
+ 0x00010000, /* PA_CL_CLIP_CNTL */
+ 0x00000004, /* PA_SU_SC_MODE_CNTL */
+ 0x00000100, /* 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 */
+
+ 0xc0116900,
+ 0x00000280,
+ 0x00000000, /* PA_SU_POINT_SIZE */
+ 0x00000000, /* PA_SU_POINT_MINMAX */
+ 0x00000008, /* PA_SU_LINE_CNTL */
+ 0x00000000, /* PA_SC_LINE_STIPPLE */
+ 0x00000000, /* VGT_OUTPUT_PATH_CNTL */
+ 0x00000000, /* VGT_HOS_CNTL */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000, /* VGT_GS_MODE */
+
+ 0xc0026900,
+ 0x00000292,
+ 0x00000000, /* PA_SC_MODE_CNTL_0 */
+ 0x00000000, /* PA_SC_MODE_CNTL_1 */
+
+ 0xc0016900,
+ 0x000002a1,
+ 0x00000000, /* VGT_PRIMITIVEID_EN */
+
+ 0xc0016900,
+ 0x000002a5,
+ 0x00000000, /* VGT_MULTI_PRIM_IB_RESET_EN */
+
+ 0xc0026900,
+ 0x000002a8,
+ 0x00000000, /* VGT_INSTANCE_STEP_RATE_0 */
+ 0x00000000,
+
+ 0xc0026900,
+ 0x000002ad,
+ 0x00000000, /* VGT_REUSE_OFF */
+ 0x00000000,
+
+ 0xc0016900,
+ 0x000002d5,
+ 0x00000000, /* VGT_SHADER_STAGES_EN */
+
+ 0xc0016900,
+ 0x000002dc,
+ 0x0000aa00, /* DB_ALPHA_TO_MASK */
+
+ 0xc0066900,
+ 0x000002de,
+ 0x00000000, /* PA_SU_POLY_OFFSET_DB_FMT_CNTL */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+
+ 0xc0026900,
+ 0x000002e5,
+ 0x00000000, /* VGT_STRMOUT_CONFIG */
+ 0x00000000,
+
+ 0xc01b6900,
+ 0x000002f5,
+ 0x76543210, /* PA_SC_CENTROID_PRIORITY_0 */
+ 0xfedcba98, /* PA_SC_CENTROID_PRIORITY_1 */
+ 0x00000000, /* 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,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xffffffff, /* PA_SC_AA_MASK_X0Y0_X1Y0 */
+ 0xffffffff,
+
+ 0xc0026900,
+ 0x00000316,
+ 0x0000000e, /* VGT_VERTEX_REUSE_BLOCK_CNTL */
+ 0x00000010, /* */
+};
+
+const u32 cik_default_size = ARRAY_SIZE(cik_default_state);
diff --git a/drivers/gpu/drm/radeon/cik_blit_shaders.h b/drivers/gpu/drm/radeon/cik_blit_shaders.h
new file mode 100644
index 000000000000..dfe7314f9ff4
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik_blit_shaders.h
@@ -0,0 +1,32 @@
+/*
+ * 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 (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CIK_BLIT_SHADERS_H
+#define CIK_BLIT_SHADERS_H
+
+extern const u32 cik_default_state[];
+
+extern const u32 cik_default_size;
+
+#endif
diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h
new file mode 100644
index 000000000000..d71e46d571f5
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cik_reg.h
@@ -0,0 +1,147 @@
+/*
+ * 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_REG_H__
+#define __CIK_REG_H__
+
+#define CIK_DC_GPIO_HPD_MASK 0x65b0
+#define CIK_DC_GPIO_HPD_A 0x65b4
+#define CIK_DC_GPIO_HPD_EN 0x65b8
+#define CIK_DC_GPIO_HPD_Y 0x65bc
+
+#define CIK_GRPH_CONTROL 0x6804
+# define CIK_GRPH_DEPTH(x) (((x) & 0x3) << 0)
+# define CIK_GRPH_DEPTH_8BPP 0
+# define CIK_GRPH_DEPTH_16BPP 1
+# define CIK_GRPH_DEPTH_32BPP 2
+# define CIK_GRPH_NUM_BANKS(x) (((x) & 0x3) << 2)
+# define CIK_ADDR_SURF_2_BANK 0
+# define CIK_ADDR_SURF_4_BANK 1
+# define CIK_ADDR_SURF_8_BANK 2
+# define CIK_ADDR_SURF_16_BANK 3
+# define CIK_GRPH_Z(x) (((x) & 0x3) << 4)
+# define CIK_GRPH_BANK_WIDTH(x) (((x) & 0x3) << 6)
+# define CIK_ADDR_SURF_BANK_WIDTH_1 0
+# define CIK_ADDR_SURF_BANK_WIDTH_2 1
+# define CIK_ADDR_SURF_BANK_WIDTH_4 2
+# define CIK_ADDR_SURF_BANK_WIDTH_8 3
+# define CIK_GRPH_FORMAT(x) (((x) & 0x7) << 8)
+/* 8 BPP */
+# define CIK_GRPH_FORMAT_INDEXED 0
+/* 16 BPP */
+# define CIK_GRPH_FORMAT_ARGB1555 0
+# define CIK_GRPH_FORMAT_ARGB565 1
+# define CIK_GRPH_FORMAT_ARGB4444 2
+# define CIK_GRPH_FORMAT_AI88 3
+# define CIK_GRPH_FORMAT_MONO16 4
+# define CIK_GRPH_FORMAT_BGRA5551 5
+/* 32 BPP */
+# define CIK_GRPH_FORMAT_ARGB8888 0
+# define CIK_GRPH_FORMAT_ARGB2101010 1
+# define CIK_GRPH_FORMAT_32BPP_DIG 2
+# define CIK_GRPH_FORMAT_8B_ARGB2101010 3
+# define CIK_GRPH_FORMAT_BGRA1010102 4
+# define CIK_GRPH_FORMAT_8B_BGRA1010102 5
+# define CIK_GRPH_FORMAT_RGB111110 6
+# define CIK_GRPH_FORMAT_BGR101111 7
+# define CIK_GRPH_BANK_HEIGHT(x) (((x) & 0x3) << 11)
+# define CIK_ADDR_SURF_BANK_HEIGHT_1 0
+# define CIK_ADDR_SURF_BANK_HEIGHT_2 1
+# define CIK_ADDR_SURF_BANK_HEIGHT_4 2
+# define CIK_ADDR_SURF_BANK_HEIGHT_8 3
+# define CIK_GRPH_TILE_SPLIT(x) (((x) & 0x7) << 13)
+# define CIK_ADDR_SURF_TILE_SPLIT_64B 0
+# define CIK_ADDR_SURF_TILE_SPLIT_128B 1
+# define CIK_ADDR_SURF_TILE_SPLIT_256B 2
+# define CIK_ADDR_SURF_TILE_SPLIT_512B 3
+# define CIK_ADDR_SURF_TILE_SPLIT_1KB 4
+# define CIK_ADDR_SURF_TILE_SPLIT_2KB 5
+# define CIK_ADDR_SURF_TILE_SPLIT_4KB 6
+# define CIK_GRPH_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 18)
+# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_1 0
+# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_2 1
+# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_4 2
+# define CIK_ADDR_SURF_MACRO_TILE_ASPECT_8 3
+# define CIK_GRPH_ARRAY_MODE(x) (((x) & 0x7) << 20)
+# define CIK_GRPH_ARRAY_LINEAR_GENERAL 0
+# define CIK_GRPH_ARRAY_LINEAR_ALIGNED 1
+# define CIK_GRPH_ARRAY_1D_TILED_THIN1 2
+# define CIK_GRPH_ARRAY_2D_TILED_THIN1 4
+# define CIK_GRPH_PIPE_CONFIG(x) (((x) & 0x1f) << 24)
+# define CIK_ADDR_SURF_P2 0
+# define CIK_ADDR_SURF_P4_8x16 4
+# define CIK_ADDR_SURF_P4_16x16 5
+# define CIK_ADDR_SURF_P4_16x32 6
+# define CIK_ADDR_SURF_P4_32x32 7
+# define CIK_ADDR_SURF_P8_16x16_8x16 8
+# define CIK_ADDR_SURF_P8_16x32_8x16 9
+# define CIK_ADDR_SURF_P8_32x32_8x16 10
+# define CIK_ADDR_SURF_P8_16x32_16x16 11
+# define CIK_ADDR_SURF_P8_32x32_16x16 12
+# define CIK_ADDR_SURF_P8_32x32_16x32 13
+# define CIK_ADDR_SURF_P8_32x64_32x32 14
+# define CIK_GRPH_MICRO_TILE_MODE(x) (((x) & 0x7) << 29)
+# define CIK_DISPLAY_MICRO_TILING 0
+# define CIK_THIN_MICRO_TILING 1
+# define CIK_DEPTH_MICRO_TILING 2
+# define CIK_ROTATED_MICRO_TILING 4
+
+/* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */
+#define CIK_CUR_CONTROL 0x6998
+# define CIK_CURSOR_EN (1 << 0)
+# define CIK_CURSOR_MODE(x) (((x) & 0x3) << 8)
+# define CIK_CURSOR_MONO 0
+# define CIK_CURSOR_24_1 1
+# define CIK_CURSOR_24_8_PRE_MULT 2
+# define CIK_CURSOR_24_8_UNPRE_MULT 3
+# define CIK_CURSOR_2X_MAGNIFY (1 << 16)
+# define CIK_CURSOR_FORCE_MC_ON (1 << 20)
+# define CIK_CURSOR_URGENT_CONTROL(x) (((x) & 0x7) << 24)
+# define CIK_CURSOR_URGENT_ALWAYS 0
+# define CIK_CURSOR_URGENT_1_8 1
+# define CIK_CURSOR_URGENT_1_4 2
+# define CIK_CURSOR_URGENT_3_8 3
+# define CIK_CURSOR_URGENT_1_2 4
+#define CIK_CUR_SURFACE_ADDRESS 0x699c
+# define CIK_CUR_SURFACE_ADDRESS_MASK 0xfffff000
+#define CIK_CUR_SIZE 0x69a0
+#define CIK_CUR_SURFACE_ADDRESS_HIGH 0x69a4
+#define CIK_CUR_POSITION 0x69a8
+#define CIK_CUR_HOT_SPOT 0x69ac
+#define CIK_CUR_COLOR1 0x69b0
+#define CIK_CUR_COLOR2 0x69b4
+#define CIK_CUR_UPDATE 0x69b8
+# define CIK_CURSOR_UPDATE_PENDING (1 << 0)
+# define CIK_CURSOR_UPDATE_TAKEN (1 << 1)
+# define CIK_CURSOR_UPDATE_LOCK (1 << 16)
+# define CIK_CURSOR_DISABLE_MULTIPLE_UPDATE (1 << 24)
+
+#define CIK_ALPHA_CONTROL 0x6af0
+# define CIK_CURSOR_ALPHA_BLND_ENA (1 << 1)
+
+#define CIK_LB_DATA_FORMAT 0x6b00
+# define CIK_INTERLEAVE_EN (1 << 3)
+
+#define CIK_LB_DESKTOP_HEIGHT 0x6b0c
+
+#endif
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
new file mode 100644
index 000000000000..63514b95889a
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -0,0 +1,1297 @@
+/*
+ * 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 BONAIRE_GB_ADDR_CONFIG_GOLDEN 0x12010001
+
+#define CIK_RB_BITMAP_WIDTH_PER_SH 2
+
+/* SMC IND registers */
+#define GENERAL_PWRMGT 0xC0200000
+# define GPU_COUNTER_CLK (1 << 15)
+
+#define CG_CLKPIN_CNTL 0xC05001A0
+# define XTALIN_DIVIDE (1 << 1)
+
+#define PCIE_INDEX 0x38
+#define PCIE_DATA 0x3C
+
+#define VGA_HDP_CONTROL 0x328
+#define VGA_MEMORY_DISABLE (1 << 4)
+
+#define DMIF_ADDR_CALC 0xC00
+
+#define SRBM_GFX_CNTL 0xE44
+#define PIPEID(x) ((x) << 0)
+#define MEID(x) ((x) << 2)
+#define VMID(x) ((x) << 4)
+#define QUEUEID(x) ((x) << 8)
+
+#define SRBM_STATUS2 0xE4C
+#define SDMA_BUSY (1 << 5)
+#define SDMA1_BUSY (1 << 6)
+#define SRBM_STATUS 0xE50
+#define UVD_RQ_PENDING (1 << 1)
+#define GRBM_RQ_PENDING (1 << 5)
+#define VMC_BUSY (1 << 8)
+#define MCB_BUSY (1 << 9)
+#define MCB_NON_DISPLAY_BUSY (1 << 10)
+#define MCC_BUSY (1 << 11)
+#define MCD_BUSY (1 << 12)
+#define SEM_BUSY (1 << 14)
+#define IH_BUSY (1 << 17)
+#define UVD_BUSY (1 << 19)
+
+#define SRBM_SOFT_RESET 0xE60
+#define SOFT_RESET_BIF (1 << 1)
+#define SOFT_RESET_R0PLL (1 << 4)
+#define SOFT_RESET_DC (1 << 5)
+#define SOFT_RESET_SDMA1 (1 << 6)
+#define SOFT_RESET_GRBM (1 << 8)
+#define SOFT_RESET_HDP (1 << 9)
+#define SOFT_RESET_IH (1 << 10)
+#define SOFT_RESET_MC (1 << 11)
+#define SOFT_RESET_ROM (1 << 14)
+#define SOFT_RESET_SEM (1 << 15)
+#define SOFT_RESET_VMC (1 << 17)
+#define SOFT_RESET_SDMA (1 << 20)
+#define SOFT_RESET_TST (1 << 21)
+#define SOFT_RESET_REGBB (1 << 22)
+#define SOFT_RESET_ORB (1 << 23)
+#define SOFT_RESET_VCE (1 << 24)
+
+#define VM_L2_CNTL 0x1400
+#define ENABLE_L2_CACHE (1 << 0)
+#define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1)
+#define L2_CACHE_PTE_ENDIAN_SWAP_MODE(x) ((x) << 2)
+#define L2_CACHE_PDE_ENDIAN_SWAP_MODE(x) ((x) << 4)
+#define ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE (1 << 9)
+#define ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE (1 << 10)
+#define EFFECTIVE_L2_QUEUE_SIZE(x) (((x) & 7) << 15)
+#define CONTEXT1_IDENTITY_ACCESS_MODE(x) (((x) & 3) << 19)
+#define VM_L2_CNTL2 0x1404
+#define INVALIDATE_ALL_L1_TLBS (1 << 0)
+#define INVALIDATE_L2_CACHE (1 << 1)
+#define INVALIDATE_CACHE_MODE(x) ((x) << 26)
+#define INVALIDATE_PTE_AND_PDE_CACHES 0
+#define INVALIDATE_ONLY_PTE_CACHES 1
+#define INVALIDATE_ONLY_PDE_CACHES 2
+#define VM_L2_CNTL3 0x1408
+#define BANK_SELECT(x) ((x) << 0)
+#define L2_CACHE_UPDATE_MODE(x) ((x) << 6)
+#define L2_CACHE_BIGK_FRAGMENT_SIZE(x) ((x) << 15)
+#define L2_CACHE_BIGK_ASSOCIATIVITY (1 << 20)
+#define VM_L2_STATUS 0x140C
+#define L2_BUSY (1 << 0)
+#define VM_CONTEXT0_CNTL 0x1410
+#define ENABLE_CONTEXT (1 << 0)
+#define PAGE_TABLE_DEPTH(x) (((x) & 3) << 1)
+#define RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 3)
+#define RANGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 4)
+#define DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 6)
+#define DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 7)
+#define PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 9)
+#define PDE0_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 10)
+#define VALID_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 12)
+#define VALID_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 13)
+#define READ_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 15)
+#define READ_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 16)
+#define WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT (1 << 18)
+#define WRITE_PROTECTION_FAULT_ENABLE_DEFAULT (1 << 19)
+#define VM_CONTEXT1_CNTL 0x1414
+#define VM_CONTEXT0_CNTL2 0x1430
+#define VM_CONTEXT1_CNTL2 0x1434
+#define VM_CONTEXT8_PAGE_TABLE_BASE_ADDR 0x1438
+#define VM_CONTEXT9_PAGE_TABLE_BASE_ADDR 0x143c
+#define VM_CONTEXT10_PAGE_TABLE_BASE_ADDR 0x1440
+#define VM_CONTEXT11_PAGE_TABLE_BASE_ADDR 0x1444
+#define VM_CONTEXT12_PAGE_TABLE_BASE_ADDR 0x1448
+#define VM_CONTEXT13_PAGE_TABLE_BASE_ADDR 0x144c
+#define VM_CONTEXT14_PAGE_TABLE_BASE_ADDR 0x1450
+#define VM_CONTEXT15_PAGE_TABLE_BASE_ADDR 0x1454
+
+#define VM_INVALIDATE_REQUEST 0x1478
+#define VM_INVALIDATE_RESPONSE 0x147c
+
+#define VM_CONTEXT1_PROTECTION_FAULT_STATUS 0x14DC
+
+#define VM_CONTEXT1_PROTECTION_FAULT_ADDR 0x14FC
+
+#define VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR 0x1518
+#define VM_CONTEXT1_PROTECTION_FAULT_DEFAULT_ADDR 0x151c
+
+#define VM_CONTEXT0_PAGE_TABLE_BASE_ADDR 0x153c
+#define VM_CONTEXT1_PAGE_TABLE_BASE_ADDR 0x1540
+#define VM_CONTEXT2_PAGE_TABLE_BASE_ADDR 0x1544
+#define VM_CONTEXT3_PAGE_TABLE_BASE_ADDR 0x1548
+#define VM_CONTEXT4_PAGE_TABLE_BASE_ADDR 0x154c
+#define VM_CONTEXT5_PAGE_TABLE_BASE_ADDR 0x1550
+#define VM_CONTEXT6_PAGE_TABLE_BASE_ADDR 0x1554
+#define VM_CONTEXT7_PAGE_TABLE_BASE_ADDR 0x1558
+#define VM_CONTEXT0_PAGE_TABLE_START_ADDR 0x155c
+#define VM_CONTEXT1_PAGE_TABLE_START_ADDR 0x1560
+
+#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C
+#define VM_CONTEXT1_PAGE_TABLE_END_ADDR 0x1580
+
+#define MC_SHARED_CHMAP 0x2004
+#define NOOFCHAN_SHIFT 12
+#define NOOFCHAN_MASK 0x0000f000
+#define MC_SHARED_CHREMAP 0x2008
+
+#define CHUB_CONTROL 0x1864
+#define BYPASS_VM (1 << 0)
+
+#define MC_VM_FB_LOCATION 0x2024
+#define MC_VM_AGP_TOP 0x2028
+#define MC_VM_AGP_BOT 0x202C
+#define MC_VM_AGP_BASE 0x2030
+#define MC_VM_SYSTEM_APERTURE_LOW_ADDR 0x2034
+#define MC_VM_SYSTEM_APERTURE_HIGH_ADDR 0x2038
+#define MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR 0x203C
+
+#define MC_VM_MX_L1_TLB_CNTL 0x2064
+#define ENABLE_L1_TLB (1 << 0)
+#define ENABLE_L1_FRAGMENT_PROCESSING (1 << 1)
+#define SYSTEM_ACCESS_MODE_PA_ONLY (0 << 3)
+#define SYSTEM_ACCESS_MODE_USE_SYS_MAP (1 << 3)
+#define SYSTEM_ACCESS_MODE_IN_SYS (2 << 3)
+#define SYSTEM_ACCESS_MODE_NOT_IN_SYS (3 << 3)
+#define SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU (0 << 5)
+#define ENABLE_ADVANCED_DRIVER_MODEL (1 << 6)
+#define MC_VM_FB_OFFSET 0x2068
+
+#define MC_SHARED_BLACKOUT_CNTL 0x20ac
+
+#define MC_ARB_RAMCFG 0x2760
+#define NOOFBANK_SHIFT 0
+#define NOOFBANK_MASK 0x00000003
+#define NOOFRANK_SHIFT 2
+#define NOOFRANK_MASK 0x00000004
+#define NOOFROWS_SHIFT 3
+#define NOOFROWS_MASK 0x00000038
+#define NOOFCOLS_SHIFT 6
+#define NOOFCOLS_MASK 0x000000C0
+#define CHANSIZE_SHIFT 8
+#define CHANSIZE_MASK 0x00000100
+#define NOOFGROUPS_SHIFT 12
+#define NOOFGROUPS_MASK 0x00001000
+
+#define MC_SEQ_SUP_CNTL 0x28c8
+#define RUN_MASK (1 << 0)
+#define MC_SEQ_SUP_PGM 0x28cc
+
+#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x28e8
+#define TRAIN_DONE_D0 (1 << 30)
+#define TRAIN_DONE_D1 (1 << 31)
+
+#define MC_IO_PAD_CNTL_D0 0x29d0
+#define MEM_FALL_OUT_CMD (1 << 8)
+
+#define MC_SEQ_IO_DEBUG_INDEX 0x2a44
+#define MC_SEQ_IO_DEBUG_DATA 0x2a48
+
+#define HDP_HOST_PATH_CNTL 0x2C00
+#define HDP_NONSURFACE_BASE 0x2C04
+#define HDP_NONSURFACE_INFO 0x2C08
+#define HDP_NONSURFACE_SIZE 0x2C0C
+
+#define HDP_ADDR_CONFIG 0x2F48
+#define HDP_MISC_CNTL 0x2F4C
+#define HDP_FLUSH_INVALIDATE_CACHE (1 << 0)
+
+#define IH_RB_CNTL 0x3e00
+# define IH_RB_ENABLE (1 << 0)
+# define IH_RB_SIZE(x) ((x) << 1) /* log2 */
+# define IH_RB_FULL_DRAIN_ENABLE (1 << 6)
+# define IH_WPTR_WRITEBACK_ENABLE (1 << 8)
+# define IH_WPTR_WRITEBACK_TIMER(x) ((x) << 9) /* log2 */
+# define IH_WPTR_OVERFLOW_ENABLE (1 << 16)
+# define IH_WPTR_OVERFLOW_CLEAR (1 << 31)
+#define IH_RB_BASE 0x3e04
+#define IH_RB_RPTR 0x3e08
+#define IH_RB_WPTR 0x3e0c
+# define RB_OVERFLOW (1 << 0)
+# define WPTR_OFFSET_MASK 0x3fffc
+#define IH_RB_WPTR_ADDR_HI 0x3e10
+#define IH_RB_WPTR_ADDR_LO 0x3e14
+#define IH_CNTL 0x3e18
+# define ENABLE_INTR (1 << 0)
+# define IH_MC_SWAP(x) ((x) << 1)
+# define IH_MC_SWAP_NONE 0
+# define IH_MC_SWAP_16BIT 1
+# define IH_MC_SWAP_32BIT 2
+# define IH_MC_SWAP_64BIT 3
+# define RPTR_REARM (1 << 4)
+# define MC_WRREQ_CREDIT(x) ((x) << 15)
+# define MC_WR_CLEAN_CNT(x) ((x) << 20)
+# define MC_VMID(x) ((x) << 25)
+
+#define CONFIG_MEMSIZE 0x5428
+
+#define INTERRUPT_CNTL 0x5468
+# define IH_DUMMY_RD_OVERRIDE (1 << 0)
+# define IH_DUMMY_RD_EN (1 << 1)
+# define IH_REQ_NONSNOOP_EN (1 << 3)
+# define GEN_IH_INT_EN (1 << 8)
+#define INTERRUPT_CNTL2 0x546c
+
+#define HDP_MEM_COHERENCY_FLUSH_CNTL 0x5480
+
+#define BIF_FB_EN 0x5490
+#define FB_READ_EN (1 << 0)
+#define FB_WRITE_EN (1 << 1)
+
+#define HDP_REG_COHERENCY_FLUSH_CNTL 0x54A0
+
+#define GPU_HDP_FLUSH_REQ 0x54DC
+#define GPU_HDP_FLUSH_DONE 0x54E0
+#define CP0 (1 << 0)
+#define CP1 (1 << 1)
+#define CP2 (1 << 2)
+#define CP3 (1 << 3)
+#define CP4 (1 << 4)
+#define CP5 (1 << 5)
+#define CP6 (1 << 6)
+#define CP7 (1 << 7)
+#define CP8 (1 << 8)
+#define CP9 (1 << 9)
+#define SDMA0 (1 << 10)
+#define SDMA1 (1 << 11)
+
+/* 0x6b04, 0x7704, 0x10304, 0x10f04, 0x11b04, 0x12704 */
+#define LB_MEMORY_CTRL 0x6b04
+#define LB_MEMORY_SIZE(x) ((x) << 0)
+#define LB_MEMORY_CONFIG(x) ((x) << 20)
+
+#define DPG_WATERMARK_MASK_CONTROL 0x6cc8
+# define LATENCY_WATERMARK_MASK(x) ((x) << 8)
+#define DPG_PIPE_LATENCY_CONTROL 0x6ccc
+# define LATENCY_LOW_WATERMARK(x) ((x) << 0)
+# define LATENCY_HIGH_WATERMARK(x) ((x) << 16)
+
+/* 0x6b24, 0x7724, 0x10324, 0x10f24, 0x11b24, 0x12724 */
+#define LB_VLINE_STATUS 0x6b24
+# define VLINE_OCCURRED (1 << 0)
+# define VLINE_ACK (1 << 4)
+# define VLINE_STAT (1 << 12)
+# define VLINE_INTERRUPT (1 << 16)
+# define VLINE_INTERRUPT_TYPE (1 << 17)
+/* 0x6b2c, 0x772c, 0x1032c, 0x10f2c, 0x11b2c, 0x1272c */
+#define LB_VBLANK_STATUS 0x6b2c
+# define VBLANK_OCCURRED (1 << 0)
+# define VBLANK_ACK (1 << 4)
+# define VBLANK_STAT (1 << 12)
+# define VBLANK_INTERRUPT (1 << 16)
+# define VBLANK_INTERRUPT_TYPE (1 << 17)
+
+/* 0x6b20, 0x7720, 0x10320, 0x10f20, 0x11b20, 0x12720 */
+#define LB_INTERRUPT_MASK 0x6b20
+# define VBLANK_INTERRUPT_MASK (1 << 0)
+# define VLINE_INTERRUPT_MASK (1 << 4)
+# define VLINE2_INTERRUPT_MASK (1 << 8)
+
+#define DISP_INTERRUPT_STATUS 0x60f4
+# define LB_D1_VLINE_INTERRUPT (1 << 2)
+# define LB_D1_VBLANK_INTERRUPT (1 << 3)
+# define DC_HPD1_INTERRUPT (1 << 17)
+# define DC_HPD1_RX_INTERRUPT (1 << 18)
+# define DACA_AUTODETECT_INTERRUPT (1 << 22)
+# define DACB_AUTODETECT_INTERRUPT (1 << 23)
+# define DC_I2C_SW_DONE_INTERRUPT (1 << 24)
+# define DC_I2C_HW_DONE_INTERRUPT (1 << 25)
+#define DISP_INTERRUPT_STATUS_CONTINUE 0x60f8
+# define LB_D2_VLINE_INTERRUPT (1 << 2)
+# define LB_D2_VBLANK_INTERRUPT (1 << 3)
+# define DC_HPD2_INTERRUPT (1 << 17)
+# define DC_HPD2_RX_INTERRUPT (1 << 18)
+# define DISP_TIMER_INTERRUPT (1 << 24)
+#define DISP_INTERRUPT_STATUS_CONTINUE2 0x60fc
+# define LB_D3_VLINE_INTERRUPT (1 << 2)
+# define LB_D3_VBLANK_INTERRUPT (1 << 3)
+# define DC_HPD3_INTERRUPT (1 << 17)
+# define DC_HPD3_RX_INTERRUPT (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE3 0x6100
+# define LB_D4_VLINE_INTERRUPT (1 << 2)
+# define LB_D4_VBLANK_INTERRUPT (1 << 3)
+# define DC_HPD4_INTERRUPT (1 << 17)
+# define DC_HPD4_RX_INTERRUPT (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE4 0x614c
+# define LB_D5_VLINE_INTERRUPT (1 << 2)
+# define LB_D5_VBLANK_INTERRUPT (1 << 3)
+# define DC_HPD5_INTERRUPT (1 << 17)
+# define DC_HPD5_RX_INTERRUPT (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE5 0x6150
+# define LB_D6_VLINE_INTERRUPT (1 << 2)
+# define LB_D6_VBLANK_INTERRUPT (1 << 3)
+# define DC_HPD6_INTERRUPT (1 << 17)
+# define DC_HPD6_RX_INTERRUPT (1 << 18)
+#define DISP_INTERRUPT_STATUS_CONTINUE6 0x6780
+
+#define DAC_AUTODETECT_INT_CONTROL 0x67c8
+
+#define DC_HPD1_INT_STATUS 0x601c
+#define DC_HPD2_INT_STATUS 0x6028
+#define DC_HPD3_INT_STATUS 0x6034
+#define DC_HPD4_INT_STATUS 0x6040
+#define DC_HPD5_INT_STATUS 0x604c
+#define DC_HPD6_INT_STATUS 0x6058
+# define DC_HPDx_INT_STATUS (1 << 0)
+# define DC_HPDx_SENSE (1 << 1)
+# define DC_HPDx_SENSE_DELAYED (1 << 4)
+# define DC_HPDx_RX_INT_STATUS (1 << 8)
+
+#define DC_HPD1_INT_CONTROL 0x6020
+#define DC_HPD2_INT_CONTROL 0x602c
+#define DC_HPD3_INT_CONTROL 0x6038
+#define DC_HPD4_INT_CONTROL 0x6044
+#define DC_HPD5_INT_CONTROL 0x6050
+#define DC_HPD6_INT_CONTROL 0x605c
+# define DC_HPDx_INT_ACK (1 << 0)
+# define DC_HPDx_INT_POLARITY (1 << 8)
+# define DC_HPDx_INT_EN (1 << 16)
+# define DC_HPDx_RX_INT_ACK (1 << 20)
+# define DC_HPDx_RX_INT_EN (1 << 24)
+
+#define DC_HPD1_CONTROL 0x6024
+#define DC_HPD2_CONTROL 0x6030
+#define DC_HPD3_CONTROL 0x603c
+#define DC_HPD4_CONTROL 0x6048
+#define DC_HPD5_CONTROL 0x6054
+#define DC_HPD6_CONTROL 0x6060
+# define DC_HPDx_CONNECTION_TIMER(x) ((x) << 0)
+# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16)
+# define DC_HPDx_EN (1 << 28)
+
+#define GRBM_CNTL 0x8000
+#define GRBM_READ_TIMEOUT(x) ((x) << 0)
+
+#define GRBM_STATUS2 0x8008
+#define ME0PIPE1_CMDFIFO_AVAIL_MASK 0x0000000F
+#define ME0PIPE1_CF_RQ_PENDING (1 << 4)
+#define ME0PIPE1_PF_RQ_PENDING (1 << 5)
+#define ME1PIPE0_RQ_PENDING (1 << 6)
+#define ME1PIPE1_RQ_PENDING (1 << 7)
+#define ME1PIPE2_RQ_PENDING (1 << 8)
+#define ME1PIPE3_RQ_PENDING (1 << 9)
+#define ME2PIPE0_RQ_PENDING (1 << 10)
+#define ME2PIPE1_RQ_PENDING (1 << 11)
+#define ME2PIPE2_RQ_PENDING (1 << 12)
+#define ME2PIPE3_RQ_PENDING (1 << 13)
+#define RLC_RQ_PENDING (1 << 14)
+#define RLC_BUSY (1 << 24)
+#define TC_BUSY (1 << 25)
+#define CPF_BUSY (1 << 28)
+#define CPC_BUSY (1 << 29)
+#define CPG_BUSY (1 << 30)
+
+#define GRBM_STATUS 0x8010
+#define ME0PIPE0_CMDFIFO_AVAIL_MASK 0x0000000F
+#define SRBM_RQ_PENDING (1 << 5)
+#define ME0PIPE0_CF_RQ_PENDING (1 << 7)
+#define ME0PIPE0_PF_RQ_PENDING (1 << 8)
+#define GDS_DMA_RQ_PENDING (1 << 9)
+#define DB_CLEAN (1 << 12)
+#define CB_CLEAN (1 << 13)
+#define TA_BUSY (1 << 14)
+#define GDS_BUSY (1 << 15)
+#define WD_BUSY_NO_DMA (1 << 16)
+#define VGT_BUSY (1 << 17)
+#define IA_BUSY_NO_DMA (1 << 18)
+#define IA_BUSY (1 << 19)
+#define SX_BUSY (1 << 20)
+#define WD_BUSY (1 << 21)
+#define SPI_BUSY (1 << 22)
+#define BCI_BUSY (1 << 23)
+#define SC_BUSY (1 << 24)
+#define PA_BUSY (1 << 25)
+#define DB_BUSY (1 << 26)
+#define CP_COHERENCY_BUSY (1 << 28)
+#define CP_BUSY (1 << 29)
+#define CB_BUSY (1 << 30)
+#define GUI_ACTIVE (1 << 31)
+#define GRBM_STATUS_SE0 0x8014
+#define GRBM_STATUS_SE1 0x8018
+#define GRBM_STATUS_SE2 0x8038
+#define GRBM_STATUS_SE3 0x803C
+#define SE_DB_CLEAN (1 << 1)
+#define SE_CB_CLEAN (1 << 2)
+#define SE_BCI_BUSY (1 << 22)
+#define SE_VGT_BUSY (1 << 23)
+#define SE_PA_BUSY (1 << 24)
+#define SE_TA_BUSY (1 << 25)
+#define SE_SX_BUSY (1 << 26)
+#define SE_SPI_BUSY (1 << 27)
+#define SE_SC_BUSY (1 << 29)
+#define SE_DB_BUSY (1 << 30)
+#define SE_CB_BUSY (1 << 31)
+
+#define GRBM_SOFT_RESET 0x8020
+#define SOFT_RESET_CP (1 << 0) /* All CP blocks */
+#define SOFT_RESET_RLC (1 << 2) /* RLC */
+#define SOFT_RESET_GFX (1 << 16) /* GFX */
+#define SOFT_RESET_CPF (1 << 17) /* CP fetcher shared by gfx and compute */
+#define SOFT_RESET_CPC (1 << 18) /* CP Compute (MEC1/2) */
+#define SOFT_RESET_CPG (1 << 19) /* CP GFX (PFP, ME, CE) */
+
+#define GRBM_INT_CNTL 0x8060
+# define RDERR_INT_ENABLE (1 << 0)
+# define GUI_IDLE_INT_ENABLE (1 << 19)
+
+#define CP_CPC_STATUS 0x8210
+#define CP_CPC_BUSY_STAT 0x8214
+#define CP_CPC_STALLED_STAT1 0x8218
+#define CP_CPF_STATUS 0x821c
+#define CP_CPF_BUSY_STAT 0x8220
+#define CP_CPF_STALLED_STAT1 0x8224
+
+#define CP_MEC_CNTL 0x8234
+#define MEC_ME2_HALT (1 << 28)
+#define MEC_ME1_HALT (1 << 30)
+
+#define CP_MEC_CNTL 0x8234
+#define MEC_ME2_HALT (1 << 28)
+#define MEC_ME1_HALT (1 << 30)
+
+#define CP_STALLED_STAT3 0x8670
+#define CP_STALLED_STAT1 0x8674
+#define CP_STALLED_STAT2 0x8678
+
+#define CP_STAT 0x8680
+
+#define CP_ME_CNTL 0x86D8
+#define CP_CE_HALT (1 << 24)
+#define CP_PFP_HALT (1 << 26)
+#define CP_ME_HALT (1 << 28)
+
+#define CP_RB0_RPTR 0x8700
+#define CP_RB_WPTR_DELAY 0x8704
+
+#define CP_MEQ_THRESHOLDS 0x8764
+#define MEQ1_START(x) ((x) << 0)
+#define MEQ2_START(x) ((x) << 8)
+
+#define VGT_VTX_VECT_EJECT_REG 0x88B0
+
+#define VGT_CACHE_INVALIDATION 0x88C4
+#define CACHE_INVALIDATION(x) ((x) << 0)
+#define VC_ONLY 0
+#define TC_ONLY 1
+#define VC_AND_TC 2
+#define AUTO_INVLD_EN(x) ((x) << 6)
+#define NO_AUTO 0
+#define ES_AUTO 1
+#define GS_AUTO 2
+#define ES_AND_GS_AUTO 3
+
+#define VGT_GS_VERTEX_REUSE 0x88D4
+
+#define CC_GC_SHADER_ARRAY_CONFIG 0x89bc
+#define INACTIVE_CUS_MASK 0xFFFF0000
+#define INACTIVE_CUS_SHIFT 16
+#define GC_USER_SHADER_ARRAY_CONFIG 0x89c0
+
+#define PA_CL_ENHANCE 0x8A14
+#define CLIP_VTX_REORDER_ENA (1 << 0)
+#define NUM_CLIP_SEQ(x) ((x) << 1)
+
+#define PA_SC_FORCE_EOV_MAX_CNTS 0x8B24
+#define FORCE_EOV_MAX_CLK_CNT(x) ((x) << 0)
+#define FORCE_EOV_MAX_REZ_CNT(x) ((x) << 16)
+
+#define PA_SC_FIFO_SIZE 0x8BCC
+#define SC_FRONTEND_PRIM_FIFO_SIZE(x) ((x) << 0)
+#define SC_BACKEND_PRIM_FIFO_SIZE(x) ((x) << 6)
+#define SC_HIZ_TILE_FIFO_SIZE(x) ((x) << 15)
+#define SC_EARLYZ_TILE_FIFO_SIZE(x) ((x) << 23)
+
+#define PA_SC_ENHANCE 0x8BF0
+#define ENABLE_PA_SC_OUT_OF_ORDER (1 << 0)
+#define DISABLE_PA_SC_GUIDANCE (1 << 13)
+
+#define SQ_CONFIG 0x8C00
+
+#define SH_MEM_BASES 0x8C28
+/* if PTR32, these are the bases for scratch and lds */
+#define PRIVATE_BASE(x) ((x) << 0) /* scratch */
+#define SHARED_BASE(x) ((x) << 16) /* LDS */
+#define SH_MEM_APE1_BASE 0x8C2C
+/* if PTR32, this is the base location of GPUVM */
+#define SH_MEM_APE1_LIMIT 0x8C30
+/* if PTR32, this is the upper limit of GPUVM */
+#define SH_MEM_CONFIG 0x8C34
+#define PTR32 (1 << 0)
+#define ALIGNMENT_MODE(x) ((x) << 2)
+#define SH_MEM_ALIGNMENT_MODE_DWORD 0
+#define SH_MEM_ALIGNMENT_MODE_DWORD_STRICT 1
+#define SH_MEM_ALIGNMENT_MODE_STRICT 2
+#define SH_MEM_ALIGNMENT_MODE_UNALIGNED 3
+#define DEFAULT_MTYPE(x) ((x) << 4)
+#define APE1_MTYPE(x) ((x) << 7)
+
+#define SX_DEBUG_1 0x9060
+
+#define SPI_CONFIG_CNTL 0x9100
+
+#define SPI_CONFIG_CNTL_1 0x913C
+#define VTX_DONE_DELAY(x) ((x) << 0)
+#define INTERP_ONE_PRIM_PER_ROW (1 << 4)
+
+#define TA_CNTL_AUX 0x9508
+
+#define DB_DEBUG 0x9830
+#define DB_DEBUG2 0x9834
+#define DB_DEBUG3 0x9838
+
+#define CC_RB_BACKEND_DISABLE 0x98F4
+#define BACKEND_DISABLE(x) ((x) << 16)
+#define GB_ADDR_CONFIG 0x98F8
+#define NUM_PIPES(x) ((x) << 0)
+#define NUM_PIPES_MASK 0x00000007
+#define NUM_PIPES_SHIFT 0
+#define PIPE_INTERLEAVE_SIZE(x) ((x) << 4)
+#define PIPE_INTERLEAVE_SIZE_MASK 0x00000070
+#define PIPE_INTERLEAVE_SIZE_SHIFT 4
+#define NUM_SHADER_ENGINES(x) ((x) << 12)
+#define NUM_SHADER_ENGINES_MASK 0x00003000
+#define NUM_SHADER_ENGINES_SHIFT 12
+#define SHADER_ENGINE_TILE_SIZE(x) ((x) << 16)
+#define SHADER_ENGINE_TILE_SIZE_MASK 0x00070000
+#define SHADER_ENGINE_TILE_SIZE_SHIFT 16
+#define ROW_SIZE(x) ((x) << 28)
+#define ROW_SIZE_MASK 0x30000000
+#define ROW_SIZE_SHIFT 28
+
+#define GB_TILE_MODE0 0x9910
+# define ARRAY_MODE(x) ((x) << 2)
+# define ARRAY_LINEAR_GENERAL 0
+# define ARRAY_LINEAR_ALIGNED 1
+# define ARRAY_1D_TILED_THIN1 2
+# define ARRAY_2D_TILED_THIN1 4
+# define ARRAY_PRT_TILED_THIN1 5
+# define ARRAY_PRT_2D_TILED_THIN1 6
+# define PIPE_CONFIG(x) ((x) << 6)
+# define ADDR_SURF_P2 0
+# define ADDR_SURF_P4_8x16 4
+# define ADDR_SURF_P4_16x16 5
+# define ADDR_SURF_P4_16x32 6
+# define ADDR_SURF_P4_32x32 7
+# define ADDR_SURF_P8_16x16_8x16 8
+# define ADDR_SURF_P8_16x32_8x16 9
+# define ADDR_SURF_P8_32x32_8x16 10
+# define ADDR_SURF_P8_16x32_16x16 11
+# define ADDR_SURF_P8_32x32_16x16 12
+# define ADDR_SURF_P8_32x32_16x32 13
+# define ADDR_SURF_P8_32x64_32x32 14
+# define TILE_SPLIT(x) ((x) << 11)
+# define ADDR_SURF_TILE_SPLIT_64B 0
+# define ADDR_SURF_TILE_SPLIT_128B 1
+# define ADDR_SURF_TILE_SPLIT_256B 2
+# define ADDR_SURF_TILE_SPLIT_512B 3
+# define ADDR_SURF_TILE_SPLIT_1KB 4
+# define ADDR_SURF_TILE_SPLIT_2KB 5
+# define ADDR_SURF_TILE_SPLIT_4KB 6
+# define MICRO_TILE_MODE_NEW(x) ((x) << 22)
+# define ADDR_SURF_DISPLAY_MICRO_TILING 0
+# define ADDR_SURF_THIN_MICRO_TILING 1
+# define ADDR_SURF_DEPTH_MICRO_TILING 2
+# define ADDR_SURF_ROTATED_MICRO_TILING 3
+# define SAMPLE_SPLIT(x) ((x) << 25)
+# define ADDR_SURF_SAMPLE_SPLIT_1 0
+# define ADDR_SURF_SAMPLE_SPLIT_2 1
+# define ADDR_SURF_SAMPLE_SPLIT_4 2
+# define ADDR_SURF_SAMPLE_SPLIT_8 3
+
+#define GB_MACROTILE_MODE0 0x9990
+# define BANK_WIDTH(x) ((x) << 0)
+# define ADDR_SURF_BANK_WIDTH_1 0
+# define ADDR_SURF_BANK_WIDTH_2 1
+# define ADDR_SURF_BANK_WIDTH_4 2
+# define ADDR_SURF_BANK_WIDTH_8 3
+# define BANK_HEIGHT(x) ((x) << 2)
+# define ADDR_SURF_BANK_HEIGHT_1 0
+# define ADDR_SURF_BANK_HEIGHT_2 1
+# define ADDR_SURF_BANK_HEIGHT_4 2
+# define ADDR_SURF_BANK_HEIGHT_8 3
+# define MACRO_TILE_ASPECT(x) ((x) << 4)
+# define ADDR_SURF_MACRO_ASPECT_1 0
+# define ADDR_SURF_MACRO_ASPECT_2 1
+# define ADDR_SURF_MACRO_ASPECT_4 2
+# define ADDR_SURF_MACRO_ASPECT_8 3
+# define NUM_BANKS(x) ((x) << 6)
+# define ADDR_SURF_2_BANK 0
+# define ADDR_SURF_4_BANK 1
+# define ADDR_SURF_8_BANK 2
+# define ADDR_SURF_16_BANK 3
+
+#define CB_HW_CONTROL 0x9A10
+
+#define GC_USER_RB_BACKEND_DISABLE 0x9B7C
+#define BACKEND_DISABLE_MASK 0x00FF0000
+#define BACKEND_DISABLE_SHIFT 16
+
+#define TCP_CHAN_STEER_LO 0xac0c
+#define TCP_CHAN_STEER_HI 0xac10
+
+#define TC_CFG_L1_LOAD_POLICY0 0xAC68
+#define TC_CFG_L1_LOAD_POLICY1 0xAC6C
+#define TC_CFG_L1_STORE_POLICY 0xAC70
+#define TC_CFG_L2_LOAD_POLICY0 0xAC74
+#define TC_CFG_L2_LOAD_POLICY1 0xAC78
+#define TC_CFG_L2_STORE_POLICY0 0xAC7C
+#define TC_CFG_L2_STORE_POLICY1 0xAC80
+#define TC_CFG_L2_ATOMIC_POLICY 0xAC84
+#define TC_CFG_L1_VOLATILE 0xAC88
+#define TC_CFG_L2_VOLATILE 0xAC8C
+
+#define CP_RB0_BASE 0xC100
+#define CP_RB0_CNTL 0xC104
+#define RB_BUFSZ(x) ((x) << 0)
+#define RB_BLKSZ(x) ((x) << 8)
+#define BUF_SWAP_32BIT (2 << 16)
+#define RB_NO_UPDATE (1 << 27)
+#define RB_RPTR_WR_ENA (1 << 31)
+
+#define CP_RB0_RPTR_ADDR 0xC10C
+#define RB_RPTR_SWAP_32BIT (2 << 0)
+#define CP_RB0_RPTR_ADDR_HI 0xC110
+#define CP_RB0_WPTR 0xC114
+
+#define CP_DEVICE_ID 0xC12C
+#define CP_ENDIAN_SWAP 0xC140
+#define CP_RB_VMID 0xC144
+
+#define CP_PFP_UCODE_ADDR 0xC150
+#define CP_PFP_UCODE_DATA 0xC154
+#define CP_ME_RAM_RADDR 0xC158
+#define CP_ME_RAM_WADDR 0xC15C
+#define CP_ME_RAM_DATA 0xC160
+
+#define CP_CE_UCODE_ADDR 0xC168
+#define CP_CE_UCODE_DATA 0xC16C
+#define CP_MEC_ME1_UCODE_ADDR 0xC170
+#define CP_MEC_ME1_UCODE_DATA 0xC174
+#define CP_MEC_ME2_UCODE_ADDR 0xC178
+#define CP_MEC_ME2_UCODE_DATA 0xC17C
+
+#define CP_INT_CNTL_RING0 0xC1A8
+# define CNTX_BUSY_INT_ENABLE (1 << 19)
+# define CNTX_EMPTY_INT_ENABLE (1 << 20)
+# define PRIV_INSTR_INT_ENABLE (1 << 22)
+# define PRIV_REG_INT_ENABLE (1 << 23)
+# define TIME_STAMP_INT_ENABLE (1 << 26)
+# define CP_RINGID2_INT_ENABLE (1 << 29)
+# define CP_RINGID1_INT_ENABLE (1 << 30)
+# define CP_RINGID0_INT_ENABLE (1 << 31)
+
+#define CP_INT_STATUS_RING0 0xC1B4
+# define PRIV_INSTR_INT_STAT (1 << 22)
+# define PRIV_REG_INT_STAT (1 << 23)
+# define TIME_STAMP_INT_STAT (1 << 26)
+# define CP_RINGID2_INT_STAT (1 << 29)
+# define CP_RINGID1_INT_STAT (1 << 30)
+# define CP_RINGID0_INT_STAT (1 << 31)
+
+#define CP_CPF_DEBUG 0xC200
+
+#define CP_PQ_WPTR_POLL_CNTL 0xC20C
+#define WPTR_POLL_EN (1 << 31)
+
+#define CP_ME1_PIPE0_INT_CNTL 0xC214
+#define CP_ME1_PIPE1_INT_CNTL 0xC218
+#define CP_ME1_PIPE2_INT_CNTL 0xC21C
+#define CP_ME1_PIPE3_INT_CNTL 0xC220
+#define CP_ME2_PIPE0_INT_CNTL 0xC224
+#define CP_ME2_PIPE1_INT_CNTL 0xC228
+#define CP_ME2_PIPE2_INT_CNTL 0xC22C
+#define CP_ME2_PIPE3_INT_CNTL 0xC230
+# define DEQUEUE_REQUEST_INT_ENABLE (1 << 13)
+# define WRM_POLL_TIMEOUT_INT_ENABLE (1 << 17)
+# define PRIV_REG_INT_ENABLE (1 << 23)
+# define TIME_STAMP_INT_ENABLE (1 << 26)
+# define GENERIC2_INT_ENABLE (1 << 29)
+# define GENERIC1_INT_ENABLE (1 << 30)
+# define GENERIC0_INT_ENABLE (1 << 31)
+#define CP_ME1_PIPE0_INT_STATUS 0xC214
+#define CP_ME1_PIPE1_INT_STATUS 0xC218
+#define CP_ME1_PIPE2_INT_STATUS 0xC21C
+#define CP_ME1_PIPE3_INT_STATUS 0xC220
+#define CP_ME2_PIPE0_INT_STATUS 0xC224
+#define CP_ME2_PIPE1_INT_STATUS 0xC228
+#define CP_ME2_PIPE2_INT_STATUS 0xC22C
+#define CP_ME2_PIPE3_INT_STATUS 0xC230
+# define DEQUEUE_REQUEST_INT_STATUS (1 << 13)
+# define WRM_POLL_TIMEOUT_INT_STATUS (1 << 17)
+# define PRIV_REG_INT_STATUS (1 << 23)
+# define TIME_STAMP_INT_STATUS (1 << 26)
+# define GENERIC2_INT_STATUS (1 << 29)
+# define GENERIC1_INT_STATUS (1 << 30)
+# define GENERIC0_INT_STATUS (1 << 31)
+
+#define CP_MAX_CONTEXT 0xC2B8
+
+#define CP_RB0_BASE_HI 0xC2C4
+
+#define RLC_CNTL 0xC300
+# define RLC_ENABLE (1 << 0)
+
+#define RLC_MC_CNTL 0xC30C
+
+#define RLC_LB_CNTR_MAX 0xC348
+
+#define RLC_LB_CNTL 0xC364
+
+#define RLC_LB_CNTR_INIT 0xC36C
+
+#define RLC_SAVE_AND_RESTORE_BASE 0xC374
+#define RLC_DRIVER_DMA_STATUS 0xC378
+
+#define RLC_GPM_UCODE_ADDR 0xC388
+#define RLC_GPM_UCODE_DATA 0xC38C
+#define RLC_GPU_CLOCK_COUNT_LSB 0xC390
+#define RLC_GPU_CLOCK_COUNT_MSB 0xC394
+#define RLC_CAPTURE_GPU_CLOCK_COUNT 0xC398
+#define RLC_UCODE_CNTL 0xC39C
+
+#define RLC_CGCG_CGLS_CTRL 0xC424
+
+#define RLC_LB_INIT_CU_MASK 0xC43C
+
+#define RLC_LB_PARAMS 0xC444
+
+#define RLC_SERDES_CU_MASTER_BUSY 0xC484
+#define RLC_SERDES_NONCU_MASTER_BUSY 0xC488
+# define SE_MASTER_BUSY_MASK 0x0000ffff
+# define GC_MASTER_BUSY (1 << 16)
+# define TC0_MASTER_BUSY (1 << 17)
+# define TC1_MASTER_BUSY (1 << 18)
+
+#define RLC_GPM_SCRATCH_ADDR 0xC4B0
+#define RLC_GPM_SCRATCH_DATA 0xC4B4
+
+#define CP_HPD_EOP_BASE_ADDR 0xC904
+#define CP_HPD_EOP_BASE_ADDR_HI 0xC908
+#define CP_HPD_EOP_VMID 0xC90C
+#define CP_HPD_EOP_CONTROL 0xC910
+#define EOP_SIZE(x) ((x) << 0)
+#define EOP_SIZE_MASK (0x3f << 0)
+#define CP_MQD_BASE_ADDR 0xC914
+#define CP_MQD_BASE_ADDR_HI 0xC918
+#define CP_HQD_ACTIVE 0xC91C
+#define CP_HQD_VMID 0xC920
+
+#define CP_HQD_PQ_BASE 0xC934
+#define CP_HQD_PQ_BASE_HI 0xC938
+#define CP_HQD_PQ_RPTR 0xC93C
+#define CP_HQD_PQ_RPTR_REPORT_ADDR 0xC940
+#define CP_HQD_PQ_RPTR_REPORT_ADDR_HI 0xC944
+#define CP_HQD_PQ_WPTR_POLL_ADDR 0xC948
+#define CP_HQD_PQ_WPTR_POLL_ADDR_HI 0xC94C
+#define CP_HQD_PQ_DOORBELL_CONTROL 0xC950
+#define DOORBELL_OFFSET(x) ((x) << 2)
+#define DOORBELL_OFFSET_MASK (0x1fffff << 2)
+#define DOORBELL_SOURCE (1 << 28)
+#define DOORBELL_SCHD_HIT (1 << 29)
+#define DOORBELL_EN (1 << 30)
+#define DOORBELL_HIT (1 << 31)
+#define CP_HQD_PQ_WPTR 0xC954
+#define CP_HQD_PQ_CONTROL 0xC958
+#define QUEUE_SIZE(x) ((x) << 0)
+#define QUEUE_SIZE_MASK (0x3f << 0)
+#define RPTR_BLOCK_SIZE(x) ((x) << 8)
+#define RPTR_BLOCK_SIZE_MASK (0x3f << 8)
+#define PQ_VOLATILE (1 << 26)
+#define NO_UPDATE_RPTR (1 << 27)
+#define UNORD_DISPATCH (1 << 28)
+#define ROQ_PQ_IB_FLIP (1 << 29)
+#define PRIV_STATE (1 << 30)
+#define KMD_QUEUE (1 << 31)
+
+#define CP_HQD_DEQUEUE_REQUEST 0xC974
+
+#define CP_MQD_CONTROL 0xC99C
+#define MQD_VMID(x) ((x) << 0)
+#define MQD_VMID_MASK (0xf << 0)
+
+#define PA_SC_RASTER_CONFIG 0x28350
+# define RASTER_CONFIG_RB_MAP_0 0
+# define RASTER_CONFIG_RB_MAP_1 1
+# define RASTER_CONFIG_RB_MAP_2 2
+# define RASTER_CONFIG_RB_MAP_3 3
+
+#define VGT_EVENT_INITIATOR 0x28a90
+# define SAMPLE_STREAMOUTSTATS1 (1 << 0)
+# define SAMPLE_STREAMOUTSTATS2 (2 << 0)
+# define SAMPLE_STREAMOUTSTATS3 (3 << 0)
+# define CACHE_FLUSH_TS (4 << 0)
+# define CACHE_FLUSH (6 << 0)
+# define CS_PARTIAL_FLUSH (7 << 0)
+# define VGT_STREAMOUT_RESET (10 << 0)
+# define END_OF_PIPE_INCR_DE (11 << 0)
+# define END_OF_PIPE_IB_END (12 << 0)
+# define RST_PIX_CNT (13 << 0)
+# define VS_PARTIAL_FLUSH (15 << 0)
+# define PS_PARTIAL_FLUSH (16 << 0)
+# define CACHE_FLUSH_AND_INV_TS_EVENT (20 << 0)
+# define ZPASS_DONE (21 << 0)
+# define CACHE_FLUSH_AND_INV_EVENT (22 << 0)
+# define PERFCOUNTER_START (23 << 0)
+# define PERFCOUNTER_STOP (24 << 0)
+# define PIPELINESTAT_START (25 << 0)
+# define PIPELINESTAT_STOP (26 << 0)
+# define PERFCOUNTER_SAMPLE (27 << 0)
+# define SAMPLE_PIPELINESTAT (30 << 0)
+# define SO_VGT_STREAMOUT_FLUSH (31 << 0)
+# define SAMPLE_STREAMOUTSTATS (32 << 0)
+# define RESET_VTX_CNT (33 << 0)
+# define VGT_FLUSH (36 << 0)
+# define BOTTOM_OF_PIPE_TS (40 << 0)
+# define DB_CACHE_FLUSH_AND_INV (42 << 0)
+# define FLUSH_AND_INV_DB_DATA_TS (43 << 0)
+# define FLUSH_AND_INV_DB_META (44 << 0)
+# define FLUSH_AND_INV_CB_DATA_TS (45 << 0)
+# define FLUSH_AND_INV_CB_META (46 << 0)
+# define CS_DONE (47 << 0)
+# define PS_DONE (48 << 0)
+# define FLUSH_AND_INV_CB_PIXEL_DATA (49 << 0)
+# define THREAD_TRACE_START (51 << 0)
+# define THREAD_TRACE_STOP (52 << 0)
+# define THREAD_TRACE_FLUSH (54 << 0)
+# define THREAD_TRACE_FINISH (55 << 0)
+# define PIXEL_PIPE_STAT_CONTROL (56 << 0)
+# define PIXEL_PIPE_STAT_DUMP (57 << 0)
+# define PIXEL_PIPE_STAT_RESET (58 << 0)
+
+#define SCRATCH_REG0 0x30100
+#define SCRATCH_REG1 0x30104
+#define SCRATCH_REG2 0x30108
+#define SCRATCH_REG3 0x3010C
+#define SCRATCH_REG4 0x30110
+#define SCRATCH_REG5 0x30114
+#define SCRATCH_REG6 0x30118
+#define SCRATCH_REG7 0x3011C
+
+#define SCRATCH_UMSK 0x30140
+#define SCRATCH_ADDR 0x30144
+
+#define CP_SEM_WAIT_TIMER 0x301BC
+
+#define CP_SEM_INCOMPLETE_TIMER_CNTL 0x301C8
+
+#define CP_WAIT_REG_MEM_TIMEOUT 0x301D0
+
+#define GRBM_GFX_INDEX 0x30800
+#define INSTANCE_INDEX(x) ((x) << 0)
+#define SH_INDEX(x) ((x) << 8)
+#define SE_INDEX(x) ((x) << 16)
+#define SH_BROADCAST_WRITES (1 << 29)
+#define INSTANCE_BROADCAST_WRITES (1 << 30)
+#define SE_BROADCAST_WRITES (1 << 31)
+
+#define VGT_ESGS_RING_SIZE 0x30900
+#define VGT_GSVS_RING_SIZE 0x30904
+#define VGT_PRIMITIVE_TYPE 0x30908
+#define VGT_INDEX_TYPE 0x3090C
+
+#define VGT_NUM_INDICES 0x30930
+#define VGT_NUM_INSTANCES 0x30934
+#define VGT_TF_RING_SIZE 0x30938
+#define VGT_HS_OFFCHIP_PARAM 0x3093C
+#define VGT_TF_MEMORY_BASE 0x30940
+
+#define PA_SU_LINE_STIPPLE_VALUE 0x30a00
+#define PA_SC_LINE_STIPPLE_STATE 0x30a04
+
+#define SQC_CACHES 0x30d20
+
+#define CP_PERFMON_CNTL 0x36020
+
+#define CGTS_TCC_DISABLE 0x3c00c
+#define CGTS_USER_TCC_DISABLE 0x3c010
+#define TCC_DISABLE_MASK 0xFFFF0000
+#define TCC_DISABLE_SHIFT 16
+
+#define CB_CGTT_SCLK_CTRL 0x3c2a0
+
+/*
+ * 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) << 2)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \
+ (((reg) >> 2) & 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_CACHE_POLICY(x) ((x) << 25)
+ /* 0 - LRU
+ * 1 - Stream
+ * 2 - Bypass
+ */
+#define EOP_TCL2_VOLATILE (1 << 27)
+#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
+#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 0x00008000
+#define PACKET3_SET_CONFIG_REG_END 0x0000b000
+#define PACKET3_SET_CONTEXT_REG 0x69
+#define PACKET3_SET_CONTEXT_REG_START 0x00028000
+#define PACKET3_SET_CONTEXT_REG_END 0x00029000
+#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73
+#define PACKET3_SET_SH_REG 0x76
+#define PACKET3_SET_SH_REG_START 0x0000b000
+#define PACKET3_SET_SH_REG_END 0x0000c000
+#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 0x00030000
+#define PACKET3_SET_UCONFIG_REG_END 0x00031000
+#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 0x800 /* not a register */
+
+#define SDMA0_UCODE_ADDR 0xD000
+#define SDMA0_UCODE_DATA 0xD004
+
+#define SDMA0_CNTL 0xD010
+# define TRAP_ENABLE (1 << 0)
+# define SEM_INCOMPLETE_INT_ENABLE (1 << 1)
+# define SEM_WAIT_INT_ENABLE (1 << 2)
+# define DATA_SWAP_ENABLE (1 << 3)
+# define FENCE_SWAP_ENABLE (1 << 4)
+# define AUTO_CTXSW_ENABLE (1 << 18)
+# define CTXEMPTY_INT_ENABLE (1 << 28)
+
+#define SDMA0_TILING_CONFIG 0xD018
+
+#define SDMA0_SEM_INCOMPLETE_TIMER_CNTL 0xD020
+#define SDMA0_SEM_WAIT_FAIL_TIMER_CNTL 0xD024
+
+#define SDMA0_STATUS_REG 0xd034
+# define SDMA_IDLE (1 << 0)
+
+#define SDMA0_ME_CNTL 0xD048
+# define SDMA_HALT (1 << 0)
+
+#define SDMA0_GFX_RB_CNTL 0xD200
+# define SDMA_RB_ENABLE (1 << 0)
+# define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */
+# define SDMA_RB_SWAP_ENABLE (1 << 9) /* 8IN32 */
+# define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12)
+# define SDMA_RPTR_WRITEBACK_SWAP_ENABLE (1 << 13) /* 8IN32 */
+# define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */
+#define SDMA0_GFX_RB_BASE 0xD204
+#define SDMA0_GFX_RB_BASE_HI 0xD208
+#define SDMA0_GFX_RB_RPTR 0xD20C
+#define SDMA0_GFX_RB_WPTR 0xD210
+
+#define SDMA0_GFX_RB_RPTR_ADDR_HI 0xD220
+#define SDMA0_GFX_RB_RPTR_ADDR_LO 0xD224
+#define SDMA0_GFX_IB_CNTL 0xD228
+# define SDMA_IB_ENABLE (1 << 0)
+# define SDMA_IB_SWAP_ENABLE (1 << 4)
+# define SDMA_SWITCH_INSIDE_IB (1 << 8)
+# define SDMA_CMD_VMID(x) ((x) << 16)
+
+#define SDMA0_GFX_VIRTUAL_ADDR 0xD29C
+#define SDMA0_GFX_APE1_CNTL 0xD2A0
+
+#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 */
+
+/* UVD */
+
+#define UVD_UDEC_ADDR_CONFIG 0xef4c
+#define UVD_UDEC_DB_ADDR_CONFIG 0xef50
+#define UVD_UDEC_DBW_ADDR_CONFIG 0xef54
+
+#define UVD_LMI_EXT40_ADDR 0xf498
+#define UVD_LMI_ADDR_EXT 0xf594
+#define UVD_VCPU_CACHE_OFFSET0 0xf608
+#define UVD_VCPU_CACHE_SIZE0 0xf60c
+#define UVD_VCPU_CACHE_OFFSET1 0xf610
+#define UVD_VCPU_CACHE_SIZE1 0xf614
+#define UVD_VCPU_CACHE_OFFSET2 0xf618
+#define UVD_VCPU_CACHE_SIZE2 0xf61c
+
+#define UVD_RBC_RB_RPTR 0xf690
+#define UVD_RBC_RB_WPTR 0xf694
+
+/* UVD clocks */
+
+#define CG_DCLK_CNTL 0xC050009C
+# define DCLK_DIVIDER_MASK 0x7f
+# define DCLK_DIR_CNTL_EN (1 << 8)
+#define CG_DCLK_STATUS 0xC05000A0
+# define DCLK_STATUS (1 << 0)
+#define CG_VCLK_CNTL 0xC05000A4
+#define CG_VCLK_STATUS 0xC05000A8
+
+#endif
diff --git a/drivers/gpu/drm/radeon/clearstate_cayman.h b/drivers/gpu/drm/radeon/clearstate_cayman.h
new file mode 100644
index 000000000000..c00339440c5e
--- /dev/null
+++ b/drivers/gpu/drm/radeon/clearstate_cayman.h
@@ -0,0 +1,1081 @@
+/*
+ * 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.
+ *
+ */
+
+static const u32 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
+ 0, // HOLE
+ 0, // HOLE
+ 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
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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, // SQ_ALU_CONST_BUFFER_SIZE_PS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_15
+ 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
+ 0x00000000, // SX_MISC
+ 0x00000000, // SX_SURFACE_SYNC
+ 0x00000000, // SX_SCATTER_EXPORT_BASE
+ 0x00000000, // SX_SCATTER_EXPORT_SIZE
+ 0x00000000, // CP_PERFMON_CNTX_CNTL
+ 0x00000000, // CP_RINGID
+ 0x00000000, // CP_VMID
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_VTX_SEMANTIC_0
+ 0x00000000, // SQ_VTX_SEMANTIC_1
+ 0x00000000, // SQ_VTX_SEMANTIC_2
+ 0x00000000, // SQ_VTX_SEMANTIC_3
+ 0x00000000, // SQ_VTX_SEMANTIC_4
+ 0x00000000, // SQ_VTX_SEMANTIC_5
+ 0x00000000, // SQ_VTX_SEMANTIC_6
+ 0x00000000, // SQ_VTX_SEMANTIC_7
+ 0x00000000, // SQ_VTX_SEMANTIC_8
+ 0x00000000, // SQ_VTX_SEMANTIC_9
+ 0x00000000, // SQ_VTX_SEMANTIC_10
+ 0x00000000, // SQ_VTX_SEMANTIC_11
+ 0x00000000, // SQ_VTX_SEMANTIC_12
+ 0x00000000, // SQ_VTX_SEMANTIC_13
+ 0x00000000, // SQ_VTX_SEMANTIC_14
+ 0x00000000, // SQ_VTX_SEMANTIC_15
+ 0x00000000, // SQ_VTX_SEMANTIC_16
+ 0x00000000, // SQ_VTX_SEMANTIC_17
+ 0x00000000, // SQ_VTX_SEMANTIC_18
+ 0x00000000, // SQ_VTX_SEMANTIC_19
+ 0x00000000, // SQ_VTX_SEMANTIC_20
+ 0x00000000, // SQ_VTX_SEMANTIC_21
+ 0x00000000, // SQ_VTX_SEMANTIC_22
+ 0x00000000, // SQ_VTX_SEMANTIC_23
+ 0x00000000, // SQ_VTX_SEMANTIC_24
+ 0x00000000, // SQ_VTX_SEMANTIC_25
+ 0x00000000, // SQ_VTX_SEMANTIC_26
+ 0x00000000, // SQ_VTX_SEMANTIC_27
+ 0x00000000, // SQ_VTX_SEMANTIC_28
+ 0x00000000, // SQ_VTX_SEMANTIC_29
+ 0x00000000, // SQ_VTX_SEMANTIC_30
+ 0x00000000, // SQ_VTX_SEMANTIC_31
+ 0xffffffff, // VGT_MAX_VTX_INDX
+ 0x00000000, // VGT_MIN_VTX_INDX
+ 0x00000000, // VGT_INDX_OFFSET
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+ 0x00000000, // SX_ALPHA_TEST_CONTROL
+ 0x00000000, // CB_BLEND_RED
+ 0x00000000, // CB_BLEND_GREEN
+ 0x00000000, // CB_BLEND_BLUE
+ 0x00000000, // CB_BLEND_ALPHA
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // DB_STENCILREFMASK
+ 0x00000000, // DB_STENCILREFMASK_BF
+ 0x00000000, // SX_ALPHA_REF
+ 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
+ 0x00000000, // SPI_VS_OUT_ID_0
+ 0x00000000, // SPI_VS_OUT_ID_1
+ 0x00000000, // SPI_VS_OUT_ID_2
+ 0x00000000, // SPI_VS_OUT_ID_3
+ 0x00000000, // SPI_VS_OUT_ID_4
+ 0x00000000, // SPI_VS_OUT_ID_5
+ 0x00000000, // SPI_VS_OUT_ID_6
+ 0x00000000, // SPI_VS_OUT_ID_7
+ 0x00000000, // SPI_VS_OUT_ID_8
+ 0x00000000, // SPI_VS_OUT_ID_9
+ 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
+ 0x00000001, // SPI_THREAD_GROUPING
+ 0x00000002, // SPI_PS_IN_CONTROL_0
+ 0x00000000, // SPI_PS_IN_CONTROL_1
+ 0x00000000, // SPI_INTERP_CONTROL_0
+ 0x00000000, // SPI_INPUT_Z
+ 0x00000000, // SPI_FOG_CNTL
+ 0x00000000, // SPI_BARYC_CNTL
+ 0x00000000, // SPI_PS_IN_CONTROL_2
+ 0x00000000, // SPI_COMPUTE_INPUT_CNTL
+ 0x00000000, // SPI_COMPUTE_NUM_THREAD_X
+ 0x00000000, // SPI_COMPUTE_NUM_THREAD_Y
+ 0x00000000, // SPI_COMPUTE_NUM_THREAD_Z
+ 0x00000000, // SPI_GPR_MGMT
+ 0x00000000, // SPI_LDS_MGMT
+ 0x00000000, // SPI_STACK_MGMT
+ 0x00000000, // SPI_WAVE_MGMT_1
+ 0x00000000, // SPI_WAVE_MGMT_2
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // GDS_ADDR_BASE
+ 0x00003fff, // GDS_ADDR_SIZE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // GDS_ORDERED_COUNT
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // GDS_APPEND_CONSUME_UAV0
+ 0x00000000, // GDS_APPEND_CONSUME_UAV1
+ 0x00000000, // GDS_APPEND_CONSUME_UAV2
+ 0x00000000, // GDS_APPEND_CONSUME_UAV3
+ 0x00000000, // GDS_APPEND_CONSUME_UAV4
+ 0x00000000, // GDS_APPEND_CONSUME_UAV5
+ 0x00000000, // GDS_APPEND_CONSUME_UAV6
+ 0x00000000, // GDS_APPEND_CONSUME_UAV7
+ 0x00000000, // GDS_APPEND_CONSUME_UAV8
+ 0x00000000, // GDS_APPEND_CONSUME_UAV9
+ 0x00000000, // GDS_APPEND_CONSUME_UAV10
+ 0x00000000, // GDS_APPEND_CONSUME_UAV11
+ 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 u32 SECT_CONTEXT_def_2[] =
+{
+ 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 u32 SECT_CONTEXT_def_3[] =
+{
+ 0x00000000, // DB_DEPTH_CONTROL
+ 0x00000000, // DB_EQAA
+ 0x00000000, // CB_COLOR_CONTROL
+ 0x00000200, // DB_SHADER_CONTROL
+ 0x00000000, // PA_CL_CLIP_CNTL
+ 0x00000000, // 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
+ 0x00000000, // SQ_LSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_HSTMP_RING_ITEMSIZE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_PS
+ 0x00000000, // SQ_PGM_RESOURCES_PS
+ 0x00000000, // SQ_PGM_RESOURCES_2_PS
+ 0x00000000, // SQ_PGM_EXPORTS_PS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_VS
+ 0x00000000, // SQ_PGM_RESOURCES_VS
+ 0x00000000, // SQ_PGM_RESOURCES_2_VS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_GS
+ 0x00000000, // SQ_PGM_RESOURCES_GS
+ 0x00000000, // SQ_PGM_RESOURCES_2_GS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_ES
+ 0x00000000, // SQ_PGM_RESOURCES_ES
+ 0x00000000, // SQ_PGM_RESOURCES_2_ES
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_FS
+ 0x00000000, // SQ_PGM_RESOURCES_FS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_HS
+ 0x00000000, // SQ_PGM_RESOURCES_HS
+ 0x00000000, // SQ_PGM_RESOURCES_2_HS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_LS
+ 0x00000000, // SQ_PGM_RESOURCES_LS
+ 0x00000000, // SQ_PGM_RESOURCES_2_LS
+};
+static const u32 SECT_CONTEXT_def_4[] =
+{
+ 0x00000000, // SQ_LDS_ALLOC
+ 0x00000000, // SQ_LDS_ALLOC_PS
+ 0x00000000, // SQ_VTX_SEMANTIC_CLEAR
+ 0, // HOLE
+ 0x00000000, // SQ_THREAD_TRACE_CTRL
+ 0, // HOLE
+ 0x00000000, // SQ_ESGS_RING_ITEMSIZE
+ 0x00000000, // SQ_GSVS_RING_ITEMSIZE
+ 0x00000000, // SQ_ESTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_GSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_VSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_PSTMP_RING_ITEMSIZE
+ 0, // HOLE
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE_1
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE_2
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE_3
+ 0x00000000, // SQ_GSVS_RING_OFFSET_1
+ 0x00000000, // SQ_GSVS_RING_OFFSET_2
+ 0x00000000, // SQ_GSVS_RING_OFFSET_3
+ 0x00000000, // SQ_GWS_RING_OFFSET
+ 0, // HOLE
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_15
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_15
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_15
+ 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
+ 0, // HOLE
+ 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
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_GS_OUT_PRIM_TYPE
+ 0x00000000, // IA_ENHANCE
+};
+static const u32 SECT_CONTEXT_def_5[] =
+{
+ 0x00000000, // VGT_DMA_MAX_SIZE
+ 0x00000000, // VGT_DMA_INDEX_TYPE
+ 0, // HOLE
+ 0x00000000, // VGT_PRIMITIVEID_EN
+ 0x00000000, // VGT_DMA_NUM_INSTANCES
+};
+static const u32 SECT_CONTEXT_def_6[] =
+{
+ 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
+ 0, // HOLE
+ 0, // HOLE
+ 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
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_0
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_3
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_0
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_1
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_2
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_3
+ 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
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_0
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_1
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_2
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_3
+ 0x00000000, // VGT_SHADER_STAGES_EN
+ 0x00000000, // VGT_LS_HS_CONFIG
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_TF_PARAM
+ 0x00000000, // DB_ALPHA_TO_MASK
+};
+static const u32 SECT_CONTEXT_def_7[] =
+{
+ 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
+ 0x00000000, // CB_IMMED0_BASE
+ 0x00000000, // CB_IMMED1_BASE
+ 0x00000000, // CB_IMMED2_BASE
+ 0x00000000, // CB_IMMED3_BASE
+ 0x00000000, // CB_IMMED4_BASE
+ 0x00000000, // CB_IMMED5_BASE
+ 0x00000000, // CB_IMMED6_BASE
+ 0x00000000, // CB_IMMED7_BASE
+ 0x00000000, // CB_IMMED8_BASE
+ 0x00000000, // CB_IMMED9_BASE
+ 0x00000000, // CB_IMMED10_BASE
+ 0x00000000, // CB_IMMED11_BASE
+ 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
+ 0x00000000, // CB_CLRCMP_CONTROL
+ 0x00000000, // CB_CLRCMP_SRC
+ 0x00000000, // CB_CLRCMP_DST
+ 0x00000000, // CB_CLRCMP_MSK
+ 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
+ 0x00000000, // CB_COLOR0_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR0_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR1_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR2_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR3_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR4_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR5_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR6_CLEAR_WORD3
+ 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_DIM
+ 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
+ 0x00000000, // CB_COLOR7_CLEAR_WORD2
+ 0x00000000, // CB_COLOR7_CLEAR_WORD3
+ 0x00000000, // CB_COLOR8_BASE
+ 0x00000000, // CB_COLOR8_PITCH
+ 0x00000000, // CB_COLOR8_SLICE
+ 0x00000000, // CB_COLOR8_VIEW
+ 0x00000000, // CB_COLOR8_INFO
+ 0x00000000, // CB_COLOR8_ATTRIB
+ 0x00000000, // CB_COLOR8_DIM
+ 0x00000000, // CB_COLOR9_BASE
+ 0x00000000, // CB_COLOR9_PITCH
+ 0x00000000, // CB_COLOR9_SLICE
+ 0x00000000, // CB_COLOR9_VIEW
+ 0x00000000, // CB_COLOR9_INFO
+ 0x00000000, // CB_COLOR9_ATTRIB
+ 0x00000000, // CB_COLOR9_DIM
+ 0x00000000, // CB_COLOR10_BASE
+ 0x00000000, // CB_COLOR10_PITCH
+ 0x00000000, // CB_COLOR10_SLICE
+ 0x00000000, // CB_COLOR10_VIEW
+ 0x00000000, // CB_COLOR10_INFO
+ 0x00000000, // CB_COLOR10_ATTRIB
+ 0x00000000, // CB_COLOR10_DIM
+ 0x00000000, // CB_COLOR11_BASE
+ 0x00000000, // CB_COLOR11_PITCH
+ 0x00000000, // CB_COLOR11_SLICE
+ 0x00000000, // CB_COLOR11_VIEW
+ 0x00000000, // CB_COLOR11_INFO
+ 0x00000000, // CB_COLOR11_ATTRIB
+ 0x00000000, // CB_COLOR11_DIM
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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, // SQ_ALU_CONST_CACHE_HS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_15
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_15
+};
+static const struct cs_extent_def SECT_CONTEXT_defs[] =
+{
+ {SECT_CONTEXT_def_1, 0x0000a000, 488 },
+ {SECT_CONTEXT_def_2, 0x0000a1f5, 6 },
+ {SECT_CONTEXT_def_3, 0x0000a200, 55 },
+ {SECT_CONTEXT_def_4, 0x0000a23a, 99 },
+ {SECT_CONTEXT_def_5, 0x0000a29e, 5 },
+ {SECT_CONTEXT_def_6, 0x0000a2a5, 56 },
+ {SECT_CONTEXT_def_7, 0x0000a2de, 290 },
+ { 0, 0, 0 }
+};
+static const u32 SECT_CLEAR_def_1[] =
+{
+ 0xffffffff, // SQ_TEX_SAMPLER_CLEAR
+ 0xffffffff, // SQ_TEX_RESOURCE_CLEAR
+ 0xffffffff, // SQ_LOOP_BOOL_CLEAR
+};
+static const struct cs_extent_def SECT_CLEAR_defs[] =
+{
+ {SECT_CLEAR_def_1, 0x0000ffc0, 3 },
+ { 0, 0, 0 }
+};
+static const u32 SECT_CTRLCONST_def_1[] =
+{
+ 0x00000000, // SQ_VTX_BASE_VTX_LOC
+ 0x00000000, // SQ_VTX_START_INST_LOC
+};
+static const struct cs_extent_def SECT_CTRLCONST_defs[] =
+{
+ {SECT_CTRLCONST_def_1, 0x0000f3fc, 2 },
+ { 0, 0, 0 }
+};
+struct cs_section_def cayman_cs_data[] = {
+ { SECT_CONTEXT_defs, SECT_CONTEXT },
+ { SECT_CLEAR_defs, SECT_CLEAR },
+ { SECT_CTRLCONST_defs, SECT_CTRLCONST },
+ { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/radeon/clearstate_defs.h b/drivers/gpu/drm/radeon/clearstate_defs.h
new file mode 100644
index 000000000000..3eda707d7388
--- /dev/null
+++ b/drivers/gpu/drm/radeon/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/radeon/clearstate_evergreen.h b/drivers/gpu/drm/radeon/clearstate_evergreen.h
new file mode 100644
index 000000000000..4791d856b7fd
--- /dev/null
+++ b/drivers/gpu/drm/radeon/clearstate_evergreen.h
@@ -0,0 +1,1080 @@
+/*
+ * 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.
+ *
+ */
+
+static const u32 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
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // DB_STENCIL_CLEAR
+ 0x00000000, // DB_DEPTH_CLEAR
+ 0x00000000, // PA_SC_SCREEN_SCISSOR_TL
+ 0x40004000, // PA_SC_SCREEN_SCISSOR_BR
+ 0, // HOLE
+ 0, // HOLE
+ 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
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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, // SQ_ALU_CONST_BUFFER_SIZE_PS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_PS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_VS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_GS_15
+ 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
+ 0x00000000, // SX_MISC
+ 0x00000000, // SX_SURFACE_SYNC
+ 0x00000000, // CP_PERFMON_CNTX_CNTL
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_VTX_SEMANTIC_0
+ 0x00000000, // SQ_VTX_SEMANTIC_1
+ 0x00000000, // SQ_VTX_SEMANTIC_2
+ 0x00000000, // SQ_VTX_SEMANTIC_3
+ 0x00000000, // SQ_VTX_SEMANTIC_4
+ 0x00000000, // SQ_VTX_SEMANTIC_5
+ 0x00000000, // SQ_VTX_SEMANTIC_6
+ 0x00000000, // SQ_VTX_SEMANTIC_7
+ 0x00000000, // SQ_VTX_SEMANTIC_8
+ 0x00000000, // SQ_VTX_SEMANTIC_9
+ 0x00000000, // SQ_VTX_SEMANTIC_10
+ 0x00000000, // SQ_VTX_SEMANTIC_11
+ 0x00000000, // SQ_VTX_SEMANTIC_12
+ 0x00000000, // SQ_VTX_SEMANTIC_13
+ 0x00000000, // SQ_VTX_SEMANTIC_14
+ 0x00000000, // SQ_VTX_SEMANTIC_15
+ 0x00000000, // SQ_VTX_SEMANTIC_16
+ 0x00000000, // SQ_VTX_SEMANTIC_17
+ 0x00000000, // SQ_VTX_SEMANTIC_18
+ 0x00000000, // SQ_VTX_SEMANTIC_19
+ 0x00000000, // SQ_VTX_SEMANTIC_20
+ 0x00000000, // SQ_VTX_SEMANTIC_21
+ 0x00000000, // SQ_VTX_SEMANTIC_22
+ 0x00000000, // SQ_VTX_SEMANTIC_23
+ 0x00000000, // SQ_VTX_SEMANTIC_24
+ 0x00000000, // SQ_VTX_SEMANTIC_25
+ 0x00000000, // SQ_VTX_SEMANTIC_26
+ 0x00000000, // SQ_VTX_SEMANTIC_27
+ 0x00000000, // SQ_VTX_SEMANTIC_28
+ 0x00000000, // SQ_VTX_SEMANTIC_29
+ 0x00000000, // SQ_VTX_SEMANTIC_30
+ 0x00000000, // SQ_VTX_SEMANTIC_31
+ 0xffffffff, // VGT_MAX_VTX_INDX
+ 0x00000000, // VGT_MIN_VTX_INDX
+ 0x00000000, // VGT_INDX_OFFSET
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_INDX
+ 0x00000000, // SX_ALPHA_TEST_CONTROL
+ 0x00000000, // CB_BLEND_RED
+ 0x00000000, // CB_BLEND_GREEN
+ 0x00000000, // CB_BLEND_BLUE
+ 0x00000000, // CB_BLEND_ALPHA
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // DB_STENCILREFMASK
+ 0x00000000, // DB_STENCILREFMASK_BF
+ 0x00000000, // SX_ALPHA_REF
+ 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
+ 0x00000000, // SPI_VS_OUT_ID_0
+ 0x00000000, // SPI_VS_OUT_ID_1
+ 0x00000000, // SPI_VS_OUT_ID_2
+ 0x00000000, // SPI_VS_OUT_ID_3
+ 0x00000000, // SPI_VS_OUT_ID_4
+ 0x00000000, // SPI_VS_OUT_ID_5
+ 0x00000000, // SPI_VS_OUT_ID_6
+ 0x00000000, // SPI_VS_OUT_ID_7
+ 0x00000000, // SPI_VS_OUT_ID_8
+ 0x00000000, // SPI_VS_OUT_ID_9
+ 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
+ 0x00000001, // SPI_THREAD_GROUPING
+ 0x00000000, // SPI_PS_IN_CONTROL_0
+ 0x00000000, // SPI_PS_IN_CONTROL_1
+ 0x00000000, // SPI_INTERP_CONTROL_0
+ 0x00000000, // SPI_INPUT_Z
+ 0x00000000, // SPI_FOG_CNTL
+ 0x00000000, // SPI_BARYC_CNTL
+ 0x00000000, // SPI_PS_IN_CONTROL_2
+ 0x00000000, // SPI_COMPUTE_INPUT_CNTL
+ 0x00000000, // SPI_COMPUTE_NUM_THREAD_X
+ 0x00000000, // SPI_COMPUTE_NUM_THREAD_Y
+ 0x00000000, // SPI_COMPUTE_NUM_THREAD_Z
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // GDS_ADDR_BASE
+ 0x00003fff, // GDS_ADDR_SIZE
+ 0x00000001, // GDS_ORDERED_WAVE_PER_SE
+ 0x00000000, // GDS_APPEND_CONSUME_UAV0
+ 0x00000000, // GDS_APPEND_CONSUME_UAV1
+ 0x00000000, // GDS_APPEND_CONSUME_UAV2
+ 0x00000000, // GDS_APPEND_CONSUME_UAV3
+ 0x00000000, // GDS_APPEND_CONSUME_UAV4
+ 0x00000000, // GDS_APPEND_CONSUME_UAV5
+ 0x00000000, // GDS_APPEND_CONSUME_UAV6
+ 0x00000000, // GDS_APPEND_CONSUME_UAV7
+ 0x00000000, // GDS_APPEND_CONSUME_UAV8
+ 0x00000000, // GDS_APPEND_CONSUME_UAV9
+ 0x00000000, // GDS_APPEND_CONSUME_UAV10
+ 0x00000000, // GDS_APPEND_CONSUME_UAV11
+ 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 u32 SECT_CONTEXT_def_2[] =
+{
+ 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 u32 SECT_CONTEXT_def_3[] =
+{
+ 0x00000000, // DB_DEPTH_CONTROL
+ 0, // HOLE
+ 0x00000000, // CB_COLOR_CONTROL
+ 0x00000200, // DB_SHADER_CONTROL
+ 0x00000000, // PA_CL_CLIP_CNTL
+ 0x00000000, // 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
+ 0x00000000, // SQ_LSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_HSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_DYN_GPR_RESOURCE_LIMIT_1
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_PS
+ 0x00000000, // SQ_PGM_RESOURCES_PS
+ 0x00000000, // SQ_PGM_RESOURCES_2_PS
+ 0x00000000, // SQ_PGM_EXPORTS_PS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_VS
+ 0x00000000, // SQ_PGM_RESOURCES_VS
+ 0x00000000, // SQ_PGM_RESOURCES_2_VS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_GS
+ 0x00000000, // SQ_PGM_RESOURCES_GS
+ 0x00000000, // SQ_PGM_RESOURCES_2_GS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_ES
+ 0x00000000, // SQ_PGM_RESOURCES_ES
+ 0x00000000, // SQ_PGM_RESOURCES_2_ES
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_FS
+ 0x00000000, // SQ_PGM_RESOURCES_FS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_HS
+ 0x00000000, // SQ_PGM_RESOURCES_HS
+ 0x00000000, // SQ_PGM_RESOURCES_2_HS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_PGM_START_LS
+ 0x00000000, // SQ_PGM_RESOURCES_LS
+ 0x00000000, // SQ_PGM_RESOURCES_2_LS
+};
+static const u32 SECT_CONTEXT_def_4[] =
+{
+ 0x00000000, // SQ_LDS_ALLOC
+ 0x00000000, // SQ_LDS_ALLOC_PS
+ 0x00000000, // SQ_VTX_SEMANTIC_CLEAR
+ 0, // HOLE
+ 0x00000000, // SQ_THREAD_TRACE_CTRL
+ 0, // HOLE
+ 0x00000000, // SQ_ESGS_RING_ITEMSIZE
+ 0x00000000, // SQ_GSVS_RING_ITEMSIZE
+ 0x00000000, // SQ_ESTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_GSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_VSTMP_RING_ITEMSIZE
+ 0x00000000, // SQ_PSTMP_RING_ITEMSIZE
+ 0, // HOLE
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE_1
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE_2
+ 0x00000000, // SQ_GS_VERT_ITEMSIZE_3
+ 0x00000000, // SQ_GSVS_RING_OFFSET_1
+ 0x00000000, // SQ_GSVS_RING_OFFSET_2
+ 0x00000000, // SQ_GSVS_RING_OFFSET_3
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_PS_15
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_VS_15
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_GS_15
+ 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
+ 0, // HOLE
+ 0x00000000, // PA_SC_MODE_CNTL_0
+ 0x00000000, // PA_SC_MODE_CNTL_1
+ 0x00000000, // VGT_ENHANCE
+ 0x00000000, // VGT_GS_PER_ES
+ 0x00000000, // VGT_ES_PER_GS
+ 0x00000000, // VGT_GS_PER_VS
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_GS_OUT_PRIM_TYPE
+};
+static const u32 SECT_CONTEXT_def_5[] =
+{
+ 0x00000000, // VGT_DMA_MAX_SIZE
+ 0x00000000, // VGT_DMA_INDEX_TYPE
+ 0, // HOLE
+ 0x00000000, // VGT_PRIMITIVEID_EN
+ 0x00000000, // VGT_DMA_NUM_INSTANCES
+};
+static const u32 SECT_CONTEXT_def_6[] =
+{
+ 0x00000000, // VGT_MULTI_PRIM_IB_RESET_EN
+ 0, // HOLE
+ 0, // HOLE
+ 0x00000000, // VGT_INSTANCE_STEP_RATE_0
+ 0x00000000, // VGT_INSTANCE_STEP_RATE_1
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_0
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_0
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_1
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_1
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_2
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_2
+ 0x00000000, // VGT_STRMOUT_BUFFER_SIZE_3
+ 0x00000000, // VGT_STRMOUT_VTX_STRIDE_3
+ 0x00000000, // VGT_STRMOUT_BUFFER_BASE_3
+ 0x00000000, // VGT_STRMOUT_BUFFER_OFFSET_3
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_0
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_1
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_2
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_3
+ 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
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_0
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_1
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_2
+ 0x00000000, // VGT_STRMOUT_BASE_OFFSET_HI_3
+ 0x00000000, // VGT_SHADER_STAGES_EN
+ 0x00000000, // VGT_LS_HS_CONFIG
+ 0x00000000, // VGT_LS_SIZE
+ 0x00000000, // VGT_HS_SIZE
+ 0x00000000, // VGT_LS_HS_ALLOC
+ 0x00000000, // VGT_HS_PATCH_CONST
+ 0x00000000, // VGT_TF_PARAM
+ 0x00000000, // DB_ALPHA_TO_MASK
+};
+static const u32 SECT_CONTEXT_def_7[] =
+{
+ 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
+ 0x00000000, // CB_IMMED0_BASE
+ 0x00000000, // CB_IMMED1_BASE
+ 0x00000000, // CB_IMMED2_BASE
+ 0x00000000, // CB_IMMED3_BASE
+ 0x00000000, // CB_IMMED4_BASE
+ 0x00000000, // CB_IMMED5_BASE
+ 0x00000000, // CB_IMMED6_BASE
+ 0x00000000, // CB_IMMED7_BASE
+ 0x00000000, // CB_IMMED8_BASE
+ 0x00000000, // CB_IMMED9_BASE
+ 0x00000000, // CB_IMMED10_BASE
+ 0x00000000, // CB_IMMED11_BASE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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_0
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_1
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_2
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_3
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_4
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_5
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_6
+ 0x00000000, // PA_SC_AA_SAMPLE_LOCS_7
+ 0xffffffff, // PA_SC_AA_MASK
+ 0x00000000, // CB_CLRCMP_CONTROL
+ 0x00000000, // CB_CLRCMP_SRC
+ 0x00000000, // CB_CLRCMP_DST
+ 0x00000000, // CB_CLRCMP_MSK
+ 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
+ 0x00000000, // CB_COLOR0_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR0_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR1_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR2_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR3_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR4_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR5_CLEAR_WORD3
+ 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_DIM
+ 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_CLEAR_WORD2
+ 0x00000000, // CB_COLOR6_CLEAR_WORD3
+ 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_DIM
+ 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
+ 0x00000000, // CB_COLOR7_CLEAR_WORD2
+ 0x00000000, // CB_COLOR7_CLEAR_WORD3
+ 0x00000000, // CB_COLOR8_BASE
+ 0x00000000, // CB_COLOR8_PITCH
+ 0x00000000, // CB_COLOR8_SLICE
+ 0x00000000, // CB_COLOR8_VIEW
+ 0x00000000, // CB_COLOR8_INFO
+ 0x00000000, // CB_COLOR8_ATTRIB
+ 0x00000000, // CB_COLOR8_DIM
+ 0x00000000, // CB_COLOR9_BASE
+ 0x00000000, // CB_COLOR9_PITCH
+ 0x00000000, // CB_COLOR9_SLICE
+ 0x00000000, // CB_COLOR9_VIEW
+ 0x00000000, // CB_COLOR9_INFO
+ 0x00000000, // CB_COLOR9_ATTRIB
+ 0x00000000, // CB_COLOR9_DIM
+ 0x00000000, // CB_COLOR10_BASE
+ 0x00000000, // CB_COLOR10_PITCH
+ 0x00000000, // CB_COLOR10_SLICE
+ 0x00000000, // CB_COLOR10_VIEW
+ 0x00000000, // CB_COLOR10_INFO
+ 0x00000000, // CB_COLOR10_ATTRIB
+ 0x00000000, // CB_COLOR10_DIM
+ 0x00000000, // CB_COLOR11_BASE
+ 0x00000000, // CB_COLOR11_PITCH
+ 0x00000000, // CB_COLOR11_SLICE
+ 0x00000000, // CB_COLOR11_VIEW
+ 0x00000000, // CB_COLOR11_INFO
+ 0x00000000, // CB_COLOR11_ATTRIB
+ 0x00000000, // CB_COLOR11_DIM
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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, // SQ_ALU_CONST_CACHE_HS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_HS_15
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_0
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_1
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_2
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_3
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_4
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_5
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_6
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_7
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_8
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_9
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_10
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_11
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_12
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_13
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_14
+ 0x00000000, // SQ_ALU_CONST_CACHE_LS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_HS_15
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_0
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_1
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_2
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_3
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_4
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_5
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_6
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_7
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_8
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_9
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_10
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_11
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_12
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_13
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_14
+ 0x00000000, // SQ_ALU_CONST_BUFFER_SIZE_LS_15
+};
+static const struct cs_extent_def SECT_CONTEXT_defs[] =
+{
+ {SECT_CONTEXT_def_1, 0x0000a000, 488 },
+ {SECT_CONTEXT_def_2, 0x0000a1f5, 6 },
+ {SECT_CONTEXT_def_3, 0x0000a200, 55 },
+ {SECT_CONTEXT_def_4, 0x0000a23a, 98 },
+ {SECT_CONTEXT_def_5, 0x0000a29e, 5 },
+ {SECT_CONTEXT_def_6, 0x0000a2a5, 56 },
+ {SECT_CONTEXT_def_7, 0x0000a2de, 290 },
+ { 0, 0, 0 }
+};
+static const u32 SECT_CLEAR_def_1[] =
+{
+ 0xffffffff, // SQ_TEX_SAMPLER_CLEAR
+ 0xffffffff, // SQ_TEX_RESOURCE_CLEAR
+ 0xffffffff, // SQ_LOOP_BOOL_CLEAR
+};
+static const struct cs_extent_def SECT_CLEAR_defs[] =
+{
+ {SECT_CLEAR_def_1, 0x0000ffc0, 3 },
+ { 0, 0, 0 }
+};
+static const u32 SECT_CTRLCONST_def_1[] =
+{
+ 0x00000000, // SQ_VTX_BASE_VTX_LOC
+ 0x00000000, // SQ_VTX_START_INST_LOC
+};
+static const struct cs_extent_def SECT_CTRLCONST_defs[] =
+{
+ {SECT_CTRLCONST_def_1, 0x0000f3fc, 2 },
+ { 0, 0, 0 }
+};
+struct cs_section_def evergreen_cs_data[] = {
+ { SECT_CONTEXT_defs, SECT_CONTEXT },
+ { SECT_CLEAR_defs, SECT_CLEAR },
+ { SECT_CTRLCONST_defs, SECT_CTRLCONST },
+ { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/radeon/clearstate_si.h b/drivers/gpu/drm/radeon/clearstate_si.h
new file mode 100644
index 000000000000..b994cb2a35a0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/clearstate_si.h
@@ -0,0 +1,941 @@
+/*
+ * 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 u32 si_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
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 0, // HOLE
+ 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_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 u32 si_SECT_CONTEXT_def_2[] =
+{
+ 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
+ 0x00000000, // SPI_WAVE_MGMT_1
+ 0x00000000, // SPI_WAVE_MGMT_2
+ 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 u32 si_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 u32 si_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
+ 0, // HOLE
+ 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 u32 si_SECT_CONTEXT_def_5[] =
+{
+ 0x00000000, // VGT_PRIMITIVEID_EN
+};
+static const u32 si_SECT_CONTEXT_def_6[] =
+{
+ 0x00000000, // VGT_PRIMITIVEID_RESET
+};
+static const u32 si_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 si_SECT_CONTEXT_defs[] =
+{
+ {si_SECT_CONTEXT_def_1, 0x0000a000, 212 },
+ {si_SECT_CONTEXT_def_2, 0x0000a0d8, 272 },
+ {si_SECT_CONTEXT_def_3, 0x0000a1f5, 6 },
+ {si_SECT_CONTEXT_def_4, 0x0000a200, 157 },
+ {si_SECT_CONTEXT_def_5, 0x0000a2a1, 1 },
+ {si_SECT_CONTEXT_def_6, 0x0000a2a3, 1 },
+ {si_SECT_CONTEXT_def_7, 0x0000a2a5, 233 },
+ { 0, 0, 0 }
+};
+static const struct cs_section_def si_cs_data[] = {
+ { si_SECT_CONTEXT_defs, SECT_CONTEXT },
+ { 0, SECT_NONE }
+};
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
new file mode 100644
index 000000000000..9bcdd174780f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -0,0 +1,2189 @@
+/*
+ * 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 "radeon.h"
+#include "evergreend.h"
+#include "r600_dpm.h"
+#include "cypress_dpm.h"
+#include "atom.h"
+
+#define SMC_RAM_END 0x8000
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0 0x05
+#define MC_CG_SEQ_DRAMCONF_S1 0x06
+#define MC_CG_SEQ_YCLK_SUSPEND 0x04
+#define MC_CG_SEQ_YCLK_RESUME 0x0a
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+
+static void cypress_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp, bif;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ if (enable) {
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+ if (!pi->boot_in_gen2) {
+ bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+ bif |= CG_CLIENT_REQ(0xd);
+ WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+ tmp |= LC_GEN2_EN_STRAP;
+
+ tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ udelay(10);
+ tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ }
+ }
+ } else {
+ if (!pi->boot_in_gen2) {
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp &= ~LC_GEN2_EN_STRAP;
+ }
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ }
+}
+
+static void cypress_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ cypress_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+#if 0
+static int cypress_enter_ulp_state(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (pi->gfx_clock_gating) {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+
+ RREG32(GB_ADDR_CONFIG);
+ }
+
+ WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
+ ~HOST_SMC_MSG_MASK);
+
+ udelay(7000);
+
+ return 0;
+}
+#endif
+
+static void cypress_gfx_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (enable) {
+ if (eg_pi->light_sleep) {
+ WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+ WREG32_CG(CG_CGLS_TILE_0, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_1, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_2, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_3, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_4, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_5, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_6, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_7, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_8, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_9, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_10, 0xFFFFFFFF);
+ WREG32_CG(CG_CGLS_TILE_11, 0xFFFFFFFF);
+
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_LIGHT_SLEEP_EN, ~DYN_LIGHT_SLEEP_EN);
+ }
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+ } else {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+ RREG32(GB_ADDR_CONFIG);
+
+ if (eg_pi->light_sleep) {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_LIGHT_SLEEP_EN);
+
+ WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+ WREG32_CG(CG_CGLS_TILE_0, 0);
+ WREG32_CG(CG_CGLS_TILE_1, 0);
+ WREG32_CG(CG_CGLS_TILE_2, 0);
+ WREG32_CG(CG_CGLS_TILE_3, 0);
+ WREG32_CG(CG_CGLS_TILE_4, 0);
+ WREG32_CG(CG_CGLS_TILE_5, 0);
+ WREG32_CG(CG_CGLS_TILE_6, 0);
+ WREG32_CG(CG_CGLS_TILE_7, 0);
+ WREG32_CG(CG_CGLS_TILE_8, 0);
+ WREG32_CG(CG_CGLS_TILE_9, 0);
+ WREG32_CG(CG_CGLS_TILE_10, 0);
+ WREG32_CG(CG_CGLS_TILE_11, 0);
+ }
+ }
+}
+
+static void cypress_mg_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (enable) {
+ u32 cgts_sm_ctrl_reg;
+
+ if (rdev->family == CHIP_CEDAR)
+ cgts_sm_ctrl_reg = CEDAR_MGCGCGTSSMCTRL_DFLT;
+ else if (rdev->family == CHIP_REDWOOD)
+ cgts_sm_ctrl_reg = REDWOOD_MGCGCGTSSMCTRL_DFLT;
+ else
+ cgts_sm_ctrl_reg = CYPRESS_MGCGCGTSSMCTRL_DFLT;
+
+ WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+ WREG32_CG(CG_CGTT_LOCAL_0, CYPRESS_MGCGTTLOCAL0_DFLT);
+ WREG32_CG(CG_CGTT_LOCAL_1, CYPRESS_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF);
+ WREG32_CG(CG_CGTT_LOCAL_2, CYPRESS_MGCGTTLOCAL2_DFLT);
+ WREG32_CG(CG_CGTT_LOCAL_3, CYPRESS_MGCGTTLOCAL3_DFLT);
+
+ if (pi->mgcgtssm)
+ WREG32(CGTS_SM_CTRL_REG, cgts_sm_ctrl_reg);
+
+ if (eg_pi->mcls) {
+ WREG32_P(MC_CITF_MISC_RD_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(MC_CITF_MISC_WR_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(MC_CITF_MISC_VM_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(MC_HUB_MISC_HUB_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(MC_HUB_MISC_VM_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(MC_HUB_MISC_SIP_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(MC_XPB_CLK_GAT, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ WREG32_P(VM_L2_CG, MEM_LS_ENABLE, ~MEM_LS_ENABLE);
+ }
+ } else {
+ WREG32(GRBM_GFX_INDEX, 0xC0000000);
+
+ WREG32_CG(CG_CGTT_LOCAL_0, 0xFFFFFFFF);
+ WREG32_CG(CG_CGTT_LOCAL_1, 0xFFFFFFFF);
+ WREG32_CG(CG_CGTT_LOCAL_2, 0xFFFFFFFF);
+ WREG32_CG(CG_CGTT_LOCAL_3, 0xFFFFFFFF);
+
+ if (pi->mgcgtssm)
+ WREG32(CGTS_SM_CTRL_REG, 0x81f44bc0);
+ }
+}
+
+void cypress_enable_spread_spectrum(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (enable) {
+ if (pi->sclk_ss)
+ WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+
+ if (pi->mclk_ss)
+ WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
+ } else {
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+ WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+ WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
+ WREG32_P(MPLL_CNTL_MODE, 0, ~SS_DSMODE_EN);
+ }
+}
+
+void cypress_start_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+void cypress_enable_sclk_control(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+ else
+ WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+}
+
+void cypress_enable_mclk_control(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+ else
+ WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+int cypress_notify_smc_display_change(struct radeon_device *rdev,
+ bool has_display)
+{
+ PPSMC_Msg msg = has_display ?
+ (PPSMC_Msg)PPSMC_MSG_HasDisplay : (PPSMC_Msg)PPSMC_MSG_NoDisplay;
+
+ if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+void cypress_program_response_times(struct radeon_device *rdev)
+{
+ u32 reference_clock;
+ u32 mclk_switch_limit;
+
+ reference_clock = radeon_get_xclk(rdev);
+ mclk_switch_limit = (460 * reference_clock) / 100;
+
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_mclk_switch_lim,
+ mclk_switch_limit);
+
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
+
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
+
+ rv770_program_response_times(rdev);
+
+ if (ASIC_IS_LOMBOK(rdev))
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_is_asic_lombok, 1);
+
+}
+
+static int cypress_pcie_performance_request(struct radeon_device *rdev,
+ u8 perf_req, bool advertise)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 tmp;
+
+ udelay(10);
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) && (tmp & LC_CURRENT_DATA_RATE))
+ return 0;
+
+#if defined(CONFIG_ACPI)
+ if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) ||
+ (perf_req == PCIE_PERF_REQ_PECI_GEN2)) {
+ eg_pi->pcie_performance_request_registered = true;
+ return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+ } else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) &&
+ eg_pi->pcie_performance_request_registered) {
+ eg_pi->pcie_performance_request_registered = false;
+ return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+ }
+#endif
+
+ return 0;
+}
+
+void cypress_advertise_gen2_capability(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp;
+
+#if defined(CONFIG_ACPI)
+ radeon_acpi_pcie_notify_device_ready(rdev);
+#endif
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+ pi->pcie_gen2 = true;
+ else
+ pi->pcie_gen2 = false;
+
+ if (!pi->pcie_gen2)
+ cypress_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true);
+
+}
+
+static enum radeon_pcie_gen cypress_get_maximum_link_speed(struct radeon_ps *radeon_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+
+ if (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+ return 1;
+ return 0;
+}
+
+void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ enum radeon_pcie_gen pcie_link_speed_target =
+ cypress_get_maximum_link_speed(radeon_new_state);
+ enum radeon_pcie_gen pcie_link_speed_current =
+ cypress_get_maximum_link_speed(radeon_current_state);
+ u8 request;
+
+ if (pcie_link_speed_target < pcie_link_speed_current) {
+ if (pcie_link_speed_target == RADEON_PCIE_GEN1)
+ request = PCIE_PERF_REQ_PECI_GEN1;
+ else if (pcie_link_speed_target == RADEON_PCIE_GEN2)
+ request = PCIE_PERF_REQ_PECI_GEN2;
+ else
+ request = PCIE_PERF_REQ_PECI_GEN3;
+
+ cypress_pcie_performance_request(rdev, request, false);
+ }
+}
+
+void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ enum radeon_pcie_gen pcie_link_speed_target =
+ cypress_get_maximum_link_speed(radeon_new_state);
+ enum radeon_pcie_gen pcie_link_speed_current =
+ cypress_get_maximum_link_speed(radeon_current_state);
+ u8 request;
+
+ if (pcie_link_speed_target > pcie_link_speed_current) {
+ if (pcie_link_speed_target == RADEON_PCIE_GEN1)
+ request = PCIE_PERF_REQ_PECI_GEN1;
+ else if (pcie_link_speed_target == RADEON_PCIE_GEN2)
+ request = PCIE_PERF_REQ_PECI_GEN2;
+ else
+ request = PCIE_PERF_REQ_PECI_GEN3;
+
+ cypress_pcie_performance_request(rdev, request, false);
+ }
+}
+
+static int cypress_populate_voltage_value(struct radeon_device *rdev,
+ struct atom_voltage_table *table,
+ u16 value, RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+ unsigned int i;
+
+ for (i = 0; i < table->count; i++) {
+ if (value <= table->entries[i].value) {
+ voltage->index = (u8)i;
+ voltage->value = cpu_to_be16(table->entries[i].value);
+ break;
+ }
+ }
+
+ if (i == table->count)
+ return -EINVAL;
+
+ return 0;
+}
+
+u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 result = 0;
+ bool strobe_mode = false;
+
+ if (pi->mem_gddr5) {
+ if (mclk <= pi->mclk_strobe_mode_threshold)
+ strobe_mode = true;
+ result = cypress_get_mclk_frequency_ratio(rdev, mclk, strobe_mode);
+
+ if (strobe_mode)
+ result |= SMC_STROBE_ENABLE;
+ }
+
+ return result;
+}
+
+u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
+{
+ u32 ref_clk = rdev->clock.mpll.reference_freq;
+ u32 vco = clkf * ref_clk;
+
+ /* 100 Mhz ref clk */
+ if (ref_clk == 10000) {
+ if (vco > 500000)
+ return 0xC6;
+ if (vco > 400000)
+ return 0x9D;
+ if (vco > 330000)
+ return 0x6C;
+ if (vco > 250000)
+ return 0x2B;
+ if (vco > 160000)
+ return 0x5B;
+ if (vco > 120000)
+ return 0x0A;
+ return 0x4B;
+ }
+
+ /* 27 Mhz ref clk */
+ if (vco > 250000)
+ return 0x8B;
+ if (vco > 200000)
+ return 0xCC;
+ if (vco > 150000)
+ return 0x9B;
+ return 0x6B;
+}
+
+static int cypress_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock,
+ RV7XX_SMC_MCLK_VALUE *mclk,
+ bool strobe_mode, bool dll_state_on)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ u32 mpll_ad_func_cntl =
+ pi->clk_regs.rv770.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl =
+ pi->clk_regs.rv770.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+ u32 mclk_pwrmgt_cntl =
+ pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+ u32 dll_cntl =
+ pi->clk_regs.rv770.dll_cntl;
+ u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
+ u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
+ struct atom_clock_dividers dividers;
+ u32 ibias;
+ u32 dll_speed;
+ int ret;
+ u32 mc_seq_misc7;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ memory_clock, strobe_mode, &dividers);
+ if (ret)
+ return ret;
+
+ if (!strobe_mode) {
+ mc_seq_misc7 = RREG32(MC_SEQ_MISC7);
+
+ if(mc_seq_misc7 & 0x8000000)
+ dividers.post_div = 1;
+ }
+
+ ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
+
+ mpll_ad_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_ad_func_cntl |= CLKR(dividers.ref_div);
+ mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+ mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
+ mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+ mpll_ad_func_cntl |= IBIAS(ibias);
+
+ if (dividers.vco_mode)
+ mpll_ad_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+ if (pi->mem_gddr5) {
+ mpll_dq_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_dq_func_cntl |= CLKR(dividers.ref_div);
+ mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+ mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
+ mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+ mpll_dq_func_cntl |= IBIAS(ibias);
+
+ if (strobe_mode)
+ mpll_dq_func_cntl &= ~PDNB;
+ else
+ mpll_dq_func_cntl |= PDNB;
+
+ if (dividers.vco_mode)
+ mpll_dq_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_dq_func_cntl_2 &= ~VCO_MODE;
+ }
+
+ if (pi->mclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = memory_clock * dividers.post_div;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+ u32 reference_clock = rdev->clock.mpll.reference_freq;
+ u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
+ u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+ u32 clk_v = ss.percentage *
+ (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
+
+ mpll_ss1 &= ~CLKV_MASK;
+ mpll_ss1 |= CLKV(clk_v);
+
+ mpll_ss2 &= ~CLKS_MASK;
+ mpll_ss2 |= CLKS(clk_s);
+ }
+ }
+
+ dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
+ memory_clock);
+
+ mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+ mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
+ if (dll_state_on)
+ mclk_pwrmgt_cntl |= (MRDCKA0_PDNB |
+ MRDCKA1_PDNB |
+ MRDCKB0_PDNB |
+ MRDCKB1_PDNB |
+ MRDCKC0_PDNB |
+ MRDCKC1_PDNB |
+ MRDCKD0_PDNB |
+ MRDCKD1_PDNB);
+ else
+ mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+ MRDCKA1_PDNB |
+ MRDCKB0_PDNB |
+ MRDCKB1_PDNB |
+ MRDCKC0_PDNB |
+ MRDCKC1_PDNB |
+ MRDCKD0_PDNB |
+ MRDCKD1_PDNB);
+
+ mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
+ mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+ mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+ mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
+ mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+ return 0;
+}
+
+u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
+ u32 memory_clock, bool strobe_mode)
+{
+ u8 mc_para_index;
+
+ if (rdev->family >= CHIP_BARTS) {
+ if (strobe_mode) {
+ if (memory_clock < 10000)
+ 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);
+ }
+ } else {
+ if (strobe_mode) {
+ if (memory_clock < 10000)
+ 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 < 40000)
+ mc_para_index = 0x00;
+ else if (memory_clock > 115000)
+ mc_para_index = 0x0f;
+ else
+ mc_para_index = (u8)((memory_clock - 40000) / 5000);
+ }
+ }
+ return mc_para_index;
+}
+
+static int cypress_populate_mvdd_value(struct radeon_device *rdev,
+ u32 mclk,
+ RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (!pi->mvdd_control) {
+ voltage->index = eg_pi->mvdd_high_index;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ return 0;
+ }
+
+ if (mclk <= pi->mvdd_split_frequency) {
+ voltage->index = eg_pi->mvdd_low_index;
+ voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+ } else {
+ voltage->index = eg_pi->mvdd_high_index;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ }
+
+ return 0;
+}
+
+int cypress_convert_power_level_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ RV770_SMC_HW_PERFORMANCE_LEVEL *level,
+ u8 watermark_level)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ int ret;
+ bool dll_state_on;
+
+ level->gen2PCIE = pi->pcie_gen2 ?
+ ((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
+ level->gen2XSP = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0;
+ level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0;
+ level->displayWatermark = watermark_level;
+
+ ret = rv740_populate_sclk_value(rdev, pl->sclk, &level->sclk);
+ if (ret)
+ return ret;
+
+ level->mcFlags = 0;
+ if (pi->mclk_stutter_mode_threshold &&
+ (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
+ !eg_pi->uvd_enabled) {
+ level->mcFlags |= SMC_MC_STUTTER_EN;
+ if (eg_pi->sclk_deep_sleep)
+ level->stateFlags |= PPSMC_STATEFLAG_AUTO_PULSE_SKIP;
+ else
+ level->stateFlags &= ~PPSMC_STATEFLAG_AUTO_PULSE_SKIP;
+ }
+
+ if (pi->mem_gddr5) {
+ if (pl->mclk > pi->mclk_edc_enable_threshold)
+ level->mcFlags |= SMC_MC_EDC_RD_FLAG;
+
+ if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
+ level->mcFlags |= SMC_MC_EDC_WR_FLAG;
+
+ level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk);
+
+ if (level->strobeMode & SMC_STROBE_ENABLE) {
+ if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >=
+ ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
+ dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+ else
+ dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+ } else
+ dll_state_on = eg_pi->dll_default_on;
+
+ ret = cypress_populate_mclk_value(rdev,
+ pl->sclk,
+ pl->mclk,
+ &level->mclk,
+ (level->strobeMode & SMC_STROBE_ENABLE) != 0,
+ dll_state_on);
+ } else {
+ ret = cypress_populate_mclk_value(rdev,
+ pl->sclk,
+ pl->mclk,
+ &level->mclk,
+ true,
+ true);
+ }
+ if (ret)
+ return ret;
+
+ ret = cypress_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ pl->vddc,
+ &level->vddc);
+ if (ret)
+ return ret;
+
+ if (eg_pi->vddci_control) {
+ ret = cypress_populate_voltage_value(rdev,
+ &eg_pi->vddci_voltage_table,
+ pl->vddci,
+ &level->vddci);
+ if (ret)
+ return ret;
+ }
+
+ ret = cypress_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+ return ret;
+}
+
+static int cypress_convert_power_state_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ int ret;
+
+ if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
+ smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ ret = cypress_convert_power_level_to_smc(rdev,
+ &state->low,
+ &smc_state->levels[0],
+ PPSMC_DISPLAY_WATERMARK_LOW);
+ if (ret)
+ return ret;
+
+ ret = cypress_convert_power_level_to_smc(rdev,
+ &state->medium,
+ &smc_state->levels[1],
+ PPSMC_DISPLAY_WATERMARK_LOW);
+ if (ret)
+ return ret;
+
+ ret = cypress_convert_power_level_to_smc(rdev,
+ &state->high,
+ &smc_state->levels[2],
+ PPSMC_DISPLAY_WATERMARK_HIGH);
+ if (ret)
+ return ret;
+
+ smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1;
+ smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2;
+ smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3;
+
+ if (eg_pi->dynamic_ac_timing) {
+ smc_state->levels[0].ACIndex = 2;
+ smc_state->levels[1].ACIndex = 3;
+ smc_state->levels[2].ACIndex = 4;
+ } else {
+ smc_state->levels[0].ACIndex = 0;
+ smc_state->levels[1].ACIndex = 0;
+ smc_state->levels[2].ACIndex = 0;
+ }
+
+ rv770_populate_smc_sp(rdev, radeon_state, smc_state);
+
+ return rv770_populate_smc_t(rdev, radeon_state, smc_state);
+}
+
+static void cypress_convert_mc_registers(struct evergreen_mc_reg_entry *entry,
+ SMC_Evergreen_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 cypress_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SMC_Evergreen_MCRegisterSet *mc_reg_table_data)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 i = 0;
+
+ for (i = 0; i < eg_pi->mc_reg_table.num_entries; i++) {
+ if (pl->mclk <=
+ eg_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+ break;
+ }
+
+ if ((i == eg_pi->mc_reg_table.num_entries) && (i > 0))
+ --i;
+
+ cypress_convert_mc_registers(&eg_pi->mc_reg_table.mc_reg_table_entry[i],
+ mc_reg_table_data,
+ eg_pi->mc_reg_table.last,
+ eg_pi->mc_reg_table.valid_flag);
+}
+
+static void cypress_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SMC_Evergreen_MCRegisters *mc_reg_table)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+
+ cypress_convert_mc_reg_table_entry_to_smc(rdev,
+ &state->low,
+ &mc_reg_table->data[2]);
+ cypress_convert_mc_reg_table_entry_to_smc(rdev,
+ &state->medium,
+ &mc_reg_table->data[3]);
+ cypress_convert_mc_reg_table_entry_to_smc(rdev,
+ &state->high,
+ &mc_reg_table->data[4]);
+}
+
+int cypress_upload_sw_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u16 address = pi->state_table_start +
+ offsetof(RV770_SMC_STATETABLE, driverState);
+ RV770_SMC_SWSTATE state = { 0 };
+ int ret;
+
+ ret = cypress_convert_power_state_to_smc(rdev, radeon_new_state, &state);
+ if (ret)
+ return ret;
+
+ return rv770_copy_bytes_to_smc(rdev, address, (u8 *)&state,
+ sizeof(RV770_SMC_SWSTATE),
+ pi->sram_end);
+}
+
+int cypress_upload_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ SMC_Evergreen_MCRegisters mc_reg_table = { 0 };
+ u16 address;
+
+ cypress_convert_mc_reg_table_to_smc(rdev, radeon_new_state, &mc_reg_table);
+
+ address = eg_pi->mc_reg_table_start +
+ (u16)offsetof(SMC_Evergreen_MCRegisters, data[2]);
+
+ return rv770_copy_bytes_to_smc(rdev, address,
+ (u8 *)&mc_reg_table.data[2],
+ sizeof(SMC_Evergreen_MCRegisterSet) * 3,
+ pi->sram_end);
+}
+
+u32 cypress_calculate_burst_time(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 multiplier = pi->mem_gddr5 ? 1 : 2;
+ u32 result = (4 * multiplier * engine_clock) / (memory_clock / 2);
+ u32 burst_time;
+
+ if (result <= 4)
+ burst_time = 0;
+ else if (result < 8)
+ burst_time = result - 4;
+ else {
+ burst_time = result / 2 ;
+ if (burst_time > 18)
+ burst_time = 18;
+ }
+
+ return burst_time;
+}
+
+void cypress_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
+ u32 mc_arb_burst_time = RREG32(MC_ARB_BURST_TIME);
+
+ mc_arb_burst_time &= ~(STATE1_MASK | STATE2_MASK | STATE3_MASK);
+
+ mc_arb_burst_time |= STATE1(cypress_calculate_burst_time(rdev,
+ new_state->low.sclk,
+ new_state->low.mclk));
+ mc_arb_burst_time |= STATE2(cypress_calculate_burst_time(rdev,
+ new_state->medium.sclk,
+ new_state->medium.mclk));
+ mc_arb_burst_time |= STATE3(cypress_calculate_burst_time(rdev,
+ new_state->high.sclk,
+ new_state->high.mclk));
+
+ rv730_program_memory_timing_parameters(rdev, radeon_new_state);
+
+ WREG32(MC_ARB_BURST_TIME, mc_arb_burst_time);
+}
+
+static void cypress_populate_mc_reg_addresses(struct radeon_device *rdev,
+ SMC_Evergreen_MCRegisters *mc_reg_table)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 i, j;
+
+ for (i = 0, j = 0; j < eg_pi->mc_reg_table.last; j++) {
+ if (eg_pi->mc_reg_table.valid_flag & (1 << j)) {
+ mc_reg_table->address[i].s0 =
+ cpu_to_be16(eg_pi->mc_reg_table.mc_reg_address[j].s0);
+ mc_reg_table->address[i].s1 =
+ cpu_to_be16(eg_pi->mc_reg_table.mc_reg_address[j].s1);
+ i++;
+ }
+ }
+
+ mc_reg_table->last = (u8)i;
+}
+
+static void cypress_set_mc_reg_address_table(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 i = 0;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RAS_TIMING_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RAS_TIMING >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_CAS_TIMING_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_CAS_TIMING >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC_TIMING_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC_TIMING >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC_TIMING2_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC_TIMING2 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RD_CTL_D0_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RD_CTL_D0 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RD_CTL_D1_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RD_CTL_D1 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_WR_CTL_D0_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_WR_CTL_D0 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_WR_CTL_D1_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_WR_CTL_D1 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_EMRS >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_MRS >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_PMG_CMD_MRS1 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC1 >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC1 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_RESERVE_M >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_RESERVE_M >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.mc_reg_address[i].s0 = MC_SEQ_MISC3 >> 2;
+ eg_pi->mc_reg_table.mc_reg_address[i].s1 = MC_SEQ_MISC3 >> 2;
+ i++;
+
+ eg_pi->mc_reg_table.last = (u8)i;
+}
+
+static void cypress_retrieve_ac_timing_for_one_entry(struct radeon_device *rdev,
+ struct evergreen_mc_reg_entry *entry)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 i;
+
+ for (i = 0; i < eg_pi->mc_reg_table.last; i++)
+ entry->mc_data[i] =
+ RREG32(eg_pi->mc_reg_table.mc_reg_address[i].s1 << 2);
+
+}
+
+static void cypress_retrieve_ac_timing_for_all_ranges(struct radeon_device *rdev,
+ struct atom_memory_clock_range_table *range_table)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 i, j;
+
+ for (i = 0; i < range_table->num_entries; i++) {
+ eg_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max =
+ range_table->mclk[i];
+ radeon_atom_set_ac_timing(rdev, range_table->mclk[i]);
+ cypress_retrieve_ac_timing_for_one_entry(rdev,
+ &eg_pi->mc_reg_table.mc_reg_table_entry[i]);
+ }
+
+ eg_pi->mc_reg_table.num_entries = range_table->num_entries;
+ eg_pi->mc_reg_table.valid_flag = 0;
+
+ for (i = 0; i < eg_pi->mc_reg_table.last; i++) {
+ for (j = 1; j < range_table->num_entries; j++) {
+ if (eg_pi->mc_reg_table.mc_reg_table_entry[j-1].mc_data[i] !=
+ eg_pi->mc_reg_table.mc_reg_table_entry[j].mc_data[i]) {
+ eg_pi->mc_reg_table.valid_flag |= (1 << i);
+ break;
+ }
+ }
+ }
+}
+
+static int cypress_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 module_index = rv770_get_memory_module_index(rdev);
+ struct atom_memory_clock_range_table range_table = { 0 };
+ int ret;
+
+ ret = radeon_atom_get_mclk_range_table(rdev,
+ pi->mem_gddr5,
+ module_index, &range_table);
+ if (ret)
+ return ret;
+
+ cypress_retrieve_ac_timing_for_all_ranges(rdev, &range_table);
+
+ return 0;
+}
+
+static void cypress_wait_for_mc_sequencer(struct radeon_device *rdev, u8 value)
+{
+ u32 i, j;
+ u32 channels = 2;
+
+ if ((rdev->family == CHIP_CYPRESS) ||
+ (rdev->family == CHIP_HEMLOCK))
+ channels = 4;
+ else if (rdev->family == CHIP_CEDAR)
+ channels = 1;
+
+ for (i = 0; i < channels; i++) {
+ if ((rdev->family == CHIP_CYPRESS) ||
+ (rdev->family == CHIP_HEMLOCK)) {
+ WREG32_P(MC_CONFIG_MCD, MC_RD_ENABLE_MCD(i), ~MC_RD_ENABLE_MCD_MASK);
+ WREG32_P(MC_CG_CONFIG_MCD, MC_RD_ENABLE_MCD(i), ~MC_RD_ENABLE_MCD_MASK);
+ } else {
+ WREG32_P(MC_CONFIG, MC_RD_ENABLE(i), ~MC_RD_ENABLE_MASK);
+ WREG32_P(MC_CG_CONFIG, MC_RD_ENABLE(i), ~MC_RD_ENABLE_MASK);
+ }
+ for (j = 0; j < rdev->usec_timeout; j++) {
+ if (((RREG32(MC_SEQ_CG) & CG_SEQ_RESP_MASK) >> CG_SEQ_RESP_SHIFT) == value)
+ break;
+ udelay(1);
+ }
+ }
+}
+
+static void cypress_force_mc_use_s1(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+ u32 strobe_mode;
+ u32 mc_seq_cg;
+ int i;
+
+ if (RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE)
+ return;
+
+ radeon_atom_set_ac_timing(rdev, boot_state->low.mclk);
+ radeon_mc_wait_for_idle(rdev);
+
+ if ((rdev->family == CHIP_CYPRESS) ||
+ (rdev->family == CHIP_HEMLOCK)) {
+ WREG32(MC_CONFIG_MCD, 0xf);
+ WREG32(MC_CG_CONFIG_MCD, 0xf);
+ } else {
+ WREG32(MC_CONFIG, 0xf);
+ WREG32(MC_CG_CONFIG, 0xf);
+ }
+
+ for (i = 0; i < rdev->num_crtc; i++)
+ radeon_wait_for_vblank(rdev, i);
+
+ WREG32(MC_SEQ_CG, MC_CG_SEQ_YCLK_SUSPEND);
+ cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_SUSPEND);
+
+ strobe_mode = cypress_get_strobe_mode_settings(rdev,
+ boot_state->low.mclk);
+
+ mc_seq_cg = CG_SEQ_REQ(MC_CG_SEQ_DRAMCONF_S1);
+ mc_seq_cg |= SEQ_CG_RESP(strobe_mode);
+ WREG32(MC_SEQ_CG, mc_seq_cg);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE)
+ break;
+ udelay(1);
+ }
+
+ mc_seq_cg &= ~CG_SEQ_REQ_MASK;
+ mc_seq_cg |= CG_SEQ_REQ(MC_CG_SEQ_YCLK_RESUME);
+ WREG32(MC_SEQ_CG, mc_seq_cg);
+
+ cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_RESUME);
+}
+
+static void cypress_copy_ac_timing_from_s1_to_s0(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 value;
+ u32 i;
+
+ for (i = 0; i < eg_pi->mc_reg_table.last; i++) {
+ value = RREG32(eg_pi->mc_reg_table.mc_reg_address[i].s1 << 2);
+ WREG32(eg_pi->mc_reg_table.mc_reg_address[i].s0 << 2, value);
+ }
+}
+
+static void cypress_force_mc_use_s0(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+ u32 strobe_mode;
+ u32 mc_seq_cg;
+ int i;
+
+ cypress_copy_ac_timing_from_s1_to_s0(rdev);
+ radeon_mc_wait_for_idle(rdev);
+
+ if ((rdev->family == CHIP_CYPRESS) ||
+ (rdev->family == CHIP_HEMLOCK)) {
+ WREG32(MC_CONFIG_MCD, 0xf);
+ WREG32(MC_CG_CONFIG_MCD, 0xf);
+ } else {
+ WREG32(MC_CONFIG, 0xf);
+ WREG32(MC_CG_CONFIG, 0xf);
+ }
+
+ for (i = 0; i < rdev->num_crtc; i++)
+ radeon_wait_for_vblank(rdev, i);
+
+ WREG32(MC_SEQ_CG, MC_CG_SEQ_YCLK_SUSPEND);
+ cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_SUSPEND);
+
+ strobe_mode = cypress_get_strobe_mode_settings(rdev,
+ boot_state->low.mclk);
+
+ mc_seq_cg = CG_SEQ_REQ(MC_CG_SEQ_DRAMCONF_S0);
+ mc_seq_cg |= SEQ_CG_RESP(strobe_mode);
+ WREG32(MC_SEQ_CG, mc_seq_cg);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32(MC_SEQ_STATUS_M) & PMG_PWRSTATE))
+ break;
+ udelay(1);
+ }
+
+ mc_seq_cg &= ~CG_SEQ_REQ_MASK;
+ mc_seq_cg |= CG_SEQ_REQ(MC_CG_SEQ_YCLK_RESUME);
+ WREG32(MC_SEQ_CG, mc_seq_cg);
+
+ cypress_wait_for_mc_sequencer(rdev, MC_CG_SEQ_YCLK_RESUME);
+}
+
+static int cypress_populate_initial_mvdd_value(struct radeon_device *rdev,
+ RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ voltage->index = eg_pi->mvdd_high_index;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+
+ return 0;
+}
+
+int cypress_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_initial_state,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_ps *initial_state = rv770_get_ps(radeon_initial_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 a_t;
+
+ table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2);
+ table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl);
+ table->initialState.levels[0].mclk.mclk770.vDLL_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.dll_cntl);
+
+ table->initialState.levels[0].mclk.mclk770.vMPLL_SS =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ss1);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ss2);
+
+ table->initialState.levels[0].mclk.mclk770.mclk_value =
+ cpu_to_be32(initial_state->low.mclk);
+
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2);
+
+ table->initialState.levels[0].sclk.sclk_value =
+ cpu_to_be32(initial_state->low.sclk);
+
+ table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+
+ table->initialState.levels[0].ACIndex = 0;
+
+ cypress_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ initial_state->low.vddc,
+ &table->initialState.levels[0].vddc);
+
+ if (eg_pi->vddci_control)
+ cypress_populate_voltage_value(rdev,
+ &eg_pi->vddci_voltage_table,
+ initial_state->low.vddci,
+ &table->initialState.levels[0].vddci);
+
+ cypress_populate_initial_mvdd_value(rdev,
+ &table->initialState.levels[0].mvdd);
+
+ a_t = CG_R(0xffff) | CG_L(0);
+ table->initialState.levels[0].aT = cpu_to_be32(a_t);
+
+ table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+
+ if (pi->boot_in_gen2)
+ table->initialState.levels[0].gen2PCIE = 1;
+ else
+ table->initialState.levels[0].gen2PCIE = 0;
+ if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+ table->initialState.levels[0].gen2XSP = 1;
+ else
+ table->initialState.levels[0].gen2XSP = 0;
+
+ if (pi->mem_gddr5) {
+ table->initialState.levels[0].strobeMode =
+ cypress_get_strobe_mode_settings(rdev,
+ initial_state->low.mclk);
+
+ if (initial_state->low.mclk > pi->mclk_edc_enable_threshold)
+ table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
+ else
+ table->initialState.levels[0].mcFlags = 0;
+ }
+
+ table->initialState.levels[1] = table->initialState.levels[0];
+ table->initialState.levels[2] = table->initialState.levels[0];
+
+ table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ return 0;
+}
+
+int cypress_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 mpll_ad_func_cntl =
+ pi->clk_regs.rv770.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl =
+ pi->clk_regs.rv770.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+ u32 spll_func_cntl =
+ pi->clk_regs.rv770.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 =
+ pi->clk_regs.rv770.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 =
+ pi->clk_regs.rv770.cg_spll_func_cntl_3;
+ u32 mclk_pwrmgt_cntl =
+ pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+ u32 dll_cntl =
+ pi->clk_regs.rv770.dll_cntl;
+
+ table->ACPIState = table->initialState;
+
+ table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc) {
+ cypress_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ pi->acpi_vddc,
+ &table->ACPIState.levels[0].vddc);
+ if (pi->pcie_gen2) {
+ if (pi->acpi_pcie_gen2)
+ table->ACPIState.levels[0].gen2PCIE = 1;
+ else
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ } else
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ if (pi->acpi_pcie_gen2)
+ table->ACPIState.levels[0].gen2XSP = 1;
+ else
+ table->ACPIState.levels[0].gen2XSP = 0;
+ } else {
+ cypress_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ pi->min_vddc_in_table,
+ &table->ACPIState.levels[0].vddc);
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ }
+
+ if (eg_pi->acpi_vddci) {
+ if (eg_pi->vddci_control) {
+ cypress_populate_voltage_value(rdev,
+ &eg_pi->vddci_voltage_table,
+ eg_pi->acpi_vddci,
+ &table->ACPIState.levels[0].vddci);
+ }
+ }
+
+ mpll_ad_func_cntl &= ~PDNB;
+
+ mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+ if (pi->mem_gddr5)
+ mpll_dq_func_cntl &= ~PDNB;
+ mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS;
+
+ mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
+ MRDCKA1_RESET |
+ MRDCKB0_RESET |
+ MRDCKB1_RESET |
+ MRDCKC0_RESET |
+ MRDCKC1_RESET |
+ MRDCKD0_RESET |
+ MRDCKD1_RESET);
+
+ mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+ MRDCKA1_PDNB |
+ MRDCKB0_PDNB |
+ MRDCKB1_PDNB |
+ MRDCKC0_PDNB |
+ MRDCKC1_PDNB |
+ MRDCKD0_PDNB |
+ MRDCKD1_PDNB);
+
+ dll_cntl |= (MRDCKA0_BYPASS |
+ MRDCKA1_BYPASS |
+ MRDCKB0_BYPASS |
+ MRDCKB1_BYPASS |
+ MRDCKC0_BYPASS |
+ MRDCKC1_BYPASS |
+ MRDCKD0_BYPASS |
+ MRDCKD1_BYPASS);
+
+ /* evergreen only */
+ if (rdev->family <= CHIP_HEMLOCK)
+ spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
+ cpu_to_be32(mpll_ad_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
+ cpu_to_be32(mpll_ad_func_cntl_2);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
+ cpu_to_be32(mpll_dq_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
+ cpu_to_be32(mpll_dq_func_cntl_2);
+ table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(mclk_pwrmgt_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+ table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
+
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(spll_func_cntl);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(spll_func_cntl_2);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(spll_func_cntl_3);
+
+ table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+ cypress_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+ if (eg_pi->dynamic_ac_timing)
+ table->ACPIState.levels[0].ACIndex = 1;
+
+ table->ACPIState.levels[1] = table->ACPIState.levels[0];
+ table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+ return 0;
+}
+
+static void cypress_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
+ struct atom_voltage_table *voltage_table)
+{
+ unsigned int i, diff;
+
+ if (voltage_table->count <= MAX_NO_VREG_STEPS)
+ return;
+
+ diff = voltage_table->count - MAX_NO_VREG_STEPS;
+
+ for (i= 0; i < MAX_NO_VREG_STEPS; i++)
+ voltage_table->entries[i] = voltage_table->entries[i + diff];
+
+ voltage_table->count = MAX_NO_VREG_STEPS;
+}
+
+int cypress_construct_voltage_tables(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ int ret;
+
+ ret = radeon_atom_get_voltage_table(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0,
+ &eg_pi->vddc_voltage_table);
+ if (ret)
+ return ret;
+
+ if (eg_pi->vddc_voltage_table.count > MAX_NO_VREG_STEPS)
+ cypress_trim_voltage_table_to_fit_state_table(rdev,
+ &eg_pi->vddc_voltage_table);
+
+ if (eg_pi->vddci_control) {
+ ret = radeon_atom_get_voltage_table(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0,
+ &eg_pi->vddci_voltage_table);
+ if (ret)
+ return ret;
+
+ if (eg_pi->vddci_voltage_table.count > MAX_NO_VREG_STEPS)
+ cypress_trim_voltage_table_to_fit_state_table(rdev,
+ &eg_pi->vddci_voltage_table);
+ }
+
+ return 0;
+}
+
+static void cypress_populate_smc_voltage_table(struct radeon_device *rdev,
+ struct atom_voltage_table *voltage_table,
+ RV770_SMC_STATETABLE *table)
+{
+ unsigned int i;
+
+ for (i = 0; i < voltage_table->count; i++) {
+ table->highSMIO[i] = 0;
+ table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
+ }
+}
+
+int cypress_populate_smc_voltage_tables(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ unsigned char i;
+
+ if (eg_pi->vddc_voltage_table.count) {
+ cypress_populate_smc_voltage_table(rdev,
+ &eg_pi->vddc_voltage_table,
+ table);
+
+ table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0;
+ table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] =
+ cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+
+ for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
+ if (pi->max_vddc_in_table <=
+ eg_pi->vddc_voltage_table.entries[i].value) {
+ table->maxVDDCIndexInPPTable = i;
+ break;
+ }
+ }
+ }
+
+ if (eg_pi->vddci_voltage_table.count) {
+ cypress_populate_smc_voltage_table(rdev,
+ &eg_pi->vddci_voltage_table,
+ table);
+
+ table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDCI] = 0;
+ table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDCI] =
+ cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+ }
+
+ return 0;
+}
+
+static u32 cypress_get_mclk_split_point(struct atom_memory_info *memory_info)
+{
+ if ((memory_info->mem_type == MEM_TYPE_GDDR3) ||
+ (memory_info->mem_type == MEM_TYPE_DDR3))
+ return 30000;
+
+ return 0;
+}
+
+int cypress_get_mvdd_configuration(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u8 module_index;
+ struct atom_memory_info memory_info;
+ u32 tmp = RREG32(GENERAL_PWRMGT);
+
+ if (!(tmp & BACKBIAS_PAD_EN)) {
+ eg_pi->mvdd_high_index = 0;
+ eg_pi->mvdd_low_index = 1;
+ pi->mvdd_control = false;
+ return 0;
+ }
+
+ if (tmp & BACKBIAS_VALUE)
+ eg_pi->mvdd_high_index = 1;
+ else
+ eg_pi->mvdd_high_index = 0;
+
+ eg_pi->mvdd_low_index =
+ (eg_pi->mvdd_high_index == 0) ? 1 : 0;
+
+ module_index = rv770_get_memory_module_index(rdev);
+
+ if (radeon_atom_get_memory_info(rdev, module_index, &memory_info)) {
+ pi->mvdd_control = false;
+ return 0;
+ }
+
+ pi->mvdd_split_frequency =
+ cypress_get_mclk_split_point(&memory_info);
+
+ if (pi->mvdd_split_frequency == 0) {
+ pi->mvdd_control = false;
+ return 0;
+ }
+
+ return 0;
+}
+
+static int cypress_init_smc_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ RV770_SMC_STATETABLE *table = &pi->smc_statetable;
+ int ret;
+
+ memset(table, 0, sizeof(RV770_SMC_STATETABLE));
+
+ cypress_populate_smc_voltage_tables(rdev, table);
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_EVERGREEN:
+ case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+ break;
+ case THERMAL_TYPE_NONE:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+ break;
+ default:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+ break;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (pi->mem_gddr5)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ ret = cypress_populate_smc_initial_state(rdev, radeon_boot_state, table);
+ if (ret)
+ return ret;
+
+ ret = cypress_populate_smc_acpi_state(rdev, table);
+ if (ret)
+ return ret;
+
+ table->driverState = table->initialState;
+
+ return rv770_copy_bytes_to_smc(rdev,
+ pi->state_table_start,
+ (u8 *)table, sizeof(RV770_SMC_STATETABLE),
+ pi->sram_end);
+}
+
+int cypress_populate_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+ SMC_Evergreen_MCRegisters mc_reg_table = { 0 };
+
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_seq_index, 1);
+
+ cypress_populate_mc_reg_addresses(rdev, &mc_reg_table);
+
+ cypress_convert_mc_reg_table_entry_to_smc(rdev,
+ &boot_state->low,
+ &mc_reg_table.data[0]);
+
+ cypress_convert_mc_registers(&eg_pi->mc_reg_table.mc_reg_table_entry[0],
+ &mc_reg_table.data[1], eg_pi->mc_reg_table.last,
+ eg_pi->mc_reg_table.valid_flag);
+
+ cypress_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, &mc_reg_table);
+
+ return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start,
+ (u8 *)&mc_reg_table, sizeof(SMC_Evergreen_MCRegisters),
+ pi->sram_end);
+}
+
+int cypress_get_table_locations(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION +
+ EVERGREEN_SMC_FIRMWARE_HEADER_stateTable,
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->state_table_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION +
+ EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters,
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ pi->soft_regs_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION +
+ EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable,
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ eg_pi->mc_reg_table_start = (u16)tmp;
+
+ return 0;
+}
+
+void cypress_enable_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+ tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+ tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+ DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
+ tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+ tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
+ DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void cypress_program_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp, pipe;
+ int i;
+
+ tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+ if (rdev->pm.dpm.new_active_crtc_count > 0)
+ tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+ else
+ tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+ if (rdev->pm.dpm.new_active_crtc_count > 1)
+ tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+ else
+ tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+
+ tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
+ pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;
+
+ if ((rdev->pm.dpm.new_active_crtc_count > 0) &&
+ (!(rdev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
+ /* find the first active crtc */
+ for (i = 0; i < rdev->num_crtc; i++) {
+ if (rdev->pm.dpm.new_active_crtcs & (1 << i))
+ break;
+ }
+ if (i == rdev->num_crtc)
+ pipe = 0;
+ else
+ pipe = i;
+
+ tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
+ tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
+ WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp);
+ }
+
+ cypress_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0);
+}
+
+void cypress_dpm_setup_asic(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ rv740_read_clock_registers(rdev);
+ rv770_read_voltage_smio_registers(rdev);
+ rv770_get_max_vddc(rdev);
+ rv770_get_memory_type(rdev);
+
+ if (eg_pi->pcie_performance_request)
+ eg_pi->pcie_performance_request_registered = false;
+
+ if (eg_pi->pcie_performance_request)
+ cypress_advertise_gen2_capability(rdev);
+
+ rv770_get_pcie_gen2_status(rdev);
+
+ rv770_enable_acpi_pm(rdev);
+}
+
+int cypress_dpm_enable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ if (pi->gfx_clock_gating)
+ rv770_restore_cgcg(rdev);
+
+ if (rv770_dpm_enabled(rdev))
+ return -EINVAL;
+
+ if (pi->voltage_control) {
+ rv770_enable_voltage_control(rdev, true);
+ ret = cypress_construct_voltage_tables(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_construct_voltage_tables failed\n");
+ return ret;
+ }
+ }
+
+ if (pi->mvdd_control) {
+ ret = cypress_get_mvdd_configuration(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_get_mvdd_configuration failed\n");
+ return ret;
+ }
+ }
+
+ if (eg_pi->dynamic_ac_timing) {
+ cypress_set_mc_reg_address_table(rdev);
+ cypress_force_mc_use_s0(rdev, boot_ps);
+ ret = cypress_initialize_mc_reg_table(rdev);
+ if (ret)
+ eg_pi->dynamic_ac_timing = false;
+ cypress_force_mc_use_s1(rdev, boot_ps);
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv770_enable_backbias(rdev, true);
+
+ if (pi->dynamic_ss)
+ cypress_enable_spread_spectrum(rdev, true);
+
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, true);
+
+ rv770_setup_bsp(rdev);
+ rv770_program_git(rdev);
+ rv770_program_tp(rdev);
+ rv770_program_tpp(rdev);
+ rv770_program_sstp(rdev);
+ rv770_program_engine_speed_parameters(rdev);
+ cypress_enable_display_gap(rdev);
+ rv770_program_vc(rdev);
+
+ if (pi->dynamic_pcie_gen2)
+ cypress_enable_dynamic_pcie_gen2(rdev, true);
+
+ ret = rv770_upload_firmware(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_upload_firmware failed\n");
+ return ret;
+ }
+
+ ret = cypress_get_table_locations(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_get_table_locations failed\n");
+ return ret;
+ }
+ ret = cypress_init_smc_table(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("cypress_init_smc_table failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = cypress_populate_mc_reg_table(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("cypress_populate_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+
+ cypress_program_response_times(rdev);
+
+ r7xx_start_smc(rdev);
+
+ ret = cypress_notify_smc_display_change(rdev, false);
+ if (ret) {
+ DRM_ERROR("cypress_notify_smc_display_change failed\n");
+ return ret;
+ }
+ cypress_enable_sclk_control(rdev, true);
+
+ if (eg_pi->memory_transition)
+ cypress_enable_mclk_control(rdev, true);
+
+ cypress_start_dpm(rdev);
+
+ if (pi->gfx_clock_gating)
+ cypress_gfx_clock_gating_enable(rdev, true);
+
+ if (pi->mg_clock_gating)
+ cypress_mg_clock_gating_enable(rdev, true);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ PPSMC_Result result;
+
+ ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+ if (result != PPSMC_Result_OK)
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+ }
+
+ rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ return 0;
+}
+
+void cypress_dpm_disable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+
+ if (!rv770_dpm_enabled(rdev))
+ return;
+
+ rv770_clear_vc(rdev);
+
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, false);
+
+ if (pi->dynamic_pcie_gen2)
+ cypress_enable_dynamic_pcie_gen2(rdev, false);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ if (pi->gfx_clock_gating)
+ cypress_gfx_clock_gating_enable(rdev, false);
+
+ if (pi->mg_clock_gating)
+ cypress_mg_clock_gating_enable(rdev, false);
+
+ rv770_stop_dpm(rdev);
+ r7xx_stop_smc(rdev);
+
+ cypress_enable_spread_spectrum(rdev, false);
+
+ if (eg_pi->dynamic_ac_timing)
+ cypress_force_mc_use_s1(rdev, boot_ps);
+
+ rv770_reset_smio_status(rdev);
+}
+
+int cypress_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+ struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+ int ret;
+
+ ret = rv770_restrict_performance_levels_before_switch(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n");
+ return ret;
+ }
+ if (eg_pi->pcie_performance_request)
+ cypress_notify_link_speed_change_before_state_change(rdev, new_ps, old_ps);
+
+ rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ ret = rv770_halt_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_halt_smc failed\n");
+ return ret;
+ }
+ ret = cypress_upload_sw_state(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("cypress_upload_sw_state failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = cypress_upload_mc_reg_table(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("cypress_upload_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+
+ cypress_program_memory_timing_parameters(rdev, new_ps);
+
+ ret = rv770_resume_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_resume_smc failed\n");
+ return ret;
+ }
+ ret = rv770_set_sw_state(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_set_sw_state failed\n");
+ return ret;
+ }
+ rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+
+ if (eg_pi->pcie_performance_request)
+ cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
+
+ ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
+ if (ret) {
+ DRM_ERROR("rv770_dpm_force_performance_level failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void cypress_dpm_reset_asic(struct radeon_device *rdev)
+{
+ rv770_restrict_performance_levels_before_switch(rdev);
+ rv770_set_boot_state(rdev);
+}
+
+void cypress_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+ cypress_program_display_gap(rdev);
+}
+
+int cypress_dpm_init(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi;
+ struct evergreen_power_info *eg_pi;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ uint16_t data_offset, size;
+ uint8_t frev, crev;
+ struct atom_clock_dividers dividers;
+ int ret;
+
+ eg_pi = kzalloc(sizeof(struct evergreen_power_info), GFP_KERNEL);
+ if (eg_pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = eg_pi;
+ pi = &eg_pi->rv7xx;
+
+ rv770_get_max_vddc(rdev);
+
+ eg_pi->ulv.supported = false;
+ pi->acpi_vddc = 0;
+ eg_pi->acpi_vddci = 0;
+ pi->min_vddc_in_table = 0;
+ pi->max_vddc_in_table = 0;
+
+ ret = rv7xx_parse_power_table(rdev);
+ if (ret)
+ return ret;
+
+ if (rdev->pm.dpm.voltage_response_time == 0)
+ rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+ if (rdev->pm.dpm.backbias_response_time == 0)
+ rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->ref_div = dividers.ref_div + 1;
+ else
+ pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ pi->mclk_strobe_mode_threshold = 40000;
+ pi->mclk_edc_enable_threshold = 40000;
+ eg_pi->mclk_edc_wr_enable_threshold = 40000;
+
+ pi->rlp = RV770_RLP_DFLT;
+ pi->rmp = RV770_RMP_DFLT;
+ pi->lhp = RV770_LHP_DFLT;
+ pi->lmp = RV770_LMP_DFLT;
+
+ pi->voltage_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0);
+
+ pi->mvdd_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
+
+ eg_pi->vddci_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->sclk_ss = true;
+ pi->mclk_ss = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->sclk_ss = false;
+ pi->mclk_ss = false;
+ pi->dynamic_ss = true;
+ }
+
+ pi->asi = RV770_ASI_DFLT;
+ pi->pasi = CYPRESS_HASI_DFLT;
+ pi->vrc = CYPRESS_VRC_DFLT;
+
+ pi->power_gating = false;
+
+ if ((rdev->family == CHIP_CYPRESS) ||
+ (rdev->family == CHIP_HEMLOCK))
+ pi->gfx_clock_gating = false;
+ else
+ pi->gfx_clock_gating = true;
+
+ pi->mg_clock_gating = true;
+ pi->mgcgtssm = true;
+ eg_pi->ls_clock_gating = false;
+ eg_pi->sclk_deep_sleep = false;
+
+ pi->dynamic_pcie_gen2 = true;
+
+ if (pi->gfx_clock_gating &&
+ (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ pi->display_gap = true;
+
+ if (rdev->flags & RADEON_IS_MOBILITY)
+ pi->dcodt = true;
+ else
+ pi->dcodt = false;
+
+ pi->ulps = true;
+
+ eg_pi->dynamic_ac_timing = true;
+ eg_pi->abm = true;
+ eg_pi->mcls = true;
+ eg_pi->light_sleep = true;
+ eg_pi->memory_transition = true;
+#if defined(CONFIG_ACPI)
+ eg_pi->pcie_performance_request =
+ radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+ eg_pi->pcie_performance_request = false;
+#endif
+
+ if ((rdev->family == CHIP_CYPRESS) ||
+ (rdev->family == CHIP_HEMLOCK) ||
+ (rdev->family == CHIP_JUNIPER))
+ eg_pi->dll_default_on = true;
+ else
+ eg_pi->dll_default_on = false;
+
+ eg_pi->sclk_deep_sleep = false;
+ pi->mclk_stutter_mode_threshold = 0;
+
+ pi->sram_end = SMC_RAM_END;
+
+ return 0;
+}
+
+void cypress_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+}
+
+bool cypress_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+ u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
+
+ if (vblank_time < switch_limit)
+ return true;
+ else
+ return false;
+
+}
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.h b/drivers/gpu/drm/radeon/cypress_dpm.h
new file mode 100644
index 000000000000..4c3f18c69f4f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/cypress_dpm.h
@@ -0,0 +1,160 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __CYPRESS_DPM_H__
+#define __CYPRESS_DPM_H__
+
+#include "rv770_dpm.h"
+#include "evergreen_smc.h"
+
+struct evergreen_mc_reg_entry {
+ u32 mclk_max;
+ u32 mc_data[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct evergreen_mc_reg_table {
+ u8 last;
+ u8 num_entries;
+ u16 valid_flag;
+ struct evergreen_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+ SMC_Evergreen_MCRegisterAddress mc_reg_address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct evergreen_ulv_param {
+ bool supported;
+ struct rv7xx_pl *pl;
+};
+
+struct evergreen_arb_registers {
+ u32 mc_arb_dram_timing;
+ u32 mc_arb_dram_timing2;
+ u32 mc_arb_rfsh_rate;
+ u32 mc_arb_burst_time;
+};
+
+struct at {
+ u32 rlp;
+ u32 rmp;
+ u32 lhp;
+ u32 lmp;
+};
+
+struct evergreen_power_info {
+ /* must be first! */
+ struct rv7xx_power_info rv7xx;
+ /* flags */
+ bool vddci_control;
+ bool dynamic_ac_timing;
+ bool abm;
+ bool mcls;
+ bool light_sleep;
+ bool memory_transition;
+ bool pcie_performance_request;
+ bool pcie_performance_request_registered;
+ bool sclk_deep_sleep;
+ bool dll_default_on;
+ bool ls_clock_gating;
+ bool smu_uvd_hs;
+ bool uvd_enabled;
+ /* stored values */
+ u16 acpi_vddci;
+ u8 mvdd_high_index;
+ u8 mvdd_low_index;
+ u32 mclk_edc_wr_enable_threshold;
+ struct evergreen_mc_reg_table mc_reg_table;
+ struct atom_voltage_table vddc_voltage_table;
+ struct atom_voltage_table vddci_voltage_table;
+ struct evergreen_arb_registers bootup_arb_registers;
+ struct evergreen_ulv_param ulv;
+ struct at ats[2];
+ /* smc offsets */
+ u16 mc_reg_table_start;
+ struct radeon_ps current_rps;
+ struct rv7xx_ps current_ps;
+ struct radeon_ps requested_rps;
+ struct rv7xx_ps requested_ps;
+};
+
+#define CYPRESS_HASI_DFLT 400000
+#define CYPRESS_MGCGTTLOCAL0_DFLT 0x00000000
+#define CYPRESS_MGCGTTLOCAL1_DFLT 0x00000000
+#define CYPRESS_MGCGTTLOCAL2_DFLT 0x00000000
+#define CYPRESS_MGCGTTLOCAL3_DFLT 0x00000000
+#define CYPRESS_MGCGCGTSSMCTRL_DFLT 0x81944bc0
+#define REDWOOD_MGCGCGTSSMCTRL_DFLT 0x6e944040
+#define CEDAR_MGCGCGTSSMCTRL_DFLT 0x46944040
+#define CYPRESS_VRC_DFLT 0xC00033
+
+#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
+
+int cypress_convert_power_level_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ RV770_SMC_HW_PERFORMANCE_LEVEL *level,
+ u8 watermark_level);
+int cypress_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table);
+int cypress_populate_smc_voltage_tables(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table);
+int cypress_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_initial_state,
+ RV770_SMC_STATETABLE *table);
+u32 cypress_calculate_burst_time(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock);
+void cypress_notify_link_speed_change_before_state_change(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state);
+int cypress_upload_sw_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state);
+int cypress_upload_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state);
+void cypress_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state);
+void cypress_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state);
+int cypress_construct_voltage_tables(struct radeon_device *rdev);
+int cypress_get_mvdd_configuration(struct radeon_device *rdev);
+void cypress_enable_spread_spectrum(struct radeon_device *rdev,
+ bool enable);
+void cypress_enable_display_gap(struct radeon_device *rdev);
+int cypress_get_table_locations(struct radeon_device *rdev);
+int cypress_populate_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state);
+void cypress_program_response_times(struct radeon_device *rdev);
+int cypress_notify_smc_display_change(struct radeon_device *rdev,
+ bool has_display);
+void cypress_enable_sclk_control(struct radeon_device *rdev,
+ bool enable);
+void cypress_enable_mclk_control(struct radeon_device *rdev,
+ bool enable);
+void cypress_start_dpm(struct radeon_device *rdev);
+void cypress_advertise_gen2_capability(struct radeon_device *rdev);
+u32 cypress_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf);
+u8 cypress_get_mclk_frequency_ratio(struct radeon_device *rdev,
+ u32 memory_clock, bool strobe_mode);
+u8 cypress_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 0f89ce3d02b9..e49059dc9b8f 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -33,9 +33,7 @@
#include "avivod.h"
#include "evergreen_reg.h"
#include "evergreen_blit_shaders.h"
-
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
+#include "radeon_ucode.h"
static const u32 crtc_offsets[6] =
{
@@ -47,9 +45,98 @@ static const u32 crtc_offsets[6] =
EVERGREEN_CRTC5_REGISTER_OFFSET
};
+#include "clearstate_evergreen.h"
+
+static u32 sumo_rlc_save_restore_register_list[] =
+{
+ 0x98fc,
+ 0x9830,
+ 0x9834,
+ 0x9838,
+ 0x9870,
+ 0x9874,
+ 0x8a14,
+ 0x8b24,
+ 0x8bcc,
+ 0x8b10,
+ 0x8d00,
+ 0x8d04,
+ 0x8c00,
+ 0x8c04,
+ 0x8c08,
+ 0x8c0c,
+ 0x8d8c,
+ 0x8c20,
+ 0x8c24,
+ 0x8c28,
+ 0x8c18,
+ 0x8c1c,
+ 0x8cf0,
+ 0x8e2c,
+ 0x8e38,
+ 0x8c30,
+ 0x9508,
+ 0x9688,
+ 0x9608,
+ 0x960c,
+ 0x9610,
+ 0x9614,
+ 0x88c4,
+ 0x88d4,
+ 0xa008,
+ 0x900c,
+ 0x9100,
+ 0x913c,
+ 0x98f8,
+ 0x98f4,
+ 0x9b7c,
+ 0x3f8c,
+ 0x8950,
+ 0x8954,
+ 0x8a18,
+ 0x8b28,
+ 0x9144,
+ 0x9148,
+ 0x914c,
+ 0x3f90,
+ 0x3f94,
+ 0x915c,
+ 0x9160,
+ 0x9178,
+ 0x917c,
+ 0x9180,
+ 0x918c,
+ 0x9190,
+ 0x9194,
+ 0x9198,
+ 0x919c,
+ 0x91a8,
+ 0x91ac,
+ 0x91b0,
+ 0x91b4,
+ 0x91b8,
+ 0x91c4,
+ 0x91c8,
+ 0x91cc,
+ 0x91d0,
+ 0x91d4,
+ 0x91e0,
+ 0x91e4,
+ 0x91ec,
+ 0x91f0,
+ 0x91f4,
+ 0x9200,
+ 0x9204,
+ 0x929c,
+ 0x9150,
+ 0x802c,
+};
+static u32 sumo_rlc_save_restore_register_list_size = ARRAY_SIZE(sumo_rlc_save_restore_register_list);
+
static void evergreen_gpu_init(struct radeon_device *rdev);
void evergreen_fini(struct radeon_device *rdev);
void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+void evergreen_program_aspm(struct radeon_device *rdev);
extern void cayman_cp_int_cntl_setup(struct radeon_device *rdev,
int ring, u32 cp_int_cntl);
@@ -1417,8 +1504,8 @@ void evergreen_pm_misc(struct radeon_device *rdev)
struct radeon_voltage *voltage = &ps->clock_info[req_cm_idx].voltage;
if (voltage->type == VOLTAGE_SW) {
- /* 0xff01 is a flag rather then an actual voltage */
- if (voltage->voltage == 0xff01)
+ /* 0xff0x are flags rather then an actual voltage */
+ if ((voltage->voltage & 0xff00) == 0xff00)
return;
if (voltage->voltage && (voltage->voltage != rdev->pm.current_vddc)) {
radeon_atom_set_voltage(rdev, voltage->voltage, SET_VOLTAGE_TYPE_ASIC_VDDC);
@@ -1438,8 +1525,8 @@ void evergreen_pm_misc(struct radeon_device *rdev)
voltage = &rdev->pm.power_state[req_ps_idx].
clock_info[rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx].voltage;
- /* 0xff01 is a flag rather then an actual voltage */
- if (voltage->vddci == 0xff01)
+ /* 0xff0x are flags rather then an actual voltage */
+ if ((voltage->vddci & 0xff00) == 0xff00)
return;
if (voltage->vddci && (voltage->vddci != rdev->pm.current_vddci)) {
radeon_atom_set_voltage(rdev, voltage->vddci, SET_VOLTAGE_TYPE_ASIC_VDDCI);
@@ -2036,7 +2123,8 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
u32 lb_size, u32 num_heads)
{
struct drm_display_mode *mode = &radeon_crtc->base.mode;
- struct evergreen_wm_params wm;
+ struct evergreen_wm_params wm_low, wm_high;
+ u32 dram_channels;
u32 pixel_period;
u32 line_time = 0;
u32 latency_watermark_a = 0, latency_watermark_b = 0;
@@ -2052,39 +2140,81 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
line_time = min((u32)mode->crtc_htotal * pixel_period, (u32)65535);
priority_a_cnt = 0;
priority_b_cnt = 0;
+ dram_channels = evergreen_get_number_of_dram_channels(rdev);
+
+ /* watermark for high clocks */
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+ wm_high.yclk =
+ radeon_dpm_get_mclk(rdev, false) * 10;
+ wm_high.sclk =
+ radeon_dpm_get_sclk(rdev, false) * 10;
+ } else {
+ wm_high.yclk = rdev->pm.current_mclk * 10;
+ wm_high.sclk = rdev->pm.current_sclk * 10;
+ }
- wm.yclk = rdev->pm.current_mclk * 10;
- wm.sclk = rdev->pm.current_sclk * 10;
- wm.disp_clk = mode->clock;
- wm.src_width = mode->crtc_hdisplay;
- wm.active_time = mode->crtc_hdisplay * pixel_period;
- wm.blank_time = line_time - wm.active_time;
- wm.interlaced = false;
+ 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.interlaced = true;
- wm.vsc = radeon_crtc->vsc;
- wm.vtaps = 1;
+ wm_high.interlaced = true;
+ wm_high.vsc = radeon_crtc->vsc;
+ wm_high.vtaps = 1;
if (radeon_crtc->rmx_type != RMX_OFF)
- wm.vtaps = 2;
- wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
- wm.lb_size = lb_size;
- wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
- wm.num_heads = num_heads;
+ 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 = dram_channels;
+ wm_high.num_heads = num_heads;
+
+ /* watermark for low clocks */
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+ wm_low.yclk =
+ radeon_dpm_get_mclk(rdev, true) * 10;
+ wm_low.sclk =
+ radeon_dpm_get_sclk(rdev, true) * 10;
+ } else {
+ wm_low.yclk = rdev->pm.current_mclk * 10;
+ wm_low.sclk = rdev->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 = radeon_crtc->vsc;
+ wm_low.vtaps = 1;
+ if (radeon_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 = dram_channels;
+ wm_low.num_heads = num_heads;
/* set for high clocks */
- latency_watermark_a = min(evergreen_latency_watermark(&wm), (u32)65535);
+ latency_watermark_a = min(evergreen_latency_watermark(&wm_high), (u32)65535);
/* set for low clocks */
- /* wm.yclk = low clk; wm.sclk = low clk */
- latency_watermark_b = min(evergreen_latency_watermark(&wm), (u32)65535);
+ latency_watermark_b = min(evergreen_latency_watermark(&wm_low), (u32)65535);
/* possibly force display priority to high */
/* should really do this at mode validation time... */
- if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
- !evergreen_average_bandwidth_vs_available_bandwidth(&wm) ||
- !evergreen_check_latency_hiding(&wm) ||
+ if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+ !evergreen_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+ !evergreen_check_latency_hiding(&wm_high) ||
(rdev->disp_priority == 2)) {
- DRM_DEBUG_KMS("force priority to high\n");
+ DRM_DEBUG_KMS("force priority a to high\n");
priority_a_cnt |= PRIORITY_ALWAYS_ON;
+ }
+ if (!evergreen_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+ !evergreen_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+ !evergreen_check_latency_hiding(&wm_low) ||
+ (rdev->disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority b to high\n");
priority_b_cnt |= PRIORITY_ALWAYS_ON;
}
@@ -2137,6 +2267,10 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
+ /* save values for DPM */
+ radeon_crtc->line_time = line_time;
+ radeon_crtc->wm_high = latency_watermark_a;
+ radeon_crtc->wm_low = latency_watermark_b;
}
/**
@@ -3120,10 +3254,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
u32 efuse_straps_4;
u32 efuse_straps_3;
- WREG32(RCU_IND_INDEX, 0x204);
- efuse_straps_4 = RREG32(RCU_IND_DATA);
- WREG32(RCU_IND_INDEX, 0x203);
- efuse_straps_3 = RREG32(RCU_IND_DATA);
+ efuse_straps_4 = RREG32_RCU(0x204);
+ efuse_straps_3 = RREG32_RCU(0x203);
tmp = (((efuse_straps_4 & 0xf) << 4) |
((efuse_straps_3 & 0xf0000000) >> 28));
} else {
@@ -3727,6 +3859,262 @@ bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin
return radeon_ring_test_lockup(rdev, ring);
}
+/*
+ * RLC
+ */
+#define RLC_SAVE_RESTORE_LIST_END_MARKER 0x00000000
+#define RLC_CLEAR_STATE_END_MARKER 0x00000001
+
+void sumo_rlc_fini(struct radeon_device *rdev)
+{
+ int r;
+
+ /* save restore block */
+ if (rdev->rlc.save_restore_obj) {
+ r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
+ if (unlikely(r != 0))
+ dev_warn(rdev->dev, "(%d) reserve RLC sr bo failed\n", r);
+ radeon_bo_unpin(rdev->rlc.save_restore_obj);
+ radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+
+ radeon_bo_unref(&rdev->rlc.save_restore_obj);
+ rdev->rlc.save_restore_obj = NULL;
+ }
+
+ /* clear state block */
+ if (rdev->rlc.clear_state_obj) {
+ r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
+ if (unlikely(r != 0))
+ dev_warn(rdev->dev, "(%d) reserve RLC c bo failed\n", r);
+ radeon_bo_unpin(rdev->rlc.clear_state_obj);
+ radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+
+ radeon_bo_unref(&rdev->rlc.clear_state_obj);
+ rdev->rlc.clear_state_obj = NULL;
+ }
+}
+
+int sumo_rlc_init(struct radeon_device *rdev)
+{
+ u32 *src_ptr;
+ volatile u32 *dst_ptr;
+ u32 dws, data, i, j, k, reg_num;
+ u32 reg_list_num, reg_list_hdr_blk_index, reg_list_blk_index;
+ u64 reg_list_mc_addr;
+ struct cs_section_def *cs_data;
+ int r;
+
+ src_ptr = rdev->rlc.reg_list;
+ dws = rdev->rlc.reg_list_size;
+ cs_data = rdev->rlc.cs_data;
+
+ /* save restore block */
+ if (rdev->rlc.save_restore_obj == NULL) {
+ r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
+ RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.save_restore_obj);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r);
+ return r;
+ }
+ }
+
+ r = radeon_bo_reserve(rdev->rlc.save_restore_obj, false);
+ if (unlikely(r != 0)) {
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_pin(rdev->rlc.save_restore_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->rlc.save_restore_gpu_addr);
+ if (r) {
+ radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+ dev_warn(rdev->dev, "(%d) pin RLC sr bo failed\n", r);
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_kmap(rdev->rlc.save_restore_obj, (void **)&rdev->rlc.sr_ptr);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map RLC sr bo failed\n", r);
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ /* write the sr buffer */
+ dst_ptr = rdev->rlc.sr_ptr;
+ /* format:
+ * dw0: (reg2 << 16) | reg1
+ * dw1: reg1 save space
+ * dw2: reg2 save space
+ */
+ for (i = 0; i < dws; i++) {
+ data = src_ptr[i] >> 2;
+ i++;
+ if (i < dws)
+ data |= (src_ptr[i] >> 2) << 16;
+ j = (((i - 1) * 3) / 2);
+ dst_ptr[j] = data;
+ }
+ j = ((i * 3) / 2);
+ dst_ptr[j] = RLC_SAVE_RESTORE_LIST_END_MARKER;
+
+ radeon_bo_kunmap(rdev->rlc.save_restore_obj);
+ radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+
+ /* clear state block */
+ reg_list_num = 0;
+ dws = 0;
+ for (i = 0; cs_data[i].section != NULL; i++) {
+ for (j = 0; cs_data[i].section[j].extent != NULL; j++) {
+ reg_list_num++;
+ dws += cs_data[i].section[j].reg_count;
+ }
+ }
+ reg_list_blk_index = (3 * reg_list_num + 2);
+ dws += reg_list_blk_index;
+
+ if (rdev->rlc.clear_state_obj == NULL) {
+ r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
+ RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.clear_state_obj);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ }
+ r = radeon_bo_reserve(rdev->rlc.clear_state_obj, false);
+ if (unlikely(r != 0)) {
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_pin(rdev->rlc.clear_state_obj, RADEON_GEM_DOMAIN_VRAM,
+ &rdev->rlc.clear_state_gpu_addr);
+ if (r) {
+
+ radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+ dev_warn(rdev->dev, "(%d) pin RLC c bo failed\n", r);
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ r = radeon_bo_kmap(rdev->rlc.clear_state_obj, (void **)&rdev->rlc.cs_ptr);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map RLC c bo failed\n", r);
+ sumo_rlc_fini(rdev);
+ return r;
+ }
+ /* set up the cs buffer */
+ dst_ptr = rdev->rlc.cs_ptr;
+ reg_list_hdr_blk_index = 0;
+ reg_list_mc_addr = rdev->rlc.clear_state_gpu_addr + (reg_list_blk_index * 4);
+ data = upper_32_bits(reg_list_mc_addr);
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+ for (i = 0; cs_data[i].section != NULL; i++) {
+ for (j = 0; cs_data[i].section[j].extent != NULL; j++) {
+ reg_num = cs_data[i].section[j].reg_count;
+ data = reg_list_mc_addr & 0xffffffff;
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+
+ data = (cs_data[i].section[j].reg_index * 4) & 0xffffffff;
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+
+ data = 0x08000000 | (reg_num * 4);
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+
+ for (k = 0; k < reg_num; k++) {
+ data = cs_data[i].section[j].extent[k];
+ dst_ptr[reg_list_blk_index + k] = data;
+ }
+ reg_list_mc_addr += reg_num * 4;
+ reg_list_blk_index += reg_num;
+ }
+ }
+ dst_ptr[reg_list_hdr_blk_index] = RLC_CLEAR_STATE_END_MARKER;
+
+ radeon_bo_kunmap(rdev->rlc.clear_state_obj);
+ radeon_bo_unreserve(rdev->rlc.clear_state_obj);
+
+ return 0;
+}
+
+static void evergreen_rlc_start(struct radeon_device *rdev)
+{
+ u32 mask = RLC_ENABLE;
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ mask |= GFX_POWER_GATING_ENABLE | GFX_POWER_GATING_SRC;
+ }
+
+ WREG32(RLC_CNTL, mask);
+}
+
+int evergreen_rlc_resume(struct radeon_device *rdev)
+{
+ u32 i;
+ const __be32 *fw_data;
+
+ if (!rdev->rlc_fw)
+ return -EINVAL;
+
+ r600_rlc_stop(rdev);
+
+ WREG32(RLC_HB_CNTL, 0);
+
+ if (rdev->flags & RADEON_IS_IGP) {
+ if (rdev->family == CHIP_ARUBA) {
+ u32 always_on_bitmap =
+ 3 | (3 << (16 * rdev->config.cayman.max_shader_engines));
+ /* find out the number of active simds */
+ u32 tmp = (RREG32(CC_GC_SHADER_PIPE_CONFIG) & 0xffff0000) >> 16;
+ tmp |= 0xffffffff << rdev->config.cayman.max_simds_per_se;
+ tmp = hweight32(~tmp);
+ if (tmp == rdev->config.cayman.max_simds_per_se) {
+ WREG32(TN_RLC_LB_ALWAYS_ACTIVE_SIMD_MASK, always_on_bitmap);
+ WREG32(TN_RLC_LB_PARAMS, 0x00601004);
+ WREG32(TN_RLC_LB_INIT_SIMD_MASK, 0xffffffff);
+ WREG32(TN_RLC_LB_CNTR_INIT, 0x00000000);
+ WREG32(TN_RLC_LB_CNTR_MAX, 0x00002000);
+ }
+ } else {
+ WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
+ WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
+ }
+ WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+ WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+ } else {
+ WREG32(RLC_HB_BASE, 0);
+ WREG32(RLC_HB_RPTR, 0);
+ WREG32(RLC_HB_WPTR, 0);
+ WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
+ WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
+ }
+ WREG32(RLC_MC_CNTL, 0);
+ WREG32(RLC_UCODE_CNTL, 0);
+
+ fw_data = (const __be32 *)rdev->rlc_fw->data;
+ if (rdev->family >= CHIP_ARUBA) {
+ for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) {
+ WREG32(RLC_UCODE_ADDR, i);
+ WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+ }
+ } else if (rdev->family >= CHIP_CAYMAN) {
+ for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) {
+ WREG32(RLC_UCODE_ADDR, i);
+ WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+ }
+ } else {
+ for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) {
+ WREG32(RLC_UCODE_ADDR, i);
+ WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
+ }
+ }
+ WREG32(RLC_UCODE_ADDR, 0);
+
+ evergreen_rlc_start(rdev);
+
+ return 0;
+}
+
/* Interrupts */
u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc)
@@ -3805,6 +4193,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;
u32 dma_cntl, dma_cntl1 = 0;
+ u32 thermal_int = 0;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -3824,6 +4213,12 @@ int evergreen_irq_set(struct radeon_device *rdev)
hpd4 = RREG32(DC_HPD4_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ if (rdev->family == CHIP_ARUBA)
+ thermal_int = RREG32(TN_CG_THERMAL_INT_CTRL) &
+ ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+ else
+ thermal_int = RREG32(CG_THERMAL_INT) &
+ ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
@@ -3869,6 +4264,11 @@ int evergreen_irq_set(struct radeon_device *rdev)
}
}
+ if (rdev->irq.dpm_thermal) {
+ DRM_DEBUG("dpm thermal\n");
+ thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+ }
+
if (rdev->irq.crtc_vblank_int[0] ||
atomic_read(&rdev->irq.pflip[0])) {
DRM_DEBUG("evergreen_irq_set: vblank 0\n");
@@ -3990,6 +4390,10 @@ int evergreen_irq_set(struct radeon_device *rdev)
WREG32(DC_HPD4_INT_CONTROL, hpd4);
WREG32(DC_HPD5_INT_CONTROL, hpd5);
WREG32(DC_HPD6_INT_CONTROL, hpd6);
+ if (rdev->family == CHIP_ARUBA)
+ WREG32(TN_CG_THERMAL_INT_CTRL, thermal_int);
+ else
+ WREG32(CG_THERMAL_INT, thermal_int);
WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1);
WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2);
@@ -4181,6 +4585,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
u32 ring_index;
bool queue_hotplug = false;
bool queue_hdmi = false;
+ bool queue_thermal = false;
if (!rdev->ih.enabled || rdev->shutdown)
return IRQ_NONE;
@@ -4502,6 +4907,16 @@ restart_ih:
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
+ case 230: /* thermal low to high */
+ DRM_DEBUG("IH: thermal low to high\n");
+ rdev->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");
+ rdev->pm.dpm.thermal.high_to_low = true;
+ queue_thermal = true;
+ break;
case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n");
break;
@@ -4524,6 +4939,8 @@ restart_ih:
schedule_work(&rdev->hotplug_work);
if (queue_hdmi)
schedule_work(&rdev->audio_work);
+ if (queue_thermal && rdev->pm.dpm_enabled)
+ schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0);
@@ -4680,6 +5097,8 @@ static int evergreen_startup(struct radeon_device *rdev)
/* enable pcie gen2 link */
evergreen_pcie_gen2_enable(rdev);
+ /* enable aspm */
+ evergreen_program_aspm(rdev);
if (ASIC_IS_DCE5(rdev)) {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
@@ -4725,6 +5144,18 @@ static int evergreen_startup(struct radeon_device *rdev)
dev_warn(rdev->dev, "failed blitter (%d) falling back to memcpy\n", r);
}
+ /* allocate rlc buffers */
+ if (rdev->flags & RADEON_IS_IGP) {
+ rdev->rlc.reg_list = sumo_rlc_save_restore_register_list;
+ rdev->rlc.reg_list_size = sumo_rlc_save_restore_register_list_size;
+ rdev->rlc.cs_data = evergreen_cs_data;
+ r = sumo_rlc_init(rdev);
+ if (r) {
+ DRM_ERROR("Failed to init rlc BOs!\n");
+ return r;
+ }
+ }
+
/* allocate wb buffer */
r = radeon_wb_init(rdev);
if (r)
@@ -4956,6 +5387,8 @@ int evergreen_init(struct radeon_device *rdev)
r700_cp_fini(rdev);
r600_dma_fini(rdev);
r600_irq_fini(rdev);
+ if (rdev->flags & RADEON_IS_IGP)
+ sumo_rlc_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
@@ -4984,6 +5417,8 @@ void evergreen_fini(struct radeon_device *rdev)
r700_cp_fini(rdev);
r600_dma_fini(rdev);
r600_irq_fini(rdev);
+ if (rdev->flags & RADEON_IS_IGP)
+ sumo_rlc_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev);
@@ -5061,3 +5496,150 @@ void evergreen_pcie_gen2_enable(struct radeon_device *rdev)
WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
}
}
+
+void evergreen_program_aspm(struct radeon_device *rdev)
+{
+ u32 data, orig;
+ u32 pcie_lc_cntl, pcie_lc_cntl_old;
+ bool disable_l0s, disable_l1 = false, disable_plloff_in_l1 = false;
+ /* fusion_platform = true
+ * if the system is a fusion system
+ * (APU or DGPU in a fusion system).
+ * todo: check if the system is a fusion platform.
+ */
+ bool fusion_platform = false;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ switch (rdev->family) {
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ case CHIP_JUNIPER:
+ case CHIP_REDWOOD:
+ case CHIP_CEDAR:
+ case CHIP_SUMO:
+ case CHIP_SUMO2:
+ case CHIP_PALM:
+ case CHIP_ARUBA:
+ disable_l0s = true;
+ break;
+ default:
+ disable_l0s = false;
+ break;
+ }
+
+ if (rdev->flags & RADEON_IS_IGP)
+ fusion_platform = true; /* XXX also dGPUs in a fusion system */
+
+ data = orig = RREG32_PIF_PHY0(PB0_PIF_PAIRING);
+ if (fusion_platform)
+ data &= ~MULTI_PIF;
+ else
+ data |= MULTI_PIF;
+ if (data != orig)
+ WREG32_PIF_PHY0(PB0_PIF_PAIRING, data);
+
+ data = orig = RREG32_PIF_PHY1(PB1_PIF_PAIRING);
+ if (fusion_platform)
+ data &= ~MULTI_PIF;
+ else
+ data |= MULTI_PIF;
+ if (data != orig)
+ WREG32_PIF_PHY1(PB1_PIF_PAIRING, data);
+
+ pcie_lc_cntl = pcie_lc_cntl_old = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+ pcie_lc_cntl &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK);
+ if (!disable_l0s) {
+ if (rdev->family >= CHIP_BARTS)
+ pcie_lc_cntl |= LC_L0S_INACTIVITY(7);
+ else
+ pcie_lc_cntl |= LC_L0S_INACTIVITY(3);
+ }
+
+ if (!disable_l1) {
+ if (rdev->family >= CHIP_BARTS)
+ pcie_lc_cntl |= LC_L1_INACTIVITY(7);
+ else
+ pcie_lc_cntl |= LC_L1_INACTIVITY(8);
+
+ if (!disable_plloff_in_l1) {
+ data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
+ data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+ if (data != orig)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
+
+ data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
+ data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+ if (data != orig)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
+
+ data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
+ data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+ if (data != orig)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
+
+ data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
+ data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+ if (data != orig)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
+
+ if (rdev->family >= CHIP_BARTS) {
+ data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
+ data &= ~PLL_RAMP_UP_TIME_0_MASK;
+ data |= PLL_RAMP_UP_TIME_0(4);
+ if (data != orig)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
+
+ data = orig = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
+ data &= ~PLL_RAMP_UP_TIME_1_MASK;
+ data |= PLL_RAMP_UP_TIME_1(4);
+ if (data != orig)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
+
+ data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
+ data &= ~PLL_RAMP_UP_TIME_0_MASK;
+ data |= PLL_RAMP_UP_TIME_0(4);
+ if (data != orig)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
+
+ data = orig = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
+ data &= ~PLL_RAMP_UP_TIME_1_MASK;
+ data |= PLL_RAMP_UP_TIME_1(4);
+ if (data != orig)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
+ }
+
+ data = orig = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+ data &= ~LC_DYN_LANES_PWR_STATE_MASK;
+ data |= LC_DYN_LANES_PWR_STATE(3);
+ if (data != orig)
+ WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data);
+
+ if (rdev->family >= CHIP_BARTS) {
+ data = orig = RREG32_PIF_PHY0(PB0_PIF_CNTL);
+ data &= ~LS2_EXIT_TIME_MASK;
+ data |= LS2_EXIT_TIME(1);
+ if (data != orig)
+ WREG32_PIF_PHY0(PB0_PIF_CNTL, data);
+
+ data = orig = RREG32_PIF_PHY1(PB1_PIF_CNTL);
+ data &= ~LS2_EXIT_TIME_MASK;
+ data |= LS2_EXIT_TIME(1);
+ if (data != orig)
+ WREG32_PIF_PHY1(PB1_PIF_CNTL, data);
+ }
+ }
+ }
+
+ /* evergreen parts only */
+ if (rdev->family < CHIP_BARTS)
+ pcie_lc_cntl |= LC_PMI_TO_L1_DIS;
+
+ if (pcie_lc_cntl != pcie_lc_cntl_old)
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, pcie_lc_cntl);
+}
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index ed7c8a768092..b9c6f7675e59 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -128,14 +128,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset = dig->afmt->offset;
uint8_t *frame = buffer + 3;
-
- /* Our header values (type, version, length) should be alright, Intel
- * is using the same. Checksum function also seems to be OK, it works
- * fine for audio infoframe. However calculated value is always lower
- * by 2 in comparison to fglrx. It breaks displaying anything in case
- * of TVs that strictly check the checksum. Hack it manually here to
- * workaround this issue. */
- frame[0x0] += 2;
+ uint8_t *header = buffer;
WREG32(AFMT_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -144,7 +137,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
WREG32(AFMT_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(AFMT_AVI_INFO3 + offset,
- frame[0xC] | (frame[0xD] << 8));
+ frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
}
static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 881aba23c477..8a4e641f0e3c 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -24,7 +24,16 @@
#ifndef __EVERGREEN_REG_H__
#define __EVERGREEN_REG_H__
+/* trinity */
+#define TN_SMC_IND_INDEX_0 0x200
+#define TN_SMC_IND_DATA_0 0x204
+
/* evergreen */
+#define EVERGREEN_PIF_PHY0_INDEX 0x8
+#define EVERGREEN_PIF_PHY0_DATA 0xc
+#define EVERGREEN_PIF_PHY1_INDEX 0x10
+#define EVERGREEN_PIF_PHY1_DATA 0x14
+
#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS 0x310
#define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH 0x324
#define EVERGREEN_D3VGA_CONTROL 0x3e0
@@ -40,6 +49,9 @@
#define EVERGREEN_AUDIO_PLL1_DIV 0x5b4
#define EVERGREEN_AUDIO_PLL1_UNK 0x5bc
+#define EVERGREEN_CG_IND_ADDR 0x8f8
+#define EVERGREEN_CG_IND_DATA 0x8fc
+
#define EVERGREEN_AUDIO_ENABLE 0x5e78
#define EVERGREEN_AUDIO_VENDOR_ID 0x5ec0
diff --git a/drivers/gpu/drm/radeon/evergreen_smc.h b/drivers/gpu/drm/radeon/evergreen_smc.h
new file mode 100644
index 000000000000..76ada8cfe902
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_smc.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __EVERGREEN_SMC_H__
+#define __EVERGREEN_SMC_H__
+
+#include "rv770_smc.h"
+
+#pragma pack(push, 1)
+
+#define SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE 16
+
+struct SMC_Evergreen_MCRegisterAddress
+{
+ uint16_t s0;
+ uint16_t s1;
+};
+
+typedef struct SMC_Evergreen_MCRegisterAddress SMC_Evergreen_MCRegisterAddress;
+
+
+struct SMC_Evergreen_MCRegisterSet
+{
+ uint32_t value[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_Evergreen_MCRegisterSet SMC_Evergreen_MCRegisterSet;
+
+struct SMC_Evergreen_MCRegisters
+{
+ uint8_t last;
+ uint8_t reserved[3];
+ SMC_Evergreen_MCRegisterAddress address[SMC_EVERGREEN_MC_REGISTER_ARRAY_SIZE];
+ SMC_Evergreen_MCRegisterSet data[5];
+};
+
+typedef struct SMC_Evergreen_MCRegisters SMC_Evergreen_MCRegisters;
+
+#define EVERGREEN_SMC_FIRMWARE_HEADER_LOCATION 0x100
+
+#define EVERGREEN_SMC_FIRMWARE_HEADER_softRegisters 0x0
+#define EVERGREEN_SMC_FIRMWARE_HEADER_stateTable 0xC
+#define EVERGREEN_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
+
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 75c05631146d..a7baf67aef6c 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -48,6 +48,293 @@
#define SUMO_GB_ADDR_CONFIG_GOLDEN 0x02010002
#define SUMO2_GB_ADDR_CONFIG_GOLDEN 0x02010002
+/* pm registers */
+#define SMC_MSG 0x20c
+#define HOST_SMC_MSG(x) ((x) << 0)
+#define HOST_SMC_MSG_MASK (0xff << 0)
+#define HOST_SMC_MSG_SHIFT 0
+#define HOST_SMC_RESP(x) ((x) << 8)
+#define HOST_SMC_RESP_MASK (0xff << 8)
+#define HOST_SMC_RESP_SHIFT 8
+#define SMC_HOST_MSG(x) ((x) << 16)
+#define SMC_HOST_MSG_MASK (0xff << 16)
+#define SMC_HOST_MSG_SHIFT 16
+#define SMC_HOST_RESP(x) ((x) << 24)
+#define SMC_HOST_RESP_MASK (0xff << 24)
+#define SMC_HOST_RESP_SHIFT 24
+
+#define DCCG_DISP_SLOW_SELECT_REG 0x4fc
+#define DCCG_DISP1_SLOW_SELECT(x) ((x) << 0)
+#define DCCG_DISP1_SLOW_SELECT_MASK (7 << 0)
+#define DCCG_DISP1_SLOW_SELECT_SHIFT 0
+#define DCCG_DISP2_SLOW_SELECT(x) ((x) << 4)
+#define DCCG_DISP2_SLOW_SELECT_MASK (7 << 4)
+#define DCCG_DISP2_SLOW_SELECT_SHIFT 4
+
+#define CG_SPLL_FUNC_CNTL 0x600
+#define SPLL_RESET (1 << 0)
+#define SPLL_SLEEP (1 << 1)
+#define SPLL_BYPASS_EN (1 << 3)
+#define SPLL_REF_DIV(x) ((x) << 4)
+#define SPLL_REF_DIV_MASK (0x3f << 4)
+#define SPLL_PDIV_A(x) ((x) << 20)
+#define SPLL_PDIV_A_MASK (0x7f << 20)
+#define CG_SPLL_FUNC_CNTL_2 0x604
+#define SCLK_MUX_SEL(x) ((x) << 0)
+#define SCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_SPLL_FUNC_CNTL_3 0x608
+#define SPLL_FB_DIV(x) ((x) << 0)
+#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define SPLL_DITHEN (1 << 28)
+
+#define MPLL_CNTL_MODE 0x61c
+# define SS_SSEN (1 << 24)
+# define SS_DSMODE_EN (1 << 25)
+
+#define MPLL_AD_FUNC_CNTL 0x624
+#define CLKF(x) ((x) << 0)
+#define CLKF_MASK (0x7f << 0)
+#define CLKR(x) ((x) << 7)
+#define CLKR_MASK (0x1f << 7)
+#define CLKFRAC(x) ((x) << 12)
+#define CLKFRAC_MASK (0x1f << 12)
+#define YCLK_POST_DIV(x) ((x) << 17)
+#define YCLK_POST_DIV_MASK (3 << 17)
+#define IBIAS(x) ((x) << 20)
+#define IBIAS_MASK (0x3ff << 20)
+#define RESET (1 << 30)
+#define PDNB (1 << 31)
+#define MPLL_AD_FUNC_CNTL_2 0x628
+#define BYPASS (1 << 19)
+#define BIAS_GEN_PDNB (1 << 24)
+#define RESET_EN (1 << 25)
+#define VCO_MODE (1 << 29)
+#define MPLL_DQ_FUNC_CNTL 0x62c
+#define MPLL_DQ_FUNC_CNTL_2 0x630
+
+#define GENERAL_PWRMGT 0x63c
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define THERMAL_PROTECTION_DIS (1 << 2)
+# define THERMAL_PROTECTION_TYPE (1 << 3)
+# define ENABLE_GEN2PCIE (1 << 4)
+# define ENABLE_GEN2XSP (1 << 5)
+# define SW_SMIO_INDEX(x) ((x) << 6)
+# define SW_SMIO_INDEX_MASK (3 << 6)
+# define SW_SMIO_INDEX_SHIFT 6
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+# define BACKBIAS_PAD_EN (1 << 18)
+# define BACKBIAS_VALUE (1 << 19)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
+# define AC_DC_SW (1 << 24)
+
+#define SCLK_PWRMGT_CNTL 0x644
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_LOW_D1 (1 << 1)
+# define FIR_RESET (1 << 4)
+# define FIR_FORCE_TREND_SEL (1 << 5)
+# define FIR_TREND_MODE (1 << 6)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define GFX_CLK_REQUEST_OFF (1 << 9)
+# define GFX_CLK_FORCE_OFF (1 << 10)
+# define GFX_CLK_OFF_ACPI_D1 (1 << 11)
+# define GFX_CLK_OFF_ACPI_D2 (1 << 12)
+# define GFX_CLK_OFF_ACPI_D3 (1 << 13)
+# define DYN_LIGHT_SLEEP_EN (1 << 14)
+#define MCLK_PWRMGT_CNTL 0x648
+# define DLL_SPEED(x) ((x) << 0)
+# define DLL_SPEED_MASK (0x1f << 0)
+# define MPLL_PWRMGT_OFF (1 << 5)
+# define DLL_READY (1 << 6)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA0_PDNB (1 << 8)
+# define MRDCKA1_PDNB (1 << 9)
+# define MRDCKB0_PDNB (1 << 10)
+# define MRDCKB1_PDNB (1 << 11)
+# define MRDCKC0_PDNB (1 << 12)
+# define MRDCKC1_PDNB (1 << 13)
+# define MRDCKD0_PDNB (1 << 14)
+# define MRDCKD1_PDNB (1 << 15)
+# define MRDCKA0_RESET (1 << 16)
+# define MRDCKA1_RESET (1 << 17)
+# define MRDCKB0_RESET (1 << 18)
+# define MRDCKB1_RESET (1 << 19)
+# define MRDCKC0_RESET (1 << 20)
+# define MRDCKC1_RESET (1 << 21)
+# define MRDCKD0_RESET (1 << 22)
+# define MRDCKD1_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define MPLL_TURNOFF_D2 (1 << 28)
+#define DLL_CNTL 0x64c
+# define MRDCKA0_BYPASS (1 << 24)
+# define MRDCKA1_BYPASS (1 << 25)
+# define MRDCKB0_BYPASS (1 << 26)
+# define MRDCKB1_BYPASS (1 << 27)
+# define MRDCKC0_BYPASS (1 << 28)
+# define MRDCKC1_BYPASS (1 << 29)
+# define MRDCKD0_BYPASS (1 << 30)
+# define MRDCKD1_BYPASS (1 << 31)
+
+#define CG_AT 0x6d4
+# define CG_R(x) ((x) << 0)
+# define CG_R_MASK (0xffff << 0)
+# define CG_L(x) ((x) << 16)
+# define CG_L_MASK (0xffff << 16)
+
+#define CG_DISPLAY_GAP_CNTL 0x714
+# define DISP1_GAP(x) ((x) << 0)
+# define DISP1_GAP_MASK (3 << 0)
+# define DISP2_GAP(x) ((x) << 2)
+# define DISP2_GAP_MASK (3 << 2)
+# define VBI_TIMER_COUNT(x) ((x) << 4)
+# define VBI_TIMER_COUNT_MASK (0x3fff << 4)
+# define VBI_TIMER_UNIT(x) ((x) << 20)
+# define VBI_TIMER_UNIT_MASK (7 << 20)
+# define DISP1_GAP_MCHG(x) ((x) << 24)
+# define DISP1_GAP_MCHG_MASK (3 << 24)
+# define DISP2_GAP_MCHG(x) ((x) << 26)
+# define DISP2_GAP_MCHG_MASK (3 << 26)
+
+#define CG_BIF_REQ_AND_RSP 0x7f4
+#define CG_CLIENT_REQ(x) ((x) << 0)
+#define CG_CLIENT_REQ_MASK (0xff << 0)
+#define CG_CLIENT_REQ_SHIFT 0
+#define CG_CLIENT_RESP(x) ((x) << 8)
+#define CG_CLIENT_RESP_MASK (0xff << 8)
+#define CG_CLIENT_RESP_SHIFT 8
+#define CLIENT_CG_REQ(x) ((x) << 16)
+#define CLIENT_CG_REQ_MASK (0xff << 16)
+#define CLIENT_CG_REQ_SHIFT 16
+#define CLIENT_CG_RESP(x) ((x) << 24)
+#define CLIENT_CG_RESP_MASK (0xff << 24)
+#define CLIENT_CG_RESP_SHIFT 24
+
+#define CG_SPLL_SPREAD_SPECTRUM 0x790
+#define SSEN (1 << 0)
+#define CG_SPLL_SPREAD_SPECTRUM_2 0x794
+
+#define MPLL_SS1 0x85c
+#define CLKV(x) ((x) << 0)
+#define CLKV_MASK (0x3ffffff << 0)
+#define MPLL_SS2 0x860
+#define CLKS(x) ((x) << 0)
+#define CLKS_MASK (0xfff << 0)
+
+#define CG_IND_ADDR 0x8f8
+#define CG_IND_DATA 0x8fc
+/* CGIND regs */
+#define CG_CGTT_LOCAL_0 0x00
+#define CG_CGTT_LOCAL_1 0x01
+#define CG_CGTT_LOCAL_2 0x02
+#define CG_CGTT_LOCAL_3 0x03
+#define CG_CGLS_TILE_0 0x20
+#define CG_CGLS_TILE_1 0x21
+#define CG_CGLS_TILE_2 0x22
+#define CG_CGLS_TILE_3 0x23
+#define CG_CGLS_TILE_4 0x24
+#define CG_CGLS_TILE_5 0x25
+#define CG_CGLS_TILE_6 0x26
+#define CG_CGLS_TILE_7 0x27
+#define CG_CGLS_TILE_8 0x28
+#define CG_CGLS_TILE_9 0x29
+#define CG_CGLS_TILE_10 0x2a
+#define CG_CGLS_TILE_11 0x2b
+
+#define VM_L2_CG 0x15c0
+
+#define MC_CONFIG 0x2000
+
+#define MC_CONFIG_MCD 0x20a0
+#define MC_CG_CONFIG_MCD 0x20a4
+#define MC_RD_ENABLE_MCD(x) ((x) << 8)
+#define MC_RD_ENABLE_MCD_MASK (7 << 8)
+
+#define MC_HUB_MISC_HUB_CG 0x20b8
+#define MC_HUB_MISC_VM_CG 0x20bc
+#define MC_HUB_MISC_SIP_CG 0x20c0
+
+#define MC_XPB_CLK_GAT 0x2478
+
+#define MC_CG_CONFIG 0x25bc
+#define MC_RD_ENABLE(x) ((x) << 4)
+#define MC_RD_ENABLE_MASK (3 << 4)
+
+#define MC_CITF_MISC_RD_CG 0x2648
+#define MC_CITF_MISC_WR_CG 0x264c
+#define MC_CITF_MISC_VM_CG 0x2650
+# define MEM_LS_ENABLE (1 << 19)
+
+#define MC_ARB_BURST_TIME 0x2808
+#define STATE0(x) ((x) << 0)
+#define STATE0_MASK (0x1f << 0)
+#define STATE1(x) ((x) << 5)
+#define STATE1_MASK (0x1f << 5)
+#define STATE2(x) ((x) << 10)
+#define STATE2_MASK (0x1f << 10)
+#define STATE3(x) ((x) << 15)
+#define STATE3_MASK (0x1f << 15)
+
+#define MC_SEQ_RAS_TIMING 0x28a0
+#define MC_SEQ_CAS_TIMING 0x28a4
+#define MC_SEQ_MISC_TIMING 0x28a8
+#define MC_SEQ_MISC_TIMING2 0x28ac
+
+#define MC_SEQ_RD_CTL_D0 0x28b4
+#define MC_SEQ_RD_CTL_D1 0x28b8
+#define MC_SEQ_WR_CTL_D0 0x28bc
+#define MC_SEQ_WR_CTL_D1 0x28c0
+
+#define MC_SEQ_STATUS_M 0x29f4
+# define PMG_PWRSTATE (1 << 16)
+
+#define MC_SEQ_MISC1 0x2a04
+#define MC_SEQ_RESERVE_M 0x2a08
+#define MC_PMG_CMD_EMRS 0x2a0c
+
+#define MC_SEQ_MISC3 0x2a2c
+
+#define MC_SEQ_MISC5 0x2a54
+#define MC_SEQ_MISC6 0x2a58
+
+#define MC_SEQ_MISC7 0x2a64
+
+#define MC_SEQ_CG 0x2a68
+#define CG_SEQ_REQ(x) ((x) << 0)
+#define CG_SEQ_REQ_MASK (0xff << 0)
+#define CG_SEQ_REQ_SHIFT 0
+#define CG_SEQ_RESP(x) ((x) << 8)
+#define CG_SEQ_RESP_MASK (0xff << 8)
+#define CG_SEQ_RESP_SHIFT 8
+#define SEQ_CG_REQ(x) ((x) << 16)
+#define SEQ_CG_REQ_MASK (0xff << 16)
+#define SEQ_CG_REQ_SHIFT 16
+#define SEQ_CG_RESP(x) ((x) << 24)
+#define SEQ_CG_RESP_MASK (0xff << 24)
+#define SEQ_CG_RESP_SHIFT 24
+#define MC_SEQ_RAS_TIMING_LP 0x2a6c
+#define MC_SEQ_CAS_TIMING_LP 0x2a70
+#define MC_SEQ_MISC_TIMING_LP 0x2a74
+#define MC_SEQ_MISC_TIMING2_LP 0x2a78
+#define MC_SEQ_WR_CTL_D0_LP 0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP 0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88
+
+#define MC_PMG_CMD_MRS 0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP 0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP 0x2b20
+
+#define MC_PMG_CMD_MRS1 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48
+
+#define CGTS_SM_CTRL_REG 0x9150
+
/* Registers */
#define RCU_IND_INDEX 0x100
@@ -90,6 +377,34 @@
#define CG_VCLK_STATUS 0x61c
#define CG_SCRATCH1 0x820
+#define RLC_CNTL 0x3f00
+# define RLC_ENABLE (1 << 0)
+# define GFX_POWER_GATING_ENABLE (1 << 7)
+# define GFX_POWER_GATING_SRC (1 << 8)
+# define DYN_PER_SIMD_PG_ENABLE (1 << 27)
+# define LB_CNT_SPIM_ACTIVE (1 << 30)
+# define LOAD_BALANCE_ENABLE (1 << 31)
+
+#define RLC_HB_BASE 0x3f10
+#define RLC_HB_CNTL 0x3f0c
+#define RLC_HB_RPTR 0x3f20
+#define RLC_HB_WPTR 0x3f1c
+#define RLC_HB_WPTR_LSB_ADDR 0x3f14
+#define RLC_HB_WPTR_MSB_ADDR 0x3f18
+#define RLC_MC_CNTL 0x3f44
+#define RLC_UCODE_CNTL 0x3f48
+#define RLC_UCODE_ADDR 0x3f2c
+#define RLC_UCODE_DATA 0x3f30
+
+/* new for TN */
+#define TN_RLC_SAVE_AND_RESTORE_BASE 0x3f10
+#define TN_RLC_LB_CNTR_MAX 0x3f14
+#define TN_RLC_LB_CNTR_INIT 0x3f18
+#define TN_RLC_CLEAR_STATE_RESTORE_BASE 0x3f20
+#define TN_RLC_LB_INIT_SIMD_MASK 0x3fe4
+#define TN_RLC_LB_ALWAYS_ACTIVE_SIMD_MASK 0x3fe8
+#define TN_RLC_LB_PARAMS 0x3fec
+
#define GRBM_GFX_INDEX 0x802C
#define INSTANCE_INDEX(x) ((x) << 0)
#define SE_INDEX(x) ((x) << 16)
@@ -503,6 +818,30 @@
#define CG_THERMAL_CTRL 0x72c
#define TOFFSET_MASK 0x00003FE0
#define TOFFSET_SHIFT 5
+#define DIG_THERM_DPM(x) ((x) << 14)
+#define DIG_THERM_DPM_MASK 0x003FC000
+#define DIG_THERM_DPM_SHIFT 14
+
+#define CG_THERMAL_INT 0x734
+#define DIG_THERM_INTH(x) ((x) << 8)
+#define DIG_THERM_INTH_MASK 0x0000FF00
+#define DIG_THERM_INTH_SHIFT 8
+#define DIG_THERM_INTL(x) ((x) << 16)
+#define DIG_THERM_INTL_MASK 0x00FF0000
+#define DIG_THERM_INTL_SHIFT 16
+#define THERM_INT_MASK_HIGH (1 << 24)
+#define THERM_INT_MASK_LOW (1 << 25)
+
+#define TN_CG_THERMAL_INT_CTRL 0x738
+#define TN_DIG_THERM_INTH(x) ((x) << 0)
+#define TN_DIG_THERM_INTH_MASK 0x000000FF
+#define TN_DIG_THERM_INTH_SHIFT 0
+#define TN_DIG_THERM_INTL(x) ((x) << 8)
+#define TN_DIG_THERM_INTL_MASK 0x0000FF00
+#define TN_DIG_THERM_INTL_SHIFT 8
+#define TN_THERM_INT_MASK_HIGH (1 << 24)
+#define TN_THERM_INT_MASK_LOW (1 << 25)
+
#define CG_MULT_THERMAL_STATUS 0x740
#define ASIC_T(x) ((x) << 16)
#define ASIC_T_MASK 0x07FF0000
@@ -510,6 +849,7 @@
#define CG_TS0_STATUS 0x760
#define TS0_ADC_DOUT_MASK 0x000003FF
#define TS0_ADC_DOUT_SHIFT 0
+
/* APU */
#define CG_THERMAL_STATUS 0x678
@@ -992,7 +1332,48 @@
#define DMA_PACKET_CONSTANT_FILL 0xd
#define DMA_PACKET_NOP 0xf
-/* PCIE link stuff */
+/* PIF PHY0 indirect regs */
+#define PB0_PIF_CNTL 0x10
+# define LS2_EXIT_TIME(x) ((x) << 17)
+# define LS2_EXIT_TIME_MASK (0x7 << 17)
+# define LS2_EXIT_TIME_SHIFT 17
+#define PB0_PIF_PAIRING 0x11
+# define MULTI_PIF (1 << 25)
+#define PB0_PIF_PWRDOWN_0 0x12
+# define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7)
+# define PLL_POWER_STATE_IN_TXS2_0_MASK (0x7 << 7)
+# define PLL_POWER_STATE_IN_TXS2_0_SHIFT 7
+# define PLL_POWER_STATE_IN_OFF_0(x) ((x) << 10)
+# define PLL_POWER_STATE_IN_OFF_0_MASK (0x7 << 10)
+# define PLL_POWER_STATE_IN_OFF_0_SHIFT 10
+# define PLL_RAMP_UP_TIME_0(x) ((x) << 24)
+# define PLL_RAMP_UP_TIME_0_MASK (0x7 << 24)
+# define PLL_RAMP_UP_TIME_0_SHIFT 24
+#define PB0_PIF_PWRDOWN_1 0x13
+# define PLL_POWER_STATE_IN_TXS2_1(x) ((x) << 7)
+# define PLL_POWER_STATE_IN_TXS2_1_MASK (0x7 << 7)
+# define PLL_POWER_STATE_IN_TXS2_1_SHIFT 7
+# define PLL_POWER_STATE_IN_OFF_1(x) ((x) << 10)
+# define PLL_POWER_STATE_IN_OFF_1_MASK (0x7 << 10)
+# define PLL_POWER_STATE_IN_OFF_1_SHIFT 10
+# define PLL_RAMP_UP_TIME_1(x) ((x) << 24)
+# define PLL_RAMP_UP_TIME_1_MASK (0x7 << 24)
+# define PLL_RAMP_UP_TIME_1_SHIFT 24
+/* PIF PHY1 indirect regs */
+#define PB1_PIF_CNTL 0x10
+#define PB1_PIF_PAIRING 0x11
+#define PB1_PIF_PWRDOWN_0 0x12
+#define PB1_PIF_PWRDOWN_1 0x13
+/* PCIE PORT indirect regs */
+#define PCIE_LC_CNTL 0xa0
+# define LC_L0S_INACTIVITY(x) ((x) << 8)
+# define LC_L0S_INACTIVITY_MASK (0xf << 8)
+# define LC_L0S_INACTIVITY_SHIFT 8
+# define LC_L1_INACTIVITY(x) ((x) << 12)
+# define LC_L1_INACTIVITY_MASK (0xf << 12)
+# define LC_L1_INACTIVITY_SHIFT 12
+# define LC_PMI_TO_L1_DIS (1 << 16)
+# define LC_ASPM_TO_L1_DIS (1 << 24)
#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
# define LC_LINK_WIDTH_SHIFT 0
@@ -1012,6 +1393,9 @@
# define LC_SHORT_RECONFIG_EN (1 << 11)
# define LC_UPCONFIGURE_SUPPORT (1 << 12)
# define LC_UPCONFIGURE_DIS (1 << 13)
+# define LC_DYN_LANES_PWR_STATE(x) ((x) << 21)
+# define LC_DYN_LANES_PWR_STATE_MASK (0x3 << 21)
+# define LC_DYN_LANES_PWR_STATE_SHIFT 21
#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
# define LC_GEN2_EN_STRAP (1 << 0)
# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1)
@@ -1020,6 +1404,9 @@
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12
# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
diff --git a/drivers/gpu/drm/radeon/mkregtable.c b/drivers/gpu/drm/radeon/mkregtable.c
index 5a82b6b75849..af85299f2126 100644
--- a/drivers/gpu/drm/radeon/mkregtable.c
+++ b/drivers/gpu/drm/radeon/mkregtable.c
@@ -373,19 +373,6 @@ static inline void list_splice_tail_init(struct list_head *list,
pos = pos->next)
/**
- * __list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop cursor.
- * @head: the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
* list_for_each_prev - iterate over a list backwards
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 84583302b081..f30127cb30ef 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -33,6 +33,135 @@
#include "atom.h"
#include "ni_reg.h"
#include "cayman_blit_shaders.h"
+#include "radeon_ucode.h"
+#include "clearstate_cayman.h"
+
+static u32 tn_rlc_save_restore_register_list[] =
+{
+ 0x98fc,
+ 0x98f0,
+ 0x9834,
+ 0x9838,
+ 0x9870,
+ 0x9874,
+ 0x8a14,
+ 0x8b24,
+ 0x8bcc,
+ 0x8b10,
+ 0x8c30,
+ 0x8d00,
+ 0x8d04,
+ 0x8c00,
+ 0x8c04,
+ 0x8c10,
+ 0x8c14,
+ 0x8d8c,
+ 0x8cf0,
+ 0x8e38,
+ 0x9508,
+ 0x9688,
+ 0x9608,
+ 0x960c,
+ 0x9610,
+ 0x9614,
+ 0x88c4,
+ 0x8978,
+ 0x88d4,
+ 0x900c,
+ 0x9100,
+ 0x913c,
+ 0x90e8,
+ 0x9354,
+ 0xa008,
+ 0x98f8,
+ 0x9148,
+ 0x914c,
+ 0x3f94,
+ 0x98f4,
+ 0x9b7c,
+ 0x3f8c,
+ 0x8950,
+ 0x8954,
+ 0x8a18,
+ 0x8b28,
+ 0x9144,
+ 0x3f90,
+ 0x915c,
+ 0x9160,
+ 0x9178,
+ 0x917c,
+ 0x9180,
+ 0x918c,
+ 0x9190,
+ 0x9194,
+ 0x9198,
+ 0x919c,
+ 0x91a8,
+ 0x91ac,
+ 0x91b0,
+ 0x91b4,
+ 0x91b8,
+ 0x91c4,
+ 0x91c8,
+ 0x91cc,
+ 0x91d0,
+ 0x91d4,
+ 0x91e0,
+ 0x91e4,
+ 0x91ec,
+ 0x91f0,
+ 0x91f4,
+ 0x9200,
+ 0x9204,
+ 0x929c,
+ 0x8030,
+ 0x9150,
+ 0x9a60,
+ 0x920c,
+ 0x9210,
+ 0x9228,
+ 0x922c,
+ 0x9244,
+ 0x9248,
+ 0x91e8,
+ 0x9294,
+ 0x9208,
+ 0x9224,
+ 0x9240,
+ 0x9220,
+ 0x923c,
+ 0x9258,
+ 0x9744,
+ 0xa200,
+ 0xa204,
+ 0xa208,
+ 0xa20c,
+ 0x8d58,
+ 0x9030,
+ 0x9034,
+ 0x9038,
+ 0x903c,
+ 0x9040,
+ 0x9654,
+ 0x897c,
+ 0xa210,
+ 0xa214,
+ 0x9868,
+ 0xa02c,
+ 0x9664,
+ 0x9698,
+ 0x949c,
+ 0x8e10,
+ 0x8e18,
+ 0x8c50,
+ 0x8c58,
+ 0x8c60,
+ 0x8c68,
+ 0x89b4,
+ 0x9830,
+ 0x802c,
+};
+static u32 tn_rlc_save_restore_register_list_size = ARRAY_SIZE(tn_rlc_save_restore_register_list);
extern bool evergreen_is_display_hung(struct radeon_device *rdev);
extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
@@ -44,36 +173,29 @@ extern void evergreen_irq_suspend(struct radeon_device *rdev);
extern int evergreen_mc_init(struct radeon_device *rdev);
extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
-extern void si_rlc_fini(struct radeon_device *rdev);
-extern int si_rlc_init(struct radeon_device *rdev);
-
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
-#define EVERGREEN_RLC_UCODE_SIZE 768
-#define BTC_MC_UCODE_SIZE 6024
-
-#define CAYMAN_PFP_UCODE_SIZE 2176
-#define CAYMAN_PM4_UCODE_SIZE 2176
-#define CAYMAN_RLC_UCODE_SIZE 1024
-#define CAYMAN_MC_UCODE_SIZE 6037
-
-#define ARUBA_RLC_UCODE_SIZE 1536
+extern void evergreen_program_aspm(struct radeon_device *rdev);
+extern void sumo_rlc_fini(struct radeon_device *rdev);
+extern int sumo_rlc_init(struct radeon_device *rdev);
/* Firmware Names */
MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
MODULE_FIRMWARE("radeon/BARTS_me.bin");
MODULE_FIRMWARE("radeon/BARTS_mc.bin");
+MODULE_FIRMWARE("radeon/BARTS_smc.bin");
MODULE_FIRMWARE("radeon/BTC_rlc.bin");
MODULE_FIRMWARE("radeon/TURKS_pfp.bin");
MODULE_FIRMWARE("radeon/TURKS_me.bin");
MODULE_FIRMWARE("radeon/TURKS_mc.bin");
+MODULE_FIRMWARE("radeon/TURKS_smc.bin");
MODULE_FIRMWARE("radeon/CAICOS_pfp.bin");
MODULE_FIRMWARE("radeon/CAICOS_me.bin");
MODULE_FIRMWARE("radeon/CAICOS_mc.bin");
+MODULE_FIRMWARE("radeon/CAICOS_smc.bin");
MODULE_FIRMWARE("radeon/CAYMAN_pfp.bin");
MODULE_FIRMWARE("radeon/CAYMAN_me.bin");
MODULE_FIRMWARE("radeon/CAYMAN_mc.bin");
MODULE_FIRMWARE("radeon/CAYMAN_rlc.bin");
+MODULE_FIRMWARE("radeon/CAYMAN_smc.bin");
MODULE_FIRMWARE("radeon/ARUBA_pfp.bin");
MODULE_FIRMWARE("radeon/ARUBA_me.bin");
MODULE_FIRMWARE("radeon/ARUBA_rlc.bin");
@@ -566,6 +688,7 @@ int ni_init_microcode(struct radeon_device *rdev)
const char *chip_name;
const char *rlc_chip_name;
size_t pfp_req_size, me_req_size, rlc_req_size, mc_req_size;
+ size_t smc_req_size = 0;
char fw_name[30];
int err;
@@ -586,6 +709,7 @@ int ni_init_microcode(struct radeon_device *rdev)
me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
mc_req_size = BTC_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(BARTS_SMC_UCODE_SIZE, 4);
break;
case CHIP_TURKS:
chip_name = "TURKS";
@@ -594,6 +718,7 @@ int ni_init_microcode(struct radeon_device *rdev)
me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
mc_req_size = BTC_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(TURKS_SMC_UCODE_SIZE, 4);
break;
case CHIP_CAICOS:
chip_name = "CAICOS";
@@ -602,6 +727,7 @@ int ni_init_microcode(struct radeon_device *rdev)
me_req_size = EVERGREEN_PM4_UCODE_SIZE * 4;
rlc_req_size = EVERGREEN_RLC_UCODE_SIZE * 4;
mc_req_size = BTC_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(CAICOS_SMC_UCODE_SIZE, 4);
break;
case CHIP_CAYMAN:
chip_name = "CAYMAN";
@@ -610,6 +736,7 @@ int ni_init_microcode(struct radeon_device *rdev)
me_req_size = CAYMAN_PM4_UCODE_SIZE * 4;
rlc_req_size = CAYMAN_RLC_UCODE_SIZE * 4;
mc_req_size = CAYMAN_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(CAYMAN_SMC_UCODE_SIZE, 4);
break;
case CHIP_ARUBA:
chip_name = "ARUBA";
@@ -672,6 +799,20 @@ int ni_init_microcode(struct radeon_device *rdev)
err = -EINVAL;
}
}
+
+ if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) {
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
+ err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->smc_fw->size != smc_req_size) {
+ printk(KERN_ERR
+ "ni_mc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->mc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+ }
+
out:
platform_device_unregister(pdev);
@@ -692,6 +833,14 @@ out:
return err;
}
+int tn_get_temp(struct radeon_device *rdev)
+{
+ u32 temp = RREG32_SMC(TN_CURRENT_GNB_TEMP) & 0x7ff;
+ int actual_temp = (temp / 8) - 49;
+
+ return actual_temp * 1000;
+}
+
/*
* Core functions
*/
@@ -1027,6 +1176,16 @@ static void cayman_gpu_init(struct radeon_device *rdev)
WREG32(PA_CL_ENHANCE, CLIP_VTX_REORDER_ENA | NUM_CLIP_SEQ(3));
udelay(50);
+
+ /* set clockgating golden values on TN */
+ if (rdev->family == CHIP_ARUBA) {
+ tmp = RREG32_CG(CG_CGTT_LOCAL_0);
+ tmp &= ~0x00380000;
+ WREG32_CG(CG_CGTT_LOCAL_0, tmp);
+ tmp = RREG32_CG(CG_CGTT_LOCAL_1);
+ tmp &= ~0x0e000000;
+ WREG32_CG(CG_CGTT_LOCAL_1, tmp);
+ }
}
/*
@@ -1928,6 +2087,8 @@ static int cayman_startup(struct radeon_device *rdev)
/* enable pcie gen2 link */
evergreen_pcie_gen2_enable(rdev);
+ /* enable aspm */
+ evergreen_program_aspm(rdev);
if (rdev->flags & RADEON_IS_IGP) {
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
@@ -1972,7 +2133,10 @@ static int cayman_startup(struct radeon_device *rdev)
/* allocate rlc buffers */
if (rdev->flags & RADEON_IS_IGP) {
- r = si_rlc_init(rdev);
+ rdev->rlc.reg_list = tn_rlc_save_restore_register_list;
+ rdev->rlc.reg_list_size = tn_rlc_save_restore_register_list_size;
+ rdev->rlc.cs_data = cayman_cs_data;
+ r = sumo_rlc_init(rdev);
if (r) {
DRM_ERROR("Failed to init rlc BOs!\n");
return r;
@@ -2229,7 +2393,7 @@ int cayman_init(struct radeon_device *rdev)
cayman_dma_fini(rdev);
r600_irq_fini(rdev);
if (rdev->flags & RADEON_IS_IGP)
- si_rlc_fini(rdev);
+ sumo_rlc_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
radeon_vm_manager_fini(rdev);
@@ -2260,7 +2424,7 @@ void cayman_fini(struct radeon_device *rdev)
cayman_dma_fini(rdev);
r600_irq_fini(rdev);
if (rdev->flags & RADEON_IS_IGP)
- si_rlc_fini(rdev);
+ sumo_rlc_fini(rdev);
radeon_wb_fini(rdev);
radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
new file mode 100644
index 000000000000..559cf24d51af
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -0,0 +1,4370 @@
+/*
+ * 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 "radeon.h"
+#include "nid.h"
+#include "r600_dpm.h"
+#include "ni_dpm.h"
+#include "atom.h"
+#include <linux/math64.h>
+#include <linux/seq_file.h>
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+#define SMC_RAM_END 0xC000
+
+static const struct ni_cac_weights cac_weights_cayman_xt =
+{
+ 0x15,
+ 0x2,
+ 0x19,
+ 0x2,
+ 0x8,
+ 0x14,
+ 0x2,
+ 0x16,
+ 0xE,
+ 0x17,
+ 0x13,
+ 0x2B,
+ 0x10,
+ 0x7,
+ 0x5,
+ 0x5,
+ 0x5,
+ 0x2,
+ 0x3,
+ 0x9,
+ 0x10,
+ 0x10,
+ 0x2B,
+ 0xA,
+ 0x9,
+ 0x4,
+ 0xD,
+ 0xD,
+ 0x3E,
+ 0x18,
+ 0x14,
+ 0,
+ 0x3,
+ 0x3,
+ 0x5,
+ 0,
+ 0x2,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x1CC,
+ 0,
+ 0x164,
+ 1,
+ 1,
+ 1,
+ 1,
+ 12,
+ 12,
+ 12,
+ 0x12,
+ 0x1F,
+ 132,
+ 5,
+ 7,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ true
+};
+
+static const struct ni_cac_weights cac_weights_cayman_pro =
+{
+ 0x16,
+ 0x4,
+ 0x10,
+ 0x2,
+ 0xA,
+ 0x16,
+ 0x2,
+ 0x18,
+ 0x10,
+ 0x1A,
+ 0x16,
+ 0x2D,
+ 0x12,
+ 0xA,
+ 0x6,
+ 0x6,
+ 0x6,
+ 0x2,
+ 0x4,
+ 0xB,
+ 0x11,
+ 0x11,
+ 0x2D,
+ 0xC,
+ 0xC,
+ 0x7,
+ 0x10,
+ 0x10,
+ 0x3F,
+ 0x1A,
+ 0x16,
+ 0,
+ 0x7,
+ 0x4,
+ 0x6,
+ 1,
+ 0x2,
+ 0x1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x30,
+ 0,
+ 0x1CF,
+ 0,
+ 0x166,
+ 1,
+ 1,
+ 1,
+ 1,
+ 12,
+ 12,
+ 12,
+ 0x15,
+ 0x1F,
+ 132,
+ 6,
+ 6,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ true
+};
+
+static const struct ni_cac_weights cac_weights_cayman_le =
+{
+ 0x7,
+ 0xE,
+ 0x1,
+ 0xA,
+ 0x1,
+ 0x3F,
+ 0x2,
+ 0x18,
+ 0x10,
+ 0x1A,
+ 0x1,
+ 0x3F,
+ 0x1,
+ 0xE,
+ 0x6,
+ 0x6,
+ 0x6,
+ 0x2,
+ 0x4,
+ 0x9,
+ 0x1A,
+ 0x1A,
+ 0x2C,
+ 0xA,
+ 0x11,
+ 0x8,
+ 0x19,
+ 0x19,
+ 0x1,
+ 0x1,
+ 0x1A,
+ 0,
+ 0x8,
+ 0x5,
+ 0x8,
+ 0x1,
+ 0x3,
+ 0x1,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0x38,
+ 0x38,
+ 0x239,
+ 0x3,
+ 0x18A,
+ 1,
+ 1,
+ 1,
+ 1,
+ 12,
+ 12,
+ 12,
+ 0x15,
+ 0x22,
+ 132,
+ 6,
+ 6,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0 },
+ true
+};
+
+#define NISLANDS_MGCG_SEQUENCE 300
+
+static const u32 cayman_cgcg_cgls_default[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_CGCG_CGLS_DEFAULT_LENGTH sizeof(cayman_cgcg_cgls_default) / (3 * sizeof(u32))
+
+static const u32 cayman_cgcg_cgls_disable[] =
+{
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00000644, 0x000f7902, 0x001f4180,
+ 0x00000644, 0x000f3802, 0x001f4180
+};
+#define CAYMAN_CGCG_CGLS_DISABLE_LENGTH sizeof(cayman_cgcg_cgls_disable) / (3 * sizeof(u32))
+
+static const u32 cayman_cgcg_cgls_enable[] =
+{
+ 0x00000644, 0x000f7882, 0x001f4080,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000020, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000021, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000022, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000023, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000024, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000025, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000026, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000027, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000028, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000029, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002a, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x0000002b, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff
+};
+#define CAYMAN_CGCG_CGLS_ENABLE_LENGTH sizeof(cayman_cgcg_cgls_enable) / (3 * sizeof(u32))
+
+static const u32 cayman_mgcg_default[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00003fc4, 0xc0000000, 0xffffffff,
+ 0x00005448, 0x00000100, 0xffffffff,
+ 0x000055e4, 0x00000100, 0xffffffff,
+ 0x0000160c, 0x00000100, 0xffffffff,
+ 0x00008984, 0x06000100, 0xffffffff,
+ 0x0000c164, 0x00000100, 0xffffffff,
+ 0x00008a18, 0x00000100, 0xffffffff,
+ 0x0000897c, 0x06000100, 0xffffffff,
+ 0x00008b28, 0x00000100, 0xffffffff,
+ 0x00009144, 0x00800200, 0xffffffff,
+ 0x00009a60, 0x00000100, 0xffffffff,
+ 0x00009868, 0x00000100, 0xffffffff,
+ 0x00008d58, 0x00000100, 0xffffffff,
+ 0x00009510, 0x00000100, 0xffffffff,
+ 0x0000949c, 0x00000100, 0xffffffff,
+ 0x00009654, 0x00000100, 0xffffffff,
+ 0x00009030, 0x00000100, 0xffffffff,
+ 0x00009034, 0x00000100, 0xffffffff,
+ 0x00009038, 0x00000100, 0xffffffff,
+ 0x0000903c, 0x00000100, 0xffffffff,
+ 0x00009040, 0x00000100, 0xffffffff,
+ 0x0000a200, 0x00000100, 0xffffffff,
+ 0x0000a204, 0x00000100, 0xffffffff,
+ 0x0000a208, 0x00000100, 0xffffffff,
+ 0x0000a20c, 0x00000100, 0xffffffff,
+ 0x00009744, 0x00000100, 0xffffffff,
+ 0x00003f80, 0x00000100, 0xffffffff,
+ 0x0000a210, 0x00000100, 0xffffffff,
+ 0x0000a214, 0x00000100, 0xffffffff,
+ 0x000004d8, 0x00000100, 0xffffffff,
+ 0x00009664, 0x00000100, 0xffffffff,
+ 0x00009698, 0x00000100, 0xffffffff,
+ 0x000004d4, 0x00000200, 0xffffffff,
+ 0x000004d0, 0x00000000, 0xffffffff,
+ 0x000030cc, 0x00000104, 0xffffffff,
+ 0x0000d0c0, 0x00000100, 0xffffffff,
+ 0x0000d8c0, 0x00000100, 0xffffffff,
+ 0x0000802c, 0x40000000, 0xffffffff,
+ 0x00003fc4, 0x40000000, 0xffffffff,
+ 0x0000915c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091b0, 0x00070000, 0xffffffff,
+ 0x000091b4, 0x00030002, 0xffffffff,
+ 0x000091b8, 0x00050004, 0xffffffff,
+ 0x000091c4, 0x00010006, 0xffffffff,
+ 0x000091c8, 0x00090008, 0xffffffff,
+ 0x000091cc, 0x00070000, 0xffffffff,
+ 0x000091d0, 0x00030002, 0xffffffff,
+ 0x000091d4, 0x00050004, 0xffffffff,
+ 0x000091e0, 0x00010006, 0xffffffff,
+ 0x000091e4, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x000091ec, 0x00070000, 0xffffffff,
+ 0x000091f0, 0x00030002, 0xffffffff,
+ 0x000091f4, 0x00050004, 0xffffffff,
+ 0x00009200, 0x00010006, 0xffffffff,
+ 0x00009204, 0x00090008, 0xffffffff,
+ 0x00009208, 0x00070000, 0xffffffff,
+ 0x0000920c, 0x00030002, 0xffffffff,
+ 0x00009210, 0x00050004, 0xffffffff,
+ 0x0000921c, 0x00010006, 0xffffffff,
+ 0x00009220, 0x00090008, 0xffffffff,
+ 0x00009224, 0x00070000, 0xffffffff,
+ 0x00009228, 0x00030002, 0xffffffff,
+ 0x0000922c, 0x00050004, 0xffffffff,
+ 0x00009238, 0x00010006, 0xffffffff,
+ 0x0000923c, 0x00090008, 0xffffffff,
+ 0x00009240, 0x00070000, 0xffffffff,
+ 0x00009244, 0x00030002, 0xffffffff,
+ 0x00009248, 0x00050004, 0xffffffff,
+ 0x00009254, 0x00010006, 0xffffffff,
+ 0x00009258, 0x00090008, 0xffffffff,
+ 0x0000925c, 0x00070000, 0xffffffff,
+ 0x00009260, 0x00030002, 0xffffffff,
+ 0x00009264, 0x00050004, 0xffffffff,
+ 0x00009270, 0x00010006, 0xffffffff,
+ 0x00009274, 0x00090008, 0xffffffff,
+ 0x00009278, 0x00070000, 0xffffffff,
+ 0x0000927c, 0x00030002, 0xffffffff,
+ 0x00009280, 0x00050004, 0xffffffff,
+ 0x0000928c, 0x00010006, 0xffffffff,
+ 0x00009290, 0x00090008, 0xffffffff,
+ 0x000092a8, 0x00070000, 0xffffffff,
+ 0x000092ac, 0x00030002, 0xffffffff,
+ 0x000092b0, 0x00050004, 0xffffffff,
+ 0x000092bc, 0x00010006, 0xffffffff,
+ 0x000092c0, 0x00090008, 0xffffffff,
+ 0x000092c4, 0x00070000, 0xffffffff,
+ 0x000092c8, 0x00030002, 0xffffffff,
+ 0x000092cc, 0x00050004, 0xffffffff,
+ 0x000092d8, 0x00010006, 0xffffffff,
+ 0x000092dc, 0x00090008, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff,
+ 0x0000802c, 0x40010000, 0xffffffff,
+ 0x00003fc4, 0x40010000, 0xffffffff,
+ 0x0000915c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091b0, 0x00070000, 0xffffffff,
+ 0x000091b4, 0x00030002, 0xffffffff,
+ 0x000091b8, 0x00050004, 0xffffffff,
+ 0x000091c4, 0x00010006, 0xffffffff,
+ 0x000091c8, 0x00090008, 0xffffffff,
+ 0x000091cc, 0x00070000, 0xffffffff,
+ 0x000091d0, 0x00030002, 0xffffffff,
+ 0x000091d4, 0x00050004, 0xffffffff,
+ 0x000091e0, 0x00010006, 0xffffffff,
+ 0x000091e4, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x000091ec, 0x00070000, 0xffffffff,
+ 0x000091f0, 0x00030002, 0xffffffff,
+ 0x000091f4, 0x00050004, 0xffffffff,
+ 0x00009200, 0x00010006, 0xffffffff,
+ 0x00009204, 0x00090008, 0xffffffff,
+ 0x00009208, 0x00070000, 0xffffffff,
+ 0x0000920c, 0x00030002, 0xffffffff,
+ 0x00009210, 0x00050004, 0xffffffff,
+ 0x0000921c, 0x00010006, 0xffffffff,
+ 0x00009220, 0x00090008, 0xffffffff,
+ 0x00009224, 0x00070000, 0xffffffff,
+ 0x00009228, 0x00030002, 0xffffffff,
+ 0x0000922c, 0x00050004, 0xffffffff,
+ 0x00009238, 0x00010006, 0xffffffff,
+ 0x0000923c, 0x00090008, 0xffffffff,
+ 0x00009240, 0x00070000, 0xffffffff,
+ 0x00009244, 0x00030002, 0xffffffff,
+ 0x00009248, 0x00050004, 0xffffffff,
+ 0x00009254, 0x00010006, 0xffffffff,
+ 0x00009258, 0x00090008, 0xffffffff,
+ 0x0000925c, 0x00070000, 0xffffffff,
+ 0x00009260, 0x00030002, 0xffffffff,
+ 0x00009264, 0x00050004, 0xffffffff,
+ 0x00009270, 0x00010006, 0xffffffff,
+ 0x00009274, 0x00090008, 0xffffffff,
+ 0x00009278, 0x00070000, 0xffffffff,
+ 0x0000927c, 0x00030002, 0xffffffff,
+ 0x00009280, 0x00050004, 0xffffffff,
+ 0x0000928c, 0x00010006, 0xffffffff,
+ 0x00009290, 0x00090008, 0xffffffff,
+ 0x000092a8, 0x00070000, 0xffffffff,
+ 0x000092ac, 0x00030002, 0xffffffff,
+ 0x000092b0, 0x00050004, 0xffffffff,
+ 0x000092bc, 0x00010006, 0xffffffff,
+ 0x000092c0, 0x00090008, 0xffffffff,
+ 0x000092c4, 0x00070000, 0xffffffff,
+ 0x000092c8, 0x00030002, 0xffffffff,
+ 0x000092cc, 0x00050004, 0xffffffff,
+ 0x000092d8, 0x00010006, 0xffffffff,
+ 0x000092dc, 0x00090008, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff,
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00003fc4, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000010, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000011, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000012, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000013, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000014, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000015, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000016, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000017, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000018, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000019, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001a, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x0000001b, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_MGCG_DEFAULT_LENGTH sizeof(cayman_mgcg_default) / (3 * sizeof(u32))
+
+static const u32 cayman_mgcg_disable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xffffffff,
+ 0x00009150, 0x00600000, 0xffffffff
+};
+#define CAYMAN_MGCG_DISABLE_LENGTH sizeof(cayman_mgcg_disable) / (3 * sizeof(u32))
+
+static const u32 cayman_mgcg_enable[] =
+{
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x000008f8, 0x00000002, 0xffffffff,
+ 0x000008fc, 0x00600000, 0xffffffff,
+ 0x000008f8, 0x00000003, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xffffffff,
+ 0x00009150, 0x96944200, 0xffffffff
+};
+
+#define CAYMAN_MGCG_ENABLE_LENGTH sizeof(cayman_mgcg_enable) / (3 * sizeof(u32))
+
+#define NISLANDS_SYSLS_SEQUENCE 100
+
+static const u32 cayman_sysls_default[] =
+{
+ /* Register, Value, Mask bits */
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x0000d8bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x00002f50, 0x00000404, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00008dfc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_SYSLS_DEFAULT_LENGTH sizeof(cayman_sysls_default) / (3 * sizeof(u32))
+
+static const u32 cayman_sysls_disable[] =
+{
+ /* Register, Value, Mask bits */
+ 0x0000d0c0, 0x00000000, 0xffffffff,
+ 0x0000d8c0, 0x00000000, 0xffffffff,
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x0000d8bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x00041401, 0xffffffff,
+ 0x0000264c, 0x00040400, 0xffffffff,
+ 0x00002648, 0x00040400, 0xffffffff,
+ 0x00002650, 0x00040400, 0xffffffff,
+ 0x000020b8, 0x00040400, 0xffffffff,
+ 0x000020bc, 0x00040400, 0xffffffff,
+ 0x000020c0, 0x00040c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680000, 0xffffffff,
+ 0x00002f50, 0x00000404, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x000064ec, 0x00007ffd, 0xffffffff,
+ 0x00000c7c, 0x0000ff00, 0xffffffff,
+ 0x00008dfc, 0x0000007f, 0xffffffff
+};
+#define CAYMAN_SYSLS_DISABLE_LENGTH sizeof(cayman_sysls_disable) / (3 * sizeof(u32))
+
+static const u32 cayman_sysls_enable[] =
+{
+ /* Register, Value, Mask bits */
+ 0x000055e8, 0x00000001, 0xffffffff,
+ 0x0000d0bc, 0x00000100, 0xffffffff,
+ 0x0000d8bc, 0x00000100, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x00002f50, 0x00000903, 0xffffffff,
+ 0x000004c8, 0x00000000, 0xffffffff,
+ 0x000064ec, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00008dfc, 0x00000000, 0xffffffff
+};
+#define CAYMAN_SYSLS_ENABLE_LENGTH sizeof(cayman_sysls_enable) / (3 * sizeof(u32))
+
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+
+struct ni_power_info *ni_get_pi(struct radeon_device *rdev)
+{
+ struct ni_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+struct ni_ps *ni_get_ps(struct radeon_ps *rps)
+{
+ struct ni_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+static void ni_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff,
+ u16 v, s32 t,
+ u32 ileakage,
+ u32 *leakage)
+{
+ s64 kt, kv, leakage_w, i_leakage, vddc, temperature;
+
+ i_leakage = div64_s64(drm_int2fixp(ileakage), 1000);
+ vddc = div64_s64(drm_int2fixp(v), 1000);
+ temperature = div64_s64(drm_int2fixp(t), 1000);
+
+ kt = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->at), 1000),
+ drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bt), 1000), temperature)));
+ kv = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->av), 1000),
+ drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bv), 1000), vddc)));
+
+ leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
+
+ *leakage = drm_fixp2int(leakage_w * 1000);
+}
+
+static void ni_calculate_leakage_for_v_and_t(struct radeon_device *rdev,
+ const struct ni_leakage_coeffients *coeff,
+ u16 v,
+ s32 t,
+ u32 i_leakage,
+ u32 *leakage)
+{
+ ni_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
+}
+
+bool ni_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+ u32 switch_limit = pi->mem_gddr5 ? 450 : 300;
+
+ if (vblank_time < switch_limit)
+ return true;
+ else
+ return false;
+
+}
+
+static void ni_apply_state_adjust_rules(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct ni_ps *ps = ni_get_ps(rps);
+ struct radeon_clock_and_voltage_limits *max_limits;
+ bool disable_mclk_switching;
+ u32 mclk, sclk;
+ u16 vddc, vddci;
+ int i;
+
+ if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
+ ni_dpm_vblank_too_short(rdev))
+ disable_mclk_switching = true;
+ else
+ disable_mclk_switching = false;
+
+ if (rdev->pm.dpm.ac_power)
+ max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ if (rdev->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;
+ if (ps->performance_levels[i].vddc > max_limits->vddc)
+ ps->performance_levels[i].vddc = max_limits->vddc;
+ if (ps->performance_levels[i].vddci > max_limits->vddci)
+ ps->performance_levels[i].vddci = max_limits->vddci;
+ }
+ }
+
+ /* 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;
+ vddc = ps->performance_levels[0].vddc;
+ vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
+ } else {
+ sclk = ps->performance_levels[0].sclk;
+ mclk = ps->performance_levels[0].mclk;
+ vddc = ps->performance_levels[0].vddc;
+ vddci = ps->performance_levels[0].vddci;
+ }
+
+ /* adjusted low state */
+ ps->performance_levels[0].sclk = sclk;
+ ps->performance_levels[0].mclk = mclk;
+ ps->performance_levels[0].vddc = vddc;
+ ps->performance_levels[0].vddci = vddci;
+
+ btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+ &ps->performance_levels[0].sclk,
+ &ps->performance_levels[0].mclk);
+
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
+ ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
+ if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
+ ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+ }
+
+ if (disable_mclk_switching) {
+ mclk = ps->performance_levels[0].mclk;
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (mclk < ps->performance_levels[i].mclk)
+ mclk = ps->performance_levels[i].mclk;
+ }
+ for (i = 0; i < ps->performance_level_count; i++) {
+ ps->performance_levels[i].mclk = mclk;
+ ps->performance_levels[i].vddci = vddci;
+ }
+ } else {
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk)
+ ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk;
+ if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci)
+ ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci;
+ }
+ }
+
+ for (i = 1; i < ps->performance_level_count; i++)
+ btc_skip_blacklist_clocks(rdev, max_limits->sclk, max_limits->mclk,
+ &ps->performance_levels[i].sclk,
+ &ps->performance_levels[i].mclk);
+
+ for (i = 0; i < ps->performance_level_count; i++)
+ btc_adjust_clock_combinations(rdev, max_limits,
+ &ps->performance_levels[i]);
+
+ for (i = 0; i < ps->performance_level_count; i++) {
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ ps->performance_levels[i].sclk,
+ max_limits->vddc, &ps->performance_levels[i].vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ ps->performance_levels[i].mclk,
+ max_limits->vddci, &ps->performance_levels[i].vddci);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ ps->performance_levels[i].mclk,
+ max_limits->vddc, &ps->performance_levels[i].vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
+ rdev->clock.current_dispclk,
+ max_limits->vddc, &ps->performance_levels[i].vddc);
+ }
+
+ for (i = 0; i < ps->performance_level_count; i++) {
+ btc_apply_voltage_delta_rules(rdev,
+ max_limits->vddc, max_limits->vddci,
+ &ps->performance_levels[i].vddc,
+ &ps->performance_levels[i].vddci);
+ }
+
+ ps->dc_compatible = true;
+ for (i = 0; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
+ ps->dc_compatible = false;
+
+ if (ps->performance_levels[i].vddc < rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2)
+ ps->performance_levels[i].flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+ }
+}
+
+static void ni_cg_clockgating_default(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *ps = NULL;
+
+ ps = (const u32 *)&cayman_cgcg_cgls_default;
+ count = CAYMAN_CGCG_CGLS_DEFAULT_LENGTH;
+
+ btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_gfx_clockgating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *ps = NULL;
+
+ if (enable) {
+ ps = (const u32 *)&cayman_cgcg_cgls_enable;
+ count = CAYMAN_CGCG_CGLS_ENABLE_LENGTH;
+ } else {
+ ps = (const u32 *)&cayman_cgcg_cgls_disable;
+ count = CAYMAN_CGCG_CGLS_DISABLE_LENGTH;
+ }
+
+ btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_mg_clockgating_default(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *ps = NULL;
+
+ ps = (const u32 *)&cayman_mgcg_default;
+ count = CAYMAN_MGCG_DEFAULT_LENGTH;
+
+ btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_mg_clockgating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *ps = NULL;
+
+ if (enable) {
+ ps = (const u32 *)&cayman_mgcg_enable;
+ count = CAYMAN_MGCG_ENABLE_LENGTH;
+ } else {
+ ps = (const u32 *)&cayman_mgcg_disable;
+ count = CAYMAN_MGCG_DISABLE_LENGTH;
+ }
+
+ btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_ls_clockgating_default(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *ps = NULL;
+
+ ps = (const u32 *)&cayman_sysls_default;
+ count = CAYMAN_SYSLS_DEFAULT_LENGTH;
+
+ btc_program_mgcg_hw_sequence(rdev, ps, count);
+}
+
+static void ni_ls_clockgating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *ps = NULL;
+
+ if (enable) {
+ ps = (const u32 *)&cayman_sysls_enable;
+ count = CAYMAN_SYSLS_ENABLE_LENGTH;
+ } else {
+ ps = (const u32 *)&cayman_sysls_disable;
+ count = CAYMAN_SYSLS_DISABLE_LENGTH;
+ }
+
+ btc_program_mgcg_hw_sequence(rdev, ps, count);
+
+}
+
+static int ni_patch_single_dependency_table_based_on_leakage(struct radeon_device *rdev,
+ struct radeon_clock_voltage_dependency_table *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 i;
+
+ if (table) {
+ for (i = 0; i < table->count; i++) {
+ if (0xff01 == table->entries[i].v) {
+ if (pi->max_vddc == 0)
+ return -EINVAL;
+ table->entries[i].v = pi->max_vddc;
+ }
+ }
+ }
+ return 0;
+}
+
+static int ni_patch_dependency_tables_based_on_leakage(struct radeon_device *rdev)
+{
+ int ret = 0;
+
+ ret = ni_patch_single_dependency_table_based_on_leakage(rdev,
+ &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
+
+ ret = ni_patch_single_dependency_table_based_on_leakage(rdev,
+ &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
+ return ret;
+}
+
+static void ni_stop_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+}
+
+#if 0
+static int ni_notify_hw_of_power_source(struct radeon_device *rdev,
+ bool ac_power)
+{
+ if (ac_power)
+ return (rv770_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+
+ return 0;
+}
+#endif
+
+static PPSMC_Result ni_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
+ PPSMC_Msg msg, u32 parameter)
+{
+ WREG32(SMC_SCRATCH0, parameter);
+ return rv770_send_msg_to_smc(rdev, msg);
+}
+
+static int ni_restrict_performance_levels_before_switch(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+int ni_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct ni_ps *ps = ni_get_ps(rps);
+ u32 levels;
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
+ return -EINVAL;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ levels = ps->performance_level_count - 1;
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+ return -EINVAL;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}
+
+static void ni_stop_smc(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = RREG32(LB_SYNC_RESET_SEL) & LB_SYNC_RESET_SEL_MASK;
+ if (tmp != 1)
+ break;
+ udelay(1);
+ }
+
+ udelay(100);
+
+ r7xx_stop_smc(rdev);
+}
+
+static int ni_process_firmware_header(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_stateTable,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ pi->state_table_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_softRegisters,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ pi->soft_regs_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ eg_pi->mc_reg_table_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_fanTable,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ ni_pi->fan_table_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ ni_pi->arb_table_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_cacTable,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ ni_pi->cac_table_start = (u16)tmp;
+
+ ret = rv770_read_smc_sram_dword(rdev,
+ NISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ NISLANDS_SMC_FIRMWARE_HEADER_spllTable,
+ &tmp, pi->sram_end);
+
+ if (ret)
+ return ret;
+
+ ni_pi->spll_table_start = (u16)tmp;
+
+
+ return ret;
+}
+
+static void ni_read_clock_registers(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+ ni_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+ ni_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
+ ni_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
+ ni_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
+ ni_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
+ ni_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+ ni_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
+ ni_pi->clock_registers.mpll_ad_func_cntl_2 = RREG32(MPLL_AD_FUNC_CNTL_2);
+ ni_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
+ ni_pi->clock_registers.mpll_dq_func_cntl_2 = RREG32(MPLL_DQ_FUNC_CNTL_2);
+ ni_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
+ ni_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
+ ni_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
+ ni_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
+}
+
+#if 0
+static int ni_enter_ulp_state(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (pi->gfx_clock_gating) {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+ RREG32(GB_ADDR_CONFIG);
+ }
+
+ WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
+ ~HOST_SMC_MSG_MASK);
+
+ udelay(25000);
+
+ return 0;
+}
+#endif
+
+static void ni_program_response_times(struct radeon_device *rdev)
+{
+ u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out;
+ u32 vddc_dly, bb_dly, acpi_dly, vbi_dly, mclk_switch_limit;
+ u32 reference_clock;
+
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
+
+ voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
+ backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
+
+ if (voltage_response_time == 0)
+ voltage_response_time = 1000;
+
+ if (backbias_response_time == 0)
+ backbias_response_time = 1000;
+
+ acpi_delay_time = 15000;
+ vbi_time_out = 100000;
+
+ reference_clock = radeon_get_xclk(rdev);
+
+ vddc_dly = (voltage_response_time * reference_clock) / 1600;
+ bb_dly = (backbias_response_time * reference_clock) / 1600;
+ acpi_dly = (acpi_delay_time * reference_clock) / 1600;
+ vbi_dly = (vbi_time_out * reference_clock) / 1600;
+
+ mclk_switch_limit = (460 * reference_clock) / 100;
+
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_vreg, vddc_dly);
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_bbias, bb_dly);
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_delay_acpi, acpi_dly);
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_mclk_switch_lim, mclk_switch_limit);
+}
+
+static void ni_populate_smc_voltage_table(struct radeon_device *rdev,
+ struct atom_voltage_table *voltage_table,
+ NISLANDS_SMC_STATETABLE *table)
+{
+ unsigned int i;
+
+ for (i = 0; i < voltage_table->count; i++) {
+ table->highSMIO[i] = 0;
+ table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
+ }
+}
+
+static void ni_populate_smc_voltage_tables(struct radeon_device *rdev,
+ NISLANDS_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ unsigned char i;
+
+ if (eg_pi->vddc_voltage_table.count) {
+ ni_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
+ table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] = 0;
+ table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDC] =
+ cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+
+ for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
+ if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
+ table->maxVDDCIndexInPPTable = i;
+ break;
+ }
+ }
+ }
+
+ if (eg_pi->vddci_voltage_table.count) {
+ ni_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
+
+ table->voltageMaskTable.highMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] = 0;
+ table->voltageMaskTable.lowMask[NISLANDS_SMC_VOLTAGEMASK_VDDCI] =
+ cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+ }
+}
+
+static int ni_populate_voltage_value(struct radeon_device *rdev,
+ struct atom_voltage_table *table,
+ u16 value,
+ NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ unsigned int i;
+
+ for (i = 0; i < table->count; i++) {
+ if (value <= table->entries[i].value) {
+ voltage->index = (u8)i;
+ voltage->value = cpu_to_be16(table->entries[i].value);
+ break;
+ }
+ }
+
+ if (i >= table->count)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void ni_populate_mvdd_value(struct radeon_device *rdev,
+ u32 mclk,
+ NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (!pi->mvdd_control) {
+ voltage->index = eg_pi->mvdd_high_index;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ return;
+ }
+
+ if (mclk <= pi->mvdd_split_frequency) {
+ voltage->index = eg_pi->mvdd_low_index;
+ voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+ } else {
+ voltage->index = eg_pi->mvdd_high_index;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ }
+}
+
+static int ni_get_std_voltage_value(struct radeon_device *rdev,
+ NISLANDS_SMC_VOLTAGE_VALUE *voltage,
+ u16 *std_voltage)
+{
+ if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries &&
+ ((u32)voltage->index < rdev->pm.dpm.dyn_state.cac_leakage_table.count))
+ *std_voltage = rdev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc;
+ else
+ *std_voltage = be16_to_cpu(voltage->value);
+
+ return 0;
+}
+
+static void ni_populate_std_voltage_value(struct radeon_device *rdev,
+ u16 value, u8 index,
+ NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ voltage->index = index;
+ voltage->value = cpu_to_be16(value);
+}
+
+static u32 ni_get_smc_power_scaling_factor(struct radeon_device *rdev)
+{
+ u32 xclk_period;
+ u32 xclk = radeon_get_xclk(rdev);
+ u32 tmp = RREG32(CG_CAC_CTRL) & TID_CNT_MASK;
+
+ xclk_period = (1000000000UL / xclk);
+ xclk_period /= 10000UL;
+
+ return tmp * xclk_period;
+}
+
+static u32 ni_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor)
+{
+ return (power_in_watts * scaling_factor) << 2;
+}
+
+static u32 ni_calculate_power_boost_limit(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ u32 near_tdp_limit)
+{
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 power_boost_limit = 0;
+ int ret;
+
+ if (ni_pi->enable_power_containment &&
+ ni_pi->use_power_boost_limit) {
+ NISLANDS_SMC_VOLTAGE_VALUE vddc;
+ u16 std_vddc_med;
+ u16 std_vddc_high;
+ u64 tmp, n, d;
+
+ if (state->performance_level_count < 3)
+ return 0;
+
+ ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ state->performance_levels[state->performance_level_count - 2].vddc,
+ &vddc);
+ if (ret)
+ return 0;
+
+ ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_med);
+ if (ret)
+ return 0;
+
+ ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ state->performance_levels[state->performance_level_count - 1].vddc,
+ &vddc);
+ if (ret)
+ return 0;
+
+ ret = ni_get_std_voltage_value(rdev, &vddc, &std_vddc_high);
+ if (ret)
+ return 0;
+
+ n = ((u64)near_tdp_limit * ((u64)std_vddc_med * (u64)std_vddc_med) * 90);
+ d = ((u64)std_vddc_high * (u64)std_vddc_high * 100);
+ tmp = div64_u64(n, d);
+
+ if (tmp >> 32)
+ return 0;
+ power_boost_limit = (u32)tmp;
+ }
+
+ return power_boost_limit;
+}
+
+static int ni_calculate_adjusted_tdp_limits(struct radeon_device *rdev,
+ bool adjust_polarity,
+ u32 tdp_adjustment,
+ u32 *tdp_limit,
+ u32 *near_tdp_limit)
+{
+ if (tdp_adjustment > (u32)rdev->pm.dpm.tdp_od_limit)
+ return -EINVAL;
+
+ if (adjust_polarity) {
+ *tdp_limit = ((100 + tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
+ *near_tdp_limit = rdev->pm.dpm.near_tdp_limit + (*tdp_limit - rdev->pm.dpm.tdp_limit);
+ } else {
+ *tdp_limit = ((100 - tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
+ *near_tdp_limit = rdev->pm.dpm.near_tdp_limit - (rdev->pm.dpm.tdp_limit - *tdp_limit);
+ }
+
+ return 0;
+}
+
+static int ni_populate_smc_tdp_limits(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+ if (ni_pi->enable_power_containment) {
+ NISLANDS_SMC_STATETABLE *smc_table = &ni_pi->smc_statetable;
+ u32 scaling_factor = ni_get_smc_power_scaling_factor(rdev);
+ u32 tdp_limit;
+ u32 near_tdp_limit;
+ u32 power_boost_limit;
+ int ret;
+
+ if (scaling_factor == 0)
+ return -EINVAL;
+
+ memset(smc_table, 0, sizeof(NISLANDS_SMC_STATETABLE));
+
+ ret = ni_calculate_adjusted_tdp_limits(rdev,
+ false, /* ??? */
+ rdev->pm.dpm.tdp_adjustment,
+ &tdp_limit,
+ &near_tdp_limit);
+ if (ret)
+ return ret;
+
+ power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state,
+ near_tdp_limit);
+
+ smc_table->dpm2Params.TDPLimit =
+ cpu_to_be32(ni_scale_power_for_smc(tdp_limit, scaling_factor));
+ smc_table->dpm2Params.NearTDPLimit =
+ cpu_to_be32(ni_scale_power_for_smc(near_tdp_limit, scaling_factor));
+ smc_table->dpm2Params.SafePowerLimit =
+ cpu_to_be32(ni_scale_power_for_smc((near_tdp_limit * NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100,
+ scaling_factor));
+ smc_table->dpm2Params.PowerBoostLimit =
+ cpu_to_be32(ni_scale_power_for_smc(power_boost_limit, scaling_factor));
+
+ ret = rv770_copy_bytes_to_smc(rdev,
+ (u16)(pi->state_table_start + offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) +
+ offsetof(PP_NIslands_DPM2Parameters, TDPLimit)),
+ (u8 *)(&smc_table->dpm2Params.TDPLimit),
+ sizeof(u32) * 4, pi->sram_end);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
+ 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(MC_ARB_DRAM_TIMING);
+ mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+ burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE0_MASK) >> STATE0_SHIFT;
+ break;
+ case MC_CG_ARB_FREQ_F1:
+ mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING_1);
+ mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_1);
+ burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE1_MASK) >> STATE1_SHIFT;
+ break;
+ case MC_CG_ARB_FREQ_F2:
+ mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING_2);
+ mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_2);
+ burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE2_MASK) >> STATE2_SHIFT;
+ break;
+ case MC_CG_ARB_FREQ_F3:
+ mc_arb_dram_timing = RREG32(MC_ARB_DRAM_TIMING_3);
+ mc_arb_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2_3);
+ burst_time = (RREG32(MC_ARB_BURST_TIME) & STATE3_MASK) >> STATE3_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (arb_freq_dest) {
+ case MC_CG_ARB_FREQ_F0:
+ WREG32(MC_ARB_DRAM_TIMING, mc_arb_dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2, mc_arb_dram_timing2);
+ WREG32_P(MC_ARB_BURST_TIME, STATE0(burst_time), ~STATE0_MASK);
+ break;
+ case MC_CG_ARB_FREQ_F1:
+ WREG32(MC_ARB_DRAM_TIMING_1, mc_arb_dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2_1, mc_arb_dram_timing2);
+ WREG32_P(MC_ARB_BURST_TIME, STATE1(burst_time), ~STATE1_MASK);
+ break;
+ case MC_CG_ARB_FREQ_F2:
+ WREG32(MC_ARB_DRAM_TIMING_2, mc_arb_dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2_2, mc_arb_dram_timing2);
+ WREG32_P(MC_ARB_BURST_TIME, STATE2(burst_time), ~STATE2_MASK);
+ break;
+ case MC_CG_ARB_FREQ_F3:
+ WREG32(MC_ARB_DRAM_TIMING_3, mc_arb_dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2_3, mc_arb_dram_timing2);
+ WREG32_P(MC_ARB_BURST_TIME, STATE3(burst_time), ~STATE3_MASK);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mc_cg_config = RREG32(MC_CG_CONFIG) | 0x0000000F;
+ WREG32(MC_CG_CONFIG, mc_cg_config);
+ WREG32_P(MC_ARB_CG, CG_ARB_REQ(arb_freq_dest), ~CG_ARB_REQ_MASK);
+
+ return 0;
+}
+
+static int ni_init_arb_table_index(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start,
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ tmp &= 0x00FFFFFF;
+ tmp |= ((u32)MC_CG_ARB_FREQ_F1) << 24;
+
+ return rv770_write_smc_sram_dword(rdev, ni_pi->arb_table_start,
+ tmp, pi->sram_end);
+}
+
+static int ni_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev)
+{
+ return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int ni_force_switch_to_arb_f0(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = rv770_read_smc_sram_dword(rdev, ni_pi->arb_table_start,
+ &tmp, pi->sram_end);
+ if (ret)
+ return ret;
+
+ tmp = (tmp >> 24) & 0xff;
+
+ if (tmp == MC_CG_ARB_FREQ_F0)
+ return 0;
+
+ return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
+}
+
+static int ni_populate_memory_timing_parameters(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SMC_NIslands_MCArbDramTimingRegisterSet *arb_regs)
+{
+ u32 dram_timing;
+ u32 dram_timing2;
+
+ arb_regs->mc_arb_rfsh_rate =
+ (u8)rv770_calculate_memory_refresh_rate(rdev, pl->sclk);
+
+
+ radeon_atom_set_engine_dram_timings(rdev,
+ pl->sclk,
+ pl->mclk);
+
+ dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+ arb_regs->mc_arb_dram_timing = cpu_to_be32(dram_timing);
+ arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2);
+
+ return 0;
+}
+
+static int ni_do_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ unsigned int first_arb_set)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ SMC_NIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
+ int i, ret = 0;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ ret = ni_populate_memory_timing_parameters(rdev, &state->performance_levels[i], &arb_regs);
+ if (ret)
+ break;
+
+ ret = rv770_copy_bytes_to_smc(rdev,
+ (u16)(ni_pi->arb_table_start +
+ offsetof(SMC_NIslands_MCArbDramTimingRegisters, data) +
+ sizeof(SMC_NIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i)),
+ (u8 *)&arb_regs,
+ (u16)sizeof(SMC_NIslands_MCArbDramTimingRegisterSet),
+ pi->sram_end);
+ if (ret)
+ break;
+ }
+ return ret;
+}
+
+static int ni_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ return ni_do_program_memory_timing_parameters(rdev, radeon_new_state,
+ NISLANDS_DRIVER_STATE_ARB_INDEX);
+}
+
+static void ni_populate_initial_mvdd_value(struct radeon_device *rdev,
+ struct NISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ voltage->index = eg_pi->mvdd_high_index;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+}
+
+static int ni_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_initial_state,
+ NISLANDS_SMC_STATETABLE *table)
+{
+ struct ni_ps *initial_state = ni_get_ps(radeon_initial_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 reg;
+ int ret;
+
+ table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
+ cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl);
+ table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 =
+ cpu_to_be32(ni_pi->clock_registers.mpll_ad_func_cntl_2);
+ table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
+ cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl);
+ table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 =
+ cpu_to_be32(ni_pi->clock_registers.mpll_dq_func_cntl_2);
+ table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(ni_pi->clock_registers.mclk_pwrmgt_cntl);
+ table->initialState.levels[0].mclk.vDLL_CNTL =
+ cpu_to_be32(ni_pi->clock_registers.dll_cntl);
+ table->initialState.levels[0].mclk.vMPLL_SS =
+ cpu_to_be32(ni_pi->clock_registers.mpll_ss1);
+ table->initialState.levels[0].mclk.vMPLL_SS2 =
+ cpu_to_be32(ni_pi->clock_registers.mpll_ss2);
+ table->initialState.levels[0].mclk.mclk_value =
+ cpu_to_be32(initial_state->performance_levels[0].mclk);
+
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_2);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_3);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
+ cpu_to_be32(ni_pi->clock_registers.cg_spll_func_cntl_4);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+ cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cpu_to_be32(ni_pi->clock_registers.cg_spll_spread_spectrum_2);
+ table->initialState.levels[0].sclk.sclk_value =
+ cpu_to_be32(initial_state->performance_levels[0].sclk);
+ table->initialState.levels[0].arbRefreshState =
+ NISLANDS_INITIAL_STATE_ARB_INDEX;
+
+ table->initialState.levels[0].ACIndex = 0;
+
+ ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ initial_state->performance_levels[0].vddc,
+ &table->initialState.levels[0].vddc);
+ if (!ret) {
+ u16 std_vddc;
+
+ ret = ni_get_std_voltage_value(rdev,
+ &table->initialState.levels[0].vddc,
+ &std_vddc);
+ if (!ret)
+ ni_populate_std_voltage_value(rdev, std_vddc,
+ table->initialState.levels[0].vddc.index,
+ &table->initialState.levels[0].std_vddc);
+ }
+
+ if (eg_pi->vddci_control)
+ ni_populate_voltage_value(rdev,
+ &eg_pi->vddci_voltage_table,
+ initial_state->performance_levels[0].vddci,
+ &table->initialState.levels[0].vddci);
+
+ ni_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd);
+
+ reg = CG_R(0xffff) | CG_L(0);
+ table->initialState.levels[0].aT = cpu_to_be32(reg);
+
+ table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+ if (pi->boot_in_gen2)
+ table->initialState.levels[0].gen2PCIE = 1;
+ else
+ table->initialState.levels[0].gen2PCIE = 0;
+
+ if (pi->mem_gddr5) {
+ table->initialState.levels[0].strobeMode =
+ cypress_get_strobe_mode_settings(rdev,
+ initial_state->performance_levels[0].mclk);
+
+ if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
+ table->initialState.levels[0].mcFlags = NISLANDS_SMC_MC_EDC_RD_FLAG | NISLANDS_SMC_MC_EDC_WR_FLAG;
+ else
+ table->initialState.levels[0].mcFlags = 0;
+ }
+
+ table->initialState.levelCount = 1;
+
+ table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ table->initialState.levels[0].dpm2.MaxPS = 0;
+ table->initialState.levels[0].dpm2.NearTDPDec = 0;
+ table->initialState.levels[0].dpm2.AboveSafeInc = 0;
+ table->initialState.levels[0].dpm2.BelowSafeInc = 0;
+
+ reg = MIN_POWER_MASK | MAX_POWER_MASK;
+ table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+ reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+ return 0;
+}
+
+static int ni_populate_smc_acpi_state(struct radeon_device *rdev,
+ NISLANDS_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 mpll_ad_func_cntl = ni_pi->clock_registers.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl = ni_pi->clock_registers.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2;
+ u32 spll_func_cntl = ni_pi->clock_registers.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = ni_pi->clock_registers.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = ni_pi->clock_registers.cg_spll_func_cntl_3;
+ u32 spll_func_cntl_4 = ni_pi->clock_registers.cg_spll_func_cntl_4;
+ u32 mclk_pwrmgt_cntl = ni_pi->clock_registers.mclk_pwrmgt_cntl;
+ u32 dll_cntl = ni_pi->clock_registers.dll_cntl;
+ u32 reg;
+ int ret;
+
+ table->ACPIState = table->initialState;
+
+ table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc) {
+ ret = ni_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
+ if (!ret) {
+ u16 std_vddc;
+
+ ret = ni_get_std_voltage_value(rdev,
+ &table->ACPIState.levels[0].vddc, &std_vddc);
+ if (!ret)
+ ni_populate_std_voltage_value(rdev, std_vddc,
+ table->ACPIState.levels[0].vddc.index,
+ &table->ACPIState.levels[0].std_vddc);
+ }
+
+ if (pi->pcie_gen2) {
+ if (pi->acpi_pcie_gen2)
+ table->ACPIState.levels[0].gen2PCIE = 1;
+ else
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ } else {
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ }
+ } else {
+ ret = ni_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ pi->min_vddc_in_table,
+ &table->ACPIState.levels[0].vddc);
+ if (!ret) {
+ u16 std_vddc;
+
+ ret = ni_get_std_voltage_value(rdev,
+ &table->ACPIState.levels[0].vddc,
+ &std_vddc);
+ if (!ret)
+ ni_populate_std_voltage_value(rdev, std_vddc,
+ table->ACPIState.levels[0].vddc.index,
+ &table->ACPIState.levels[0].std_vddc);
+ }
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ }
+
+ if (eg_pi->acpi_vddci) {
+ if (eg_pi->vddci_control)
+ ni_populate_voltage_value(rdev,
+ &eg_pi->vddci_voltage_table,
+ eg_pi->acpi_vddci,
+ &table->ACPIState.levels[0].vddci);
+ }
+
+
+ mpll_ad_func_cntl &= ~PDNB;
+
+ mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+ if (pi->mem_gddr5)
+ mpll_dq_func_cntl &= ~PDNB;
+ mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN | BYPASS;
+
+
+ mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
+ MRDCKA1_RESET |
+ MRDCKB0_RESET |
+ MRDCKB1_RESET |
+ MRDCKC0_RESET |
+ MRDCKC1_RESET |
+ MRDCKD0_RESET |
+ MRDCKD1_RESET);
+
+ mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+ MRDCKA1_PDNB |
+ MRDCKB0_PDNB |
+ MRDCKB1_PDNB |
+ MRDCKC0_PDNB |
+ MRDCKC1_PDNB |
+ MRDCKD0_PDNB |
+ MRDCKD1_PDNB);
+
+ dll_cntl |= (MRDCKA0_BYPASS |
+ MRDCKA1_BYPASS |
+ MRDCKB0_BYPASS |
+ MRDCKB1_BYPASS |
+ MRDCKC0_BYPASS |
+ MRDCKC1_BYPASS |
+ MRDCKD0_BYPASS |
+ MRDCKD1_BYPASS);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+ table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+ table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ table->ACPIState.levels[0].mclk.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+ table->ACPIState.levels[0].mclk.mclk_value = 0;
+
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(spll_func_cntl_4);
+
+ table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+ ni_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+ if (eg_pi->dynamic_ac_timing)
+ table->ACPIState.levels[0].ACIndex = 1;
+
+ table->ACPIState.levels[0].dpm2.MaxPS = 0;
+ table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
+ table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
+ table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
+
+ reg = MIN_POWER_MASK | MAX_POWER_MASK;
+ table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+ reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+ return 0;
+}
+
+static int ni_init_smc_table(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ int ret;
+ struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+ NISLANDS_SMC_STATETABLE *table = &ni_pi->smc_statetable;
+
+ memset(table, 0, sizeof(NISLANDS_SMC_STATETABLE));
+
+ ni_populate_smc_voltage_tables(rdev, table);
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_NI:
+ case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+ break;
+ case THERMAL_TYPE_NONE:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+ break;
+ default:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+ break;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (pi->mem_gddr5)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ ret = ni_populate_smc_initial_state(rdev, radeon_boot_state, table);
+ if (ret)
+ return ret;
+
+ ret = ni_populate_smc_acpi_state(rdev, table);
+ if (ret)
+ return ret;
+
+ table->driverState = table->initialState;
+
+ table->ULVState = table->initialState;
+
+ ret = ni_do_program_memory_timing_parameters(rdev, radeon_boot_state,
+ NISLANDS_INITIAL_STATE_ARB_INDEX);
+ if (ret)
+ return ret;
+
+ return rv770_copy_bytes_to_smc(rdev, pi->state_table_start, (u8 *)table,
+ sizeof(NISLANDS_SMC_STATETABLE), pi->sram_end);
+}
+
+static int ni_calculate_sclk_params(struct radeon_device *rdev,
+ u32 engine_clock,
+ NISLANDS_SMC_SCLK_VALUE *sclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ u32 spll_func_cntl = ni_pi->clock_registers.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = ni_pi->clock_registers.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = ni_pi->clock_registers.cg_spll_func_cntl_3;
+ u32 spll_func_cntl_4 = ni_pi->clock_registers.cg_spll_func_cntl_4;
+ u32 cg_spll_spread_spectrum = ni_pi->clock_registers.cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2 = ni_pi->clock_registers.cg_spll_spread_spectrum_2;
+ u64 tmp;
+ u32 reference_clock = rdev->clock.spll.reference_freq;
+ u32 reference_divider;
+ u32 fbdiv;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ engine_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = 1 + dividers.ref_div;
+
+
+ tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16834;
+ do_div(tmp, reference_clock);
+ fbdiv = (u32) tmp;
+
+ spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
+ spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+ spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+ spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+ spll_func_cntl_3 |= SPLL_DITHEN;
+
+ if (pi->sclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = engine_clock * dividers.post_div;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &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 &= ~CLK_S_MASK;
+ cg_spll_spread_spectrum |= CLK_S(clk_s);
+ cg_spll_spread_spectrum |= SSEN;
+
+ cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+ cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+ }
+ }
+
+ sclk->sclk_value = engine_clock;
+ sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl;
+ sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2;
+ sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3;
+ sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4;
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum;
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2;
+
+ return 0;
+}
+
+static int ni_populate_sclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ NISLANDS_SMC_SCLK_VALUE *sclk)
+{
+ NISLANDS_SMC_SCLK_VALUE sclk_tmp;
+ int ret;
+
+ ret = ni_calculate_sclk_params(rdev, engine_clock, &sclk_tmp);
+ if (!ret) {
+ sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value);
+ sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL);
+ sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2);
+ sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3);
+ sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2);
+ }
+
+ return ret;
+}
+
+static int ni_init_smc_spll_table(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ SMC_NISLANDS_SPLL_DIV_TABLE *spll_table;
+ NISLANDS_SMC_SCLK_VALUE sclk_params;
+ u32 fb_div;
+ u32 p_div;
+ u32 clk_s;
+ u32 clk_v;
+ u32 sclk = 0;
+ int i, ret;
+ u32 tmp;
+
+ if (ni_pi->spll_table_start == 0)
+ return -EINVAL;
+
+ spll_table = kzalloc(sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
+ if (spll_table == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < 256; i++) {
+ ret = ni_calculate_sclk_params(rdev, sclk, &sclk_params);
+ if (ret)
+ break;
+
+ p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
+ fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+ clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
+ clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;
+
+ fb_div &= ~0x00001FFF;
+ fb_div >>= 1;
+ clk_v >>= 6;
+
+ if (p_div & ~(SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
+ ret = -EINVAL;
+
+ if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+ ret = -EINVAL;
+
+ if (clk_s & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+ ret = -EINVAL;
+
+ if (clk_v & ~(SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
+ ret = -EINVAL;
+
+ if (ret)
+ break;
+
+ tmp = ((fb_div << SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) |
+ ((p_div << SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK);
+ spll_table->freq[i] = cpu_to_be32(tmp);
+
+ tmp = ((clk_v << SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK) |
+ ((clk_s << SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK);
+ spll_table->ss[i] = cpu_to_be32(tmp);
+
+ sclk += 512;
+ }
+
+ if (!ret)
+ ret = rv770_copy_bytes_to_smc(rdev, ni_pi->spll_table_start, (u8 *)spll_table,
+ sizeof(SMC_NISLANDS_SPLL_DIV_TABLE), pi->sram_end);
+
+ kfree(spll_table);
+
+ return ret;
+}
+
+static int ni_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ u32 memory_clock,
+ NISLANDS_SMC_MCLK_VALUE *mclk,
+ bool strobe_mode,
+ bool dll_state_on)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 mpll_ad_func_cntl = ni_pi->clock_registers.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 = ni_pi->clock_registers.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl = ni_pi->clock_registers.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 = ni_pi->clock_registers.mpll_dq_func_cntl_2;
+ u32 mclk_pwrmgt_cntl = ni_pi->clock_registers.mclk_pwrmgt_cntl;
+ u32 dll_cntl = ni_pi->clock_registers.dll_cntl;
+ u32 mpll_ss1 = ni_pi->clock_registers.mpll_ss1;
+ u32 mpll_ss2 = ni_pi->clock_registers.mpll_ss2;
+ struct atom_clock_dividers dividers;
+ u32 ibias;
+ u32 dll_speed;
+ int ret;
+ u32 mc_seq_misc7;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ memory_clock, strobe_mode, &dividers);
+ if (ret)
+ return ret;
+
+ if (!strobe_mode) {
+ mc_seq_misc7 = RREG32(MC_SEQ_MISC7);
+
+ if (mc_seq_misc7 & 0x8000000)
+ dividers.post_div = 1;
+ }
+
+ ibias = cypress_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
+
+ mpll_ad_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_ad_func_cntl |= CLKR(dividers.ref_div);
+ mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+ mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
+ mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+ mpll_ad_func_cntl |= IBIAS(ibias);
+
+ if (dividers.vco_mode)
+ mpll_ad_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+ if (pi->mem_gddr5) {
+ mpll_dq_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_dq_func_cntl |= CLKR(dividers.ref_div);
+ mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+ mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
+ mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+ mpll_dq_func_cntl |= IBIAS(ibias);
+
+ if (strobe_mode)
+ mpll_dq_func_cntl &= ~PDNB;
+ else
+ mpll_dq_func_cntl |= PDNB;
+
+ if (dividers.vco_mode)
+ mpll_dq_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_dq_func_cntl_2 &= ~VCO_MODE;
+ }
+
+ if (pi->mclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = memory_clock * dividers.post_div;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+ u32 reference_clock = rdev->clock.mpll.reference_freq;
+ u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
+ u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+ u32 clk_v = ss.percentage *
+ (0x4000 * dividers.whole_fb_div + 0x800 * dividers.frac_fb_div) / (clk_s * 625);
+
+ mpll_ss1 &= ~CLKV_MASK;
+ mpll_ss1 |= CLKV(clk_v);
+
+ mpll_ss2 &= ~CLKS_MASK;
+ mpll_ss2 |= CLKS(clk_s);
+ }
+ }
+
+ dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
+ memory_clock);
+
+ mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+ mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
+ if (dll_state_on)
+ mclk_pwrmgt_cntl |= (MRDCKA0_PDNB |
+ MRDCKA1_PDNB |
+ MRDCKB0_PDNB |
+ MRDCKB1_PDNB |
+ MRDCKC0_PDNB |
+ MRDCKC1_PDNB |
+ MRDCKD0_PDNB |
+ MRDCKD1_PDNB);
+ else
+ mclk_pwrmgt_cntl &= ~(MRDCKA0_PDNB |
+ MRDCKA1_PDNB |
+ MRDCKB0_PDNB |
+ MRDCKB1_PDNB |
+ MRDCKC0_PDNB |
+ MRDCKC1_PDNB |
+ MRDCKD0_PDNB |
+ MRDCKD1_PDNB);
+
+
+ mclk->mclk_value = cpu_to_be32(memory_clock);
+ mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ mclk->vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ mclk->vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+ mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ mclk->vDLL_CNTL = cpu_to_be32(dll_cntl);
+ mclk->vMPLL_SS = cpu_to_be32(mpll_ss1);
+ mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+ return 0;
+}
+
+static void ni_populate_smc_sp(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ NISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct ni_ps *ps = ni_get_ps(radeon_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+
+ for (i = 0; i < ps->performance_level_count - 1; i++)
+ smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
+
+ smc_state->levels[ps->performance_level_count - 1].bSP =
+ cpu_to_be32(pi->psp);
+}
+
+static int ni_convert_power_level_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ NISLANDS_SMC_HW_PERFORMANCE_LEVEL *level)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ int ret;
+ bool dll_state_on;
+ u16 std_vddc;
+ u32 tmp = RREG32(DC_STUTTER_CNTL);
+
+ level->gen2PCIE = pi->pcie_gen2 ?
+ ((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
+
+ ret = ni_populate_sclk_value(rdev, pl->sclk, &level->sclk);
+ if (ret)
+ return ret;
+
+ level->mcFlags = 0;
+ if (pi->mclk_stutter_mode_threshold &&
+ (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
+ !eg_pi->uvd_enabled &&
+ (tmp & DC_STUTTER_ENABLE_A) &&
+ (tmp & DC_STUTTER_ENABLE_B))
+ level->mcFlags |= NISLANDS_SMC_MC_STUTTER_EN;
+
+ if (pi->mem_gddr5) {
+ if (pl->mclk > pi->mclk_edc_enable_threshold)
+ level->mcFlags |= NISLANDS_SMC_MC_EDC_RD_FLAG;
+ if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
+ level->mcFlags |= NISLANDS_SMC_MC_EDC_WR_FLAG;
+
+ level->strobeMode = cypress_get_strobe_mode_settings(rdev, pl->mclk);
+
+ if (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) {
+ if (cypress_get_mclk_frequency_ratio(rdev, pl->mclk, true) >=
+ ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
+ dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+ else
+ dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+ } else {
+ dll_state_on = false;
+ if (pl->mclk > ni_pi->mclk_rtt_mode_threshold)
+ level->mcFlags |= NISLANDS_SMC_MC_RTT_ENABLE;
+ }
+
+ ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk,
+ &level->mclk,
+ (level->strobeMode & NISLANDS_SMC_STROBE_ENABLE) != 0,
+ dll_state_on);
+ } else
+ ret = ni_populate_mclk_value(rdev, pl->sclk, pl->mclk, &level->mclk, 1, 1);
+
+ if (ret)
+ return ret;
+
+ ret = ni_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ pl->vddc, &level->vddc);
+ if (ret)
+ return ret;
+
+ ret = ni_get_std_voltage_value(rdev, &level->vddc, &std_vddc);
+ if (ret)
+ return ret;
+
+ ni_populate_std_voltage_value(rdev, std_vddc,
+ level->vddc.index, &level->std_vddc);
+
+ if (eg_pi->vddci_control) {
+ ret = ni_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table,
+ pl->vddci, &level->vddci);
+ if (ret)
+ return ret;
+ }
+
+ ni_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+ return ret;
+}
+
+static int ni_populate_smc_t(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ NISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ u32 a_t;
+ u32 t_l, t_h;
+ u32 high_bsp;
+ int i, ret;
+
+ if (state->performance_level_count >= 9)
+ return -EINVAL;
+
+ if (state->performance_level_count < 2) {
+ a_t = CG_R(0xffff) | CG_L(0);
+ smc_state->levels[0].aT = cpu_to_be32(a_t);
+ return 0;
+ }
+
+ smc_state->levels[0].aT = cpu_to_be32(0);
+
+ for (i = 0; i <= state->performance_level_count - 2; i++) {
+ if (eg_pi->uvd_enabled)
+ ret = r600_calculate_at(
+ 1000 * (i * (eg_pi->smu_uvd_hs ? 2 : 8) + 2),
+ 100 * R600_AH_DFLT,
+ state->performance_levels[i + 1].sclk,
+ state->performance_levels[i].sclk,
+ &t_l,
+ &t_h);
+ else
+ ret = r600_calculate_at(
+ 1000 * (i + 1),
+ 100 * R600_AH_DFLT,
+ state->performance_levels[i + 1].sclk,
+ state->performance_levels[i].sclk,
+ &t_l,
+ &t_h);
+
+ if (ret) {
+ t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT;
+ t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT;
+ }
+
+ a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK;
+ a_t |= CG_R(t_l * pi->bsp / 20000);
+ smc_state->levels[i].aT = cpu_to_be32(a_t);
+
+ high_bsp = (i == state->performance_level_count - 2) ?
+ pi->pbsp : pi->bsp;
+
+ a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000);
+ smc_state->levels[i + 1].aT = cpu_to_be32(a_t);
+ }
+
+ return 0;
+}
+
+static int ni_populate_power_containment_values(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ NISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ u32 prev_sclk;
+ u32 max_sclk;
+ u32 min_sclk;
+ int i, ret;
+ u32 tdp_limit;
+ u32 near_tdp_limit;
+ u32 power_boost_limit;
+ u8 max_ps_percent;
+
+ if (ni_pi->enable_power_containment == false)
+ return 0;
+
+ if (state->performance_level_count == 0)
+ return -EINVAL;
+
+ if (smc_state->levelCount != state->performance_level_count)
+ return -EINVAL;
+
+ ret = ni_calculate_adjusted_tdp_limits(rdev,
+ false, /* ??? */
+ rdev->pm.dpm.tdp_adjustment,
+ &tdp_limit,
+ &near_tdp_limit);
+ if (ret)
+ return ret;
+
+ power_boost_limit = ni_calculate_power_boost_limit(rdev, radeon_state, near_tdp_limit);
+
+ ret = rv770_write_smc_sram_dword(rdev,
+ pi->state_table_start +
+ offsetof(NISLANDS_SMC_STATETABLE, dpm2Params) +
+ offsetof(PP_NIslands_DPM2Parameters, PowerBoostLimit),
+ ni_scale_power_for_smc(power_boost_limit, ni_get_smc_power_scaling_factor(rdev)),
+ pi->sram_end);
+ if (ret)
+ power_boost_limit = 0;
+
+ smc_state->levels[0].dpm2.MaxPS = 0;
+ smc_state->levels[0].dpm2.NearTDPDec = 0;
+ smc_state->levels[0].dpm2.AboveSafeInc = 0;
+ smc_state->levels[0].dpm2.BelowSafeInc = 0;
+ smc_state->levels[0].stateFlags |= power_boost_limit ? PPSMC_STATEFLAG_POWERBOOST : 0;
+
+ for (i = 1; i < state->performance_level_count; i++) {
+ prev_sclk = state->performance_levels[i-1].sclk;
+ max_sclk = state->performance_levels[i].sclk;
+ max_ps_percent = (i != (state->performance_level_count - 1)) ?
+ NISLANDS_DPM2_MAXPS_PERCENT_M : NISLANDS_DPM2_MAXPS_PERCENT_H;
+
+ if (max_sclk < prev_sclk)
+ return -EINVAL;
+
+ if ((max_ps_percent == 0) || (prev_sclk == max_sclk) || eg_pi->uvd_enabled)
+ min_sclk = max_sclk;
+ else if (1 == i)
+ min_sclk = prev_sclk;
+ else
+ min_sclk = (prev_sclk * (u32)max_ps_percent) / 100;
+
+ if (min_sclk < state->performance_levels[0].sclk)
+ min_sclk = state->performance_levels[0].sclk;
+
+ if (min_sclk == 0)
+ return -EINVAL;
+
+ smc_state->levels[i].dpm2.MaxPS =
+ (u8)((NISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk);
+ smc_state->levels[i].dpm2.NearTDPDec = NISLANDS_DPM2_NEAR_TDP_DEC;
+ smc_state->levels[i].dpm2.AboveSafeInc = NISLANDS_DPM2_ABOVE_SAFE_INC;
+ smc_state->levels[i].dpm2.BelowSafeInc = NISLANDS_DPM2_BELOW_SAFE_INC;
+ smc_state->levels[i].stateFlags |=
+ ((i != (state->performance_level_count - 1)) && power_boost_limit) ?
+ PPSMC_STATEFLAG_POWERBOOST : 0;
+ }
+
+ return 0;
+}
+
+static int ni_populate_sq_ramping_values(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ NISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ u32 sq_power_throttle;
+ u32 sq_power_throttle2;
+ bool enable_sq_ramping = ni_pi->enable_sq_ramping;
+ int i;
+
+ if (state->performance_level_count == 0)
+ return -EINVAL;
+
+ if (smc_state->levelCount != state->performance_level_count)
+ return -EINVAL;
+
+ if (rdev->pm.dpm.sq_ramping_threshold == 0)
+ return -EINVAL;
+
+ if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
+ enable_sq_ramping = false;
+
+ if (NISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
+ enable_sq_ramping = false;
+
+ if (NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
+ enable_sq_ramping = false;
+
+ if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
+ enable_sq_ramping = false;
+
+ if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ enable_sq_ramping = false;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ sq_power_throttle = 0;
+ sq_power_throttle2 = 0;
+
+ if ((state->performance_levels[i].sclk >= rdev->pm.dpm.sq_ramping_threshold) &&
+ enable_sq_ramping) {
+ sq_power_throttle |= MAX_POWER(NISLANDS_DPM2_SQ_RAMP_MAX_POWER);
+ sq_power_throttle |= MIN_POWER(NISLANDS_DPM2_SQ_RAMP_MIN_POWER);
+ sq_power_throttle2 |= MAX_POWER_DELTA(NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
+ sq_power_throttle2 |= STI_SIZE(NISLANDS_DPM2_SQ_RAMP_STI_SIZE);
+ sq_power_throttle2 |= LTI_RATIO(NISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
+ } else {
+ sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
+ sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ }
+
+ smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle);
+ smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2);
+ }
+
+ return 0;
+}
+
+static int ni_enable_power_containment(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ bool enable)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ PPSMC_Result smc_result;
+ int ret = 0;
+
+ if (ni_pi->enable_power_containment) {
+ if (enable) {
+ if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingActive);
+ if (smc_result != PPSMC_Result_OK) {
+ ret = -EINVAL;
+ ni_pi->pc_enabled = false;
+ } else {
+ ni_pi->pc_enabled = true;
+ }
+ }
+ } else {
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_TDPClampingInactive);
+ if (smc_result != PPSMC_Result_OK)
+ ret = -EINVAL;
+ ni_pi->pc_enabled = false;
+ }
+ }
+
+ return ret;
+}
+
+static int ni_convert_power_state_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ NISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ int i, ret;
+ u32 threshold = state->performance_levels[state->performance_level_count - 1].sclk * 100 / 100;
+
+ if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
+ smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ smc_state->levelCount = 0;
+
+ if (state->performance_level_count > NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE)
+ return -EINVAL;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ ret = ni_convert_power_level_to_smc(rdev, &state->performance_levels[i],
+ &smc_state->levels[i]);
+ smc_state->levels[i].arbRefreshState =
+ (u8)(NISLANDS_DRIVER_STATE_ARB_INDEX + i);
+
+ if (ret)
+ return ret;
+
+ if (ni_pi->enable_power_containment)
+ smc_state->levels[i].displayWatermark =
+ (state->performance_levels[i].sclk < threshold) ?
+ PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+ else
+ smc_state->levels[i].displayWatermark = (i < 2) ?
+ PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ if (eg_pi->dynamic_ac_timing)
+ smc_state->levels[i].ACIndex = NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i;
+ else
+ smc_state->levels[i].ACIndex = 0;
+
+ smc_state->levelCount++;
+ }
+
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_watermark_threshold,
+ cpu_to_be32(threshold / 512));
+
+ ni_populate_smc_sp(rdev, radeon_state, smc_state);
+
+ ret = ni_populate_power_containment_values(rdev, radeon_state, smc_state);
+ if (ret)
+ ni_pi->enable_power_containment = false;
+
+ ret = ni_populate_sq_ramping_values(rdev, radeon_state, smc_state);
+ if (ret)
+ ni_pi->enable_sq_ramping = false;
+
+ return ni_populate_smc_t(rdev, radeon_state, smc_state);
+}
+
+static int ni_upload_sw_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u16 address = pi->state_table_start +
+ offsetof(NISLANDS_SMC_STATETABLE, driverState);
+ u16 state_size = sizeof(NISLANDS_SMC_SWSTATE) +
+ ((NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1) * sizeof(NISLANDS_SMC_HW_PERFORMANCE_LEVEL));
+ int ret;
+ NISLANDS_SMC_SWSTATE *smc_state = kzalloc(state_size, GFP_KERNEL);
+
+ if (smc_state == NULL)
+ return -ENOMEM;
+
+ ret = ni_convert_power_state_to_smc(rdev, radeon_new_state, smc_state);
+ if (ret)
+ goto done;
+
+ ret = rv770_copy_bytes_to_smc(rdev, address, (u8 *)smc_state, state_size, pi->sram_end);
+
+done:
+ kfree(smc_state);
+
+ return ret;
+}
+
+static int ni_set_mc_special_registers(struct radeon_device *rdev,
+ struct ni_mc_reg_table *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 i, j, k;
+ u32 temp_reg;
+
+ for (i = 0, j = table->last; i < table->last; i++) {
+ switch (table->mc_reg_address[i].s1) {
+ case MC_SEQ_MISC1 >> 2:
+ if (j >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ temp_reg = RREG32(MC_PMG_CMD_EMRS);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ 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 >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ temp_reg = RREG32(MC_PMG_CMD_MRS);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ 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 (!pi->mem_gddr5)
+ table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+ }
+ j++;
+ if (j > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ break;
+ case MC_SEQ_RESERVE_M >> 2:
+ temp_reg = RREG32(MC_PMG_CMD_MRS1);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ 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 > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ table->last = j;
+
+ return 0;
+}
+
+static bool ni_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+ bool result = true;
+
+ switch (in_reg) {
+ case MC_SEQ_RAS_TIMING >> 2:
+ *out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_CAS_TIMING >> 2:
+ *out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_MISC_TIMING >> 2:
+ *out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_MISC_TIMING2 >> 2:
+ *out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
+ break;
+ case MC_SEQ_RD_CTL_D0 >> 2:
+ *out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
+ break;
+ case MC_SEQ_RD_CTL_D1 >> 2:
+ *out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_D0 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_D1 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
+ break;
+ case MC_PMG_CMD_EMRS >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS1 >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ break;
+ case MC_SEQ_PMG_TIMING >> 2:
+ *out_reg = MC_SEQ_PMG_TIMING_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS2 >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static void ni_set_valid_flag(struct ni_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 ni_set_s0_mc_reg_index(struct ni_mc_reg_table *table)
+{
+ u32 i;
+ u16 address;
+
+ for (i = 0; i < table->last; i++)
+ table->mc_reg_address[i].s0 =
+ ni_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+ address : table->mc_reg_address[i].s1;
+}
+
+static int ni_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
+ struct ni_mc_reg_table *ni_table)
+{
+ u8 i, j;
+
+ if (table->last > SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+ return -EINVAL;
+
+ for (i = 0; i < table->last; i++)
+ ni_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+ ni_table->last = table->last;
+
+ for (i = 0; i < table->num_entries; i++) {
+ ni_table->mc_reg_table_entry[i].mclk_max =
+ table->mc_reg_table_entry[i].mclk_max;
+ for (j = 0; j < table->last; j++)
+ ni_table->mc_reg_table_entry[i].mc_data[j] =
+ table->mc_reg_table_entry[i].mc_data[j];
+ }
+ ni_table->num_entries = table->num_entries;
+
+ return 0;
+}
+
+static int ni_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ int ret;
+ struct atom_mc_reg_table *table;
+ struct ni_mc_reg_table *ni_table = &ni_pi->mc_reg_table;
+ u8 module_index = rv770_get_memory_module_index(rdev);
+
+ table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
+ WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
+ WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
+ WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
+ WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
+ WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
+ WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
+ WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
+ WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
+ WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
+ WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
+ WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
+ WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
+
+ ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
+
+ if (ret)
+ goto init_mc_done;
+
+ ret = ni_copy_vbios_mc_reg_table(table, ni_table);
+
+ if (ret)
+ goto init_mc_done;
+
+ ni_set_s0_mc_reg_index(ni_table);
+
+ ret = ni_set_mc_special_registers(rdev, ni_table);
+
+ if (ret)
+ goto init_mc_done;
+
+ ni_set_valid_flag(ni_table);
+
+init_mc_done:
+ kfree(table);
+
+ return ret;
+}
+
+static void ni_populate_mc_reg_addresses(struct radeon_device *rdev,
+ SMC_NIslands_MCRegisters *mc_reg_table)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 i, j;
+
+ for (i = 0, j = 0; j < ni_pi->mc_reg_table.last; j++) {
+ if (ni_pi->mc_reg_table.valid_flag & (1 << j)) {
+ if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ break;
+ mc_reg_table->address[i].s0 =
+ cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s0);
+ mc_reg_table->address[i].s1 =
+ cpu_to_be16(ni_pi->mc_reg_table.mc_reg_address[j].s1);
+ i++;
+ }
+ }
+ mc_reg_table->last = (u8)i;
+}
+
+
+static void ni_convert_mc_registers(struct ni_mc_reg_entry *entry,
+ SMC_NIslands_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 ni_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SMC_NIslands_MCRegisterSet *mc_reg_table_data)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 i = 0;
+
+ for (i = 0; i < ni_pi->mc_reg_table.num_entries; i++) {
+ if (pl->mclk <= ni_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+ break;
+ }
+
+ if ((i == ni_pi->mc_reg_table.num_entries) && (i > 0))
+ --i;
+
+ ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[i],
+ mc_reg_table_data,
+ ni_pi->mc_reg_table.last,
+ ni_pi->mc_reg_table.valid_flag);
+}
+
+static void ni_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SMC_NIslands_MCRegisters *mc_reg_table)
+{
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ int i;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ ni_convert_mc_reg_table_entry_to_smc(rdev,
+ &state->performance_levels[i],
+ &mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]);
+ }
+}
+
+static int ni_populate_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *boot_state = ni_get_ps(radeon_boot_state);
+ SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
+
+ memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters));
+
+ rv770_write_smc_soft_register(rdev, NI_SMC_SOFT_REGISTER_seq_index, 1);
+
+ ni_populate_mc_reg_addresses(rdev, mc_reg_table);
+
+ ni_convert_mc_reg_table_entry_to_smc(rdev, &boot_state->performance_levels[0],
+ &mc_reg_table->data[0]);
+
+ ni_convert_mc_registers(&ni_pi->mc_reg_table.mc_reg_table_entry[0],
+ &mc_reg_table->data[1],
+ ni_pi->mc_reg_table.last,
+ ni_pi->mc_reg_table.valid_flag);
+
+ ni_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, mc_reg_table);
+
+ return rv770_copy_bytes_to_smc(rdev, eg_pi->mc_reg_table_start,
+ (u8 *)mc_reg_table,
+ sizeof(SMC_NIslands_MCRegisters),
+ pi->sram_end);
+}
+
+static int ni_upload_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *ni_new_state = ni_get_ps(radeon_new_state);
+ SMC_NIslands_MCRegisters *mc_reg_table = &ni_pi->smc_mc_reg_table;
+ u16 address;
+
+ memset(mc_reg_table, 0, sizeof(SMC_NIslands_MCRegisters));
+
+ ni_convert_mc_reg_table_to_smc(rdev, radeon_new_state, mc_reg_table);
+
+ address = eg_pi->mc_reg_table_start +
+ (u16)offsetof(SMC_NIslands_MCRegisters, data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]);
+
+ return rv770_copy_bytes_to_smc(rdev, address,
+ (u8 *)&mc_reg_table->data[NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT],
+ sizeof(SMC_NIslands_MCRegisterSet) * ni_new_state->performance_level_count,
+ pi->sram_end);
+}
+
+static int ni_init_driver_calculated_leakage_table(struct radeon_device *rdev,
+ PP_NIslands_CACTABLES *cac_tables)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 leakage = 0;
+ unsigned int i, j, table_size;
+ s32 t;
+ u32 smc_leakage, max_leakage = 0;
+ u32 scaling_factor;
+
+ table_size = eg_pi->vddc_voltage_table.count;
+
+ if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size)
+ table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
+
+ scaling_factor = ni_get_smc_power_scaling_factor(rdev);
+
+ for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++) {
+ for (j = 0; j < table_size; j++) {
+ t = (1000 * ((i + 1) * 8));
+
+ if (t < ni_pi->cac_data.leakage_minimum_temperature)
+ t = ni_pi->cac_data.leakage_minimum_temperature;
+
+ ni_calculate_leakage_for_v_and_t(rdev,
+ &ni_pi->cac_data.leakage_coefficients,
+ eg_pi->vddc_voltage_table.entries[j].value,
+ t,
+ ni_pi->cac_data.i_leakage,
+ &leakage);
+
+ smc_leakage = ni_scale_power_for_smc(leakage, scaling_factor) / 1000;
+ if (smc_leakage > max_leakage)
+ max_leakage = smc_leakage;
+
+ cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(smc_leakage);
+ }
+ }
+
+ for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+ for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
+ cac_tables->cac_lkge_lut[i][j] = cpu_to_be32(max_leakage);
+ }
+ return 0;
+}
+
+static int ni_init_simplified_leakage_table(struct radeon_device *rdev,
+ PP_NIslands_CACTABLES *cac_tables)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_cac_leakage_table *leakage_table =
+ &rdev->pm.dpm.dyn_state.cac_leakage_table;
+ u32 i, j, table_size;
+ u32 smc_leakage, max_leakage = 0;
+ u32 scaling_factor;
+
+ if (!leakage_table)
+ return -EINVAL;
+
+ table_size = leakage_table->count;
+
+ if (eg_pi->vddc_voltage_table.count != table_size)
+ table_size = (eg_pi->vddc_voltage_table.count < leakage_table->count) ?
+ eg_pi->vddc_voltage_table.count : leakage_table->count;
+
+ if (SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES < table_size)
+ table_size = SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
+
+ if (table_size == 0)
+ return -EINVAL;
+
+ scaling_factor = ni_get_smc_power_scaling_factor(rdev);
+
+ for (j = 0; j < table_size; j++) {
+ smc_leakage = leakage_table->entries[j].leakage;
+
+ if (smc_leakage > max_leakage)
+ max_leakage = smc_leakage;
+
+ for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
+ cac_tables->cac_lkge_lut[i][j] =
+ cpu_to_be32(ni_scale_power_for_smc(smc_leakage, scaling_factor));
+ }
+
+ for (j = table_size; j < SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+ for (i = 0; i < SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES; i++)
+ cac_tables->cac_lkge_lut[i][j] =
+ cpu_to_be32(ni_scale_power_for_smc(max_leakage, scaling_factor));
+ }
+ return 0;
+}
+
+static int ni_initialize_smc_cac_tables(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ PP_NIslands_CACTABLES *cac_tables = NULL;
+ int i, ret;
+ u32 reg;
+
+ if (ni_pi->enable_cac == false)
+ return 0;
+
+ cac_tables = kzalloc(sizeof(PP_NIslands_CACTABLES), GFP_KERNEL);
+ if (!cac_tables)
+ return -ENOMEM;
+
+ reg = RREG32(CG_CAC_CTRL) & ~(TID_CNT_MASK | TID_UNIT_MASK);
+ reg |= (TID_CNT(ni_pi->cac_weights->tid_cnt) |
+ TID_UNIT(ni_pi->cac_weights->tid_unit));
+ WREG32(CG_CAC_CTRL, reg);
+
+ for (i = 0; i < NISLANDS_DCCAC_MAX_LEVELS; i++)
+ ni_pi->dc_cac_table[i] = ni_pi->cac_weights->dc_cac[i];
+
+ for (i = 0; i < SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES; i++)
+ cac_tables->cac_bif_lut[i] = ni_pi->cac_weights->pcie_cac[i];
+
+ ni_pi->cac_data.i_leakage = rdev->pm.dpm.cac_leakage;
+ ni_pi->cac_data.pwr_const = 0;
+ ni_pi->cac_data.dc_cac_value = ni_pi->dc_cac_table[NISLANDS_DCCAC_LEVEL_0];
+ ni_pi->cac_data.bif_cac_value = 0;
+ ni_pi->cac_data.mc_wr_weight = ni_pi->cac_weights->mc_write_weight;
+ ni_pi->cac_data.mc_rd_weight = ni_pi->cac_weights->mc_read_weight;
+ ni_pi->cac_data.allow_ovrflw = 0;
+ ni_pi->cac_data.l2num_win_tdp = ni_pi->lta_window_size;
+ ni_pi->cac_data.num_win_tdp = 0;
+ ni_pi->cac_data.lts_truncate_n = ni_pi->lts_truncate;
+
+ if (ni_pi->driver_calculate_cac_leakage)
+ ret = ni_init_driver_calculated_leakage_table(rdev, cac_tables);
+ else
+ ret = ni_init_simplified_leakage_table(rdev, cac_tables);
+
+ if (ret)
+ goto done_free;
+
+ cac_tables->pwr_const = cpu_to_be32(ni_pi->cac_data.pwr_const);
+ cac_tables->dc_cacValue = cpu_to_be32(ni_pi->cac_data.dc_cac_value);
+ cac_tables->bif_cacValue = cpu_to_be32(ni_pi->cac_data.bif_cac_value);
+ cac_tables->AllowOvrflw = ni_pi->cac_data.allow_ovrflw;
+ cac_tables->MCWrWeight = ni_pi->cac_data.mc_wr_weight;
+ cac_tables->MCRdWeight = ni_pi->cac_data.mc_rd_weight;
+ cac_tables->numWin_TDP = ni_pi->cac_data.num_win_tdp;
+ cac_tables->l2numWin_TDP = ni_pi->cac_data.l2num_win_tdp;
+ cac_tables->lts_truncate_n = ni_pi->cac_data.lts_truncate_n;
+
+ ret = rv770_copy_bytes_to_smc(rdev, ni_pi->cac_table_start, (u8 *)cac_tables,
+ sizeof(PP_NIslands_CACTABLES), pi->sram_end);
+
+done_free:
+ if (ret) {
+ ni_pi->enable_cac = false;
+ ni_pi->enable_power_containment = false;
+ }
+
+ kfree(cac_tables);
+
+ return 0;
+}
+
+static int ni_initialize_hardware_cac_manager(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ u32 reg;
+
+ if (!ni_pi->enable_cac ||
+ !ni_pi->cac_configuration_required)
+ return 0;
+
+ if (ni_pi->cac_weights == NULL)
+ return -EINVAL;
+
+ reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_0) & ~(WEIGHT_TCP_SIG0_MASK |
+ WEIGHT_TCP_SIG1_MASK |
+ WEIGHT_TA_SIG_MASK);
+ reg |= (WEIGHT_TCP_SIG0(ni_pi->cac_weights->weight_tcp_sig0) |
+ WEIGHT_TCP_SIG1(ni_pi->cac_weights->weight_tcp_sig1) |
+ WEIGHT_TA_SIG(ni_pi->cac_weights->weight_ta_sig));
+ WREG32_CG(CG_CAC_REGION_1_WEIGHT_0, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_1_WEIGHT_1) & ~(WEIGHT_TCC_EN0_MASK |
+ WEIGHT_TCC_EN1_MASK |
+ WEIGHT_TCC_EN2_MASK);
+ reg |= (WEIGHT_TCC_EN0(ni_pi->cac_weights->weight_tcc_en0) |
+ WEIGHT_TCC_EN1(ni_pi->cac_weights->weight_tcc_en1) |
+ WEIGHT_TCC_EN2(ni_pi->cac_weights->weight_tcc_en2));
+ WREG32_CG(CG_CAC_REGION_1_WEIGHT_1, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_0) & ~(WEIGHT_CB_EN0_MASK |
+ WEIGHT_CB_EN1_MASK |
+ WEIGHT_CB_EN2_MASK |
+ WEIGHT_CB_EN3_MASK);
+ reg |= (WEIGHT_CB_EN0(ni_pi->cac_weights->weight_cb_en0) |
+ WEIGHT_CB_EN1(ni_pi->cac_weights->weight_cb_en1) |
+ WEIGHT_CB_EN2(ni_pi->cac_weights->weight_cb_en2) |
+ WEIGHT_CB_EN3(ni_pi->cac_weights->weight_cb_en3));
+ WREG32_CG(CG_CAC_REGION_2_WEIGHT_0, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_1) & ~(WEIGHT_DB_SIG0_MASK |
+ WEIGHT_DB_SIG1_MASK |
+ WEIGHT_DB_SIG2_MASK |
+ WEIGHT_DB_SIG3_MASK);
+ reg |= (WEIGHT_DB_SIG0(ni_pi->cac_weights->weight_db_sig0) |
+ WEIGHT_DB_SIG1(ni_pi->cac_weights->weight_db_sig1) |
+ WEIGHT_DB_SIG2(ni_pi->cac_weights->weight_db_sig2) |
+ WEIGHT_DB_SIG3(ni_pi->cac_weights->weight_db_sig3));
+ WREG32_CG(CG_CAC_REGION_2_WEIGHT_1, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_2_WEIGHT_2) & ~(WEIGHT_SXM_SIG0_MASK |
+ WEIGHT_SXM_SIG1_MASK |
+ WEIGHT_SXM_SIG2_MASK |
+ WEIGHT_SXS_SIG0_MASK |
+ WEIGHT_SXS_SIG1_MASK);
+ reg |= (WEIGHT_SXM_SIG0(ni_pi->cac_weights->weight_sxm_sig0) |
+ WEIGHT_SXM_SIG1(ni_pi->cac_weights->weight_sxm_sig1) |
+ WEIGHT_SXM_SIG2(ni_pi->cac_weights->weight_sxm_sig2) |
+ WEIGHT_SXS_SIG0(ni_pi->cac_weights->weight_sxs_sig0) |
+ WEIGHT_SXS_SIG1(ni_pi->cac_weights->weight_sxs_sig1));
+ WREG32_CG(CG_CAC_REGION_2_WEIGHT_2, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_0) & ~(WEIGHT_XBR_0_MASK |
+ WEIGHT_XBR_1_MASK |
+ WEIGHT_XBR_2_MASK |
+ WEIGHT_SPI_SIG0_MASK);
+ reg |= (WEIGHT_XBR_0(ni_pi->cac_weights->weight_xbr_0) |
+ WEIGHT_XBR_1(ni_pi->cac_weights->weight_xbr_1) |
+ WEIGHT_XBR_2(ni_pi->cac_weights->weight_xbr_2) |
+ WEIGHT_SPI_SIG0(ni_pi->cac_weights->weight_spi_sig0));
+ WREG32_CG(CG_CAC_REGION_3_WEIGHT_0, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_3_WEIGHT_1) & ~(WEIGHT_SPI_SIG1_MASK |
+ WEIGHT_SPI_SIG2_MASK |
+ WEIGHT_SPI_SIG3_MASK |
+ WEIGHT_SPI_SIG4_MASK |
+ WEIGHT_SPI_SIG5_MASK);
+ reg |= (WEIGHT_SPI_SIG1(ni_pi->cac_weights->weight_spi_sig1) |
+ WEIGHT_SPI_SIG2(ni_pi->cac_weights->weight_spi_sig2) |
+ WEIGHT_SPI_SIG3(ni_pi->cac_weights->weight_spi_sig3) |
+ WEIGHT_SPI_SIG4(ni_pi->cac_weights->weight_spi_sig4) |
+ WEIGHT_SPI_SIG5(ni_pi->cac_weights->weight_spi_sig5));
+ WREG32_CG(CG_CAC_REGION_3_WEIGHT_1, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_0) & ~(WEIGHT_LDS_SIG0_MASK |
+ WEIGHT_LDS_SIG1_MASK |
+ WEIGHT_SC_MASK);
+ reg |= (WEIGHT_LDS_SIG0(ni_pi->cac_weights->weight_lds_sig0) |
+ WEIGHT_LDS_SIG1(ni_pi->cac_weights->weight_lds_sig1) |
+ WEIGHT_SC(ni_pi->cac_weights->weight_sc));
+ WREG32_CG(CG_CAC_REGION_4_WEIGHT_0, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_1) & ~(WEIGHT_BIF_MASK |
+ WEIGHT_CP_MASK |
+ WEIGHT_PA_SIG0_MASK |
+ WEIGHT_PA_SIG1_MASK |
+ WEIGHT_VGT_SIG0_MASK);
+ reg |= (WEIGHT_BIF(ni_pi->cac_weights->weight_bif) |
+ WEIGHT_CP(ni_pi->cac_weights->weight_cp) |
+ WEIGHT_PA_SIG0(ni_pi->cac_weights->weight_pa_sig0) |
+ WEIGHT_PA_SIG1(ni_pi->cac_weights->weight_pa_sig1) |
+ WEIGHT_VGT_SIG0(ni_pi->cac_weights->weight_vgt_sig0));
+ WREG32_CG(CG_CAC_REGION_4_WEIGHT_1, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_2) & ~(WEIGHT_VGT_SIG1_MASK |
+ WEIGHT_VGT_SIG2_MASK |
+ WEIGHT_DC_SIG0_MASK |
+ WEIGHT_DC_SIG1_MASK |
+ WEIGHT_DC_SIG2_MASK);
+ reg |= (WEIGHT_VGT_SIG1(ni_pi->cac_weights->weight_vgt_sig1) |
+ WEIGHT_VGT_SIG2(ni_pi->cac_weights->weight_vgt_sig2) |
+ WEIGHT_DC_SIG0(ni_pi->cac_weights->weight_dc_sig0) |
+ WEIGHT_DC_SIG1(ni_pi->cac_weights->weight_dc_sig1) |
+ WEIGHT_DC_SIG2(ni_pi->cac_weights->weight_dc_sig2));
+ WREG32_CG(CG_CAC_REGION_4_WEIGHT_2, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_4_WEIGHT_3) & ~(WEIGHT_DC_SIG3_MASK |
+ WEIGHT_UVD_SIG0_MASK |
+ WEIGHT_UVD_SIG1_MASK |
+ WEIGHT_SPARE0_MASK |
+ WEIGHT_SPARE1_MASK);
+ reg |= (WEIGHT_DC_SIG3(ni_pi->cac_weights->weight_dc_sig3) |
+ WEIGHT_UVD_SIG0(ni_pi->cac_weights->weight_uvd_sig0) |
+ WEIGHT_UVD_SIG1(ni_pi->cac_weights->weight_uvd_sig1) |
+ WEIGHT_SPARE0(ni_pi->cac_weights->weight_spare0) |
+ WEIGHT_SPARE1(ni_pi->cac_weights->weight_spare1));
+ WREG32_CG(CG_CAC_REGION_4_WEIGHT_3, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_0) & ~(WEIGHT_SQ_VSP_MASK |
+ WEIGHT_SQ_VSP0_MASK);
+ reg |= (WEIGHT_SQ_VSP(ni_pi->cac_weights->weight_sq_vsp) |
+ WEIGHT_SQ_VSP0(ni_pi->cac_weights->weight_sq_vsp0));
+ WREG32_CG(CG_CAC_REGION_5_WEIGHT_0, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_5_WEIGHT_1) & ~(WEIGHT_SQ_GPR_MASK);
+ reg |= WEIGHT_SQ_GPR(ni_pi->cac_weights->weight_sq_gpr);
+ WREG32_CG(CG_CAC_REGION_5_WEIGHT_1, reg);
+
+ reg = RREG32_CG(CG_CAC_REGION_4_OVERRIDE_4) & ~(OVR_MODE_SPARE_0_MASK |
+ OVR_VAL_SPARE_0_MASK |
+ OVR_MODE_SPARE_1_MASK |
+ OVR_VAL_SPARE_1_MASK);
+ reg |= (OVR_MODE_SPARE_0(ni_pi->cac_weights->ovr_mode_spare_0) |
+ OVR_VAL_SPARE_0(ni_pi->cac_weights->ovr_val_spare_0) |
+ OVR_MODE_SPARE_1(ni_pi->cac_weights->ovr_mode_spare_1) |
+ OVR_VAL_SPARE_1(ni_pi->cac_weights->ovr_val_spare_1));
+ WREG32_CG(CG_CAC_REGION_4_OVERRIDE_4, reg);
+
+ reg = RREG32(SQ_CAC_THRESHOLD) & ~(VSP_MASK |
+ VSP0_MASK |
+ GPR_MASK);
+ reg |= (VSP(ni_pi->cac_weights->vsp) |
+ VSP0(ni_pi->cac_weights->vsp0) |
+ GPR(ni_pi->cac_weights->gpr));
+ WREG32(SQ_CAC_THRESHOLD, reg);
+
+ reg = (MCDW_WR_ENABLE |
+ MCDX_WR_ENABLE |
+ MCDY_WR_ENABLE |
+ MCDZ_WR_ENABLE |
+ INDEX(0x09D4));
+ WREG32(MC_CG_CONFIG, reg);
+
+ reg = (READ_WEIGHT(ni_pi->cac_weights->mc_read_weight) |
+ WRITE_WEIGHT(ni_pi->cac_weights->mc_write_weight) |
+ ALLOW_OVERFLOW);
+ WREG32(MC_CG_DATAPORT, reg);
+
+ return 0;
+}
+
+static int ni_enable_smc_cac(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ bool enable)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ int ret = 0;
+ PPSMC_Result smc_result;
+
+ if (ni_pi->enable_cac) {
+ if (enable) {
+ if (!r600_is_uvd_state(radeon_new_state->class, radeon_new_state->class2)) {
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_CollectCAC_PowerCorreln);
+
+ if (ni_pi->support_cac_long_term_average) {
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgEnable);
+ if (PPSMC_Result_OK != smc_result)
+ ni_pi->support_cac_long_term_average = false;
+ }
+
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac);
+ if (PPSMC_Result_OK != smc_result)
+ ret = -EINVAL;
+
+ ni_pi->cac_enabled = (PPSMC_Result_OK == smc_result) ? true : false;
+ }
+ } else if (ni_pi->cac_enabled) {
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac);
+
+ ni_pi->cac_enabled = false;
+
+ if (ni_pi->support_cac_long_term_average) {
+ smc_result = rv770_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgDisable);
+ if (PPSMC_Result_OK != smc_result)
+ ni_pi->support_cac_long_term_average = false;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int ni_pcie_performance_request(struct radeon_device *rdev,
+ u8 perf_req, bool advertise)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+#if defined(CONFIG_ACPI)
+ if ((perf_req == PCIE_PERF_REQ_PECI_GEN1) ||
+ (perf_req == PCIE_PERF_REQ_PECI_GEN2)) {
+ if (eg_pi->pcie_performance_request_registered == false)
+ radeon_acpi_pcie_notify_device_ready(rdev);
+ eg_pi->pcie_performance_request_registered = true;
+ return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+ } else if ((perf_req == PCIE_PERF_REQ_REMOVE_REGISTRY) &&
+ eg_pi->pcie_performance_request_registered) {
+ eg_pi->pcie_performance_request_registered = false;
+ return radeon_acpi_pcie_performance_request(rdev, perf_req, advertise);
+ }
+#endif
+ return 0;
+}
+
+static int ni_advertise_gen2_capability(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+ pi->pcie_gen2 = true;
+ else
+ pi->pcie_gen2 = false;
+
+ if (!pi->pcie_gen2)
+ ni_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, true);
+
+ return 0;
+}
+
+static void ni_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp, bif;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+ if (enable) {
+ if (!pi->boot_in_gen2) {
+ bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+ bif |= CG_CLIENT_REQ(0xd);
+ WREG32(CG_BIF_REQ_AND_RSP, bif);
+ }
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+ tmp |= LC_GEN2_EN_STRAP;
+
+ tmp |= LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ udelay(10);
+ tmp &= ~LC_CLR_FAILED_SPD_CHANGE_CNT;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ } else {
+ if (!pi->boot_in_gen2) {
+ bif = RREG32(CG_BIF_REQ_AND_RSP) & ~CG_CLIENT_REQ_MASK;
+ bif |= CG_CLIENT_REQ(0xd);
+ WREG32(CG_BIF_REQ_AND_RSP, bif);
+
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp &= ~LC_GEN2_EN_STRAP;
+ }
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ }
+ }
+}
+
+static void ni_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ ni_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+void ni_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct ni_ps *new_state = ni_get_ps(new_ps);
+ struct ni_ps *current_state = ni_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->performance_levels[new_state->performance_level_count - 1].sclk >=
+ current_state->performance_levels[current_state->performance_level_count - 1].sclk)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct ni_ps *new_state = ni_get_ps(new_ps);
+ struct ni_ps *current_state = ni_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->performance_levels[new_state->performance_level_count - 1].sclk <
+ current_state->performance_levels[current_state->performance_level_count - 1].sclk)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+void ni_dpm_setup_asic(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ ni_read_clock_registers(rdev);
+ btc_read_arb_registers(rdev);
+ rv770_get_memory_type(rdev);
+ if (eg_pi->pcie_performance_request)
+ ni_advertise_gen2_capability(rdev);
+ rv770_get_pcie_gen2_status(rdev);
+ rv770_enable_acpi_pm(rdev);
+}
+
+void ni_update_current_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct ni_ps *new_ps = ni_get_ps(rps);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+ eg_pi->current_rps = *rps;
+ ni_pi->current_ps = *new_ps;
+ eg_pi->current_rps.ps_priv = &ni_pi->current_ps;
+}
+
+void ni_update_requested_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct ni_ps *new_ps = ni_get_ps(rps);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+
+ eg_pi->requested_rps = *rps;
+ ni_pi->requested_ps = *new_ps;
+ eg_pi->requested_rps.ps_priv = &ni_pi->requested_ps;
+}
+
+int ni_dpm_enable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ if (pi->gfx_clock_gating)
+ ni_cg_clockgating_default(rdev);
+ if (btc_dpm_enabled(rdev))
+ return -EINVAL;
+ if (pi->mg_clock_gating)
+ ni_mg_clockgating_default(rdev);
+ if (eg_pi->ls_clock_gating)
+ ni_ls_clockgating_default(rdev);
+ if (pi->voltage_control) {
+ rv770_enable_voltage_control(rdev, true);
+ ret = cypress_construct_voltage_tables(rdev);
+ if (ret) {
+ DRM_ERROR("cypress_construct_voltage_tables failed\n");
+ return ret;
+ }
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = ni_initialize_mc_reg_table(rdev);
+ if (ret)
+ eg_pi->dynamic_ac_timing = false;
+ }
+ if (pi->dynamic_ss)
+ cypress_enable_spread_spectrum(rdev, true);
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, true);
+ rv770_setup_bsp(rdev);
+ rv770_program_git(rdev);
+ rv770_program_tp(rdev);
+ rv770_program_tpp(rdev);
+ rv770_program_sstp(rdev);
+ cypress_enable_display_gap(rdev);
+ rv770_program_vc(rdev);
+ if (pi->dynamic_pcie_gen2)
+ ni_enable_dynamic_pcie_gen2(rdev, true);
+ ret = rv770_upload_firmware(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_upload_firmware failed\n");
+ return ret;
+ }
+ ret = ni_process_firmware_header(rdev);
+ if (ret) {
+ DRM_ERROR("ni_process_firmware_header failed\n");
+ return ret;
+ }
+ ret = ni_initial_switch_from_arb_f0_to_f1(rdev);
+ if (ret) {
+ DRM_ERROR("ni_initial_switch_from_arb_f0_to_f1 failed\n");
+ return ret;
+ }
+ ret = ni_init_smc_table(rdev);
+ if (ret) {
+ DRM_ERROR("ni_init_smc_table failed\n");
+ return ret;
+ }
+ ret = ni_init_smc_spll_table(rdev);
+ if (ret) {
+ DRM_ERROR("ni_init_smc_spll_table failed\n");
+ return ret;
+ }
+ ret = ni_init_arb_table_index(rdev);
+ if (ret) {
+ DRM_ERROR("ni_init_arb_table_index failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = ni_populate_mc_reg_table(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("ni_populate_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+ ret = ni_initialize_smc_cac_tables(rdev);
+ if (ret) {
+ DRM_ERROR("ni_initialize_smc_cac_tables failed\n");
+ return ret;
+ }
+ ret = ni_initialize_hardware_cac_manager(rdev);
+ if (ret) {
+ DRM_ERROR("ni_initialize_hardware_cac_manager failed\n");
+ return ret;
+ }
+ ret = ni_populate_smc_tdp_limits(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("ni_populate_smc_tdp_limits failed\n");
+ return ret;
+ }
+ ni_program_response_times(rdev);
+ r7xx_start_smc(rdev);
+ ret = cypress_notify_smc_display_change(rdev, false);
+ if (ret) {
+ DRM_ERROR("cypress_notify_smc_display_change failed\n");
+ return ret;
+ }
+ cypress_enable_sclk_control(rdev, true);
+ if (eg_pi->memory_transition)
+ cypress_enable_mclk_control(rdev, true);
+ cypress_start_dpm(rdev);
+ if (pi->gfx_clock_gating)
+ ni_gfx_clockgating_enable(rdev, true);
+ if (pi->mg_clock_gating)
+ ni_mg_clockgating_enable(rdev, true);
+ if (eg_pi->ls_clock_gating)
+ ni_ls_clockgating_enable(rdev, true);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ PPSMC_Result result;
+
+ ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, 0xff * 1000);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+ if (result != PPSMC_Result_OK)
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+ }
+
+ rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ ni_update_current_ps(rdev, boot_ps);
+
+ return 0;
+}
+
+void ni_dpm_disable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+
+ if (!btc_dpm_enabled(rdev))
+ return;
+ rv770_clear_vc(rdev);
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, false);
+ ni_enable_power_containment(rdev, boot_ps, false);
+ ni_enable_smc_cac(rdev, boot_ps, false);
+ cypress_enable_spread_spectrum(rdev, false);
+ rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
+ if (pi->dynamic_pcie_gen2)
+ ni_enable_dynamic_pcie_gen2(rdev, false);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ if (pi->gfx_clock_gating)
+ ni_gfx_clockgating_enable(rdev, false);
+ if (pi->mg_clock_gating)
+ ni_mg_clockgating_enable(rdev, false);
+ if (eg_pi->ls_clock_gating)
+ ni_ls_clockgating_enable(rdev, false);
+ ni_stop_dpm(rdev);
+ btc_reset_to_default(rdev);
+ ni_stop_smc(rdev);
+ ni_force_switch_to_arb_f0(rdev);
+
+ ni_update_current_ps(rdev, boot_ps);
+}
+
+static int ni_power_control_set_level(struct radeon_device *rdev)
+{
+ struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+ int ret;
+
+ ret = ni_restrict_performance_levels_before_switch(rdev);
+ if (ret)
+ return ret;
+ ret = rv770_halt_smc(rdev);
+ if (ret)
+ return ret;
+ ret = ni_populate_smc_tdp_limits(rdev, new_ps);
+ if (ret)
+ return ret;
+ ret = rv770_resume_smc(rdev);
+ if (ret)
+ return ret;
+ ret = rv770_set_sw_state(rdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int ni_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+ struct radeon_ps *new_ps = &requested_ps;
+
+ ni_update_requested_ps(rdev, new_ps);
+
+ ni_apply_state_adjust_rules(rdev, &eg_pi->requested_rps);
+
+ return 0;
+}
+
+int ni_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = &eg_pi->requested_rps;
+ struct radeon_ps *old_ps = &eg_pi->current_rps;
+ int ret;
+
+ ret = ni_restrict_performance_levels_before_switch(rdev);
+ if (ret) {
+ DRM_ERROR("ni_restrict_performance_levels_before_switch failed\n");
+ return ret;
+ }
+ ni_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ ret = ni_enable_power_containment(rdev, new_ps, false);
+ if (ret) {
+ DRM_ERROR("ni_enable_power_containment failed\n");
+ return ret;
+ }
+ ret = ni_enable_smc_cac(rdev, new_ps, false);
+ if (ret) {
+ DRM_ERROR("ni_enable_smc_cac failed\n");
+ return ret;
+ }
+ ret = rv770_halt_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_halt_smc failed\n");
+ return ret;
+ }
+ if (eg_pi->smu_uvd_hs)
+ btc_notify_uvd_to_smc(rdev, new_ps);
+ ret = ni_upload_sw_state(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("ni_upload_sw_state failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = ni_upload_mc_reg_table(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("ni_upload_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+ ret = ni_program_memory_timing_parameters(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("ni_program_memory_timing_parameters failed\n");
+ return ret;
+ }
+ ret = rv770_resume_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_resume_smc failed\n");
+ return ret;
+ }
+ ret = rv770_set_sw_state(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_set_sw_state failed\n");
+ return ret;
+ }
+ ni_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+ ret = ni_enable_smc_cac(rdev, new_ps, true);
+ if (ret) {
+ DRM_ERROR("ni_enable_smc_cac failed\n");
+ return ret;
+ }
+ ret = ni_enable_power_containment(rdev, new_ps, true);
+ if (ret) {
+ DRM_ERROR("ni_enable_power_containment failed\n");
+ return ret;
+ }
+
+ /* update tdp */
+ ret = ni_power_control_set_level(rdev);
+ if (ret) {
+ DRM_ERROR("ni_power_control_set_level failed\n");
+ return ret;
+ }
+
+ ret = ni_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
+ if (ret) {
+ DRM_ERROR("ni_dpm_force_performance_level failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void ni_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = &eg_pi->requested_rps;
+
+ ni_update_current_ps(rdev, new_ps);
+}
+
+void ni_dpm_reset_asic(struct radeon_device *rdev)
+{
+ ni_restrict_performance_levels_before_switch(rdev);
+ rv770_set_boot_state(rdev);
+}
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void ni_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_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 if (r600_is_uvd_state(rps->class, rps->class2)) {
+ rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+ rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ rdev->pm.dpm.boot_ps = rps;
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void ni_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_ps *ps = ni_get_ps(rps);
+ u16 vddc;
+ struct rv7xx_pl *pl = &ps->performance_levels[index];
+
+ ps->performance_level_count = index + 1;
+
+ pl->sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
+ pl->sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
+ pl->mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
+ pl->mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
+
+ pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
+ pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
+ pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
+
+ /* patch up vddc if necessary */
+ if (pl->vddc == 0xff01) {
+ if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
+ pl->vddc = vddc;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+ pi->acpi_vddc = pl->vddc;
+ eg_pi->acpi_vddci = pl->vddci;
+ if (ps->performance_levels[0].flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+ pi->acpi_pcie_gen2 = true;
+ else
+ pi->acpi_pcie_gen2 = false;
+ }
+
+ if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
+ eg_pi->ulv.supported = true;
+ eg_pi->ulv.pl = pl;
+ }
+
+ if (pi->min_vddc_in_table > pl->vddc)
+ pi->min_vddc_in_table = pl->vddc;
+
+ if (pi->max_vddc_in_table < pl->vddc)
+ pi->max_vddc_in_table = pl->vddc;
+
+ /* patch up boot state */
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ u16 vddc, vddci, mvdd;
+ radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
+ pl->mclk = rdev->clock.default_mclk;
+ pl->sclk = rdev->clock.default_sclk;
+ pl->vddc = vddc;
+ pl->vddci = vddci;
+ }
+
+ if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+ ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+ }
+}
+
+static int ni_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j;
+ union pplib_clock_info *clock_info;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ struct ni_ps *ps;
+
+ if (!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);
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ power_info->pplib.ucNumStates, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+ for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+ power_state = (union pplib_power_state *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+ i * power_info->pplib.ucStateEntrySize);
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+ (power_state->v1.ucNonClockStateIndex *
+ power_info->pplib.ucNonClockSize));
+ if (power_info->pplib.ucStateEntrySize - 1) {
+ ps = kzalloc(sizeof(struct ni_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.ps[i].ps_priv = ps;
+ ni_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info,
+ power_info->pplib.ucNonClockSize);
+ for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+ clock_info = (union pplib_clock_info *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+ (power_state->v1.ucClockStateIndices[j] *
+ power_info->pplib.ucClockInfoSize));
+ ni_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i], j,
+ clock_info);
+ }
+ }
+ }
+ rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+ return 0;
+}
+
+int ni_dpm_init(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi;
+ struct evergreen_power_info *eg_pi;
+ struct ni_power_info *ni_pi;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ u16 data_offset, size;
+ u8 frev, crev;
+ struct atom_clock_dividers dividers;
+ int ret;
+
+ ni_pi = kzalloc(sizeof(struct ni_power_info), GFP_KERNEL);
+ if (ni_pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = ni_pi;
+ eg_pi = &ni_pi->eg;
+ pi = &eg_pi->rv7xx;
+
+ rv770_get_max_vddc(rdev);
+
+ eg_pi->ulv.supported = false;
+ pi->acpi_vddc = 0;
+ eg_pi->acpi_vddci = 0;
+ pi->min_vddc_in_table = 0;
+ pi->max_vddc_in_table = 0;
+
+ ret = ni_parse_power_table(rdev);
+ if (ret)
+ return ret;
+ ret = r600_parse_extended_power_table(rdev);
+ if (ret)
+ return ret;
+
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
+ kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL);
+ if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
+ r600_free_extended_power_table(rdev);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
+
+ ni_patch_dependency_tables_based_on_leakage(rdev);
+
+ if (rdev->pm.dpm.voltage_response_time == 0)
+ rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+ if (rdev->pm.dpm.backbias_response_time == 0)
+ rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->ref_div = dividers.ref_div + 1;
+ else
+ pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ pi->rlp = RV770_RLP_DFLT;
+ pi->rmp = RV770_RMP_DFLT;
+ pi->lhp = RV770_LHP_DFLT;
+ pi->lmp = RV770_LMP_DFLT;
+
+ eg_pi->ats[0].rlp = RV770_RLP_DFLT;
+ eg_pi->ats[0].rmp = RV770_RMP_DFLT;
+ eg_pi->ats[0].lhp = RV770_LHP_DFLT;
+ eg_pi->ats[0].lmp = RV770_LMP_DFLT;
+
+ eg_pi->ats[1].rlp = BTC_RLP_UVD_DFLT;
+ eg_pi->ats[1].rmp = BTC_RMP_UVD_DFLT;
+ eg_pi->ats[1].lhp = BTC_LHP_UVD_DFLT;
+ eg_pi->ats[1].lmp = BTC_LMP_UVD_DFLT;
+
+ eg_pi->smu_uvd_hs = true;
+
+ if (rdev->pdev->device == 0x6707) {
+ pi->mclk_strobe_mode_threshold = 55000;
+ pi->mclk_edc_enable_threshold = 55000;
+ eg_pi->mclk_edc_wr_enable_threshold = 55000;
+ } else {
+ pi->mclk_strobe_mode_threshold = 40000;
+ pi->mclk_edc_enable_threshold = 40000;
+ eg_pi->mclk_edc_wr_enable_threshold = 40000;
+ }
+ ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
+
+ pi->voltage_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0);
+
+ pi->mvdd_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
+
+ eg_pi->vddci_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->sclk_ss = true;
+ pi->mclk_ss = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->sclk_ss = false;
+ pi->mclk_ss = false;
+ pi->dynamic_ss = true;
+ }
+
+ pi->asi = RV770_ASI_DFLT;
+ pi->pasi = CYPRESS_HASI_DFLT;
+ pi->vrc = CYPRESS_VRC_DFLT;
+
+ pi->power_gating = false;
+
+ pi->gfx_clock_gating = true;
+
+ pi->mg_clock_gating = true;
+ pi->mgcgtssm = true;
+ eg_pi->ls_clock_gating = false;
+ eg_pi->sclk_deep_sleep = false;
+
+ pi->dynamic_pcie_gen2 = true;
+
+ if (pi->gfx_clock_gating &&
+ (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ pi->display_gap = true;
+
+ pi->dcodt = true;
+
+ pi->ulps = true;
+
+ eg_pi->dynamic_ac_timing = true;
+ eg_pi->abm = true;
+ eg_pi->mcls = true;
+ eg_pi->light_sleep = true;
+ eg_pi->memory_transition = true;
+#if defined(CONFIG_ACPI)
+ eg_pi->pcie_performance_request =
+ radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+ eg_pi->pcie_performance_request = false;
+#endif
+
+ eg_pi->dll_default_on = false;
+
+ eg_pi->sclk_deep_sleep = false;
+
+ pi->mclk_stutter_mode_threshold = 0;
+
+ pi->sram_end = SMC_RAM_END;
+
+ rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 3;
+ rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+ rdev->pm.dpm.dyn_state.min_vddc_for_pcie_gen2 = 900;
+ rdev->pm.dpm.dyn_state.valid_sclk_values.count = ARRAY_SIZE(btc_valid_sclk);
+ rdev->pm.dpm.dyn_state.valid_sclk_values.values = btc_valid_sclk;
+ rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+ rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+ rdev->pm.dpm.dyn_state.sclk_mclk_delta = 12500;
+
+ ni_pi->cac_data.leakage_coefficients.at = 516;
+ ni_pi->cac_data.leakage_coefficients.bt = 18;
+ ni_pi->cac_data.leakage_coefficients.av = 51;
+ ni_pi->cac_data.leakage_coefficients.bv = 2957;
+
+ switch (rdev->pdev->device) {
+ case 0x6700:
+ case 0x6701:
+ case 0x6702:
+ case 0x6703:
+ case 0x6718:
+ ni_pi->cac_weights = &cac_weights_cayman_xt;
+ break;
+ case 0x6705:
+ case 0x6719:
+ case 0x671D:
+ case 0x671C:
+ default:
+ ni_pi->cac_weights = &cac_weights_cayman_pro;
+ break;
+ case 0x6704:
+ case 0x6706:
+ case 0x6707:
+ case 0x6708:
+ case 0x6709:
+ ni_pi->cac_weights = &cac_weights_cayman_le;
+ break;
+ }
+
+ if (ni_pi->cac_weights->enable_power_containment_by_default) {
+ ni_pi->enable_power_containment = true;
+ ni_pi->enable_cac = true;
+ ni_pi->enable_sq_ramping = true;
+ } else {
+ ni_pi->enable_power_containment = false;
+ ni_pi->enable_cac = false;
+ ni_pi->enable_sq_ramping = false;
+ }
+
+ ni_pi->driver_calculate_cac_leakage = false;
+ ni_pi->cac_configuration_required = true;
+
+ if (ni_pi->cac_configuration_required) {
+ ni_pi->support_cac_long_term_average = true;
+ ni_pi->lta_window_size = ni_pi->cac_weights->l2_lta_window_size;
+ ni_pi->lts_truncate = ni_pi->cac_weights->lts_truncate;
+ } else {
+ ni_pi->support_cac_long_term_average = false;
+ ni_pi->lta_window_size = 0;
+ ni_pi->lts_truncate = 0;
+ }
+
+ ni_pi->use_power_boost_limit = true;
+
+ return 0;
+}
+
+void ni_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
+ r600_free_extended_power_table(rdev);
+}
+
+void ni_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct ni_ps *ps = ni_get_ps(rps);
+ struct rv7xx_pl *pl;
+ int i;
+
+ r600_dpm_print_class_info(rps->class, rps->class2);
+ r600_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];
+ if (rdev->family >= CHIP_TAHITI)
+ printk("\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
+ i, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
+ else
+ printk("\t\tpower level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ i, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ }
+ r600_dpm_print_ps_status(rdev, rps);
+}
+
+void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct ni_ps *ps = ni_get_ps(rps);
+ struct rv7xx_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+ CURRENT_STATE_INDEX_SHIFT;
+
+ if (current_index >= ps->performance_level_count) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ pl = &ps->performance_levels[current_index];
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ }
+}
+
+u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_ps *requested_state = ni_get_ps(&eg_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;
+}
+
+u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_ps *requested_state = ni_get_ps(&eg_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;
+}
+
diff --git a/drivers/gpu/drm/radeon/ni_dpm.h b/drivers/gpu/drm/radeon/ni_dpm.h
new file mode 100644
index 000000000000..6bbee9180909
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ni_dpm.h
@@ -0,0 +1,250 @@
+/*
+ * 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 __NI_DPM_H__
+#define __NI_DPM_H__
+
+#include "cypress_dpm.h"
+#include "btc_dpm.h"
+#include "nislands_smc.h"
+
+struct ni_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 mclk_pwrmgt_cntl;
+ u32 dll_cntl;
+ u32 mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2;
+ u32 mpll_ss1;
+ u32 mpll_ss2;
+};
+
+struct ni_mc_reg_entry {
+ u32 mclk_max;
+ u32 mc_data[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct ni_mc_reg_table {
+ u8 last;
+ u8 num_entries;
+ u16 valid_flag;
+ struct ni_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+ SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+#define NISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT 2
+
+enum ni_dc_cac_level
+{
+ NISLANDS_DCCAC_LEVEL_0 = 0,
+ NISLANDS_DCCAC_LEVEL_1,
+ NISLANDS_DCCAC_LEVEL_2,
+ NISLANDS_DCCAC_LEVEL_3,
+ NISLANDS_DCCAC_LEVEL_4,
+ NISLANDS_DCCAC_LEVEL_5,
+ NISLANDS_DCCAC_LEVEL_6,
+ NISLANDS_DCCAC_LEVEL_7,
+ NISLANDS_DCCAC_MAX_LEVELS
+};
+
+struct ni_leakage_coeffients
+{
+ u32 at;
+ u32 bt;
+ u32 av;
+ u32 bv;
+ s32 t_slope;
+ s32 t_intercept;
+ u32 t_ref;
+};
+
+struct ni_cac_data
+{
+ struct ni_leakage_coeffients leakage_coefficients;
+ u32 i_leakage;
+ s32 leakage_minimum_temperature;
+ u32 pwr_const;
+ u32 dc_cac_value;
+ u32 bif_cac_value;
+ u32 lkge_pwr;
+ u8 mc_wr_weight;
+ u8 mc_rd_weight;
+ u8 allow_ovrflw;
+ u8 num_win_tdp;
+ u8 l2num_win_tdp;
+ u8 lts_truncate_n;
+};
+
+struct ni_cac_weights
+{
+ u32 weight_tcp_sig0;
+ u32 weight_tcp_sig1;
+ u32 weight_ta_sig;
+ u32 weight_tcc_en0;
+ u32 weight_tcc_en1;
+ u32 weight_tcc_en2;
+ u32 weight_cb_en0;
+ u32 weight_cb_en1;
+ u32 weight_cb_en2;
+ u32 weight_cb_en3;
+ u32 weight_db_sig0;
+ u32 weight_db_sig1;
+ u32 weight_db_sig2;
+ u32 weight_db_sig3;
+ u32 weight_sxm_sig0;
+ u32 weight_sxm_sig1;
+ u32 weight_sxm_sig2;
+ u32 weight_sxs_sig0;
+ u32 weight_sxs_sig1;
+ u32 weight_xbr_0;
+ u32 weight_xbr_1;
+ u32 weight_xbr_2;
+ u32 weight_spi_sig0;
+ u32 weight_spi_sig1;
+ u32 weight_spi_sig2;
+ u32 weight_spi_sig3;
+ u32 weight_spi_sig4;
+ u32 weight_spi_sig5;
+ u32 weight_lds_sig0;
+ u32 weight_lds_sig1;
+ u32 weight_sc;
+ u32 weight_bif;
+ u32 weight_cp;
+ u32 weight_pa_sig0;
+ u32 weight_pa_sig1;
+ u32 weight_vgt_sig0;
+ u32 weight_vgt_sig1;
+ u32 weight_vgt_sig2;
+ u32 weight_dc_sig0;
+ u32 weight_dc_sig1;
+ u32 weight_dc_sig2;
+ u32 weight_dc_sig3;
+ u32 weight_uvd_sig0;
+ u32 weight_uvd_sig1;
+ u32 weight_spare0;
+ u32 weight_spare1;
+ u32 weight_sq_vsp;
+ u32 weight_sq_vsp0;
+ u32 weight_sq_gpr;
+ u32 ovr_mode_spare_0;
+ u32 ovr_val_spare_0;
+ u32 ovr_mode_spare_1;
+ u32 ovr_val_spare_1;
+ u32 vsp;
+ u32 vsp0;
+ u32 gpr;
+ u8 mc_read_weight;
+ u8 mc_write_weight;
+ u32 tid_cnt;
+ u32 tid_unit;
+ u32 l2_lta_window_size;
+ u32 lts_truncate;
+ u32 dc_cac[NISLANDS_DCCAC_MAX_LEVELS];
+ u32 pcie_cac[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES];
+ bool enable_power_containment_by_default;
+};
+
+struct ni_ps {
+ u16 performance_level_count;
+ bool dc_compatible;
+ struct rv7xx_pl performance_levels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+};
+
+struct ni_power_info {
+ /* must be first! */
+ struct evergreen_power_info eg;
+ struct ni_clock_registers clock_registers;
+ struct ni_mc_reg_table mc_reg_table;
+ u32 mclk_rtt_mode_threshold;
+ /* flags */
+ bool use_power_boost_limit;
+ bool support_cac_long_term_average;
+ bool cac_enabled;
+ bool cac_configuration_required;
+ bool driver_calculate_cac_leakage;
+ bool pc_enabled;
+ bool enable_power_containment;
+ bool enable_cac;
+ bool enable_sq_ramping;
+ /* smc offsets */
+ u16 arb_table_start;
+ u16 fan_table_start;
+ u16 cac_table_start;
+ u16 spll_table_start;
+ /* CAC stuff */
+ struct ni_cac_data cac_data;
+ u32 dc_cac_table[NISLANDS_DCCAC_MAX_LEVELS];
+ const struct ni_cac_weights *cac_weights;
+ u8 lta_window_size;
+ u8 lts_truncate;
+ struct ni_ps current_ps;
+ struct ni_ps requested_ps;
+ /* scratch structs */
+ SMC_NIslands_MCRegisters smc_mc_reg_table;
+ NISLANDS_SMC_STATETABLE smc_statetable;
+};
+
+#define NISLANDS_INITIAL_STATE_ARB_INDEX 0
+#define NISLANDS_ACPI_STATE_ARB_INDEX 1
+#define NISLANDS_ULV_STATE_ARB_INDEX 2
+#define NISLANDS_DRIVER_STATE_ARB_INDEX 3
+
+#define NISLANDS_DPM2_MAX_PULSE_SKIP 256
+
+#define NISLANDS_DPM2_NEAR_TDP_DEC 10
+#define NISLANDS_DPM2_ABOVE_SAFE_INC 5
+#define NISLANDS_DPM2_BELOW_SAFE_INC 20
+
+#define NISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT 80
+
+#define NISLANDS_DPM2_MAXPS_PERCENT_H 90
+#define NISLANDS_DPM2_MAXPS_PERCENT_M 0
+
+#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
+#define NISLANDS_DPM2_SQ_RAMP_MIN_POWER 0x12
+#define NISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
+#define NISLANDS_DPM2_SQ_RAMP_STI_SIZE 0x1E
+#define NISLANDS_DPM2_SQ_RAMP_LTI_RATIO 0xF
+
+int ni_copy_and_switch_arb_sets(struct radeon_device *rdev,
+ u32 arb_freq_src, u32 arb_freq_dest);
+void ni_update_current_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps);
+void ni_update_requested_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps);
+
+void ni_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps);
+void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps);
+
+bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index e226faf16fea..fe24a93542ec 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -489,6 +489,571 @@
# define CACHE_FLUSH_AND_INV_EVENT_TS (0x14 << 0)
# define CACHE_FLUSH_AND_INV_EVENT (0x16 << 0)
+/* TN SMU registers */
+#define TN_CURRENT_GNB_TEMP 0x1F390
+
+/* pm registers */
+#define SMC_MSG 0x20c
+#define HOST_SMC_MSG(x) ((x) << 0)
+#define HOST_SMC_MSG_MASK (0xff << 0)
+#define HOST_SMC_MSG_SHIFT 0
+#define HOST_SMC_RESP(x) ((x) << 8)
+#define HOST_SMC_RESP_MASK (0xff << 8)
+#define HOST_SMC_RESP_SHIFT 8
+#define SMC_HOST_MSG(x) ((x) << 16)
+#define SMC_HOST_MSG_MASK (0xff << 16)
+#define SMC_HOST_MSG_SHIFT 16
+#define SMC_HOST_RESP(x) ((x) << 24)
+#define SMC_HOST_RESP_MASK (0xff << 24)
+#define SMC_HOST_RESP_SHIFT 24
+
+#define CG_SPLL_FUNC_CNTL 0x600
+#define SPLL_RESET (1 << 0)
+#define SPLL_SLEEP (1 << 1)
+#define SPLL_BYPASS_EN (1 << 3)
+#define SPLL_REF_DIV(x) ((x) << 4)
+#define SPLL_REF_DIV_MASK (0x3f << 4)
+#define SPLL_PDIV_A(x) ((x) << 20)
+#define SPLL_PDIV_A_MASK (0x7f << 20)
+#define SPLL_PDIV_A_SHIFT 20
+#define CG_SPLL_FUNC_CNTL_2 0x604
+#define SCLK_MUX_SEL(x) ((x) << 0)
+#define SCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_SPLL_FUNC_CNTL_3 0x608
+#define SPLL_FB_DIV(x) ((x) << 0)
+#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define SPLL_FB_DIV_SHIFT 0
+#define SPLL_DITHEN (1 << 28)
+
+#define MPLL_CNTL_MODE 0x61c
+# define SS_SSEN (1 << 24)
+# define SS_DSMODE_EN (1 << 25)
+
+#define MPLL_AD_FUNC_CNTL 0x624
+#define CLKF(x) ((x) << 0)
+#define CLKF_MASK (0x7f << 0)
+#define CLKR(x) ((x) << 7)
+#define CLKR_MASK (0x1f << 7)
+#define CLKFRAC(x) ((x) << 12)
+#define CLKFRAC_MASK (0x1f << 12)
+#define YCLK_POST_DIV(x) ((x) << 17)
+#define YCLK_POST_DIV_MASK (3 << 17)
+#define IBIAS(x) ((x) << 20)
+#define IBIAS_MASK (0x3ff << 20)
+#define RESET (1 << 30)
+#define PDNB (1 << 31)
+#define MPLL_AD_FUNC_CNTL_2 0x628
+#define BYPASS (1 << 19)
+#define BIAS_GEN_PDNB (1 << 24)
+#define RESET_EN (1 << 25)
+#define VCO_MODE (1 << 29)
+#define MPLL_DQ_FUNC_CNTL 0x62c
+#define MPLL_DQ_FUNC_CNTL_2 0x630
+
+#define GENERAL_PWRMGT 0x63c
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define THERMAL_PROTECTION_DIS (1 << 2)
+# define THERMAL_PROTECTION_TYPE (1 << 3)
+# define ENABLE_GEN2PCIE (1 << 4)
+# define ENABLE_GEN2XSP (1 << 5)
+# define SW_SMIO_INDEX(x) ((x) << 6)
+# define SW_SMIO_INDEX_MASK (3 << 6)
+# define SW_SMIO_INDEX_SHIFT 6
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+# define BACKBIAS_PAD_EN (1 << 18)
+# define BACKBIAS_VALUE (1 << 19)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
+# define AC_DC_SW (1 << 24)
+
+#define SCLK_PWRMGT_CNTL 0x644
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_LOW_D1 (1 << 1)
+# define FIR_RESET (1 << 4)
+# define FIR_FORCE_TREND_SEL (1 << 5)
+# define FIR_TREND_MODE (1 << 6)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define GFX_CLK_REQUEST_OFF (1 << 9)
+# define GFX_CLK_FORCE_OFF (1 << 10)
+# define GFX_CLK_OFF_ACPI_D1 (1 << 11)
+# define GFX_CLK_OFF_ACPI_D2 (1 << 12)
+# define GFX_CLK_OFF_ACPI_D3 (1 << 13)
+# define DYN_LIGHT_SLEEP_EN (1 << 14)
+#define MCLK_PWRMGT_CNTL 0x648
+# define DLL_SPEED(x) ((x) << 0)
+# define DLL_SPEED_MASK (0x1f << 0)
+# define MPLL_PWRMGT_OFF (1 << 5)
+# define DLL_READY (1 << 6)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA0_PDNB (1 << 8)
+# define MRDCKA1_PDNB (1 << 9)
+# define MRDCKB0_PDNB (1 << 10)
+# define MRDCKB1_PDNB (1 << 11)
+# define MRDCKC0_PDNB (1 << 12)
+# define MRDCKC1_PDNB (1 << 13)
+# define MRDCKD0_PDNB (1 << 14)
+# define MRDCKD1_PDNB (1 << 15)
+# define MRDCKA0_RESET (1 << 16)
+# define MRDCKA1_RESET (1 << 17)
+# define MRDCKB0_RESET (1 << 18)
+# define MRDCKB1_RESET (1 << 19)
+# define MRDCKC0_RESET (1 << 20)
+# define MRDCKC1_RESET (1 << 21)
+# define MRDCKD0_RESET (1 << 22)
+# define MRDCKD1_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define MPLL_TURNOFF_D2 (1 << 28)
+#define DLL_CNTL 0x64c
+# define MRDCKA0_BYPASS (1 << 24)
+# define MRDCKA1_BYPASS (1 << 25)
+# define MRDCKB0_BYPASS (1 << 26)
+# define MRDCKB1_BYPASS (1 << 27)
+# define MRDCKC0_BYPASS (1 << 28)
+# define MRDCKC1_BYPASS (1 << 29)
+# define MRDCKD0_BYPASS (1 << 30)
+# define MRDCKD1_BYPASS (1 << 31)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c
+# define CURRENT_STATE_INDEX_MASK (0xf << 4)
+# define CURRENT_STATE_INDEX_SHIFT 4
+
+#define CG_AT 0x6d4
+# define CG_R(x) ((x) << 0)
+# define CG_R_MASK (0xffff << 0)
+# define CG_L(x) ((x) << 16)
+# define CG_L_MASK (0xffff << 16)
+
+#define CG_BIF_REQ_AND_RSP 0x7f4
+#define CG_CLIENT_REQ(x) ((x) << 0)
+#define CG_CLIENT_REQ_MASK (0xff << 0)
+#define CG_CLIENT_REQ_SHIFT 0
+#define CG_CLIENT_RESP(x) ((x) << 8)
+#define CG_CLIENT_RESP_MASK (0xff << 8)
+#define CG_CLIENT_RESP_SHIFT 8
+#define CLIENT_CG_REQ(x) ((x) << 16)
+#define CLIENT_CG_REQ_MASK (0xff << 16)
+#define CLIENT_CG_REQ_SHIFT 16
+#define CLIENT_CG_RESP(x) ((x) << 24)
+#define CLIENT_CG_RESP_MASK (0xff << 24)
+#define CLIENT_CG_RESP_SHIFT 24
+
+#define CG_SPLL_SPREAD_SPECTRUM 0x790
+#define SSEN (1 << 0)
+#define CLK_S(x) ((x) << 4)
+#define CLK_S_MASK (0xfff << 4)
+#define CLK_S_SHIFT 4
+#define CG_SPLL_SPREAD_SPECTRUM_2 0x794
+#define CLK_V(x) ((x) << 0)
+#define CLK_V_MASK (0x3ffffff << 0)
+#define CLK_V_SHIFT 0
+
+#define SMC_SCRATCH0 0x81c
+
+#define CG_SPLL_FUNC_CNTL_4 0x850
+
+#define MPLL_SS1 0x85c
+#define CLKV(x) ((x) << 0)
+#define CLKV_MASK (0x3ffffff << 0)
+#define MPLL_SS2 0x860
+#define CLKS(x) ((x) << 0)
+#define CLKS_MASK (0xfff << 0)
+
+#define CG_CAC_CTRL 0x88c
+#define TID_CNT(x) ((x) << 0)
+#define TID_CNT_MASK (0x3fff << 0)
+#define TID_UNIT(x) ((x) << 14)
+#define TID_UNIT_MASK (0xf << 14)
+
+#define CG_IND_ADDR 0x8f8
+#define CG_IND_DATA 0x8fc
+/* CGIND regs */
+#define CG_CGTT_LOCAL_0 0x00
+#define CG_CGTT_LOCAL_1 0x01
+
+#define MC_CG_CONFIG 0x25bc
+#define MCDW_WR_ENABLE (1 << 0)
+#define MCDX_WR_ENABLE (1 << 1)
+#define MCDY_WR_ENABLE (1 << 2)
+#define MCDZ_WR_ENABLE (1 << 3)
+#define MC_RD_ENABLE(x) ((x) << 4)
+#define MC_RD_ENABLE_MASK (3 << 4)
+#define INDEX(x) ((x) << 6)
+#define INDEX_MASK (0xfff << 6)
+#define INDEX_SHIFT 6
+
+#define MC_ARB_CAC_CNTL 0x2750
+#define ENABLE (1 << 0)
+#define READ_WEIGHT(x) ((x) << 1)
+#define READ_WEIGHT_MASK (0x3f << 1)
+#define READ_WEIGHT_SHIFT 1
+#define WRITE_WEIGHT(x) ((x) << 7)
+#define WRITE_WEIGHT_MASK (0x3f << 7)
+#define WRITE_WEIGHT_SHIFT 7
+#define ALLOW_OVERFLOW (1 << 13)
+
+#define MC_ARB_DRAM_TIMING 0x2774
+#define MC_ARB_DRAM_TIMING2 0x2778
+
+#define MC_ARB_RFSH_RATE 0x27b0
+#define POWERMODE0(x) ((x) << 0)
+#define POWERMODE0_MASK (0xff << 0)
+#define POWERMODE0_SHIFT 0
+#define POWERMODE1(x) ((x) << 8)
+#define POWERMODE1_MASK (0xff << 8)
+#define POWERMODE1_SHIFT 8
+#define POWERMODE2(x) ((x) << 16)
+#define POWERMODE2_MASK (0xff << 16)
+#define POWERMODE2_SHIFT 16
+#define POWERMODE3(x) ((x) << 24)
+#define POWERMODE3_MASK (0xff << 24)
+#define POWERMODE3_SHIFT 24
+
+#define MC_ARB_CG 0x27e8
+#define CG_ARB_REQ(x) ((x) << 0)
+#define CG_ARB_REQ_MASK (0xff << 0)
+#define CG_ARB_REQ_SHIFT 0
+#define CG_ARB_RESP(x) ((x) << 8)
+#define CG_ARB_RESP_MASK (0xff << 8)
+#define CG_ARB_RESP_SHIFT 8
+#define ARB_CG_REQ(x) ((x) << 16)
+#define ARB_CG_REQ_MASK (0xff << 16)
+#define ARB_CG_REQ_SHIFT 16
+#define ARB_CG_RESP(x) ((x) << 24)
+#define ARB_CG_RESP_MASK (0xff << 24)
+#define ARB_CG_RESP_SHIFT 24
+
+#define MC_ARB_DRAM_TIMING_1 0x27f0
+#define MC_ARB_DRAM_TIMING_2 0x27f4
+#define MC_ARB_DRAM_TIMING_3 0x27f8
+#define MC_ARB_DRAM_TIMING2_1 0x27fc
+#define MC_ARB_DRAM_TIMING2_2 0x2800
+#define MC_ARB_DRAM_TIMING2_3 0x2804
+#define MC_ARB_BURST_TIME 0x2808
+#define STATE0(x) ((x) << 0)
+#define STATE0_MASK (0x1f << 0)
+#define STATE0_SHIFT 0
+#define STATE1(x) ((x) << 5)
+#define STATE1_MASK (0x1f << 5)
+#define STATE1_SHIFT 5
+#define STATE2(x) ((x) << 10)
+#define STATE2_MASK (0x1f << 10)
+#define STATE2_SHIFT 10
+#define STATE3(x) ((x) << 15)
+#define STATE3_MASK (0x1f << 15)
+#define STATE3_SHIFT 15
+
+#define MC_CG_DATAPORT 0x2884
+
+#define MC_SEQ_RAS_TIMING 0x28a0
+#define MC_SEQ_CAS_TIMING 0x28a4
+#define MC_SEQ_MISC_TIMING 0x28a8
+#define MC_SEQ_MISC_TIMING2 0x28ac
+#define MC_SEQ_PMG_TIMING 0x28b0
+#define MC_SEQ_RD_CTL_D0 0x28b4
+#define MC_SEQ_RD_CTL_D1 0x28b8
+#define MC_SEQ_WR_CTL_D0 0x28bc
+#define MC_SEQ_WR_CTL_D1 0x28c0
+
+#define MC_SEQ_MISC0 0x2a00
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+#define MC_SEQ_MISC1 0x2a04
+#define MC_SEQ_RESERVE_M 0x2a08
+#define MC_PMG_CMD_EMRS 0x2a0c
+
+#define MC_SEQ_MISC3 0x2a2c
+
+#define MC_SEQ_MISC5 0x2a54
+#define MC_SEQ_MISC6 0x2a58
+
+#define MC_SEQ_MISC7 0x2a64
+
+#define MC_SEQ_RAS_TIMING_LP 0x2a6c
+#define MC_SEQ_CAS_TIMING_LP 0x2a70
+#define MC_SEQ_MISC_TIMING_LP 0x2a74
+#define MC_SEQ_MISC_TIMING2_LP 0x2a78
+#define MC_SEQ_WR_CTL_D0_LP 0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP 0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88
+
+#define MC_PMG_CMD_MRS 0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP 0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP 0x2b20
+
+#define MC_PMG_CMD_MRS1 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48
+#define MC_SEQ_PMG_TIMING_LP 0x2b4c
+
+#define MC_PMG_CMD_MRS2 0x2b5c
+#define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60
+
+#define LB_SYNC_RESET_SEL 0x6b28
+#define LB_SYNC_RESET_SEL_MASK (3 << 0)
+#define LB_SYNC_RESET_SEL_SHIFT 0
+
+#define DC_STUTTER_CNTL 0x6b30
+#define DC_STUTTER_ENABLE_A (1 << 0)
+#define DC_STUTTER_ENABLE_B (1 << 1)
+
+#define SQ_CAC_THRESHOLD 0x8e4c
+#define VSP(x) ((x) << 0)
+#define VSP_MASK (0xff << 0)
+#define VSP_SHIFT 0
+#define VSP0(x) ((x) << 8)
+#define VSP0_MASK (0xff << 8)
+#define VSP0_SHIFT 8
+#define GPR(x) ((x) << 16)
+#define GPR_MASK (0xff << 16)
+#define GPR_SHIFT 16
+
+#define SQ_POWER_THROTTLE 0x8e58
+#define MIN_POWER(x) ((x) << 0)
+#define MIN_POWER_MASK (0x3fff << 0)
+#define MIN_POWER_SHIFT 0
+#define MAX_POWER(x) ((x) << 16)
+#define MAX_POWER_MASK (0x3fff << 16)
+#define MAX_POWER_SHIFT 0
+#define SQ_POWER_THROTTLE2 0x8e5c
+#define MAX_POWER_DELTA(x) ((x) << 0)
+#define MAX_POWER_DELTA_MASK (0x3fff << 0)
+#define MAX_POWER_DELTA_SHIFT 0
+#define STI_SIZE(x) ((x) << 16)
+#define STI_SIZE_MASK (0x3ff << 16)
+#define STI_SIZE_SHIFT 16
+#define LTI_RATIO(x) ((x) << 27)
+#define LTI_RATIO_MASK (0xf << 27)
+#define LTI_RATIO_SHIFT 27
+
+/* CG indirect registers */
+#define CG_CAC_REGION_1_WEIGHT_0 0x83
+#define WEIGHT_TCP_SIG0(x) ((x) << 0)
+#define WEIGHT_TCP_SIG0_MASK (0x3f << 0)
+#define WEIGHT_TCP_SIG0_SHIFT 0
+#define WEIGHT_TCP_SIG1(x) ((x) << 6)
+#define WEIGHT_TCP_SIG1_MASK (0x3f << 6)
+#define WEIGHT_TCP_SIG1_SHIFT 6
+#define WEIGHT_TA_SIG(x) ((x) << 12)
+#define WEIGHT_TA_SIG_MASK (0x3f << 12)
+#define WEIGHT_TA_SIG_SHIFT 12
+#define CG_CAC_REGION_1_WEIGHT_1 0x84
+#define WEIGHT_TCC_EN0(x) ((x) << 0)
+#define WEIGHT_TCC_EN0_MASK (0x3f << 0)
+#define WEIGHT_TCC_EN0_SHIFT 0
+#define WEIGHT_TCC_EN1(x) ((x) << 6)
+#define WEIGHT_TCC_EN1_MASK (0x3f << 6)
+#define WEIGHT_TCC_EN1_SHIFT 6
+#define WEIGHT_TCC_EN2(x) ((x) << 12)
+#define WEIGHT_TCC_EN2_MASK (0x3f << 12)
+#define WEIGHT_TCC_EN2_SHIFT 12
+#define WEIGHT_TCC_EN3(x) ((x) << 18)
+#define WEIGHT_TCC_EN3_MASK (0x3f << 18)
+#define WEIGHT_TCC_EN3_SHIFT 18
+#define CG_CAC_REGION_2_WEIGHT_0 0x85
+#define WEIGHT_CB_EN0(x) ((x) << 0)
+#define WEIGHT_CB_EN0_MASK (0x3f << 0)
+#define WEIGHT_CB_EN0_SHIFT 0
+#define WEIGHT_CB_EN1(x) ((x) << 6)
+#define WEIGHT_CB_EN1_MASK (0x3f << 6)
+#define WEIGHT_CB_EN1_SHIFT 6
+#define WEIGHT_CB_EN2(x) ((x) << 12)
+#define WEIGHT_CB_EN2_MASK (0x3f << 12)
+#define WEIGHT_CB_EN2_SHIFT 12
+#define WEIGHT_CB_EN3(x) ((x) << 18)
+#define WEIGHT_CB_EN3_MASK (0x3f << 18)
+#define WEIGHT_CB_EN3_SHIFT 18
+#define CG_CAC_REGION_2_WEIGHT_1 0x86
+#define WEIGHT_DB_SIG0(x) ((x) << 0)
+#define WEIGHT_DB_SIG0_MASK (0x3f << 0)
+#define WEIGHT_DB_SIG0_SHIFT 0
+#define WEIGHT_DB_SIG1(x) ((x) << 6)
+#define WEIGHT_DB_SIG1_MASK (0x3f << 6)
+#define WEIGHT_DB_SIG1_SHIFT 6
+#define WEIGHT_DB_SIG2(x) ((x) << 12)
+#define WEIGHT_DB_SIG2_MASK (0x3f << 12)
+#define WEIGHT_DB_SIG2_SHIFT 12
+#define WEIGHT_DB_SIG3(x) ((x) << 18)
+#define WEIGHT_DB_SIG3_MASK (0x3f << 18)
+#define WEIGHT_DB_SIG3_SHIFT 18
+#define CG_CAC_REGION_2_WEIGHT_2 0x87
+#define WEIGHT_SXM_SIG0(x) ((x) << 0)
+#define WEIGHT_SXM_SIG0_MASK (0x3f << 0)
+#define WEIGHT_SXM_SIG0_SHIFT 0
+#define WEIGHT_SXM_SIG1(x) ((x) << 6)
+#define WEIGHT_SXM_SIG1_MASK (0x3f << 6)
+#define WEIGHT_SXM_SIG1_SHIFT 6
+#define WEIGHT_SXM_SIG2(x) ((x) << 12)
+#define WEIGHT_SXM_SIG2_MASK (0x3f << 12)
+#define WEIGHT_SXM_SIG2_SHIFT 12
+#define WEIGHT_SXS_SIG0(x) ((x) << 18)
+#define WEIGHT_SXS_SIG0_MASK (0x3f << 18)
+#define WEIGHT_SXS_SIG0_SHIFT 18
+#define WEIGHT_SXS_SIG1(x) ((x) << 24)
+#define WEIGHT_SXS_SIG1_MASK (0x3f << 24)
+#define WEIGHT_SXS_SIG1_SHIFT 24
+#define CG_CAC_REGION_3_WEIGHT_0 0x88
+#define WEIGHT_XBR_0(x) ((x) << 0)
+#define WEIGHT_XBR_0_MASK (0x3f << 0)
+#define WEIGHT_XBR_0_SHIFT 0
+#define WEIGHT_XBR_1(x) ((x) << 6)
+#define WEIGHT_XBR_1_MASK (0x3f << 6)
+#define WEIGHT_XBR_1_SHIFT 6
+#define WEIGHT_XBR_2(x) ((x) << 12)
+#define WEIGHT_XBR_2_MASK (0x3f << 12)
+#define WEIGHT_XBR_2_SHIFT 12
+#define WEIGHT_SPI_SIG0(x) ((x) << 18)
+#define WEIGHT_SPI_SIG0_MASK (0x3f << 18)
+#define WEIGHT_SPI_SIG0_SHIFT 18
+#define CG_CAC_REGION_3_WEIGHT_1 0x89
+#define WEIGHT_SPI_SIG1(x) ((x) << 0)
+#define WEIGHT_SPI_SIG1_MASK (0x3f << 0)
+#define WEIGHT_SPI_SIG1_SHIFT 0
+#define WEIGHT_SPI_SIG2(x) ((x) << 6)
+#define WEIGHT_SPI_SIG2_MASK (0x3f << 6)
+#define WEIGHT_SPI_SIG2_SHIFT 6
+#define WEIGHT_SPI_SIG3(x) ((x) << 12)
+#define WEIGHT_SPI_SIG3_MASK (0x3f << 12)
+#define WEIGHT_SPI_SIG3_SHIFT 12
+#define WEIGHT_SPI_SIG4(x) ((x) << 18)
+#define WEIGHT_SPI_SIG4_MASK (0x3f << 18)
+#define WEIGHT_SPI_SIG4_SHIFT 18
+#define WEIGHT_SPI_SIG5(x) ((x) << 24)
+#define WEIGHT_SPI_SIG5_MASK (0x3f << 24)
+#define WEIGHT_SPI_SIG5_SHIFT 24
+#define CG_CAC_REGION_4_WEIGHT_0 0x8a
+#define WEIGHT_LDS_SIG0(x) ((x) << 0)
+#define WEIGHT_LDS_SIG0_MASK (0x3f << 0)
+#define WEIGHT_LDS_SIG0_SHIFT 0
+#define WEIGHT_LDS_SIG1(x) ((x) << 6)
+#define WEIGHT_LDS_SIG1_MASK (0x3f << 6)
+#define WEIGHT_LDS_SIG1_SHIFT 6
+#define WEIGHT_SC(x) ((x) << 24)
+#define WEIGHT_SC_MASK (0x3f << 24)
+#define WEIGHT_SC_SHIFT 24
+#define CG_CAC_REGION_4_WEIGHT_1 0x8b
+#define WEIGHT_BIF(x) ((x) << 0)
+#define WEIGHT_BIF_MASK (0x3f << 0)
+#define WEIGHT_BIF_SHIFT 0
+#define WEIGHT_CP(x) ((x) << 6)
+#define WEIGHT_CP_MASK (0x3f << 6)
+#define WEIGHT_CP_SHIFT 6
+#define WEIGHT_PA_SIG0(x) ((x) << 12)
+#define WEIGHT_PA_SIG0_MASK (0x3f << 12)
+#define WEIGHT_PA_SIG0_SHIFT 12
+#define WEIGHT_PA_SIG1(x) ((x) << 18)
+#define WEIGHT_PA_SIG1_MASK (0x3f << 18)
+#define WEIGHT_PA_SIG1_SHIFT 18
+#define WEIGHT_VGT_SIG0(x) ((x) << 24)
+#define WEIGHT_VGT_SIG0_MASK (0x3f << 24)
+#define WEIGHT_VGT_SIG0_SHIFT 24
+#define CG_CAC_REGION_4_WEIGHT_2 0x8c
+#define WEIGHT_VGT_SIG1(x) ((x) << 0)
+#define WEIGHT_VGT_SIG1_MASK (0x3f << 0)
+#define WEIGHT_VGT_SIG1_SHIFT 0
+#define WEIGHT_VGT_SIG2(x) ((x) << 6)
+#define WEIGHT_VGT_SIG2_MASK (0x3f << 6)
+#define WEIGHT_VGT_SIG2_SHIFT 6
+#define WEIGHT_DC_SIG0(x) ((x) << 12)
+#define WEIGHT_DC_SIG0_MASK (0x3f << 12)
+#define WEIGHT_DC_SIG0_SHIFT 12
+#define WEIGHT_DC_SIG1(x) ((x) << 18)
+#define WEIGHT_DC_SIG1_MASK (0x3f << 18)
+#define WEIGHT_DC_SIG1_SHIFT 18
+#define WEIGHT_DC_SIG2(x) ((x) << 24)
+#define WEIGHT_DC_SIG2_MASK (0x3f << 24)
+#define WEIGHT_DC_SIG2_SHIFT 24
+#define CG_CAC_REGION_4_WEIGHT_3 0x8d
+#define WEIGHT_DC_SIG3(x) ((x) << 0)
+#define WEIGHT_DC_SIG3_MASK (0x3f << 0)
+#define WEIGHT_DC_SIG3_SHIFT 0
+#define WEIGHT_UVD_SIG0(x) ((x) << 6)
+#define WEIGHT_UVD_SIG0_MASK (0x3f << 6)
+#define WEIGHT_UVD_SIG0_SHIFT 6
+#define WEIGHT_UVD_SIG1(x) ((x) << 12)
+#define WEIGHT_UVD_SIG1_MASK (0x3f << 12)
+#define WEIGHT_UVD_SIG1_SHIFT 12
+#define WEIGHT_SPARE0(x) ((x) << 18)
+#define WEIGHT_SPARE0_MASK (0x3f << 18)
+#define WEIGHT_SPARE0_SHIFT 18
+#define WEIGHT_SPARE1(x) ((x) << 24)
+#define WEIGHT_SPARE1_MASK (0x3f << 24)
+#define WEIGHT_SPARE1_SHIFT 24
+#define CG_CAC_REGION_5_WEIGHT_0 0x8e
+#define WEIGHT_SQ_VSP(x) ((x) << 0)
+#define WEIGHT_SQ_VSP_MASK (0x3fff << 0)
+#define WEIGHT_SQ_VSP_SHIFT 0
+#define WEIGHT_SQ_VSP0(x) ((x) << 14)
+#define WEIGHT_SQ_VSP0_MASK (0x3fff << 14)
+#define WEIGHT_SQ_VSP0_SHIFT 14
+#define CG_CAC_REGION_4_OVERRIDE_4 0xab
+#define OVR_MODE_SPARE_0(x) ((x) << 16)
+#define OVR_MODE_SPARE_0_MASK (0x1 << 16)
+#define OVR_MODE_SPARE_0_SHIFT 16
+#define OVR_VAL_SPARE_0(x) ((x) << 17)
+#define OVR_VAL_SPARE_0_MASK (0x1 << 17)
+#define OVR_VAL_SPARE_0_SHIFT 17
+#define OVR_MODE_SPARE_1(x) ((x) << 18)
+#define OVR_MODE_SPARE_1_MASK (0x3f << 18)
+#define OVR_MODE_SPARE_1_SHIFT 18
+#define OVR_VAL_SPARE_1(x) ((x) << 19)
+#define OVR_VAL_SPARE_1_MASK (0x3f << 19)
+#define OVR_VAL_SPARE_1_SHIFT 19
+#define CG_CAC_REGION_5_WEIGHT_1 0xb7
+#define WEIGHT_SQ_GPR(x) ((x) << 0)
+#define WEIGHT_SQ_GPR_MASK (0x3fff << 0)
+#define WEIGHT_SQ_GPR_SHIFT 0
+#define WEIGHT_SQ_LDS(x) ((x) << 14)
+#define WEIGHT_SQ_LDS_MASK (0x3fff << 14)
+#define WEIGHT_SQ_LDS_SHIFT 14
+
+/* PCIE link stuff */
+#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
+#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
+# define LC_LINK_WIDTH_SHIFT 0
+# define LC_LINK_WIDTH_MASK 0x7
+# define LC_LINK_WIDTH_X0 0
+# define LC_LINK_WIDTH_X1 1
+# define LC_LINK_WIDTH_X2 2
+# define LC_LINK_WIDTH_X4 3
+# define LC_LINK_WIDTH_X8 4
+# define LC_LINK_WIDTH_X16 6
+# define LC_LINK_WIDTH_RD_SHIFT 4
+# define LC_LINK_WIDTH_RD_MASK 0x70
+# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define LC_RECONFIG_NOW (1 << 8)
+# define LC_RENEGOTIATION_SUPPORT (1 << 9)
+# define LC_RENEGOTIATE_EN (1 << 10)
+# define LC_SHORT_RECONFIG_EN (1 << 11)
+# define LC_UPCONFIGURE_SUPPORT (1 << 12)
+# define LC_UPCONFIGURE_DIS (1 << 13)
+#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
+# define LC_GEN2_EN_STRAP (1 << 0)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 1)
+# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 5)
+# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 6)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
+# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12
+# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
+# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24)
+#define MM_CFGREGS_CNTL 0x544c
+# define MM_WR_TO_CFG_EN (1 << 3)
+#define LINK_CNTL2 0x88 /* F0 */
+# define TARGET_LINK_SPEED_MASK (0xf << 0)
+# define SELECTABLE_DEEMPHASIS (1 << 6)
+
/*
* UVD
*/
diff --git a/drivers/gpu/drm/radeon/nislands_smc.h b/drivers/gpu/drm/radeon/nislands_smc.h
new file mode 100644
index 000000000000..3cf8fc0d83f4
--- /dev/null
+++ b/drivers/gpu/drm/radeon/nislands_smc.h
@@ -0,0 +1,329 @@
+/*
+ * 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 __NISLANDS_SMC_H__
+#define __NISLANDS_SMC_H__
+
+#pragma pack(push, 1)
+
+#define NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
+
+struct PP_NIslands_Dpm2PerfLevel
+{
+ uint8_t MaxPS;
+ uint8_t TgtAct;
+ uint8_t MaxPS_StepInc;
+ uint8_t MaxPS_StepDec;
+ uint8_t PSST;
+ uint8_t NearTDPDec;
+ uint8_t AboveSafeInc;
+ uint8_t BelowSafeInc;
+ uint8_t PSDeltaLimit;
+ uint8_t PSDeltaWin;
+ uint8_t Reserved[6];
+};
+
+typedef struct PP_NIslands_Dpm2PerfLevel PP_NIslands_Dpm2PerfLevel;
+
+struct PP_NIslands_DPM2Parameters
+{
+ uint32_t TDPLimit;
+ uint32_t NearTDPLimit;
+ uint32_t SafePowerLimit;
+ uint32_t PowerBoostLimit;
+};
+typedef struct PP_NIslands_DPM2Parameters PP_NIslands_DPM2Parameters;
+
+struct NISLANDS_SMC_SCLK_VALUE
+{
+ uint32_t vCG_SPLL_FUNC_CNTL;
+ uint32_t vCG_SPLL_FUNC_CNTL_2;
+ uint32_t vCG_SPLL_FUNC_CNTL_3;
+ uint32_t vCG_SPLL_FUNC_CNTL_4;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t sclk_value;
+};
+
+typedef struct NISLANDS_SMC_SCLK_VALUE NISLANDS_SMC_SCLK_VALUE;
+
+struct NISLANDS_SMC_MCLK_VALUE
+{
+ uint32_t vMPLL_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL_1;
+ uint32_t vMPLL_FUNC_CNTL_2;
+ uint32_t vMPLL_AD_FUNC_CNTL;
+ uint32_t vMPLL_AD_FUNC_CNTL_2;
+ uint32_t vMPLL_DQ_FUNC_CNTL;
+ uint32_t vMPLL_DQ_FUNC_CNTL_2;
+ uint32_t vMCLK_PWRMGT_CNTL;
+ uint32_t vDLL_CNTL;
+ uint32_t vMPLL_SS;
+ uint32_t vMPLL_SS2;
+ uint32_t mclk_value;
+};
+
+typedef struct NISLANDS_SMC_MCLK_VALUE NISLANDS_SMC_MCLK_VALUE;
+
+struct NISLANDS_SMC_VOLTAGE_VALUE
+{
+ uint16_t value;
+ uint8_t index;
+ uint8_t padding;
+};
+
+typedef struct NISLANDS_SMC_VOLTAGE_VALUE NISLANDS_SMC_VOLTAGE_VALUE;
+
+struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL
+{
+ uint8_t arbValue;
+ uint8_t ACIndex;
+ uint8_t displayWatermark;
+ uint8_t gen2PCIE;
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint8_t strobeMode;
+ uint8_t mcFlags;
+ uint32_t aT;
+ uint32_t bSP;
+ NISLANDS_SMC_SCLK_VALUE sclk;
+ NISLANDS_SMC_MCLK_VALUE mclk;
+ NISLANDS_SMC_VOLTAGE_VALUE vddc;
+ NISLANDS_SMC_VOLTAGE_VALUE mvdd;
+ NISLANDS_SMC_VOLTAGE_VALUE vddci;
+ NISLANDS_SMC_VOLTAGE_VALUE std_vddc;
+ uint32_t powergate_en;
+ uint8_t hUp;
+ uint8_t hDown;
+ uint8_t stateFlags;
+ uint8_t arbRefreshState;
+ uint32_t SQPowerThrottle;
+ uint32_t SQPowerThrottle_2;
+ uint32_t reserved[2];
+ PP_NIslands_Dpm2PerfLevel dpm2;
+};
+
+#define NISLANDS_SMC_STROBE_RATIO 0x0F
+#define NISLANDS_SMC_STROBE_ENABLE 0x10
+
+#define NISLANDS_SMC_MC_EDC_RD_FLAG 0x01
+#define NISLANDS_SMC_MC_EDC_WR_FLAG 0x02
+#define NISLANDS_SMC_MC_RTT_ENABLE 0x04
+#define NISLANDS_SMC_MC_STUTTER_EN 0x08
+
+typedef struct NISLANDS_SMC_HW_PERFORMANCE_LEVEL NISLANDS_SMC_HW_PERFORMANCE_LEVEL;
+
+struct NISLANDS_SMC_SWSTATE
+{
+ uint8_t flags;
+ uint8_t levelCount;
+ uint8_t padding2;
+ uint8_t padding3;
+ NISLANDS_SMC_HW_PERFORMANCE_LEVEL levels[1];
+};
+
+typedef struct NISLANDS_SMC_SWSTATE NISLANDS_SMC_SWSTATE;
+
+#define NISLANDS_SMC_VOLTAGEMASK_VDDC 0
+#define NISLANDS_SMC_VOLTAGEMASK_MVDD 1
+#define NISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define NISLANDS_SMC_VOLTAGEMASK_MAX 4
+
+struct NISLANDS_SMC_VOLTAGEMASKTABLE
+{
+ uint8_t highMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
+ uint32_t lowMask[NISLANDS_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct NISLANDS_SMC_VOLTAGEMASKTABLE NISLANDS_SMC_VOLTAGEMASKTABLE;
+
+#define NISLANDS_MAX_NO_VREG_STEPS 32
+
+struct NISLANDS_SMC_STATETABLE
+{
+ uint8_t thermalProtectType;
+ uint8_t systemFlags;
+ uint8_t maxVDDCIndexInPPTable;
+ uint8_t extraFlags;
+ uint8_t highSMIO[NISLANDS_MAX_NO_VREG_STEPS];
+ uint32_t lowSMIO[NISLANDS_MAX_NO_VREG_STEPS];
+ NISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
+ PP_NIslands_DPM2Parameters dpm2Params;
+ NISLANDS_SMC_SWSTATE initialState;
+ NISLANDS_SMC_SWSTATE ACPIState;
+ NISLANDS_SMC_SWSTATE ULVState;
+ NISLANDS_SMC_SWSTATE driverState;
+ NISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[NISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
+};
+
+typedef struct NISLANDS_SMC_STATETABLE NISLANDS_SMC_STATETABLE;
+
+#define NI_SMC_SOFT_REGISTERS_START 0x108
+
+#define NI_SMC_SOFT_REGISTER_mclk_chg_timeout 0x0
+#define NI_SMC_SOFT_REGISTER_delay_bbias 0xC
+#define NI_SMC_SOFT_REGISTER_delay_vreg 0x10
+#define NI_SMC_SOFT_REGISTER_delay_acpi 0x2C
+#define NI_SMC_SOFT_REGISTER_seq_index 0x64
+#define NI_SMC_SOFT_REGISTER_mvdd_chg_time 0x68
+#define NI_SMC_SOFT_REGISTER_mclk_switch_lim 0x78
+#define NI_SMC_SOFT_REGISTER_watermark_threshold 0x80
+#define NI_SMC_SOFT_REGISTER_mc_block_delay 0x84
+#define NI_SMC_SOFT_REGISTER_uvd_enabled 0x98
+
+#define SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES 16
+#define SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 16
+#define SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES 4
+
+struct SMC_NISLANDS_MC_TPP_CAC_TABLE
+{
+ uint32_t tpp[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES];
+ uint32_t cacValue[SMC_NISLANDS_MC_TPP_CAC_NUM_OF_ENTRIES];
+};
+
+typedef struct SMC_NISLANDS_MC_TPP_CAC_TABLE SMC_NISLANDS_MC_TPP_CAC_TABLE;
+
+
+struct PP_NIslands_CACTABLES
+{
+ uint32_t cac_bif_lut[SMC_NISLANDS_BIF_LUT_NUM_OF_ENTRIES];
+ uint32_t cac_lkge_lut[SMC_NISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_NISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES];
+
+ uint32_t pwr_const;
+
+ uint32_t dc_cacValue;
+ uint32_t bif_cacValue;
+ uint32_t lkge_pwr;
+
+ uint8_t cac_width;
+ uint8_t window_size_p2;
+
+ uint8_t num_drop_lsb;
+ uint8_t padding_0;
+
+ uint32_t last_power;
+
+ uint8_t AllowOvrflw;
+ uint8_t MCWrWeight;
+ uint8_t MCRdWeight;
+ uint8_t padding_1[9];
+
+ uint8_t enableWinAvg;
+ uint8_t numWin_TDP;
+ uint8_t l2numWin_TDP;
+ uint8_t WinIndex;
+
+ uint32_t dynPwr_TDP[4];
+ uint32_t lkgePwr_TDP[4];
+ uint32_t power_TDP[4];
+ uint32_t avg_dynPwr_TDP;
+ uint32_t avg_lkgePwr_TDP;
+ uint32_t avg_power_TDP;
+ uint32_t lts_power_TDP;
+ uint8_t lts_truncate_n;
+ uint8_t padding_2[7];
+};
+
+typedef struct PP_NIslands_CACTABLES PP_NIslands_CACTABLES;
+
+#define SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE 32
+#define SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
+
+struct SMC_NIslands_MCRegisterAddress
+{
+ uint16_t s0;
+ uint16_t s1;
+};
+
+typedef struct SMC_NIslands_MCRegisterAddress SMC_NIslands_MCRegisterAddress;
+
+
+struct SMC_NIslands_MCRegisterSet
+{
+ uint32_t value[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_NIslands_MCRegisterSet SMC_NIslands_MCRegisterSet;
+
+struct SMC_NIslands_MCRegisters
+{
+ uint8_t last;
+ uint8_t reserved[3];
+ SMC_NIslands_MCRegisterAddress address[SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE];
+ SMC_NIslands_MCRegisterSet data[SMC_NISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMC_NIslands_MCRegisters SMC_NIslands_MCRegisters;
+
+struct SMC_NIslands_MCArbDramTimingRegisterSet
+{
+ uint32_t mc_arb_dram_timing;
+ uint32_t mc_arb_dram_timing2;
+ uint8_t mc_arb_rfsh_rate;
+ uint8_t padding[3];
+};
+
+typedef struct SMC_NIslands_MCArbDramTimingRegisterSet SMC_NIslands_MCArbDramTimingRegisterSet;
+
+struct SMC_NIslands_MCArbDramTimingRegisters
+{
+ uint8_t arb_current;
+ uint8_t reserved[3];
+ SMC_NIslands_MCArbDramTimingRegisterSet data[20];
+};
+
+typedef struct SMC_NIslands_MCArbDramTimingRegisters SMC_NIslands_MCArbDramTimingRegisters;
+
+struct SMC_NISLANDS_SPLL_DIV_TABLE
+{
+ uint32_t freq[256];
+ uint32_t ss[256];
+};
+
+#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_MASK 0x01ffffff
+#define SMC_NISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0
+#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_MASK 0xfe000000
+#define SMC_NISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT 25
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_MASK 0x000fffff
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT 0
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_MASK 0xfff00000
+#define SMC_NISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT 20
+
+typedef struct SMC_NISLANDS_SPLL_DIV_TABLE SMC_NISLANDS_SPLL_DIV_TABLE;
+
+#define NISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x100
+
+#define NISLANDS_SMC_FIRMWARE_HEADER_version 0x0
+#define NISLANDS_SMC_FIRMWARE_HEADER_flags 0x4
+#define NISLANDS_SMC_FIRMWARE_HEADER_softRegisters 0x8
+#define NISLANDS_SMC_FIRMWARE_HEADER_stateTable 0xC
+#define NISLANDS_SMC_FIRMWARE_HEADER_fanTable 0x10
+#define NISLANDS_SMC_FIRMWARE_HEADER_cacTable 0x14
+#define NISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable 0x20
+#define NISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x2C
+#define NISLANDS_SMC_FIRMWARE_HEADER_spllTable 0x30
+
+#pragma pack(pop)
+
+#endif
+
diff --git a/drivers/gpu/drm/radeon/ppsmc.h b/drivers/gpu/drm/radeon/ppsmc.h
new file mode 100644
index 000000000000..b5564a3645d2
--- /dev/null
+++ b/drivers/gpu/drm/radeon/ppsmc.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ */
+#ifndef PP_SMC_H
+#define PP_SMC_H
+
+#pragma pack(push, 1)
+
+#define PPSMC_SWSTATE_FLAG_DC 0x01
+#define PPSMC_SWSTATE_FLAG_UVD 0x02
+#define PPSMC_SWSTATE_FLAG_VCE 0x04
+#define PPSMC_SWSTATE_FLAG_PCIE_X1 0x08
+
+#define PPSMC_THERMAL_PROTECT_TYPE_INTERNAL 0x00
+#define PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL 0x01
+#define PPSMC_THERMAL_PROTECT_TYPE_NONE 0xff
+
+#define PPSMC_SYSTEMFLAG_GPIO_DC 0x01
+#define PPSMC_SYSTEMFLAG_STEPVDDC 0x02
+#define PPSMC_SYSTEMFLAG_GDDR5 0x04
+#define PPSMC_SYSTEMFLAG_DISABLE_BABYSTEP 0x08
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT 0x10
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_ANALOG 0x20
+#define PPSMC_SYSTEMFLAG_REGULATOR_HOT_PROG_GPIO 0x40
+
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_MASK 0x07
+#define PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK 0x08
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTODPMLOWSTATE 0x00
+#define PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE 0x01
+#define PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH 0x02
+
+#define PPSMC_DISPLAY_WATERMARK_LOW 0
+#define PPSMC_DISPLAY_WATERMARK_HIGH 1
+
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
+#define PPSMC_STATEFLAG_POWERBOOST 0x02
+#define PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE 0x20
+#define PPSMC_STATEFLAG_DEEPSLEEP_BYPASS 0x40
+
+#define PPSMC_Result_OK ((uint8_t)0x01)
+#define PPSMC_Result_Failed ((uint8_t)0xFF)
+
+typedef uint8_t PPSMC_Result;
+
+#define PPSMC_MSG_Halt ((uint8_t)0x10)
+#define PPSMC_MSG_Resume ((uint8_t)0x11)
+#define PPSMC_MSG_ZeroLevelsDisabled ((uint8_t)0x13)
+#define PPSMC_MSG_OneLevelsDisabled ((uint8_t)0x14)
+#define PPSMC_MSG_TwoLevelsDisabled ((uint8_t)0x15)
+#define PPSMC_MSG_EnableThermalInterrupt ((uint8_t)0x16)
+#define PPSMC_MSG_RunningOnAC ((uint8_t)0x17)
+#define PPSMC_MSG_SwitchToSwState ((uint8_t)0x20)
+#define PPSMC_MSG_SwitchToInitialState ((uint8_t)0x40)
+#define PPSMC_MSG_NoForcedLevel ((uint8_t)0x41)
+#define PPSMC_MSG_ForceHigh ((uint8_t)0x42)
+#define PPSMC_MSG_ForceMediumOrHigh ((uint8_t)0x43)
+#define PPSMC_MSG_SwitchToMinimumPower ((uint8_t)0x51)
+#define PPSMC_MSG_ResumeFromMinimumPower ((uint8_t)0x52)
+#define PPSMC_MSG_EnableCac ((uint8_t)0x53)
+#define PPSMC_MSG_DisableCac ((uint8_t)0x54)
+#define PPSMC_TDPClampingActive ((uint8_t)0x59)
+#define PPSMC_TDPClampingInactive ((uint8_t)0x5A)
+#define PPSMC_MSG_NoDisplay ((uint8_t)0x5D)
+#define PPSMC_MSG_HasDisplay ((uint8_t)0x5E)
+#define PPSMC_MSG_UVDPowerOFF ((uint8_t)0x60)
+#define PPSMC_MSG_UVDPowerON ((uint8_t)0x61)
+#define PPSMC_MSG_EnableULV ((uint8_t)0x62)
+#define PPSMC_MSG_DisableULV ((uint8_t)0x63)
+#define PPSMC_MSG_EnterULV ((uint8_t)0x64)
+#define PPSMC_MSG_ExitULV ((uint8_t)0x65)
+#define PPSMC_CACLongTermAvgEnable ((uint8_t)0x6E)
+#define PPSMC_CACLongTermAvgDisable ((uint8_t)0x6F)
+#define PPSMC_MSG_CollectCAC_PowerCorreln ((uint8_t)0x7A)
+#define PPSMC_FlushDataCache ((uint8_t)0x80)
+#define PPSMC_MSG_SetEnabledLevels ((uint8_t)0x82)
+#define PPSMC_MSG_SetForcedLevels ((uint8_t)0x83)
+#define PPSMC_MSG_ResetToDefaults ((uint8_t)0x84)
+#define PPSMC_MSG_EnableDTE ((uint8_t)0x87)
+#define PPSMC_MSG_DisableDTE ((uint8_t)0x88)
+#define PPSMC_MSG_ThrottleOVRDSCLKDS ((uint8_t)0x96)
+#define PPSMC_MSG_CancelThrottleOVRDSCLKDS ((uint8_t)0x97)
+
+/* TN */
+#define PPSMC_MSG_DPM_Config ((uint32_t) 0x102)
+#define PPSMC_MSG_DPM_ForceState ((uint32_t) 0x104)
+#define PPSMC_MSG_PG_SIMD_Config ((uint32_t) 0x108)
+#define PPSMC_MSG_DPM_N_LevelsDisabled ((uint32_t) 0x112)
+#define PPSMC_MSG_DCE_RemoveVoltageAdjustment ((uint32_t) 0x11d)
+#define PPSMC_MSG_DCE_AllowVoltageAdjustment ((uint32_t) 0x11e)
+#define PPSMC_MSG_UVD_DPM_Config ((uint32_t) 0x124)
+
+
+typedef uint16_t PPSMC_Msg;
+
+#pragma pack(pop)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index d0314ecbd7c1..c9affefd79f6 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -3077,6 +3077,10 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg,
flags |= RADEON_SURF_TILE_COLOR_BOTH;
if (tiling_flags & RADEON_TILING_MACRO)
flags |= RADEON_SURF_TILE_COLOR_MACRO;
+ /* setting pitch to 0 disables tiling */
+ if ((tiling_flags & (RADEON_TILING_MACRO|RADEON_TILING_MICRO))
+ == 0)
+ pitch = 0;
} else if (rdev->family <= CHIP_RV280) {
if (tiling_flags & (RADEON_TILING_MACRO))
flags |= R200_SURF_TILE_COLOR_MACRO;
@@ -3094,13 +3098,6 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg,
if (tiling_flags & RADEON_TILING_SWAP_32BIT)
flags |= RADEON_SURF_AP0_SWP_32BPP | RADEON_SURF_AP1_SWP_32BPP;
- /* when we aren't tiling the pitch seems to needs to be furtherdivided down. - tested on power5 + rn50 server */
- if (tiling_flags & (RADEON_TILING_SWAP_16BIT | RADEON_TILING_SWAP_32BIT)) {
- if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO)))
- if (ASIC_IS_RN50(rdev))
- pitch /= 16;
- }
-
/* r100/r200 divide by 16 */
if (rdev->family < CHIP_R300)
flags |= pitch / 16;
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 6948eb88c2b7..2d3655f7f41e 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -38,18 +38,7 @@
#include "r600d.h"
#include "atom.h"
#include "avivod.h"
-
-#define PFP_UCODE_SIZE 576
-#define PM4_UCODE_SIZE 1792
-#define RLC_UCODE_SIZE 768
-#define R700_PFP_UCODE_SIZE 848
-#define R700_PM4_UCODE_SIZE 1360
-#define R700_RLC_UCODE_SIZE 1024
-#define EVERGREEN_PFP_UCODE_SIZE 1120
-#define EVERGREEN_PM4_UCODE_SIZE 1376
-#define EVERGREEN_RLC_UCODE_SIZE 768
-#define CAYMAN_RLC_UCODE_SIZE 1024
-#define ARUBA_RLC_UCODE_SIZE 1536
+#include "radeon_ucode.h"
/* Firmware Names */
MODULE_FIRMWARE("radeon/R600_pfp.bin");
@@ -68,24 +57,32 @@ MODULE_FIRMWARE("radeon/RS780_pfp.bin");
MODULE_FIRMWARE("radeon/RS780_me.bin");
MODULE_FIRMWARE("radeon/RV770_pfp.bin");
MODULE_FIRMWARE("radeon/RV770_me.bin");
+MODULE_FIRMWARE("radeon/RV770_smc.bin");
MODULE_FIRMWARE("radeon/RV730_pfp.bin");
MODULE_FIRMWARE("radeon/RV730_me.bin");
+MODULE_FIRMWARE("radeon/RV730_smc.bin");
+MODULE_FIRMWARE("radeon/RV740_smc.bin");
MODULE_FIRMWARE("radeon/RV710_pfp.bin");
MODULE_FIRMWARE("radeon/RV710_me.bin");
+MODULE_FIRMWARE("radeon/RV710_smc.bin");
MODULE_FIRMWARE("radeon/R600_rlc.bin");
MODULE_FIRMWARE("radeon/R700_rlc.bin");
MODULE_FIRMWARE("radeon/CEDAR_pfp.bin");
MODULE_FIRMWARE("radeon/CEDAR_me.bin");
MODULE_FIRMWARE("radeon/CEDAR_rlc.bin");
+MODULE_FIRMWARE("radeon/CEDAR_smc.bin");
MODULE_FIRMWARE("radeon/REDWOOD_pfp.bin");
MODULE_FIRMWARE("radeon/REDWOOD_me.bin");
MODULE_FIRMWARE("radeon/REDWOOD_rlc.bin");
+MODULE_FIRMWARE("radeon/REDWOOD_smc.bin");
MODULE_FIRMWARE("radeon/JUNIPER_pfp.bin");
MODULE_FIRMWARE("radeon/JUNIPER_me.bin");
MODULE_FIRMWARE("radeon/JUNIPER_rlc.bin");
+MODULE_FIRMWARE("radeon/JUNIPER_smc.bin");
MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin");
MODULE_FIRMWARE("radeon/CYPRESS_me.bin");
MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin");
+MODULE_FIRMWARE("radeon/CYPRESS_smc.bin");
MODULE_FIRMWARE("radeon/PALM_pfp.bin");
MODULE_FIRMWARE("radeon/PALM_me.bin");
MODULE_FIRMWARE("radeon/SUMO_rlc.bin");
@@ -108,6 +105,7 @@ static void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
void r600_irq_disable(struct radeon_device *rdev);
static void r600_pcie_gen2_enable(struct radeon_device *rdev);
+extern int evergreen_rlc_resume(struct radeon_device *rdev);
/**
* r600_get_xclk - get the xclk
@@ -2149,7 +2147,8 @@ int r600_init_microcode(struct radeon_device *rdev)
struct platform_device *pdev;
const char *chip_name;
const char *rlc_chip_name;
- size_t pfp_req_size, me_req_size, rlc_req_size;
+ const char *smc_chip_name = "RV770";
+ size_t pfp_req_size, me_req_size, rlc_req_size, smc_req_size = 0;
char fw_name[30];
int err;
@@ -2195,32 +2194,51 @@ int r600_init_microcode(struct radeon_device *rdev)
case CHIP_RV770:
chip_name = "RV770";
rlc_chip_name = "R700";
+ smc_chip_name = "RV770";
+ smc_req_size = ALIGN(RV770_SMC_UCODE_SIZE, 4);
break;
case CHIP_RV730:
- case CHIP_RV740:
chip_name = "RV730";
rlc_chip_name = "R700";
+ smc_chip_name = "RV730";
+ smc_req_size = ALIGN(RV730_SMC_UCODE_SIZE, 4);
break;
case CHIP_RV710:
chip_name = "RV710";
rlc_chip_name = "R700";
+ smc_chip_name = "RV710";
+ smc_req_size = ALIGN(RV710_SMC_UCODE_SIZE, 4);
+ break;
+ case CHIP_RV740:
+ chip_name = "RV730";
+ rlc_chip_name = "R700";
+ smc_chip_name = "RV740";
+ smc_req_size = ALIGN(RV740_SMC_UCODE_SIZE, 4);
break;
case CHIP_CEDAR:
chip_name = "CEDAR";
rlc_chip_name = "CEDAR";
+ smc_chip_name = "CEDAR";
+ smc_req_size = ALIGN(CEDAR_SMC_UCODE_SIZE, 4);
break;
case CHIP_REDWOOD:
chip_name = "REDWOOD";
rlc_chip_name = "REDWOOD";
+ smc_chip_name = "REDWOOD";
+ smc_req_size = ALIGN(REDWOOD_SMC_UCODE_SIZE, 4);
break;
case CHIP_JUNIPER:
chip_name = "JUNIPER";
rlc_chip_name = "JUNIPER";
+ smc_chip_name = "JUNIPER";
+ smc_req_size = ALIGN(JUNIPER_SMC_UCODE_SIZE, 4);
break;
case CHIP_CYPRESS:
case CHIP_HEMLOCK:
chip_name = "CYPRESS";
rlc_chip_name = "CYPRESS";
+ smc_chip_name = "CYPRESS";
+ smc_req_size = ALIGN(CYPRESS_SMC_UCODE_SIZE, 4);
break;
case CHIP_PALM:
chip_name = "PALM";
@@ -2246,9 +2264,9 @@ int r600_init_microcode(struct radeon_device *rdev)
me_req_size = R700_PM4_UCODE_SIZE * 4;
rlc_req_size = R700_RLC_UCODE_SIZE * 4;
} else {
- pfp_req_size = PFP_UCODE_SIZE * 4;
- me_req_size = PM4_UCODE_SIZE * 12;
- rlc_req_size = RLC_UCODE_SIZE * 4;
+ pfp_req_size = R600_PFP_UCODE_SIZE * 4;
+ me_req_size = R600_PM4_UCODE_SIZE * 12;
+ rlc_req_size = R600_RLC_UCODE_SIZE * 4;
}
DRM_INFO("Loading %s Microcode\n", chip_name);
@@ -2287,6 +2305,19 @@ int r600_init_microcode(struct radeon_device *rdev)
err = -EINVAL;
}
+ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) {
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name);
+ err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->smc_fw->size != smc_req_size) {
+ printk(KERN_ERR
+ "smc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->smc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+ }
+
out:
platform_device_unregister(pdev);
@@ -2301,6 +2332,8 @@ out:
rdev->me_fw = NULL;
release_firmware(rdev->rlc_fw);
rdev->rlc_fw = NULL;
+ release_firmware(rdev->smc_fw);
+ rdev->smc_fw = NULL;
}
return err;
}
@@ -2331,13 +2364,13 @@ static int r600_cp_load_microcode(struct radeon_device *rdev)
fw_data = (const __be32 *)rdev->me_fw->data;
WREG32(CP_ME_RAM_WADDR, 0);
- for (i = 0; i < PM4_UCODE_SIZE * 3; i++)
+ for (i = 0; i < R600_PM4_UCODE_SIZE * 3; i++)
WREG32(CP_ME_RAM_DATA,
be32_to_cpup(fw_data++));
fw_data = (const __be32 *)rdev->pfp_fw->data;
WREG32(CP_PFP_UCODE_ADDR, 0);
- for (i = 0; i < PFP_UCODE_SIZE; i++)
+ for (i = 0; i < R600_PFP_UCODE_SIZE; i++)
WREG32(CP_PFP_UCODE_DATA,
be32_to_cpup(fw_data++));
@@ -3789,7 +3822,7 @@ static void r600_rlc_start(struct radeon_device *rdev)
WREG32(RLC_CNTL, RLC_ENABLE);
}
-static int r600_rlc_init(struct radeon_device *rdev)
+static int r600_rlc_resume(struct radeon_device *rdev)
{
u32 i;
const __be32 *fw_data;
@@ -3801,45 +3834,22 @@ static int r600_rlc_init(struct radeon_device *rdev)
WREG32(RLC_HB_CNTL, 0);
- if (rdev->family == CHIP_ARUBA) {
- WREG32(TN_RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
- WREG32(TN_RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
- }
- if (rdev->family <= CHIP_CAYMAN) {
- WREG32(RLC_HB_BASE, 0);
- WREG32(RLC_HB_RPTR, 0);
- WREG32(RLC_HB_WPTR, 0);
- }
- if (rdev->family <= CHIP_CAICOS) {
- WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
- WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
- }
+ WREG32(RLC_HB_BASE, 0);
+ WREG32(RLC_HB_RPTR, 0);
+ WREG32(RLC_HB_WPTR, 0);
+ WREG32(RLC_HB_WPTR_LSB_ADDR, 0);
+ WREG32(RLC_HB_WPTR_MSB_ADDR, 0);
WREG32(RLC_MC_CNTL, 0);
WREG32(RLC_UCODE_CNTL, 0);
fw_data = (const __be32 *)rdev->rlc_fw->data;
- if (rdev->family >= CHIP_ARUBA) {
- for (i = 0; i < ARUBA_RLC_UCODE_SIZE; i++) {
- WREG32(RLC_UCODE_ADDR, i);
- WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
- }
- } else if (rdev->family >= CHIP_CAYMAN) {
- for (i = 0; i < CAYMAN_RLC_UCODE_SIZE; i++) {
- WREG32(RLC_UCODE_ADDR, i);
- WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
- }
- } else if (rdev->family >= CHIP_CEDAR) {
- for (i = 0; i < EVERGREEN_RLC_UCODE_SIZE; i++) {
- WREG32(RLC_UCODE_ADDR, i);
- WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
- }
- } else if (rdev->family >= CHIP_RV770) {
+ if (rdev->family >= CHIP_RV770) {
for (i = 0; i < R700_RLC_UCODE_SIZE; i++) {
WREG32(RLC_UCODE_ADDR, i);
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
}
} else {
- for (i = 0; i < RLC_UCODE_SIZE; i++) {
+ for (i = 0; i < R600_RLC_UCODE_SIZE; i++) {
WREG32(RLC_UCODE_ADDR, i);
WREG32(RLC_UCODE_DATA, be32_to_cpup(fw_data++));
}
@@ -3947,7 +3957,10 @@ int r600_irq_init(struct radeon_device *rdev)
r600_disable_interrupts(rdev);
/* init rlc */
- ret = r600_rlc_init(rdev);
+ if (rdev->family >= CHIP_CEDAR)
+ ret = evergreen_rlc_resume(rdev);
+ else
+ ret = r600_rlc_resume(rdev);
if (ret) {
r600_ih_ring_fini(rdev);
return ret;
@@ -4028,6 +4041,7 @@ int r600_irq_set(struct radeon_device *rdev)
u32 hdmi0, hdmi1;
u32 d1grph = 0, d2grph = 0;
u32 dma_cntl;
+ u32 thermal_int = 0;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -4062,8 +4076,21 @@ int r600_irq_set(struct radeon_device *rdev)
hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
}
+
dma_cntl = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
+ if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
+ thermal_int = RREG32(CG_THERMAL_INT) &
+ ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+ } else if (rdev->family >= CHIP_RV770) {
+ thermal_int = RREG32(RV770_CG_THERMAL_INT) &
+ ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+ }
+ if (rdev->irq.dpm_thermal) {
+ DRM_DEBUG("dpm thermal\n");
+ thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+ }
+
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
DRM_DEBUG("r600_irq_set: sw int\n");
cp_int_cntl |= RB_INT_ENABLE;
@@ -4145,6 +4172,11 @@ int r600_irq_set(struct radeon_device *rdev)
WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
}
+ if ((rdev->family > CHIP_R600) && (rdev->family < CHIP_RV770)) {
+ WREG32(CG_THERMAL_INT, thermal_int);
+ } else if (rdev->family >= CHIP_RV770) {
+ WREG32(RV770_CG_THERMAL_INT, thermal_int);
+ }
return 0;
}
@@ -4336,6 +4368,7 @@ int r600_irq_process(struct radeon_device *rdev)
u32 ring_index;
bool queue_hotplug = false;
bool queue_hdmi = false;
+ bool queue_thermal = false;
if (!rdev->ih.enabled || rdev->shutdown)
return IRQ_NONE;
@@ -4503,6 +4536,16 @@ restart_ih:
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
+ case 230: /* thermal low to high */
+ DRM_DEBUG("IH: thermal low to high\n");
+ rdev->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");
+ rdev->pm.dpm.thermal.high_to_low = true;
+ queue_thermal = true;
+ break;
case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n");
break;
@@ -4519,6 +4562,8 @@ restart_ih:
schedule_work(&rdev->hotplug_work);
if (queue_hdmi)
schedule_work(&rdev->audio_work);
+ if (queue_thermal && rdev->pm.dpm_enabled)
+ schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0);
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
new file mode 100644
index 000000000000..b88f54b134ab
--- /dev/null
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -0,0 +1,1048 @@
+/*
+ * 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 "radeon.h"
+#include "r600d.h"
+#include "r600_dpm.h"
+#include "atom.h"
+
+const u32 r600_utc[R600_PM_NUMBER_OF_TC] =
+{
+ R600_UTC_DFLT_00,
+ R600_UTC_DFLT_01,
+ R600_UTC_DFLT_02,
+ R600_UTC_DFLT_03,
+ R600_UTC_DFLT_04,
+ R600_UTC_DFLT_05,
+ R600_UTC_DFLT_06,
+ R600_UTC_DFLT_07,
+ R600_UTC_DFLT_08,
+ R600_UTC_DFLT_09,
+ R600_UTC_DFLT_10,
+ R600_UTC_DFLT_11,
+ R600_UTC_DFLT_12,
+ R600_UTC_DFLT_13,
+ R600_UTC_DFLT_14,
+};
+
+const u32 r600_dtc[R600_PM_NUMBER_OF_TC] =
+{
+ R600_DTC_DFLT_00,
+ R600_DTC_DFLT_01,
+ R600_DTC_DFLT_02,
+ R600_DTC_DFLT_03,
+ R600_DTC_DFLT_04,
+ R600_DTC_DFLT_05,
+ R600_DTC_DFLT_06,
+ R600_DTC_DFLT_07,
+ R600_DTC_DFLT_08,
+ R600_DTC_DFLT_09,
+ R600_DTC_DFLT_10,
+ R600_DTC_DFLT_11,
+ R600_DTC_DFLT_12,
+ R600_DTC_DFLT_13,
+ R600_DTC_DFLT_14,
+};
+
+void r600_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 r600_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 r600_dpm_print_ps_status(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ printk("\tstatus: ");
+ if (rps == rdev->pm.dpm.current_ps)
+ printk("c ");
+ if (rps == rdev->pm.dpm.requested_ps)
+ printk("r ");
+ if (rps == rdev->pm.dpm.boot_ps)
+ printk("b ");
+ printk("\n");
+}
+
+u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)
+{
+ struct drm_device *dev = rdev->ddev;
+ struct drm_crtc *crtc;
+ struct radeon_crtc *radeon_crtc;
+ u32 line_time_us, vblank_lines;
+ u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ radeon_crtc = to_radeon_crtc(crtc);
+ if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
+ line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) /
+ radeon_crtc->hw_mode.clock;
+ vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end -
+ radeon_crtc->hw_mode.crtc_vdisplay +
+ (radeon_crtc->v_border * 2);
+ vblank_time_us = vblank_lines * line_time_us;
+ break;
+ }
+ }
+
+ return vblank_time_us;
+}
+
+void r600_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 r600_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;
+}
+
+void r600_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
+{
+ int i;
+
+ if (enable) {
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+ } else {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+
+ WREG32(CG_RLC_REQ_AND_RSP, 0x2);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (((RREG32(CG_RLC_REQ_AND_RSP) & CG_RLC_RSP_TYPE_MASK) >> CG_RLC_RSP_TYPE_SHIFT) == 1)
+ break;
+ udelay(1);
+ }
+
+ WREG32(CG_RLC_REQ_AND_RSP, 0x0);
+
+ WREG32(GRBM_PWR_CNTL, 0x1);
+ RREG32(GRBM_PWR_CNTL);
+ }
+}
+
+void r600_dynamicpm_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+}
+
+void r600_enable_thermal_protection(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ else
+ WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+}
+
+void r600_enable_acpi_pm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+void r600_enable_dynamic_pcie_gen2(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+bool r600_dynamicpm_enabled(struct radeon_device *rdev)
+{
+ if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
+ return true;
+ else
+ return false;
+}
+
+void r600_enable_sclk_control(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, 0, ~SCLK_PWRMGT_OFF);
+ else
+ WREG32_P(GENERAL_PWRMGT, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+}
+
+void r600_enable_mclk_control(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+ else
+ WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+void r600_enable_spll_bypass(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(CG_SPLL_FUNC_CNTL, SPLL_BYPASS_EN, ~SPLL_BYPASS_EN);
+ else
+ WREG32_P(CG_SPLL_FUNC_CNTL, 0, ~SPLL_BYPASS_EN);
+}
+
+void r600_wait_for_spll_change(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_CHG_STATUS)
+ break;
+ udelay(1);
+ }
+}
+
+void r600_set_bsp(struct radeon_device *rdev, u32 u, u32 p)
+{
+ WREG32(CG_BSP, BSP(p) | BSU(u));
+}
+
+void r600_set_at(struct radeon_device *rdev,
+ u32 l_to_m, u32 m_to_h,
+ u32 h_to_m, u32 m_to_l)
+{
+ WREG32(CG_RT, FLS(l_to_m) | FMS(m_to_h));
+ WREG32(CG_LT, FHS(h_to_m) | FMS(m_to_l));
+}
+
+void r600_set_tc(struct radeon_device *rdev,
+ u32 index, u32 u_t, u32 d_t)
+{
+ WREG32(CG_FFCT_0 + (index * 4), UTC_0(u_t) | DTC_0(d_t));
+}
+
+void r600_select_td(struct radeon_device *rdev,
+ enum r600_td td)
+{
+ if (td == R600_TD_AUTO)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+ else
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+ if (td == R600_TD_UP)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+ if (td == R600_TD_DOWN)
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+void r600_set_vrc(struct radeon_device *rdev, u32 vrv)
+{
+ WREG32(CG_FTV, vrv);
+}
+
+void r600_set_tpu(struct radeon_device *rdev, u32 u)
+{
+ WREG32_P(CG_TPC, TPU(u), ~TPU_MASK);
+}
+
+void r600_set_tpc(struct radeon_device *rdev, u32 c)
+{
+ WREG32_P(CG_TPC, TPCC(c), ~TPCC_MASK);
+}
+
+void r600_set_sstu(struct radeon_device *rdev, u32 u)
+{
+ WREG32_P(CG_SSP, CG_SSTU(u), ~CG_SSTU_MASK);
+}
+
+void r600_set_sst(struct radeon_device *rdev, u32 t)
+{
+ WREG32_P(CG_SSP, CG_SST(t), ~CG_SST_MASK);
+}
+
+void r600_set_git(struct radeon_device *rdev, u32 t)
+{
+ WREG32_P(CG_GIT, CG_GICST(t), ~CG_GICST_MASK);
+}
+
+void r600_set_fctu(struct radeon_device *rdev, u32 u)
+{
+ WREG32_P(CG_FC_T, FC_TU(u), ~FC_TU_MASK);
+}
+
+void r600_set_fct(struct radeon_device *rdev, u32 t)
+{
+ WREG32_P(CG_FC_T, FC_T(t), ~FC_T_MASK);
+}
+
+void r600_set_ctxcgtt3d_rphc(struct radeon_device *rdev, u32 p)
+{
+ WREG32_P(CG_CTX_CGTT3D_R, PHC(p), ~PHC_MASK);
+}
+
+void r600_set_ctxcgtt3d_rsdc(struct radeon_device *rdev, u32 s)
+{
+ WREG32_P(CG_CTX_CGTT3D_R, SDC(s), ~SDC_MASK);
+}
+
+void r600_set_vddc3d_oorsu(struct radeon_device *rdev, u32 u)
+{
+ WREG32_P(CG_VDDC3D_OOR, SU(u), ~SU_MASK);
+}
+
+void r600_set_vddc3d_oorphc(struct radeon_device *rdev, u32 p)
+{
+ WREG32_P(CG_VDDC3D_OOR, PHC(p), ~PHC_MASK);
+}
+
+void r600_set_vddc3d_oorsdc(struct radeon_device *rdev, u32 s)
+{
+ WREG32_P(CG_VDDC3D_OOR, SDC(s), ~SDC_MASK);
+}
+
+void r600_set_mpll_lock_time(struct radeon_device *rdev, u32 lock_time)
+{
+ WREG32_P(MPLL_TIME, MPLL_LOCK_TIME(lock_time), ~MPLL_LOCK_TIME_MASK);
+}
+
+void r600_set_mpll_reset_time(struct radeon_device *rdev, u32 reset_time)
+{
+ WREG32_P(MPLL_TIME, MPLL_RESET_TIME(reset_time), ~MPLL_RESET_TIME_MASK);
+}
+
+void r600_engine_clock_entry_enable(struct radeon_device *rdev,
+ u32 index, bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+ STEP_0_SPLL_ENTRY_VALID, ~STEP_0_SPLL_ENTRY_VALID);
+ else
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+ 0, ~STEP_0_SPLL_ENTRY_VALID);
+}
+
+void r600_engine_clock_entry_enable_pulse_skipping(struct radeon_device *rdev,
+ u32 index, bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+ STEP_0_SPLL_STEP_ENABLE, ~STEP_0_SPLL_STEP_ENABLE);
+ else
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+ 0, ~STEP_0_SPLL_STEP_ENABLE);
+}
+
+void r600_engine_clock_entry_enable_post_divider(struct radeon_device *rdev,
+ u32 index, bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+ STEP_0_POST_DIV_EN, ~STEP_0_POST_DIV_EN);
+ else
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART2 + (index * 4 * 2),
+ 0, ~STEP_0_POST_DIV_EN);
+}
+
+void r600_engine_clock_entry_set_post_divider(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+ STEP_0_SPLL_POST_DIV(divider), ~STEP_0_SPLL_POST_DIV_MASK);
+}
+
+void r600_engine_clock_entry_set_reference_divider(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+ STEP_0_SPLL_REF_DIV(divider), ~STEP_0_SPLL_REF_DIV_MASK);
+}
+
+void r600_engine_clock_entry_set_feedback_divider(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+ STEP_0_SPLL_FB_DIV(divider), ~STEP_0_SPLL_FB_DIV_MASK);
+}
+
+void r600_engine_clock_entry_set_step_time(struct radeon_device *rdev,
+ u32 index, u32 step_time)
+{
+ WREG32_P(SCLK_FREQ_SETTING_STEP_0_PART1 + (index * 4 * 2),
+ STEP_0_SPLL_STEP_TIME(step_time), ~STEP_0_SPLL_STEP_TIME_MASK);
+}
+
+void r600_vid_rt_set_ssu(struct radeon_device *rdev, u32 u)
+{
+ WREG32_P(VID_RT, SSTU(u), ~SSTU_MASK);
+}
+
+void r600_vid_rt_set_vru(struct radeon_device *rdev, u32 u)
+{
+ WREG32_P(VID_RT, VID_CRTU(u), ~VID_CRTU_MASK);
+}
+
+void r600_vid_rt_set_vrt(struct radeon_device *rdev, u32 rt)
+{
+ WREG32_P(VID_RT, VID_CRT(rt), ~VID_CRT_MASK);
+}
+
+void r600_voltage_control_enable_pins(struct radeon_device *rdev,
+ u64 mask)
+{
+ WREG32(LOWER_GPIO_ENABLE, mask & 0xffffffff);
+ WREG32(UPPER_GPIO_ENABLE, upper_32_bits(mask));
+}
+
+
+void r600_voltage_control_program_voltages(struct radeon_device *rdev,
+ enum r600_power_level index, u64 pins)
+{
+ u32 tmp, mask;
+ u32 ix = 3 - (3 & index);
+
+ WREG32(CTXSW_VID_LOWER_GPIO_CNTL + (ix * 4), pins & 0xffffffff);
+
+ mask = 7 << (3 * ix);
+ tmp = RREG32(VID_UPPER_GPIO_CNTL);
+ tmp = (tmp & ~mask) | ((pins >> (32 - (3 * ix))) & mask);
+ WREG32(VID_UPPER_GPIO_CNTL, tmp);
+}
+
+void r600_voltage_control_deactivate_static_control(struct radeon_device *rdev,
+ u64 mask)
+{
+ u32 gpio;
+
+ gpio = RREG32(GPIOPAD_MASK);
+ gpio &= ~mask;
+ WREG32(GPIOPAD_MASK, gpio);
+
+ gpio = RREG32(GPIOPAD_EN);
+ gpio &= ~mask;
+ WREG32(GPIOPAD_EN, gpio);
+
+ gpio = RREG32(GPIOPAD_A);
+ gpio &= ~mask;
+ WREG32(GPIOPAD_A, gpio);
+}
+
+void r600_power_level_enable(struct radeon_device *rdev,
+ enum r600_power_level index, bool enable)
+{
+ u32 ix = 3 - (3 & index);
+
+ if (enable)
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), CTXSW_FREQ_STATE_ENABLE,
+ ~CTXSW_FREQ_STATE_ENABLE);
+ else
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), 0,
+ ~CTXSW_FREQ_STATE_ENABLE);
+}
+
+void r600_power_level_set_voltage_index(struct radeon_device *rdev,
+ enum r600_power_level index, u32 voltage_index)
+{
+ u32 ix = 3 - (3 & index);
+
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4),
+ CTXSW_FREQ_VIDS_CFG_INDEX(voltage_index), ~CTXSW_FREQ_VIDS_CFG_INDEX_MASK);
+}
+
+void r600_power_level_set_mem_clock_index(struct radeon_device *rdev,
+ enum r600_power_level index, u32 mem_clock_index)
+{
+ u32 ix = 3 - (3 & index);
+
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4),
+ CTXSW_FREQ_MCLK_CFG_INDEX(mem_clock_index), ~CTXSW_FREQ_MCLK_CFG_INDEX_MASK);
+}
+
+void r600_power_level_set_eng_clock_index(struct radeon_device *rdev,
+ enum r600_power_level index, u32 eng_clock_index)
+{
+ u32 ix = 3 - (3 & index);
+
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4),
+ CTXSW_FREQ_SCLK_CFG_INDEX(eng_clock_index), ~CTXSW_FREQ_SCLK_CFG_INDEX_MASK);
+}
+
+void r600_power_level_set_watermark_id(struct radeon_device *rdev,
+ enum r600_power_level index,
+ enum r600_display_watermark watermark_id)
+{
+ u32 ix = 3 - (3 & index);
+ u32 tmp = 0;
+
+ if (watermark_id == R600_DISPLAY_WATERMARK_HIGH)
+ tmp = CTXSW_FREQ_DISPLAY_WATERMARK;
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), tmp, ~CTXSW_FREQ_DISPLAY_WATERMARK);
+}
+
+void r600_power_level_set_pcie_gen2(struct radeon_device *rdev,
+ enum r600_power_level index, bool compatible)
+{
+ u32 ix = 3 - (3 & index);
+ u32 tmp = 0;
+
+ if (compatible)
+ tmp = CTXSW_FREQ_GEN2PCIE_VOLT;
+ WREG32_P(CTXSW_PROFILE_INDEX + (ix * 4), tmp, ~CTXSW_FREQ_GEN2PCIE_VOLT);
+}
+
+enum r600_power_level r600_power_level_get_current_index(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK;
+ tmp >>= CURRENT_PROFILE_INDEX_SHIFT;
+ return tmp;
+}
+
+enum r600_power_level r600_power_level_get_target_index(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_PROFILE_INDEX_MASK;
+ tmp >>= TARGET_PROFILE_INDEX_SHIFT;
+ return tmp;
+}
+
+void r600_power_level_set_enter_index(struct radeon_device *rdev,
+ enum r600_power_level index)
+{
+ WREG32_P(TARGET_AND_CURRENT_PROFILE_INDEX, DYN_PWR_ENTER_INDEX(index),
+ ~DYN_PWR_ENTER_INDEX_MASK);
+}
+
+void r600_wait_for_power_level_unequal(struct radeon_device *rdev,
+ enum r600_power_level index)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (r600_power_level_get_target_index(rdev) != index)
+ break;
+ udelay(1);
+ }
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (r600_power_level_get_current_index(rdev) != index)
+ break;
+ udelay(1);
+ }
+}
+
+void r600_wait_for_power_level(struct radeon_device *rdev,
+ enum r600_power_level index)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (r600_power_level_get_target_index(rdev) == index)
+ break;
+ udelay(1);
+ }
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (r600_power_level_get_current_index(rdev) == index)
+ break;
+ udelay(1);
+ }
+}
+
+void r600_start_dpm(struct radeon_device *rdev)
+{
+ r600_enable_sclk_control(rdev, false);
+ r600_enable_mclk_control(rdev, false);
+
+ r600_dynamicpm_enable(rdev, true);
+
+ radeon_wait_for_vblank(rdev, 0);
+ radeon_wait_for_vblank(rdev, 1);
+
+ r600_enable_spll_bypass(rdev, true);
+ r600_wait_for_spll_change(rdev);
+ r600_enable_spll_bypass(rdev, false);
+ r600_wait_for_spll_change(rdev);
+
+ r600_enable_spll_bypass(rdev, true);
+ r600_wait_for_spll_change(rdev);
+ r600_enable_spll_bypass(rdev, false);
+ r600_wait_for_spll_change(rdev);
+
+ r600_enable_sclk_control(rdev, true);
+ r600_enable_mclk_control(rdev, true);
+}
+
+void r600_stop_dpm(struct radeon_device *rdev)
+{
+ r600_dynamicpm_enable(rdev, false);
+}
+
+int r600_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+ return 0;
+}
+
+void r600_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+
+}
+
+bool r600_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;
+}
+
+int r600_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp)
+{
+ int low_temp = 0 * 1000;
+ int high_temp = 255 * 1000;
+
+ 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;
+ }
+
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
+ WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+
+ rdev->pm.dpm.thermal.min_temp = low_temp;
+ rdev->pm.dpm.thermal.max_temp = high_temp;
+
+ return 0;
+}
+
+bool r600_is_internal_thermal_sensor(enum radeon_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:
+ 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;
+};
+
+static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependency_table *radeon_table,
+ ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
+{
+ u32 size = atom_table->ucNumEntries *
+ sizeof(struct radeon_clock_voltage_dependency_entry);
+ int i;
+
+ radeon_table->entries = kzalloc(size, GFP_KERNEL);
+ if (!radeon_table->entries)
+ return -ENOMEM;
+
+ for (i = 0; i < atom_table->ucNumEntries; i++) {
+ radeon_table->entries[i].clk = le16_to_cpu(atom_table->entries[i].usClockLow) |
+ (atom_table->entries[i].ucClockHigh << 16);
+ radeon_table->entries[i].v = le16_to_cpu(atom_table->entries[i].usVoltage);
+ }
+ radeon_table->count = atom_table->ucNumEntries;
+
+ 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
+
+int r600_parse_extended_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->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 (!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));
+ rdev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
+ rdev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin);
+ rdev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed);
+ rdev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh);
+ rdev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin);
+ rdev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed);
+ rdev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh);
+ if (fan_info->fan.ucFanTableFormat >= 2)
+ rdev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax);
+ else
+ rdev->pm.dpm.fan.t_max = 10900;
+ rdev->pm.dpm.fan.cycle_delay = 100000;
+ rdev->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 = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ dep_table);
+ if (ret)
+ 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 = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ dep_table);
+ if (ret) {
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+ 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 = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ dep_table);
+ if (ret) {
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+ 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) {
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
+ le16_to_cpu(clk_v->entries[0].usSclkLow) |
+ (clk_v->entries[0].ucSclkHigh << 16);
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
+ le16_to_cpu(clk_v->entries[0].usMclkLow) |
+ (clk_v->entries[0].ucMclkHigh << 16);
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
+ le16_to_cpu(clk_v->entries[0].usVddc);
+ rdev->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));
+
+ rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries =
+ kzalloc(psl->ucNumEntries *
+ sizeof(struct radeon_phase_shedding_limits_entry),
+ GFP_KERNEL);
+ if (!rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries) {
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < psl->ucNumEntries; i++) {
+ rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk =
+ le16_to_cpu(psl->entries[i].usSclkLow) |
+ (psl->entries[i].ucSclkHigh << 16);
+ rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk =
+ le16_to_cpu(psl->entries[i].usMclkLow) |
+ (psl->entries[i].ucMclkHigh << 16);
+ rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage =
+ le16_to_cpu(psl->entries[i].usVoltage);
+ }
+ rdev->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)) {
+ rdev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit);
+ rdev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
+ rdev->pm.dpm.near_tdp_limit_adjusted = rdev->pm.dpm.near_tdp_limit;
+ rdev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit);
+ if (rdev->pm.dpm.tdp_od_limit)
+ rdev->pm.dpm.power_control = true;
+ else
+ rdev->pm.dpm.power_control = false;
+ rdev->pm.dpm.tdp_adjustment = 0;
+ rdev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
+ rdev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage);
+ rdev->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));
+ u32 size = cac_table->ucNumEntries * sizeof(struct radeon_cac_leakage_table);
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL);
+ if (!rdev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+ return -ENOMEM;
+ }
+ for (i = 0; i < cac_table->ucNumEntries; i++) {
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
+ le16_to_cpu(cac_table->entries[i].usVddc);
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
+ le32_to_cpu(cac_table->entries[i].ulLeakageValue);
+ }
+ rdev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries;
+ }
+ }
+
+ /* ppm table */
+ 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_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));
+ rdev->pm.dpm.dyn_state.ppm_table =
+ kzalloc(sizeof(struct radeon_ppm_table), GFP_KERNEL);
+ if (!rdev->pm.dpm.dyn_state.ppm_table) {
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+ kfree(rdev->pm.dpm.dyn_state.cac_leakage_table.entries);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign;
+ rdev->pm.dpm.dyn_state.ppm_table->cpu_core_number =
+ le16_to_cpu(ppm->usCpuCoreNumber);
+ rdev->pm.dpm.dyn_state.ppm_table->platform_tdp =
+ le32_to_cpu(ppm->ulPlatformTDP);
+ rdev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp =
+ le32_to_cpu(ppm->ulSmallACPlatformTDP);
+ rdev->pm.dpm.dyn_state.ppm_table->platform_tdc =
+ le32_to_cpu(ppm->ulPlatformTDC);
+ rdev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc =
+ le32_to_cpu(ppm->ulSmallACPlatformTDC);
+ rdev->pm.dpm.dyn_state.ppm_table->apu_tdp =
+ le32_to_cpu(ppm->ulApuTDP);
+ rdev->pm.dpm.dyn_state.ppm_table->dgpu_tdp =
+ le32_to_cpu(ppm->ulDGpuTDP);
+ rdev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power =
+ le32_to_cpu(ppm->ulDGpuUlvPower);
+ rdev->pm.dpm.dyn_state.ppm_table->tj_max =
+ le32_to_cpu(ppm->ulTjmax);
+ }
+ }
+
+ return 0;
+}
+
+void r600_free_extended_power_table(struct radeon_device *rdev)
+{
+ if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries)
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
+ if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries)
+ kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
+ if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries)
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
+ if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries)
+ kfree(rdev->pm.dpm.dyn_state.cac_leakage_table.entries);
+ if (rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries)
+ kfree(rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries);
+ if (rdev->pm.dpm.dyn_state.ppm_table)
+ kfree(rdev->pm.dpm.dyn_state.ppm_table);
+}
+
+enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev,
+ u32 sys_mask,
+ enum radeon_pcie_gen asic_gen,
+ enum radeon_pcie_gen default_gen)
+{
+ switch (asic_gen) {
+ case RADEON_PCIE_GEN1:
+ return RADEON_PCIE_GEN1;
+ case RADEON_PCIE_GEN2:
+ return RADEON_PCIE_GEN2;
+ case RADEON_PCIE_GEN3:
+ return RADEON_PCIE_GEN3;
+ default:
+ if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == RADEON_PCIE_GEN3))
+ return RADEON_PCIE_GEN3;
+ else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == RADEON_PCIE_GEN2))
+ return RADEON_PCIE_GEN2;
+ else
+ return RADEON_PCIE_GEN1;
+ }
+ return RADEON_PCIE_GEN1;
+}
diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h
new file mode 100644
index 000000000000..7c822d9ae53d
--- /dev/null
+++ b/drivers/gpu/drm/radeon/r600_dpm.h
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __R600_DPM_H__
+#define __R600_DPM_H__
+
+#define R600_ASI_DFLT 10000
+#define R600_BSP_DFLT 0x41EB
+#define R600_BSU_DFLT 0x2
+#define R600_AH_DFLT 5
+#define R600_RLP_DFLT 25
+#define R600_RMP_DFLT 65
+#define R600_LHP_DFLT 40
+#define R600_LMP_DFLT 15
+#define R600_TD_DFLT 0
+#define R600_UTC_DFLT_00 0x24
+#define R600_UTC_DFLT_01 0x22
+#define R600_UTC_DFLT_02 0x22
+#define R600_UTC_DFLT_03 0x22
+#define R600_UTC_DFLT_04 0x22
+#define R600_UTC_DFLT_05 0x22
+#define R600_UTC_DFLT_06 0x22
+#define R600_UTC_DFLT_07 0x22
+#define R600_UTC_DFLT_08 0x22
+#define R600_UTC_DFLT_09 0x22
+#define R600_UTC_DFLT_10 0x22
+#define R600_UTC_DFLT_11 0x22
+#define R600_UTC_DFLT_12 0x22
+#define R600_UTC_DFLT_13 0x22
+#define R600_UTC_DFLT_14 0x22
+#define R600_DTC_DFLT_00 0x24
+#define R600_DTC_DFLT_01 0x22
+#define R600_DTC_DFLT_02 0x22
+#define R600_DTC_DFLT_03 0x22
+#define R600_DTC_DFLT_04 0x22
+#define R600_DTC_DFLT_05 0x22
+#define R600_DTC_DFLT_06 0x22
+#define R600_DTC_DFLT_07 0x22
+#define R600_DTC_DFLT_08 0x22
+#define R600_DTC_DFLT_09 0x22
+#define R600_DTC_DFLT_10 0x22
+#define R600_DTC_DFLT_11 0x22
+#define R600_DTC_DFLT_12 0x22
+#define R600_DTC_DFLT_13 0x22
+#define R600_DTC_DFLT_14 0x22
+#define R600_VRC_DFLT 0x0000C003
+#define R600_VOLTAGERESPONSETIME_DFLT 1000
+#define R600_BACKBIASRESPONSETIME_DFLT 1000
+#define R600_VRU_DFLT 0x3
+#define R600_SPLLSTEPTIME_DFLT 0x1000
+#define R600_SPLLSTEPUNIT_DFLT 0x3
+#define R600_TPU_DFLT 0
+#define R600_TPC_DFLT 0x200
+#define R600_SSTU_DFLT 0
+#define R600_SST_DFLT 0x00C8
+#define R600_GICST_DFLT 0x200
+#define R600_FCT_DFLT 0x0400
+#define R600_FCTU_DFLT 0
+#define R600_CTXCGTT3DRPHC_DFLT 0x20
+#define R600_CTXCGTT3DRSDC_DFLT 0x40
+#define R600_VDDC3DOORPHC_DFLT 0x100
+#define R600_VDDC3DOORSDC_DFLT 0x7
+#define R600_VDDC3DOORSU_DFLT 0
+#define R600_MPLLLOCKTIME_DFLT 100
+#define R600_MPLLRESETTIME_DFLT 150
+#define R600_VCOSTEPPCT_DFLT 20
+#define R600_ENDINGVCOSTEPPCT_DFLT 5
+#define R600_REFERENCEDIVIDER_DFLT 4
+
+#define R600_PM_NUMBER_OF_TC 15
+#define R600_PM_NUMBER_OF_SCLKS 20
+#define R600_PM_NUMBER_OF_MCLKS 4
+#define R600_PM_NUMBER_OF_VOLTAGE_LEVELS 4
+#define R600_PM_NUMBER_OF_ACTIVITY_LEVELS 3
+
+/* XXX are these ok? */
+#define R600_TEMP_RANGE_MIN (90 * 1000)
+#define R600_TEMP_RANGE_MAX (120 * 1000)
+
+enum r600_power_level {
+ R600_POWER_LEVEL_LOW = 0,
+ R600_POWER_LEVEL_MEDIUM = 1,
+ R600_POWER_LEVEL_HIGH = 2,
+ R600_POWER_LEVEL_CTXSW = 3,
+};
+
+enum r600_td {
+ R600_TD_AUTO,
+ R600_TD_UP,
+ R600_TD_DOWN,
+};
+
+enum r600_display_watermark {
+ R600_DISPLAY_WATERMARK_LOW = 0,
+ R600_DISPLAY_WATERMARK_HIGH = 1,
+};
+
+enum r600_display_gap
+{
+ R600_PM_DISPLAY_GAP_VBLANK_OR_WM = 0,
+ R600_PM_DISPLAY_GAP_VBLANK = 1,
+ R600_PM_DISPLAY_GAP_WATERMARK = 2,
+ R600_PM_DISPLAY_GAP_IGNORE = 3,
+};
+
+extern const u32 r600_utc[R600_PM_NUMBER_OF_TC];
+extern const u32 r600_dtc[R600_PM_NUMBER_OF_TC];
+
+void r600_dpm_print_class_info(u32 class, u32 class2);
+void r600_dpm_print_cap_info(u32 caps);
+void r600_dpm_print_ps_status(struct radeon_device *rdev,
+ struct radeon_ps *rps);
+u32 r600_dpm_get_vblank_time(struct radeon_device *rdev);
+bool r600_is_uvd_state(u32 class, u32 class2);
+void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
+ u32 *p, u32 *u);
+int r600_calculate_at(u32 t, u32 h, u32 fh, u32 fl, u32 *tl, u32 *th);
+void r600_gfx_clockgating_enable(struct radeon_device *rdev, bool enable);
+void r600_dynamicpm_enable(struct radeon_device *rdev, bool enable);
+void r600_enable_thermal_protection(struct radeon_device *rdev, bool enable);
+void r600_enable_acpi_pm(struct radeon_device *rdev);
+void r600_enable_dynamic_pcie_gen2(struct radeon_device *rdev, bool enable);
+bool r600_dynamicpm_enabled(struct radeon_device *rdev);
+void r600_enable_sclk_control(struct radeon_device *rdev, bool enable);
+void r600_enable_mclk_control(struct radeon_device *rdev, bool enable);
+void r600_enable_spll_bypass(struct radeon_device *rdev, bool enable);
+void r600_wait_for_spll_change(struct radeon_device *rdev);
+void r600_set_bsp(struct radeon_device *rdev, u32 u, u32 p);
+void r600_set_at(struct radeon_device *rdev,
+ u32 l_to_m, u32 m_to_h,
+ u32 h_to_m, u32 m_to_l);
+void r600_set_tc(struct radeon_device *rdev, u32 index, u32 u_t, u32 d_t);
+void r600_select_td(struct radeon_device *rdev, enum r600_td td);
+void r600_set_vrc(struct radeon_device *rdev, u32 vrv);
+void r600_set_tpu(struct radeon_device *rdev, u32 u);
+void r600_set_tpc(struct radeon_device *rdev, u32 c);
+void r600_set_sstu(struct radeon_device *rdev, u32 u);
+void r600_set_sst(struct radeon_device *rdev, u32 t);
+void r600_set_git(struct radeon_device *rdev, u32 t);
+void r600_set_fctu(struct radeon_device *rdev, u32 u);
+void r600_set_fct(struct radeon_device *rdev, u32 t);
+void r600_set_ctxcgtt3d_rphc(struct radeon_device *rdev, u32 p);
+void r600_set_ctxcgtt3d_rsdc(struct radeon_device *rdev, u32 s);
+void r600_set_vddc3d_oorsu(struct radeon_device *rdev, u32 u);
+void r600_set_vddc3d_oorphc(struct radeon_device *rdev, u32 p);
+void r600_set_vddc3d_oorsdc(struct radeon_device *rdev, u32 s);
+void r600_set_mpll_lock_time(struct radeon_device *rdev, u32 lock_time);
+void r600_set_mpll_reset_time(struct radeon_device *rdev, u32 reset_time);
+void r600_engine_clock_entry_enable(struct radeon_device *rdev,
+ u32 index, bool enable);
+void r600_engine_clock_entry_enable_pulse_skipping(struct radeon_device *rdev,
+ u32 index, bool enable);
+void r600_engine_clock_entry_enable_post_divider(struct radeon_device *rdev,
+ u32 index, bool enable);
+void r600_engine_clock_entry_set_post_divider(struct radeon_device *rdev,
+ u32 index, u32 divider);
+void r600_engine_clock_entry_set_reference_divider(struct radeon_device *rdev,
+ u32 index, u32 divider);
+void r600_engine_clock_entry_set_feedback_divider(struct radeon_device *rdev,
+ u32 index, u32 divider);
+void r600_engine_clock_entry_set_step_time(struct radeon_device *rdev,
+ u32 index, u32 step_time);
+void r600_vid_rt_set_ssu(struct radeon_device *rdev, u32 u);
+void r600_vid_rt_set_vru(struct radeon_device *rdev, u32 u);
+void r600_vid_rt_set_vrt(struct radeon_device *rdev, u32 rt);
+void r600_voltage_control_enable_pins(struct radeon_device *rdev,
+ u64 mask);
+void r600_voltage_control_program_voltages(struct radeon_device *rdev,
+ enum r600_power_level index, u64 pins);
+void r600_voltage_control_deactivate_static_control(struct radeon_device *rdev,
+ u64 mask);
+void r600_power_level_enable(struct radeon_device *rdev,
+ enum r600_power_level index, bool enable);
+void r600_power_level_set_voltage_index(struct radeon_device *rdev,
+ enum r600_power_level index, u32 voltage_index);
+void r600_power_level_set_mem_clock_index(struct radeon_device *rdev,
+ enum r600_power_level index, u32 mem_clock_index);
+void r600_power_level_set_eng_clock_index(struct radeon_device *rdev,
+ enum r600_power_level index, u32 eng_clock_index);
+void r600_power_level_set_watermark_id(struct radeon_device *rdev,
+ enum r600_power_level index,
+ enum r600_display_watermark watermark_id);
+void r600_power_level_set_pcie_gen2(struct radeon_device *rdev,
+ enum r600_power_level index, bool compatible);
+enum r600_power_level r600_power_level_get_current_index(struct radeon_device *rdev);
+enum r600_power_level r600_power_level_get_target_index(struct radeon_device *rdev);
+void r600_power_level_set_enter_index(struct radeon_device *rdev,
+ enum r600_power_level index);
+void r600_wait_for_power_level_unequal(struct radeon_device *rdev,
+ enum r600_power_level index);
+void r600_wait_for_power_level(struct radeon_device *rdev,
+ enum r600_power_level index);
+void r600_start_dpm(struct radeon_device *rdev);
+void r600_stop_dpm(struct radeon_device *rdev);
+
+int r600_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp);
+bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
+
+int r600_parse_extended_power_table(struct radeon_device *rdev);
+void r600_free_extended_power_table(struct radeon_device *rdev);
+
+enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev,
+ u32 sys_mask,
+ enum radeon_pcie_gen asic_gen,
+ enum radeon_pcie_gen default_gen);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 456750a0daa5..e73b2a73494a 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -133,14 +133,7 @@ static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset = dig->afmt->offset;
uint8_t *frame = buffer + 3;
-
- /* Our header values (type, version, length) should be alright, Intel
- * is using the same. Checksum function also seems to be OK, it works
- * fine for audio infoframe. However calculated value is always lower
- * by 2 in comparison to fglrx. It breaks displaying anything in case
- * of TVs that strictly check the checksum. Hack it manually here to
- * workaround this issue. */
- frame[0x0] += 2;
+ uint8_t *header = buffer;
WREG32(HDMI0_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -149,7 +142,7 @@ static void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
WREG32(HDMI0_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(HDMI0_AVI_INFO3 + offset,
- frame[0xC] | (frame[0xD] << 8));
+ frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
}
/*
diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h
index 909219b1bf80..3ef202629e7e 100644
--- a/drivers/gpu/drm/radeon/r600_reg.h
+++ b/drivers/gpu/drm/radeon/r600_reg.h
@@ -31,6 +31,12 @@
#define R600_PCIE_PORT_INDEX 0x0038
#define R600_PCIE_PORT_DATA 0x003c
+#define R600_RCU_INDEX 0x0100
+#define R600_RCU_DATA 0x0104
+
+#define R600_UVD_CTX_INDEX 0xf4a0
+#define R600_UVD_CTX_DATA 0xf4a4
+
#define R600_MC_VM_FB_LOCATION 0x2180
#define R600_MC_FB_BASE_MASK 0x0000FFFF
#define R600_MC_FB_BASE_SHIFT 0
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 79df558f8c40..f1b3084d8f51 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -302,10 +302,25 @@
#define GRBM_SOFT_RESET 0x8020
#define SOFT_RESET_CP (1<<0)
+#define CG_THERMAL_CTRL 0x7F0
+#define DIG_THERM_DPM(x) ((x) << 12)
+#define DIG_THERM_DPM_MASK 0x000FF000
+#define DIG_THERM_DPM_SHIFT 12
#define CG_THERMAL_STATUS 0x7F4
#define ASIC_T(x) ((x) << 0)
#define ASIC_T_MASK 0x1FF
#define ASIC_T_SHIFT 0
+#define CG_THERMAL_INT 0x7F8
+#define DIG_THERM_INTH(x) ((x) << 8)
+#define DIG_THERM_INTH_MASK 0x0000FF00
+#define DIG_THERM_INTH_SHIFT 8
+#define DIG_THERM_INTL(x) ((x) << 16)
+#define DIG_THERM_INTL_MASK 0x00FF0000
+#define DIG_THERM_INTL_SHIFT 16
+#define THERM_INT_MASK_HIGH (1 << 24)
+#define THERM_INT_MASK_LOW (1 << 25)
+
+#define RV770_CG_THERMAL_INT 0x734
#define HDP_HOST_PATH_CNTL 0x2C00
#define HDP_NONSURFACE_BASE 0x2C04
@@ -684,10 +699,6 @@
#define RLC_UCODE_ADDR 0x3f2c
#define RLC_UCODE_DATA 0x3f30
-/* new for TN */
-#define TN_RLC_SAVE_AND_RESTORE_BASE 0x3f10
-#define TN_RLC_CLEAR_STATE_RESTORE_BASE 0x3f20
-
#define SRBM_SOFT_RESET 0xe60
# define SOFT_RESET_DMA (1 << 12)
# define SOFT_RESET_RLC (1 << 13)
@@ -1148,6 +1159,219 @@
# define AFMT_AZ_FORMAT_WTRIG_ACK (1 << 29)
# define AFMT_AZ_AUDIO_ENABLE_CHG_ACK (1 << 30)
+/* Power management */
+#define CG_SPLL_FUNC_CNTL 0x600
+# define SPLL_RESET (1 << 0)
+# define SPLL_SLEEP (1 << 1)
+# define SPLL_REF_DIV(x) ((x) << 2)
+# define SPLL_REF_DIV_MASK (7 << 2)
+# define SPLL_FB_DIV(x) ((x) << 5)
+# define SPLL_FB_DIV_MASK (0xff << 5)
+# define SPLL_PULSEEN (1 << 13)
+# define SPLL_PULSENUM(x) ((x) << 14)
+# define SPLL_PULSENUM_MASK (3 << 14)
+# define SPLL_SW_HILEN(x) ((x) << 16)
+# define SPLL_SW_HILEN_MASK (0xf << 16)
+# define SPLL_SW_LOLEN(x) ((x) << 20)
+# define SPLL_SW_LOLEN_MASK (0xf << 20)
+# define SPLL_DIVEN (1 << 24)
+# define SPLL_BYPASS_EN (1 << 25)
+# define SPLL_CHG_STATUS (1 << 29)
+# define SPLL_CTLREQ (1 << 30)
+# define SPLL_CTLACK (1 << 31)
+
+#define GENERAL_PWRMGT 0x618
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define MOBILE_SU (1 << 2)
+# define THERMAL_PROTECTION_DIS (1 << 3)
+# define THERMAL_PROTECTION_TYPE (1 << 4)
+# define ENABLE_GEN2PCIE (1 << 5)
+# define SW_GPIO_INDEX(x) ((x) << 6)
+# define SW_GPIO_INDEX_MASK (3 << 6)
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+#define CG_TPC 0x61c
+# define TPCC(x) ((x) << 0)
+# define TPCC_MASK (0x7fffff << 0)
+# define TPU(x) ((x) << 23)
+# define TPU_MASK (0x1f << 23)
+#define SCLK_PWRMGT_CNTL 0x620
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_TURNOFF (1 << 1)
+# define SPLL_TURNOFF (1 << 2)
+# define SU_SCLK_USE_BCLK (1 << 3)
+# define DYNAMIC_GFX_ISLAND_PWR_DOWN (1 << 4)
+# define DYNAMIC_GFX_ISLAND_PWR_LP (1 << 5)
+# define CLK_TURN_ON_STAGGER (1 << 6)
+# define CLK_TURN_OFF_STAGGER (1 << 7)
+# define FIR_FORCE_TREND_SEL (1 << 8)
+# define FIR_TREND_MODE (1 << 9)
+# define DYN_GFX_CLK_OFF_EN (1 << 10)
+# define VDDC3D_TURNOFF_D1 (1 << 11)
+# define VDDC3D_TURNOFF_D2 (1 << 12)
+# define VDDC3D_TURNOFF_D3 (1 << 13)
+# define SPLL_TURNOFF_D2 (1 << 14)
+# define SCLK_LOW_D1 (1 << 15)
+# define DYN_GFX_CLK_OFF_MC_EN (1 << 16)
+#define MCLK_PWRMGT_CNTL 0x624
+# define MPLL_PWRMGT_OFF (1 << 0)
+# define YCLK_TURNOFF (1 << 1)
+# define MPLL_TURNOFF (1 << 2)
+# define SU_MCLK_USE_BCLK (1 << 3)
+# define DLL_READY (1 << 4)
+# define MC_BUSY (1 << 5)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA_SLEEP (1 << 8)
+# define MRDCKB_SLEEP (1 << 9)
+# define MRDCKC_SLEEP (1 << 10)
+# define MRDCKD_SLEEP (1 << 11)
+# define MRDCKE_SLEEP (1 << 12)
+# define MRDCKF_SLEEP (1 << 13)
+# define MRDCKG_SLEEP (1 << 14)
+# define MRDCKH_SLEEP (1 << 15)
+# define MRDCKA_RESET (1 << 16)
+# define MRDCKB_RESET (1 << 17)
+# define MRDCKC_RESET (1 << 18)
+# define MRDCKD_RESET (1 << 19)
+# define MRDCKE_RESET (1 << 20)
+# define MRDCKF_RESET (1 << 21)
+# define MRDCKG_RESET (1 << 22)
+# define MRDCKH_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define USE_DISPLAY_GAP_CTXSW (1 << 27)
+# define MPLL_TURNOFF_D2 (1 << 28)
+# define USE_DISPLAY_URGENT_CTXSW (1 << 29)
+
+#define MPLL_TIME 0x634
+# define MPLL_LOCK_TIME(x) ((x) << 0)
+# define MPLL_LOCK_TIME_MASK (0xffff << 0)
+# define MPLL_RESET_TIME(x) ((x) << 16)
+# define MPLL_RESET_TIME_MASK (0xffff << 16)
+
+#define SCLK_FREQ_SETTING_STEP_0_PART1 0x648
+# define STEP_0_SPLL_POST_DIV(x) ((x) << 0)
+# define STEP_0_SPLL_POST_DIV_MASK (0xff << 0)
+# define STEP_0_SPLL_FB_DIV(x) ((x) << 8)
+# define STEP_0_SPLL_FB_DIV_MASK (0xff << 8)
+# define STEP_0_SPLL_REF_DIV(x) ((x) << 16)
+# define STEP_0_SPLL_REF_DIV_MASK (7 << 16)
+# define STEP_0_SPLL_STEP_TIME(x) ((x) << 19)
+# define STEP_0_SPLL_STEP_TIME_MASK (0x1fff << 19)
+#define SCLK_FREQ_SETTING_STEP_0_PART2 0x64c
+# define STEP_0_PULSE_HIGH_CNT(x) ((x) << 0)
+# define STEP_0_PULSE_HIGH_CNT_MASK (0x1ff << 0)
+# define STEP_0_POST_DIV_EN (1 << 9)
+# define STEP_0_SPLL_STEP_ENABLE (1 << 30)
+# define STEP_0_SPLL_ENTRY_VALID (1 << 31)
+
+#define VID_RT 0x6f8
+# define VID_CRT(x) ((x) << 0)
+# define VID_CRT_MASK (0x1fff << 0)
+# define VID_CRTU(x) ((x) << 13)
+# define VID_CRTU_MASK (7 << 13)
+# define SSTU(x) ((x) << 16)
+# define SSTU_MASK (7 << 16)
+#define CTXSW_PROFILE_INDEX 0x6fc
+# define CTXSW_FREQ_VIDS_CFG_INDEX(x) ((x) << 0)
+# define CTXSW_FREQ_VIDS_CFG_INDEX_MASK (3 << 0)
+# define CTXSW_FREQ_VIDS_CFG_INDEX_SHIFT 0
+# define CTXSW_FREQ_MCLK_CFG_INDEX(x) ((x) << 2)
+# define CTXSW_FREQ_MCLK_CFG_INDEX_MASK (3 << 2)
+# define CTXSW_FREQ_MCLK_CFG_INDEX_SHIFT 2
+# define CTXSW_FREQ_SCLK_CFG_INDEX(x) ((x) << 4)
+# define CTXSW_FREQ_SCLK_CFG_INDEX_MASK (0x1f << 4)
+# define CTXSW_FREQ_SCLK_CFG_INDEX_SHIFT 4
+# define CTXSW_FREQ_STATE_SPLL_RESET_EN (1 << 9)
+# define CTXSW_FREQ_STATE_ENABLE (1 << 10)
+# define CTXSW_FREQ_DISPLAY_WATERMARK (1 << 11)
+# define CTXSW_FREQ_GEN2PCIE_VOLT (1 << 12)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x70c
+# define TARGET_PROFILE_INDEX_MASK (3 << 0)
+# define TARGET_PROFILE_INDEX_SHIFT 0
+# define CURRENT_PROFILE_INDEX_MASK (3 << 2)
+# define CURRENT_PROFILE_INDEX_SHIFT 2
+# define DYN_PWR_ENTER_INDEX(x) ((x) << 4)
+# define DYN_PWR_ENTER_INDEX_MASK (3 << 4)
+# define DYN_PWR_ENTER_INDEX_SHIFT 4
+# define CURR_MCLK_INDEX_MASK (3 << 6)
+# define CURR_MCLK_INDEX_SHIFT 6
+# define CURR_SCLK_INDEX_MASK (0x1f << 8)
+# define CURR_SCLK_INDEX_SHIFT 8
+# define CURR_VID_INDEX_MASK (3 << 13)
+# define CURR_VID_INDEX_SHIFT 13
+
+#define LOWER_GPIO_ENABLE 0x710
+#define UPPER_GPIO_ENABLE 0x714
+#define CTXSW_VID_LOWER_GPIO_CNTL 0x718
+
+#define VID_UPPER_GPIO_CNTL 0x740
+#define CG_CTX_CGTT3D_R 0x744
+# define PHC(x) ((x) << 0)
+# define PHC_MASK (0x1ff << 0)
+# define SDC(x) ((x) << 9)
+# define SDC_MASK (0x3fff << 9)
+#define CG_VDDC3D_OOR 0x748
+# define SU(x) ((x) << 23)
+# define SU_MASK (0xf << 23)
+#define CG_FTV 0x74c
+#define CG_FFCT_0 0x750
+# define UTC_0(x) ((x) << 0)
+# define UTC_0_MASK (0x3ff << 0)
+# define DTC_0(x) ((x) << 10)
+# define DTC_0_MASK (0x3ff << 10)
+
+#define CG_BSP 0x78c
+# define BSP(x) ((x) << 0)
+# define BSP_MASK (0xffff << 0)
+# define BSU(x) ((x) << 16)
+# define BSU_MASK (0xf << 16)
+#define CG_RT 0x790
+# define FLS(x) ((x) << 0)
+# define FLS_MASK (0xffff << 0)
+# define FMS(x) ((x) << 16)
+# define FMS_MASK (0xffff << 16)
+#define CG_LT 0x794
+# define FHS(x) ((x) << 0)
+# define FHS_MASK (0xffff << 0)
+#define CG_GIT 0x798
+# define CG_GICST(x) ((x) << 0)
+# define CG_GICST_MASK (0xffff << 0)
+# define CG_GIPOT(x) ((x) << 16)
+# define CG_GIPOT_MASK (0xffff << 16)
+
+#define CG_SSP 0x7a8
+# define CG_SST(x) ((x) << 0)
+# define CG_SST_MASK (0xffff << 0)
+# define CG_SSTU(x) ((x) << 16)
+# define CG_SSTU_MASK (0xf << 16)
+
+#define CG_RLC_REQ_AND_RSP 0x7c4
+# define RLC_CG_REQ_TYPE_MASK 0xf
+# define RLC_CG_REQ_TYPE_SHIFT 0
+# define CG_RLC_RSP_TYPE_MASK 0xf0
+# define CG_RLC_RSP_TYPE_SHIFT 4
+
+#define CG_FC_T 0x7cc
+# define FC_T(x) ((x) << 0)
+# define FC_T_MASK (0xffff << 0)
+# define FC_TU(x) ((x) << 16)
+# define FC_TU_MASK (0x1f << 16)
+
+#define GPIOPAD_MASK 0x1798
+#define GPIOPAD_A 0x179c
+#define GPIOPAD_EN 0x17a0
+
+#define GRBM_PWR_CNTL 0x800c
+# define REQ_TYPE_MASK 0xf
+# define REQ_TYPE_SHIFT 0
+# define RSP_TYPE_MASK 0xf0
+# define RSP_TYPE_SHIFT 4
+
/*
* UVD
*/
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 142ce6cc69f5..9b7025d02cd0 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -96,6 +96,7 @@ extern int radeon_pcie_gen2;
extern int radeon_msi;
extern int radeon_lockup_timeout;
extern int radeon_fastfb;
+extern int radeon_dpm;
/*
* Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -150,6 +151,13 @@ extern int radeon_fastfb;
#define RADEON_RESET_MC (1 << 10)
#define RADEON_RESET_DISPLAY (1 << 11)
+/* max cursor sizes (in pixels) */
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+
+#define CIK_CURSOR_WIDTH 128
+#define CIK_CURSOR_HEIGHT 128
+
/*
* Errata workarounds.
*/
@@ -192,6 +200,7 @@ struct radeon_clock {
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;
};
@@ -211,13 +220,51 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
u32 clock,
bool strobe_mode,
struct atom_clock_dividers *dividers);
+int radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev,
+ u32 clock,
+ bool strobe_mode,
+ struct atom_mpll_param *mpll_param);
void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 voltage_type);
+int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
+ u16 voltage_level, u8 voltage_type,
+ u32 *gpio_value, u32 *gpio_mask);
+void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
+ u32 eng_clock, u32 mem_clock);
+int radeon_atom_get_voltage_step(struct radeon_device *rdev,
+ u8 voltage_type, u16 *voltage_step);
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+ u16 voltage_id, u16 *voltage);
+int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev,
+ u16 *voltage,
+ u16 leakage_idx);
+int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
+ u8 voltage_type,
+ u16 nominal_voltage,
+ u16 *true_voltage);
+int radeon_atom_get_min_voltage(struct radeon_device *rdev,
+ u8 voltage_type, u16 *min_voltage);
+int radeon_atom_get_max_voltage(struct radeon_device *rdev,
+ u8 voltage_type, u16 *max_voltage);
+int radeon_atom_get_voltage_table(struct radeon_device *rdev,
+ u8 voltage_type, u8 voltage_mode,
+ struct atom_voltage_table *voltage_table);
+bool radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
+ u8 voltage_type, u8 voltage_mode);
+void radeon_atom_update_memory_dll(struct radeon_device *rdev,
+ u32 mem_clock);
+void radeon_atom_set_ac_timing(struct radeon_device *rdev,
+ u32 mem_clock);
+int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
+ u8 module_index,
+ struct atom_mc_reg_table *reg_table);
+int radeon_atom_get_memory_info(struct radeon_device *rdev,
+ u8 module_index, struct atom_memory_info *mem_info);
+int radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
+ bool gddr5, u8 module_index,
+ struct atom_memory_clock_range_table *mclk_range_table);
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+ u16 voltage_id, u16 *voltage);
void rs690_pm_info(struct radeon_device *rdev);
-extern int rv6xx_get_temp(struct radeon_device *rdev);
-extern int rv770_get_temp(struct radeon_device *rdev);
-extern int evergreen_get_temp(struct radeon_device *rdev);
-extern int sumo_get_temp(struct radeon_device *rdev);
-extern int si_get_temp(struct radeon_device *rdev);
extern void evergreen_tiling_fields(unsigned tiling_flags, unsigned *bankw,
unsigned *bankh, unsigned *mtaspect,
unsigned *tile_split);
@@ -549,6 +596,20 @@ struct radeon_scratch {
int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
+/*
+ * GPU doorbell structures, functions & helpers
+ */
+struct radeon_doorbell {
+ u32 num_pages;
+ bool free[1024];
+ /* doorbell mmio */
+ resource_size_t base;
+ resource_size_t size;
+ void __iomem *ptr;
+};
+
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
/*
* IRQS.
@@ -600,10 +661,21 @@ struct evergreen_irq_stat_regs {
u32 afmt_status6;
};
+struct cik_irq_stat_regs {
+ u32 disp_int;
+ u32 disp_int_cont;
+ u32 disp_int_cont2;
+ u32 disp_int_cont3;
+ u32 disp_int_cont4;
+ u32 disp_int_cont5;
+ u32 disp_int_cont6;
+};
+
union radeon_irq_stat_regs {
struct r500_irq_stat_regs r500;
struct r600_irq_stat_regs r600;
struct evergreen_irq_stat_regs evergreen;
+ struct cik_irq_stat_regs cik;
};
#define RADEON_MAX_HPD_PINS 6
@@ -620,6 +692,7 @@ struct radeon_irq {
bool hpd[RADEON_MAX_HPD_PINS];
bool afmt[RADEON_MAX_AFMT_BLOCKS];
union radeon_irq_stat_regs stat_regs;
+ bool dpm_thermal;
};
int radeon_irq_kms_init(struct radeon_device *rdev);
@@ -677,6 +750,22 @@ struct radeon_ring {
u32 idx;
u64 last_semaphore_signal_addr;
u64 last_semaphore_wait_addr;
+ /* for CIK queues */
+ u32 me;
+ u32 pipe;
+ u32 queue;
+ struct radeon_bo *mqd_obj;
+ u32 doorbell_page_num;
+ u32 doorbell_offset;
+ unsigned wptr_offs;
+};
+
+struct radeon_mec {
+ struct radeon_bo *hpd_eop_obj;
+ u64 hpd_eop_gpu_addr;
+ u32 num_pipe;
+ u32 num_mec;
+ u32 num_queue;
};
/*
@@ -778,15 +867,22 @@ struct r600_blit {
};
/*
- * SI RLC stuff
+ * RLC stuff
*/
-struct si_rlc {
+#include "clearstate_defs.h"
+
+struct radeon_rlc {
/* for power gating */
struct radeon_bo *save_restore_obj;
uint64_t save_restore_gpu_addr;
+ volatile uint32_t *sr_ptr;
+ u32 *reg_list;
+ u32 reg_list_size;
/* for clear state */
struct radeon_bo *clear_state_obj;
uint64_t clear_state_gpu_addr;
+ volatile uint32_t *cs_ptr;
+ struct cs_section_def *cs_data;
};
int radeon_ib_get(struct radeon_device *rdev, int ring,
@@ -883,6 +979,7 @@ struct radeon_cs_parser {
u32 cs_flags;
u32 ring;
s32 priority;
+ struct ww_acquire_ctx ticket;
};
extern int radeon_cs_finish_pages(struct radeon_cs_parser *p);
@@ -934,6 +1031,8 @@ struct radeon_wb {
#define CAYMAN_WB_DMA1_RPTR_OFFSET 2304
#define R600_WB_UVD_RPTR_OFFSET 2560
#define R600_WB_EVENT_OFFSET 3072
+#define CIK_WB_CP1_WPTR_OFFSET 3328
+#define CIK_WB_CP2_WPTR_OFFSET 3584
/**
* struct radeon_pm - power management datas
@@ -958,6 +1057,7 @@ struct radeon_wb {
enum radeon_pm_method {
PM_METHOD_PROFILE,
PM_METHOD_DYNPM,
+ PM_METHOD_DPM,
};
enum radeon_dynpm_state {
@@ -983,11 +1083,24 @@ enum radeon_voltage_type {
};
enum radeon_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 radeon_pm_profile_type {
@@ -1016,12 +1129,17 @@ struct radeon_pm_profile {
enum radeon_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,
};
struct radeon_voltage {
@@ -1075,6 +1193,201 @@ struct radeon_power_state {
*/
#define RADEON_MODE_OVERCLOCK_MARGIN 500 /* 5 MHz */
+enum radeon_dpm_auto_throttle_src {
+ RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL,
+ RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL
+};
+
+enum radeon_dpm_event_src {
+ RADEON_DPM_EVENT_SRC_ANALOG = 0,
+ RADEON_DPM_EVENT_SRC_EXTERNAL = 1,
+ RADEON_DPM_EVENT_SRC_DIGITAL = 2,
+ RADEON_DPM_EVENT_SRC_ANALOG_OR_EXTERNAL = 3,
+ RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL = 4
+};
+
+struct radeon_ps {
+ u32 caps; /* vbios flags */
+ u32 class; /* vbios flags */
+ u32 class2; /* vbios flags */
+ /* UVD clocks */
+ u32 vclk;
+ u32 dclk;
+ /* asic priv */
+ void *ps_priv;
+};
+
+struct radeon_dpm_thermal {
+ /* thermal interrupt work */
+ struct work_struct work;
+ /* low temperature threshold */
+ int min_temp;
+ /* high temperature threshold */
+ int max_temp;
+ /* was interrupt low to high or high to low */
+ bool high_to_low;
+};
+
+enum radeon_clk_action
+{
+ RADEON_SCLK_UP = 1,
+ RADEON_SCLK_DOWN
+};
+
+struct radeon_blacklist_clocks
+{
+ u32 sclk;
+ u32 mclk;
+ enum radeon_clk_action action;
+};
+
+struct radeon_clock_and_voltage_limits {
+ u32 sclk;
+ u32 mclk;
+ u32 vddc;
+ u32 vddci;
+};
+
+struct radeon_clock_array {
+ u32 count;
+ u32 *values;
+};
+
+struct radeon_clock_voltage_dependency_entry {
+ u32 clk;
+ u16 v;
+};
+
+struct radeon_clock_voltage_dependency_table {
+ u32 count;
+ struct radeon_clock_voltage_dependency_entry *entries;
+};
+
+struct radeon_cac_leakage_entry {
+ u16 vddc;
+ u32 leakage;
+};
+
+struct radeon_cac_leakage_table {
+ u32 count;
+ struct radeon_cac_leakage_entry *entries;
+};
+
+struct radeon_phase_shedding_limits_entry {
+ u16 voltage;
+ u32 sclk;
+ u32 mclk;
+};
+
+struct radeon_phase_shedding_limits_table {
+ u32 count;
+ struct radeon_phase_shedding_limits_entry *entries;
+};
+
+struct radeon_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 radeon_dpm_dynamic_state {
+ struct radeon_clock_voltage_dependency_table vddc_dependency_on_sclk;
+ struct radeon_clock_voltage_dependency_table vddci_dependency_on_mclk;
+ struct radeon_clock_voltage_dependency_table vddc_dependency_on_mclk;
+ struct radeon_clock_voltage_dependency_table vddc_dependency_on_dispclk;
+ struct radeon_clock_array valid_sclk_values;
+ struct radeon_clock_array valid_mclk_values;
+ struct radeon_clock_and_voltage_limits max_clock_voltage_on_dc;
+ struct radeon_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 radeon_cac_leakage_table cac_leakage_table;
+ struct radeon_phase_shedding_limits_table phase_shedding_limits_table;
+ struct radeon_ppm_table *ppm_table;
+};
+
+struct radeon_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;
+ bool ucode_fan_control;
+};
+
+enum radeon_pcie_gen {
+ RADEON_PCIE_GEN1 = 0,
+ RADEON_PCIE_GEN2 = 1,
+ RADEON_PCIE_GEN3 = 2,
+ RADEON_PCIE_GEN_INVALID = 0xffff
+};
+
+enum radeon_dpm_forced_level {
+ RADEON_DPM_FORCED_LEVEL_AUTO = 0,
+ RADEON_DPM_FORCED_LEVEL_LOW = 1,
+ RADEON_DPM_FORCED_LEVEL_HIGH = 2,
+};
+
+struct radeon_dpm {
+ struct radeon_ps *ps;
+ /* number of valid power states */
+ int num_ps;
+ /* current power state that is active */
+ struct radeon_ps *current_ps;
+ /* requested power state */
+ struct radeon_ps *requested_ps;
+ /* boot up power state */
+ struct radeon_ps *boot_ps;
+ /* default uvd power state */
+ struct radeon_ps *uvd_ps;
+ enum radeon_pm_state_type state;
+ enum radeon_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 radeon_dpm_dynamic_state dyn_state;
+ struct radeon_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;
+ /* thermal handling */
+ struct radeon_dpm_thermal thermal;
+ /* forced levels */
+ enum radeon_dpm_forced_level forced_level;
+};
+
+void radeon_dpm_enable_power_state(struct radeon_device *rdev,
+ enum radeon_pm_state_type dpm_state);
+
+
struct radeon_pm {
struct mutex mutex;
/* write locked while reprogramming mclk */
@@ -1128,6 +1441,9 @@ struct radeon_pm {
/* internal thermal controller on rv6xx+ */
enum radeon_int_thermal_type int_thermal_type;
struct device *int_hwmon_dev;
+ /* dpm */
+ bool dpm_enabled;
+ struct radeon_dpm dpm;
};
int radeon_pm_get_type_index(struct radeon_device *rdev,
@@ -1266,6 +1582,10 @@ struct radeon_asic {
int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp);
bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);
void (*vm_flush)(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+
+ u32 (*get_rptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+ u32 (*get_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
+ void (*set_wptr)(struct radeon_device *rdev, struct radeon_ring *ring);
} ring[RADEON_NUM_RINGS];
/* irqs */
struct {
@@ -1325,7 +1645,7 @@ struct radeon_asic {
bool (*sense)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
void (*set_polarity)(struct radeon_device *rdev, enum radeon_hpd_id hpd);
} hpd;
- /* power management */
+ /* static power management */
struct {
void (*misc)(struct radeon_device *rdev);
void (*prepare)(struct radeon_device *rdev);
@@ -1340,7 +1660,26 @@ struct radeon_asic {
void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
void (*set_clock_gating)(struct radeon_device *rdev, int enable);
int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk);
+ int (*get_temperature)(struct radeon_device *rdev);
} pm;
+ /* dynamic power management */
+ struct {
+ int (*init)(struct radeon_device *rdev);
+ void (*setup_asic)(struct radeon_device *rdev);
+ int (*enable)(struct radeon_device *rdev);
+ void (*disable)(struct radeon_device *rdev);
+ int (*pre_set_power_state)(struct radeon_device *rdev);
+ int (*set_power_state)(struct radeon_device *rdev);
+ void (*post_set_power_state)(struct radeon_device *rdev);
+ void (*display_configuration_changed)(struct radeon_device *rdev);
+ void (*fini)(struct radeon_device *rdev);
+ u32 (*get_sclk)(struct radeon_device *rdev, bool low);
+ u32 (*get_mclk)(struct radeon_device *rdev, bool low);
+ void (*print_power_state)(struct radeon_device *rdev, struct radeon_ps *ps);
+ void (*debugfs_print_current_performance_level)(struct radeon_device *rdev, struct seq_file *m);
+ int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level);
+ bool (*vblank_too_short)(struct radeon_device *rdev);
+ } dpm;
/* pageflipping */
struct {
void (*pre_page_flip)(struct radeon_device *rdev, int crtc);
@@ -1505,6 +1844,36 @@ struct si_asic {
uint32_t tile_mode_array[32];
};
+struct cik_asic {
+ 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 num_backends_per_se;
+ unsigned backend_disable_mask_per_asic;
+ unsigned backend_map;
+ unsigned num_texture_channel_caches;
+ 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 tile_config;
+ uint32_t tile_mode_array[32];
+};
+
union radeon_asic_config {
struct r300_asic r300;
struct r100_asic r100;
@@ -1513,6 +1882,7 @@ union radeon_asic_config {
struct evergreen_asic evergreen;
struct cayman_asic cayman;
struct si_asic si;
+ struct cik_asic cik;
};
/*
@@ -1657,6 +2027,7 @@ struct radeon_device {
struct radeon_gart gart;
struct radeon_mode_info mode_info;
struct radeon_scratch scratch;
+ struct radeon_doorbell doorbell;
struct radeon_mman mman;
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS];
wait_queue_head_t fence_queue;
@@ -1684,13 +2055,18 @@ struct radeon_device {
const struct firmware *mc_fw; /* NI MC firmware */
const struct firmware *ce_fw; /* SI CE firmware */
const struct firmware *uvd_fw; /* UVD firmware */
+ const struct firmware *mec_fw; /* CIK MEC firmware */
+ const struct firmware *sdma_fw; /* CIK SDMA firmware */
+ const struct firmware *smc_fw; /* SMC firmware */
struct r600_blit r600_blit;
struct r600_vram_scratch vram_scratch;
int msi_enabled; /* msi enabled */
struct r600_ih ih; /* r6/700 interrupt ring */
- struct si_rlc rlc;
+ struct radeon_rlc rlc;
+ struct radeon_mec mec;
struct work_struct hotplug_work;
struct work_struct audio_work;
+ struct work_struct reset_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
bool audio_enabled;
@@ -1727,6 +2103,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
+
/*
* Cast helper
*/
@@ -1754,6 +2133,18 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
#define WREG32_PCIE(reg, v) rv370_pcie_wreg(rdev, (reg), (v))
#define RREG32_PCIE_PORT(reg) rdev->pciep_rreg(rdev, (reg))
#define WREG32_PCIE_PORT(reg, v) rdev->pciep_wreg(rdev, (reg), (v))
+#define RREG32_SMC(reg) tn_smc_rreg(rdev, (reg))
+#define WREG32_SMC(reg, v) tn_smc_wreg(rdev, (reg), (v))
+#define RREG32_RCU(reg) r600_rcu_rreg(rdev, (reg))
+#define WREG32_RCU(reg, v) r600_rcu_wreg(rdev, (reg), (v))
+#define RREG32_CG(reg) eg_cg_rreg(rdev, (reg))
+#define WREG32_CG(reg, v) eg_cg_wreg(rdev, (reg), (v))
+#define RREG32_PIF_PHY0(reg) eg_pif_phy0_rreg(rdev, (reg))
+#define WREG32_PIF_PHY0(reg, v) eg_pif_phy0_wreg(rdev, (reg), (v))
+#define RREG32_PIF_PHY1(reg) eg_pif_phy1_rreg(rdev, (reg))
+#define WREG32_PIF_PHY1(reg, v) eg_pif_phy1_wreg(rdev, (reg), (v))
+#define RREG32_UVD_CTX(reg) r600_uvd_ctx_rreg(rdev, (reg))
+#define WREG32_UVD_CTX(reg, v) r600_uvd_ctx_wreg(rdev, (reg), (v))
#define WREG32_P(reg, val, mask) \
do { \
uint32_t tmp_ = RREG32(reg); \
@@ -1774,6 +2165,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
#define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
#define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
+#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
+#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
+
/*
* Indirect registers accessor
*/
@@ -1792,6 +2186,96 @@ static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uin
WREG32(RADEON_PCIE_DATA, (v));
}
+static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(TN_SMC_IND_INDEX_0, (reg));
+ r = RREG32(TN_SMC_IND_DATA_0);
+ return r;
+}
+
+static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(TN_SMC_IND_INDEX_0, (reg));
+ WREG32(TN_SMC_IND_DATA_0, (v));
+}
+
+static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
+ r = RREG32(R600_RCU_DATA);
+ return r;
+}
+
+static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
+ WREG32(R600_RCU_DATA, (v));
+}
+
+static inline u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
+ r = RREG32(EVERGREEN_CG_IND_DATA);
+ return r;
+}
+
+static inline void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
+ WREG32(EVERGREEN_CG_IND_DATA, (v));
+}
+
+static inline u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
+ r = RREG32(EVERGREEN_PIF_PHY0_DATA);
+ return r;
+}
+
+static inline void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
+ WREG32(EVERGREEN_PIF_PHY0_DATA, (v));
+}
+
+static inline u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
+ r = RREG32(EVERGREEN_PIF_PHY1_DATA);
+ return r;
+}
+
+static inline void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
+ WREG32(EVERGREEN_PIF_PHY1_DATA, (v));
+}
+
+static inline u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg)
+{
+ u32 r;
+
+ WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff));
+ r = RREG32(R600_UVD_CTX_DATA);
+ return r;
+}
+
+static inline void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v)
+{
+ WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff));
+ WREG32(R600_UVD_CTX_DATA, (v));
+}
+
void r100_pll_errata_after_index(struct radeon_device *rdev);
@@ -1840,6 +2324,16 @@ void r100_pll_errata_after_index(struct radeon_device *rdev);
(rdev->flags & RADEON_IS_IGP))
#define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND))
#define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN))
+#define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE))
+
+#define ASIC_IS_LOMBOK(rdev) ((rdev->ddev->pdev->device == 0x6849) || \
+ (rdev->ddev->pdev->device == 0x6850) || \
+ (rdev->ddev->pdev->device == 0x6858) || \
+ (rdev->ddev->pdev->device == 0x6859) || \
+ (rdev->ddev->pdev->device == 0x6840) || \
+ (rdev->ddev->pdev->device == 0x6841) || \
+ (rdev->ddev->pdev->device == 0x6842) || \
+ (rdev->ddev->pdev->device == 0x6843))
/*
* BIOS helpers.
@@ -1892,6 +2386,9 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib))
#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp))
#define radeon_ring_vm_flush(rdev, r, vm) (rdev)->asic->ring[(r)].vm_flush((rdev), (r), (vm))
+#define radeon_ring_get_rptr(rdev, r) (rdev)->asic->ring[(r)->idx].get_rptr((rdev), (r))
+#define radeon_ring_get_wptr(rdev, r) (rdev)->asic->ring[(r)->idx].get_wptr((rdev), (r))
+#define radeon_ring_set_wptr(rdev, r) (rdev)->asic->ring[(r)->idx].set_wptr((rdev), (r))
#define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev))
#define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev))
#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc))
@@ -1915,6 +2412,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))
#define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))
#define radeon_set_uvd_clocks(rdev, v, d) (rdev)->asic->pm.set_uvd_clocks((rdev), (v), (d))
+#define radeon_get_temperature(rdev) (rdev)->asic->pm.get_temperature((rdev))
#define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))
#define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r)))
#define radeon_bandwidth_update(rdev) (rdev)->asic->display.bandwidth_update((rdev))
@@ -1935,6 +2433,21 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
#define radeon_get_xclk(rdev) (rdev)->asic->get_xclk((rdev))
#define radeon_get_gpu_clock_counter(rdev) (rdev)->asic->get_gpu_clock_counter((rdev))
+#define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
+#define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
+#define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
+#define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev))
+#define radeon_dpm_pre_set_power_state(rdev) rdev->asic->dpm.pre_set_power_state((rdev))
+#define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev))
+#define radeon_dpm_post_set_power_state(rdev) rdev->asic->dpm.post_set_power_state((rdev))
+#define radeon_dpm_display_configuration_changed(rdev) rdev->asic->dpm.display_configuration_changed((rdev))
+#define radeon_dpm_fini(rdev) rdev->asic->dpm.fini((rdev))
+#define radeon_dpm_get_sclk(rdev, l) rdev->asic->dpm.get_sclk((rdev), (l))
+#define radeon_dpm_get_mclk(rdev, l) rdev->asic->dpm.get_mclk((rdev), (l))
+#define radeon_dpm_print_power_state(rdev, ps) rdev->asic->dpm.print_power_state((rdev), (ps))
+#define radeon_dpm_debugfs_print_current_performance_level(rdev, m) rdev->asic->dpm.debugfs_print_current_performance_level((rdev), (m))
+#define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l))
+#define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
/* Common functions */
/* AGP */
@@ -2054,6 +2567,10 @@ extern int ni_mc_load_microcode(struct radeon_device *rdev);
#if defined(CONFIG_ACPI)
extern int radeon_acpi_init(struct radeon_device *rdev);
extern void radeon_acpi_fini(struct radeon_device *rdev);
+extern bool radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev);
+extern int radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
+ u8 perf_req, bool advertise);
+extern int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev);
#else
static inline int radeon_acpi_init(struct radeon_device *rdev) { return 0; }
static inline void radeon_acpi_fini(struct radeon_device *rdev) { }
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 196d28d99570..10f98c7742d8 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -78,6 +78,22 @@ struct atcs_verify_interface {
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
*/
/**
@@ -506,6 +522,135 @@ out:
}
/**
+ * radeon_acpi_is_pcie_performance_request_supported
+ *
+ * @rdev: radeon_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 radeon_acpi_is_pcie_performance_request_supported(struct radeon_device *rdev)
+{
+ struct radeon_atcs *atcs = &rdev->atcs;
+
+ if (atcs->functions.pcie_perf_req && atcs->functions.pcie_dev_rdy)
+ return true;
+
+ return false;
+}
+
+/**
+ * radeon_acpi_pcie_notify_device_ready
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Executes the PCIE_DEVICE_READY_NOTIFICATION method
+ * (all asics).
+ * returns 0 on success, error on failure.
+ */
+int radeon_acpi_pcie_notify_device_ready(struct radeon_device *rdev)
+{
+ acpi_handle handle;
+ union acpi_object *info;
+ struct radeon_atcs *atcs = &rdev->atcs;
+
+ /* Get the device handle */
+ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev);
+ if (!handle)
+ return -EINVAL;
+
+ if (!atcs->functions.pcie_dev_rdy)
+ return -EINVAL;
+
+ info = radeon_atcs_call(handle, ATCS_FUNCTION_PCIE_DEVICE_READY_NOTIFICATION, NULL);
+ if (!info)
+ return -EIO;
+
+ kfree(info);
+
+ return 0;
+}
+
+/**
+ * radeon_acpi_pcie_performance_request
+ *
+ * @rdev: radeon_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 radeon_acpi_pcie_performance_request(struct radeon_device *rdev,
+ u8 perf_req, bool advertise)
+{
+ acpi_handle handle;
+ union acpi_object *info;
+ struct radeon_atcs *atcs = &rdev->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 = DEVICE_ACPI_HANDLE(&rdev->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 = rdev->pdev->devfn | (rdev->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 = radeon_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;
+}
+
+/**
* radeon_acpi_event - handle notify events
*
* @nb: notifier block
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index a2802b47ee95..097077499cc6 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -126,7 +126,11 @@ static void radeon_register_accessor_init(struct radeon_device *rdev)
rdev->mc_rreg = &rs780_mc_rreg;
rdev->mc_wreg = &rs780_mc_wreg;
}
- if (rdev->family >= CHIP_R600) {
+
+ if (rdev->family >= CHIP_BONAIRE) {
+ rdev->pciep_rreg = &cik_pciep_rreg;
+ rdev->pciep_wreg = &cik_pciep_wreg;
+ } else if (rdev->family >= CHIP_R600) {
rdev->pciep_rreg = &r600_pciep_rreg;
rdev->pciep_wreg = &r600_pciep_wreg;
}
@@ -192,6 +196,9 @@ static struct radeon_asic r100_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -268,6 +275,9 @@ static struct radeon_asic r200_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -344,6 +354,9 @@ static struct radeon_asic r300_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -420,6 +433,9 @@ static struct radeon_asic r300_asic_pcie = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -496,6 +512,9 @@ static struct radeon_asic r420_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -572,6 +591,9 @@ static struct radeon_asic rs400_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -648,6 +670,9 @@ static struct radeon_asic rs600_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -726,6 +751,9 @@ static struct radeon_asic rs690_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -804,6 +832,9 @@ static struct radeon_asic rv515_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -880,6 +911,9 @@ static struct radeon_asic r520_asic = {
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
.is_lockup = &r100_gpu_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -957,6 +991,9 @@ static struct radeon_asic r600_asic = {
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
.is_lockup = &r600_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &r600_dma_ring_ib_execute,
@@ -966,6 +1003,9 @@ static struct radeon_asic r600_asic = {
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1012,6 +1052,115 @@ static struct radeon_asic r600_asic = {
.get_pcie_lanes = &r600_get_pcie_lanes,
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
+ .get_temperature = &rv6xx_get_temp,
+ },
+ .pflip = {
+ .pre_page_flip = &rs600_pre_page_flip,
+ .page_flip = &rs600_page_flip,
+ .post_page_flip = &rs600_post_page_flip,
+ },
+};
+
+static struct radeon_asic rv6xx_asic = {
+ .init = &r600_init,
+ .fini = &r600_fini,
+ .suspend = &r600_suspend,
+ .resume = &r600_resume,
+ .vga_set_state = &r600_vga_set_state,
+ .asic_reset = &r600_asic_reset,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &r600_mc_wait_for_idle,
+ .get_xclk = &r600_get_xclk,
+ .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
+ .gart = {
+ .tlb_flush = &r600_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
+ .ring = {
+ [RADEON_RING_TYPE_GFX_INDEX] = {
+ .ib_execute = &r600_ring_ib_execute,
+ .emit_fence = &r600_fence_ring_emit,
+ .emit_semaphore = &r600_semaphore_ring_emit,
+ .cs_parse = &r600_cs_parse,
+ .ring_test = &r600_ring_test,
+ .ib_test = &r600_ib_test,
+ .is_lockup = &r600_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [R600_RING_TYPE_DMA_INDEX] = {
+ .ib_execute = &r600_dma_ring_ib_execute,
+ .emit_fence = &r600_dma_fence_ring_emit,
+ .emit_semaphore = &r600_dma_semaphore_ring_emit,
+ .cs_parse = &r600_dma_cs_parse,
+ .ring_test = &r600_dma_ring_test,
+ .ib_test = &r600_dma_ib_test,
+ .is_lockup = &r600_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ }
+ },
+ .irq = {
+ .set = &r600_irq_set,
+ .process = &r600_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &rv515_bandwidth_update,
+ .get_vblank_counter = &rs600_get_vblank_counter,
+ .wait_for_vblank = &avivo_wait_for_vblank,
+ .set_backlight_level = &atombios_set_backlight_level,
+ .get_backlight_level = &atombios_get_backlight_level,
+ },
+ .copy = {
+ .blit = &r600_copy_blit,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &r600_copy_dma,
+ .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+ .copy = &r600_copy_dma,
+ .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &r600_hpd_init,
+ .fini = &r600_hpd_fini,
+ .sense = &r600_hpd_sense,
+ .set_polarity = &r600_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &r600_pm_misc,
+ .prepare = &rs600_pm_prepare,
+ .finish = &rs600_pm_finish,
+ .init_profile = &r600_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = &r600_get_pcie_lanes,
+ .set_pcie_lanes = &r600_set_pcie_lanes,
+ .set_clock_gating = NULL,
+ .get_temperature = &rv6xx_get_temp,
+ },
+ .dpm = {
+ .init = &rv6xx_dpm_init,
+ .setup_asic = &rv6xx_setup_asic,
+ .enable = &rv6xx_dpm_enable,
+ .disable = &rv6xx_dpm_disable,
+ .pre_set_power_state = &r600_dpm_pre_set_power_state,
+ .set_power_state = &rv6xx_dpm_set_power_state,
+ .post_set_power_state = &r600_dpm_post_set_power_state,
+ .display_configuration_changed = &rv6xx_dpm_display_configuration_changed,
+ .fini = &rv6xx_dpm_fini,
+ .get_sclk = &rv6xx_dpm_get_sclk,
+ .get_mclk = &rv6xx_dpm_get_mclk,
+ .print_power_state = &rv6xx_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
},
.pflip = {
.pre_page_flip = &rs600_pre_page_flip,
@@ -1045,6 +1194,9 @@ static struct radeon_asic rs780_asic = {
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
.is_lockup = &r600_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &r600_dma_ring_ib_execute,
@@ -1054,6 +1206,9 @@ static struct radeon_asic rs780_asic = {
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1100,6 +1255,21 @@ static struct radeon_asic rs780_asic = {
.get_pcie_lanes = NULL,
.set_pcie_lanes = NULL,
.set_clock_gating = NULL,
+ .get_temperature = &rv6xx_get_temp,
+ },
+ .dpm = {
+ .init = &rs780_dpm_init,
+ .setup_asic = &rs780_dpm_setup_asic,
+ .enable = &rs780_dpm_enable,
+ .disable = &rs780_dpm_disable,
+ .pre_set_power_state = &r600_dpm_pre_set_power_state,
+ .set_power_state = &rs780_dpm_set_power_state,
+ .post_set_power_state = &r600_dpm_post_set_power_state,
+ .display_configuration_changed = &rs780_dpm_display_configuration_changed,
+ .fini = &rs780_dpm_fini,
+ .get_sclk = &rs780_dpm_get_sclk,
+ .get_mclk = &rs780_dpm_get_mclk,
+ .print_power_state = &rs780_dpm_print_power_state,
},
.pflip = {
.pre_page_flip = &rs600_pre_page_flip,
@@ -1133,6 +1303,9 @@ static struct radeon_asic rv770_asic = {
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
.is_lockup = &r600_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &r600_dma_ring_ib_execute,
@@ -1142,6 +1315,9 @@ static struct radeon_asic rv770_asic = {
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &r600_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1151,6 +1327,9 @@ static struct radeon_asic rv770_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1198,6 +1377,24 @@ static struct radeon_asic rv770_asic = {
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = &radeon_atom_set_clock_gating,
.set_uvd_clocks = &rv770_set_uvd_clocks,
+ .get_temperature = &rv770_get_temp,
+ },
+ .dpm = {
+ .init = &rv770_dpm_init,
+ .setup_asic = &rv770_dpm_setup_asic,
+ .enable = &rv770_dpm_enable,
+ .disable = &rv770_dpm_disable,
+ .pre_set_power_state = &r600_dpm_pre_set_power_state,
+ .set_power_state = &rv770_dpm_set_power_state,
+ .post_set_power_state = &r600_dpm_post_set_power_state,
+ .display_configuration_changed = &rv770_dpm_display_configuration_changed,
+ .fini = &rv770_dpm_fini,
+ .get_sclk = &rv770_dpm_get_sclk,
+ .get_mclk = &rv770_dpm_get_mclk,
+ .print_power_state = &rv770_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &rv770_dpm_force_performance_level,
+ .vblank_too_short = &rv770_dpm_vblank_too_short,
},
.pflip = {
.pre_page_flip = &rs600_pre_page_flip,
@@ -1231,6 +1428,9 @@ static struct radeon_asic evergreen_asic = {
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
.is_lockup = &evergreen_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &evergreen_dma_ring_ib_execute,
@@ -1240,6 +1440,9 @@ static struct radeon_asic evergreen_asic = {
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &evergreen_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1249,6 +1452,9 @@ static struct radeon_asic evergreen_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1296,6 +1502,24 @@ static struct radeon_asic evergreen_asic = {
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
.set_uvd_clocks = &evergreen_set_uvd_clocks,
+ .get_temperature = &evergreen_get_temp,
+ },
+ .dpm = {
+ .init = &cypress_dpm_init,
+ .setup_asic = &cypress_dpm_setup_asic,
+ .enable = &cypress_dpm_enable,
+ .disable = &cypress_dpm_disable,
+ .pre_set_power_state = &r600_dpm_pre_set_power_state,
+ .set_power_state = &cypress_dpm_set_power_state,
+ .post_set_power_state = &r600_dpm_post_set_power_state,
+ .display_configuration_changed = &cypress_dpm_display_configuration_changed,
+ .fini = &cypress_dpm_fini,
+ .get_sclk = &rv770_dpm_get_sclk,
+ .get_mclk = &rv770_dpm_get_mclk,
+ .print_power_state = &rv770_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &rv770_dpm_force_performance_level,
+ .vblank_too_short = &cypress_dpm_vblank_too_short,
},
.pflip = {
.pre_page_flip = &evergreen_pre_page_flip,
@@ -1329,6 +1553,9 @@ static struct radeon_asic sumo_asic = {
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
.is_lockup = &evergreen_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &evergreen_dma_ring_ib_execute,
@@ -1338,6 +1565,9 @@ static struct radeon_asic sumo_asic = {
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &evergreen_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1347,6 +1577,9 @@ static struct radeon_asic sumo_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1394,6 +1627,23 @@ static struct radeon_asic sumo_asic = {
.set_pcie_lanes = NULL,
.set_clock_gating = NULL,
.set_uvd_clocks = &sumo_set_uvd_clocks,
+ .get_temperature = &sumo_get_temp,
+ },
+ .dpm = {
+ .init = &sumo_dpm_init,
+ .setup_asic = &sumo_dpm_setup_asic,
+ .enable = &sumo_dpm_enable,
+ .disable = &sumo_dpm_disable,
+ .pre_set_power_state = &sumo_dpm_pre_set_power_state,
+ .set_power_state = &sumo_dpm_set_power_state,
+ .post_set_power_state = &sumo_dpm_post_set_power_state,
+ .display_configuration_changed = &sumo_dpm_display_configuration_changed,
+ .fini = &sumo_dpm_fini,
+ .get_sclk = &sumo_dpm_get_sclk,
+ .get_mclk = &sumo_dpm_get_mclk,
+ .print_power_state = &sumo_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &sumo_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &sumo_dpm_force_performance_level,
},
.pflip = {
.pre_page_flip = &evergreen_pre_page_flip,
@@ -1427,6 +1677,9 @@ static struct radeon_asic btc_asic = {
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
.is_lockup = &evergreen_gfx_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &evergreen_dma_ring_ib_execute,
@@ -1436,6 +1689,9 @@ static struct radeon_asic btc_asic = {
.ring_test = &r600_dma_ring_test,
.ib_test = &r600_dma_ib_test,
.is_lockup = &evergreen_dma_is_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1445,6 +1701,9 @@ static struct radeon_asic btc_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1492,6 +1751,24 @@ static struct radeon_asic btc_asic = {
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
.set_uvd_clocks = &evergreen_set_uvd_clocks,
+ .get_temperature = &evergreen_get_temp,
+ },
+ .dpm = {
+ .init = &btc_dpm_init,
+ .setup_asic = &btc_dpm_setup_asic,
+ .enable = &btc_dpm_enable,
+ .disable = &btc_dpm_disable,
+ .pre_set_power_state = &btc_dpm_pre_set_power_state,
+ .set_power_state = &btc_dpm_set_power_state,
+ .post_set_power_state = &btc_dpm_post_set_power_state,
+ .display_configuration_changed = &cypress_dpm_display_configuration_changed,
+ .fini = &btc_dpm_fini,
+ .get_sclk = &btc_dpm_get_sclk,
+ .get_mclk = &btc_dpm_get_mclk,
+ .print_power_state = &rv770_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &rv770_dpm_force_performance_level,
+ .vblank_too_short = &btc_dpm_vblank_too_short,
},
.pflip = {
.pre_page_flip = &evergreen_pre_page_flip,
@@ -1533,6 +1810,9 @@ static struct radeon_asic cayman_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &cayman_gfx_is_lockup,
.vm_flush = &cayman_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1544,6 +1824,9 @@ static struct radeon_asic cayman_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &cayman_gfx_is_lockup,
.vm_flush = &cayman_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1555,6 +1838,9 @@ static struct radeon_asic cayman_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &cayman_gfx_is_lockup,
.vm_flush = &cayman_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
@@ -1566,6 +1852,9 @@ static struct radeon_asic cayman_asic = {
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_DMA1_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
@@ -1577,6 +1866,9 @@ static struct radeon_asic cayman_asic = {
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1586,6 +1878,9 @@ static struct radeon_asic cayman_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1633,6 +1928,24 @@ static struct radeon_asic cayman_asic = {
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
.set_uvd_clocks = &evergreen_set_uvd_clocks,
+ .get_temperature = &evergreen_get_temp,
+ },
+ .dpm = {
+ .init = &ni_dpm_init,
+ .setup_asic = &ni_dpm_setup_asic,
+ .enable = &ni_dpm_enable,
+ .disable = &ni_dpm_disable,
+ .pre_set_power_state = &ni_dpm_pre_set_power_state,
+ .set_power_state = &ni_dpm_set_power_state,
+ .post_set_power_state = &ni_dpm_post_set_power_state,
+ .display_configuration_changed = &cypress_dpm_display_configuration_changed,
+ .fini = &ni_dpm_fini,
+ .get_sclk = &ni_dpm_get_sclk,
+ .get_mclk = &ni_dpm_get_mclk,
+ .print_power_state = &ni_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &ni_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &ni_dpm_force_performance_level,
+ .vblank_too_short = &ni_dpm_vblank_too_short,
},
.pflip = {
.pre_page_flip = &evergreen_pre_page_flip,
@@ -1674,6 +1987,9 @@ static struct radeon_asic trinity_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &cayman_gfx_is_lockup,
.vm_flush = &cayman_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1685,6 +2001,9 @@ static struct radeon_asic trinity_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &cayman_gfx_is_lockup,
.vm_flush = &cayman_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1696,6 +2015,9 @@ static struct radeon_asic trinity_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &cayman_gfx_is_lockup,
.vm_flush = &cayman_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
@@ -1707,6 +2029,9 @@ static struct radeon_asic trinity_asic = {
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_DMA1_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
@@ -1718,6 +2043,9 @@ static struct radeon_asic trinity_asic = {
.ib_test = &r600_dma_ib_test,
.is_lockup = &cayman_dma_is_lockup,
.vm_flush = &cayman_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1727,6 +2055,9 @@ static struct radeon_asic trinity_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1772,6 +2103,23 @@ static struct radeon_asic trinity_asic = {
.set_pcie_lanes = NULL,
.set_clock_gating = NULL,
.set_uvd_clocks = &sumo_set_uvd_clocks,
+ .get_temperature = &tn_get_temp,
+ },
+ .dpm = {
+ .init = &trinity_dpm_init,
+ .setup_asic = &trinity_dpm_setup_asic,
+ .enable = &trinity_dpm_enable,
+ .disable = &trinity_dpm_disable,
+ .pre_set_power_state = &trinity_dpm_pre_set_power_state,
+ .set_power_state = &trinity_dpm_set_power_state,
+ .post_set_power_state = &trinity_dpm_post_set_power_state,
+ .display_configuration_changed = &trinity_dpm_display_configuration_changed,
+ .fini = &trinity_dpm_fini,
+ .get_sclk = &trinity_dpm_get_sclk,
+ .get_mclk = &trinity_dpm_get_mclk,
+ .print_power_state = &trinity_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &trinity_dpm_force_performance_level,
},
.pflip = {
.pre_page_flip = &evergreen_pre_page_flip,
@@ -1813,6 +2161,9 @@ static struct radeon_asic si_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &si_gfx_is_lockup,
.vm_flush = &si_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &si_ring_ib_execute,
@@ -1824,6 +2175,9 @@ static struct radeon_asic si_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &si_gfx_is_lockup,
.vm_flush = &si_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &si_ring_ib_execute,
@@ -1835,6 +2189,9 @@ static struct radeon_asic si_asic = {
.ib_test = &r600_ib_test,
.is_lockup = &si_gfx_is_lockup,
.vm_flush = &si_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_DMA_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
@@ -1846,6 +2203,9 @@ static struct radeon_asic si_asic = {
.ib_test = &r600_dma_ib_test,
.is_lockup = &si_dma_is_lockup,
.vm_flush = &si_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[CAYMAN_RING_TYPE_DMA1_INDEX] = {
.ib_execute = &cayman_dma_ring_ib_execute,
@@ -1857,6 +2217,9 @@ static struct radeon_asic si_asic = {
.ib_test = &r600_dma_ib_test,
.is_lockup = &si_dma_is_lockup,
.vm_flush = &si_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
},
[R600_RING_TYPE_UVD_INDEX] = {
.ib_execute = &r600_uvd_ib_execute,
@@ -1866,6 +2229,9 @@ static struct radeon_asic si_asic = {
.ring_test = &r600_uvd_ring_test,
.ib_test = &r600_uvd_ib_test,
.is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
}
},
.irq = {
@@ -1911,6 +2277,334 @@ static struct radeon_asic si_asic = {
.set_pcie_lanes = &r600_set_pcie_lanes,
.set_clock_gating = NULL,
.set_uvd_clocks = &si_set_uvd_clocks,
+ .get_temperature = &si_get_temp,
+ },
+ .dpm = {
+ .init = &si_dpm_init,
+ .setup_asic = &si_dpm_setup_asic,
+ .enable = &si_dpm_enable,
+ .disable = &si_dpm_disable,
+ .pre_set_power_state = &si_dpm_pre_set_power_state,
+ .set_power_state = &si_dpm_set_power_state,
+ .post_set_power_state = &si_dpm_post_set_power_state,
+ .display_configuration_changed = &si_dpm_display_configuration_changed,
+ .fini = &si_dpm_fini,
+ .get_sclk = &ni_dpm_get_sclk,
+ .get_mclk = &ni_dpm_get_mclk,
+ .print_power_state = &ni_dpm_print_power_state,
+ .debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
+ .force_performance_level = &si_dpm_force_performance_level,
+ .vblank_too_short = &ni_dpm_vblank_too_short,
+ },
+ .pflip = {
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
+ },
+};
+
+static struct radeon_asic ci_asic = {
+ .init = &cik_init,
+ .fini = &cik_fini,
+ .suspend = &cik_suspend,
+ .resume = &cik_resume,
+ .asic_reset = &cik_asic_reset,
+ .vga_set_state = &r600_vga_set_state,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+ .get_xclk = &cik_get_xclk,
+ .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+ .gart = {
+ .tlb_flush = &cik_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
+ .vm = {
+ .init = &cik_vm_init,
+ .fini = &cik_vm_fini,
+ .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+ .set_page = &cik_vm_set_page,
+ },
+ .ring = {
+ [RADEON_RING_TYPE_GFX_INDEX] = {
+ .ib_execute = &cik_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_fence_gfx_ring_emit,
+ .emit_semaphore = &cik_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_ring_test,
+ .ib_test = &cik_ib_test,
+ .is_lockup = &cik_gfx_is_lockup,
+ .vm_flush = &cik_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [CAYMAN_RING_TYPE_CP1_INDEX] = {
+ .ib_execute = &cik_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_fence_compute_ring_emit,
+ .emit_semaphore = &cik_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_ring_test,
+ .ib_test = &cik_ib_test,
+ .is_lockup = &cik_gfx_is_lockup,
+ .vm_flush = &cik_vm_flush,
+ .get_rptr = &cik_compute_ring_get_rptr,
+ .get_wptr = &cik_compute_ring_get_wptr,
+ .set_wptr = &cik_compute_ring_set_wptr,
+ },
+ [CAYMAN_RING_TYPE_CP2_INDEX] = {
+ .ib_execute = &cik_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_fence_compute_ring_emit,
+ .emit_semaphore = &cik_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_ring_test,
+ .ib_test = &cik_ib_test,
+ .is_lockup = &cik_gfx_is_lockup,
+ .vm_flush = &cik_vm_flush,
+ .get_rptr = &cik_compute_ring_get_rptr,
+ .get_wptr = &cik_compute_ring_get_wptr,
+ .set_wptr = &cik_compute_ring_set_wptr,
+ },
+ [R600_RING_TYPE_DMA_INDEX] = {
+ .ib_execute = &cik_sdma_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_sdma_fence_ring_emit,
+ .emit_semaphore = &cik_sdma_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_sdma_ring_test,
+ .ib_test = &cik_sdma_ib_test,
+ .is_lockup = &cik_sdma_is_lockup,
+ .vm_flush = &cik_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [CAYMAN_RING_TYPE_DMA1_INDEX] = {
+ .ib_execute = &cik_sdma_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_sdma_fence_ring_emit,
+ .emit_semaphore = &cik_sdma_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_sdma_ring_test,
+ .ib_test = &cik_sdma_ib_test,
+ .is_lockup = &cik_sdma_is_lockup,
+ .vm_flush = &cik_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [R600_RING_TYPE_UVD_INDEX] = {
+ .ib_execute = &r600_uvd_ib_execute,
+ .emit_fence = &r600_uvd_fence_emit,
+ .emit_semaphore = &cayman_uvd_semaphore_emit,
+ .cs_parse = &radeon_uvd_cs_parse,
+ .ring_test = &r600_uvd_ring_test,
+ .ib_test = &r600_uvd_ib_test,
+ .is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ }
+ },
+ .irq = {
+ .set = &cik_irq_set,
+ .process = &cik_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &dce8_bandwidth_update,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .wait_for_vblank = &dce4_wait_for_vblank,
+ },
+ .copy = {
+ .blit = NULL,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &cik_copy_dma,
+ .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+ .copy = &cik_copy_dma,
+ .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &evergreen_hpd_init,
+ .fini = &evergreen_hpd_fini,
+ .sense = &evergreen_hpd_sense,
+ .set_polarity = &evergreen_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &evergreen_pm_misc,
+ .prepare = &evergreen_pm_prepare,
+ .finish = &evergreen_pm_finish,
+ .init_profile = &sumo_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ .set_uvd_clocks = &cik_set_uvd_clocks,
+ },
+ .pflip = {
+ .pre_page_flip = &evergreen_pre_page_flip,
+ .page_flip = &evergreen_page_flip,
+ .post_page_flip = &evergreen_post_page_flip,
+ },
+};
+
+static struct radeon_asic kv_asic = {
+ .init = &cik_init,
+ .fini = &cik_fini,
+ .suspend = &cik_suspend,
+ .resume = &cik_resume,
+ .asic_reset = &cik_asic_reset,
+ .vga_set_state = &r600_vga_set_state,
+ .ioctl_wait_idle = NULL,
+ .gui_idle = &r600_gui_idle,
+ .mc_wait_for_idle = &evergreen_mc_wait_for_idle,
+ .get_xclk = &cik_get_xclk,
+ .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
+ .gart = {
+ .tlb_flush = &cik_pcie_gart_tlb_flush,
+ .set_page = &rs600_gart_set_page,
+ },
+ .vm = {
+ .init = &cik_vm_init,
+ .fini = &cik_vm_fini,
+ .pt_ring_index = R600_RING_TYPE_DMA_INDEX,
+ .set_page = &cik_vm_set_page,
+ },
+ .ring = {
+ [RADEON_RING_TYPE_GFX_INDEX] = {
+ .ib_execute = &cik_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_fence_gfx_ring_emit,
+ .emit_semaphore = &cik_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_ring_test,
+ .ib_test = &cik_ib_test,
+ .is_lockup = &cik_gfx_is_lockup,
+ .vm_flush = &cik_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [CAYMAN_RING_TYPE_CP1_INDEX] = {
+ .ib_execute = &cik_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_fence_compute_ring_emit,
+ .emit_semaphore = &cik_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_ring_test,
+ .ib_test = &cik_ib_test,
+ .is_lockup = &cik_gfx_is_lockup,
+ .vm_flush = &cik_vm_flush,
+ .get_rptr = &cik_compute_ring_get_rptr,
+ .get_wptr = &cik_compute_ring_get_wptr,
+ .set_wptr = &cik_compute_ring_set_wptr,
+ },
+ [CAYMAN_RING_TYPE_CP2_INDEX] = {
+ .ib_execute = &cik_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_fence_compute_ring_emit,
+ .emit_semaphore = &cik_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_ring_test,
+ .ib_test = &cik_ib_test,
+ .is_lockup = &cik_gfx_is_lockup,
+ .vm_flush = &cik_vm_flush,
+ .get_rptr = &cik_compute_ring_get_rptr,
+ .get_wptr = &cik_compute_ring_get_wptr,
+ .set_wptr = &cik_compute_ring_set_wptr,
+ },
+ [R600_RING_TYPE_DMA_INDEX] = {
+ .ib_execute = &cik_sdma_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_sdma_fence_ring_emit,
+ .emit_semaphore = &cik_sdma_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_sdma_ring_test,
+ .ib_test = &cik_sdma_ib_test,
+ .is_lockup = &cik_sdma_is_lockup,
+ .vm_flush = &cik_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [CAYMAN_RING_TYPE_DMA1_INDEX] = {
+ .ib_execute = &cik_sdma_ring_ib_execute,
+ .ib_parse = &cik_ib_parse,
+ .emit_fence = &cik_sdma_fence_ring_emit,
+ .emit_semaphore = &cik_sdma_semaphore_ring_emit,
+ .cs_parse = NULL,
+ .ring_test = &cik_sdma_ring_test,
+ .ib_test = &cik_sdma_ib_test,
+ .is_lockup = &cik_sdma_is_lockup,
+ .vm_flush = &cik_dma_vm_flush,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ },
+ [R600_RING_TYPE_UVD_INDEX] = {
+ .ib_execute = &r600_uvd_ib_execute,
+ .emit_fence = &r600_uvd_fence_emit,
+ .emit_semaphore = &cayman_uvd_semaphore_emit,
+ .cs_parse = &radeon_uvd_cs_parse,
+ .ring_test = &r600_uvd_ring_test,
+ .ib_test = &r600_uvd_ib_test,
+ .is_lockup = &radeon_ring_test_lockup,
+ .get_rptr = &radeon_ring_generic_get_rptr,
+ .get_wptr = &radeon_ring_generic_get_wptr,
+ .set_wptr = &radeon_ring_generic_set_wptr,
+ }
+ },
+ .irq = {
+ .set = &cik_irq_set,
+ .process = &cik_irq_process,
+ },
+ .display = {
+ .bandwidth_update = &dce8_bandwidth_update,
+ .get_vblank_counter = &evergreen_get_vblank_counter,
+ .wait_for_vblank = &dce4_wait_for_vblank,
+ },
+ .copy = {
+ .blit = NULL,
+ .blit_ring_index = RADEON_RING_TYPE_GFX_INDEX,
+ .dma = &cik_copy_dma,
+ .dma_ring_index = R600_RING_TYPE_DMA_INDEX,
+ .copy = &cik_copy_dma,
+ .copy_ring_index = R600_RING_TYPE_DMA_INDEX,
+ },
+ .surface = {
+ .set_reg = r600_set_surface_reg,
+ .clear_reg = r600_clear_surface_reg,
+ },
+ .hpd = {
+ .init = &evergreen_hpd_init,
+ .fini = &evergreen_hpd_fini,
+ .sense = &evergreen_hpd_sense,
+ .set_polarity = &evergreen_hpd_set_polarity,
+ },
+ .pm = {
+ .misc = &evergreen_pm_misc,
+ .prepare = &evergreen_pm_prepare,
+ .finish = &evergreen_pm_finish,
+ .init_profile = &sumo_pm_init_profile,
+ .get_dynpm_state = &r600_pm_get_dynpm_state,
+ .get_engine_clock = &radeon_atom_get_engine_clock,
+ .set_engine_clock = &radeon_atom_set_engine_clock,
+ .get_memory_clock = &radeon_atom_get_memory_clock,
+ .set_memory_clock = &radeon_atom_set_memory_clock,
+ .get_pcie_lanes = NULL,
+ .set_pcie_lanes = NULL,
+ .set_clock_gating = NULL,
+ .set_uvd_clocks = &cik_set_uvd_clocks,
},
.pflip = {
.pre_page_flip = &evergreen_pre_page_flip,
@@ -1999,16 +2693,15 @@ int radeon_asic_init(struct radeon_device *rdev)
rdev->asic = &r520_asic;
break;
case CHIP_R600:
+ rdev->asic = &r600_asic;
+ break;
case CHIP_RV610:
case CHIP_RV630:
case CHIP_RV620:
case CHIP_RV635:
case CHIP_RV670:
- rdev->asic = &r600_asic;
- if (rdev->family == CHIP_R600)
- rdev->has_uvd = false;
- else
- rdev->has_uvd = true;
+ rdev->asic = &rv6xx_asic;
+ rdev->has_uvd = true;
break;
case CHIP_RS780:
case CHIP_RS880:
@@ -2082,6 +2775,19 @@ int radeon_asic_init(struct radeon_device *rdev)
else
rdev->has_uvd = true;
break;
+ case CHIP_BONAIRE:
+ rdev->asic = &ci_asic;
+ rdev->num_crtc = 6;
+ break;
+ case CHIP_KAVERI:
+ case CHIP_KABINI:
+ rdev->asic = &kv_asic;
+ /* set num crtcs */
+ if (rdev->family == CHIP_KAVERI)
+ rdev->num_crtc = 4;
+ else
+ rdev->num_crtc = 2;
+ break;
default:
/* FIXME: not supported yet */
return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index a72759ede753..45d0693cddd5 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -47,6 +47,12 @@ u8 atombios_get_backlight_level(struct radeon_encoder *radeon_encoder);
void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level);
u8 radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder);
+u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev,
+ struct radeon_ring *ring);
+u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring);
+void radeon_ring_generic_set_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring);
/*
* r100,rv100,rs100,rv200,rs200
@@ -395,6 +401,35 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
int r600_mc_wait_for_idle(struct radeon_device *rdev);
u32 r600_get_xclk(struct radeon_device *rdev);
uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
+int rv6xx_get_temp(struct radeon_device *rdev);
+int r600_dpm_pre_set_power_state(struct radeon_device *rdev);
+void r600_dpm_post_set_power_state(struct radeon_device *rdev);
+/* rv6xx dpm */
+int rv6xx_dpm_init(struct radeon_device *rdev);
+int rv6xx_dpm_enable(struct radeon_device *rdev);
+void rv6xx_dpm_disable(struct radeon_device *rdev);
+int rv6xx_dpm_set_power_state(struct radeon_device *rdev);
+void rv6xx_setup_asic(struct radeon_device *rdev);
+void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rv6xx_dpm_fini(struct radeon_device *rdev);
+u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *ps);
+void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
+/* rs780 dpm */
+int rs780_dpm_init(struct radeon_device *rdev);
+int rs780_dpm_enable(struct radeon_device *rdev);
+void rs780_dpm_disable(struct radeon_device *rdev);
+int rs780_dpm_set_power_state(struct radeon_device *rdev);
+void rs780_dpm_setup_asic(struct radeon_device *rdev);
+void rs780_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rs780_dpm_fini(struct radeon_device *rdev);
+u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rs780_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *ps);
/* uvd */
int r600_uvd_init(struct radeon_device *rdev);
@@ -428,6 +463,24 @@ int rv770_copy_dma(struct radeon_device *rdev,
u32 rv770_get_xclk(struct radeon_device *rdev);
int rv770_uvd_resume(struct radeon_device *rdev);
int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int rv770_get_temp(struct radeon_device *rdev);
+/* rv7xx pm */
+int rv770_dpm_init(struct radeon_device *rdev);
+int rv770_dpm_enable(struct radeon_device *rdev);
+void rv770_dpm_disable(struct radeon_device *rdev);
+int rv770_dpm_set_power_state(struct radeon_device *rdev);
+void rv770_dpm_setup_asic(struct radeon_device *rdev);
+void rv770_dpm_display_configuration_changed(struct radeon_device *rdev);
+void rv770_dpm_fini(struct radeon_device *rdev);
+u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void rv770_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *ps);
+void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
+int rv770_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
+bool rv770_dpm_vblank_too_short(struct radeon_device *rdev);
/*
* evergreen
@@ -482,6 +535,45 @@ int evergreen_copy_dma(struct radeon_device *rdev,
struct radeon_fence **fence);
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
+int evergreen_get_temp(struct radeon_device *rdev);
+int sumo_get_temp(struct radeon_device *rdev);
+int tn_get_temp(struct radeon_device *rdev);
+int cypress_dpm_init(struct radeon_device *rdev);
+void cypress_dpm_setup_asic(struct radeon_device *rdev);
+int cypress_dpm_enable(struct radeon_device *rdev);
+void cypress_dpm_disable(struct radeon_device *rdev);
+int cypress_dpm_set_power_state(struct radeon_device *rdev);
+void cypress_dpm_display_configuration_changed(struct radeon_device *rdev);
+void cypress_dpm_fini(struct radeon_device *rdev);
+bool cypress_dpm_vblank_too_short(struct radeon_device *rdev);
+int btc_dpm_init(struct radeon_device *rdev);
+void btc_dpm_setup_asic(struct radeon_device *rdev);
+int btc_dpm_enable(struct radeon_device *rdev);
+void btc_dpm_disable(struct radeon_device *rdev);
+int btc_dpm_pre_set_power_state(struct radeon_device *rdev);
+int btc_dpm_set_power_state(struct radeon_device *rdev);
+void btc_dpm_post_set_power_state(struct radeon_device *rdev);
+void btc_dpm_fini(struct radeon_device *rdev);
+u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
+bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
+int sumo_dpm_init(struct radeon_device *rdev);
+int sumo_dpm_enable(struct radeon_device *rdev);
+void sumo_dpm_disable(struct radeon_device *rdev);
+int sumo_dpm_pre_set_power_state(struct radeon_device *rdev);
+int sumo_dpm_set_power_state(struct radeon_device *rdev);
+void sumo_dpm_post_set_power_state(struct radeon_device *rdev);
+void sumo_dpm_setup_asic(struct radeon_device *rdev);
+void sumo_dpm_display_configuration_changed(struct radeon_device *rdev);
+void sumo_dpm_fini(struct radeon_device *rdev);
+u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void sumo_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *ps);
+void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
+int sumo_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
/*
* cayman
@@ -516,6 +608,41 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+int ni_dpm_init(struct radeon_device *rdev);
+void ni_dpm_setup_asic(struct radeon_device *rdev);
+int ni_dpm_enable(struct radeon_device *rdev);
+void ni_dpm_disable(struct radeon_device *rdev);
+int ni_dpm_pre_set_power_state(struct radeon_device *rdev);
+int ni_dpm_set_power_state(struct radeon_device *rdev);
+void ni_dpm_post_set_power_state(struct radeon_device *rdev);
+void ni_dpm_fini(struct radeon_device *rdev);
+u32 ni_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 ni_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void ni_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *ps);
+void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
+int ni_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
+bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
+int trinity_dpm_init(struct radeon_device *rdev);
+int trinity_dpm_enable(struct radeon_device *rdev);
+void trinity_dpm_disable(struct radeon_device *rdev);
+int trinity_dpm_pre_set_power_state(struct radeon_device *rdev);
+int trinity_dpm_set_power_state(struct radeon_device *rdev);
+void trinity_dpm_post_set_power_state(struct radeon_device *rdev);
+void trinity_dpm_setup_asic(struct radeon_device *rdev);
+void trinity_dpm_display_configuration_changed(struct radeon_device *rdev);
+void trinity_dpm_fini(struct radeon_device *rdev);
+u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low);
+u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low);
+void trinity_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *ps);
+void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
+int trinity_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
+
/* DCE6 - SI */
void dce6_bandwidth_update(struct radeon_device *rdev);
@@ -552,5 +679,82 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
u32 si_get_xclk(struct radeon_device *rdev);
uint64_t si_get_gpu_clock_counter(struct radeon_device *rdev);
int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int si_get_temp(struct radeon_device *rdev);
+int si_dpm_init(struct radeon_device *rdev);
+void si_dpm_setup_asic(struct radeon_device *rdev);
+int si_dpm_enable(struct radeon_device *rdev);
+void si_dpm_disable(struct radeon_device *rdev);
+int si_dpm_pre_set_power_state(struct radeon_device *rdev);
+int si_dpm_set_power_state(struct radeon_device *rdev);
+void si_dpm_post_set_power_state(struct radeon_device *rdev);
+void si_dpm_fini(struct radeon_device *rdev);
+void si_dpm_display_configuration_changed(struct radeon_device *rdev);
+void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m);
+int si_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
+
+/* DCE8 - CIK */
+void dce8_bandwidth_update(struct radeon_device *rdev);
+
+/*
+ * cik
+ */
+uint64_t cik_get_gpu_clock_counter(struct radeon_device *rdev);
+u32 cik_get_xclk(struct radeon_device *rdev);
+uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
+void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int cik_uvd_resume(struct radeon_device *rdev);
+void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence);
+void cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
+ struct radeon_ring *ring,
+ struct radeon_semaphore *semaphore,
+ bool emit_wait);
+void cik_sdma_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+int cik_copy_dma(struct radeon_device *rdev,
+ uint64_t src_offset, uint64_t dst_offset,
+ unsigned num_gpu_pages,
+ struct radeon_fence **fence);
+int cik_sdma_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int cik_sdma_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
+bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
+void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence);
+void cik_fence_compute_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence);
+void cik_semaphore_ring_emit(struct radeon_device *rdev,
+ struct radeon_ring *cp,
+ struct radeon_semaphore *semaphore,
+ bool emit_wait);
+void cik_pcie_gart_tlb_flush(struct radeon_device *rdev);
+int cik_init(struct radeon_device *rdev);
+void cik_fini(struct radeon_device *rdev);
+int cik_suspend(struct radeon_device *rdev);
+int cik_resume(struct radeon_device *rdev);
+bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
+int cik_asic_reset(struct radeon_device *rdev);
+void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int cik_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int cik_irq_set(struct radeon_device *rdev);
+int cik_irq_process(struct radeon_device *rdev);
+int cik_vm_init(struct radeon_device *rdev);
+void cik_vm_fini(struct radeon_device *rdev);
+void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+void cik_vm_set_page(struct radeon_device *rdev,
+ struct radeon_ib *ib,
+ uint64_t pe,
+ uint64_t addr, unsigned count,
+ uint32_t incr, uint32_t flags);
+void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
+int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
+u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
+ struct radeon_ring *ring);
+u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring);
+void cik_compute_ring_set_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring);
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index dea6f63c9724..fbdaff55556b 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -56,10 +56,6 @@ extern void
radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
uint32_t supported_device);
-/* local */
-static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
- u16 voltage_id, u16 *voltage);
-
union atom_supported_devices {
struct _ATOM_SUPPORTED_DEVICES_INFO info;
struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
@@ -1247,6 +1243,7 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
}
rdev->clock.dp_extclk =
le16_to_cpu(firmware_info->info_21.usUniphyDPModeExtClkFreq);
+ rdev->clock.current_dispclk = rdev->clock.default_dispclk;
}
*dcpll = *p1pll;
@@ -1269,6 +1266,7 @@ union igp_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;
};
bool radeon_atombios_sideport_present(struct radeon_device *rdev)
@@ -1438,6 +1436,22 @@ static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
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;
default:
DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
break;
@@ -1499,6 +1513,10 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
ss->type = ss_info->info_2.asSpreadSpectrum[i].ucSpreadSpectrumMode;
ss->rate = le16_to_cpu(ss_info->info_2.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+ if ((crev == 2) &&
+ ((id == ASIC_INTERNAL_ENGINE_SS) ||
+ (id == ASIC_INTERNAL_MEMORY_SS)))
+ ss->rate /= 100;
return true;
}
}
@@ -1513,6 +1531,9 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage);
ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode;
ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz);
+ if ((id == ASIC_INTERNAL_ENGINE_SS) ||
+ (id == ASIC_INTERNAL_MEMORY_SS))
+ ss->rate /= 100;
if (rdev->flags & RADEON_IS_IGP)
radeon_atombios_get_igp_ss_overrides(rdev, ss, id);
return true;
@@ -1927,6 +1948,7 @@ static const char *pp_lib_thermal_controller_names[] = {
"Northern Islands",
"Southern Islands",
"lm96163",
+ "Sea Islands",
};
union power_info {
@@ -1944,6 +1966,7 @@ union pplib_clock_info {
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 {
@@ -2209,6 +2232,11 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
rdev->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");
+ rdev->pm.int_thermal_type = THERMAL_TYPE_CI;
} else if ((controller->ucType ==
ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) ||
(controller->ucType ==
@@ -2241,8 +2269,8 @@ static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *r
}
}
-static void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
- u16 *vddc, u16 *vddci)
+void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
+ u16 *vddc, u16 *vddci, u16 *mvdd)
{
struct radeon_mode_info *mode_info = &rdev->mode_info;
int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
@@ -2252,6 +2280,7 @@ static void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
*vddc = 0;
*vddci = 0;
+ *mvdd = 0;
if (atom_parse_data_header(mode_info->atom_context, index, NULL,
&frev, &crev, &data_offset)) {
@@ -2259,8 +2288,10 @@ static void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
(union firmware_info *)(mode_info->atom_context->bios +
data_offset);
*vddc = le16_to_cpu(firmware_info->info_14.usBootUpVDDCVoltage);
- if ((frev == 2) && (crev >= 2))
+ if ((frev == 2) && (crev >= 2)) {
*vddci = le16_to_cpu(firmware_info->info_22.usBootUpVDDCIVoltage);
+ *mvdd = le16_to_cpu(firmware_info->info_22.usBootUpMVDDCVoltage);
+ }
}
}
@@ -2271,9 +2302,9 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
int j;
u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings);
u32 misc2 = le16_to_cpu(non_clock_info->usClassification);
- u16 vddc, vddci;
+ u16 vddc, vddci, mvdd;
- radeon_atombios_get_default_voltages(rdev, &vddc, &vddci);
+ radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
rdev->pm.power_state[state_index].misc = misc;
rdev->pm.power_state[state_index].misc2 = misc2;
@@ -2316,7 +2347,13 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
rdev->pm.default_vddc = rdev->pm.power_state[state_index].clock_info[0].voltage.voltage;
rdev->pm.default_vddci = rdev->pm.power_state[state_index].clock_info[0].voltage.vddci;
} else {
- /* patch the table values with the default slck/mclk from firmware info */
+ u16 max_vddci = 0;
+
+ if (ASIC_IS_DCE4(rdev))
+ radeon_atom_get_max_voltage(rdev,
+ SET_VOLTAGE_TYPE_ASIC_VDDCI,
+ &max_vddci);
+ /* patch the table values with the default sclk/mclk from firmware info */
for (j = 0; j < mode_index; j++) {
rdev->pm.power_state[state_index].clock_info[j].mclk =
rdev->clock.default_mclk;
@@ -2325,6 +2362,9 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde
if (vddc)
rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
vddc;
+ if (max_vddci)
+ rdev->pm.power_state[state_index].clock_info[j].voltage.vddci =
+ max_vddci;
}
}
}
@@ -2347,6 +2387,15 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
}
+ } else if (rdev->family >= CHIP_BONAIRE) {
+ 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;
+ rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk;
+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type =
+ VOLTAGE_NONE;
} else if (rdev->family >= CHIP_TAHITI) {
sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
sclk |= clock_info->si.ucEngineClockHigh << 16;
@@ -2392,6 +2441,10 @@ static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev,
case ATOM_VIRTUAL_VOLTAGE_ID1:
case ATOM_VIRTUAL_VOLTAGE_ID2:
case ATOM_VIRTUAL_VOLTAGE_ID3:
+ case ATOM_VIRTUAL_VOLTAGE_ID4:
+ case ATOM_VIRTUAL_VOLTAGE_ID5:
+ case ATOM_VIRTUAL_VOLTAGE_ID6:
+ case ATOM_VIRTUAL_VOLTAGE_ID7:
if (radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC,
rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage,
&vddc) == 0)
@@ -2667,6 +2720,8 @@ union get_clock_dividers {
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 radeon_atom_get_clock_dividers(struct radeon_device *rdev,
@@ -2699,7 +2754,8 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
break;
case 2:
case 3:
- /* r6xx, r7xx, evergreen, ni */
+ case 5:
+ /* r6xx, r7xx, evergreen, ni, si */
if (rdev->family <= CHIP_RV770) {
args.v2.ucAction = clock_type;
args.v2.ulClock = cpu_to_le32(clock); /* 10 khz */
@@ -2732,6 +2788,9 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
dividers->vco_mode = (args.v3.ucCntlFlag &
ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE) ? 1 : 0;
} else {
+ /* for SI we use ComputeMemoryClockParam for memory plls */
+ if (rdev->family >= CHIP_TAHITI)
+ return -EINVAL;
args.v5.ulClockParams = cpu_to_le32((clock_type << 24) | clock);
if (strobe_mode)
args.v5.ucInputFlag = ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN;
@@ -2757,9 +2816,76 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
- dividers->post_div = args.v4.ucPostDiv;
+ 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 */
+
+ atom_execute_table(rdev->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 radeon_atom_get_memory_pll_dividers(struct radeon_device *rdev,
+ 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 (!atom_parse_cmd_header(rdev->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;
+
+ atom_execute_table(rdev->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) ? 1 : 0;
+ 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;
}
@@ -2819,6 +2945,48 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev,
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+void radeon_atom_set_engine_dram_timings(struct radeon_device *rdev,
+ 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);
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_update_memory_dll(struct radeon_device *rdev,
+ u32 mem_clock)
+{
+ u32 args;
+ int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
+
+ args = cpu_to_le32(mem_clock); /* 10 khz */
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_set_ac_timing(struct radeon_device *rdev,
+ u32 mem_clock)
+{
+ SET_MEMORY_CLOCK_PS_ALLOCATION args;
+ int index = GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings);
+ u32 tmp = mem_clock | (COMPUTE_MEMORY_PLL_PARAM << 24);
+
+ args.ulTargetMemoryClock = cpu_to_le32(tmp); /* 10 khz */
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
union set_voltage {
struct _SET_VOLTAGE_PS_ALLOCATION alloc;
struct _SET_VOLTAGE_PARAMETERS v1;
@@ -2863,8 +3031,8 @@ void radeon_atom_set_voltage(struct radeon_device *rdev, u16 voltage_level, u8 v
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
-static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
- u16 voltage_id, u16 *voltage)
+int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
+ u16 voltage_id, u16 *voltage)
{
union set_voltage args;
int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
@@ -2902,6 +3070,695 @@ static int radeon_atom_get_max_vddc(struct radeon_device *rdev, u8 voltage_type,
return 0;
}
+int radeon_atom_get_leakage_vddc_based_on_leakage_idx(struct radeon_device *rdev,
+ u16 *voltage,
+ u16 leakage_idx)
+{
+ return radeon_atom_get_max_vddc(rdev, VOLTAGE_TYPE_VDDC, leakage_idx, voltage);
+}
+
+int radeon_atom_get_voltage_gpio_settings(struct radeon_device *rdev,
+ u16 voltage_level, u8 voltage_type,
+ u32 *gpio_value, u32 *gpio_mask)
+{
+ union set_voltage args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+ u8 frev, crev;
+
+ if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+ return -EINVAL;
+
+ switch (crev) {
+ case 1:
+ return -EINVAL;
+ case 2:
+ args.v2.ucVoltageType = voltage_type;
+ args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK;
+ args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ *gpio_mask = le32_to_cpu(*(u32 *)&args.v2);
+
+ args.v2.ucVoltageType = voltage_type;
+ args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL;
+ args.v2.usVoltageLevel = cpu_to_le16(voltage_level);
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ *gpio_value = le32_to_cpu(*(u32 *)&args.v2);
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+
+ 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 *atom_lookup_voltage_object_v1(ATOM_VOLTAGE_OBJECT_INFO *v1,
+ u8 voltage_type)
+{
+ u32 size = le16_to_cpu(v1->sHeader.usStructureSize);
+ u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO, asVoltageObj[0]);
+ u8 *start = (u8 *)v1;
+
+ while (offset < size) {
+ ATOM_VOLTAGE_OBJECT *vo = (ATOM_VOLTAGE_OBJECT *)(start + offset);
+ if (vo->ucVoltageType == voltage_type)
+ return vo;
+ offset += offsetof(ATOM_VOLTAGE_OBJECT, asFormula.ucVIDAdjustEntries) +
+ vo->asFormula.ucNumOfVoltageEntries;
+ }
+ return NULL;
+}
+
+static ATOM_VOLTAGE_OBJECT_V2 *atom_lookup_voltage_object_v2(ATOM_VOLTAGE_OBJECT_INFO_V2 *v2,
+ u8 voltage_type)
+{
+ u32 size = le16_to_cpu(v2->sHeader.usStructureSize);
+ u32 offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V2, asVoltageObj[0]);
+ u8 *start = (u8*)v2;
+
+ while (offset < size) {
+ ATOM_VOLTAGE_OBJECT_V2 *vo = (ATOM_VOLTAGE_OBJECT_V2 *)(start + offset);
+ if (vo->ucVoltageType == voltage_type)
+ return vo;
+ offset += offsetof(ATOM_VOLTAGE_OBJECT_V2, asFormula.asVIDAdjustEntries) +
+ (vo->asFormula.ucNumOfVoltageEntries * sizeof(VOLTAGE_LUT_ENTRY));
+ }
+ return NULL;
+}
+
+static ATOM_VOLTAGE_OBJECT_V3 *atom_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
+radeon_atom_is_voltage_gpio(struct radeon_device *rdev,
+ u8 voltage_type, u8 voltage_mode)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 1:
+ case 2:
+ switch (crev) {
+ case 1:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object &&
+ (voltage_object->v1.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
+ return true;
+ break;
+ case 2:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object &&
+ (voltage_object->v2.asControl.ucVoltageControlId == VOLTAGE_CONTROLLED_BY_GPIO))
+ return true;
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return false;
+ }
+ break;
+ case 3:
+ switch (crev) {
+ case 1:
+ if (atom_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 radeon_atom_get_max_voltage(struct radeon_device *rdev,
+ u8 voltage_type, u16 *max_voltage)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+
+ switch (crev) {
+ case 1:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA *formula =
+ &voltage_object->v1.asFormula;
+ if (formula->ucFlag & 1)
+ *max_voltage =
+ le16_to_cpu(formula->usVoltageBaseLevel) +
+ formula->ucNumOfVoltageEntries / 2 *
+ le16_to_cpu(formula->usVoltageStep);
+ else
+ *max_voltage =
+ le16_to_cpu(formula->usVoltageBaseLevel) +
+ (formula->ucNumOfVoltageEntries - 1) *
+ le16_to_cpu(formula->usVoltageStep);
+ return 0;
+ }
+ break;
+ case 2:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA_V2 *formula =
+ &voltage_object->v2.asFormula;
+ if (formula->ucNumOfVoltageEntries) {
+ *max_voltage =
+ le16_to_cpu(formula->asVIDAdjustEntries[
+ formula->ucNumOfVoltageEntries - 1
+ ].usVoltageValue);
+ return 0;
+ }
+ }
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return -EINVAL;
+ }
+
+ }
+ return -EINVAL;
+}
+
+int radeon_atom_get_min_voltage(struct radeon_device *rdev,
+ u8 voltage_type, u16 *min_voltage)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+
+ switch (crev) {
+ case 1:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA *formula =
+ &voltage_object->v1.asFormula;
+ *min_voltage =
+ le16_to_cpu(formula->usVoltageBaseLevel);
+ return 0;
+ }
+ break;
+ case 2:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA_V2 *formula =
+ &voltage_object->v2.asFormula;
+ if (formula->ucNumOfVoltageEntries) {
+ *min_voltage =
+ le16_to_cpu(formula->asVIDAdjustEntries[
+ 0
+ ].usVoltageValue);
+ return 0;
+ }
+ }
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return -EINVAL;
+ }
+
+ }
+ return -EINVAL;
+}
+
+int radeon_atom_get_voltage_step(struct radeon_device *rdev,
+ u8 voltage_type, u16 *voltage_step)
+{
+ int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo);
+ u8 frev, crev;
+ u16 data_offset, size;
+ union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+
+ switch (crev) {
+ case 1:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v1(&voltage_info->v1, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA *formula =
+ &voltage_object->v1.asFormula;
+ if (formula->ucFlag & 1)
+ *voltage_step =
+ (le16_to_cpu(formula->usVoltageStep) + 1) / 2;
+ else
+ *voltage_step =
+ le16_to_cpu(formula->usVoltageStep);
+ return 0;
+ }
+ break;
+ case 2:
+ return -EINVAL;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return -EINVAL;
+ }
+
+ }
+ return -EINVAL;
+}
+
+int radeon_atom_round_to_true_voltage(struct radeon_device *rdev,
+ u8 voltage_type,
+ u16 nominal_voltage,
+ u16 *true_voltage)
+{
+ u16 min_voltage, max_voltage, voltage_step;
+
+ if (radeon_atom_get_max_voltage(rdev, voltage_type, &max_voltage))
+ return -EINVAL;
+ if (radeon_atom_get_min_voltage(rdev, voltage_type, &min_voltage))
+ return -EINVAL;
+ if (radeon_atom_get_voltage_step(rdev, voltage_type, &voltage_step))
+ return -EINVAL;
+
+ if (nominal_voltage <= min_voltage)
+ *true_voltage = min_voltage;
+ else if (nominal_voltage >= max_voltage)
+ *true_voltage = max_voltage;
+ else
+ *true_voltage = min_voltage +
+ ((nominal_voltage - min_voltage) / voltage_step) *
+ voltage_step;
+
+ return 0;
+}
+
+int radeon_atom_get_voltage_table(struct radeon_device *rdev,
+ 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, ret;
+ union voltage_object_info *voltage_info;
+ union voltage_object *voltage_object = NULL;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ voltage_info = (union voltage_object_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+
+ switch (frev) {
+ case 1:
+ case 2:
+ switch (crev) {
+ case 1:
+ DRM_ERROR("old table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ case 2:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v2(&voltage_info->v2, voltage_type);
+ if (voltage_object) {
+ ATOM_VOLTAGE_FORMULA_V2 *formula =
+ &voltage_object->v2.asFormula;
+ if (formula->ucNumOfVoltageEntries > MAX_VOLTAGE_ENTRIES)
+ return -EINVAL;
+ for (i = 0; i < formula->ucNumOfVoltageEntries; i++) {
+ voltage_table->entries[i].value =
+ le16_to_cpu(formula->asVIDAdjustEntries[i].usVoltageValue);
+ ret = radeon_atom_get_voltage_gpio_settings(rdev,
+ voltage_table->entries[i].value,
+ voltage_type,
+ &voltage_table->entries[i].smio_low,
+ &voltage_table->mask_low);
+ if (ret)
+ return ret;
+ }
+ voltage_table->count = formula->ucNumOfVoltageEntries;
+ return 0;
+ }
+ break;
+ default:
+ DRM_ERROR("unknown voltage object table\n");
+ return -EINVAL;
+ }
+ break;
+ case 3:
+ switch (crev) {
+ case 1:
+ voltage_object = (union voltage_object *)
+ atom_lookup_voltage_object_v3(&voltage_info->v3,
+ voltage_type, voltage_mode);
+ if (voltage_object) {
+ ATOM_GPIO_VOLTAGE_OBJECT_V3 *gpio =
+ &voltage_object->v3.asGpioVoltageObj;
+ if (gpio->ucGpioEntryNum > MAX_VOLTAGE_ENTRIES)
+ return -EINVAL;
+ for (i = 0; i < gpio->ucGpioEntryNum; i++) {
+ voltage_table->entries[i].value =
+ le16_to_cpu(gpio->asVolGpioLut[i].usVoltageValue);
+ voltage_table->entries[i].smio_low =
+ le32_to_cpu(gpio->asVolGpioLut[i].ulVoltageId);
+ }
+ 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;
+};
+
+int radeon_atom_get_memory_info(struct radeon_device *rdev,
+ u8 module_index, struct atom_memory_info *mem_info)
+{
+ int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
+ u8 frev, crev, i;
+ u16 data_offset, size;
+ union vram_info *vram_info;
+ u8 *p;
+
+ memset(mem_info, 0, sizeof(struct atom_memory_info));
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ vram_info = (union vram_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 3:
+ /* r6xx */
+ if (module_index < vram_info->v1_3.ucNumOfVRAMModule) {
+ ATOM_VRAM_MODULE_V3 *vram_module =
+ (ATOM_VRAM_MODULE_V3 *)vram_info->v1_3.aVramInfo;
+ p = (u8 *)vram_info->v1_3.aVramInfo;
+
+ for (i = 0; i < module_index; i++) {
+ vram_module = (ATOM_VRAM_MODULE_V3 *)p;
+ if (le16_to_cpu(vram_module->usSize) == 0)
+ return -EINVAL;
+ p += le16_to_cpu(vram_module->usSize);
+ }
+ mem_info->mem_vendor = vram_module->asMemory.ucMemoryVenderID & 0xf;
+ mem_info->mem_type = vram_module->asMemory.ucMemoryType & 0xf0;
+ } else
+ return -EINVAL;
+ break;
+ case 4:
+ /* r7xx, evergreen */
+ if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
+ ATOM_VRAM_MODULE_V4 *vram_module =
+ (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
+ p = (u8 *)vram_info->v1_4.aVramInfo;
+
+ for (i = 0; i < module_index; i++) {
+ vram_module = (ATOM_VRAM_MODULE_V4 *)p;
+ if (le16_to_cpu(vram_module->usModuleSize) == 0)
+ return -EINVAL;
+ p += le16_to_cpu(vram_module->usModuleSize);
+ }
+ mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
+ mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
+ } else
+ return -EINVAL;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ switch (crev) {
+ case 1:
+ /* ni */
+ if (module_index < vram_info->v2_1.ucNumOfVRAMModule) {
+ ATOM_VRAM_MODULE_V7 *vram_module =
+ (ATOM_VRAM_MODULE_V7 *)vram_info->v2_1.aVramInfo;
+ p = (u8 *)vram_info->v2_1.aVramInfo;
+
+ for (i = 0; i < module_index; i++) {
+ vram_module = (ATOM_VRAM_MODULE_V7 *)p;
+ if (le16_to_cpu(vram_module->usModuleSize) == 0)
+ return -EINVAL;
+ p += le16_to_cpu(vram_module->usModuleSize);
+ }
+ mem_info->mem_vendor = vram_module->ucMemoryVenderID & 0xf;
+ mem_info->mem_type = vram_module->ucMemoryType & 0xf0;
+ } 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;
+}
+
+int radeon_atom_get_mclk_range_table(struct radeon_device *rdev,
+ bool gddr5, u8 module_index,
+ struct atom_memory_clock_range_table *mclk_range_table)
+{
+ int index = GetIndexIntoMasterTable(DATA, VRAM_Info);
+ u8 frev, crev, i;
+ u16 data_offset, size;
+ union vram_info *vram_info;
+ u32 mem_timing_size = gddr5 ?
+ sizeof(ATOM_MEMORY_TIMING_FORMAT_V2) : sizeof(ATOM_MEMORY_TIMING_FORMAT);
+ u8 *p;
+
+ memset(mclk_range_table, 0, sizeof(struct atom_memory_clock_range_table));
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ vram_info = (union vram_info *)
+ (rdev->mode_info.atom_context->bios + data_offset);
+ switch (frev) {
+ case 1:
+ switch (crev) {
+ case 3:
+ DRM_ERROR("old table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ case 4:
+ /* r7xx, evergreen */
+ if (module_index < vram_info->v1_4.ucNumOfVRAMModule) {
+ ATOM_VRAM_MODULE_V4 *vram_module =
+ (ATOM_VRAM_MODULE_V4 *)vram_info->v1_4.aVramInfo;
+ ATOM_MEMORY_TIMING_FORMAT *format;
+ p = (u8 *)vram_info->v1_4.aVramInfo;
+
+ for (i = 0; i < module_index; i++) {
+ vram_module = (ATOM_VRAM_MODULE_V4 *)p;
+ if (le16_to_cpu(vram_module->usModuleSize) == 0)
+ return -EINVAL;
+ p += le16_to_cpu(vram_module->usModuleSize);
+ }
+ mclk_range_table->num_entries = (u8)
+ ((vram_module->usModuleSize - offsetof(ATOM_VRAM_MODULE_V4, asMemTiming)) /
+ mem_timing_size);
+ p = (u8 *)vram_module->asMemTiming;
+ for (i = 0; i < mclk_range_table->num_entries; i++) {
+ format = (ATOM_MEMORY_TIMING_FORMAT *)p;
+ mclk_range_table->mclk[i] = le32_to_cpu(format->ulClkRange);
+ p += mem_timing_size;
+ }
+ } else
+ return -EINVAL;
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ DRM_ERROR("new table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return -EINVAL;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+#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 radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
+ 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 (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ vram_info = (union vram_info *)
+ (rdev->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));
+ 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 (!(reg_block->asRegIndexBuf[i].ucPreRegDataLength & ACCESS_PLACEHOLDER) &&
+ (i < num_entries)) {
+ reg_table->mc_reg_address[i].s1 =
+ (u16)(le16_to_cpu(reg_block->asRegIndexBuf[i].usRegIndex));
+ reg_table->mc_reg_address[i].pre_reg_data =
+ (u8)(reg_block->asRegIndexBuf[i].ucPreRegDataLength);
+ i++;
+ }
+ reg_table->last = i;
+ while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) &&
+ (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
+ t_mem_id = (u8)((*(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)((*(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)*((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 (*(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 radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 7e265a58141f..13a130fb3517 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -106,7 +106,7 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
radeon_bo_list_add_object(&p->relocs[i].lobj,
&p->validated);
}
- return radeon_bo_list_validate(&p->validated, p->ring);
+ return radeon_bo_list_validate(&p->ticket, &p->validated, p->ring);
}
static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
@@ -314,15 +314,17 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
* If error is set than unvalidate buffer, otherwise just free memory
* used by parsing context.
**/
-static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
+static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bool backoff)
{
unsigned i;
if (!error) {
- ttm_eu_fence_buffer_objects(&parser->validated,
+ ttm_eu_fence_buffer_objects(&parser->ticket,
+ &parser->validated,
parser->ib.fence);
- } else {
- ttm_eu_backoff_reservation(&parser->validated);
+ } else if (backoff) {
+ ttm_eu_backoff_reservation(&parser->ticket,
+ &parser->validated);
}
if (parser->relocs != NULL) {
@@ -535,7 +537,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
r = radeon_cs_parser_init(&parser, data);
if (r) {
DRM_ERROR("Failed to initialize parser !\n");
- radeon_cs_parser_fini(&parser, r);
+ radeon_cs_parser_fini(&parser, r, false);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r);
return r;
@@ -544,12 +546,13 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to parse relocation %d!\n", r);
- radeon_cs_parser_fini(&parser, r);
+ radeon_cs_parser_fini(&parser, r, false);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r);
return r;
}
+ /* XXX pick SD/HD/MVC */
if (parser.ring == R600_RING_TYPE_UVD_INDEX)
radeon_uvd_note_usage(rdev);
@@ -562,7 +565,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
goto out;
}
out:
- radeon_cs_parser_fini(&parser, r);
+ radeon_cs_parser_fini(&parser, r, true);
up_read(&rdev->exclusive_lock);
r = radeon_cs_handle_lockup(rdev, r);
return r;
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index b097d5b4ff39..9630e8d95fb4 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -27,9 +27,6 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
-#define CURSOR_WIDTH 64
-#define CURSOR_HEIGHT 64
-
static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
{
struct radeon_device *rdev = crtc->dev->dev_private;
@@ -167,7 +164,8 @@ int radeon_crtc_cursor_set(struct drm_crtc *crtc,
goto unpin;
}
- if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+ if ((width > radeon_crtc->max_cursor_width) ||
+ (height > radeon_crtc->max_cursor_height)) {
DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
return -EINVAL;
}
@@ -233,11 +231,11 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
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, CURSOR_WIDTH - 1);
+ xorigin = min(-x, radeon_crtc->max_cursor_width - 1);
x = 0;
}
if (y < 0) {
- yorigin = min(-y, CURSOR_HEIGHT - 1);
+ yorigin = min(-y, radeon_crtc->max_cursor_height - 1);
y = 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index b0dc0b6cb4e0..82335e38ec4f 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -95,6 +95,9 @@ static const char radeon_family_name[][16] = {
"VERDE",
"OLAND",
"HAINAN",
+ "BONAIRE",
+ "KAVERI",
+ "KABINI",
"LAST",
};
@@ -229,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
}
/*
+ * GPU doorbell aperture helpers function.
+ */
+/**
+ * radeon_doorbell_init - Init doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Init doorbell driver information (CIK)
+ * Returns 0 on success, error on failure.
+ */
+int radeon_doorbell_init(struct radeon_device *rdev)
+{
+ int i;
+
+ /* doorbell bar mapping */
+ rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
+ rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
+
+ /* limit to 4 MB for now */
+ if (rdev->doorbell.size > (4 * 1024 * 1024))
+ rdev->doorbell.size = 4 * 1024 * 1024;
+
+ rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
+ if (rdev->doorbell.ptr == NULL) {
+ return -ENOMEM;
+ }
+ DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
+ DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
+
+ rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
+
+ for (i = 0; i < rdev->doorbell.num_pages; i++) {
+ rdev->doorbell.free[i] = true;
+ }
+ return 0;
+}
+
+/**
+ * radeon_doorbell_fini - Tear down doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down doorbell driver information (CIK)
+ */
+void radeon_doorbell_fini(struct radeon_device *rdev)
+{
+ iounmap(rdev->doorbell.ptr);
+ rdev->doorbell.ptr = NULL;
+}
+
+/**
+ * radeon_doorbell_get - Allocate a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Allocate a doorbell page for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
+{
+ int i;
+
+ for (i = 0; i < rdev->doorbell.num_pages; i++) {
+ if (rdev->doorbell.free[i]) {
+ rdev->doorbell.free[i] = false;
+ *doorbell = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/**
+ * radeon_doorbell_free - Free a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Free a doorbell page allocated for use by the driver (all asics)
+ */
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
+{
+ if (doorbell < rdev->doorbell.num_pages)
+ rdev->doorbell.free[doorbell] = true;
+}
+
+/*
* radeon_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,
@@ -1145,8 +1236,13 @@ int radeon_device_init(struct radeon_device *rdev,
/* Registers mapping */
/* TODO: block userspace mapping of io register */
spin_lock_init(&rdev->mmio_idx_lock);
- rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
- rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
+ if (rdev->family >= CHIP_BONAIRE) {
+ rdev->rmmio_base = pci_resource_start(rdev->pdev, 5);
+ rdev->rmmio_size = pci_resource_len(rdev->pdev, 5);
+ } else {
+ rdev->rmmio_base = pci_resource_start(rdev->pdev, 2);
+ rdev->rmmio_size = pci_resource_len(rdev->pdev, 2);
+ }
rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
if (rdev->rmmio == NULL) {
return -ENOMEM;
@@ -1154,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
+ /* doorbell bar mapping */
+ if (rdev->family >= CHIP_BONAIRE)
+ radeon_doorbell_init(rdev);
+
/* io port mapping */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
@@ -1231,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
rdev->rio_mem = NULL;
iounmap(rdev->rmmio);
rdev->rmmio = NULL;
+ if (rdev->family >= CHIP_BONAIRE)
+ radeon_doorbell_fini(rdev);
radeon_debugfs_remove_files(rdev);
}
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index eb18bb7af1cc..c2b67b4e1ac2 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -153,7 +153,13 @@ static void dce5_crtc_load_lut(struct drm_crtc *crtc)
NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS)));
/* XXX match this to the depth of the crtc fmt block, move to modeset? */
WREG32(0x6940 + radeon_crtc->crtc_offset, 0);
-
+ if (ASIC_IS_DCE8(rdev)) {
+ /* XXX this only needs to be programmed once per crtc at startup,
+ * not sure where the best place for it is
+ */
+ WREG32(CIK_ALPHA_CONTROL + radeon_crtc->crtc_offset,
+ CIK_CURSOR_ALPHA_BLND_ENA);
+ }
}
static void legacy_crtc_load_lut(struct drm_crtc *crtc)
@@ -512,6 +518,14 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
radeon_crtc->crtc_id = index;
rdev->mode_info.crtcs[index] = radeon_crtc;
+ if (rdev->family >= CHIP_BONAIRE) {
+ radeon_crtc->max_cursor_width = CIK_CURSOR_WIDTH;
+ radeon_crtc->max_cursor_height = CIK_CURSOR_HEIGHT;
+ } else {
+ radeon_crtc->max_cursor_width = CURSOR_WIDTH;
+ radeon_crtc->max_cursor_height = CURSOR_HEIGHT;
+ }
+
#if 0
radeon_crtc->mode_set.crtc = &radeon_crtc->base;
radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
@@ -530,7 +544,7 @@ static void radeon_crtc_init(struct drm_device *dev, int index)
radeon_legacy_init_crtc(dev, radeon_crtc);
}
-static const char *encoder_names[37] = {
+static const char *encoder_names[38] = {
"NONE",
"INTERNAL_LVDS",
"INTERNAL_TMDS1",
@@ -567,7 +581,8 @@ static const char *encoder_names[37] = {
"INTERNAL_UNIPHY2",
"NUTMEG",
"TRAVIS",
- "INTERNAL_VCE"
+ "INTERNAL_VCE",
+ "INTERNAL_UNIPHY3",
};
static const char *hpd_names[6] = {
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 094e7e5ea39e..e5419b350170 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -74,9 +74,10 @@
* 2.31.0 - Add fastfb support for rs690
* 2.32.0 - new info request for rings working
* 2.33.0 - Add SI tiling mode array query
+ * 2.34.0 - Add CIK tiling mode array query
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 33
+#define KMS_DRIVER_MINOR 34
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
@@ -127,6 +128,7 @@ struct drm_gem_object *radeon_gem_prime_import_sg_table(struct drm_device *dev,
size_t size,
struct sg_table *sg);
int radeon_gem_prime_pin(struct drm_gem_object *obj);
+void radeon_gem_prime_unpin(struct drm_gem_object *obj);
void *radeon_gem_prime_vmap(struct drm_gem_object *obj);
void radeon_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
extern long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd,
@@ -164,6 +166,7 @@ int radeon_pcie_gen2 = -1;
int radeon_msi = -1;
int radeon_lockup_timeout = 10000;
int radeon_fastfb = 0;
+int radeon_dpm = -1;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -219,6 +222,9 @@ module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
MODULE_PARM_DESC(fastfb, "Direct FB access for IGP chips (0 = disable, 1 = enable)");
module_param_named(fastfb, radeon_fastfb, int, 0444);
+MODULE_PARM_DESC(dpm, "DPM support (1 = enable, 0 = disable, -1 = auto)");
+module_param_named(dpm, radeon_dpm, int, 0444);
+
static struct pci_device_id pciidlist[] = {
radeon_PCI_IDS
};
@@ -422,6 +428,7 @@ static struct drm_driver kms_driver = {
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_pin = radeon_gem_prime_pin,
+ .gem_prime_unpin = radeon_gem_prime_unpin,
.gem_prime_get_sg_table = radeon_gem_prime_get_sg_table,
.gem_prime_import_sg_table = radeon_gem_prime_import_sg_table,
.gem_prime_vmap = radeon_gem_prime_vmap,
diff --git a/drivers/gpu/drm/radeon/radeon_family.h b/drivers/gpu/drm/radeon/radeon_family.h
index 36e9803b077d..3c8289083f9d 100644
--- a/drivers/gpu/drm/radeon/radeon_family.h
+++ b/drivers/gpu/drm/radeon/radeon_family.h
@@ -93,6 +93,9 @@ enum radeon_family {
CHIP_VERDE,
CHIP_OLAND,
CHIP_HAINAN,
+ CHIP_BONAIRE,
+ CHIP_KAVERI,
+ CHIP_KABINI,
CHIP_LAST,
};
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index b1746741bc59..665ced3b7313 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -230,7 +230,7 @@ static int radeonfb_create(struct drm_fb_helper *helper,
ret = radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
if (ret) {
- DRM_ERROR("failed to initalise framebuffer %d\n", ret);
+ DRM_ERROR("failed to initialize framebuffer %d\n", ret);
goto out_unref;
}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 5a99d433fc35..bcdefd1dcd43 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -82,6 +82,23 @@ static void radeon_hotplug_work_func(struct work_struct *work)
}
/**
+ * radeon_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 radeon_irq_reset_work_func(struct work_struct *work)
+{
+ struct radeon_device *rdev = container_of(work, struct radeon_device,
+ reset_work);
+
+ radeon_gpu_reset(rdev);
+}
+
+/**
* radeon_driver_irq_preinstall_kms - drm irq preinstall callback
*
* @dev: drm dev pointer
@@ -99,6 +116,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
/* Disable *all* interrupts */
for (i = 0; i < RADEON_NUM_RINGS; i++)
atomic_set(&rdev->irq.ring_int[i], 0);
+ rdev->irq.dpm_thermal = false;
for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
rdev->irq.hpd[i] = false;
for (i = 0; i < RADEON_MAX_CRTCS; i++) {
@@ -146,6 +164,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
/* Disable *all* interrupts */
for (i = 0; i < RADEON_NUM_RINGS; i++)
atomic_set(&rdev->irq.ring_int[i], 0);
+ rdev->irq.dpm_thermal = false;
for (i = 0; i < RADEON_MAX_HPD_PINS; i++)
rdev->irq.hpd[i] = false;
for (i = 0; i < RADEON_MAX_CRTCS; i++) {
@@ -243,6 +262,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
+ INIT_WORK(&rdev->reset_work, radeon_irq_reset_work_func);
spin_lock_init(&rdev->irq.lock);
r = drm_vblank_init(rdev->ddev, rdev->num_crtc);
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 4f2d4f4c1dab..49ff3d1a6102 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -229,7 +229,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*value = rdev->accel_working;
break;
case RADEON_INFO_TILING_CONFIG:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ *value = rdev->config.cik.tile_config;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.tile_config;
else if (rdev->family >= CHIP_CAYMAN)
*value = rdev->config.cayman.tile_config;
@@ -281,7 +283,10 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*value = rdev->clock.spll.reference_freq * 10;
break;
case RADEON_INFO_NUM_BACKENDS:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ *value = rdev->config.cik.max_backends_per_se *
+ rdev->config.cik.max_shader_engines;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.max_backends_per_se *
rdev->config.si.max_shader_engines;
else if (rdev->family >= CHIP_CAYMAN)
@@ -298,7 +303,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
break;
case RADEON_INFO_NUM_TILE_PIPES:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ *value = rdev->config.cik.max_tile_pipes;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.max_tile_pipes;
else if (rdev->family >= CHIP_CAYMAN)
*value = rdev->config.cayman.max_tile_pipes;
@@ -316,7 +323,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*value = 1;
break;
case RADEON_INFO_BACKEND_MAP:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ return -EINVAL;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.backend_map;
else if (rdev->family >= CHIP_CAYMAN)
*value = rdev->config.cayman.backend_map;
@@ -343,7 +352,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*value = RADEON_IB_VM_MAX_SIZE;
break;
case RADEON_INFO_MAX_PIPES:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ *value = rdev->config.cik.max_cu_per_sh;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.max_cu_per_sh;
else if (rdev->family >= CHIP_CAYMAN)
*value = rdev->config.cayman.max_pipes_per_simd;
@@ -367,7 +378,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
value64 = radeon_get_gpu_clock_counter(rdev);
break;
case RADEON_INFO_MAX_SE:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ *value = rdev->config.cik.max_shader_engines;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.max_shader_engines;
else if (rdev->family >= CHIP_CAYMAN)
*value = rdev->config.cayman.max_shader_engines;
@@ -377,7 +390,9 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
*value = 1;
break;
case RADEON_INFO_MAX_SH_PER_SE:
- if (rdev->family >= CHIP_TAHITI)
+ if (rdev->family >= CHIP_BONAIRE)
+ *value = rdev->config.cik.max_sh_per_se;
+ else if (rdev->family >= CHIP_TAHITI)
*value = rdev->config.si.max_sh_per_se;
else
return -EINVAL;
@@ -407,12 +422,16 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
break;
case RADEON_INFO_SI_TILE_MODE_ARRAY:
- if (rdev->family < CHIP_TAHITI) {
- DRM_DEBUG_KMS("tile mode array is si only!\n");
+ if (rdev->family >= CHIP_BONAIRE) {
+ value = rdev->config.cik.tile_mode_array;
+ value_size = sizeof(uint32_t)*32;
+ } else if (rdev->family >= CHIP_TAHITI) {
+ value = rdev->config.si.tile_mode_array;
+ value_size = sizeof(uint32_t)*32;
+ } else {
+ DRM_DEBUG_KMS("tile mode array is si+ only!\n");
return -EINVAL;
}
- value = rdev->config.si.tile_mode_array;
- value_size = sizeof(uint32_t)*32;
break;
default:
DRM_DEBUG_KMS("Invalid request %d\n", info->request);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 69ad4fe224c1..8296632a4235 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -307,6 +307,8 @@ struct radeon_crtc {
uint64_t cursor_addr;
int cursor_width;
int cursor_height;
+ int max_cursor_width;
+ int max_cursor_height;
uint32_t legacy_display_base_addr;
uint32_t legacy_cursor_offset;
enum radeon_rmx_type rmx_type;
@@ -329,6 +331,11 @@ struct radeon_crtc {
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 radeon_encoder_primary_dac {
@@ -512,12 +519,99 @@ struct atom_clock_dividers {
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];
};
extern enum radeon_tv_std
radeon_combios_get_tv_info(struct radeon_device *rdev);
extern enum radeon_tv_std
radeon_atombios_get_tv_info(struct radeon_device *rdev);
+extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
+ u16 *vddc, u16 *vddci, u16 *mvdd);
extern struct drm_connector *
radeon_get_connector_for_encoder(struct drm_encoder *encoder);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 1424ccde2377..0219d263e2df 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -322,8 +322,8 @@ int radeon_bo_init(struct radeon_device *rdev)
{
/* Add an MTRR for the VRAM */
if (!rdev->fastfb_working) {
- rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size,
- MTRR_TYPE_WRCOMB, 1);
+ rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
+ rdev->mc.aper_size);
}
DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
rdev->mc.mc_vram_size >> 20,
@@ -336,6 +336,7 @@ int radeon_bo_init(struct radeon_device *rdev)
void radeon_bo_fini(struct radeon_device *rdev)
{
radeon_ttm_fini(rdev);
+ arch_phys_wc_del(rdev->mc.vram_mtrr);
}
void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
@@ -348,14 +349,15 @@ void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
}
}
-int radeon_bo_list_validate(struct list_head *head, int ring)
+int radeon_bo_list_validate(struct ww_acquire_ctx *ticket,
+ struct list_head *head, int ring)
{
struct radeon_bo_list *lobj;
struct radeon_bo *bo;
u32 domain;
int r;
- r = ttm_eu_reserve_buffers(head);
+ r = ttm_eu_reserve_buffers(ticket, head);
if (unlikely(r != 0)) {
return r;
}
@@ -398,7 +400,7 @@ int radeon_bo_get_surface_reg(struct radeon_bo *bo)
int steal;
int i;
- BUG_ON(!radeon_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->tbo.resv->lock.base);
if (!bo->tiling_flags)
return 0;
@@ -524,7 +526,8 @@ void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
uint32_t *tiling_flags,
uint32_t *pitch)
{
- BUG_ON(!radeon_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->tbo.resv->lock.base);
+
if (tiling_flags)
*tiling_flags = bo->tiling_flags;
if (pitch)
@@ -534,7 +537,8 @@ void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
bool force_drop)
{
- BUG_ON(!radeon_bo_is_reserved(bo) && !force_drop);
+ if (!force_drop)
+ lockdep_assert_held(&bo->tbo.resv->lock.base);
if (!(bo->tiling_flags & RADEON_TILING_SURFACE))
return 0;
@@ -617,26 +621,3 @@ int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)
ttm_bo_unreserve(&bo->tbo);
return r;
}
-
-
-/**
- * radeon_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.
- */
-int radeon_bo_reserve(struct radeon_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->rdev->dev, "%p reserve failed\n", bo);
- return r;
- }
- return 0;
-}
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index e2cb80a96b51..91519a5622b4 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -52,7 +52,27 @@ static inline unsigned radeon_mem_type_to_domain(u32 mem_type)
return 0;
}
-int radeon_bo_reserve(struct radeon_bo *bo, bool no_intr);
+/**
+ * radeon_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 radeon_bo_reserve(struct radeon_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->rdev->dev, "%p reserve failed\n", bo);
+ return r;
+ }
+ return 0;
+}
static inline void radeon_bo_unreserve(struct radeon_bo *bo)
{
@@ -78,11 +98,6 @@ static inline unsigned long radeon_bo_size(struct radeon_bo *bo)
return bo->tbo.num_pages << PAGE_SHIFT;
}
-static inline bool radeon_bo_is_reserved(struct radeon_bo *bo)
-{
- return ttm_bo_is_reserved(&bo->tbo);
-}
-
static inline unsigned radeon_bo_ngpu_pages(struct radeon_bo *bo)
{
return (bo->tbo.num_pages << PAGE_SHIFT) / RADEON_GPU_PAGE_SIZE;
@@ -128,7 +143,8 @@ extern int radeon_bo_init(struct radeon_device *rdev);
extern void radeon_bo_fini(struct radeon_device *rdev);
extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
struct list_head *head);
-extern int radeon_bo_list_validate(struct list_head *head, int ring);
+extern int radeon_bo_list_validate(struct ww_acquire_ctx *ticket,
+ struct list_head *head, int ring);
extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
struct vm_area_struct *vma);
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 788c64cb4b47..f374c467aaca 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -388,7 +388,8 @@ static ssize_t radeon_get_pm_method(struct device *dev,
int pm = rdev->pm.pm_method;
return snprintf(buf, PAGE_SIZE, "%s\n",
- (pm == PM_METHOD_DYNPM) ? "dynpm" : "profile");
+ (pm == PM_METHOD_DYNPM) ? "dynpm" :
+ (pm == PM_METHOD_PROFILE) ? "profile" : "dpm");
}
static ssize_t radeon_set_pm_method(struct device *dev,
@@ -399,6 +400,11 @@ static ssize_t radeon_set_pm_method(struct device *dev,
struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
struct radeon_device *rdev = ddev->dev_private;
+ /* we don't support the legacy modes with dpm */
+ if (rdev->pm.pm_method == PM_METHOD_DPM) {
+ count = -EINVAL;
+ goto fail;
+ }
if (strncmp("dynpm", buf, strlen("dynpm")) == 0) {
mutex_lock(&rdev->pm.mutex);
@@ -423,8 +429,96 @@ fail:
return count;
}
+static ssize_t radeon_get_dpm_state(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct radeon_device *rdev = ddev->dev_private;
+ enum radeon_pm_state_type pm = rdev->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 radeon_set_dpm_state(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct radeon_device *rdev = ddev->dev_private;
+
+ mutex_lock(&rdev->pm.mutex);
+ if (strncmp("battery", buf, strlen("battery")) == 0)
+ rdev->pm.dpm.user_state = POWER_STATE_TYPE_BATTERY;
+ else if (strncmp("balanced", buf, strlen("balanced")) == 0)
+ rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+ else if (strncmp("performance", buf, strlen("performance")) == 0)
+ rdev->pm.dpm.user_state = POWER_STATE_TYPE_PERFORMANCE;
+ else {
+ mutex_unlock(&rdev->pm.mutex);
+ count = -EINVAL;
+ goto fail;
+ }
+ mutex_unlock(&rdev->pm.mutex);
+ radeon_pm_compute_clocks(rdev);
+fail:
+ return count;
+}
+
+static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct radeon_device *rdev = ddev->dev_private;
+ enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ (level == RADEON_DPM_FORCED_LEVEL_AUTO) ? "auto" :
+ (level == RADEON_DPM_FORCED_LEVEL_LOW) ? "low" : "high");
+}
+
+static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+ struct radeon_device *rdev = ddev->dev_private;
+ enum radeon_dpm_forced_level level;
+ int ret = 0;
+
+ mutex_lock(&rdev->pm.mutex);
+ if (strncmp("low", buf, strlen("low")) == 0) {
+ level = RADEON_DPM_FORCED_LEVEL_LOW;
+ } else if (strncmp("high", buf, strlen("high")) == 0) {
+ level = RADEON_DPM_FORCED_LEVEL_HIGH;
+ } else if (strncmp("auto", buf, strlen("auto")) == 0) {
+ level = RADEON_DPM_FORCED_LEVEL_AUTO;
+ } else {
+ mutex_unlock(&rdev->pm.mutex);
+ count = -EINVAL;
+ goto fail;
+ }
+ if (rdev->asic->dpm.force_performance_level) {
+ ret = radeon_dpm_force_performance_level(rdev, level);
+ if (ret)
+ count = -EINVAL;
+ }
+ mutex_unlock(&rdev->pm.mutex);
+fail:
+ return count;
+}
+
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
+static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
+static DEVICE_ATTR(power_dpm_force_performance_level, S_IRUGO | S_IWUSR,
+ radeon_get_dpm_forced_performance_level,
+ radeon_set_dpm_forced_performance_level);
static ssize_t radeon_hwmon_show_temp(struct device *dev,
struct device_attribute *attr,
@@ -434,27 +528,10 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
struct radeon_device *rdev = ddev->dev_private;
int temp;
- switch (rdev->pm.int_thermal_type) {
- case THERMAL_TYPE_RV6XX:
- temp = rv6xx_get_temp(rdev);
- break;
- case THERMAL_TYPE_RV770:
- temp = rv770_get_temp(rdev);
- break;
- case THERMAL_TYPE_EVERGREEN:
- case THERMAL_TYPE_NI:
- temp = evergreen_get_temp(rdev);
- break;
- case THERMAL_TYPE_SUMO:
- temp = sumo_get_temp(rdev);
- break;
- case THERMAL_TYPE_SI:
- temp = si_get_temp(rdev);
- break;
- default:
+ if (rdev->asic->pm.get_temperature)
+ temp = radeon_get_temperature(rdev);
+ else
temp = 0;
- break;
- }
return snprintf(buf, PAGE_SIZE, "%d\n", temp);
}
@@ -492,8 +569,7 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
case THERMAL_TYPE_NI:
case THERMAL_TYPE_SUMO:
case THERMAL_TYPE_SI:
- /* No support for TN yet */
- if (rdev->family == CHIP_ARUBA)
+ if (rdev->asic->pm.get_temperature == NULL)
return err;
rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev);
if (IS_ERR(rdev->pm.int_hwmon_dev)) {
@@ -526,7 +602,289 @@ static void radeon_hwmon_fini(struct radeon_device *rdev)
}
}
-void radeon_pm_suspend(struct radeon_device *rdev)
+static void radeon_dpm_thermal_work_handler(struct work_struct *work)
+{
+ struct radeon_device *rdev =
+ container_of(work, struct radeon_device,
+ pm.dpm.thermal.work);
+ /* switch to the thermal state */
+ enum radeon_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
+
+ if (!rdev->pm.dpm_enabled)
+ return;
+
+ if (rdev->asic->pm.get_temperature) {
+ int temp = radeon_get_temperature(rdev);
+
+ if (temp < rdev->pm.dpm.thermal.min_temp)
+ /* switch back the user state */
+ dpm_state = rdev->pm.dpm.user_state;
+ } else {
+ if (rdev->pm.dpm.thermal.high_to_low)
+ /* switch back the user state */
+ dpm_state = rdev->pm.dpm.user_state;
+ }
+ radeon_dpm_enable_power_state(rdev, dpm_state);
+}
+
+static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
+ enum radeon_pm_state_type dpm_state)
+{
+ int i;
+ struct radeon_ps *ps;
+ u32 ui_class;
+ bool single_display = (rdev->pm.dpm.new_active_crtc_count < 2) ?
+ true : false;
+
+ /* check if the vblank period is too short to adjust the mclk */
+ if (single_display && rdev->asic->dpm.vblank_too_short) {
+ if (radeon_dpm_vblank_too_short(rdev))
+ 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 < rdev->pm.dpm.num_ps; i++) {
+ ps = &rdev->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:
+ return rdev->pm.dpm.uvd_ps;
+ 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 rdev->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:
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+ case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+ return rdev->pm.dpm.uvd_ps;
+ 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 radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
+{
+ int i;
+ struct radeon_ps *ps;
+ enum radeon_pm_state_type dpm_state;
+ int ret;
+
+ /* if dpm init failed */
+ if (!rdev->pm.dpm_enabled)
+ return;
+
+ if (rdev->pm.dpm.user_state != rdev->pm.dpm.state) {
+ /* add other state override checks here */
+ if ((!rdev->pm.dpm.thermal_active) &&
+ (!rdev->pm.dpm.uvd_active))
+ rdev->pm.dpm.state = rdev->pm.dpm.user_state;
+ }
+ dpm_state = rdev->pm.dpm.state;
+
+ ps = radeon_dpm_pick_power_state(rdev, dpm_state);
+ if (ps)
+ rdev->pm.dpm.requested_ps = ps;
+ else
+ return;
+
+ /* no need to reprogram if nothing changed unless we are on BTC+ */
+ if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) {
+ if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
+ /* for pre-BTC and APUs if the num crtcs changed but state is the same,
+ * all we need to do is update the display configuration.
+ */
+ if (rdev->pm.dpm.new_active_crtcs != rdev->pm.dpm.current_active_crtcs) {
+ /* update display watermarks based on new power state */
+ radeon_bandwidth_update(rdev);
+ /* update displays */
+ radeon_dpm_display_configuration_changed(rdev);
+ rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+ rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+ }
+ 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 (rdev->pm.dpm.new_active_crtcs ==
+ rdev->pm.dpm.current_active_crtcs) {
+ return;
+ } else {
+ if ((rdev->pm.dpm.current_active_crtc_count > 1) &&
+ (rdev->pm.dpm.new_active_crtc_count > 1)) {
+ /* update display watermarks based on new power state */
+ radeon_bandwidth_update(rdev);
+ /* update displays */
+ radeon_dpm_display_configuration_changed(rdev);
+ rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+ rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+ return;
+ }
+ }
+ }
+ }
+
+ printk("switching from power state:\n");
+ radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps);
+ printk("switching to power state:\n");
+ radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps);
+
+ mutex_lock(&rdev->ddev->struct_mutex);
+ down_write(&rdev->pm.mclk_lock);
+ mutex_lock(&rdev->ring_lock);
+
+ ret = radeon_dpm_pre_set_power_state(rdev);
+ if (ret)
+ goto done;
+
+ /* update display watermarks based on new power state */
+ radeon_bandwidth_update(rdev);
+ /* update displays */
+ radeon_dpm_display_configuration_changed(rdev);
+
+ rdev->pm.dpm.current_active_crtcs = rdev->pm.dpm.new_active_crtcs;
+ rdev->pm.dpm.current_active_crtc_count = rdev->pm.dpm.new_active_crtc_count;
+
+ /* wait for the rings to drain */
+ for (i = 0; i < RADEON_NUM_RINGS; i++) {
+ struct radeon_ring *ring = &rdev->ring[i];
+ if (ring->ready)
+ radeon_fence_wait_empty_locked(rdev, i);
+ }
+
+ /* program the new power state */
+ radeon_dpm_set_power_state(rdev);
+
+ /* update current power state */
+ rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps;
+
+ radeon_dpm_post_set_power_state(rdev);
+
+done:
+ mutex_unlock(&rdev->ring_lock);
+ up_write(&rdev->pm.mclk_lock);
+ mutex_unlock(&rdev->ddev->struct_mutex);
+}
+
+void radeon_dpm_enable_power_state(struct radeon_device *rdev,
+ enum radeon_pm_state_type dpm_state)
+{
+ if (!rdev->pm.dpm_enabled)
+ return;
+
+ mutex_lock(&rdev->pm.mutex);
+ switch (dpm_state) {
+ case POWER_STATE_TYPE_INTERNAL_THERMAL:
+ rdev->pm.dpm.thermal_active = true;
+ break;
+ case POWER_STATE_TYPE_INTERNAL_UVD:
+ case POWER_STATE_TYPE_INTERNAL_UVD_SD:
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD:
+ case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
+ case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
+ rdev->pm.dpm.uvd_active = true;
+ break;
+ default:
+ rdev->pm.dpm.thermal_active = false;
+ rdev->pm.dpm.uvd_active = false;
+ break;
+ }
+ rdev->pm.dpm.state = dpm_state;
+ mutex_unlock(&rdev->pm.mutex);
+ radeon_pm_compute_clocks(rdev);
+}
+
+static void radeon_pm_suspend_old(struct radeon_device *rdev)
{
mutex_lock(&rdev->pm.mutex);
if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
@@ -538,11 +896,30 @@ void radeon_pm_suspend(struct radeon_device *rdev)
cancel_delayed_work_sync(&rdev->pm.dynpm_idle_work);
}
-void radeon_pm_resume(struct radeon_device *rdev)
+static void radeon_pm_suspend_dpm(struct radeon_device *rdev)
+{
+ mutex_lock(&rdev->pm.mutex);
+ /* disable dpm */
+ radeon_dpm_disable(rdev);
+ /* reset the power state */
+ rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
+ rdev->pm.dpm_enabled = false;
+ mutex_unlock(&rdev->pm.mutex);
+}
+
+void radeon_pm_suspend(struct radeon_device *rdev)
+{
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_suspend_dpm(rdev);
+ else
+ radeon_pm_suspend_old(rdev);
+}
+
+static void radeon_pm_resume_old(struct radeon_device *rdev)
{
/* set up the default clocks if the MC ucode is loaded */
if ((rdev->family >= CHIP_BARTS) &&
- (rdev->family <= CHIP_CAYMAN) &&
+ (rdev->family <= CHIP_HAINAN) &&
rdev->mc_fw) {
if (rdev->pm.default_vddc)
radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -573,12 +950,50 @@ void radeon_pm_resume(struct radeon_device *rdev)
radeon_pm_compute_clocks(rdev);
}
-int radeon_pm_init(struct radeon_device *rdev)
+static void radeon_pm_resume_dpm(struct radeon_device *rdev)
+{
+ int ret;
+
+ /* asic init will reset to the boot state */
+ mutex_lock(&rdev->pm.mutex);
+ rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
+ radeon_dpm_setup_asic(rdev);
+ ret = radeon_dpm_enable(rdev);
+ mutex_unlock(&rdev->pm.mutex);
+ if (ret) {
+ DRM_ERROR("radeon: dpm resume failed\n");
+ if ((rdev->family >= CHIP_BARTS) &&
+ (rdev->family <= CHIP_HAINAN) &&
+ rdev->mc_fw) {
+ if (rdev->pm.default_vddc)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+ SET_VOLTAGE_TYPE_ASIC_VDDC);
+ if (rdev->pm.default_vddci)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+ SET_VOLTAGE_TYPE_ASIC_VDDCI);
+ if (rdev->pm.default_sclk)
+ radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+ if (rdev->pm.default_mclk)
+ radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+ }
+ } else {
+ rdev->pm.dpm_enabled = true;
+ radeon_pm_compute_clocks(rdev);
+ }
+}
+
+void radeon_pm_resume(struct radeon_device *rdev)
+{
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_resume_dpm(rdev);
+ else
+ radeon_pm_resume_old(rdev);
+}
+
+static int radeon_pm_init_old(struct radeon_device *rdev)
{
int ret;
- /* default to profile method */
- rdev->pm.pm_method = PM_METHOD_PROFILE;
rdev->pm.profile = PM_PROFILE_DEFAULT;
rdev->pm.dynpm_state = DYNPM_STATE_DISABLED;
rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
@@ -599,7 +1014,7 @@ int radeon_pm_init(struct radeon_device *rdev)
radeon_pm_init_profile(rdev);
/* set up the default clocks if the MC ucode is loaded */
if ((rdev->family >= CHIP_BARTS) &&
- (rdev->family <= CHIP_CAYMAN) &&
+ (rdev->family <= CHIP_HAINAN) &&
rdev->mc_fw) {
if (rdev->pm.default_vddc)
radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
@@ -640,7 +1055,145 @@ int radeon_pm_init(struct radeon_device *rdev)
return 0;
}
-void radeon_pm_fini(struct radeon_device *rdev)
+static void radeon_dpm_print_power_states(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ printk("== power state %d ==\n", i);
+ radeon_dpm_print_power_state(rdev, &rdev->pm.dpm.ps[i]);
+ }
+}
+
+static int radeon_pm_init_dpm(struct radeon_device *rdev)
+{
+ int ret;
+
+ /* default to performance state */
+ rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
+ rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+ rdev->pm.default_sclk = rdev->clock.default_sclk;
+ rdev->pm.default_mclk = rdev->clock.default_mclk;
+ rdev->pm.current_sclk = rdev->clock.default_sclk;
+ rdev->pm.current_mclk = rdev->clock.default_mclk;
+ rdev->pm.int_thermal_type = THERMAL_TYPE_NONE;
+
+ if (rdev->bios && rdev->is_atom_bios)
+ radeon_atombios_get_power_modes(rdev);
+ else
+ return -EINVAL;
+
+ /* set up the internal thermal sensor if applicable */
+ ret = radeon_hwmon_init(rdev);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&rdev->pm.dpm.thermal.work, radeon_dpm_thermal_work_handler);
+ mutex_lock(&rdev->pm.mutex);
+ radeon_dpm_init(rdev);
+ rdev->pm.dpm.current_ps = rdev->pm.dpm.requested_ps = rdev->pm.dpm.boot_ps;
+ radeon_dpm_print_power_states(rdev);
+ radeon_dpm_setup_asic(rdev);
+ ret = radeon_dpm_enable(rdev);
+ mutex_unlock(&rdev->pm.mutex);
+ if (ret) {
+ rdev->pm.dpm_enabled = false;
+ if ((rdev->family >= CHIP_BARTS) &&
+ (rdev->family <= CHIP_HAINAN) &&
+ rdev->mc_fw) {
+ if (rdev->pm.default_vddc)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+ SET_VOLTAGE_TYPE_ASIC_VDDC);
+ if (rdev->pm.default_vddci)
+ radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+ SET_VOLTAGE_TYPE_ASIC_VDDCI);
+ if (rdev->pm.default_sclk)
+ radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+ if (rdev->pm.default_mclk)
+ radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+ }
+ DRM_ERROR("radeon: dpm initialization failed\n");
+ return ret;
+ }
+ rdev->pm.dpm_enabled = true;
+ radeon_pm_compute_clocks(rdev);
+
+ if (rdev->pm.num_power_states > 1) {
+ ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
+ if (ret)
+ DRM_ERROR("failed to create device file for dpm state\n");
+ ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
+ if (ret)
+ DRM_ERROR("failed to create device file for dpm state\n");
+ /* XXX: these are noops for dpm but are here for backwards compat */
+ ret = device_create_file(rdev->dev, &dev_attr_power_profile);
+ if (ret)
+ DRM_ERROR("failed to create device file for power profile\n");
+ ret = device_create_file(rdev->dev, &dev_attr_power_method);
+ if (ret)
+ DRM_ERROR("failed to create device file for power method\n");
+
+ if (radeon_debugfs_pm_init(rdev)) {
+ DRM_ERROR("Failed to register debugfs file for dpm!\n");
+ }
+
+ DRM_INFO("radeon: dpm initialized\n");
+ }
+
+ return 0;
+}
+
+int radeon_pm_init(struct radeon_device *rdev)
+{
+ /* enable dpm on rv6xx+ */
+ switch (rdev->family) {
+ case CHIP_RV610:
+ case CHIP_RV630:
+ case CHIP_RV620:
+ case CHIP_RV635:
+ case CHIP_RV670:
+ case CHIP_RS780:
+ case CHIP_RS880:
+ case CHIP_RV770:
+ case CHIP_RV730:
+ case CHIP_RV710:
+ case CHIP_RV740:
+ case CHIP_CEDAR:
+ case CHIP_REDWOOD:
+ case CHIP_JUNIPER:
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ case CHIP_PALM:
+ case CHIP_SUMO:
+ case CHIP_SUMO2:
+ case CHIP_BARTS:
+ case CHIP_TURKS:
+ case CHIP_CAICOS:
+ case CHIP_CAYMAN:
+ case CHIP_ARUBA:
+ case CHIP_TAHITI:
+ case CHIP_PITCAIRN:
+ case CHIP_VERDE:
+ case CHIP_OLAND:
+ case CHIP_HAINAN:
+ if (radeon_dpm == 1)
+ rdev->pm.pm_method = PM_METHOD_DPM;
+ else
+ rdev->pm.pm_method = PM_METHOD_PROFILE;
+ break;
+ default:
+ /* default to profile method */
+ rdev->pm.pm_method = PM_METHOD_PROFILE;
+ break;
+ }
+
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ return radeon_pm_init_dpm(rdev);
+ else
+ return radeon_pm_init_old(rdev);
+}
+
+static void radeon_pm_fini_old(struct radeon_device *rdev)
{
if (rdev->pm.num_power_states > 1) {
mutex_lock(&rdev->pm.mutex);
@@ -668,7 +1221,36 @@ void radeon_pm_fini(struct radeon_device *rdev)
radeon_hwmon_fini(rdev);
}
-void radeon_pm_compute_clocks(struct radeon_device *rdev)
+static void radeon_pm_fini_dpm(struct radeon_device *rdev)
+{
+ if (rdev->pm.num_power_states > 1) {
+ mutex_lock(&rdev->pm.mutex);
+ radeon_dpm_disable(rdev);
+ mutex_unlock(&rdev->pm.mutex);
+
+ device_remove_file(rdev->dev, &dev_attr_power_dpm_state);
+ device_remove_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
+ /* XXX backwards compat */
+ device_remove_file(rdev->dev, &dev_attr_power_profile);
+ device_remove_file(rdev->dev, &dev_attr_power_method);
+ }
+ radeon_dpm_fini(rdev);
+
+ if (rdev->pm.power_state)
+ kfree(rdev->pm.power_state);
+
+ radeon_hwmon_fini(rdev);
+}
+
+void radeon_pm_fini(struct radeon_device *rdev)
+{
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_fini_dpm(rdev);
+ else
+ radeon_pm_fini_old(rdev);
+}
+
+static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
{
struct drm_device *ddev = rdev->ddev;
struct drm_crtc *crtc;
@@ -739,6 +1321,46 @@ void radeon_pm_compute_clocks(struct radeon_device *rdev)
mutex_unlock(&rdev->pm.mutex);
}
+static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
+{
+ struct drm_device *ddev = rdev->ddev;
+ struct drm_crtc *crtc;
+ struct radeon_crtc *radeon_crtc;
+
+ mutex_lock(&rdev->pm.mutex);
+
+ /* update active crtc counts */
+ rdev->pm.dpm.new_active_crtcs = 0;
+ rdev->pm.dpm.new_active_crtc_count = 0;
+ list_for_each_entry(crtc,
+ &ddev->mode_config.crtc_list, head) {
+ radeon_crtc = to_radeon_crtc(crtc);
+ if (crtc->enabled) {
+ rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
+ rdev->pm.dpm.new_active_crtc_count++;
+ }
+ }
+
+ /* update battery/ac status */
+ if (power_supply_is_system_supplied() > 0)
+ rdev->pm.dpm.ac_power = true;
+ else
+ rdev->pm.dpm.ac_power = false;
+
+ radeon_dpm_change_power_state_locked(rdev);
+
+ mutex_unlock(&rdev->pm.mutex);
+
+}
+
+void radeon_pm_compute_clocks(struct radeon_device *rdev)
+{
+ if (rdev->pm.pm_method == PM_METHOD_DPM)
+ radeon_pm_compute_clocks_dpm(rdev);
+ else
+ radeon_pm_compute_clocks_old(rdev);
+}
+
static bool radeon_pm_in_vbl(struct radeon_device *rdev)
{
int crtc, vpos, hpos, vbl_status;
@@ -842,19 +1464,28 @@ static int radeon_debugfs_pm_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
- seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
- /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */
- if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP))
- seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk);
- else
- seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
- seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
- if (rdev->asic->pm.get_memory_clock)
- seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
- if (rdev->pm.current_vddc)
- seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
- if (rdev->asic->pm.get_pcie_lanes)
- seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
+ if (rdev->pm.dpm_enabled) {
+ mutex_lock(&rdev->pm.mutex);
+ if (rdev->asic->dpm.debugfs_print_current_performance_level)
+ radeon_dpm_debugfs_print_current_performance_level(rdev, m);
+ else
+ seq_printf(m, "Debugfs support not implemented for this asic\n");
+ mutex_unlock(&rdev->pm.mutex);
+ } else {
+ seq_printf(m, "default engine clock: %u0 kHz\n", rdev->pm.default_sclk);
+ /* radeon_get_engine_clock is not reliable on APUs so just print the current clock */
+ if ((rdev->family >= CHIP_PALM) && (rdev->flags & RADEON_IS_IGP))
+ seq_printf(m, "current engine clock: %u0 kHz\n", rdev->pm.current_sclk);
+ else
+ seq_printf(m, "current engine clock: %u0 kHz\n", radeon_get_engine_clock(rdev));
+ seq_printf(m, "default memory clock: %u0 kHz\n", rdev->pm.default_mclk);
+ if (rdev->asic->pm.get_memory_clock)
+ seq_printf(m, "current memory clock: %u0 kHz\n", radeon_get_memory_clock(rdev));
+ if (rdev->pm.current_vddc)
+ seq_printf(m, "voltage: %u mV\n", rdev->pm.current_vddc);
+ if (rdev->asic->pm.get_pcie_lanes)
+ seq_printf(m, "PCIE lanes: %d\n", radeon_get_pcie_lanes(rdev));
+ }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
index 4940af7e75e6..65b9eabd5a2f 100644
--- a/drivers/gpu/drm/radeon/radeon_prime.c
+++ b/drivers/gpu/drm/radeon/radeon_prime.c
@@ -88,11 +88,19 @@ int radeon_gem_prime_pin(struct drm_gem_object *obj)
/* pin buffer into GTT */
ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL);
- if (ret) {
- radeon_bo_unreserve(bo);
- return ret;
- }
radeon_bo_unreserve(bo);
+ return ret;
+}
+
+void radeon_gem_prime_unpin(struct drm_gem_object *obj)
+{
+ struct radeon_bo *bo = gem_to_radeon_bo(obj);
+ int ret = 0;
- return 0;
+ ret = radeon_bo_reserve(bo, false);
+ if (unlikely(ret != 0))
+ return;
+
+ radeon_bo_unpin(bo);
+ radeon_bo_unreserve(bo);
}
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
index 7e2c2b7cf188..62d54976d24e 100644
--- a/drivers/gpu/drm/radeon/radeon_reg.h
+++ b/drivers/gpu/drm/radeon/radeon_reg.h
@@ -57,6 +57,7 @@
#include "evergreen_reg.h"
#include "ni_reg.h"
#include "si_reg.h"
+#include "cik_reg.h"
#define RADEON_MC_AGP_LOCATION 0x014c
#define RADEON_MC_AGP_START_MASK 0x0000FFFF
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index 82434018cbe8..5f1c51a776ed 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -357,6 +357,38 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
}
}
+u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ u32 rptr;
+
+ if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
+ rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+ else
+ rptr = RREG32(ring->rptr_reg);
+ rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+ return rptr;
+}
+
+u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ u32 wptr;
+
+ wptr = RREG32(ring->wptr_reg);
+ wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+
+ return wptr;
+}
+
+void radeon_ring_generic_set_wptr(struct radeon_device *rdev,
+ struct radeon_ring *ring)
+{
+ WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
+ (void)RREG32(ring->wptr_reg);
+}
+
/**
* radeon_ring_free_size - update the free size
*
@@ -367,13 +399,7 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
*/
void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring)
{
- u32 rptr;
-
- if (rdev->wb.enabled && ring != &rdev->ring[R600_RING_TYPE_UVD_INDEX])
- rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
- else
- rptr = RREG32(ring->rptr_reg);
- ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+ ring->rptr = radeon_ring_get_rptr(rdev, ring);
/* This works because ring_size is a power of 2 */
ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4));
ring->ring_free_dw -= ring->wptr;
@@ -465,8 +491,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
radeon_ring_write(ring, ring->nop);
}
DRM_MEMORYBARRIER();
- WREG32(ring->wptr_reg, (ring->wptr << ring->ptr_reg_shift) & ring->ptr_reg_mask);
- (void)RREG32(ring->wptr_reg);
+ radeon_ring_set_wptr(rdev, ring);
}
/**
@@ -568,7 +593,6 @@ void radeon_ring_lockup_update(struct radeon_ring *ring)
bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
{
unsigned long cjiffies, elapsed;
- uint32_t rptr;
cjiffies = jiffies;
if (!time_after(cjiffies, ring->last_activity)) {
@@ -576,8 +600,7 @@ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *rin
radeon_ring_lockup_update(ring);
return false;
}
- rptr = RREG32(ring->rptr_reg);
- ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+ ring->rptr = radeon_ring_get_rptr(rdev, ring);
if (ring->rptr != ring->last_rptr) {
/* CP is still working no lockup */
radeon_ring_lockup_update(ring);
@@ -804,9 +827,9 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
radeon_ring_free_size(rdev, ring);
count = (ring->ring_size / 4) - ring->ring_free_dw;
- tmp = RREG32(ring->wptr_reg) >> ring->ptr_reg_shift;
+ tmp = radeon_ring_get_wptr(rdev, ring);
seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
- tmp = RREG32(ring->rptr_reg) >> ring->ptr_reg_shift;
+ tmp = radeon_ring_get_rptr(rdev, ring);
seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
if (ring->rptr_save_reg) {
seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index bbed4af8d0bc..f4d6bcee9006 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -35,7 +35,6 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
{
struct radeon_bo *vram_obj = NULL;
struct radeon_bo **gtt_obj = NULL;
- struct radeon_fence *fence = NULL;
uint64_t gtt_addr, vram_addr;
unsigned i, n, size;
int r, ring;
@@ -81,37 +80,38 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
}
r = radeon_bo_reserve(vram_obj, false);
if (unlikely(r != 0))
- goto out_cleanup;
+ goto out_unref;
r = radeon_bo_pin(vram_obj, RADEON_GEM_DOMAIN_VRAM, &vram_addr);
if (r) {
DRM_ERROR("Failed to pin VRAM object\n");
- goto out_cleanup;
+ 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 radeon_fence *fence = NULL;
r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT, NULL, gtt_obj + i);
if (r) {
DRM_ERROR("Failed to create GTT object %d\n", i);
- goto out_cleanup;
+ goto out_lclean;
}
r = radeon_bo_reserve(gtt_obj[i], false);
if (unlikely(r != 0))
- goto out_cleanup;
+ goto out_lclean_unref;
r = radeon_bo_pin(gtt_obj[i], RADEON_GEM_DOMAIN_GTT, &gtt_addr);
if (r) {
DRM_ERROR("Failed to pin GTT object %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unres;
}
r = radeon_bo_kmap(gtt_obj[i], &gtt_map);
if (r) {
DRM_ERROR("Failed to map GTT object %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
for (gtt_start = gtt_map, gtt_end = gtt_map + size;
@@ -127,13 +127,13 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
r = radeon_copy_blit(rdev, gtt_addr, vram_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
if (r) {
DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
r = radeon_fence_wait(fence, false);
if (r) {
DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
radeon_fence_unref(&fence);
@@ -141,7 +141,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
r = radeon_bo_kmap(vram_obj, &vram_map);
if (r) {
DRM_ERROR("Failed to map VRAM object after copy %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
for (gtt_start = gtt_map, gtt_end = gtt_map + size,
@@ -160,7 +160,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
(vram_addr - rdev->mc.vram_start +
(void*)gtt_start - gtt_map));
radeon_bo_kunmap(vram_obj);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
*vram_start = vram_start;
}
@@ -173,13 +173,13 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
r = radeon_copy_blit(rdev, vram_addr, gtt_addr, size / RADEON_GPU_PAGE_SIZE, &fence);
if (r) {
DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
r = radeon_fence_wait(fence, false);
if (r) {
DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
radeon_fence_unref(&fence);
@@ -187,7 +187,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
r = radeon_bo_kmap(gtt_obj[i], &gtt_map);
if (r) {
DRM_ERROR("Failed to map GTT object after copy %d\n", i);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
for (gtt_start = gtt_map, gtt_end = gtt_map + size,
@@ -206,7 +206,7 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
(gtt_addr - rdev->mc.gtt_start +
(void*)vram_start - vram_map));
radeon_bo_kunmap(gtt_obj[i]);
- goto out_cleanup;
+ goto out_lclean_unpin;
}
}
@@ -214,31 +214,32 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
DRM_INFO("Tested GTT->VRAM and VRAM->GTT copy for GTT offset 0x%llx\n",
gtt_addr - rdev->mc.gtt_start);
+ continue;
+
+out_lclean_unpin:
+ radeon_bo_unpin(gtt_obj[i]);
+out_lclean_unres:
+ radeon_bo_unreserve(gtt_obj[i]);
+out_lclean_unref:
+ radeon_bo_unref(&gtt_obj[i]);
+out_lclean:
+ for (--i; i >= 0; --i) {
+ radeon_bo_unpin(gtt_obj[i]);
+ radeon_bo_unreserve(gtt_obj[i]);
+ radeon_bo_unref(&gtt_obj[i]);
+ }
+ if (fence)
+ radeon_fence_unref(&fence);
+ break;
}
+ radeon_bo_unpin(vram_obj);
+out_unres:
+ radeon_bo_unreserve(vram_obj);
+out_unref:
+ radeon_bo_unref(&vram_obj);
out_cleanup:
- if (vram_obj) {
- if (radeon_bo_is_reserved(vram_obj)) {
- radeon_bo_unpin(vram_obj);
- radeon_bo_unreserve(vram_obj);
- }
- radeon_bo_unref(&vram_obj);
- }
- if (gtt_obj) {
- for (i = 0; i < n; i++) {
- if (gtt_obj[i]) {
- if (radeon_bo_is_reserved(gtt_obj[i])) {
- radeon_bo_unpin(gtt_obj[i]);
- radeon_bo_unreserve(gtt_obj[i]);
- }
- radeon_bo_unref(&gtt_obj[i]);
- }
- }
- kfree(gtt_obj);
- }
- if (fence) {
- radeon_fence_unref(&fence);
- }
+ kfree(gtt_obj);
if (r) {
printk(KERN_WARNING "Error while testing BO move.\n");
}
diff --git a/drivers/gpu/drm/radeon/radeon_ucode.h b/drivers/gpu/drm/radeon/radeon_ucode.h
new file mode 100644
index 000000000000..d8b05f7bcf1a
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_ucode.h
@@ -0,0 +1,129 @@
+/*
+ * 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 __RADEON_UCODE_H__
+#define __RADEON_UCODE_H__
+
+/* CP */
+#define R600_PFP_UCODE_SIZE 576
+#define R600_PM4_UCODE_SIZE 1792
+#define R700_PFP_UCODE_SIZE 848
+#define R700_PM4_UCODE_SIZE 1360
+#define EVERGREEN_PFP_UCODE_SIZE 1120
+#define EVERGREEN_PM4_UCODE_SIZE 1376
+#define CAYMAN_PFP_UCODE_SIZE 2176
+#define CAYMAN_PM4_UCODE_SIZE 2176
+#define SI_PFP_UCODE_SIZE 2144
+#define SI_PM4_UCODE_SIZE 2144
+#define SI_CE_UCODE_SIZE 2144
+
+/* RLC */
+#define R600_RLC_UCODE_SIZE 768
+#define R700_RLC_UCODE_SIZE 1024
+#define EVERGREEN_RLC_UCODE_SIZE 768
+#define CAYMAN_RLC_UCODE_SIZE 1024
+#define ARUBA_RLC_UCODE_SIZE 1536
+#define SI_RLC_UCODE_SIZE 2048
+
+/* MC */
+#define BTC_MC_UCODE_SIZE 6024
+#define CAYMAN_MC_UCODE_SIZE 6037
+#define SI_MC_UCODE_SIZE 7769
+#define OLAND_MC_UCODE_SIZE 7863
+
+/* SMC */
+#define RV770_SMC_UCODE_START 0x0100
+#define RV770_SMC_UCODE_SIZE 0x410d
+#define RV770_SMC_INT_VECTOR_START 0xffc0
+#define RV770_SMC_INT_VECTOR_SIZE 0x0040
+
+#define RV730_SMC_UCODE_START 0x0100
+#define RV730_SMC_UCODE_SIZE 0x412c
+#define RV730_SMC_INT_VECTOR_START 0xffc0
+#define RV730_SMC_INT_VECTOR_SIZE 0x0040
+
+#define RV710_SMC_UCODE_START 0x0100
+#define RV710_SMC_UCODE_SIZE 0x3f1f
+#define RV710_SMC_INT_VECTOR_START 0xffc0
+#define RV710_SMC_INT_VECTOR_SIZE 0x0040
+
+#define RV740_SMC_UCODE_START 0x0100
+#define RV740_SMC_UCODE_SIZE 0x41c5
+#define RV740_SMC_INT_VECTOR_START 0xffc0
+#define RV740_SMC_INT_VECTOR_SIZE 0x0040
+
+#define CEDAR_SMC_UCODE_START 0x0100
+#define CEDAR_SMC_UCODE_SIZE 0x5d50
+#define CEDAR_SMC_INT_VECTOR_START 0xffc0
+#define CEDAR_SMC_INT_VECTOR_SIZE 0x0040
+
+#define REDWOOD_SMC_UCODE_START 0x0100
+#define REDWOOD_SMC_UCODE_SIZE 0x5f0a
+#define REDWOOD_SMC_INT_VECTOR_START 0xffc0
+#define REDWOOD_SMC_INT_VECTOR_SIZE 0x0040
+
+#define JUNIPER_SMC_UCODE_START 0x0100
+#define JUNIPER_SMC_UCODE_SIZE 0x5f1f
+#define JUNIPER_SMC_INT_VECTOR_START 0xffc0
+#define JUNIPER_SMC_INT_VECTOR_SIZE 0x0040
+
+#define CYPRESS_SMC_UCODE_START 0x0100
+#define CYPRESS_SMC_UCODE_SIZE 0x61f7
+#define CYPRESS_SMC_INT_VECTOR_START 0xffc0
+#define CYPRESS_SMC_INT_VECTOR_SIZE 0x0040
+
+#define BARTS_SMC_UCODE_START 0x0100
+#define BARTS_SMC_UCODE_SIZE 0x6107
+#define BARTS_SMC_INT_VECTOR_START 0xffc0
+#define BARTS_SMC_INT_VECTOR_SIZE 0x0040
+
+#define TURKS_SMC_UCODE_START 0x0100
+#define TURKS_SMC_UCODE_SIZE 0x605b
+#define TURKS_SMC_INT_VECTOR_START 0xffc0
+#define TURKS_SMC_INT_VECTOR_SIZE 0x0040
+
+#define CAICOS_SMC_UCODE_START 0x0100
+#define CAICOS_SMC_UCODE_SIZE 0x5fbd
+#define CAICOS_SMC_INT_VECTOR_START 0xffc0
+#define CAICOS_SMC_INT_VECTOR_SIZE 0x0040
+
+#define CAYMAN_SMC_UCODE_START 0x0100
+#define CAYMAN_SMC_UCODE_SIZE 0x79ec
+#define CAYMAN_SMC_INT_VECTOR_START 0xffc0
+#define CAYMAN_SMC_INT_VECTOR_SIZE 0x0040
+
+#define TAHITI_SMC_UCODE_START 0x10000
+#define TAHITI_SMC_UCODE_SIZE 0xf458
+
+#define PITCAIRN_SMC_UCODE_START 0x10000
+#define PITCAIRN_SMC_UCODE_SIZE 0xe9f4
+
+#define VERDE_SMC_UCODE_START 0x10000
+#define VERDE_SMC_UCODE_SIZE 0xebe4
+
+#define OLAND_SMC_UCODE_START 0x10000
+#define OLAND_SMC_UCODE_SIZE 0xe7b4
+
+#define HAINAN_SMC_UCODE_START 0x10000
+#define HAINAN_SMC_UCODE_SIZE 0xe67C
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
index cad735dd02c6..41efcec28cd8 100644
--- a/drivers/gpu/drm/radeon/radeon_uvd.c
+++ b/drivers/gpu/drm/radeon/radeon_uvd.c
@@ -44,11 +44,13 @@
#define FIRMWARE_CYPRESS "radeon/CYPRESS_uvd.bin"
#define FIRMWARE_SUMO "radeon/SUMO_uvd.bin"
#define FIRMWARE_TAHITI "radeon/TAHITI_uvd.bin"
+#define FIRMWARE_BONAIRE "radeon/BONAIRE_uvd.bin"
MODULE_FIRMWARE(FIRMWARE_RV710);
MODULE_FIRMWARE(FIRMWARE_CYPRESS);
MODULE_FIRMWARE(FIRMWARE_SUMO);
MODULE_FIRMWARE(FIRMWARE_TAHITI);
+MODULE_FIRMWARE(FIRMWARE_BONAIRE);
static void radeon_uvd_idle_work_handler(struct work_struct *work);
@@ -100,6 +102,12 @@ int radeon_uvd_init(struct radeon_device *rdev)
fw_name = FIRMWARE_TAHITI;
break;
+ case CHIP_BONAIRE:
+ case CHIP_KABINI:
+ case CHIP_KAVERI:
+ fw_name = FIRMWARE_BONAIRE;
+ break;
+
default:
return -EINVAL;
}
@@ -542,6 +550,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
struct radeon_fence **fence)
{
struct ttm_validate_buffer tv;
+ struct ww_acquire_ctx ticket;
struct list_head head;
struct radeon_ib ib;
uint64_t addr;
@@ -553,7 +562,7 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
INIT_LIST_HEAD(&head);
list_add(&tv.head, &head);
- r = ttm_eu_reserve_buffers(&head);
+ r = ttm_eu_reserve_buffers(&ticket, &head);
if (r)
return r;
@@ -561,16 +570,12 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
radeon_uvd_force_into_uvd_segment(bo);
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
- if (r) {
- ttm_eu_backoff_reservation(&head);
- return r;
- }
+ if (r)
+ goto err;
r = radeon_ib_get(rdev, ring, &ib, NULL, 16);
- if (r) {
- ttm_eu_backoff_reservation(&head);
- return r;
- }
+ if (r)
+ goto err;
addr = radeon_bo_gpu_offset(bo);
ib.ptr[0] = PACKET0(UVD_GPCOM_VCPU_DATA0, 0);
@@ -584,11 +589,9 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
ib.length_dw = 16;
r = radeon_ib_schedule(rdev, &ib, NULL);
- if (r) {
- ttm_eu_backoff_reservation(&head);
- return r;
- }
- ttm_eu_fence_buffer_objects(&head, ib.fence);
+ if (r)
+ goto err;
+ ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
if (fence)
*fence = radeon_fence_ref(ib.fence);
@@ -596,6 +599,10 @@ static int radeon_uvd_send_msg(struct radeon_device *rdev,
radeon_ib_free(rdev, &ib);
radeon_bo_unref(&bo);
return 0;
+
+err:
+ ttm_eu_backoff_reservation(&ticket, &head);
+ return r;
}
/* multiple fence commands without any stream commands in between can
@@ -691,11 +698,19 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
struct radeon_device *rdev =
container_of(work, struct radeon_device, uvd.idle_work.work);
- if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0)
- radeon_set_uvd_clocks(rdev, 0, 0);
- else
+ if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+ mutex_lock(&rdev->pm.mutex);
+ rdev->pm.dpm.uvd_active = false;
+ mutex_unlock(&rdev->pm.mutex);
+ radeon_pm_compute_clocks(rdev);
+ } else {
+ radeon_set_uvd_clocks(rdev, 0, 0);
+ }
+ } else {
schedule_delayed_work(&rdev->uvd.idle_work,
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
+ }
}
void radeon_uvd_note_usage(struct radeon_device *rdev)
@@ -703,8 +718,14 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)
bool set_clocks = !cancel_delayed_work_sync(&rdev->uvd.idle_work);
set_clocks &= schedule_delayed_work(&rdev->uvd.idle_work,
msecs_to_jiffies(UVD_IDLE_TIMEOUT_MS));
- if (set_clocks)
- radeon_set_uvd_clocks(rdev, 53300, 40000);
+ if (set_clocks) {
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+ /* XXX pick SD/HD/MVC */
+ radeon_dpm_enable_power_state(rdev, POWER_STATE_TYPE_INTERNAL_UVD);
+ } else {
+ radeon_set_uvd_clocks(rdev, 53300, 40000);
+ }
+ }
}
static unsigned radeon_uvd_calc_upll_post_div(unsigned vco_freq,
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 55880d5962c3..d8ddfb34545d 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -248,13 +248,16 @@ struct rs690_watermark {
};
static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
- struct radeon_crtc *crtc,
- struct rs690_watermark *wm)
+ struct radeon_crtc *crtc,
+ struct rs690_watermark *wm,
+ bool low)
{
struct drm_display_mode *mode = &crtc->base.mode;
fixed20_12 a, b, c;
fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
+ fixed20_12 sclk, core_bandwidth, max_bandwidth;
+ u32 selected_sclk;
if (!crtc->base.enabled) {
/* FIXME: wouldn't it better to set priority mark to maximum */
@@ -262,6 +265,21 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
return;
}
+ if (((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880)) &&
+ (rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
+ selected_sclk = radeon_dpm_get_sclk(rdev, low);
+ else
+ selected_sclk = rdev->pm.current_sclk;
+
+ /* sclk in Mhz */
+ a.full = dfixed_const(100);
+ sclk.full = dfixed_const(selected_sclk);
+ sclk.full = dfixed_div(sclk, a);
+
+ /* core_bandwidth = sclk(Mhz) * 16 */
+ a.full = dfixed_const(16);
+ core_bandwidth.full = dfixed_div(rdev->pm.sclk, a);
+
if (crtc->vsc.full > dfixed_const(2))
wm->num_line_pair.full = dfixed_const(2);
else
@@ -322,36 +340,36 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
wm->active_time.full = dfixed_div(wm->active_time, a);
/* Maximun bandwidth is the minimun bandwidth of all component */
- rdev->pm.max_bandwidth = rdev->pm.core_bandwidth;
+ max_bandwidth = core_bandwidth;
if (rdev->mc.igp_sideport_enabled) {
- if (rdev->pm.max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&
+ if (max_bandwidth.full > rdev->pm.sideport_bandwidth.full &&
rdev->pm.sideport_bandwidth.full)
- rdev->pm.max_bandwidth = rdev->pm.sideport_bandwidth;
+ max_bandwidth = rdev->pm.sideport_bandwidth;
read_delay_latency.full = dfixed_const(370 * 800 * 1000);
read_delay_latency.full = dfixed_div(read_delay_latency,
rdev->pm.igp_sideport_mclk);
} else {
- if (rdev->pm.max_bandwidth.full > rdev->pm.k8_bandwidth.full &&
+ if (max_bandwidth.full > rdev->pm.k8_bandwidth.full &&
rdev->pm.k8_bandwidth.full)
- rdev->pm.max_bandwidth = rdev->pm.k8_bandwidth;
- if (rdev->pm.max_bandwidth.full > rdev->pm.ht_bandwidth.full &&
+ max_bandwidth = rdev->pm.k8_bandwidth;
+ if (max_bandwidth.full > rdev->pm.ht_bandwidth.full &&
rdev->pm.ht_bandwidth.full)
- rdev->pm.max_bandwidth = rdev->pm.ht_bandwidth;
+ max_bandwidth = rdev->pm.ht_bandwidth;
read_delay_latency.full = dfixed_const(5000);
}
/* sclk = system clocks(ns) = 1000 / max_bandwidth / 16 */
a.full = dfixed_const(16);
- rdev->pm.sclk.full = dfixed_mul(rdev->pm.max_bandwidth, a);
+ sclk.full = dfixed_mul(max_bandwidth, a);
a.full = dfixed_const(1000);
- rdev->pm.sclk.full = dfixed_div(a, rdev->pm.sclk);
+ sclk.full = dfixed_div(a, sclk);
/* Determine chunk time
* ChunkTime = the time it takes the DCP to send one chunk of data
* to the LB which consists of pipeline delay and inter chunk gap
* sclk = system clock(ns)
*/
a.full = dfixed_const(256 * 13);
- chunk_time.full = dfixed_mul(rdev->pm.sclk, a);
+ chunk_time.full = dfixed_mul(sclk, a);
a.full = dfixed_const(10);
chunk_time.full = dfixed_div(chunk_time, a);
@@ -415,175 +433,200 @@ static void rs690_crtc_bandwidth_compute(struct radeon_device *rdev,
}
}
-void rs690_bandwidth_update(struct radeon_device *rdev)
+static void rs690_compute_mode_priority(struct radeon_device *rdev,
+ struct rs690_watermark *wm0,
+ struct rs690_watermark *wm1,
+ struct drm_display_mode *mode0,
+ struct drm_display_mode *mode1,
+ u32 *d1mode_priority_a_cnt,
+ u32 *d2mode_priority_a_cnt)
{
- struct drm_display_mode *mode0 = NULL;
- struct drm_display_mode *mode1 = NULL;
- struct rs690_watermark wm0;
- struct rs690_watermark wm1;
- u32 tmp;
- u32 d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
- u32 d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
fixed20_12 priority_mark02, priority_mark12, fill_rate;
fixed20_12 a, b;
- radeon_update_display_priority(rdev);
-
- if (rdev->mode_info.crtcs[0]->base.enabled)
- mode0 = &rdev->mode_info.crtcs[0]->base.mode;
- if (rdev->mode_info.crtcs[1]->base.enabled)
- mode1 = &rdev->mode_info.crtcs[1]->base.mode;
- /*
- * Set display0/1 priority up in the memory controller for
- * modes if the user specifies HIGH for displaypriority
- * option.
- */
- if ((rdev->disp_priority == 2) &&
- ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) {
- tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER);
- tmp &= C_000104_MC_DISP0R_INIT_LAT;
- tmp &= C_000104_MC_DISP1R_INIT_LAT;
- if (mode0)
- tmp |= S_000104_MC_DISP0R_INIT_LAT(1);
- if (mode1)
- tmp |= S_000104_MC_DISP1R_INIT_LAT(1);
- WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp);
- }
- rs690_line_buffer_adjust(rdev, mode0, mode1);
-
- if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))
- WREG32(R_006C9C_DCP_CONTROL, 0);
- if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
- WREG32(R_006C9C_DCP_CONTROL, 2);
-
- rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0);
- rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1);
-
- tmp = (wm0.lb_request_fifo_depth - 1);
- tmp |= (wm1.lb_request_fifo_depth - 1) << 16;
- WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp);
+ *d1mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
+ *d2mode_priority_a_cnt = S_006548_D1MODE_PRIORITY_A_OFF(1);
if (mode0 && mode1) {
- if (dfixed_trunc(wm0.dbpp) > 64)
- a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair);
+ if (dfixed_trunc(wm0->dbpp) > 64)
+ a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair);
else
- a.full = wm0.num_line_pair.full;
- if (dfixed_trunc(wm1.dbpp) > 64)
- b.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair);
+ a.full = wm0->num_line_pair.full;
+ if (dfixed_trunc(wm1->dbpp) > 64)
+ b.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair);
else
- b.full = wm1.num_line_pair.full;
+ b.full = wm1->num_line_pair.full;
a.full += b.full;
- fill_rate.full = dfixed_div(wm0.sclk, a);
- if (wm0.consumption_rate.full > fill_rate.full) {
- b.full = wm0.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm0.active_time);
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ fill_rate.full = dfixed_div(wm0->sclk, a);
+ if (wm0->consumption_rate.full > fill_rate.full) {
+ b.full = wm0->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm0->active_time);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
a.full = a.full + b.full;
b.full = dfixed_const(16 * 1000);
priority_mark02.full = dfixed_div(a, b);
} else {
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark02.full = dfixed_div(a, b);
}
- if (wm1.consumption_rate.full > fill_rate.full) {
- b.full = wm1.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm1.active_time);
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ if (wm1->consumption_rate.full > fill_rate.full) {
+ b.full = wm1->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm1->active_time);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
a.full = a.full + b.full;
b.full = dfixed_const(16 * 1000);
priority_mark12.full = dfixed_div(a, b);
} else {
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark12.full = dfixed_div(a, b);
}
- if (wm0.priority_mark.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark.full;
+ if (wm0->priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark.full;
if (dfixed_trunc(priority_mark02) < 0)
priority_mark02.full = 0;
- if (wm0.priority_mark_max.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark_max.full;
- if (wm1.priority_mark.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark.full;
+ if (wm0->priority_mark_max.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark_max.full;
+ if (wm1->priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark.full;
if (dfixed_trunc(priority_mark12) < 0)
priority_mark12.full = 0;
- if (wm1.priority_mark_max.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark_max.full;
- d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
- d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+ if (wm1->priority_mark_max.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark_max.full;
+ *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+ *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
if (rdev->disp_priority == 2) {
- d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
- d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
+ *d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
+ *d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
}
} else if (mode0) {
- if (dfixed_trunc(wm0.dbpp) > 64)
- a.full = dfixed_mul(wm0.dbpp, wm0.num_line_pair);
+ if (dfixed_trunc(wm0->dbpp) > 64)
+ a.full = dfixed_mul(wm0->dbpp, wm0->num_line_pair);
else
- a.full = wm0.num_line_pair.full;
- fill_rate.full = dfixed_div(wm0.sclk, a);
- if (wm0.consumption_rate.full > fill_rate.full) {
- b.full = wm0.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm0.active_time);
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = wm0->num_line_pair.full;
+ fill_rate.full = dfixed_div(wm0->sclk, a);
+ if (wm0->consumption_rate.full > fill_rate.full) {
+ b.full = wm0->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm0->active_time);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
a.full = a.full + b.full;
b.full = dfixed_const(16 * 1000);
priority_mark02.full = dfixed_div(a, b);
} else {
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark02.full = dfixed_div(a, b);
}
- if (wm0.priority_mark.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark.full;
+ if (wm0->priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark.full;
if (dfixed_trunc(priority_mark02) < 0)
priority_mark02.full = 0;
- if (wm0.priority_mark_max.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark_max.full;
- d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+ if (wm0->priority_mark_max.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark_max.full;
+ *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
if (rdev->disp_priority == 2)
- d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
+ *d1mode_priority_a_cnt |= S_006548_D1MODE_PRIORITY_A_ALWAYS_ON(1);
} else if (mode1) {
- if (dfixed_trunc(wm1.dbpp) > 64)
- a.full = dfixed_mul(wm1.dbpp, wm1.num_line_pair);
+ if (dfixed_trunc(wm1->dbpp) > 64)
+ a.full = dfixed_mul(wm1->dbpp, wm1->num_line_pair);
else
- a.full = wm1.num_line_pair.full;
- fill_rate.full = dfixed_div(wm1.sclk, a);
- if (wm1.consumption_rate.full > fill_rate.full) {
- b.full = wm1.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm1.active_time);
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = wm1->num_line_pair.full;
+ fill_rate.full = dfixed_div(wm1->sclk, a);
+ if (wm1->consumption_rate.full > fill_rate.full) {
+ b.full = wm1->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm1->active_time);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
a.full = a.full + b.full;
b.full = dfixed_const(16 * 1000);
priority_mark12.full = dfixed_div(a, b);
} else {
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark12.full = dfixed_div(a, b);
}
- if (wm1.priority_mark.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark.full;
+ if (wm1->priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark.full;
if (dfixed_trunc(priority_mark12) < 0)
priority_mark12.full = 0;
- if (wm1.priority_mark_max.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark_max.full;
- d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+ if (wm1->priority_mark_max.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark_max.full;
+ *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
if (rdev->disp_priority == 2)
- d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
+ *d2mode_priority_a_cnt |= S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(1);
}
+}
+
+void rs690_bandwidth_update(struct radeon_device *rdev)
+{
+ struct drm_display_mode *mode0 = NULL;
+ struct drm_display_mode *mode1 = NULL;
+ struct rs690_watermark wm0_high, wm0_low;
+ struct rs690_watermark wm1_high, wm1_low;
+ u32 tmp;
+ u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt;
+ u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt;
+
+ radeon_update_display_priority(rdev);
+
+ if (rdev->mode_info.crtcs[0]->base.enabled)
+ mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+ if (rdev->mode_info.crtcs[1]->base.enabled)
+ mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+ /*
+ * Set display0/1 priority up in the memory controller for
+ * modes if the user specifies HIGH for displaypriority
+ * option.
+ */
+ if ((rdev->disp_priority == 2) &&
+ ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))) {
+ tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER);
+ tmp &= C_000104_MC_DISP0R_INIT_LAT;
+ tmp &= C_000104_MC_DISP1R_INIT_LAT;
+ if (mode0)
+ tmp |= S_000104_MC_DISP0R_INIT_LAT(1);
+ if (mode1)
+ tmp |= S_000104_MC_DISP1R_INIT_LAT(1);
+ WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp);
+ }
+ rs690_line_buffer_adjust(rdev, mode0, mode1);
+
+ if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))
+ WREG32(R_006C9C_DCP_CONTROL, 0);
+ if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
+ WREG32(R_006C9C_DCP_CONTROL, 2);
+
+ rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false);
+ rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false);
+
+ rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, true);
+ rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, true);
+
+ tmp = (wm0_high.lb_request_fifo_depth - 1);
+ tmp |= (wm1_high.lb_request_fifo_depth - 1) << 16;
+ WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp);
+
+ rs690_compute_mode_priority(rdev,
+ &wm0_high, &wm1_high,
+ mode0, mode1,
+ &d1mode_priority_a_cnt, &d2mode_priority_a_cnt);
+ rs690_compute_mode_priority(rdev,
+ &wm0_low, &wm1_low,
+ mode0, mode1,
+ &d1mode_priority_b_cnt, &d2mode_priority_b_cnt);
WREG32(R_006548_D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
- WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+ WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt);
WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
- WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
+ WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt);
}
uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg)
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c
new file mode 100644
index 000000000000..bef832a62fee
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780_dpm.c
@@ -0,0 +1,963 @@
+/*
+ * 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 "radeon.h"
+#include "rs780d.h"
+#include "r600_dpm.h"
+#include "rs780_dpm.h"
+#include "atom.h"
+
+static struct igp_ps *rs780_get_ps(struct radeon_ps *rps)
+{
+ struct igp_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+static struct igp_power_info *rs780_get_pi(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+ struct radeon_mode_info *minfo = &rdev->mode_info;
+ struct drm_crtc *crtc;
+ struct radeon_crtc *radeon_crtc;
+ int i;
+
+ /* defaults */
+ pi->crtc_id = 0;
+ pi->refresh_rate = 60;
+
+ for (i = 0; i < rdev->num_crtc; i++) {
+ crtc = (struct drm_crtc *)minfo->crtcs[i];
+ if (crtc && crtc->enabled) {
+ radeon_crtc = to_radeon_crtc(crtc);
+ pi->crtc_id = radeon_crtc->crtc_id;
+ if (crtc->mode.htotal && crtc->mode.vtotal)
+ pi->refresh_rate =
+ (crtc->mode.clock * 1000) /
+ (crtc->mode.htotal * crtc->mode.vtotal);
+ break;
+ }
+ }
+}
+
+static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable);
+
+static int rs780_initialize_dpm_power_state(struct radeon_device *rdev,
+ struct radeon_ps *boot_ps)
+{
+ struct atom_clock_dividers dividers;
+ struct igp_ps *default_state = rs780_get_ps(boot_ps);
+ int i, ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ default_state->sclk_low, false, &dividers);
+ if (ret)
+ return ret;
+
+ r600_engine_clock_entry_set_reference_divider(rdev, 0, dividers.ref_div);
+ r600_engine_clock_entry_set_feedback_divider(rdev, 0, dividers.fb_div);
+ r600_engine_clock_entry_set_post_divider(rdev, 0, dividers.post_div);
+
+ if (dividers.enable_post_div)
+ r600_engine_clock_entry_enable_post_divider(rdev, 0, true);
+ else
+ r600_engine_clock_entry_enable_post_divider(rdev, 0, false);
+
+ r600_engine_clock_entry_set_step_time(rdev, 0, R600_SST_DFLT);
+ r600_engine_clock_entry_enable_pulse_skipping(rdev, 0, false);
+
+ r600_engine_clock_entry_enable(rdev, 0, true);
+ for (i = 1; i < R600_PM_NUMBER_OF_SCLKS; i++)
+ r600_engine_clock_entry_enable(rdev, i, false);
+
+ r600_enable_mclk_control(rdev, false);
+ r600_voltage_control_enable_pins(rdev, 0);
+
+ return 0;
+}
+
+static int rs780_initialize_dpm_parameters(struct radeon_device *rdev,
+ struct radeon_ps *boot_ps)
+{
+ int ret = 0;
+ int i;
+
+ r600_set_bsp(rdev, R600_BSU_DFLT, R600_BSP_DFLT);
+
+ r600_set_at(rdev, 0, 0, 0, 0);
+
+ r600_set_git(rdev, R600_GICST_DFLT);
+
+ for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+ r600_set_tc(rdev, i, 0, 0);
+
+ r600_select_td(rdev, R600_TD_DFLT);
+ r600_set_vrc(rdev, 0);
+
+ r600_set_tpu(rdev, R600_TPU_DFLT);
+ r600_set_tpc(rdev, R600_TPC_DFLT);
+
+ r600_set_sstu(rdev, R600_SSTU_DFLT);
+ r600_set_sst(rdev, R600_SST_DFLT);
+
+ r600_set_fctu(rdev, R600_FCTU_DFLT);
+ r600_set_fct(rdev, R600_FCT_DFLT);
+
+ r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
+ r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
+ r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
+ r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
+ r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
+
+ r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
+ r600_vid_rt_set_vrt(rdev, R600_VOLTAGERESPONSETIME_DFLT);
+ r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
+
+ ret = rs780_initialize_dpm_power_state(rdev, boot_ps);
+
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0);
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH, 0);
+
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH, 0);
+
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM, 0);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH, 0);
+
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW, R600_DISPLAY_WATERMARK_HIGH);
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM, R600_DISPLAY_WATERMARK_HIGH);
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH, R600_DISPLAY_WATERMARK_HIGH);
+
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_CTXSW, false);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+
+ r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_LOW);
+
+ r600_set_vrc(rdev, RS780_CGFTV_DFLT);
+
+ return ret;
+}
+
+static void rs780_start_dpm(struct radeon_device *rdev)
+{
+ r600_enable_sclk_control(rdev, false);
+ r600_enable_mclk_control(rdev, false);
+
+ r600_dynamicpm_enable(rdev, true);
+
+ radeon_wait_for_vblank(rdev, 0);
+ radeon_wait_for_vblank(rdev, 1);
+
+ r600_enable_spll_bypass(rdev, true);
+ r600_wait_for_spll_change(rdev);
+ r600_enable_spll_bypass(rdev, false);
+ r600_wait_for_spll_change(rdev);
+
+ r600_enable_spll_bypass(rdev, true);
+ r600_wait_for_spll_change(rdev);
+ r600_enable_spll_bypass(rdev, false);
+ r600_wait_for_spll_change(rdev);
+
+ r600_enable_sclk_control(rdev, true);
+}
+
+
+static void rs780_preset_ranges_slow_clk_fbdiv_en(struct radeon_device *rdev)
+{
+ WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1, RANGE_SLOW_CLK_FEEDBACK_DIV_EN,
+ ~RANGE_SLOW_CLK_FEEDBACK_DIV_EN);
+
+ WREG32_P(FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1,
+ RANGE0_SLOW_CLK_FEEDBACK_DIV(RS780_SLOWCLKFEEDBACKDIV_DFLT),
+ ~RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK);
+}
+
+static void rs780_preset_starting_fbdiv(struct radeon_device *rdev)
+{
+ u32 fbdiv = (RREG32(CG_SPLL_FUNC_CNTL) & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+
+ WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fbdiv),
+ ~STARTING_FEEDBACK_DIV_MASK);
+
+ WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fbdiv),
+ ~FORCED_FEEDBACK_DIV_MASK);
+
+ WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+}
+
+static void rs780_voltage_scaling_init(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+ struct drm_device *dev = rdev->ddev;
+ u32 fv_throt_pwm_fb_div_range[3];
+ u32 fv_throt_pwm_range[4];
+
+ if (dev->pdev->device == 0x9614) {
+ fv_throt_pwm_fb_div_range[0] = RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+ fv_throt_pwm_fb_div_range[1] = RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+ fv_throt_pwm_fb_div_range[2] = RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+ } else if ((dev->pdev->device == 0x9714) ||
+ (dev->pdev->device == 0x9715)) {
+ fv_throt_pwm_fb_div_range[0] = RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+ fv_throt_pwm_fb_div_range[1] = RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+ fv_throt_pwm_fb_div_range[2] = RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+ } else {
+ fv_throt_pwm_fb_div_range[0] = RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT;
+ fv_throt_pwm_fb_div_range[1] = RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT;
+ fv_throt_pwm_fb_div_range[2] = RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT;
+ }
+
+ if (pi->pwm_voltage_control) {
+ fv_throt_pwm_range[0] = pi->min_voltage;
+ fv_throt_pwm_range[1] = pi->min_voltage;
+ fv_throt_pwm_range[2] = pi->max_voltage;
+ fv_throt_pwm_range[3] = pi->max_voltage;
+ } else {
+ fv_throt_pwm_range[0] = pi->invert_pwm_required ?
+ RS780_FVTHROTPWMRANGE3_GPIO_DFLT : RS780_FVTHROTPWMRANGE0_GPIO_DFLT;
+ fv_throt_pwm_range[1] = pi->invert_pwm_required ?
+ RS780_FVTHROTPWMRANGE2_GPIO_DFLT : RS780_FVTHROTPWMRANGE1_GPIO_DFLT;
+ fv_throt_pwm_range[2] = pi->invert_pwm_required ?
+ RS780_FVTHROTPWMRANGE1_GPIO_DFLT : RS780_FVTHROTPWMRANGE2_GPIO_DFLT;
+ fv_throt_pwm_range[3] = pi->invert_pwm_required ?
+ RS780_FVTHROTPWMRANGE0_GPIO_DFLT : RS780_FVTHROTPWMRANGE3_GPIO_DFLT;
+ }
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0,
+ STARTING_PWM_HIGHTIME(pi->max_voltage),
+ ~STARTING_PWM_HIGHTIME_MASK);
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0,
+ NUMBER_OF_CYCLES_IN_PERIOD(pi->num_of_cycles_in_period),
+ ~NUMBER_OF_CYCLES_IN_PERIOD_MASK);
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0, FORCE_STARTING_PWM_HIGHTIME,
+ ~FORCE_STARTING_PWM_HIGHTIME);
+
+ if (pi->invert_pwm_required)
+ WREG32_P(FVTHROT_PWM_CTRL_REG0, INVERT_PWM_WAVEFORM, ~INVERT_PWM_WAVEFORM);
+ else
+ WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~INVERT_PWM_WAVEFORM);
+
+ rs780_voltage_scaling_enable(rdev, true);
+
+ WREG32(FVTHROT_PWM_CTRL_REG1,
+ (MIN_PWM_HIGHTIME(pi->min_voltage) |
+ MAX_PWM_HIGHTIME(pi->max_voltage)));
+
+ WREG32(FVTHROT_PWM_US_REG0, RS780_FVTHROTPWMUSREG0_DFLT);
+ WREG32(FVTHROT_PWM_US_REG1, RS780_FVTHROTPWMUSREG1_DFLT);
+ WREG32(FVTHROT_PWM_DS_REG0, RS780_FVTHROTPWMDSREG0_DFLT);
+ WREG32(FVTHROT_PWM_DS_REG1, RS780_FVTHROTPWMDSREG1_DFLT);
+
+ WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
+ RANGE0_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[0]),
+ ~RANGE0_PWM_FEEDBACK_DIV_MASK);
+
+ WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG2,
+ (RANGE1_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[1]) |
+ RANGE2_PWM_FEEDBACK_DIV(fv_throt_pwm_fb_div_range[2])));
+
+ WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG3,
+ (RANGE0_PWM(fv_throt_pwm_range[1]) |
+ RANGE1_PWM(fv_throt_pwm_range[2])));
+ WREG32(FVTHROT_PWM_FEEDBACK_DIV_REG4,
+ (RANGE2_PWM(fv_throt_pwm_range[1]) |
+ RANGE3_PWM(fv_throt_pwm_range[2])));
+}
+
+static void rs780_clk_scaling_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT | ENABLE_FV_UPDATE,
+ ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
+ else
+ WREG32_P(FVTHROT_CNTRL_REG, 0,
+ ~(ENABLE_FV_THROT | ENABLE_FV_UPDATE));
+}
+
+static void rs780_voltage_scaling_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(FVTHROT_CNTRL_REG, ENABLE_FV_THROT_IO, ~ENABLE_FV_THROT_IO);
+ else
+ WREG32_P(FVTHROT_CNTRL_REG, 0, ~ENABLE_FV_THROT_IO);
+}
+
+static void rs780_set_engine_clock_wfc(struct radeon_device *rdev)
+{
+ WREG32(FVTHROT_UTC0, RS780_FVTHROTUTC0_DFLT);
+ WREG32(FVTHROT_UTC1, RS780_FVTHROTUTC1_DFLT);
+ WREG32(FVTHROT_UTC2, RS780_FVTHROTUTC2_DFLT);
+ WREG32(FVTHROT_UTC3, RS780_FVTHROTUTC3_DFLT);
+ WREG32(FVTHROT_UTC4, RS780_FVTHROTUTC4_DFLT);
+
+ WREG32(FVTHROT_DTC0, RS780_FVTHROTDTC0_DFLT);
+ WREG32(FVTHROT_DTC1, RS780_FVTHROTDTC1_DFLT);
+ WREG32(FVTHROT_DTC2, RS780_FVTHROTDTC2_DFLT);
+ WREG32(FVTHROT_DTC3, RS780_FVTHROTDTC3_DFLT);
+ WREG32(FVTHROT_DTC4, RS780_FVTHROTDTC4_DFLT);
+}
+
+static void rs780_set_engine_clock_sc(struct radeon_device *rdev)
+{
+ WREG32_P(FVTHROT_FBDIV_REG2,
+ FB_DIV_TIMER_VAL(RS780_FBDIVTIMERVAL_DFLT),
+ ~FB_DIV_TIMER_VAL_MASK);
+
+ WREG32_P(FVTHROT_CNTRL_REG,
+ REFRESH_RATE_DIVISOR(0) | MINIMUM_CIP(0xf),
+ ~(REFRESH_RATE_DIVISOR_MASK | MINIMUM_CIP_MASK));
+}
+
+static void rs780_set_engine_clock_tdc(struct radeon_device *rdev)
+{
+ WREG32_P(FVTHROT_CNTRL_REG, 0, ~(FORCE_TREND_SEL | TREND_SEL_MODE));
+}
+
+static void rs780_set_engine_clock_ssc(struct radeon_device *rdev)
+{
+ WREG32(FVTHROT_FB_US_REG0, RS780_FVTHROTFBUSREG0_DFLT);
+ WREG32(FVTHROT_FB_US_REG1, RS780_FVTHROTFBUSREG1_DFLT);
+ WREG32(FVTHROT_FB_DS_REG0, RS780_FVTHROTFBDSREG0_DFLT);
+ WREG32(FVTHROT_FB_DS_REG1, RS780_FVTHROTFBDSREG1_DFLT);
+
+ WREG32_P(FVTHROT_FBDIV_REG1, MAX_FEEDBACK_STEP(1), ~MAX_FEEDBACK_STEP_MASK);
+}
+
+static void rs780_program_at(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+
+ WREG32(FVTHROT_TARGET_REG, 30000000 / pi->refresh_rate);
+ WREG32(FVTHROT_CB1, 1000000 * 5 / pi->refresh_rate);
+ WREG32(FVTHROT_CB2, 1000000 * 10 / pi->refresh_rate);
+ WREG32(FVTHROT_CB3, 1000000 * 30 / pi->refresh_rate);
+ WREG32(FVTHROT_CB4, 1000000 * 50 / pi->refresh_rate);
+}
+
+static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
+{
+ WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
+}
+
+static void rs780_force_voltage_to_high(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+ struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+ if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
+ (current_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
+ return;
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+ udelay(1);
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0,
+ STARTING_PWM_HIGHTIME(pi->max_voltage),
+ ~STARTING_PWM_HIGHTIME_MASK);
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0,
+ FORCE_STARTING_PWM_HIGHTIME, ~FORCE_STARTING_PWM_HIGHTIME);
+
+ WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1, 0,
+ ~RANGE_PWM_FEEDBACK_DIV_EN);
+
+ udelay(1);
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
+static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct atom_clock_dividers min_dividers, max_dividers, current_max_dividers;
+ struct igp_ps *new_state = rs780_get_ps(new_ps);
+ struct igp_ps *old_state = rs780_get_ps(old_ps);
+ int ret;
+
+ if ((new_state->sclk_high == old_state->sclk_high) &&
+ (new_state->sclk_low == old_state->sclk_low))
+ return 0;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ new_state->sclk_low, false, &min_dividers);
+ if (ret)
+ return ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ new_state->sclk_high, false, &max_dividers);
+ if (ret)
+ return ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ old_state->sclk_high, false, &current_max_dividers);
+ if (ret)
+ return ret;
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+ WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
+ ~FORCED_FEEDBACK_DIV_MASK);
+ WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
+ ~STARTING_FEEDBACK_DIV_MASK);
+ WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+ udelay(100);
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+
+ if (max_dividers.fb_div > min_dividers.fb_div) {
+ WREG32_P(FVTHROT_FBDIV_REG0,
+ MIN_FEEDBACK_DIV(min_dividers.fb_div) |
+ MAX_FEEDBACK_DIV(max_dividers.fb_div),
+ ~(MIN_FEEDBACK_DIV_MASK | MAX_FEEDBACK_DIV_MASK));
+
+ WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+ }
+
+ return 0;
+}
+
+static void rs780_set_engine_clock_spc(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct igp_ps *new_state = rs780_get_ps(new_ps);
+ struct igp_ps *old_state = rs780_get_ps(old_ps);
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+
+ if ((new_state->sclk_high == old_state->sclk_high) &&
+ (new_state->sclk_low == old_state->sclk_low))
+ return;
+
+ if (pi->crtc_id == 0)
+ WREG32_P(CG_INTGFX_MISC, 0, ~FVTHROT_VBLANK_SEL);
+ else
+ WREG32_P(CG_INTGFX_MISC, FVTHROT_VBLANK_SEL, ~FVTHROT_VBLANK_SEL);
+
+}
+
+static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct igp_ps *new_state = rs780_get_ps(new_ps);
+ struct igp_ps *old_state = rs780_get_ps(old_ps);
+
+ if ((new_state->sclk_high == old_state->sclk_high) &&
+ (new_state->sclk_low == old_state->sclk_low))
+ return;
+
+ rs780_clk_scaling_enable(rdev, true);
+}
+
+static u32 rs780_get_voltage_for_vddc_level(struct radeon_device *rdev,
+ enum rs780_vddc_level vddc)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+
+ if (vddc == RS780_VDDC_LEVEL_HIGH)
+ return pi->max_voltage;
+ else if (vddc == RS780_VDDC_LEVEL_LOW)
+ return pi->min_voltage;
+ else
+ return pi->max_voltage;
+}
+
+static void rs780_enable_voltage_scaling(struct radeon_device *rdev,
+ struct radeon_ps *new_ps)
+{
+ struct igp_ps *new_state = rs780_get_ps(new_ps);
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+ enum rs780_vddc_level vddc_high, vddc_low;
+
+ udelay(100);
+
+ if ((new_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
+ (new_state->min_voltage == RS780_VDDC_LEVEL_HIGH))
+ return;
+
+ vddc_high = rs780_get_voltage_for_vddc_level(rdev,
+ new_state->max_voltage);
+ vddc_low = rs780_get_voltage_for_vddc_level(rdev,
+ new_state->min_voltage);
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+ udelay(1);
+ if (vddc_high > vddc_low) {
+ WREG32_P(FVTHROT_PWM_FEEDBACK_DIV_REG1,
+ RANGE_PWM_FEEDBACK_DIV_EN, ~RANGE_PWM_FEEDBACK_DIV_EN);
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0, 0, ~FORCE_STARTING_PWM_HIGHTIME);
+ } else if (vddc_high == vddc_low) {
+ if (pi->max_voltage != vddc_high) {
+ WREG32_P(FVTHROT_PWM_CTRL_REG0,
+ STARTING_PWM_HIGHTIME(vddc_high),
+ ~STARTING_PWM_HIGHTIME_MASK);
+
+ WREG32_P(FVTHROT_PWM_CTRL_REG0,
+ FORCE_STARTING_PWM_HIGHTIME,
+ ~FORCE_STARTING_PWM_HIGHTIME);
+ }
+ }
+
+ WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
+static void rs780_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct igp_ps *new_state = rs780_get_ps(new_ps);
+ struct igp_ps *current_state = rs780_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->sclk_high >= current_state->sclk_high)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+static void rs780_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct igp_ps *new_state = rs780_get_ps(new_ps);
+ struct igp_ps *current_state = rs780_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->sclk_high < current_state->sclk_high)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+int rs780_dpm_enable(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ rs780_get_pm_mode_parameters(rdev);
+ rs780_disable_vbios_powersaving(rdev);
+
+ if (r600_dynamicpm_enabled(rdev))
+ return -EINVAL;
+ ret = rs780_initialize_dpm_parameters(rdev, boot_ps);
+ if (ret)
+ return ret;
+ rs780_start_dpm(rdev);
+
+ rs780_preset_ranges_slow_clk_fbdiv_en(rdev);
+ rs780_preset_starting_fbdiv(rdev);
+ if (pi->voltage_control)
+ rs780_voltage_scaling_init(rdev);
+ rs780_clk_scaling_enable(rdev, true);
+ rs780_set_engine_clock_sc(rdev);
+ rs780_set_engine_clock_wfc(rdev);
+ rs780_program_at(rdev);
+ rs780_set_engine_clock_tdc(rdev);
+ rs780_set_engine_clock_ssc(rdev);
+
+ if (pi->gfx_clock_gating)
+ r600_gfx_clockgating_enable(rdev, true);
+
+ if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
+ ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ }
+
+ return 0;
+}
+
+void rs780_dpm_disable(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+
+ r600_dynamicpm_enable(rdev, false);
+
+ rs780_clk_scaling_enable(rdev, false);
+ rs780_voltage_scaling_enable(rdev, false);
+
+ if (pi->gfx_clock_gating)
+ r600_gfx_clockgating_enable(rdev, false);
+
+ if (rdev->irq.installed &&
+ (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+}
+
+int rs780_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+ struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+ struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+ int ret;
+
+ rs780_get_pm_mode_parameters(rdev);
+
+ rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+
+ if (pi->voltage_control) {
+ rs780_force_voltage_to_high(rdev);
+ mdelay(5);
+ }
+
+ ret = rs780_set_engine_clock_scaling(rdev, new_ps, old_ps);
+ if (ret)
+ return ret;
+ rs780_set_engine_clock_spc(rdev, new_ps, old_ps);
+
+ rs780_activate_engine_clk_scaling(rdev, new_ps, old_ps);
+
+ if (pi->voltage_control)
+ rs780_enable_voltage_scaling(rdev, new_ps);
+
+ rs780_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+
+ return 0;
+}
+
+void rs780_dpm_setup_asic(struct radeon_device *rdev)
+{
+
+}
+
+void rs780_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+ rs780_get_pm_mode_parameters(rdev);
+ rs780_program_at(rdev);
+}
+
+union igp_info {
+ struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+};
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_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 if (r600_is_uvd_state(rps->class, rps->class2)) {
+ rps->vclk = RS780_DEFAULT_VCLK_FREQ;
+ rps->dclk = RS780_DEFAULT_DCLK_FREQ;
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ rdev->pm.dpm.boot_ps = rps;
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rs780_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps,
+ union pplib_clock_info *clock_info)
+{
+ struct igp_ps *ps = rs780_get_ps(rps);
+ u32 sclk;
+
+ sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow);
+ sclk |= clock_info->rs780.ucLowEngineClockHigh << 16;
+ ps->sclk_low = sclk;
+ sclk = le16_to_cpu(clock_info->rs780.usHighEngineClockLow);
+ sclk |= clock_info->rs780.ucHighEngineClockHigh << 16;
+ ps->sclk_high = sclk;
+ switch (le16_to_cpu(clock_info->rs780.usVDDC)) {
+ case ATOM_PPLIB_RS780_VOLTAGE_NONE:
+ default:
+ ps->min_voltage = RS780_VDDC_LEVEL_UNKNOWN;
+ ps->max_voltage = RS780_VDDC_LEVEL_UNKNOWN;
+ break;
+ case ATOM_PPLIB_RS780_VOLTAGE_LOW:
+ ps->min_voltage = RS780_VDDC_LEVEL_LOW;
+ ps->max_voltage = RS780_VDDC_LEVEL_LOW;
+ break;
+ case ATOM_PPLIB_RS780_VOLTAGE_HIGH:
+ ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
+ ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+ break;
+ case ATOM_PPLIB_RS780_VOLTAGE_VARIABLE:
+ ps->min_voltage = RS780_VDDC_LEVEL_LOW;
+ ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+ break;
+ }
+ ps->flags = le32_to_cpu(clock_info->rs780.ulFlags);
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ ps->sclk_low = rdev->clock.default_sclk;
+ ps->sclk_high = rdev->clock.default_sclk;
+ ps->min_voltage = RS780_VDDC_LEVEL_HIGH;
+ ps->max_voltage = RS780_VDDC_LEVEL_HIGH;
+ }
+}
+
+static int rs780_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i;
+ union pplib_clock_info *clock_info;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ struct igp_ps *ps;
+
+ if (!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);
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ power_info->pplib.ucNumStates, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+ for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+ power_state = (union pplib_power_state *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+ i * power_info->pplib.ucStateEntrySize);
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+ (power_state->v1.ucNonClockStateIndex *
+ power_info->pplib.ucNonClockSize));
+ if (power_info->pplib.ucStateEntrySize - 1) {
+ clock_info = (union pplib_clock_info *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+ (power_state->v1.ucClockStateIndices[0] *
+ power_info->pplib.ucClockInfoSize));
+ ps = kzalloc(sizeof(struct igp_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.ps[i].ps_priv = ps;
+ rs780_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info,
+ power_info->pplib.ucNonClockSize);
+ rs780_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i],
+ clock_info);
+ }
+ }
+ rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+ return 0;
+}
+
+int rs780_dpm_init(struct radeon_device *rdev)
+{
+ struct igp_power_info *pi;
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ union igp_info *info;
+ u16 data_offset;
+ u8 frev, crev;
+ int ret;
+
+ pi = kzalloc(sizeof(struct igp_power_info), GFP_KERNEL);
+ if (pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = pi;
+
+ ret = rs780_parse_power_table(rdev);
+ if (ret)
+ return ret;
+
+ pi->voltage_control = false;
+ pi->gfx_clock_gating = true;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, NULL,
+ &frev, &crev, &data_offset)) {
+ info = (union igp_info *)(rdev->mode_info.atom_context->bios + data_offset);
+
+ /* Get various system informations from bios */
+ switch (crev) {
+ case 1:
+ pi->num_of_cycles_in_period =
+ info->info.ucNumberOfCyclesInPeriod;
+ pi->num_of_cycles_in_period |=
+ info->info.ucNumberOfCyclesInPeriodHi << 8;
+ pi->invert_pwm_required =
+ (pi->num_of_cycles_in_period & 0x8000) ? true : false;
+ pi->boot_voltage = info->info.ucStartingPWM_HighTime;
+ pi->max_voltage = info->info.ucMaxNBVoltage;
+ pi->max_voltage |= info->info.ucMaxNBVoltageHigh << 8;
+ pi->min_voltage = info->info.ucMinNBVoltage;
+ pi->min_voltage |= info->info.ucMinNBVoltageHigh << 8;
+ pi->inter_voltage_low =
+ le16_to_cpu(info->info.usInterNBVoltageLow);
+ pi->inter_voltage_high =
+ le16_to_cpu(info->info.usInterNBVoltageHigh);
+ pi->voltage_control = true;
+ pi->bootup_uma_clk = info->info.usK8MemoryClock * 100;
+ break;
+ case 2:
+ pi->num_of_cycles_in_period =
+ le16_to_cpu(info->info_2.usNumberOfCyclesInPeriod);
+ pi->invert_pwm_required =
+ (pi->num_of_cycles_in_period & 0x8000) ? true : false;
+ pi->boot_voltage =
+ le16_to_cpu(info->info_2.usBootUpNBVoltage);
+ pi->max_voltage =
+ le16_to_cpu(info->info_2.usMaxNBVoltage);
+ pi->min_voltage =
+ le16_to_cpu(info->info_2.usMinNBVoltage);
+ pi->system_config =
+ le32_to_cpu(info->info_2.ulSystemConfig);
+ pi->pwm_voltage_control =
+ (pi->system_config & 0x4) ? true : false;
+ pi->voltage_control = true;
+ pi->bootup_uma_clk = le32_to_cpu(info->info_2.ulBootUpUMAClock);
+ break;
+ default:
+ DRM_ERROR("No integrated system info for your GPU\n");
+ return -EINVAL;
+ }
+ if (pi->min_voltage > pi->max_voltage)
+ pi->voltage_control = false;
+ if (pi->pwm_voltage_control) {
+ if ((pi->num_of_cycles_in_period == 0) ||
+ (pi->max_voltage == 0) ||
+ (pi->min_voltage == 0))
+ pi->voltage_control = false;
+ } else {
+ if ((pi->num_of_cycles_in_period == 0) ||
+ (pi->max_voltage == 0))
+ pi->voltage_control = false;
+ }
+
+ return 0;
+ }
+ radeon_dpm_fini(rdev);
+ return -EINVAL;
+}
+
+void rs780_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct igp_ps *ps = rs780_get_ps(rps);
+
+ r600_dpm_print_class_info(rps->class, rps->class2);
+ r600_dpm_print_cap_info(rps->caps);
+ printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ printk("\t\tpower level 0 sclk: %u vddc_index: %d\n",
+ ps->sclk_low, ps->min_voltage);
+ printk("\t\tpower level 1 sclk: %u vddc_index: %d\n",
+ ps->sclk_high, ps->max_voltage);
+ r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rs780_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+}
+
+u32 rs780_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct igp_ps *requested_state = rs780_get_ps(rdev->pm.dpm.requested_ps);
+
+ if (low)
+ return requested_state->sclk_low;
+ else
+ return requested_state->sclk_high;
+}
+
+u32 rs780_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct igp_power_info *pi = rs780_get_pi(rdev);
+
+ return pi->bootup_uma_clk;
+}
diff --git a/drivers/gpu/drm/radeon/rs780_dpm.h b/drivers/gpu/drm/radeon/rs780_dpm.h
new file mode 100644
index 000000000000..47a40b14fa43
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780_dpm.h
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __RS780_DPM_H__
+#define __RS780_DPM_H__
+
+enum rs780_vddc_level {
+ RS780_VDDC_LEVEL_UNKNOWN = 0,
+ RS780_VDDC_LEVEL_LOW = 1,
+ RS780_VDDC_LEVEL_HIGH = 2,
+};
+
+struct igp_power_info {
+ /* flags */
+ bool invert_pwm_required;
+ bool pwm_voltage_control;
+ bool voltage_control;
+ bool gfx_clock_gating;
+ /* stored values */
+ u32 system_config;
+ u32 bootup_uma_clk;
+ u16 max_voltage;
+ u16 min_voltage;
+ u16 boot_voltage;
+ u16 inter_voltage_low;
+ u16 inter_voltage_high;
+ u16 num_of_cycles_in_period;
+ /* variable */
+ int crtc_id;
+ int refresh_rate;
+};
+
+struct igp_ps {
+ enum rs780_vddc_level min_voltage;
+ enum rs780_vddc_level max_voltage;
+ u32 sclk_low;
+ u32 sclk_high;
+ u32 flags;
+};
+
+#define RS780_CGFTV_DFLT 0x0303000f
+#define RS780_FBDIVTIMERVAL_DFLT 0x2710
+
+#define RS780_FVTHROTUTC0_DFLT 0x04010040
+#define RS780_FVTHROTUTC1_DFLT 0x04010040
+#define RS780_FVTHROTUTC2_DFLT 0x04010040
+#define RS780_FVTHROTUTC3_DFLT 0x04010040
+#define RS780_FVTHROTUTC4_DFLT 0x04010040
+
+#define RS780_FVTHROTDTC0_DFLT 0x04010040
+#define RS780_FVTHROTDTC1_DFLT 0x04010040
+#define RS780_FVTHROTDTC2_DFLT 0x04010040
+#define RS780_FVTHROTDTC3_DFLT 0x04010040
+#define RS780_FVTHROTDTC4_DFLT 0x04010040
+
+#define RS780_FVTHROTFBUSREG0_DFLT 0x00001001
+#define RS780_FVTHROTFBUSREG1_DFLT 0x00002002
+#define RS780_FVTHROTFBDSREG0_DFLT 0x00004001
+#define RS780_FVTHROTFBDSREG1_DFLT 0x00020010
+
+#define RS780_FVTHROTPWMUSREG0_DFLT 0x00002001
+#define RS780_FVTHROTPWMUSREG1_DFLT 0x00004003
+#define RS780_FVTHROTPWMDSREG0_DFLT 0x00002001
+#define RS780_FVTHROTPWMDSREG1_DFLT 0x00004003
+
+#define RS780_FVTHROTPWMFBDIVRANGEREG0_DFLT 0x37
+#define RS780_FVTHROTPWMFBDIVRANGEREG1_DFLT 0x4b
+#define RS780_FVTHROTPWMFBDIVRANGEREG2_DFLT 0x8b
+
+#define RS780D_FVTHROTPWMFBDIVRANGEREG0_DFLT 0x8b
+#define RS780D_FVTHROTPWMFBDIVRANGEREG1_DFLT 0x8c
+#define RS780D_FVTHROTPWMFBDIVRANGEREG2_DFLT 0xb5
+
+#define RS880D_FVTHROTPWMFBDIVRANGEREG0_DFLT 0x8d
+#define RS880D_FVTHROTPWMFBDIVRANGEREG1_DFLT 0x8e
+#define RS880D_FVTHROTPWMFBDIVRANGEREG2_DFLT 0xBa
+
+#define RS780_FVTHROTPWMRANGE0_GPIO_DFLT 0x1a
+#define RS780_FVTHROTPWMRANGE1_GPIO_DFLT 0x1a
+#define RS780_FVTHROTPWMRANGE2_GPIO_DFLT 0x0
+#define RS780_FVTHROTPWMRANGE3_GPIO_DFLT 0x0
+
+#define RS780_SLOWCLKFEEDBACKDIV_DFLT 110
+
+#define RS780_CGCLKGATING_DFLT 0x0000E204
+
+#define RS780_DEFAULT_VCLK_FREQ 53300 /* 10 khz */
+#define RS780_DEFAULT_DCLK_FREQ 40000 /* 10 khz */
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs780d.h b/drivers/gpu/drm/radeon/rs780d.h
new file mode 100644
index 000000000000..b1142ed1c628
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs780d.h
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __RS780D_H__
+#define __RS780D_H__
+
+#define CG_SPLL_FUNC_CNTL 0x600
+# define SPLL_RESET (1 << 0)
+# define SPLL_SLEEP (1 << 1)
+# define SPLL_REF_DIV(x) ((x) << 2)
+# define SPLL_REF_DIV_MASK (7 << 2)
+# define SPLL_FB_DIV(x) ((x) << 5)
+# define SPLL_FB_DIV_MASK (0xff << 2)
+# define SPLL_FB_DIV_SHIFT 2
+# define SPLL_PULSEEN (1 << 13)
+# define SPLL_PULSENUM(x) ((x) << 14)
+# define SPLL_PULSENUM_MASK (3 << 14)
+# define SPLL_SW_HILEN(x) ((x) << 16)
+# define SPLL_SW_HILEN_MASK (0xf << 16)
+# define SPLL_SW_LOLEN(x) ((x) << 20)
+# define SPLL_SW_LOLEN_MASK (0xf << 20)
+# define SPLL_DIVEN (1 << 24)
+# define SPLL_BYPASS_EN (1 << 25)
+# define SPLL_CHG_STATUS (1 << 29)
+# define SPLL_CTLREQ (1 << 30)
+# define SPLL_CTLACK (1 << 31)
+
+/* RS780/RS880 PM */
+#define FVTHROT_CNTRL_REG 0x3000
+#define DONT_WAIT_FOR_FBDIV_WRAP (1 << 0)
+#define MINIMUM_CIP(x) ((x) << 1)
+#define MINIMUM_CIP_SHIFT 1
+#define MINIMUM_CIP_MASK 0x1fffffe
+#define REFRESH_RATE_DIVISOR(x) ((x) << 25)
+#define REFRESH_RATE_DIVISOR_SHIFT 25
+#define REFRESH_RATE_DIVISOR_MASK (0x3 << 25)
+#define ENABLE_FV_THROT (1 << 27)
+#define ENABLE_FV_UPDATE (1 << 28)
+#define TREND_SEL_MODE (1 << 29)
+#define FORCE_TREND_SEL (1 << 30)
+#define ENABLE_FV_THROT_IO (1 << 31)
+#define FVTHROT_TARGET_REG 0x3004
+#define TARGET_IDLE_COUNT(x) ((x) << 0)
+#define TARGET_IDLE_COUNT_MASK 0xffffff
+#define TARGET_IDLE_COUNT_SHIFT 0
+#define FVTHROT_CB1 0x3008
+#define FVTHROT_CB2 0x300c
+#define FVTHROT_CB3 0x3010
+#define FVTHROT_CB4 0x3014
+#define FVTHROT_UTC0 0x3018
+#define FVTHROT_UTC1 0x301c
+#define FVTHROT_UTC2 0x3020
+#define FVTHROT_UTC3 0x3024
+#define FVTHROT_UTC4 0x3028
+#define FVTHROT_DTC0 0x302c
+#define FVTHROT_DTC1 0x3030
+#define FVTHROT_DTC2 0x3034
+#define FVTHROT_DTC3 0x3038
+#define FVTHROT_DTC4 0x303c
+#define FVTHROT_FBDIV_REG0 0x3040
+#define MIN_FEEDBACK_DIV(x) ((x) << 0)
+#define MIN_FEEDBACK_DIV_MASK 0xfff
+#define MIN_FEEDBACK_DIV_SHIFT 0
+#define MAX_FEEDBACK_DIV(x) ((x) << 12)
+#define MAX_FEEDBACK_DIV_MASK (0xfff << 12)
+#define MAX_FEEDBACK_DIV_SHIFT 12
+#define FVTHROT_FBDIV_REG1 0x3044
+#define MAX_FEEDBACK_STEP(x) ((x) << 0)
+#define MAX_FEEDBACK_STEP_MASK 0xfff
+#define MAX_FEEDBACK_STEP_SHIFT 0
+#define STARTING_FEEDBACK_DIV(x) ((x) << 12)
+#define STARTING_FEEDBACK_DIV_MASK (0xfff << 12)
+#define STARTING_FEEDBACK_DIV_SHIFT 12
+#define FORCE_FEEDBACK_DIV (1 << 24)
+#define FVTHROT_FBDIV_REG2 0x3048
+#define FORCED_FEEDBACK_DIV(x) ((x) << 0)
+#define FORCED_FEEDBACK_DIV_MASK 0xfff
+#define FORCED_FEEDBACK_DIV_SHIFT 0
+#define FB_DIV_TIMER_VAL(x) ((x) << 12)
+#define FB_DIV_TIMER_VAL_MASK (0xffff << 12)
+#define FB_DIV_TIMER_VAL_SHIFT 12
+#define FVTHROT_FB_US_REG0 0x304c
+#define FVTHROT_FB_US_REG1 0x3050
+#define FVTHROT_FB_DS_REG0 0x3054
+#define FVTHROT_FB_DS_REG1 0x3058
+#define FVTHROT_PWM_CTRL_REG0 0x305c
+#define STARTING_PWM_HIGHTIME(x) ((x) << 0)
+#define STARTING_PWM_HIGHTIME_MASK 0xfff
+#define STARTING_PWM_HIGHTIME_SHIFT 0
+#define NUMBER_OF_CYCLES_IN_PERIOD(x) ((x) << 12)
+#define NUMBER_OF_CYCLES_IN_PERIOD_MASK (0xfff << 12)
+#define NUMBER_OF_CYCLES_IN_PERIOD_SHIFT 12
+#define FORCE_STARTING_PWM_HIGHTIME (1 << 24)
+#define INVERT_PWM_WAVEFORM (1 << 25)
+#define FVTHROT_PWM_CTRL_REG1 0x3060
+#define MIN_PWM_HIGHTIME(x) ((x) << 0)
+#define MIN_PWM_HIGHTIME_MASK 0xfff
+#define MIN_PWM_HIGHTIME_SHIFT 0
+#define MAX_PWM_HIGHTIME(x) ((x) << 12)
+#define MAX_PWM_HIGHTIME_MASK (0xfff << 12)
+#define MAX_PWM_HIGHTIME_SHIFT 12
+#define FVTHROT_PWM_US_REG0 0x3064
+#define FVTHROT_PWM_US_REG1 0x3068
+#define FVTHROT_PWM_DS_REG0 0x306c
+#define FVTHROT_PWM_DS_REG1 0x3070
+#define FVTHROT_STATUS_REG0 0x3074
+#define CURRENT_FEEDBACK_DIV_MASK 0xfff
+#define CURRENT_FEEDBACK_DIV_SHIFT 0
+#define FVTHROT_STATUS_REG1 0x3078
+#define FVTHROT_STATUS_REG2 0x307c
+#define CG_INTGFX_MISC 0x3080
+#define FVTHROT_VBLANK_SEL (1 << 9)
+#define FVTHROT_PWM_FEEDBACK_DIV_REG1 0x308c
+#define RANGE0_PWM_FEEDBACK_DIV(x) ((x) << 0)
+#define RANGE0_PWM_FEEDBACK_DIV_MASK 0xfff
+#define RANGE0_PWM_FEEDBACK_DIV_SHIFT 0
+#define RANGE_PWM_FEEDBACK_DIV_EN (1 << 12)
+#define FVTHROT_PWM_FEEDBACK_DIV_REG2 0x3090
+#define RANGE1_PWM_FEEDBACK_DIV(x) ((x) << 0)
+#define RANGE1_PWM_FEEDBACK_DIV_MASK 0xfff
+#define RANGE1_PWM_FEEDBACK_DIV_SHIFT 0
+#define RANGE2_PWM_FEEDBACK_DIV(x) ((x) << 12)
+#define RANGE2_PWM_FEEDBACK_DIV_MASK (0xfff << 12)
+#define RANGE2_PWM_FEEDBACK_DIV_SHIFT 12
+#define FVTHROT_PWM_FEEDBACK_DIV_REG3 0x3094
+#define RANGE0_PWM(x) ((x) << 0)
+#define RANGE0_PWM_MASK 0xfff
+#define RANGE0_PWM_SHIFT 0
+#define RANGE1_PWM(x) ((x) << 12)
+#define RANGE1_PWM_MASK (0xfff << 12)
+#define RANGE1_PWM_SHIFT 12
+#define FVTHROT_PWM_FEEDBACK_DIV_REG4 0x3098
+#define RANGE2_PWM(x) ((x) << 0)
+#define RANGE2_PWM_MASK 0xfff
+#define RANGE2_PWM_SHIFT 0
+#define RANGE3_PWM(x) ((x) << 12)
+#define RANGE3_PWM_MASK (0xfff << 12)
+#define RANGE3_PWM_SHIFT 12
+#define FVTHROT_SLOW_CLK_FEEDBACK_DIV_REG1 0x30ac
+#define RANGE0_SLOW_CLK_FEEDBACK_DIV(x) ((x) << 0)
+#define RANGE0_SLOW_CLK_FEEDBACK_DIV_MASK 0xfff
+#define RANGE0_SLOW_CLK_FEEDBACK_DIV_SHIFT 0
+#define RANGE_SLOW_CLK_FEEDBACK_DIV_EN (1 << 12)
+
+#define GFX_MACRO_BYPASS_CNTL 0x30c0
+#define SPLL_BYPASS_CNTL (1 << 0)
+#define UPLL_BYPASS_CNTL (1 << 1)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 21c7d7b26e55..8ea1573ae820 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -937,13 +937,16 @@ struct rv515_watermark {
};
static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
- struct radeon_crtc *crtc,
- struct rv515_watermark *wm)
+ struct radeon_crtc *crtc,
+ struct rv515_watermark *wm,
+ bool low)
{
struct drm_display_mode *mode = &crtc->base.mode;
fixed20_12 a, b, c;
fixed20_12 pclk, request_fifo_depth, tolerable_latency, estimated_width;
fixed20_12 consumption_time, line_time, chunk_time, read_delay_latency;
+ fixed20_12 sclk;
+ u32 selected_sclk;
if (!crtc->base.enabled) {
/* FIXME: wouldn't it better to set priority mark to maximum */
@@ -951,6 +954,18 @@ static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
return;
}
+ /* rv6xx, rv7xx */
+ if ((rdev->family >= CHIP_RV610) &&
+ (rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled)
+ selected_sclk = radeon_dpm_get_sclk(rdev, low);
+ else
+ selected_sclk = rdev->pm.current_sclk;
+
+ /* sclk in Mhz */
+ a.full = dfixed_const(100);
+ sclk.full = dfixed_const(selected_sclk);
+ sclk.full = dfixed_div(sclk, a);
+
if (crtc->vsc.full > dfixed_const(2))
wm->num_line_pair.full = dfixed_const(2);
else
@@ -1016,7 +1031,7 @@ static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
* sclk = system clock(Mhz)
*/
a.full = dfixed_const(600 * 1000);
- chunk_time.full = dfixed_div(a, rdev->pm.sclk);
+ chunk_time.full = dfixed_div(a, sclk);
read_delay_latency.full = dfixed_const(1000);
/* Determine the worst case latency
@@ -1077,152 +1092,177 @@ static void rv515_crtc_bandwidth_compute(struct radeon_device *rdev,
}
}
-void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
+static void rv515_compute_mode_priority(struct radeon_device *rdev,
+ struct rv515_watermark *wm0,
+ struct rv515_watermark *wm1,
+ struct drm_display_mode *mode0,
+ struct drm_display_mode *mode1,
+ u32 *d1mode_priority_a_cnt,
+ u32 *d2mode_priority_a_cnt)
{
- struct drm_display_mode *mode0 = NULL;
- struct drm_display_mode *mode1 = NULL;
- struct rv515_watermark wm0;
- struct rv515_watermark wm1;
- u32 tmp;
- u32 d1mode_priority_a_cnt = MODE_PRIORITY_OFF;
- u32 d2mode_priority_a_cnt = MODE_PRIORITY_OFF;
fixed20_12 priority_mark02, priority_mark12, fill_rate;
fixed20_12 a, b;
- if (rdev->mode_info.crtcs[0]->base.enabled)
- mode0 = &rdev->mode_info.crtcs[0]->base.mode;
- if (rdev->mode_info.crtcs[1]->base.enabled)
- mode1 = &rdev->mode_info.crtcs[1]->base.mode;
- rs690_line_buffer_adjust(rdev, mode0, mode1);
-
- rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0);
- rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1);
-
- tmp = wm0.lb_request_fifo_depth;
- tmp |= wm1.lb_request_fifo_depth << 16;
- WREG32(LB_MAX_REQ_OUTSTANDING, tmp);
+ *d1mode_priority_a_cnt = MODE_PRIORITY_OFF;
+ *d2mode_priority_a_cnt = MODE_PRIORITY_OFF;
if (mode0 && mode1) {
- if (dfixed_trunc(wm0.dbpp) > 64)
- a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair);
+ if (dfixed_trunc(wm0->dbpp) > 64)
+ a.full = dfixed_div(wm0->dbpp, wm0->num_line_pair);
else
- a.full = wm0.num_line_pair.full;
- if (dfixed_trunc(wm1.dbpp) > 64)
- b.full = dfixed_div(wm1.dbpp, wm1.num_line_pair);
+ a.full = wm0->num_line_pair.full;
+ if (dfixed_trunc(wm1->dbpp) > 64)
+ b.full = dfixed_div(wm1->dbpp, wm1->num_line_pair);
else
- b.full = wm1.num_line_pair.full;
+ b.full = wm1->num_line_pair.full;
a.full += b.full;
- fill_rate.full = dfixed_div(wm0.sclk, a);
- if (wm0.consumption_rate.full > fill_rate.full) {
- b.full = wm0.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm0.active_time);
+ fill_rate.full = dfixed_div(wm0->sclk, a);
+ if (wm0->consumption_rate.full > fill_rate.full) {
+ b.full = wm0->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm0->active_time);
a.full = dfixed_const(16);
b.full = dfixed_div(b, a);
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
priority_mark02.full = a.full + b.full;
} else {
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark02.full = dfixed_div(a, b);
}
- if (wm1.consumption_rate.full > fill_rate.full) {
- b.full = wm1.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm1.active_time);
+ if (wm1->consumption_rate.full > fill_rate.full) {
+ b.full = wm1->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm1->active_time);
a.full = dfixed_const(16);
b.full = dfixed_div(b, a);
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
priority_mark12.full = a.full + b.full;
} else {
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark12.full = dfixed_div(a, b);
}
- if (wm0.priority_mark.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark.full;
+ if (wm0->priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark.full;
if (dfixed_trunc(priority_mark02) < 0)
priority_mark02.full = 0;
- if (wm0.priority_mark_max.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark_max.full;
- if (wm1.priority_mark.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark.full;
+ if (wm0->priority_mark_max.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark_max.full;
+ if (wm1->priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark.full;
if (dfixed_trunc(priority_mark12) < 0)
priority_mark12.full = 0;
- if (wm1.priority_mark_max.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark_max.full;
- d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
- d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+ if (wm1->priority_mark_max.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark_max.full;
+ *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+ *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
if (rdev->disp_priority == 2) {
- d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
- d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+ *d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+ *d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
}
} else if (mode0) {
- if (dfixed_trunc(wm0.dbpp) > 64)
- a.full = dfixed_div(wm0.dbpp, wm0.num_line_pair);
+ if (dfixed_trunc(wm0->dbpp) > 64)
+ a.full = dfixed_div(wm0->dbpp, wm0->num_line_pair);
else
- a.full = wm0.num_line_pair.full;
- fill_rate.full = dfixed_div(wm0.sclk, a);
- if (wm0.consumption_rate.full > fill_rate.full) {
- b.full = wm0.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm0.active_time);
+ a.full = wm0->num_line_pair.full;
+ fill_rate.full = dfixed_div(wm0->sclk, a);
+ if (wm0->consumption_rate.full > fill_rate.full) {
+ b.full = wm0->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm0->active_time);
a.full = dfixed_const(16);
b.full = dfixed_div(b, a);
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
priority_mark02.full = a.full + b.full;
} else {
- a.full = dfixed_mul(wm0.worst_case_latency,
- wm0.consumption_rate);
+ a.full = dfixed_mul(wm0->worst_case_latency,
+ wm0->consumption_rate);
b.full = dfixed_const(16);
priority_mark02.full = dfixed_div(a, b);
}
- if (wm0.priority_mark.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark.full;
+ if (wm0->priority_mark.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark.full;
if (dfixed_trunc(priority_mark02) < 0)
priority_mark02.full = 0;
- if (wm0.priority_mark_max.full > priority_mark02.full)
- priority_mark02.full = wm0.priority_mark_max.full;
- d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
+ if (wm0->priority_mark_max.full > priority_mark02.full)
+ priority_mark02.full = wm0->priority_mark_max.full;
+ *d1mode_priority_a_cnt = dfixed_trunc(priority_mark02);
if (rdev->disp_priority == 2)
- d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+ *d1mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
} else if (mode1) {
- if (dfixed_trunc(wm1.dbpp) > 64)
- a.full = dfixed_div(wm1.dbpp, wm1.num_line_pair);
+ if (dfixed_trunc(wm1->dbpp) > 64)
+ a.full = dfixed_div(wm1->dbpp, wm1->num_line_pair);
else
- a.full = wm1.num_line_pair.full;
- fill_rate.full = dfixed_div(wm1.sclk, a);
- if (wm1.consumption_rate.full > fill_rate.full) {
- b.full = wm1.consumption_rate.full - fill_rate.full;
- b.full = dfixed_mul(b, wm1.active_time);
+ a.full = wm1->num_line_pair.full;
+ fill_rate.full = dfixed_div(wm1->sclk, a);
+ if (wm1->consumption_rate.full > fill_rate.full) {
+ b.full = wm1->consumption_rate.full - fill_rate.full;
+ b.full = dfixed_mul(b, wm1->active_time);
a.full = dfixed_const(16);
b.full = dfixed_div(b, a);
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
priority_mark12.full = a.full + b.full;
} else {
- a.full = dfixed_mul(wm1.worst_case_latency,
- wm1.consumption_rate);
+ a.full = dfixed_mul(wm1->worst_case_latency,
+ wm1->consumption_rate);
b.full = dfixed_const(16 * 1000);
priority_mark12.full = dfixed_div(a, b);
}
- if (wm1.priority_mark.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark.full;
+ if (wm1->priority_mark.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark.full;
if (dfixed_trunc(priority_mark12) < 0)
priority_mark12.full = 0;
- if (wm1.priority_mark_max.full > priority_mark12.full)
- priority_mark12.full = wm1.priority_mark_max.full;
- d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
+ if (wm1->priority_mark_max.full > priority_mark12.full)
+ priority_mark12.full = wm1->priority_mark_max.full;
+ *d2mode_priority_a_cnt = dfixed_trunc(priority_mark12);
if (rdev->disp_priority == 2)
- d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
+ *d2mode_priority_a_cnt |= MODE_PRIORITY_ALWAYS_ON;
}
+}
+
+void rv515_bandwidth_avivo_update(struct radeon_device *rdev)
+{
+ struct drm_display_mode *mode0 = NULL;
+ struct drm_display_mode *mode1 = NULL;
+ struct rv515_watermark wm0_high, wm0_low;
+ struct rv515_watermark wm1_high, wm1_low;
+ u32 tmp;
+ u32 d1mode_priority_a_cnt, d1mode_priority_b_cnt;
+ u32 d2mode_priority_a_cnt, d2mode_priority_b_cnt;
+
+ if (rdev->mode_info.crtcs[0]->base.enabled)
+ mode0 = &rdev->mode_info.crtcs[0]->base.mode;
+ if (rdev->mode_info.crtcs[1]->base.enabled)
+ mode1 = &rdev->mode_info.crtcs[1]->base.mode;
+ rs690_line_buffer_adjust(rdev, mode0, mode1);
+
+ rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_high, false);
+ rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_high, false);
+
+ rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0_low, false);
+ rv515_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1_low, false);
+
+ tmp = wm0_high.lb_request_fifo_depth;
+ tmp |= wm1_high.lb_request_fifo_depth << 16;
+ WREG32(LB_MAX_REQ_OUTSTANDING, tmp);
+
+ rv515_compute_mode_priority(rdev,
+ &wm0_high, &wm1_high,
+ mode0, mode1,
+ &d1mode_priority_a_cnt, &d2mode_priority_a_cnt);
+ rv515_compute_mode_priority(rdev,
+ &wm0_low, &wm1_low,
+ mode0, mode1,
+ &d1mode_priority_b_cnt, &d2mode_priority_b_cnt);
WREG32(D1MODE_PRIORITY_A_CNT, d1mode_priority_a_cnt);
- WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_a_cnt);
+ WREG32(D1MODE_PRIORITY_B_CNT, d1mode_priority_b_cnt);
WREG32(D2MODE_PRIORITY_A_CNT, d2mode_priority_a_cnt);
- WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_a_cnt);
+ WREG32(D2MODE_PRIORITY_B_CNT, d2mode_priority_b_cnt);
}
void rv515_bandwidth_update(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c
new file mode 100644
index 000000000000..8303de267ee5
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c
@@ -0,0 +1,2085 @@
+/*
+ * 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 "radeon.h"
+#include "rv6xxd.h"
+#include "r600_dpm.h"
+#include "rv6xx_dpm.h"
+#include "atom.h"
+#include <linux/seq_file.h>
+
+static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
+ u32 unscaled_count, u32 unit);
+
+static struct rv6xx_ps *rv6xx_get_ps(struct radeon_ps *rps)
+{
+ struct rv6xx_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+static struct rv6xx_power_info *rv6xx_get_pi(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+static void rv6xx_force_pcie_gen1(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int i;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ tmp &= LC_GEN2_EN;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ tmp |= LC_INITIATE_LINK_SPEED_CHANGE;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (!(RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE))
+ break;
+ udelay(1);
+ }
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ tmp &= ~LC_INITIATE_LINK_SPEED_CHANGE;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+}
+
+static void rv6xx_enable_pcie_gen2_support(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2)) {
+ tmp |= LC_GEN2_EN;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+ }
+}
+
+static void rv6xx_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ if (enable)
+ tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+ else
+ tmp |= LC_HW_VOLTAGE_IF_CONTROL(0);
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+}
+
+static void rv6xx_enable_l0s(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK;
+ tmp |= LC_L0S_INACTIVITY(3);
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv6xx_enable_l1(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+ tmp &= ~LC_L1_INACTIVITY_MASK;
+ tmp |= LC_L1_INACTIVITY(4);
+ tmp &= ~LC_PMI_TO_L1_DIS;
+ tmp &= ~LC_ASPM_TO_L1_DIS;
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv6xx_enable_pll_sleep_in_l1(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK;
+ tmp |= LC_L1_INACTIVITY(8);
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+
+ /* NOTE, this is a PCIE indirect reg, not PCIE PORT */
+ tmp = RREG32_PCIE(PCIE_P_CNTL);
+ tmp |= P_PLL_PWRDN_IN_L1L23;
+ tmp &= ~P_PLL_BUF_PDNB;
+ tmp &= ~P_PLL_PDNB;
+ tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF;
+ WREG32_PCIE(PCIE_P_CNTL, tmp);
+}
+
+static int rv6xx_convert_clock_to_stepping(struct radeon_device *rdev,
+ u32 clock, struct rv6xx_sclk_stepping *step)
+{
+ int ret;
+ struct atom_clock_dividers dividers;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ if (dividers.enable_post_div)
+ step->post_divider = 2 + (dividers.post_div & 0xF) + (dividers.post_div >> 4);
+ else
+ step->post_divider = 1;
+
+ step->vco_frequency = clock * step->post_divider;
+
+ return 0;
+}
+
+static void rv6xx_output_stepping(struct radeon_device *rdev,
+ u32 step_index, struct rv6xx_sclk_stepping *step)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ u32 ref_clk = rdev->clock.spll.reference_freq;
+ u32 fb_divider;
+ u32 spll_step_count = rv6xx_scale_count_given_unit(rdev,
+ R600_SPLLSTEPTIME_DFLT *
+ pi->spll_ref_div,
+ R600_SPLLSTEPUNIT_DFLT);
+
+ r600_engine_clock_entry_enable(rdev, step_index, true);
+ r600_engine_clock_entry_enable_pulse_skipping(rdev, step_index, false);
+
+ if (step->post_divider == 1)
+ r600_engine_clock_entry_enable_post_divider(rdev, step_index, false);
+ else {
+ u32 lo_len = (step->post_divider - 2) / 2;
+ u32 hi_len = step->post_divider - 2 - lo_len;
+
+ r600_engine_clock_entry_enable_post_divider(rdev, step_index, true);
+ r600_engine_clock_entry_set_post_divider(rdev, step_index, (hi_len << 4) | lo_len);
+ }
+
+ fb_divider = ((step->vco_frequency * pi->spll_ref_div) / ref_clk) >>
+ pi->fb_div_scale;
+
+ r600_engine_clock_entry_set_reference_divider(rdev, step_index,
+ pi->spll_ref_div - 1);
+ r600_engine_clock_entry_set_feedback_divider(rdev, step_index, fb_divider);
+ r600_engine_clock_entry_set_step_time(rdev, step_index, spll_step_count);
+
+}
+
+static struct rv6xx_sclk_stepping rv6xx_next_vco_step(struct radeon_device *rdev,
+ struct rv6xx_sclk_stepping *cur,
+ bool increasing_vco, u32 step_size)
+{
+ struct rv6xx_sclk_stepping next;
+
+ next.post_divider = cur->post_divider;
+
+ if (increasing_vco)
+ next.vco_frequency = (cur->vco_frequency * (100 + step_size)) / 100;
+ else
+ next.vco_frequency = (cur->vco_frequency * 100 + 99 + step_size) / (100 + step_size);
+
+ return next;
+}
+
+static bool rv6xx_can_step_post_div(struct radeon_device *rdev,
+ struct rv6xx_sclk_stepping *cur,
+ struct rv6xx_sclk_stepping *target)
+{
+ return (cur->post_divider > target->post_divider) &&
+ ((cur->vco_frequency * target->post_divider) <=
+ (target->vco_frequency * (cur->post_divider - 1)));
+}
+
+static struct rv6xx_sclk_stepping rv6xx_next_post_div_step(struct radeon_device *rdev,
+ struct rv6xx_sclk_stepping *cur,
+ struct rv6xx_sclk_stepping *target)
+{
+ struct rv6xx_sclk_stepping next = *cur;
+
+ while (rv6xx_can_step_post_div(rdev, &next, target))
+ next.post_divider--;
+
+ return next;
+}
+
+static bool rv6xx_reached_stepping_target(struct radeon_device *rdev,
+ struct rv6xx_sclk_stepping *cur,
+ struct rv6xx_sclk_stepping *target,
+ bool increasing_vco)
+{
+ return (increasing_vco && (cur->vco_frequency >= target->vco_frequency)) ||
+ (!increasing_vco && (cur->vco_frequency <= target->vco_frequency));
+}
+
+static void rv6xx_generate_steps(struct radeon_device *rdev,
+ u32 low, u32 high,
+ u32 start_index, u8 *end_index)
+{
+ struct rv6xx_sclk_stepping cur;
+ struct rv6xx_sclk_stepping target;
+ bool increasing_vco;
+ u32 step_index = start_index;
+
+ rv6xx_convert_clock_to_stepping(rdev, low, &cur);
+ rv6xx_convert_clock_to_stepping(rdev, high, &target);
+
+ rv6xx_output_stepping(rdev, step_index++, &cur);
+
+ increasing_vco = (target.vco_frequency >= cur.vco_frequency);
+
+ if (target.post_divider > cur.post_divider)
+ cur.post_divider = target.post_divider;
+
+ while (1) {
+ struct rv6xx_sclk_stepping next;
+
+ if (rv6xx_can_step_post_div(rdev, &cur, &target))
+ next = rv6xx_next_post_div_step(rdev, &cur, &target);
+ else
+ next = rv6xx_next_vco_step(rdev, &cur, increasing_vco, R600_VCOSTEPPCT_DFLT);
+
+ if (rv6xx_reached_stepping_target(rdev, &next, &target, increasing_vco)) {
+ struct rv6xx_sclk_stepping tiny =
+ rv6xx_next_vco_step(rdev, &target, !increasing_vco, R600_ENDINGVCOSTEPPCT_DFLT);
+ tiny.post_divider = next.post_divider;
+
+ if (!rv6xx_reached_stepping_target(rdev, &tiny, &cur, !increasing_vco))
+ rv6xx_output_stepping(rdev, step_index++, &tiny);
+
+ if ((next.post_divider != target.post_divider) &&
+ (next.vco_frequency != target.vco_frequency)) {
+ struct rv6xx_sclk_stepping final_vco;
+
+ final_vco.vco_frequency = target.vco_frequency;
+ final_vco.post_divider = next.post_divider;
+
+ rv6xx_output_stepping(rdev, step_index++, &final_vco);
+ }
+
+ rv6xx_output_stepping(rdev, step_index++, &target);
+ break;
+ } else
+ rv6xx_output_stepping(rdev, step_index++, &next);
+
+ cur = next;
+ }
+
+ *end_index = (u8)step_index - 1;
+
+}
+
+static void rv6xx_generate_single_step(struct radeon_device *rdev,
+ u32 clock, u32 index)
+{
+ struct rv6xx_sclk_stepping step;
+
+ rv6xx_convert_clock_to_stepping(rdev, clock, &step);
+ rv6xx_output_stepping(rdev, index, &step);
+}
+
+static void rv6xx_invalidate_intermediate_steps_range(struct radeon_device *rdev,
+ u32 start_index, u32 end_index)
+{
+ u32 step_index;
+
+ for (step_index = start_index + 1; step_index < end_index; step_index++)
+ r600_engine_clock_entry_enable(rdev, step_index, false);
+}
+
+static void rv6xx_set_engine_spread_spectrum_clk_s(struct radeon_device *rdev,
+ u32 index, u32 clk_s)
+{
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+ CLKS(clk_s), ~CLKS_MASK);
+}
+
+static void rv6xx_set_engine_spread_spectrum_clk_v(struct radeon_device *rdev,
+ u32 index, u32 clk_v)
+{
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+ CLKV(clk_v), ~CLKV_MASK);
+}
+
+static void rv6xx_enable_engine_spread_spectrum(struct radeon_device *rdev,
+ u32 index, bool enable)
+{
+ if (enable)
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+ SSEN, ~SSEN);
+ else
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM_LOW + (index * 4),
+ 0, ~SSEN);
+}
+
+static void rv6xx_set_memory_spread_spectrum_clk_s(struct radeon_device *rdev,
+ u32 clk_s)
+{
+ WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKS(clk_s), ~CLKS_MASK);
+}
+
+static void rv6xx_set_memory_spread_spectrum_clk_v(struct radeon_device *rdev,
+ u32 clk_v)
+{
+ WREG32_P(CG_MPLL_SPREAD_SPECTRUM, CLKV(clk_v), ~CLKV_MASK);
+}
+
+static void rv6xx_enable_memory_spread_spectrum(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(CG_MPLL_SPREAD_SPECTRUM, SSEN, ~SSEN);
+ else
+ WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+}
+
+static void rv6xx_enable_dynamic_spread_spectrum(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+}
+
+static void rv6xx_memory_clock_entry_enable_post_divider(struct radeon_device *rdev,
+ u32 index, bool enable)
+{
+ if (enable)
+ WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
+ LEVEL0_MPLL_DIV_EN, ~LEVEL0_MPLL_DIV_EN);
+ else
+ WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), 0, ~LEVEL0_MPLL_DIV_EN);
+}
+
+static void rv6xx_memory_clock_entry_set_post_divider(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
+ LEVEL0_MPLL_POST_DIV(divider), ~LEVEL0_MPLL_POST_DIV_MASK);
+}
+
+static void rv6xx_memory_clock_entry_set_feedback_divider(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4), LEVEL0_MPLL_FB_DIV(divider),
+ ~LEVEL0_MPLL_FB_DIV_MASK);
+}
+
+static void rv6xx_memory_clock_entry_set_reference_divider(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ WREG32_P(MPLL_FREQ_LEVEL_0 + (index * 4),
+ LEVEL0_MPLL_REF_DIV(divider), ~LEVEL0_MPLL_REF_DIV_MASK);
+}
+
+static void rv6xx_vid_response_set_brt(struct radeon_device *rdev, u32 rt)
+{
+ WREG32_P(VID_RT, BRT(rt), ~BRT_MASK);
+}
+
+static void rv6xx_enable_engine_feedback_and_reference_sync(struct radeon_device *rdev)
+{
+ WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);
+}
+
+static u64 rv6xx_clocks_per_unit(u32 unit)
+{
+ u64 tmp = 1 << (2 * unit);
+
+ return tmp;
+}
+
+static u32 rv6xx_scale_count_given_unit(struct radeon_device *rdev,
+ u32 unscaled_count, u32 unit)
+{
+ u32 count_per_unit = (u32)rv6xx_clocks_per_unit(unit);
+
+ return (unscaled_count + count_per_unit - 1) / count_per_unit;
+}
+
+static u32 rv6xx_compute_count_for_delay(struct radeon_device *rdev,
+ u32 delay_us, u32 unit)
+{
+ u32 ref_clk = rdev->clock.spll.reference_freq;
+
+ return rv6xx_scale_count_given_unit(rdev, delay_us * (ref_clk / 100), unit);
+}
+
+static void rv6xx_calculate_engine_speed_stepping_parameters(struct radeon_device *rdev,
+ struct rv6xx_ps *state)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ pi->hw.sclks[R600_POWER_LEVEL_LOW] =
+ state->low.sclk;
+ pi->hw.sclks[R600_POWER_LEVEL_MEDIUM] =
+ state->medium.sclk;
+ pi->hw.sclks[R600_POWER_LEVEL_HIGH] =
+ state->high.sclk;
+
+ pi->hw.low_sclk_index = R600_POWER_LEVEL_LOW;
+ pi->hw.medium_sclk_index = R600_POWER_LEVEL_MEDIUM;
+ pi->hw.high_sclk_index = R600_POWER_LEVEL_HIGH;
+}
+
+static void rv6xx_calculate_memory_clock_stepping_parameters(struct radeon_device *rdev,
+ struct rv6xx_ps *state)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ pi->hw.mclks[R600_POWER_LEVEL_CTXSW] =
+ state->high.mclk;
+ pi->hw.mclks[R600_POWER_LEVEL_HIGH] =
+ state->high.mclk;
+ pi->hw.mclks[R600_POWER_LEVEL_MEDIUM] =
+ state->medium.mclk;
+ pi->hw.mclks[R600_POWER_LEVEL_LOW] =
+ state->low.mclk;
+
+ pi->hw.high_mclk_index = R600_POWER_LEVEL_HIGH;
+
+ if (state->high.mclk == state->medium.mclk)
+ pi->hw.medium_mclk_index =
+ pi->hw.high_mclk_index;
+ else
+ pi->hw.medium_mclk_index = R600_POWER_LEVEL_MEDIUM;
+
+
+ if (state->medium.mclk == state->low.mclk)
+ pi->hw.low_mclk_index =
+ pi->hw.medium_mclk_index;
+ else
+ pi->hw.low_mclk_index = R600_POWER_LEVEL_LOW;
+}
+
+static void rv6xx_calculate_voltage_stepping_parameters(struct radeon_device *rdev,
+ struct rv6xx_ps *state)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ pi->hw.vddc[R600_POWER_LEVEL_CTXSW] = state->high.vddc;
+ pi->hw.vddc[R600_POWER_LEVEL_HIGH] = state->high.vddc;
+ pi->hw.vddc[R600_POWER_LEVEL_MEDIUM] = state->medium.vddc;
+ pi->hw.vddc[R600_POWER_LEVEL_LOW] = state->low.vddc;
+
+ pi->hw.backbias[R600_POWER_LEVEL_CTXSW] =
+ (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+ pi->hw.backbias[R600_POWER_LEVEL_HIGH] =
+ (state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+ pi->hw.backbias[R600_POWER_LEVEL_MEDIUM] =
+ (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+ pi->hw.backbias[R600_POWER_LEVEL_LOW] =
+ (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? true : false;
+
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH] =
+ (state->high.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM] =
+ (state->medium.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW] =
+ (state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? true : false;
+
+ pi->hw.high_vddc_index = R600_POWER_LEVEL_HIGH;
+
+ if ((state->high.vddc == state->medium.vddc) &&
+ ((state->high.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ==
+ (state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)))
+ pi->hw.medium_vddc_index =
+ pi->hw.high_vddc_index;
+ else
+ pi->hw.medium_vddc_index = R600_POWER_LEVEL_MEDIUM;
+
+ if ((state->medium.vddc == state->low.vddc) &&
+ ((state->medium.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ==
+ (state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE)))
+ pi->hw.low_vddc_index =
+ pi->hw.medium_vddc_index;
+ else
+ pi->hw.medium_vddc_index = R600_POWER_LEVEL_LOW;
+}
+
+static inline u32 rv6xx_calculate_vco_frequency(u32 ref_clock,
+ struct atom_clock_dividers *dividers,
+ u32 fb_divider_scale)
+{
+ return ref_clock * ((dividers->fb_div & ~1) << fb_divider_scale) /
+ (dividers->ref_div + 1);
+}
+
+static inline u32 rv6xx_calculate_spread_spectrum_clk_v(u32 vco_freq, u32 ref_freq,
+ u32 ss_rate, u32 ss_percent,
+ u32 fb_divider_scale)
+{
+ u32 fb_divider = vco_freq / ref_freq;
+
+ return (ss_percent * ss_rate * 4 * (fb_divider * fb_divider) /
+ (5375 * ((vco_freq * 10) / (4096 >> fb_divider_scale))));
+}
+
+static inline u32 rv6xx_calculate_spread_spectrum_clk_s(u32 ss_rate, u32 ref_freq)
+{
+ return (((ref_freq * 10) / (ss_rate * 2)) - 1) / 4;
+}
+
+static void rv6xx_program_engine_spread_spectrum(struct radeon_device *rdev,
+ u32 clock, enum r600_power_level level)
+{
+ u32 ref_clk = rdev->clock.spll.reference_freq;
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ struct radeon_atom_ss ss;
+ u32 vco_freq, clk_v, clk_s;
+
+ rv6xx_enable_engine_spread_spectrum(rdev, level, false);
+
+ if (clock && pi->sclk_ss) {
+ if (radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM, clock, false, &dividers) == 0) {
+ vco_freq = rv6xx_calculate_vco_frequency(ref_clk, &dividers,
+ pi->fb_div_scale);
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+ clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq,
+ (ref_clk / (dividers.ref_div + 1)),
+ ss.rate,
+ ss.percentage,
+ pi->fb_div_scale);
+
+ clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate,
+ (ref_clk / (dividers.ref_div + 1)));
+
+ rv6xx_set_engine_spread_spectrum_clk_v(rdev, level, clk_v);
+ rv6xx_set_engine_spread_spectrum_clk_s(rdev, level, clk_s);
+ rv6xx_enable_engine_spread_spectrum(rdev, level, true);
+ }
+ }
+ }
+}
+
+static void rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_program_engine_spread_spectrum(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_HIGH],
+ R600_POWER_LEVEL_HIGH);
+
+ rv6xx_program_engine_spread_spectrum(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_MEDIUM],
+ R600_POWER_LEVEL_MEDIUM);
+
+}
+
+static int rv6xx_program_mclk_stepping_entry(struct radeon_device *rdev,
+ u32 entry, u32 clock)
+{
+ struct atom_clock_dividers dividers;
+
+ if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM, clock, false, &dividers))
+ return -EINVAL;
+
+
+ rv6xx_memory_clock_entry_set_reference_divider(rdev, entry, dividers.ref_div);
+ rv6xx_memory_clock_entry_set_feedback_divider(rdev, entry, dividers.fb_div);
+ rv6xx_memory_clock_entry_set_post_divider(rdev, entry, dividers.post_div);
+
+ if (dividers.enable_post_div)
+ rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, true);
+ else
+ rv6xx_memory_clock_entry_enable_post_divider(rdev, entry, false);
+
+ return 0;
+}
+
+static void rv6xx_program_mclk_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ int i;
+
+ for (i = 1; i < R600_PM_NUMBER_OF_MCLKS; i++) {
+ if (pi->hw.mclks[i])
+ rv6xx_program_mclk_stepping_entry(rdev, i,
+ pi->hw.mclks[i]);
+ }
+}
+
+static void rv6xx_find_memory_clock_with_highest_vco(struct radeon_device *rdev,
+ u32 requested_memory_clock,
+ u32 ref_clk,
+ struct atom_clock_dividers *dividers,
+ u32 *vco_freq)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ struct atom_clock_dividers req_dividers;
+ u32 vco_freq_temp;
+
+ if (radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ requested_memory_clock, false, &req_dividers) == 0) {
+ vco_freq_temp = rv6xx_calculate_vco_frequency(ref_clk, &req_dividers,
+ pi->fb_div_scale);
+
+ if (vco_freq_temp > *vco_freq) {
+ *dividers = req_dividers;
+ *vco_freq = vco_freq_temp;
+ }
+ }
+}
+
+static void rv6xx_program_mclk_spread_spectrum_parameters(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ u32 ref_clk = rdev->clock.mpll.reference_freq;
+ struct atom_clock_dividers dividers;
+ struct radeon_atom_ss ss;
+ u32 vco_freq = 0, clk_v, clk_s;
+
+ rv6xx_enable_memory_spread_spectrum(rdev, false);
+
+ if (pi->mclk_ss) {
+ rv6xx_find_memory_clock_with_highest_vco(rdev,
+ pi->hw.mclks[pi->hw.high_mclk_index],
+ ref_clk,
+ &dividers,
+ &vco_freq);
+
+ rv6xx_find_memory_clock_with_highest_vco(rdev,
+ pi->hw.mclks[pi->hw.medium_mclk_index],
+ ref_clk,
+ &dividers,
+ &vco_freq);
+
+ rv6xx_find_memory_clock_with_highest_vco(rdev,
+ pi->hw.mclks[pi->hw.low_mclk_index],
+ ref_clk,
+ &dividers,
+ &vco_freq);
+
+ if (vco_freq) {
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+ clk_v = rv6xx_calculate_spread_spectrum_clk_v(vco_freq,
+ (ref_clk / (dividers.ref_div + 1)),
+ ss.rate,
+ ss.percentage,
+ pi->fb_div_scale);
+
+ clk_s = rv6xx_calculate_spread_spectrum_clk_s(ss.rate,
+ (ref_clk / (dividers.ref_div + 1)));
+
+ rv6xx_set_memory_spread_spectrum_clk_v(rdev, clk_v);
+ rv6xx_set_memory_spread_spectrum_clk_s(rdev, clk_s);
+ rv6xx_enable_memory_spread_spectrum(rdev, true);
+ }
+ }
+ }
+}
+
+static int rv6xx_program_voltage_stepping_entry(struct radeon_device *rdev,
+ u32 entry, u16 voltage)
+{
+ u32 mask, set_pins;
+ int ret;
+
+ ret = radeon_atom_get_voltage_gpio_settings(rdev, voltage,
+ SET_VOLTAGE_TYPE_ASIC_VDDC,
+ &set_pins, &mask);
+ if (ret)
+ return ret;
+
+ r600_voltage_control_program_voltages(rdev, entry, set_pins);
+
+ return 0;
+}
+
+static void rv6xx_program_voltage_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ int i;
+
+ for (i = 1; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++)
+ rv6xx_program_voltage_stepping_entry(rdev, i,
+ pi->hw.vddc[i]);
+
+}
+
+static void rv6xx_program_backbias_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (pi->hw.backbias[1])
+ WREG32_P(VID_UPPER_GPIO_CNTL, MEDIUM_BACKBIAS_VALUE, ~MEDIUM_BACKBIAS_VALUE);
+ else
+ WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~MEDIUM_BACKBIAS_VALUE);
+
+ if (pi->hw.backbias[2])
+ WREG32_P(VID_UPPER_GPIO_CNTL, HIGH_BACKBIAS_VALUE, ~HIGH_BACKBIAS_VALUE);
+ else
+ WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~HIGH_BACKBIAS_VALUE);
+}
+
+static void rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_program_engine_spread_spectrum(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_LOW],
+ R600_POWER_LEVEL_LOW);
+}
+
+static void rv6xx_program_mclk_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (pi->hw.mclks[0])
+ rv6xx_program_mclk_stepping_entry(rdev, 0,
+ pi->hw.mclks[0]);
+}
+
+static void rv6xx_program_voltage_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_program_voltage_stepping_entry(rdev, 0,
+ pi->hw.vddc[0]);
+
+}
+
+static void rv6xx_program_backbias_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (pi->hw.backbias[0])
+ WREG32_P(VID_UPPER_GPIO_CNTL, LOW_BACKBIAS_VALUE, ~LOW_BACKBIAS_VALUE);
+ else
+ WREG32_P(VID_UPPER_GPIO_CNTL, 0, ~LOW_BACKBIAS_VALUE);
+}
+
+static u32 calculate_memory_refresh_rate(struct radeon_device *rdev,
+ u32 engine_clock)
+{
+ u32 dram_rows, dram_refresh_rate;
+ u32 tmp;
+
+ tmp = (RREG32(RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+ dram_rows = 1 << (tmp + 10);
+ dram_refresh_rate = 1 << ((RREG32(MC_SEQ_RESERVE_M) & 0x3) + 3);
+
+ return ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
+}
+
+static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ u32 sqm_ratio;
+ u32 arb_refresh_rate;
+ u32 high_clock;
+
+ if (pi->hw.sclks[R600_POWER_LEVEL_HIGH] <
+ (pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40))
+ high_clock = pi->hw.sclks[R600_POWER_LEVEL_HIGH];
+ else
+ high_clock =
+ pi->hw.sclks[R600_POWER_LEVEL_LOW] * 0xFF / 0x40;
+
+ radeon_atom_set_engine_dram_timings(rdev, high_clock, 0);
+
+ sqm_ratio = (STATE0(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_LOW]) |
+ STATE1(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_MEDIUM]) |
+ STATE2(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]) |
+ STATE3(64 * high_clock / pi->hw.sclks[R600_POWER_LEVEL_HIGH]));
+ WREG32(SQM_RATIO, sqm_ratio);
+
+ arb_refresh_rate =
+ (POWERMODE0(calculate_memory_refresh_rate(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_LOW])) |
+ POWERMODE1(calculate_memory_refresh_rate(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+ POWERMODE2(calculate_memory_refresh_rate(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+ POWERMODE3(calculate_memory_refresh_rate(rdev,
+ pi->hw.sclks[R600_POWER_LEVEL_HIGH])));
+ WREG32(ARB_RFSH_RATE, arb_refresh_rate);
+}
+
+static void rv6xx_program_mpll_timing_parameters(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ r600_set_mpll_lock_time(rdev, R600_MPLLLOCKTIME_DFLT *
+ pi->mpll_ref_div);
+ r600_set_mpll_reset_time(rdev, R600_MPLLRESETTIME_DFLT);
+}
+
+static void rv6xx_program_bsp(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ u32 ref_clk = rdev->clock.spll.reference_freq;
+
+ r600_calculate_u_and_p(R600_ASI_DFLT,
+ ref_clk, 16,
+ &pi->bsp,
+ &pi->bsu);
+
+ r600_set_bsp(rdev, pi->bsu, pi->bsp);
+}
+
+static void rv6xx_program_at(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ r600_set_at(rdev,
+ (pi->hw.rp[0] * pi->bsp) / 200,
+ (pi->hw.rp[1] * pi->bsp) / 200,
+ (pi->hw.lp[2] * pi->bsp) / 200,
+ (pi->hw.lp[1] * pi->bsp) / 200);
+}
+
+static void rv6xx_program_git(struct radeon_device *rdev)
+{
+ r600_set_git(rdev, R600_GICST_DFLT);
+}
+
+static void rv6xx_program_tp(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+ r600_set_tc(rdev, i, r600_utc[i], r600_dtc[i]);
+
+ r600_select_td(rdev, R600_TD_DFLT);
+}
+
+static void rv6xx_program_vc(struct radeon_device *rdev)
+{
+ r600_set_vrc(rdev, R600_VRC_DFLT);
+}
+
+static void rv6xx_clear_vc(struct radeon_device *rdev)
+{
+ r600_set_vrc(rdev, 0);
+}
+
+static void rv6xx_program_tpp(struct radeon_device *rdev)
+{
+ r600_set_tpu(rdev, R600_TPU_DFLT);
+ r600_set_tpc(rdev, R600_TPC_DFLT);
+}
+
+static void rv6xx_program_sstp(struct radeon_device *rdev)
+{
+ r600_set_sstu(rdev, R600_SSTU_DFLT);
+ r600_set_sst(rdev, R600_SST_DFLT);
+}
+
+static void rv6xx_program_fcp(struct radeon_device *rdev)
+{
+ r600_set_fctu(rdev, R600_FCTU_DFLT);
+ r600_set_fct(rdev, R600_FCT_DFLT);
+}
+
+static void rv6xx_program_vddc3d_parameters(struct radeon_device *rdev)
+{
+ r600_set_vddc3d_oorsu(rdev, R600_VDDC3DOORSU_DFLT);
+ r600_set_vddc3d_oorphc(rdev, R600_VDDC3DOORPHC_DFLT);
+ r600_set_vddc3d_oorsdc(rdev, R600_VDDC3DOORSDC_DFLT);
+ r600_set_ctxcgtt3d_rphc(rdev, R600_CTXCGTT3DRPHC_DFLT);
+ r600_set_ctxcgtt3d_rsdc(rdev, R600_CTXCGTT3DRSDC_DFLT);
+}
+
+static void rv6xx_program_voltage_timing_parameters(struct radeon_device *rdev)
+{
+ u32 rt;
+
+ r600_vid_rt_set_vru(rdev, R600_VRU_DFLT);
+
+ r600_vid_rt_set_vrt(rdev,
+ rv6xx_compute_count_for_delay(rdev,
+ rdev->pm.dpm.voltage_response_time,
+ R600_VRU_DFLT));
+
+ rt = rv6xx_compute_count_for_delay(rdev,
+ rdev->pm.dpm.backbias_response_time,
+ R600_VRU_DFLT);
+
+ rv6xx_vid_response_set_brt(rdev, (rt + 0x1F) >> 5);
+}
+
+static void rv6xx_program_engine_speed_parameters(struct radeon_device *rdev)
+{
+ r600_vid_rt_set_ssu(rdev, R600_SPLLSTEPUNIT_DFLT);
+ rv6xx_enable_engine_feedback_and_reference_sync(rdev);
+}
+
+static u64 rv6xx_get_master_voltage_mask(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ u64 master_mask = 0;
+ int i;
+
+ for (i = 0; i < R600_PM_NUMBER_OF_VOLTAGE_LEVELS; i++) {
+ u32 tmp_mask, tmp_set_pins;
+ int ret;
+
+ ret = radeon_atom_get_voltage_gpio_settings(rdev,
+ pi->hw.vddc[i],
+ SET_VOLTAGE_TYPE_ASIC_VDDC,
+ &tmp_set_pins, &tmp_mask);
+
+ if (ret == 0)
+ master_mask |= tmp_mask;
+ }
+
+ return master_mask;
+}
+
+static void rv6xx_program_voltage_gpio_pins(struct radeon_device *rdev)
+{
+ r600_voltage_control_enable_pins(rdev,
+ rv6xx_get_master_voltage_mask(rdev));
+}
+
+static void rv6xx_enable_static_voltage_control(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ bool enable)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+
+ if (enable)
+ radeon_atom_set_voltage(rdev,
+ new_state->low.vddc,
+ SET_VOLTAGE_TYPE_ASIC_VDDC);
+ else
+ r600_voltage_control_deactivate_static_control(rdev,
+ rv6xx_get_master_voltage_mask(rdev));
+}
+
+static void rv6xx_enable_display_gap(struct radeon_device *rdev, bool enable)
+{
+ if (enable) {
+ u32 tmp = (DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) |
+ DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM) |
+ DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+ DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+ VBI_TIMER_COUNT(0x3FFF) |
+ VBI_TIMER_UNIT(7));
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+
+ WREG32_P(MCLK_PWRMGT_CNTL, USE_DISPLAY_GAP, ~USE_DISPLAY_GAP);
+ } else
+ WREG32_P(MCLK_PWRMGT_CNTL, 0, ~USE_DISPLAY_GAP);
+}
+
+static void rv6xx_program_power_level_enter_state(struct radeon_device *rdev)
+{
+ r600_power_level_set_enter_index(rdev, R600_POWER_LEVEL_MEDIUM);
+}
+
+static void rv6xx_calculate_t(u32 l_f, u32 h_f, int h,
+ int d_l, int d_r, u8 *l, u8 *r)
+{
+ int a_n, a_d, h_r, l_r;
+
+ h_r = d_l;
+ l_r = 100 - d_r;
+
+ a_n = (int)h_f * d_l + (int)l_f * (h - d_r);
+ a_d = (int)l_f * l_r + (int)h_f * h_r;
+
+ if (a_d != 0) {
+ *l = d_l - h_r * a_n / a_d;
+ *r = d_r + l_r * a_n / a_d;
+ }
+}
+
+static void rv6xx_calculate_ap(struct radeon_device *rdev,
+ struct rv6xx_ps *state)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ pi->hw.lp[0] = 0;
+ pi->hw.rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS - 1]
+ = 100;
+
+ rv6xx_calculate_t(state->low.sclk,
+ state->medium.sclk,
+ R600_AH_DFLT,
+ R600_LMP_DFLT,
+ R600_RLP_DFLT,
+ &pi->hw.lp[1],
+ &pi->hw.rp[0]);
+
+ rv6xx_calculate_t(state->medium.sclk,
+ state->high.sclk,
+ R600_AH_DFLT,
+ R600_LHP_DFLT,
+ R600_RMP_DFLT,
+ &pi->hw.lp[2],
+ &pi->hw.rp[1]);
+
+}
+
+static void rv6xx_calculate_stepping_parameters(struct radeon_device *rdev,
+ struct radeon_ps *new_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+
+ rv6xx_calculate_engine_speed_stepping_parameters(rdev, new_state);
+ rv6xx_calculate_memory_clock_stepping_parameters(rdev, new_state);
+ rv6xx_calculate_voltage_stepping_parameters(rdev, new_state);
+ rv6xx_calculate_ap(rdev, new_state);
+}
+
+static void rv6xx_program_stepping_parameters_except_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_program_mclk_stepping_parameters_except_lowest_entry(rdev);
+ if (pi->voltage_control)
+ rv6xx_program_voltage_stepping_parameters_except_lowest_entry(rdev);
+ rv6xx_program_backbias_stepping_parameters_except_lowest_entry(rdev);
+ rv6xx_program_sclk_spread_spectrum_parameters_except_lowest_entry(rdev);
+ rv6xx_program_mclk_spread_spectrum_parameters(rdev);
+ rv6xx_program_memory_timing_parameters(rdev);
+}
+
+static void rv6xx_program_stepping_parameters_lowest_entry(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_program_mclk_stepping_parameters_lowest_entry(rdev);
+ if (pi->voltage_control)
+ rv6xx_program_voltage_stepping_parameters_lowest_entry(rdev);
+ rv6xx_program_backbias_stepping_parameters_lowest_entry(rdev);
+ rv6xx_program_sclk_spread_spectrum_parameters_lowest_entry(rdev);
+}
+
+static void rv6xx_program_power_level_low(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW,
+ pi->hw.low_vddc_index);
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW,
+ pi->hw.low_mclk_index);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW,
+ pi->hw.low_sclk_index);
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,
+ R600_DISPLAY_WATERMARK_LOW);
+ r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW,
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
+}
+
+static void rv6xx_program_power_level_low_to_lowest_state(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_LOW, 0);
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_LOW, 0);
+
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_LOW,
+ R600_DISPLAY_WATERMARK_LOW);
+
+ r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_LOW,
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
+
+}
+
+static void rv6xx_program_power_level_medium(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM,
+ pi->hw.medium_vddc_index);
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+ pi->hw.medium_mclk_index);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+ pi->hw.medium_sclk_index);
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM,
+ R600_DISPLAY_WATERMARK_LOW);
+ r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM,
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_MEDIUM]);
+}
+
+static void rv6xx_program_power_level_medium_for_transition(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_program_mclk_stepping_entry(rdev,
+ R600_POWER_LEVEL_CTXSW,
+ pi->hw.mclks[pi->hw.low_mclk_index]);
+
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_MEDIUM, 1);
+
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+ R600_POWER_LEVEL_CTXSW);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_MEDIUM,
+ pi->hw.medium_sclk_index);
+
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_MEDIUM,
+ R600_DISPLAY_WATERMARK_LOW);
+
+ rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+ r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_MEDIUM,
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_LOW]);
+}
+
+static void rv6xx_program_power_level_high(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ r600_power_level_set_voltage_index(rdev, R600_POWER_LEVEL_HIGH,
+ pi->hw.high_vddc_index);
+ r600_power_level_set_mem_clock_index(rdev, R600_POWER_LEVEL_HIGH,
+ pi->hw.high_mclk_index);
+ r600_power_level_set_eng_clock_index(rdev, R600_POWER_LEVEL_HIGH,
+ pi->hw.high_sclk_index);
+
+ r600_power_level_set_watermark_id(rdev, R600_POWER_LEVEL_HIGH,
+ R600_DISPLAY_WATERMARK_HIGH);
+
+ r600_power_level_set_pcie_gen2(rdev, R600_POWER_LEVEL_HIGH,
+ pi->hw.pcie_gen2[R600_POWER_LEVEL_HIGH]);
+}
+
+static void rv6xx_enable_backbias(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL,
+ ~(BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL));
+ else
+ WREG32_P(GENERAL_PWRMGT, 0,
+ ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN | BACKBIAS_DPM_CNTL));
+}
+
+static void rv6xx_program_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+ tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+ if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+ tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+ tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+ tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+ } else {
+ tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ }
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void rv6xx_set_sw_voltage_to_safe(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+ u16 safe_voltage;
+
+ safe_voltage = (new_state->low.vddc >= old_state->low.vddc) ?
+ new_state->low.vddc : old_state->low.vddc;
+
+ rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
+ safe_voltage);
+
+ WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW),
+ ~SW_GPIO_INDEX_MASK);
+}
+
+static void rv6xx_set_sw_voltage_to_low(struct radeon_device *rdev,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+
+ rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
+ old_state->low.vddc);
+
+ WREG32_P(GENERAL_PWRMGT, SW_GPIO_INDEX(R600_POWER_LEVEL_CTXSW),
+ ~SW_GPIO_INDEX_MASK);
+}
+
+static void rv6xx_set_safe_backbias(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+
+ if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) &&
+ (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE))
+ WREG32_P(GENERAL_PWRMGT, BACKBIAS_VALUE, ~BACKBIAS_VALUE);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_VALUE);
+}
+
+static void rv6xx_set_safe_pcie_gen2(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+
+ if ((new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) !=
+ (old_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
+ rv6xx_force_pcie_gen1(rdev);
+}
+
+static void rv6xx_enable_dynamic_voltage_control(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+}
+
+static void rv6xx_enable_dynamic_backbias_control(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, BACKBIAS_DPM_CNTL, ~BACKBIAS_DPM_CNTL);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~BACKBIAS_DPM_CNTL);
+}
+
+static int rv6xx_step_sw_voltage(struct radeon_device *rdev,
+ u16 initial_voltage,
+ u16 target_voltage)
+{
+ u16 current_voltage;
+ u16 true_target_voltage;
+ u16 voltage_step;
+ int signed_voltage_step;
+
+ if ((radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+ &voltage_step)) ||
+ (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+ initial_voltage, &current_voltage)) ||
+ (radeon_atom_round_to_true_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC,
+ target_voltage, &true_target_voltage)))
+ return -EINVAL;
+
+ if (true_target_voltage < current_voltage)
+ signed_voltage_step = -(int)voltage_step;
+ else
+ signed_voltage_step = voltage_step;
+
+ while (current_voltage != true_target_voltage) {
+ current_voltage += signed_voltage_step;
+ rv6xx_program_voltage_stepping_entry(rdev, R600_POWER_LEVEL_CTXSW,
+ current_voltage);
+ msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
+ }
+
+ return 0;
+}
+
+static int rv6xx_step_voltage_if_increasing(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+
+ if (new_state->low.vddc > old_state->low.vddc)
+ return rv6xx_step_sw_voltage(rdev,
+ old_state->low.vddc,
+ new_state->low.vddc);
+
+ return 0;
+}
+
+static int rv6xx_step_voltage_if_decreasing(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+
+ if (new_state->low.vddc < old_state->low.vddc)
+ return rv6xx_step_sw_voltage(rdev,
+ old_state->low.vddc,
+ new_state->low.vddc);
+ else
+ return 0;
+}
+
+static void rv6xx_enable_high(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if ((pi->restricted_levels < 1) ||
+ (pi->restricted_levels == 3))
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
+}
+
+static void rv6xx_enable_medium(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (pi->restricted_levels < 2)
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+}
+
+static void rv6xx_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ bool want_thermal_protection;
+ enum radeon_dpm_event_src dpm_event_src;
+
+ switch (sources) {
+ case 0:
+ default:
+ want_thermal_protection = false;
+ break;
+ case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
+ break;
+
+ case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
+ break;
+
+ case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+ (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+ break;
+ }
+
+ if (want_thermal_protection) {
+ WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+ if (pi->thermal_protection)
+ WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ } else {
+ WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+ }
+}
+
+static void rv6xx_enable_auto_throttle_source(struct radeon_device *rdev,
+ enum radeon_dpm_auto_throttle_src source,
+ bool enable)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (enable) {
+ if (!(pi->active_auto_throttle_sources & (1 << source))) {
+ pi->active_auto_throttle_sources |= 1 << source;
+ rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+ }
+ } else {
+ if (pi->active_auto_throttle_sources & (1 << source)) {
+ pi->active_auto_throttle_sources &= ~(1 << source);
+ rv6xx_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+ }
+ }
+}
+
+
+static void rv6xx_enable_thermal_protection(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ if (pi->active_auto_throttle_sources)
+ r600_enable_thermal_protection(rdev, enable);
+}
+
+static void rv6xx_generate_transition_stepping(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *old_state = rv6xx_get_ps(old_ps);
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_generate_steps(rdev,
+ old_state->low.sclk,
+ new_state->low.sclk,
+ 0, &pi->hw.medium_sclk_index);
+}
+
+static void rv6xx_generate_low_step(struct radeon_device *rdev,
+ struct radeon_ps *new_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ pi->hw.low_sclk_index = 0;
+ rv6xx_generate_single_step(rdev,
+ new_state->low.sclk,
+ 0);
+}
+
+static void rv6xx_invalidate_intermediate_steps(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ rv6xx_invalidate_intermediate_steps_range(rdev, 0,
+ pi->hw.medium_sclk_index);
+}
+
+static void rv6xx_generate_stepping_table(struct radeon_device *rdev,
+ struct radeon_ps *new_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+ pi->hw.low_sclk_index = 0;
+
+ rv6xx_generate_steps(rdev,
+ new_state->low.sclk,
+ new_state->medium.sclk,
+ 0,
+ &pi->hw.medium_sclk_index);
+ rv6xx_generate_steps(rdev,
+ new_state->medium.sclk,
+ new_state->high.sclk,
+ pi->hw.medium_sclk_index,
+ &pi->hw.high_sclk_index);
+}
+
+static void rv6xx_enable_spread_spectrum(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ rv6xx_enable_dynamic_spread_spectrum(rdev, true);
+ else {
+ rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_LOW, false);
+ rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_MEDIUM, false);
+ rv6xx_enable_engine_spread_spectrum(rdev, R600_POWER_LEVEL_HIGH, false);
+ rv6xx_enable_dynamic_spread_spectrum(rdev, false);
+ rv6xx_enable_memory_spread_spectrum(rdev, false);
+ }
+}
+
+static void rv6xx_reset_lvtm_data_sync(struct radeon_device *rdev)
+{
+ if (ASIC_IS_DCE3(rdev))
+ WREG32_P(DCE3_LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG);
+ else
+ WREG32_P(LVTMA_DATA_SYNCHRONIZATION, LVTMA_PFREQCHG, ~LVTMA_PFREQCHG);
+}
+
+static void rv6xx_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ bool enable)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+
+ if (enable) {
+ rv6xx_enable_bif_dynamic_pcie_gen2(rdev, true);
+ rv6xx_enable_pcie_gen2_support(rdev);
+ r600_enable_dynamic_pcie_gen2(rdev, true);
+ } else {
+ if (!(new_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2))
+ rv6xx_force_pcie_gen1(rdev);
+ rv6xx_enable_bif_dynamic_pcie_gen2(rdev, false);
+ r600_enable_dynamic_pcie_gen2(rdev, false);
+ }
+}
+
+static void rv6xx_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->high.sclk >= current_state->high.sclk)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+static void rv6xx_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv6xx_ps *new_state = rv6xx_get_ps(new_ps);
+ struct rv6xx_ps *current_state = rv6xx_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->high.sclk < current_state->high.sclk)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+int rv6xx_dpm_enable(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ if (r600_dynamicpm_enabled(rdev))
+ return -EINVAL;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv6xx_enable_backbias(rdev, true);
+
+ if (pi->dynamic_ss)
+ rv6xx_enable_spread_spectrum(rdev, true);
+
+ rv6xx_program_mpll_timing_parameters(rdev);
+ rv6xx_program_bsp(rdev);
+ rv6xx_program_git(rdev);
+ rv6xx_program_tp(rdev);
+ rv6xx_program_tpp(rdev);
+ rv6xx_program_sstp(rdev);
+ rv6xx_program_fcp(rdev);
+ rv6xx_program_vddc3d_parameters(rdev);
+ rv6xx_program_voltage_timing_parameters(rdev);
+ rv6xx_program_engine_speed_parameters(rdev);
+
+ rv6xx_enable_display_gap(rdev, true);
+ if (pi->display_gap == false)
+ rv6xx_enable_display_gap(rdev, false);
+
+ rv6xx_program_power_level_enter_state(rdev);
+
+ rv6xx_calculate_stepping_parameters(rdev, boot_ps);
+
+ if (pi->voltage_control)
+ rv6xx_program_voltage_gpio_pins(rdev);
+
+ rv6xx_generate_stepping_table(rdev, boot_ps);
+
+ rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
+ rv6xx_program_stepping_parameters_lowest_entry(rdev);
+
+ rv6xx_program_power_level_low(rdev);
+ rv6xx_program_power_level_medium(rdev);
+ rv6xx_program_power_level_high(rdev);
+ rv6xx_program_vc(rdev);
+ rv6xx_program_at(rdev);
+
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ }
+
+ rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ r600_start_dpm(rdev);
+
+ if (pi->voltage_control)
+ rv6xx_enable_static_voltage_control(rdev, boot_ps, false);
+
+ if (pi->dynamic_pcie_gen2)
+ rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, true);
+
+ if (pi->gfx_clock_gating)
+ r600_gfx_clockgating_enable(rdev, true);
+
+ return 0;
+}
+
+void rv6xx_dpm_disable(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+
+ if (!r600_dynamicpm_enabled(rdev))
+ return;
+
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+ rv6xx_enable_display_gap(rdev, false);
+ rv6xx_clear_vc(rdev);
+ r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+
+ if (pi->thermal_protection)
+ r600_enable_thermal_protection(rdev, false);
+
+ r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv6xx_enable_backbias(rdev, false);
+
+ rv6xx_enable_spread_spectrum(rdev, false);
+
+ if (pi->voltage_control)
+ rv6xx_enable_static_voltage_control(rdev, boot_ps, true);
+
+ if (pi->dynamic_pcie_gen2)
+ rv6xx_enable_dynamic_pcie_gen2(rdev, boot_ps, false);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ if (pi->gfx_clock_gating)
+ r600_gfx_clockgating_enable(rdev, false);
+
+ r600_stop_dpm(rdev);
+}
+
+int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+ struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+ struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+ int ret;
+
+ rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+
+ rv6xx_clear_vc(rdev);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+ r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+
+ if (pi->thermal_protection)
+ r600_enable_thermal_protection(rdev, false);
+
+ r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+ rv6xx_generate_transition_stepping(rdev, new_ps, old_ps);
+ rv6xx_program_power_level_medium_for_transition(rdev);
+
+ if (pi->voltage_control) {
+ rv6xx_set_sw_voltage_to_safe(rdev, new_ps, old_ps);
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ rv6xx_set_sw_voltage_to_low(rdev, old_ps);
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv6xx_set_safe_backbias(rdev, new_ps, old_ps);
+
+ if (pi->dynamic_pcie_gen2)
+ rv6xx_set_safe_pcie_gen2(rdev, new_ps, old_ps);
+
+ if (pi->voltage_control)
+ rv6xx_enable_dynamic_voltage_control(rdev, false);
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv6xx_enable_dynamic_backbias_control(rdev, false);
+
+ if (pi->voltage_control) {
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ rv6xx_step_voltage_if_increasing(rdev, new_ps, old_ps);
+ msleep((rdev->pm.dpm.voltage_response_time + 999) / 1000);
+ }
+
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
+ r600_wait_for_power_level_unequal(rdev, R600_POWER_LEVEL_LOW);
+
+ rv6xx_generate_low_step(rdev, new_ps);
+ rv6xx_invalidate_intermediate_steps(rdev);
+ rv6xx_calculate_stepping_parameters(rdev, new_ps);
+ rv6xx_program_stepping_parameters_lowest_entry(rdev);
+ rv6xx_program_power_level_low_to_lowest_state(rdev);
+
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+ r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+ r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+
+ if (pi->voltage_control) {
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC) {
+ ret = rv6xx_step_voltage_if_decreasing(rdev, new_ps, old_ps);
+ if (ret)
+ return ret;
+ }
+ rv6xx_enable_dynamic_voltage_control(rdev, true);
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv6xx_enable_dynamic_backbias_control(rdev, true);
+
+ if (pi->dynamic_pcie_gen2)
+ rv6xx_enable_dynamic_pcie_gen2(rdev, new_ps, true);
+
+ rv6xx_reset_lvtm_data_sync(rdev);
+
+ rv6xx_generate_stepping_table(rdev, new_ps);
+ rv6xx_program_stepping_parameters_except_lowest_entry(rdev);
+ rv6xx_program_power_level_low(rdev);
+ rv6xx_program_power_level_medium(rdev);
+ rv6xx_program_power_level_high(rdev);
+ rv6xx_enable_medium(rdev);
+ rv6xx_enable_high(rdev);
+
+ if (pi->thermal_protection)
+ rv6xx_enable_thermal_protection(rdev, true);
+ rv6xx_program_vc(rdev);
+ rv6xx_program_at(rdev);
+
+ rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+
+ return 0;
+}
+
+void rv6xx_setup_asic(struct radeon_device *rdev)
+{
+ r600_enable_acpi_pm(rdev);
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
+ rv6xx_enable_l0s(rdev);
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
+ rv6xx_enable_l1(rdev);
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
+ rv6xx_enable_pll_sleep_in_l1(rdev);
+}
+
+void rv6xx_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+ rv6xx_program_display_gap(rdev);
+}
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void rv6xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps,
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info)
+{
+ 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 (r600_is_uvd_state(rps->class, rps->class2)) {
+ rps->vclk = RV6XX_DEFAULT_VCLK_FREQ;
+ rps->dclk = RV6XX_DEFAULT_DCLK_FREQ;
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ rdev->pm.dpm.boot_ps = rps;
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rv6xx_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+ u32 sclk, mclk;
+ u16 vddc;
+ struct rv6xx_pl *pl;
+
+ switch (index) {
+ case 0:
+ pl = &ps->low;
+ break;
+ case 1:
+ pl = &ps->medium;
+ break;
+ case 2:
+ default:
+ pl = &ps->high;
+ break;
+ }
+
+ sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+ sclk |= clock_info->r600.ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+ mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+
+ pl->mclk = mclk;
+ pl->sclk = sclk;
+ pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
+ pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+
+ /* patch up vddc if necessary */
+ if (pl->vddc == 0xff01) {
+ if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
+ pl->vddc = vddc;
+ }
+
+ /* fix up pcie gen2 */
+ if (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) {
+ if ((rdev->family == CHIP_RV610) || (rdev->family == CHIP_RV630)) {
+ if (pl->vddc < 1100)
+ pl->flags &= ~ATOM_PPLIB_R600_FLAGS_PCIEGEN2;
+ }
+ }
+
+ /* patch up boot state */
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ u16 vddc, vddci, mvdd;
+ radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
+ pl->mclk = rdev->clock.default_mclk;
+ pl->sclk = rdev->clock.default_sclk;
+ pl->vddc = vddc;
+ }
+}
+
+static int rv6xx_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j;
+ union pplib_clock_info *clock_info;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ struct rv6xx_ps *ps;
+
+ if (!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);
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ power_info->pplib.ucNumStates, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+ for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+ power_state = (union pplib_power_state *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+ i * power_info->pplib.ucStateEntrySize);
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+ (power_state->v1.ucNonClockStateIndex *
+ power_info->pplib.ucNonClockSize));
+ if (power_info->pplib.ucStateEntrySize - 1) {
+ ps = kzalloc(sizeof(struct rv6xx_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.ps[i].ps_priv = ps;
+ rv6xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info);
+ for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+ clock_info = (union pplib_clock_info *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+ (power_state->v1.ucClockStateIndices[j] *
+ power_info->pplib.ucClockInfoSize));
+ rv6xx_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i], j,
+ clock_info);
+ }
+ }
+ }
+ rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+ return 0;
+}
+
+int rv6xx_dpm_init(struct radeon_device *rdev)
+{
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ uint16_t data_offset, size;
+ uint8_t frev, crev;
+ struct atom_clock_dividers dividers;
+ struct rv6xx_power_info *pi;
+ int ret;
+
+ pi = kzalloc(sizeof(struct rv6xx_power_info), GFP_KERNEL);
+ if (pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = pi;
+
+ ret = rv6xx_parse_power_table(rdev);
+ if (ret)
+ return ret;
+
+ if (rdev->pm.dpm.voltage_response_time == 0)
+ rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+ if (rdev->pm.dpm.backbias_response_time == 0)
+ rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->spll_ref_div = dividers.ref_div + 1;
+ else
+ pi->spll_ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->mpll_ref_div = dividers.ref_div + 1;
+ else
+ pi->mpll_ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ if (rdev->family >= CHIP_RV670)
+ pi->fb_div_scale = 1;
+ else
+ pi->fb_div_scale = 0;
+
+ pi->voltage_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0);
+
+ pi->gfx_clock_gating = true;
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->sclk_ss = true;
+ pi->mclk_ss = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->sclk_ss = false;
+ pi->mclk_ss = false;
+ pi->dynamic_ss = false;
+ }
+
+ pi->dynamic_pcie_gen2 = true;
+
+ if (pi->gfx_clock_gating &&
+ (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ pi->display_gap = true;
+
+ return 0;
+}
+
+void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+ struct rv6xx_pl *pl;
+
+ r600_dpm_print_class_info(rps->class, rps->class2);
+ r600_dpm_print_cap_info(rps->caps);
+ printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ pl = &ps->low;
+ printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n",
+ pl->sclk, pl->mclk, pl->vddc);
+ pl = &ps->medium;
+ printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n",
+ pl->sclk, pl->mclk, pl->vddc);
+ pl = &ps->high;
+ printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n",
+ pl->sclk, pl->mclk, pl->vddc);
+ r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct rv6xx_ps *ps = rv6xx_get_ps(rps);
+ struct rv6xx_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+ CURRENT_PROFILE_INDEX_SHIFT;
+
+ if (current_index > 2) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ if (current_index == 0)
+ pl = &ps->low;
+ else if (current_index == 1)
+ pl = &ps->medium;
+ else /* current_index == 2 */
+ pl = &ps->high;
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc);
+ }
+}
+
+void rv6xx_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+}
+
+u32 rv6xx_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+ if (low)
+ return requested_state->low.sclk;
+ else
+ return requested_state->high.sclk;
+}
+
+u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct rv6xx_ps *requested_state = rv6xx_get_ps(rdev->pm.dpm.requested_ps);
+
+ if (low)
+ return requested_state->low.mclk;
+ else
+ return requested_state->high.mclk;
+}
diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.h b/drivers/gpu/drm/radeon/rv6xx_dpm.h
new file mode 100644
index 000000000000..8035d53ebea6
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv6xx_dpm.h
@@ -0,0 +1,95 @@
+/*
+ * 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
+ */
+
+#ifndef __RV6XX_DPM_H__
+#define __RV6XX_DPM_H__
+
+#include "r600_dpm.h"
+
+/* Represents a single SCLK step. */
+struct rv6xx_sclk_stepping
+{
+ u32 vco_frequency;
+ u32 post_divider;
+};
+
+struct rv6xx_pm_hw_state {
+ u32 sclks[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+ u32 mclks[R600_PM_NUMBER_OF_MCLKS];
+ u16 vddc[R600_PM_NUMBER_OF_VOLTAGE_LEVELS];
+ bool backbias[R600_PM_NUMBER_OF_VOLTAGE_LEVELS];
+ bool pcie_gen2[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+ u8 high_sclk_index;
+ u8 medium_sclk_index;
+ u8 low_sclk_index;
+ u8 high_mclk_index;
+ u8 medium_mclk_index;
+ u8 low_mclk_index;
+ u8 high_vddc_index;
+ u8 medium_vddc_index;
+ u8 low_vddc_index;
+ u8 rp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+ u8 lp[R600_PM_NUMBER_OF_ACTIVITY_LEVELS];
+};
+
+struct rv6xx_power_info {
+ /* flags */
+ bool voltage_control;
+ bool sclk_ss;
+ bool mclk_ss;
+ bool dynamic_ss;
+ bool dynamic_pcie_gen2;
+ bool thermal_protection;
+ bool display_gap;
+ bool gfx_clock_gating;
+ /* clk values */
+ u32 fb_div_scale;
+ u32 spll_ref_div;
+ u32 mpll_ref_div;
+ u32 bsu;
+ u32 bsp;
+ /* */
+ u32 active_auto_throttle_sources;
+ /* current power state */
+ u32 restricted_levels;
+ struct rv6xx_pm_hw_state hw;
+};
+
+struct rv6xx_pl {
+ u32 sclk;
+ u32 mclk;
+ u16 vddc;
+ u32 flags;
+};
+
+struct rv6xx_ps {
+ struct rv6xx_pl high;
+ struct rv6xx_pl medium;
+ struct rv6xx_pl low;
+};
+
+#define RV6XX_DEFAULT_VCLK_FREQ 40000 /* 10 khz */
+#define RV6XX_DEFAULT_DCLK_FREQ 30000 /* 10 khz */
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv6xxd.h b/drivers/gpu/drm/radeon/rv6xxd.h
new file mode 100644
index 000000000000..34e86f90b431
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv6xxd.h
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ *
+ */
+#ifndef RV6XXD_H
+#define RV6XXD_H
+
+/* RV6xx power management */
+#define SPLL_CNTL_MODE 0x60c
+# define SPLL_DIV_SYNC (1 << 5)
+
+#define GENERAL_PWRMGT 0x618
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define MOBILE_SU (1 << 2)
+# define THERMAL_PROTECTION_DIS (1 << 3)
+# define THERMAL_PROTECTION_TYPE (1 << 4)
+# define ENABLE_GEN2PCIE (1 << 5)
+# define SW_GPIO_INDEX(x) ((x) << 6)
+# define SW_GPIO_INDEX_MASK (3 << 6)
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+# define BACKBIAS_PAD_EN (1 << 16)
+# define BACKBIAS_VALUE (1 << 17)
+# define BACKBIAS_DPM_CNTL (1 << 18)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 21)
+
+#define MCLK_PWRMGT_CNTL 0x624
+# define MPLL_PWRMGT_OFF (1 << 0)
+# define YCLK_TURNOFF (1 << 1)
+# define MPLL_TURNOFF (1 << 2)
+# define SU_MCLK_USE_BCLK (1 << 3)
+# define DLL_READY (1 << 4)
+# define MC_BUSY (1 << 5)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA_SLEEP (1 << 8)
+# define MRDCKB_SLEEP (1 << 9)
+# define MRDCKC_SLEEP (1 << 10)
+# define MRDCKD_SLEEP (1 << 11)
+# define MRDCKE_SLEEP (1 << 12)
+# define MRDCKF_SLEEP (1 << 13)
+# define MRDCKG_SLEEP (1 << 14)
+# define MRDCKH_SLEEP (1 << 15)
+# define MRDCKA_RESET (1 << 16)
+# define MRDCKB_RESET (1 << 17)
+# define MRDCKC_RESET (1 << 18)
+# define MRDCKD_RESET (1 << 19)
+# define MRDCKE_RESET (1 << 20)
+# define MRDCKF_RESET (1 << 21)
+# define MRDCKG_RESET (1 << 22)
+# define MRDCKH_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define USE_DISPLAY_GAP_CTXSW (1 << 27)
+# define MPLL_TURNOFF_D2 (1 << 28)
+# define USE_DISPLAY_URGENT_CTXSW (1 << 29)
+
+#define MPLL_FREQ_LEVEL_0 0x6e8
+# define LEVEL0_MPLL_POST_DIV(x) ((x) << 0)
+# define LEVEL0_MPLL_POST_DIV_MASK (0xff << 0)
+# define LEVEL0_MPLL_FB_DIV(x) ((x) << 8)
+# define LEVEL0_MPLL_FB_DIV_MASK (0xfff << 8)
+# define LEVEL0_MPLL_REF_DIV(x) ((x) << 20)
+# define LEVEL0_MPLL_REF_DIV_MASK (0x3f << 20)
+# define LEVEL0_MPLL_DIV_EN (1 << 28)
+# define LEVEL0_DLL_BYPASS (1 << 29)
+# define LEVEL0_DLL_RESET (1 << 30)
+
+#define VID_RT 0x6f8
+# define VID_CRT(x) ((x) << 0)
+# define VID_CRT_MASK (0x1fff << 0)
+# define VID_CRTU(x) ((x) << 13)
+# define VID_CRTU_MASK (7 << 13)
+# define SSTU(x) ((x) << 16)
+# define SSTU_MASK (7 << 16)
+# define VID_SWT(x) ((x) << 19)
+# define VID_SWT_MASK (0x1f << 19)
+# define BRT(x) ((x) << 24)
+# define BRT_MASK (0xff << 24)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x70c
+# define TARGET_PROFILE_INDEX_MASK (3 << 0)
+# define TARGET_PROFILE_INDEX_SHIFT 0
+# define CURRENT_PROFILE_INDEX_MASK (3 << 2)
+# define CURRENT_PROFILE_INDEX_SHIFT 2
+# define DYN_PWR_ENTER_INDEX(x) ((x) << 4)
+# define DYN_PWR_ENTER_INDEX_MASK (3 << 4)
+# define DYN_PWR_ENTER_INDEX_SHIFT 4
+# define CURR_MCLK_INDEX_MASK (3 << 6)
+# define CURR_MCLK_INDEX_SHIFT 6
+# define CURR_SCLK_INDEX_MASK (0x1f << 8)
+# define CURR_SCLK_INDEX_SHIFT 8
+# define CURR_VID_INDEX_MASK (3 << 13)
+# define CURR_VID_INDEX_SHIFT 13
+
+#define VID_UPPER_GPIO_CNTL 0x740
+# define CTXSW_UPPER_GPIO_VALUES(x) ((x) << 0)
+# define CTXSW_UPPER_GPIO_VALUES_MASK (7 << 0)
+# define HIGH_UPPER_GPIO_VALUES(x) ((x) << 3)
+# define HIGH_UPPER_GPIO_VALUES_MASK (7 << 3)
+# define MEDIUM_UPPER_GPIO_VALUES(x) ((x) << 6)
+# define MEDIUM_UPPER_GPIO_VALUES_MASK (7 << 6)
+# define LOW_UPPER_GPIO_VALUES(x) ((x) << 9)
+# define LOW_UPPER_GPIO_VALUES_MASK (7 << 9)
+# define CTXSW_BACKBIAS_VALUE (1 << 12)
+# define HIGH_BACKBIAS_VALUE (1 << 13)
+# define MEDIUM_BACKBIAS_VALUE (1 << 14)
+# define LOW_BACKBIAS_VALUE (1 << 15)
+
+#define CG_DISPLAY_GAP_CNTL 0x7dc
+# define DISP1_GAP(x) ((x) << 0)
+# define DISP1_GAP_MASK (3 << 0)
+# define DISP2_GAP(x) ((x) << 2)
+# define DISP2_GAP_MASK (3 << 2)
+# define VBI_TIMER_COUNT(x) ((x) << 4)
+# define VBI_TIMER_COUNT_MASK (0x3fff << 4)
+# define VBI_TIMER_UNIT(x) ((x) << 20)
+# define VBI_TIMER_UNIT_MASK (7 << 20)
+# define DISP1_GAP_MCHG(x) ((x) << 24)
+# define DISP1_GAP_MCHG_MASK (3 << 24)
+# define DISP2_GAP_MCHG(x) ((x) << 26)
+# define DISP2_GAP_MCHG_MASK (3 << 26)
+
+#define CG_THERMAL_CTRL 0x7f0
+# define DPM_EVENT_SRC(x) ((x) << 0)
+# define DPM_EVENT_SRC_MASK (7 << 0)
+# define THERM_INC_CLK (1 << 3)
+# define TOFFSET(x) ((x) << 4)
+# define TOFFSET_MASK (0xff << 4)
+# define DIG_THERM_DPM(x) ((x) << 12)
+# define DIG_THERM_DPM_MASK (0xff << 12)
+# define CTF_SEL(x) ((x) << 20)
+# define CTF_SEL_MASK (7 << 20)
+# define CTF_PAD_POLARITY (1 << 23)
+# define CTF_PAD_EN (1 << 24)
+
+#define CG_SPLL_SPREAD_SPECTRUM_LOW 0x820
+# define SSEN (1 << 0)
+# define CLKS(x) ((x) << 3)
+# define CLKS_MASK (0xff << 3)
+# define CLKS_SHIFT 3
+# define CLKV(x) ((x) << 11)
+# define CLKV_MASK (0x7ff << 11)
+# define CLKV_SHIFT 11
+#define CG_MPLL_SPREAD_SPECTRUM 0x830
+
+#define CITF_CNTL 0x200c
+# define BLACKOUT_RD (1 << 0)
+# define BLACKOUT_WR (1 << 1)
+
+#define RAMCFG 0x2408
+#define NOOFBANK_SHIFT 0
+#define NOOFBANK_MASK 0x00000001
+#define NOOFRANK_SHIFT 1
+#define NOOFRANK_MASK 0x00000002
+#define NOOFROWS_SHIFT 2
+#define NOOFROWS_MASK 0x0000001C
+#define NOOFCOLS_SHIFT 5
+#define NOOFCOLS_MASK 0x00000060
+#define CHANSIZE_SHIFT 7
+#define CHANSIZE_MASK 0x00000080
+#define BURSTLENGTH_SHIFT 8
+#define BURSTLENGTH_MASK 0x00000100
+#define CHANSIZE_OVERRIDE (1 << 10)
+
+#define SQM_RATIO 0x2424
+# define STATE0(x) ((x) << 0)
+# define STATE0_MASK (0xff << 0)
+# define STATE1(x) ((x) << 8)
+# define STATE1_MASK (0xff << 8)
+# define STATE2(x) ((x) << 16)
+# define STATE2_MASK (0xff << 16)
+# define STATE3(x) ((x) << 24)
+# define STATE3_MASK (0xff << 24)
+
+#define ARB_RFSH_CNTL 0x2460
+# define ENABLE (1 << 0)
+#define ARB_RFSH_RATE 0x2464
+# define POWERMODE0(x) ((x) << 0)
+# define POWERMODE0_MASK (0xff << 0)
+# define POWERMODE1(x) ((x) << 8)
+# define POWERMODE1_MASK (0xff << 8)
+# define POWERMODE2(x) ((x) << 16)
+# define POWERMODE2_MASK (0xff << 16)
+# define POWERMODE3(x) ((x) << 24)
+# define POWERMODE3_MASK (0xff << 24)
+
+#define MC_SEQ_DRAM 0x2608
+# define CKE_DYN (1 << 12)
+
+#define MC_SEQ_CMD 0x26c4
+
+#define MC_SEQ_RESERVE_S 0x2890
+#define MC_SEQ_RESERVE_M 0x2894
+
+#define LVTMA_DATA_SYNCHRONIZATION 0x7adc
+# define LVTMA_PFREQCHG (1 << 8)
+#define DCE3_LVTMA_DATA_SYNCHRONIZATION 0x7f98
+
+/* PCIE indirect regs */
+#define PCIE_P_CNTL 0x40
+# define P_PLL_PWRDN_IN_L1L23 (1 << 3)
+# define P_PLL_BUF_PDNB (1 << 4)
+# define P_PLL_PDNB (1 << 9)
+# define P_ALLOW_PRX_FRONTEND_SHUTOFF (1 << 12)
+/* PCIE PORT indirect regs */
+#define PCIE_LC_CNTL 0xa0
+# define LC_L0S_INACTIVITY(x) ((x) << 8)
+# define LC_L0S_INACTIVITY_MASK (0xf << 8)
+# define LC_L0S_INACTIVITY_SHIFT 8
+# define LC_L1_INACTIVITY(x) ((x) << 12)
+# define LC_L1_INACTIVITY_MASK (0xf << 12)
+# define LC_L1_INACTIVITY_SHIFT 12
+# define LC_PMI_TO_L1_DIS (1 << 16)
+# define LC_ASPM_TO_L1_DIS (1 << 24)
+#define PCIE_LC_SPEED_CNTL 0xa4
+# define LC_GEN2_EN (1 << 0)
+# define LC_INITIATE_LINK_SPEED_CHANGE (1 << 7)
+# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 24)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv730_dpm.c b/drivers/gpu/drm/radeon/rv730_dpm.c
new file mode 100644
index 000000000000..3f5e1cf138ba
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv730_dpm.c
@@ -0,0 +1,508 @@
+/*
+ * 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 "radeon.h"
+#include "rv730d.h"
+#include "r600_dpm.h"
+#include "rv770_dpm.h"
+#include "atom.h"
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+
+int rv730_populate_sclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ RV770_SMC_SCLK_VALUE *sclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ u32 spll_func_cntl = pi->clk_regs.rv730.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = pi->clk_regs.rv730.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = pi->clk_regs.rv730.cg_spll_func_cntl_3;
+ u32 cg_spll_spread_spectrum = pi->clk_regs.rv730.cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv730.cg_spll_spread_spectrum_2;
+ u64 tmp;
+ u32 reference_clock = rdev->clock.spll.reference_freq;
+ u32 reference_divider, post_divider;
+ u32 fbdiv;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ engine_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = 1 + dividers.ref_div;
+
+ if (dividers.enable_post_div)
+ post_divider = ((dividers.post_div >> 4) & 0xf) +
+ (dividers.post_div & 0xf) + 2;
+ else
+ post_divider = 1;
+
+ tmp = (u64) engine_clock * reference_divider * post_divider * 16384;
+ do_div(tmp, reference_clock);
+ fbdiv = (u32) tmp;
+
+ /* set up registers */
+ if (dividers.enable_post_div)
+ spll_func_cntl |= SPLL_DIVEN;
+ else
+ spll_func_cntl &= ~SPLL_DIVEN;
+ spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK);
+ spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+ spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf);
+ spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+ spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+ spll_func_cntl_3 |= SPLL_DITHEN;
+
+ if (pi->sclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = engine_clock * post_divider;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+ u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+ u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000);
+
+ cg_spll_spread_spectrum &= ~CLK_S_MASK;
+ cg_spll_spread_spectrum |= CLK_S(clk_s);
+ cg_spll_spread_spectrum |= SSEN;
+
+ cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+ cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+ }
+ }
+
+ sclk->sclk_value = cpu_to_be32(engine_clock);
+ sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
+
+ return 0;
+}
+
+int rv730_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock,
+ LPRV7XX_SMC_MCLK_VALUE mclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 mclk_pwrmgt_cntl = pi->clk_regs.rv730.mclk_pwrmgt_cntl;
+ u32 dll_cntl = pi->clk_regs.rv730.dll_cntl;
+ u32 mpll_func_cntl = pi->clk_regs.rv730.mpll_func_cntl;
+ u32 mpll_func_cntl_2 = pi->clk_regs.rv730.mpll_func_cntl2;
+ u32 mpll_func_cntl_3 = pi->clk_regs.rv730.mpll_func_cntl3;
+ u32 mpll_ss = pi->clk_regs.rv730.mpll_ss;
+ u32 mpll_ss2 = pi->clk_regs.rv730.mpll_ss2;
+ struct atom_clock_dividers dividers;
+ u32 post_divider, reference_divider;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ memory_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = dividers.ref_div + 1;
+
+ if (dividers.enable_post_div)
+ post_divider = ((dividers.post_div >> 4) & 0xf) +
+ (dividers.post_div & 0xf) + 2;
+ else
+ post_divider = 1;
+
+ /* setup the registers */
+ if (dividers.enable_post_div)
+ mpll_func_cntl |= MPLL_DIVEN;
+ else
+ mpll_func_cntl &= ~MPLL_DIVEN;
+
+ mpll_func_cntl &= ~(MPLL_REF_DIV_MASK | MPLL_HILEN_MASK | MPLL_LOLEN_MASK);
+ mpll_func_cntl |= MPLL_REF_DIV(dividers.ref_div);
+ mpll_func_cntl |= MPLL_HILEN((dividers.post_div >> 4) & 0xf);
+ mpll_func_cntl |= MPLL_LOLEN(dividers.post_div & 0xf);
+
+ mpll_func_cntl_3 &= ~MPLL_FB_DIV_MASK;
+ mpll_func_cntl_3 |= MPLL_FB_DIV(dividers.fb_div);
+ if (dividers.enable_dithen)
+ mpll_func_cntl_3 |= MPLL_DITHEN;
+ else
+ mpll_func_cntl_3 &= ~MPLL_DITHEN;
+
+ if (pi->mclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = memory_clock * post_divider;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+ u32 reference_clock = rdev->clock.mpll.reference_freq;
+ u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+ u32 clk_v = ss.percentage * dividers.fb_div / (clk_s * 10000);
+
+ mpll_ss &= ~CLK_S_MASK;
+ mpll_ss |= CLK_S(clk_s);
+ mpll_ss |= SSEN;
+
+ mpll_ss2 &= ~CLK_V_MASK;
+ mpll_ss |= CLK_V(clk_v);
+ }
+ }
+
+
+ mclk->mclk730.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ mclk->mclk730.vDLL_CNTL = cpu_to_be32(dll_cntl);
+ mclk->mclk730.mclk_value = cpu_to_be32(memory_clock);
+ mclk->mclk730.vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl);
+ mclk->mclk730.vMPLL_FUNC_CNTL2 = cpu_to_be32(mpll_func_cntl_2);
+ mclk->mclk730.vMPLL_FUNC_CNTL3 = cpu_to_be32(mpll_func_cntl_3);
+ mclk->mclk730.vMPLL_SS = cpu_to_be32(mpll_ss);
+ mclk->mclk730.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+ return 0;
+}
+
+void rv730_read_clock_registers(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ pi->clk_regs.rv730.cg_spll_func_cntl =
+ RREG32(CG_SPLL_FUNC_CNTL);
+ pi->clk_regs.rv730.cg_spll_func_cntl_2 =
+ RREG32(CG_SPLL_FUNC_CNTL_2);
+ pi->clk_regs.rv730.cg_spll_func_cntl_3 =
+ RREG32(CG_SPLL_FUNC_CNTL_3);
+ pi->clk_regs.rv730.cg_spll_spread_spectrum =
+ RREG32(CG_SPLL_SPREAD_SPECTRUM);
+ pi->clk_regs.rv730.cg_spll_spread_spectrum_2 =
+ RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+
+ pi->clk_regs.rv730.mclk_pwrmgt_cntl =
+ RREG32(TCI_MCLK_PWRMGT_CNTL);
+ pi->clk_regs.rv730.dll_cntl =
+ RREG32(TCI_DLL_CNTL);
+ pi->clk_regs.rv730.mpll_func_cntl =
+ RREG32(CG_MPLL_FUNC_CNTL);
+ pi->clk_regs.rv730.mpll_func_cntl2 =
+ RREG32(CG_MPLL_FUNC_CNTL_2);
+ pi->clk_regs.rv730.mpll_func_cntl3 =
+ RREG32(CG_MPLL_FUNC_CNTL_3);
+ pi->clk_regs.rv730.mpll_ss =
+ RREG32(CG_TCI_MPLL_SPREAD_SPECTRUM);
+ pi->clk_regs.rv730.mpll_ss2 =
+ RREG32(CG_TCI_MPLL_SPREAD_SPECTRUM_2);
+}
+
+int rv730_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 mpll_func_cntl = 0;
+ u32 mpll_func_cntl_2 = 0 ;
+ u32 mpll_func_cntl_3 = 0;
+ u32 mclk_pwrmgt_cntl;
+ u32 dll_cntl;
+ u32 spll_func_cntl;
+ u32 spll_func_cntl_2;
+ u32 spll_func_cntl_3;
+
+ table->ACPIState = table->initialState;
+ table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc) {
+ rv770_populate_vddc_value(rdev, pi->acpi_vddc,
+ &table->ACPIState.levels[0].vddc);
+ table->ACPIState.levels[0].gen2PCIE = pi->pcie_gen2 ?
+ pi->acpi_pcie_gen2 : 0;
+ table->ACPIState.levels[0].gen2XSP =
+ pi->acpi_pcie_gen2;
+ } else {
+ rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
+ &table->ACPIState.levels[0].vddc);
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ }
+
+ mpll_func_cntl = pi->clk_regs.rv730.mpll_func_cntl;
+ mpll_func_cntl_2 = pi->clk_regs.rv730.mpll_func_cntl2;
+ mpll_func_cntl_3 = pi->clk_regs.rv730.mpll_func_cntl3;
+
+ mpll_func_cntl |= MPLL_RESET | MPLL_BYPASS_EN;
+ mpll_func_cntl &= ~MPLL_SLEEP;
+
+ mpll_func_cntl_2 &= ~MCLK_MUX_SEL_MASK;
+ mpll_func_cntl_2 |= MCLK_MUX_SEL(1);
+
+ mclk_pwrmgt_cntl = (MRDCKA_RESET |
+ MRDCKB_RESET |
+ MRDCKC_RESET |
+ MRDCKD_RESET |
+ MRDCKE_RESET |
+ MRDCKF_RESET |
+ MRDCKG_RESET |
+ MRDCKH_RESET |
+ MRDCKA_SLEEP |
+ MRDCKB_SLEEP |
+ MRDCKC_SLEEP |
+ MRDCKD_SLEEP |
+ MRDCKE_SLEEP |
+ MRDCKF_SLEEP |
+ MRDCKG_SLEEP |
+ MRDCKH_SLEEP);
+
+ dll_cntl = 0xff000000;
+
+ spll_func_cntl = pi->clk_regs.rv730.cg_spll_func_cntl;
+ spll_func_cntl_2 = pi->clk_regs.rv730.cg_spll_func_cntl_2;
+ spll_func_cntl_3 = pi->clk_regs.rv730.cg_spll_func_cntl_3;
+
+ spll_func_cntl |= SPLL_RESET | SPLL_BYPASS_EN;
+ spll_func_cntl &= ~SPLL_SLEEP;
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+ table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL2 = cpu_to_be32(mpll_func_cntl_2);
+ table->ACPIState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL3 = cpu_to_be32(mpll_func_cntl_3);
+ table->ACPIState.levels[0].mclk.mclk730.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ table->ACPIState.levels[0].mclk.mclk730.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+ table->ACPIState.levels[0].mclk.mclk730.mclk_value = 0;
+
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+
+ table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+ rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+ table->ACPIState.levels[1] = table->ACPIState.levels[0];
+ table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+ return 0;
+}
+
+int rv730_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 a_t;
+
+ table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl);
+ table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL2 =
+ cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl2);
+ table->initialState.levels[0].mclk.mclk730.vMPLL_FUNC_CNTL3 =
+ cpu_to_be32(pi->clk_regs.rv730.mpll_func_cntl3);
+ table->initialState.levels[0].mclk.mclk730.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(pi->clk_regs.rv730.mclk_pwrmgt_cntl);
+ table->initialState.levels[0].mclk.mclk730.vDLL_CNTL =
+ cpu_to_be32(pi->clk_regs.rv730.dll_cntl);
+ table->initialState.levels[0].mclk.mclk730.vMPLL_SS =
+ cpu_to_be32(pi->clk_regs.rv730.mpll_ss);
+ table->initialState.levels[0].mclk.mclk730.vMPLL_SS2 =
+ cpu_to_be32(pi->clk_regs.rv730.mpll_ss2);
+
+ table->initialState.levels[0].mclk.mclk730.mclk_value =
+ cpu_to_be32(initial_state->low.mclk);
+
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl_2);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(pi->clk_regs.rv730.cg_spll_func_cntl_3);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+ cpu_to_be32(pi->clk_regs.rv730.cg_spll_spread_spectrum);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cpu_to_be32(pi->clk_regs.rv730.cg_spll_spread_spectrum_2);
+
+ table->initialState.levels[0].sclk.sclk_value =
+ cpu_to_be32(initial_state->low.sclk);
+
+ table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+
+ table->initialState.levels[0].seqValue =
+ rv770_get_seq_value(rdev, &initial_state->low);
+
+ rv770_populate_vddc_value(rdev,
+ initial_state->low.vddc,
+ &table->initialState.levels[0].vddc);
+ rv770_populate_initial_mvdd_value(rdev,
+ &table->initialState.levels[0].mvdd);
+
+ a_t = CG_R(0xffff) | CG_L(0);
+
+ table->initialState.levels[0].aT = cpu_to_be32(a_t);
+
+ table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+ if (pi->boot_in_gen2)
+ table->initialState.levels[0].gen2PCIE = 1;
+ else
+ table->initialState.levels[0].gen2PCIE = 0;
+ if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+ table->initialState.levels[0].gen2XSP = 1;
+ else
+ table->initialState.levels[0].gen2XSP = 0;
+
+ table->initialState.levels[1] = table->initialState.levels[0];
+ table->initialState.levels[2] = table->initialState.levels[0];
+
+ table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ return 0;
+}
+
+void rv730_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+ u32 arb_refresh_rate = 0;
+ u32 dram_timing = 0;
+ u32 dram_timing2 = 0;
+ u32 old_dram_timing = 0;
+ u32 old_dram_timing2 = 0;
+
+ arb_refresh_rate = RREG32(MC_ARB_RFSH_RATE) &
+ ~(POWERMODE1_MASK | POWERMODE2_MASK | POWERMODE3_MASK);
+ arb_refresh_rate |=
+ (POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) |
+ POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) |
+ POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk)));
+ WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate);
+
+ /* save the boot dram timings */
+ old_dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ old_dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+ radeon_atom_set_engine_dram_timings(rdev,
+ state->high.sclk,
+ state->high.mclk);
+
+ dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+ WREG32(MC_ARB_DRAM_TIMING_3, dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2_3, dram_timing2);
+
+ radeon_atom_set_engine_dram_timings(rdev,
+ state->medium.sclk,
+ state->medium.mclk);
+
+ dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+ WREG32(MC_ARB_DRAM_TIMING_2, dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2_2, dram_timing2);
+
+ radeon_atom_set_engine_dram_timings(rdev,
+ state->low.sclk,
+ state->low.mclk);
+
+ dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+
+ WREG32(MC_ARB_DRAM_TIMING_1, dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2_1, dram_timing2);
+
+ /* restore the boot dram timings */
+ WREG32(MC_ARB_DRAM_TIMING, old_dram_timing);
+ WREG32(MC_ARB_DRAM_TIMING2, old_dram_timing2);
+
+}
+
+void rv730_start_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+
+ WREG32_P(TCI_MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+
+ WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+void rv730_stop_dpm(struct radeon_device *rdev)
+{
+ PPSMC_Result result;
+
+ result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
+
+ if (result != PPSMC_Result_OK)
+ DRM_ERROR("Could not force DPM to low\n");
+
+ WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+
+ WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+
+ WREG32_P(TCI_MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+void rv730_program_dcodt(struct radeon_device *rdev, bool use_dcodt)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 i = use_dcodt ? 0 : 1;
+ u32 mc4_io_pad_cntl;
+
+ mc4_io_pad_cntl = RREG32(MC4_IO_DQ_PAD_CNTL_D0_I0);
+ mc4_io_pad_cntl &= 0xFFFFFF00;
+ mc4_io_pad_cntl |= pi->odt_value_0[i];
+ WREG32(MC4_IO_DQ_PAD_CNTL_D0_I0, mc4_io_pad_cntl);
+ WREG32(MC4_IO_DQ_PAD_CNTL_D0_I1, mc4_io_pad_cntl);
+
+ mc4_io_pad_cntl = RREG32(MC4_IO_QS_PAD_CNTL_D0_I0);
+ mc4_io_pad_cntl &= 0xFFFFFF00;
+ mc4_io_pad_cntl |= pi->odt_value_1[i];
+ WREG32(MC4_IO_QS_PAD_CNTL_D0_I0, mc4_io_pad_cntl);
+ WREG32(MC4_IO_QS_PAD_CNTL_D0_I1, mc4_io_pad_cntl);
+}
+
+void rv730_get_odt_values(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 mc4_io_pad_cntl;
+
+ pi->odt_value_0[0] = (u8)0;
+ pi->odt_value_1[0] = (u8)0x80;
+
+ mc4_io_pad_cntl = RREG32(MC4_IO_DQ_PAD_CNTL_D0_I0);
+ pi->odt_value_0[1] = (u8)(mc4_io_pad_cntl & 0xff);
+
+ mc4_io_pad_cntl = RREG32(MC4_IO_QS_PAD_CNTL_D0_I0);
+ pi->odt_value_1[1] = (u8)(mc4_io_pad_cntl & 0xff);
+}
diff --git a/drivers/gpu/drm/radeon/rv730d.h b/drivers/gpu/drm/radeon/rv730d.h
new file mode 100644
index 000000000000..f0a7954fb1cb
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv730d.h
@@ -0,0 +1,165 @@
+/*
+ * 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.
+ *
+ */
+#ifndef RV730_H
+#define RV730_H
+
+#define CG_SPLL_FUNC_CNTL 0x600
+#define SPLL_RESET (1 << 0)
+#define SPLL_SLEEP (1 << 1)
+#define SPLL_DIVEN (1 << 2)
+#define SPLL_BYPASS_EN (1 << 3)
+#define SPLL_REF_DIV(x) ((x) << 4)
+#define SPLL_REF_DIV_MASK (0x3f << 4)
+#define SPLL_HILEN(x) ((x) << 12)
+#define SPLL_HILEN_MASK (0xf << 12)
+#define SPLL_LOLEN(x) ((x) << 16)
+#define SPLL_LOLEN_MASK (0xf << 16)
+#define CG_SPLL_FUNC_CNTL_2 0x604
+#define SCLK_MUX_SEL(x) ((x) << 0)
+#define SCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_SPLL_FUNC_CNTL_3 0x608
+#define SPLL_FB_DIV(x) ((x) << 0)
+#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define SPLL_DITHEN (1 << 28)
+
+#define CG_MPLL_FUNC_CNTL 0x624
+#define MPLL_RESET (1 << 0)
+#define MPLL_SLEEP (1 << 1)
+#define MPLL_DIVEN (1 << 2)
+#define MPLL_BYPASS_EN (1 << 3)
+#define MPLL_REF_DIV(x) ((x) << 4)
+#define MPLL_REF_DIV_MASK (0x3f << 4)
+#define MPLL_HILEN(x) ((x) << 12)
+#define MPLL_HILEN_MASK (0xf << 12)
+#define MPLL_LOLEN(x) ((x) << 16)
+#define MPLL_LOLEN_MASK (0xf << 16)
+#define CG_MPLL_FUNC_CNTL_2 0x628
+#define MCLK_MUX_SEL(x) ((x) << 0)
+#define MCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_MPLL_FUNC_CNTL_3 0x62c
+#define MPLL_FB_DIV(x) ((x) << 0)
+#define MPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define MPLL_DITHEN (1 << 28)
+
+#define CG_TCI_MPLL_SPREAD_SPECTRUM 0x634
+#define CG_TCI_MPLL_SPREAD_SPECTRUM_2 0x638
+#define GENERAL_PWRMGT 0x63c
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define THERMAL_PROTECTION_DIS (1 << 2)
+# define THERMAL_PROTECTION_TYPE (1 << 3)
+# define ENABLE_GEN2PCIE (1 << 4)
+# define ENABLE_GEN2XSP (1 << 5)
+# define SW_SMIO_INDEX(x) ((x) << 6)
+# define SW_SMIO_INDEX_MASK (3 << 6)
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+# define BACKBIAS_PAD_EN (1 << 18)
+# define BACKBIAS_VALUE (1 << 19)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
+# define AC_DC_SW (1 << 24)
+
+#define SCLK_PWRMGT_CNTL 0x644
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_LOW_D1 (1 << 1)
+# define FIR_RESET (1 << 4)
+# define FIR_FORCE_TREND_SEL (1 << 5)
+# define FIR_TREND_MODE (1 << 6)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define GFX_CLK_REQUEST_OFF (1 << 9)
+# define GFX_CLK_FORCE_OFF (1 << 10)
+# define GFX_CLK_OFF_ACPI_D1 (1 << 11)
+# define GFX_CLK_OFF_ACPI_D2 (1 << 12)
+# define GFX_CLK_OFF_ACPI_D3 (1 << 13)
+
+#define TCI_MCLK_PWRMGT_CNTL 0x648
+# define MPLL_PWRMGT_OFF (1 << 5)
+# define DLL_READY (1 << 6)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA_SLEEP (1 << 8)
+# define MRDCKB_SLEEP (1 << 9)
+# define MRDCKC_SLEEP (1 << 10)
+# define MRDCKD_SLEEP (1 << 11)
+# define MRDCKE_SLEEP (1 << 12)
+# define MRDCKF_SLEEP (1 << 13)
+# define MRDCKG_SLEEP (1 << 14)
+# define MRDCKH_SLEEP (1 << 15)
+# define MRDCKA_RESET (1 << 16)
+# define MRDCKB_RESET (1 << 17)
+# define MRDCKC_RESET (1 << 18)
+# define MRDCKD_RESET (1 << 19)
+# define MRDCKE_RESET (1 << 20)
+# define MRDCKF_RESET (1 << 21)
+# define MRDCKG_RESET (1 << 22)
+# define MRDCKH_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define MPLL_TURNOFF_D2 (1 << 28)
+#define TCI_DLL_CNTL 0x64c
+
+#define CG_PG_CNTL 0x858
+# define PWRGATE_ENABLE (1 << 0)
+
+#define CG_AT 0x6d4
+#define CG_R(x) ((x) << 0)
+#define CG_R_MASK (0xffff << 0)
+#define CG_L(x) ((x) << 16)
+#define CG_L_MASK (0xffff << 16)
+
+#define CG_SPLL_SPREAD_SPECTRUM 0x790
+#define SSEN (1 << 0)
+#define CLK_S(x) ((x) << 4)
+#define CLK_S_MASK (0xfff << 4)
+#define CG_SPLL_SPREAD_SPECTRUM_2 0x794
+#define CLK_V(x) ((x) << 0)
+#define CLK_V_MASK (0x3ffffff << 0)
+
+#define MC_ARB_DRAM_TIMING 0x2774
+#define MC_ARB_DRAM_TIMING2 0x2778
+
+#define MC_ARB_RFSH_RATE 0x27b0
+#define POWERMODE0(x) ((x) << 0)
+#define POWERMODE0_MASK (0xff << 0)
+#define POWERMODE1(x) ((x) << 8)
+#define POWERMODE1_MASK (0xff << 8)
+#define POWERMODE2(x) ((x) << 16)
+#define POWERMODE2_MASK (0xff << 16)
+#define POWERMODE3(x) ((x) << 24)
+#define POWERMODE3_MASK (0xff << 24)
+
+#define MC_ARB_DRAM_TIMING_1 0x27f0
+#define MC_ARB_DRAM_TIMING_2 0x27f4
+#define MC_ARB_DRAM_TIMING_3 0x27f8
+#define MC_ARB_DRAM_TIMING2_1 0x27fc
+#define MC_ARB_DRAM_TIMING2_2 0x2800
+#define MC_ARB_DRAM_TIMING2_3 0x2804
+
+#define MC4_IO_DQ_PAD_CNTL_D0_I0 0x2978
+#define MC4_IO_DQ_PAD_CNTL_D0_I1 0x297c
+#define MC4_IO_QS_PAD_CNTL_D0_I0 0x2980
+#define MC4_IO_QS_PAD_CNTL_D0_I1 0x2984
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv740_dpm.c b/drivers/gpu/drm/radeon/rv740_dpm.c
new file mode 100644
index 000000000000..c4c8da501da8
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv740_dpm.c
@@ -0,0 +1,416 @@
+/*
+ * 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 "radeon.h"
+#include "rv740d.h"
+#include "r600_dpm.h"
+#include "rv770_dpm.h"
+#include "atom.h"
+
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+
+u32 rv740_get_decoded_reference_divider(u32 encoded_ref)
+{
+ u32 ref = 0;
+
+ switch (encoded_ref) {
+ case 0:
+ ref = 1;
+ break;
+ case 16:
+ ref = 2;
+ break;
+ case 17:
+ ref = 3;
+ break;
+ case 18:
+ ref = 2;
+ break;
+ case 19:
+ ref = 3;
+ break;
+ case 20:
+ ref = 4;
+ break;
+ case 21:
+ ref = 5;
+ break;
+ default:
+ DRM_ERROR("Invalid encoded Reference Divider\n");
+ ref = 0;
+ break;
+ }
+
+ return ref;
+}
+
+struct dll_speed_setting {
+ u16 min;
+ u16 max;
+ u32 dll_speed;
+};
+
+static struct dll_speed_setting dll_speed_table[16] =
+{
+ { 270, 320, 0x0f },
+ { 240, 270, 0x0e },
+ { 200, 240, 0x0d },
+ { 180, 200, 0x0c },
+ { 160, 180, 0x0b },
+ { 140, 160, 0x0a },
+ { 120, 140, 0x09 },
+ { 110, 120, 0x08 },
+ { 95, 110, 0x07 },
+ { 85, 95, 0x06 },
+ { 78, 85, 0x05 },
+ { 70, 78, 0x04 },
+ { 65, 70, 0x03 },
+ { 60, 65, 0x02 },
+ { 42, 60, 0x01 },
+ { 00, 42, 0x00 }
+};
+
+u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock)
+{
+ int i;
+ u32 factor;
+ u16 data_rate;
+
+ if (is_gddr5)
+ factor = 4;
+ else
+ factor = 2;
+
+ data_rate = (u16)(memory_clock * factor / 1000);
+
+ if (data_rate < dll_speed_table[0].max) {
+ for (i = 0; i < 16; i++) {
+ if (data_rate > dll_speed_table[i].min &&
+ data_rate <= dll_speed_table[i].max)
+ return dll_speed_table[i].dll_speed;
+ }
+ }
+
+ DRM_DEBUG_KMS("Target MCLK greater than largest MCLK in DLL speed table\n");
+
+ return 0x0f;
+}
+
+int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
+ RV770_SMC_SCLK_VALUE *sclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
+ u32 cg_spll_spread_spectrum = pi->clk_regs.rv770.cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2 = pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
+ u64 tmp;
+ u32 reference_clock = rdev->clock.spll.reference_freq;
+ u32 reference_divider;
+ u32 fbdiv;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ engine_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = 1 + dividers.ref_div;
+
+ tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384;
+ do_div(tmp, reference_clock);
+ fbdiv = (u32) tmp;
+
+ spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
+ spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+ spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+ spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+ spll_func_cntl_3 |= SPLL_DITHEN;
+
+ if (pi->sclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = engine_clock * dividers.post_div;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &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 &= ~CLK_S_MASK;
+ cg_spll_spread_spectrum |= CLK_S(clk_s);
+ cg_spll_spread_spectrum |= SSEN;
+
+ cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+ cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+ }
+ }
+
+ sclk->sclk_value = cpu_to_be32(engine_clock);
+ sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
+
+ return 0;
+}
+
+int rv740_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock,
+ RV7XX_SMC_MCLK_VALUE *mclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+ u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+ u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
+ u32 mpll_ss1 = pi->clk_regs.rv770.mpll_ss1;
+ u32 mpll_ss2 = pi->clk_regs.rv770.mpll_ss2;
+ struct atom_clock_dividers dividers;
+ u32 ibias;
+ u32 dll_speed;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ memory_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ ibias = rv770_map_clkf_to_ibias(rdev, dividers.whole_fb_div);
+
+ mpll_ad_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_ad_func_cntl |= CLKR(dividers.ref_div);
+ mpll_ad_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+ mpll_ad_func_cntl |= CLKF(dividers.whole_fb_div);
+ mpll_ad_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+ mpll_ad_func_cntl |= IBIAS(ibias);
+
+ if (dividers.vco_mode)
+ mpll_ad_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+ if (pi->mem_gddr5) {
+ mpll_dq_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_dq_func_cntl |= CLKR(dividers.ref_div);
+ mpll_dq_func_cntl |= YCLK_POST_DIV(dividers.post_div);
+ mpll_dq_func_cntl |= CLKF(dividers.whole_fb_div);
+ mpll_dq_func_cntl |= CLKFRAC(dividers.frac_fb_div);
+ mpll_dq_func_cntl |= IBIAS(ibias);
+
+ if (dividers.vco_mode)
+ mpll_dq_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_dq_func_cntl_2 &= ~VCO_MODE;
+ }
+
+ if (pi->mclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = memory_clock * dividers.post_div;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_MEMORY_SS, vco_freq)) {
+ u32 reference_clock = rdev->clock.mpll.reference_freq;
+ u32 decoded_ref = rv740_get_decoded_reference_divider(dividers.ref_div);
+ u32 clk_s = reference_clock * 5 / (decoded_ref * ss.rate);
+ u32 clk_v = 0x40000 * ss.percentage *
+ (dividers.whole_fb_div + (dividers.frac_fb_div / 8)) / (clk_s * 10000);
+
+ mpll_ss1 &= ~CLKV_MASK;
+ mpll_ss1 |= CLKV(clk_v);
+
+ mpll_ss2 &= ~CLKS_MASK;
+ mpll_ss2 |= CLKS(clk_s);
+ }
+ }
+
+ dll_speed = rv740_get_dll_speed(pi->mem_gddr5,
+ memory_clock);
+
+ mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+ mclk_pwrmgt_cntl |= DLL_SPEED(dll_speed);
+
+ mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
+ mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+ mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+ mclk->mclk770.vMPLL_SS = cpu_to_be32(mpll_ss1);
+ mclk->mclk770.vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+ return 0;
+}
+
+void rv740_read_clock_registers(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ pi->clk_regs.rv770.cg_spll_func_cntl =
+ RREG32(CG_SPLL_FUNC_CNTL);
+ pi->clk_regs.rv770.cg_spll_func_cntl_2 =
+ RREG32(CG_SPLL_FUNC_CNTL_2);
+ pi->clk_regs.rv770.cg_spll_func_cntl_3 =
+ RREG32(CG_SPLL_FUNC_CNTL_3);
+ pi->clk_regs.rv770.cg_spll_spread_spectrum =
+ RREG32(CG_SPLL_SPREAD_SPECTRUM);
+ pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
+ RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+
+ pi->clk_regs.rv770.mpll_ad_func_cntl =
+ RREG32(MPLL_AD_FUNC_CNTL);
+ pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
+ RREG32(MPLL_AD_FUNC_CNTL_2);
+ pi->clk_regs.rv770.mpll_dq_func_cntl =
+ RREG32(MPLL_DQ_FUNC_CNTL);
+ pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
+ RREG32(MPLL_DQ_FUNC_CNTL_2);
+ pi->clk_regs.rv770.mclk_pwrmgt_cntl =
+ RREG32(MCLK_PWRMGT_CNTL);
+ pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
+ pi->clk_regs.rv770.mpll_ss1 = RREG32(MPLL_SS1);
+ pi->clk_regs.rv770.mpll_ss2 = RREG32(MPLL_SS2);
+}
+
+int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 mpll_ad_func_cntl = pi->clk_regs.rv770.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 = pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl = pi->clk_regs.rv770.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 = pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+ u32 spll_func_cntl = pi->clk_regs.rv770.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = pi->clk_regs.rv770.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = pi->clk_regs.rv770.cg_spll_func_cntl_3;
+ u32 mclk_pwrmgt_cntl = pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+ u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
+
+ table->ACPIState = table->initialState;
+
+ table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc) {
+ rv770_populate_vddc_value(rdev, pi->acpi_vddc,
+ &table->ACPIState.levels[0].vddc);
+ table->ACPIState.levels[0].gen2PCIE =
+ pi->pcie_gen2 ?
+ pi->acpi_pcie_gen2 : 0;
+ table->ACPIState.levels[0].gen2XSP =
+ pi->acpi_pcie_gen2;
+ } else {
+ rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
+ &table->ACPIState.levels[0].vddc);
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ }
+
+ mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+ mpll_dq_func_cntl_2 |= BYPASS | BIAS_GEN_PDNB | RESET_EN;
+
+ mclk_pwrmgt_cntl |= (MRDCKA0_RESET |
+ MRDCKA1_RESET |
+ MRDCKB0_RESET |
+ MRDCKB1_RESET |
+ MRDCKC0_RESET |
+ MRDCKC1_RESET |
+ MRDCKD0_RESET |
+ MRDCKD1_RESET);
+
+ dll_cntl |= (MRDCKA0_BYPASS |
+ MRDCKA1_BYPASS |
+ MRDCKB0_BYPASS |
+ MRDCKB1_BYPASS |
+ MRDCKC0_BYPASS |
+ MRDCKC1_BYPASS |
+ MRDCKD0_BYPASS |
+ MRDCKD1_BYPASS);
+
+ spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+ table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+ table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
+
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+
+ table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+ table->ACPIState.levels[1] = table->ACPIState.levels[0];
+ table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+ rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+ return 0;
+}
+
+void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(MPLL_CNTL_MODE, SS_SSEN, ~SS_SSEN);
+ else
+ WREG32_P(MPLL_CNTL_MODE, 0, ~SS_SSEN);
+}
+
+u8 rv740_get_mclk_frequency_ratio(u32 memory_clock)
+{
+ u8 mc_para_index;
+
+ if ((memory_clock < 10000) || (memory_clock > 47500))
+ mc_para_index = 0x00;
+ else
+ mc_para_index = (u8)((memory_clock - 10000) / 2500);
+
+ return mc_para_index;
+}
diff --git a/drivers/gpu/drm/radeon/rv740d.h b/drivers/gpu/drm/radeon/rv740d.h
new file mode 100644
index 000000000000..fe5ab075dc17
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv740d.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ *
+ */
+#ifndef RV740_H
+#define RV740_H
+
+#define CG_SPLL_FUNC_CNTL 0x600
+#define SPLL_RESET (1 << 0)
+#define SPLL_SLEEP (1 << 1)
+#define SPLL_BYPASS_EN (1 << 3)
+#define SPLL_REF_DIV(x) ((x) << 4)
+#define SPLL_REF_DIV_MASK (0x3f << 4)
+#define SPLL_PDIV_A(x) ((x) << 20)
+#define SPLL_PDIV_A_MASK (0x7f << 20)
+#define CG_SPLL_FUNC_CNTL_2 0x604
+#define SCLK_MUX_SEL(x) ((x) << 0)
+#define SCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_SPLL_FUNC_CNTL_3 0x608
+#define SPLL_FB_DIV(x) ((x) << 0)
+#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define SPLL_DITHEN (1 << 28)
+
+#define MPLL_CNTL_MODE 0x61c
+#define SS_SSEN (1 << 24)
+
+#define MPLL_AD_FUNC_CNTL 0x624
+#define CLKF(x) ((x) << 0)
+#define CLKF_MASK (0x7f << 0)
+#define CLKR(x) ((x) << 7)
+#define CLKR_MASK (0x1f << 7)
+#define CLKFRAC(x) ((x) << 12)
+#define CLKFRAC_MASK (0x1f << 12)
+#define YCLK_POST_DIV(x) ((x) << 17)
+#define YCLK_POST_DIV_MASK (3 << 17)
+#define IBIAS(x) ((x) << 20)
+#define IBIAS_MASK (0x3ff << 20)
+#define RESET (1 << 30)
+#define PDNB (1 << 31)
+#define MPLL_AD_FUNC_CNTL_2 0x628
+#define BYPASS (1 << 19)
+#define BIAS_GEN_PDNB (1 << 24)
+#define RESET_EN (1 << 25)
+#define VCO_MODE (1 << 29)
+#define MPLL_DQ_FUNC_CNTL 0x62c
+#define MPLL_DQ_FUNC_CNTL_2 0x630
+
+#define MCLK_PWRMGT_CNTL 0x648
+#define DLL_SPEED(x) ((x) << 0)
+#define DLL_SPEED_MASK (0x1f << 0)
+# define MPLL_PWRMGT_OFF (1 << 5)
+# define DLL_READY (1 << 6)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA0_SLEEP (1 << 8)
+# define MRDCKA1_SLEEP (1 << 9)
+# define MRDCKB0_SLEEP (1 << 10)
+# define MRDCKB1_SLEEP (1 << 11)
+# define MRDCKC0_SLEEP (1 << 12)
+# define MRDCKC1_SLEEP (1 << 13)
+# define MRDCKD0_SLEEP (1 << 14)
+# define MRDCKD1_SLEEP (1 << 15)
+# define MRDCKA0_RESET (1 << 16)
+# define MRDCKA1_RESET (1 << 17)
+# define MRDCKB0_RESET (1 << 18)
+# define MRDCKB1_RESET (1 << 19)
+# define MRDCKC0_RESET (1 << 20)
+# define MRDCKC1_RESET (1 << 21)
+# define MRDCKD0_RESET (1 << 22)
+# define MRDCKD1_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define MPLL_TURNOFF_D2 (1 << 28)
+#define DLL_CNTL 0x64c
+# define MRDCKA0_BYPASS (1 << 24)
+# define MRDCKA1_BYPASS (1 << 25)
+# define MRDCKB0_BYPASS (1 << 26)
+# define MRDCKB1_BYPASS (1 << 27)
+# define MRDCKC0_BYPASS (1 << 28)
+# define MRDCKC1_BYPASS (1 << 29)
+# define MRDCKD0_BYPASS (1 << 30)
+# define MRDCKD1_BYPASS (1 << 31)
+
+#define CG_SPLL_SPREAD_SPECTRUM 0x790
+#define SSEN (1 << 0)
+#define CLK_S(x) ((x) << 4)
+#define CLK_S_MASK (0xfff << 4)
+#define CG_SPLL_SPREAD_SPECTRUM_2 0x794
+#define CLK_V(x) ((x) << 0)
+#define CLK_V_MASK (0x3ffffff << 0)
+
+#define MPLL_SS1 0x85c
+#define CLKV(x) ((x) << 0)
+#define CLKV_MASK (0x3ffffff << 0)
+#define MPLL_SS2 0x860
+#define CLKS(x) ((x) << 0)
+#define CLKS_MASK (0xfff << 0)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
new file mode 100644
index 000000000000..d914e04ea39a
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -0,0 +1,2521 @@
+/*
+ * 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 "radeon.h"
+#include "rv770d.h"
+#include "r600_dpm.h"
+#include "rv770_dpm.h"
+#include "cypress_dpm.h"
+#include "atom.h"
+#include <linux/seq_file.h>
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+#define MC_CG_SEQ_DRAMCONF_S0 0x05
+#define MC_CG_SEQ_DRAMCONF_S1 0x06
+
+#define PCIE_BUS_CLK 10000
+#define TCLK (PCIE_BUS_CLK / 10)
+
+#define SMC_RAM_END 0xC000
+
+struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps)
+{
+ struct rv7xx_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+static void rv770_enable_bif_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ if (enable) {
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp |= LC_HW_VOLTAGE_IF_CONTROL(1);
+ tmp |= LC_GEN2_EN_STRAP;
+ } else {
+ if (!pi->boot_in_gen2) {
+ tmp &= ~LC_HW_VOLTAGE_IF_CONTROL_MASK;
+ tmp &= ~LC_GEN2_EN_STRAP;
+ }
+ }
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) ||
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, tmp);
+
+}
+
+static void rv770_enable_l0s(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L0S_INACTIVITY_MASK;
+ tmp |= LC_L0S_INACTIVITY(3);
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv770_enable_l1(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+ tmp &= ~LC_L1_INACTIVITY_MASK;
+ tmp |= LC_L1_INACTIVITY(4);
+ tmp &= ~LC_PMI_TO_L1_DIS;
+ tmp &= ~LC_ASPM_TO_L1_DIS;
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+}
+
+static void rv770_enable_pll_sleep_in_l1(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL) & ~LC_L1_INACTIVITY_MASK;
+ tmp |= LC_L1_INACTIVITY(8);
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, tmp);
+
+ /* NOTE, this is a PCIE indirect reg, not PCIE PORT */
+ tmp = RREG32_PCIE(PCIE_P_CNTL);
+ tmp |= P_PLL_PWRDN_IN_L1L23;
+ tmp &= ~P_PLL_BUF_PDNB;
+ tmp &= ~P_PLL_PDNB;
+ tmp |= P_ALLOW_PRX_FRONTEND_SHUTOFF;
+ WREG32_PCIE(PCIE_P_CNTL, tmp);
+}
+
+static void rv770_gfx_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+ else {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+ RREG32(GB_TILING_CONFIG);
+ }
+}
+
+static void rv770_mg_clock_gating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (enable) {
+ u32 mgcg_cgtt_local0;
+
+ if (rdev->family == CHIP_RV770)
+ mgcg_cgtt_local0 = RV770_MGCGTTLOCAL0_DFLT;
+ else
+ mgcg_cgtt_local0 = RV7XX_MGCGTTLOCAL0_DFLT;
+
+ WREG32(CG_CGTT_LOCAL_0, mgcg_cgtt_local0);
+ WREG32(CG_CGTT_LOCAL_1, (RV770_MGCGTTLOCAL1_DFLT & 0xFFFFCFFF));
+
+ if (pi->mgcgtssm)
+ WREG32(CGTS_SM_CTRL_REG, RV770_MGCGCGTSSMCTRL_DFLT);
+ } else {
+ WREG32(CG_CGTT_LOCAL_0, 0xFFFFFFFF);
+ WREG32(CG_CGTT_LOCAL_1, 0xFFFFCFFF);
+ }
+}
+
+void rv770_restore_cgcg(struct radeon_device *rdev)
+{
+ bool dpm_en = false, cg_en = false;
+
+ if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
+ dpm_en = true;
+ if (RREG32(SCLK_PWRMGT_CNTL) & DYN_GFX_CLK_OFF_EN)
+ cg_en = true;
+
+ if (dpm_en && !cg_en)
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+}
+
+static void rv770_start_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+
+ WREG32_P(MCLK_PWRMGT_CNTL, 0, ~MPLL_PWRMGT_OFF);
+
+ WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+void rv770_stop_dpm(struct radeon_device *rdev)
+{
+ PPSMC_Result result;
+
+ result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
+
+ if (result != PPSMC_Result_OK)
+ DRM_ERROR("Could not force DPM to low.\n");
+
+ WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+
+ WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+
+ WREG32_P(MCLK_PWRMGT_CNTL, MPLL_PWRMGT_OFF, ~MPLL_PWRMGT_OFF);
+}
+
+bool rv770_dpm_enabled(struct radeon_device *rdev)
+{
+ if (RREG32(GENERAL_PWRMGT) & GLOBAL_PWRMGT_EN)
+ return true;
+ else
+ return false;
+}
+
+void rv770_enable_thermal_protection(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ else
+ WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+}
+
+void rv770_enable_acpi_pm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+u8 rv770_get_seq_value(struct radeon_device *rdev,
+ struct rv7xx_pl *pl)
+{
+ return (pl->flags & ATOM_PPLIB_R600_FLAGS_LOWPOWER) ?
+ MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1;
+}
+
+int rv770_read_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 *value)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ return rv770_read_smc_sram_dword(rdev,
+ pi->soft_regs_start + reg_offset,
+ value, pi->sram_end);
+}
+
+int rv770_write_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 value)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ return rv770_write_smc_sram_dword(rdev,
+ pi->soft_regs_start + reg_offset,
+ value, pi->sram_end);
+}
+
+int rv770_populate_smc_t(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+ int a_n;
+ int a_d;
+ u8 l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+ u8 r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+ u32 a_t;
+
+ l[0] = 0;
+ r[2] = 100;
+
+ a_n = (int)state->medium.sclk * pi->lmp +
+ (int)state->low.sclk * (R600_AH_DFLT - pi->rlp);
+ a_d = (int)state->low.sclk * (100 - (int)pi->rlp) +
+ (int)state->medium.sclk * pi->lmp;
+
+ l[1] = (u8)(pi->lmp - (int)pi->lmp * a_n / a_d);
+ r[0] = (u8)(pi->rlp + (100 - (int)pi->rlp) * a_n / a_d);
+
+ a_n = (int)state->high.sclk * pi->lhp + (int)state->medium.sclk *
+ (R600_AH_DFLT - pi->rmp);
+ a_d = (int)state->medium.sclk * (100 - (int)pi->rmp) +
+ (int)state->high.sclk * pi->lhp;
+
+ l[2] = (u8)(pi->lhp - (int)pi->lhp * a_n / a_d);
+ r[1] = (u8)(pi->rmp + (100 - (int)pi->rmp) * a_n / a_d);
+
+ for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++) {
+ a_t = CG_R(r[i] * pi->bsp / 200) | CG_L(l[i] * pi->bsp / 200);
+ smc_state->levels[i].aT = cpu_to_be32(a_t);
+ }
+
+ a_t = CG_R(r[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200) |
+ CG_L(l[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1] * pi->pbsp / 200);
+
+ smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].aT =
+ cpu_to_be32(a_t);
+
+ return 0;
+}
+
+int rv770_populate_smc_sp(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+
+ for (i = 0; i < (RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1); i++)
+ smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
+
+ smc_state->levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1].bSP =
+ cpu_to_be32(pi->psp);
+
+ return 0;
+}
+
+static void rv770_calculate_fractional_mpll_feedback_divider(u32 memory_clock,
+ u32 reference_clock,
+ bool gddr5,
+ struct atom_clock_dividers *dividers,
+ u32 *clkf,
+ u32 *clkfrac)
+{
+ u32 post_divider, reference_divider, feedback_divider8;
+ u32 fyclk;
+
+ if (gddr5)
+ fyclk = (memory_clock * 8) / 2;
+ else
+ fyclk = (memory_clock * 4) / 2;
+
+ post_divider = dividers->post_div;
+ reference_divider = dividers->ref_div;
+
+ feedback_divider8 =
+ (8 * fyclk * reference_divider * post_divider) / reference_clock;
+
+ *clkf = feedback_divider8 / 8;
+ *clkfrac = feedback_divider8 % 8;
+}
+
+static int rv770_encode_yclk_post_div(u32 postdiv, u32 *encoded_postdiv)
+{
+ int ret = 0;
+
+ switch (postdiv) {
+ case 1:
+ *encoded_postdiv = 0;
+ break;
+ case 2:
+ *encoded_postdiv = 1;
+ break;
+ case 4:
+ *encoded_postdiv = 2;
+ break;
+ case 8:
+ *encoded_postdiv = 3;
+ break;
+ case 16:
+ *encoded_postdiv = 4;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf)
+{
+ if (clkf <= 0x10)
+ return 0x4B;
+ if (clkf <= 0x19)
+ return 0x5B;
+ if (clkf <= 0x21)
+ return 0x2B;
+ if (clkf <= 0x27)
+ return 0x6C;
+ if (clkf <= 0x31)
+ return 0x9D;
+ return 0xC6;
+}
+
+static int rv770_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock,
+ RV7XX_SMC_MCLK_VALUE *mclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 encoded_reference_dividers[] = { 0, 16, 17, 20, 21 };
+ u32 mpll_ad_func_cntl =
+ pi->clk_regs.rv770.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl =
+ pi->clk_regs.rv770.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+ u32 mclk_pwrmgt_cntl =
+ pi->clk_regs.rv770.mclk_pwrmgt_cntl;
+ u32 dll_cntl = pi->clk_regs.rv770.dll_cntl;
+ struct atom_clock_dividers dividers;
+ u32 reference_clock = rdev->clock.mpll.reference_freq;
+ u32 clkf, clkfrac;
+ u32 postdiv_yclk;
+ u32 ibias;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_MEMORY_PLL_PARAM,
+ memory_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ if ((dividers.ref_div < 1) || (dividers.ref_div > 5))
+ return -EINVAL;
+
+ rv770_calculate_fractional_mpll_feedback_divider(memory_clock, reference_clock,
+ pi->mem_gddr5,
+ &dividers, &clkf, &clkfrac);
+
+ ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk);
+ if (ret)
+ return ret;
+
+ ibias = rv770_map_clkf_to_ibias(rdev, clkf);
+
+ mpll_ad_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_ad_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]);
+ mpll_ad_func_cntl |= YCLK_POST_DIV(postdiv_yclk);
+ mpll_ad_func_cntl |= CLKF(clkf);
+ mpll_ad_func_cntl |= CLKFRAC(clkfrac);
+ mpll_ad_func_cntl |= IBIAS(ibias);
+
+ if (dividers.vco_mode)
+ mpll_ad_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_ad_func_cntl_2 &= ~VCO_MODE;
+
+ if (pi->mem_gddr5) {
+ rv770_calculate_fractional_mpll_feedback_divider(memory_clock,
+ reference_clock,
+ pi->mem_gddr5,
+ &dividers, &clkf, &clkfrac);
+
+ ibias = rv770_map_clkf_to_ibias(rdev, clkf);
+
+ ret = rv770_encode_yclk_post_div(dividers.post_div, &postdiv_yclk);
+ if (ret)
+ return ret;
+
+ mpll_dq_func_cntl &= ~(CLKR_MASK |
+ YCLK_POST_DIV_MASK |
+ CLKF_MASK |
+ CLKFRAC_MASK |
+ IBIAS_MASK);
+ mpll_dq_func_cntl |= CLKR(encoded_reference_dividers[dividers.ref_div - 1]);
+ mpll_dq_func_cntl |= YCLK_POST_DIV(postdiv_yclk);
+ mpll_dq_func_cntl |= CLKF(clkf);
+ mpll_dq_func_cntl |= CLKFRAC(clkfrac);
+ mpll_dq_func_cntl |= IBIAS(ibias);
+
+ if (dividers.vco_mode)
+ mpll_dq_func_cntl_2 |= VCO_MODE;
+ else
+ mpll_dq_func_cntl_2 &= ~VCO_MODE;
+ }
+
+ mclk->mclk770.mclk_value = cpu_to_be32(memory_clock);
+ mclk->mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ mclk->mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ mclk->mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ mclk->mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+ mclk->mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ mclk->mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+ return 0;
+}
+
+static int rv770_populate_sclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ RV770_SMC_SCLK_VALUE *sclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ u32 spll_func_cntl =
+ pi->clk_regs.rv770.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 =
+ pi->clk_regs.rv770.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 =
+ pi->clk_regs.rv770.cg_spll_func_cntl_3;
+ u32 cg_spll_spread_spectrum =
+ pi->clk_regs.rv770.cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2 =
+ pi->clk_regs.rv770.cg_spll_spread_spectrum_2;
+ u64 tmp;
+ u32 reference_clock = rdev->clock.spll.reference_freq;
+ u32 reference_divider, post_divider;
+ u32 fbdiv;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ engine_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = 1 + dividers.ref_div;
+
+ if (dividers.enable_post_div)
+ post_divider = (0x0f & (dividers.post_div >> 4)) + (0x0f & dividers.post_div) + 2;
+ else
+ post_divider = 1;
+
+ tmp = (u64) engine_clock * reference_divider * post_divider * 16384;
+ do_div(tmp, reference_clock);
+ fbdiv = (u32) tmp;
+
+ if (dividers.enable_post_div)
+ spll_func_cntl |= SPLL_DIVEN;
+ else
+ spll_func_cntl &= ~SPLL_DIVEN;
+ spll_func_cntl &= ~(SPLL_HILEN_MASK | SPLL_LOLEN_MASK | SPLL_REF_DIV_MASK);
+ spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+ spll_func_cntl |= SPLL_HILEN((dividers.post_div >> 4) & 0xf);
+ spll_func_cntl |= SPLL_LOLEN(dividers.post_div & 0xf);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+ spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+ spll_func_cntl_3 |= SPLL_DITHEN;
+
+ if (pi->sclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = engine_clock * post_divider;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_ENGINE_SS, vco_freq)) {
+ u32 clk_s = reference_clock * 5 / (reference_divider * ss.rate);
+ u32 clk_v = ss.percentage * fbdiv / (clk_s * 10000);
+
+ cg_spll_spread_spectrum &= ~CLKS_MASK;
+ cg_spll_spread_spectrum |= CLKS(clk_s);
+ cg_spll_spread_spectrum |= SSEN;
+
+ cg_spll_spread_spectrum_2 &= ~CLKV_MASK;
+ cg_spll_spread_spectrum_2 |= CLKV(clk_v);
+ }
+ }
+
+ sclk->sclk_value = cpu_to_be32(engine_clock);
+ sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(cg_spll_spread_spectrum);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(cg_spll_spread_spectrum_2);
+
+ return 0;
+}
+
+int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc,
+ RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+
+ if (!pi->voltage_control) {
+ voltage->index = 0;
+ voltage->value = 0;
+ return 0;
+ }
+
+ for (i = 0; i < pi->valid_vddc_entries; i++) {
+ if (vddc <= pi->vddc_table[i].vddc) {
+ voltage->index = pi->vddc_table[i].vddc_index;
+ voltage->value = cpu_to_be16(vddc);
+ break;
+ }
+ }
+
+ if (i == pi->valid_vddc_entries)
+ return -EINVAL;
+
+ return 0;
+}
+
+int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
+ RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (!pi->mvdd_control) {
+ voltage->index = MVDD_HIGH_INDEX;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ return 0;
+ }
+
+ if (mclk <= pi->mvdd_split_frequency) {
+ voltage->index = MVDD_LOW_INDEX;
+ voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+ } else {
+ voltage->index = MVDD_HIGH_INDEX;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ }
+
+ return 0;
+}
+
+static int rv770_convert_power_level_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ RV770_SMC_HW_PERFORMANCE_LEVEL *level,
+ u8 watermark_level)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int ret;
+
+ level->gen2PCIE = pi->pcie_gen2 ?
+ ((pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0) : 0;
+ level->gen2XSP = (pl->flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2) ? 1 : 0;
+ level->backbias = (pl->flags & ATOM_PPLIB_R600_FLAGS_BACKBIASENABLE) ? 1 : 0;
+ level->displayWatermark = watermark_level;
+
+ if (rdev->family == CHIP_RV740)
+ ret = rv740_populate_sclk_value(rdev, pl->sclk,
+ &level->sclk);
+ else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ ret = rv730_populate_sclk_value(rdev, pl->sclk,
+ &level->sclk);
+ else
+ ret = rv770_populate_sclk_value(rdev, pl->sclk,
+ &level->sclk);
+ if (ret)
+ return ret;
+
+ if (rdev->family == CHIP_RV740) {
+ if (pi->mem_gddr5) {
+ if (pl->mclk <= pi->mclk_strobe_mode_threshold)
+ level->strobeMode =
+ rv740_get_mclk_frequency_ratio(pl->mclk) | 0x10;
+ else
+ level->strobeMode = 0;
+
+ if (pl->mclk > pi->mclk_edc_enable_threshold)
+ level->mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
+ else
+ level->mcFlags = 0;
+ }
+ ret = rv740_populate_mclk_value(rdev, pl->sclk,
+ pl->mclk, &level->mclk);
+ } else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ ret = rv730_populate_mclk_value(rdev, pl->sclk,
+ pl->mclk, &level->mclk);
+ else
+ ret = rv770_populate_mclk_value(rdev, pl->sclk,
+ pl->mclk, &level->mclk);
+ if (ret)
+ return ret;
+
+ ret = rv770_populate_vddc_value(rdev, pl->vddc,
+ &level->vddc);
+ if (ret)
+ return ret;
+
+ ret = rv770_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+ return ret;
+}
+
+static int rv770_convert_power_state_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+ int ret;
+
+ if (!(radeon_state->caps & ATOM_PPLIB_DISALLOW_ON_DC))
+ smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ ret = rv770_convert_power_level_to_smc(rdev,
+ &state->low,
+ &smc_state->levels[0],
+ PPSMC_DISPLAY_WATERMARK_LOW);
+ if (ret)
+ return ret;
+
+ ret = rv770_convert_power_level_to_smc(rdev,
+ &state->medium,
+ &smc_state->levels[1],
+ PPSMC_DISPLAY_WATERMARK_LOW);
+ if (ret)
+ return ret;
+
+ ret = rv770_convert_power_level_to_smc(rdev,
+ &state->high,
+ &smc_state->levels[2],
+ PPSMC_DISPLAY_WATERMARK_HIGH);
+ if (ret)
+ return ret;
+
+ smc_state->levels[0].arbValue = MC_CG_ARB_FREQ_F1;
+ smc_state->levels[1].arbValue = MC_CG_ARB_FREQ_F2;
+ smc_state->levels[2].arbValue = MC_CG_ARB_FREQ_F3;
+
+ smc_state->levels[0].seqValue = rv770_get_seq_value(rdev,
+ &state->low);
+ smc_state->levels[1].seqValue = rv770_get_seq_value(rdev,
+ &state->medium);
+ smc_state->levels[2].seqValue = rv770_get_seq_value(rdev,
+ &state->high);
+
+ rv770_populate_smc_sp(rdev, radeon_state, smc_state);
+
+ return rv770_populate_smc_t(rdev, radeon_state, smc_state);
+
+}
+
+u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev,
+ u32 engine_clock)
+{
+ u32 dram_rows;
+ u32 dram_refresh_rate;
+ u32 mc_arb_rfsh_rate;
+ u32 tmp;
+
+ tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+ dram_rows = 1 << (tmp + 10);
+ tmp = RREG32(MC_SEQ_MISC0) & 3;
+ dram_refresh_rate = 1 << (tmp + 3);
+ mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
+
+ return mc_arb_rfsh_rate;
+}
+
+static void rv770_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct rv7xx_ps *state = rv770_get_ps(radeon_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 sqm_ratio;
+ u32 arb_refresh_rate;
+ u32 high_clock;
+
+ if (state->high.sclk < (state->low.sclk * 0xFF / 0x40))
+ high_clock = state->high.sclk;
+ else
+ high_clock = (state->low.sclk * 0xFF / 0x40);
+
+ radeon_atom_set_engine_dram_timings(rdev, high_clock,
+ state->high.mclk);
+
+ sqm_ratio =
+ STATE0(64 * high_clock / pi->boot_sclk) |
+ STATE1(64 * high_clock / state->low.sclk) |
+ STATE2(64 * high_clock / state->medium.sclk) |
+ STATE3(64 * high_clock / state->high.sclk);
+ WREG32(MC_ARB_SQM_RATIO, sqm_ratio);
+
+ arb_refresh_rate =
+ POWERMODE0(rv770_calculate_memory_refresh_rate(rdev, pi->boot_sclk)) |
+ POWERMODE1(rv770_calculate_memory_refresh_rate(rdev, state->low.sclk)) |
+ POWERMODE2(rv770_calculate_memory_refresh_rate(rdev, state->medium.sclk)) |
+ POWERMODE3(rv770_calculate_memory_refresh_rate(rdev, state->high.sclk));
+ WREG32(MC_ARB_RFSH_RATE, arb_refresh_rate);
+}
+
+void rv770_enable_backbias(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, BACKBIAS_PAD_EN, ~BACKBIAS_PAD_EN);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~(BACKBIAS_VALUE | BACKBIAS_PAD_EN));
+}
+
+static void rv770_enable_spread_spectrum(struct radeon_device *rdev,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (enable) {
+ if (pi->sclk_ss)
+ WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+
+ if (pi->mclk_ss) {
+ if (rdev->family == CHIP_RV740)
+ rv740_enable_mclk_spread_spectrum(rdev, true);
+ }
+ } else {
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+
+ WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+
+ WREG32_P(CG_MPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+
+ if (rdev->family == CHIP_RV740)
+ rv740_enable_mclk_spread_spectrum(rdev, false);
+ }
+}
+
+static void rv770_program_mpll_timing_parameters(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if ((rdev->family == CHIP_RV770) && !pi->mem_gddr5) {
+ WREG32(MPLL_TIME,
+ (MPLL_LOCK_TIME(R600_MPLLLOCKTIME_DFLT * pi->ref_div) |
+ MPLL_RESET_TIME(R600_MPLLRESETTIME_DFLT)));
+ }
+}
+
+void rv770_setup_bsp(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 xclk = radeon_get_xclk(rdev);
+
+ r600_calculate_u_and_p(pi->asi,
+ xclk,
+ 16,
+ &pi->bsp,
+ &pi->bsu);
+
+ r600_calculate_u_and_p(pi->pasi,
+ xclk,
+ 16,
+ &pi->pbsp,
+ &pi->pbsu);
+
+ pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
+ pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+
+ WREG32(CG_BSP, pi->dsp);
+
+}
+
+void rv770_program_git(struct radeon_device *rdev)
+{
+ WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
+}
+
+void rv770_program_tp(struct radeon_device *rdev)
+{
+ int i;
+ enum r600_td td = R600_TD_DFLT;
+
+ for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+ WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));
+
+ if (td == R600_TD_AUTO)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+ else
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+ if (td == R600_TD_UP)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+ if (td == R600_TD_DOWN)
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+void rv770_program_tpp(struct radeon_device *rdev)
+{
+ WREG32(CG_TPC, R600_TPC_DFLT);
+}
+
+void rv770_program_sstp(struct radeon_device *rdev)
+{
+ WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
+}
+
+void rv770_program_engine_speed_parameters(struct radeon_device *rdev)
+{
+ WREG32_P(SPLL_CNTL_MODE, SPLL_DIV_SYNC, ~SPLL_DIV_SYNC);
+}
+
+static void rv770_enable_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+ tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+ tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+ DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+void rv770_program_vc(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ WREG32(CG_FTV, pi->vrc);
+}
+
+void rv770_clear_vc(struct radeon_device *rdev)
+{
+ WREG32(CG_FTV, 0);
+}
+
+int rv770_upload_firmware(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int ret;
+
+ rv770_reset_smc(rdev);
+ rv770_stop_smc_clock(rdev);
+
+ ret = rv770_load_smc_ucode(rdev, pi->sram_end);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rv770_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ u32 mpll_ad_func_cntl =
+ pi->clk_regs.rv770.mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl =
+ pi->clk_regs.rv770.mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2 =
+ pi->clk_regs.rv770.mpll_dq_func_cntl_2;
+ u32 spll_func_cntl =
+ pi->clk_regs.rv770.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 =
+ pi->clk_regs.rv770.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 =
+ pi->clk_regs.rv770.cg_spll_func_cntl_3;
+ u32 mclk_pwrmgt_cntl;
+ u32 dll_cntl;
+
+ table->ACPIState = table->initialState;
+
+ table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc) {
+ rv770_populate_vddc_value(rdev, pi->acpi_vddc,
+ &table->ACPIState.levels[0].vddc);
+ if (pi->pcie_gen2) {
+ if (pi->acpi_pcie_gen2)
+ table->ACPIState.levels[0].gen2PCIE = 1;
+ else
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ } else
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ if (pi->acpi_pcie_gen2)
+ table->ACPIState.levels[0].gen2XSP = 1;
+ else
+ table->ACPIState.levels[0].gen2XSP = 0;
+ } else {
+ rv770_populate_vddc_value(rdev, pi->min_vddc_in_table,
+ &table->ACPIState.levels[0].vddc);
+ table->ACPIState.levels[0].gen2PCIE = 0;
+ }
+
+
+ mpll_ad_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+ mpll_dq_func_cntl_2 |= BIAS_GEN_PDNB | RESET_EN;
+
+ mclk_pwrmgt_cntl = (MRDCKA0_RESET |
+ MRDCKA1_RESET |
+ MRDCKB0_RESET |
+ MRDCKB1_RESET |
+ MRDCKC0_RESET |
+ MRDCKC1_RESET |
+ MRDCKD0_RESET |
+ MRDCKD1_RESET);
+
+ dll_cntl = 0xff000000;
+
+ spll_func_cntl |= SPLL_RESET | SPLL_SLEEP | SPLL_BYPASS_EN;
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 = cpu_to_be32(mpll_ad_func_cntl_2);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 = cpu_to_be32(mpll_dq_func_cntl_2);
+
+ table->ACPIState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ table->ACPIState.levels[0].mclk.mclk770.vDLL_CNTL = cpu_to_be32(dll_cntl);
+
+ table->ACPIState.levels[0].mclk.mclk770.mclk_value = 0;
+
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL = cpu_to_be32(spll_func_cntl);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(spll_func_cntl_2);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(spll_func_cntl_3);
+
+ table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+ rv770_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+ table->ACPIState.levels[1] = table->ACPIState.levels[0];
+ table->ACPIState.levels[2] = table->ACPIState.levels[0];
+
+ return 0;
+}
+
+int rv770_populate_initial_mvdd_value(struct radeon_device *rdev,
+ RV770_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if ((pi->s0_vid_lower_smio_cntl & pi->mvdd_mask_low) ==
+ (pi->mvdd_low_smio[MVDD_LOW_INDEX] & pi->mvdd_mask_low) ) {
+ voltage->index = MVDD_LOW_INDEX;
+ voltage->value = cpu_to_be16(MVDD_LOW_VALUE);
+ } else {
+ voltage->index = MVDD_HIGH_INDEX;
+ voltage->value = cpu_to_be16(MVDD_HIGH_VALUE);
+ }
+
+ return 0;
+}
+
+static int rv770_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_ps *initial_state = rv770_get_ps(radeon_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 a_t;
+
+ table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_AD_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ad_func_cntl_2);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_DQ_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_dq_func_cntl_2);
+ table->initialState.levels[0].mclk.mclk770.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.mclk_pwrmgt_cntl);
+ table->initialState.levels[0].mclk.mclk770.vDLL_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.dll_cntl);
+
+ table->initialState.levels[0].mclk.mclk770.vMPLL_SS =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ss1);
+ table->initialState.levels[0].mclk.mclk770.vMPLL_SS2 =
+ cpu_to_be32(pi->clk_regs.rv770.mpll_ss2);
+
+ table->initialState.levels[0].mclk.mclk770.mclk_value =
+ cpu_to_be32(initial_state->low.mclk);
+
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_2);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_func_cntl_3);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cpu_to_be32(pi->clk_regs.rv770.cg_spll_spread_spectrum_2);
+
+ table->initialState.levels[0].sclk.sclk_value =
+ cpu_to_be32(initial_state->low.sclk);
+
+ table->initialState.levels[0].arbValue = MC_CG_ARB_FREQ_F0;
+
+ table->initialState.levels[0].seqValue =
+ rv770_get_seq_value(rdev, &initial_state->low);
+
+ rv770_populate_vddc_value(rdev,
+ initial_state->low.vddc,
+ &table->initialState.levels[0].vddc);
+ rv770_populate_initial_mvdd_value(rdev,
+ &table->initialState.levels[0].mvdd);
+
+ a_t = CG_R(0xffff) | CG_L(0);
+ table->initialState.levels[0].aT = cpu_to_be32(a_t);
+
+ table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+ if (pi->boot_in_gen2)
+ table->initialState.levels[0].gen2PCIE = 1;
+ else
+ table->initialState.levels[0].gen2PCIE = 0;
+ if (initial_state->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+ table->initialState.levels[0].gen2XSP = 1;
+ else
+ table->initialState.levels[0].gen2XSP = 0;
+
+ if (rdev->family == CHIP_RV740) {
+ if (pi->mem_gddr5) {
+ if (initial_state->low.mclk <= pi->mclk_strobe_mode_threshold)
+ table->initialState.levels[0].strobeMode =
+ rv740_get_mclk_frequency_ratio(initial_state->low.mclk) | 0x10;
+ else
+ table->initialState.levels[0].strobeMode = 0;
+
+ if (initial_state->low.mclk >= pi->mclk_edc_enable_threshold)
+ table->initialState.levels[0].mcFlags = SMC_MC_EDC_RD_FLAG | SMC_MC_EDC_WR_FLAG;
+ else
+ table->initialState.levels[0].mcFlags = 0;
+ }
+ }
+
+ table->initialState.levels[1] = table->initialState.levels[0];
+ table->initialState.levels[2] = table->initialState.levels[0];
+
+ table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ return 0;
+}
+
+static int rv770_populate_smc_vddc_table(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+
+ for (i = 0; i < pi->valid_vddc_entries; i++) {
+ table->highSMIO[pi->vddc_table[i].vddc_index] =
+ pi->vddc_table[i].high_smio;
+ table->lowSMIO[pi->vddc_table[i].vddc_index] =
+ cpu_to_be32(pi->vddc_table[i].low_smio);
+ }
+
+ table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_VDDC] = 0;
+ table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_VDDC] =
+ cpu_to_be32(pi->vddc_mask_low);
+
+ for (i = 0;
+ ((i < pi->valid_vddc_entries) &&
+ (pi->max_vddc_in_table >
+ pi->vddc_table[i].vddc));
+ i++);
+
+ table->maxVDDCIndexInPPTable =
+ pi->vddc_table[i].vddc_index;
+
+ return 0;
+}
+
+static int rv770_populate_smc_mvdd_table(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (pi->mvdd_control) {
+ table->lowSMIO[MVDD_HIGH_INDEX] |=
+ cpu_to_be32(pi->mvdd_low_smio[MVDD_HIGH_INDEX]);
+ table->lowSMIO[MVDD_LOW_INDEX] |=
+ cpu_to_be32(pi->mvdd_low_smio[MVDD_LOW_INDEX]);
+
+ table->voltageMaskTable.highMask[RV770_SMC_VOLTAGEMASK_MVDD] = 0;
+ table->voltageMaskTable.lowMask[RV770_SMC_VOLTAGEMASK_MVDD] =
+ cpu_to_be32(pi->mvdd_mask_low);
+ }
+
+ return 0;
+}
+
+static int rv770_init_smc_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct rv7xx_ps *boot_state = rv770_get_ps(radeon_boot_state);
+ RV770_SMC_STATETABLE *table = &pi->smc_statetable;
+ int ret;
+
+ memset(table, 0, sizeof(RV770_SMC_STATETABLE));
+
+ pi->boot_sclk = boot_state->low.sclk;
+
+ rv770_populate_smc_vddc_table(rdev, table);
+ rv770_populate_smc_mvdd_table(rdev, table);
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_RV770:
+ case THERMAL_TYPE_ADT7473_WITH_INTERNAL:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+ break;
+ case THERMAL_TYPE_NONE:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+ break;
+ case THERMAL_TYPE_EXTERNAL_GPIO:
+ default:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+ break;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) {
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT)
+ table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_DONT_WAIT_FOR_VBLANK;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT)
+ table->extraFlags |= PPSMC_EXTRAFLAGS_AC2DC_ACTION_GOTOINITIALSTATE;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (pi->mem_gddr5)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ ret = rv730_populate_smc_initial_state(rdev, radeon_boot_state, table);
+ else
+ ret = rv770_populate_smc_initial_state(rdev, radeon_boot_state, table);
+ if (ret)
+ return ret;
+
+ if (rdev->family == CHIP_RV740)
+ ret = rv740_populate_smc_acpi_state(rdev, table);
+ else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ ret = rv730_populate_smc_acpi_state(rdev, table);
+ else
+ ret = rv770_populate_smc_acpi_state(rdev, table);
+ if (ret)
+ return ret;
+
+ table->driverState = table->initialState;
+
+ return rv770_copy_bytes_to_smc(rdev,
+ pi->state_table_start,
+ (const u8 *)table,
+ sizeof(RV770_SMC_STATETABLE),
+ pi->sram_end);
+}
+
+static int rv770_construct_vddc_table(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u16 min, max, step;
+ u32 steps = 0;
+ u8 vddc_index = 0;
+ u32 i;
+
+ radeon_atom_get_min_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &min);
+ radeon_atom_get_max_voltage(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &max);
+ radeon_atom_get_voltage_step(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, &step);
+
+ steps = (max - min) / step + 1;
+
+ if (steps > MAX_NO_VREG_STEPS)
+ return -EINVAL;
+
+ for (i = 0; i < steps; i++) {
+ u32 gpio_pins, gpio_mask;
+
+ pi->vddc_table[i].vddc = (u16)(min + i * step);
+ radeon_atom_get_voltage_gpio_settings(rdev,
+ pi->vddc_table[i].vddc,
+ SET_VOLTAGE_TYPE_ASIC_VDDC,
+ &gpio_pins, &gpio_mask);
+ pi->vddc_table[i].low_smio = gpio_pins & gpio_mask;
+ pi->vddc_table[i].high_smio = 0;
+ pi->vddc_mask_low = gpio_mask;
+ if (i > 0) {
+ if ((pi->vddc_table[i].low_smio !=
+ pi->vddc_table[i - 1].low_smio ) ||
+ (pi->vddc_table[i].high_smio !=
+ pi->vddc_table[i - 1].high_smio))
+ vddc_index++;
+ }
+ pi->vddc_table[i].vddc_index = vddc_index;
+ }
+
+ pi->valid_vddc_entries = (u8)steps;
+
+ return 0;
+}
+
+static u32 rv770_get_mclk_split_point(struct atom_memory_info *memory_info)
+{
+ if (memory_info->mem_type == MEM_TYPE_GDDR3)
+ return 30000;
+
+ return 0;
+}
+
+static int rv770_get_mvdd_pin_configuration(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 gpio_pins, gpio_mask;
+
+ radeon_atom_get_voltage_gpio_settings(rdev,
+ MVDD_HIGH_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC,
+ &gpio_pins, &gpio_mask);
+ pi->mvdd_mask_low = gpio_mask;
+ pi->mvdd_low_smio[MVDD_HIGH_INDEX] =
+ gpio_pins & gpio_mask;
+
+ radeon_atom_get_voltage_gpio_settings(rdev,
+ MVDD_LOW_VALUE, SET_VOLTAGE_TYPE_ASIC_MVDDC,
+ &gpio_pins, &gpio_mask);
+ pi->mvdd_low_smio[MVDD_LOW_INDEX] =
+ gpio_pins & gpio_mask;
+
+ return 0;
+}
+
+u8 rv770_get_memory_module_index(struct radeon_device *rdev)
+{
+ return (u8) ((RREG32(BIOS_SCRATCH_4) >> 16) & 0xff);
+}
+
+static int rv770_get_mvdd_configuration(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 memory_module_index;
+ struct atom_memory_info memory_info;
+
+ memory_module_index = rv770_get_memory_module_index(rdev);
+
+ if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info)) {
+ pi->mvdd_control = false;
+ return 0;
+ }
+
+ pi->mvdd_split_frequency =
+ rv770_get_mclk_split_point(&memory_info);
+
+ if (pi->mvdd_split_frequency == 0) {
+ pi->mvdd_control = false;
+ return 0;
+ }
+
+ return rv770_get_mvdd_pin_configuration(rdev);
+}
+
+void rv770_enable_voltage_control(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+}
+
+static void rv770_program_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+ tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+ if (rdev->pm.dpm.new_active_crtcs & 1) {
+ tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+ tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ } else if (rdev->pm.dpm.new_active_crtcs & 2) {
+ tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
+ } else {
+ tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
+ }
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void rv770_enable_dynamic_pcie_gen2(struct radeon_device *rdev,
+ bool enable)
+{
+ rv770_enable_bif_dynamic_pcie_gen2(rdev, enable);
+
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, ENABLE_GEN2PCIE, ~ENABLE_GEN2PCIE);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~ENABLE_GEN2PCIE);
+}
+
+static void r7xx_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ if ((rdev->family == CHIP_RV730) ||
+ (rdev->family == CHIP_RV710) ||
+ (rdev->family == CHIP_RV740))
+ rv730_program_memory_timing_parameters(rdev, radeon_new_state);
+ else
+ rv770_program_memory_timing_parameters(rdev, radeon_new_state);
+}
+
+static int rv770_upload_sw_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u16 address = pi->state_table_start +
+ offsetof(RV770_SMC_STATETABLE, driverState);
+ RV770_SMC_SWSTATE state = { 0 };
+ int ret;
+
+ ret = rv770_convert_power_state_to_smc(rdev, radeon_new_state, &state);
+ if (ret)
+ return ret;
+
+ return rv770_copy_bytes_to_smc(rdev, address, (const u8 *)&state,
+ sizeof(RV770_SMC_SWSTATE),
+ pi->sram_end);
+}
+
+int rv770_halt_smc(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ if (rv770_wait_for_smc_inactive(rdev) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+int rv770_resume_smc(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_Resume) != PPSMC_Result_OK)
+ return -EINVAL;
+ return 0;
+}
+
+int rv770_set_sw_state(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK)
+ return -EINVAL;
+ return 0;
+}
+
+int rv770_set_boot_state(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) != PPSMC_Result_OK)
+ return -EINVAL;
+ return 0;
+}
+
+void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv7xx_ps *new_state = rv770_get_ps(new_ps);
+ struct rv7xx_ps *current_state = rv770_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->high.sclk >= current_state->high.sclk)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps)
+{
+ struct rv7xx_ps *new_state = rv770_get_ps(new_ps);
+ struct rv7xx_ps *current_state = rv770_get_ps(old_ps);
+
+ if ((new_ps->vclk == old_ps->vclk) &&
+ (new_ps->dclk == old_ps->dclk))
+ return;
+
+ if (new_state->high.sclk < current_state->high.sclk)
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_ps->vclk, new_ps->dclk);
+}
+
+int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev)
+{
+ if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_NoForcedLevel)) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ if (rv770_send_msg_to_smc(rdev, (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled)) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return 0;
+}
+
+int rv770_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ PPSMC_Msg msg;
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_ZeroLevelsDisabled) != PPSMC_Result_OK)
+ return -EINVAL;
+ msg = PPSMC_MSG_ForceHigh;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+ return -EINVAL;
+ msg = (PPSMC_Msg)(PPSMC_MSG_TwoLevelsDisabled);
+ } else {
+ if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+ return -EINVAL;
+ msg = (PPSMC_Msg)(PPSMC_MSG_ZeroLevelsDisabled);
+ }
+
+ if (rv770_send_msg_to_smc(rdev, msg) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}
+
+void r7xx_start_smc(struct radeon_device *rdev)
+{
+ rv770_start_smc(rdev);
+ rv770_start_smc_clock(rdev);
+}
+
+
+void r7xx_stop_smc(struct radeon_device *rdev)
+{
+ rv770_reset_smc(rdev);
+ rv770_stop_smc_clock(rdev);
+}
+
+static void rv770_read_clock_registers(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ pi->clk_regs.rv770.cg_spll_func_cntl =
+ RREG32(CG_SPLL_FUNC_CNTL);
+ pi->clk_regs.rv770.cg_spll_func_cntl_2 =
+ RREG32(CG_SPLL_FUNC_CNTL_2);
+ pi->clk_regs.rv770.cg_spll_func_cntl_3 =
+ RREG32(CG_SPLL_FUNC_CNTL_3);
+ pi->clk_regs.rv770.cg_spll_spread_spectrum =
+ RREG32(CG_SPLL_SPREAD_SPECTRUM);
+ pi->clk_regs.rv770.cg_spll_spread_spectrum_2 =
+ RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+ pi->clk_regs.rv770.mpll_ad_func_cntl =
+ RREG32(MPLL_AD_FUNC_CNTL);
+ pi->clk_regs.rv770.mpll_ad_func_cntl_2 =
+ RREG32(MPLL_AD_FUNC_CNTL_2);
+ pi->clk_regs.rv770.mpll_dq_func_cntl =
+ RREG32(MPLL_DQ_FUNC_CNTL);
+ pi->clk_regs.rv770.mpll_dq_func_cntl_2 =
+ RREG32(MPLL_DQ_FUNC_CNTL_2);
+ pi->clk_regs.rv770.mclk_pwrmgt_cntl =
+ RREG32(MCLK_PWRMGT_CNTL);
+ pi->clk_regs.rv770.dll_cntl = RREG32(DLL_CNTL);
+}
+
+static void r7xx_read_clock_registers(struct radeon_device *rdev)
+{
+ if (rdev->family == CHIP_RV740)
+ rv740_read_clock_registers(rdev);
+ else if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ rv730_read_clock_registers(rdev);
+ else
+ rv770_read_clock_registers(rdev);
+}
+
+void rv770_read_voltage_smio_registers(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ pi->s0_vid_lower_smio_cntl =
+ RREG32(S0_VID_LOWER_SMIO_CNTL);
+}
+
+void rv770_reset_smio_status(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 sw_smio_index, vid_smio_cntl;
+
+ sw_smio_index =
+ (RREG32(GENERAL_PWRMGT) & SW_SMIO_INDEX_MASK) >> SW_SMIO_INDEX_SHIFT;
+ switch (sw_smio_index) {
+ case 3:
+ vid_smio_cntl = RREG32(S3_VID_LOWER_SMIO_CNTL);
+ break;
+ case 2:
+ vid_smio_cntl = RREG32(S2_VID_LOWER_SMIO_CNTL);
+ break;
+ case 1:
+ vid_smio_cntl = RREG32(S1_VID_LOWER_SMIO_CNTL);
+ break;
+ case 0:
+ return;
+ default:
+ vid_smio_cntl = pi->s0_vid_lower_smio_cntl;
+ break;
+ }
+
+ WREG32(S0_VID_LOWER_SMIO_CNTL, vid_smio_cntl);
+ WREG32_P(GENERAL_PWRMGT, SW_SMIO_INDEX(0), ~SW_SMIO_INDEX_MASK);
+}
+
+void rv770_get_memory_type(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp;
+
+ tmp = RREG32(MC_SEQ_MISC0);
+
+ if (((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT) ==
+ MC_SEQ_MISC0_GDDR5_VALUE)
+ pi->mem_gddr5 = true;
+ else
+ pi->mem_gddr5 = false;
+
+}
+
+void rv770_get_pcie_gen2_status(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 tmp;
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+
+ if ((tmp & LC_OTHER_SIDE_EVER_SENT_GEN2) &&
+ (tmp & LC_OTHER_SIDE_SUPPORTS_GEN2))
+ pi->pcie_gen2 = true;
+ else
+ pi->pcie_gen2 = false;
+
+ if (pi->pcie_gen2) {
+ if (tmp & LC_CURRENT_DATA_RATE)
+ pi->boot_in_gen2 = true;
+ else
+ pi->boot_in_gen2 = false;
+ } else
+ pi->boot_in_gen2 = false;
+}
+
+#if 0
+static int rv770_enter_ulp_state(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (pi->gfx_clock_gating) {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+ RREG32(GB_TILING_CONFIG);
+ }
+
+ WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_SwitchToMinimumPower),
+ ~HOST_SMC_MSG_MASK);
+
+ udelay(7000);
+
+ return 0;
+}
+
+static int rv770_exit_ulp_state(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+
+ WREG32_P(SMC_MSG, HOST_SMC_MSG(PPSMC_MSG_ResumeFromMinimumPower),
+ ~HOST_SMC_MSG_MASK);
+
+ udelay(7000);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (((RREG32(SMC_MSG) & HOST_SMC_RESP_MASK) >> HOST_SMC_RESP_SHIFT) == 1)
+ break;
+ udelay(1000);
+ }
+
+ if (pi->gfx_clock_gating)
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+
+ return 0;
+}
+#endif
+
+static void rv770_get_mclk_odt_threshold(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 memory_module_index;
+ struct atom_memory_info memory_info;
+
+ pi->mclk_odt_threshold = 0;
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710)) {
+ memory_module_index = rv770_get_memory_module_index(rdev);
+
+ if (radeon_atom_get_memory_info(rdev, memory_module_index, &memory_info))
+ return;
+
+ if (memory_info.mem_type == MEM_TYPE_DDR2 ||
+ memory_info.mem_type == MEM_TYPE_DDR3)
+ pi->mclk_odt_threshold = 30000;
+ }
+}
+
+void rv770_get_max_vddc(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u16 vddc;
+
+ if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc))
+ pi->max_vddc = 0;
+ else
+ pi->max_vddc = vddc;
+}
+
+void rv770_program_response_times(struct radeon_device *rdev)
+{
+ u32 voltage_response_time, backbias_response_time;
+ u32 acpi_delay_time, vbi_time_out;
+ u32 vddc_dly, bb_dly, acpi_dly, vbi_dly;
+ u32 reference_clock;
+
+ voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
+ backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
+
+ if (voltage_response_time == 0)
+ voltage_response_time = 1000;
+
+ if (backbias_response_time == 0)
+ backbias_response_time = 1000;
+
+ acpi_delay_time = 15000;
+ vbi_time_out = 100000;
+
+ reference_clock = radeon_get_xclk(rdev);
+
+ vddc_dly = (voltage_response_time * reference_clock) / 1600;
+ bb_dly = (backbias_response_time * reference_clock) / 1600;
+ acpi_dly = (acpi_delay_time * reference_clock) / 1600;
+ vbi_dly = (vbi_time_out * reference_clock) / 1600;
+
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_delay_vreg, vddc_dly);
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_delay_bbias, bb_dly);
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_delay_acpi, acpi_dly);
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
+#if 0
+ /* XXX look up hw revision */
+ if (WEKIVA_A21)
+ rv770_write_smc_soft_register(rdev,
+ RV770_SMC_SOFT_REGISTER_baby_step_timer,
+ 0x10);
+#endif
+}
+
+static void rv770_program_dcodt_before_state_switch(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
+ struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
+ bool current_use_dc = false;
+ bool new_use_dc = false;
+
+ if (pi->mclk_odt_threshold == 0)
+ return;
+
+ if (current_state->high.mclk <= pi->mclk_odt_threshold)
+ current_use_dc = true;
+
+ if (new_state->high.mclk <= pi->mclk_odt_threshold)
+ new_use_dc = true;
+
+ if (current_use_dc == new_use_dc)
+ return;
+
+ if (!current_use_dc && new_use_dc)
+ return;
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ rv730_program_dcodt(rdev, new_use_dc);
+}
+
+static void rv770_program_dcodt_after_state_switch(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct rv7xx_ps *new_state = rv770_get_ps(radeon_new_state);
+ struct rv7xx_ps *current_state = rv770_get_ps(radeon_current_state);
+ bool current_use_dc = false;
+ bool new_use_dc = false;
+
+ if (pi->mclk_odt_threshold == 0)
+ return;
+
+ if (current_state->high.mclk <= pi->mclk_odt_threshold)
+ current_use_dc = true;
+
+ if (new_state->high.mclk <= pi->mclk_odt_threshold)
+ new_use_dc = true;
+
+ if (current_use_dc == new_use_dc)
+ return;
+
+ if (current_use_dc && !new_use_dc)
+ return;
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ rv730_program_dcodt(rdev, new_use_dc);
+}
+
+static void rv770_retrieve_odt_values(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (pi->mclk_odt_threshold == 0)
+ return;
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ rv730_get_odt_values(rdev);
+}
+
+static void rv770_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ bool want_thermal_protection;
+ enum radeon_dpm_event_src dpm_event_src;
+
+ switch (sources) {
+ case 0:
+ default:
+ want_thermal_protection = false;
+ break;
+ case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
+ break;
+
+ case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
+ break;
+
+ case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+ (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+ break;
+ }
+
+ if (want_thermal_protection) {
+ WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+ if (pi->thermal_protection)
+ WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ } else {
+ WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+ }
+}
+
+void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
+ enum radeon_dpm_auto_throttle_src source,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (enable) {
+ if (!(pi->active_auto_throttle_sources & (1 << source))) {
+ pi->active_auto_throttle_sources |= 1 << source;
+ rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+ }
+ } else {
+ if (pi->active_auto_throttle_sources & (1 << source)) {
+ pi->active_auto_throttle_sources &= ~(1 << source);
+ rv770_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+ }
+ }
+}
+
+int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp)
+{
+ int low_temp = 0 * 1000;
+ int high_temp = 255 * 1000;
+
+ 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;
+ }
+
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
+ WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+
+ rdev->pm.dpm.thermal.min_temp = low_temp;
+ rdev->pm.dpm.thermal.max_temp = high_temp;
+
+ return 0;
+}
+
+int rv770_dpm_enable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ if (pi->gfx_clock_gating)
+ rv770_restore_cgcg(rdev);
+
+ if (rv770_dpm_enabled(rdev))
+ return -EINVAL;
+
+ if (pi->voltage_control) {
+ rv770_enable_voltage_control(rdev, true);
+ ret = rv770_construct_vddc_table(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_construct_vddc_table failed\n");
+ return ret;
+ }
+ }
+
+ if (pi->dcodt)
+ rv770_retrieve_odt_values(rdev);
+
+ if (pi->mvdd_control) {
+ ret = rv770_get_mvdd_configuration(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_get_mvdd_configuration failed\n");
+ return ret;
+ }
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS)
+ rv770_enable_backbias(rdev, true);
+
+ rv770_enable_spread_spectrum(rdev, true);
+
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, true);
+
+ rv770_program_mpll_timing_parameters(rdev);
+ rv770_setup_bsp(rdev);
+ rv770_program_git(rdev);
+ rv770_program_tp(rdev);
+ rv770_program_tpp(rdev);
+ rv770_program_sstp(rdev);
+ rv770_program_engine_speed_parameters(rdev);
+ rv770_enable_display_gap(rdev);
+ rv770_program_vc(rdev);
+
+ if (pi->dynamic_pcie_gen2)
+ rv770_enable_dynamic_pcie_gen2(rdev, true);
+
+ ret = rv770_upload_firmware(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_upload_firmware failed\n");
+ return ret;
+ }
+ ret = rv770_init_smc_table(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("rv770_init_smc_table failed\n");
+ return ret;
+ }
+
+ rv770_program_response_times(rdev);
+ r7xx_start_smc(rdev);
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ rv730_start_dpm(rdev);
+ else
+ rv770_start_dpm(rdev);
+
+ if (pi->gfx_clock_gating)
+ rv770_gfx_clock_gating_enable(rdev, true);
+
+ if (pi->mg_clock_gating)
+ rv770_mg_clock_gating_enable(rdev, true);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ PPSMC_Result result;
+
+ ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+ if (result != PPSMC_Result_OK)
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+ }
+
+ rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ return 0;
+}
+
+void rv770_dpm_disable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (!rv770_dpm_enabled(rdev))
+ return;
+
+ rv770_clear_vc(rdev);
+
+ if (pi->thermal_protection)
+ rv770_enable_thermal_protection(rdev, false);
+
+ rv770_enable_spread_spectrum(rdev, false);
+
+ if (pi->dynamic_pcie_gen2)
+ rv770_enable_dynamic_pcie_gen2(rdev, false);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ if (pi->gfx_clock_gating)
+ rv770_gfx_clock_gating_enable(rdev, false);
+
+ if (pi->mg_clock_gating)
+ rv770_mg_clock_gating_enable(rdev, false);
+
+ if ((rdev->family == CHIP_RV730) || (rdev->family == CHIP_RV710))
+ rv730_stop_dpm(rdev);
+ else
+ rv770_stop_dpm(rdev);
+
+ r7xx_stop_smc(rdev);
+ rv770_reset_smio_status(rdev);
+}
+
+int rv770_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+ struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
+ int ret;
+
+ ret = rv770_restrict_performance_levels_before_switch(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_restrict_performance_levels_before_switch failed\n");
+ return ret;
+ }
+ rv770_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ ret = rv770_halt_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_halt_smc failed\n");
+ return ret;
+ }
+ ret = rv770_upload_sw_state(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("rv770_upload_sw_state failed\n");
+ return ret;
+ }
+ r7xx_program_memory_timing_parameters(rdev, new_ps);
+ if (pi->dcodt)
+ rv770_program_dcodt_before_state_switch(rdev, new_ps, old_ps);
+ ret = rv770_resume_smc(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_resume_smc failed\n");
+ return ret;
+ }
+ ret = rv770_set_sw_state(rdev);
+ if (ret) {
+ DRM_ERROR("rv770_set_sw_state failed\n");
+ return ret;
+ }
+ if (pi->dcodt)
+ rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps);
+ rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+
+ ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
+ if (ret) {
+ DRM_ERROR("rv770_dpm_force_performance_level failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void rv770_dpm_reset_asic(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+
+ rv770_restrict_performance_levels_before_switch(rdev);
+ if (pi->dcodt)
+ rv770_program_dcodt_before_state_switch(rdev, boot_ps, boot_ps);
+ rv770_set_boot_state(rdev);
+ if (pi->dcodt)
+ rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps);
+}
+
+void rv770_dpm_setup_asic(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ r7xx_read_clock_registers(rdev);
+ rv770_read_voltage_smio_registers(rdev);
+ rv770_get_memory_type(rdev);
+ if (pi->dcodt)
+ rv770_get_mclk_odt_threshold(rdev);
+ rv770_get_pcie_gen2_status(rdev);
+
+ rv770_enable_acpi_pm(rdev);
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s)
+ rv770_enable_l0s(rdev);
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1)
+ rv770_enable_l1(rdev);
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1)
+ rv770_enable_pll_sleep_in_l1(rdev);
+}
+
+void rv770_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+ rv770_program_display_gap(rdev);
+}
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void rv7xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_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 if (r600_is_uvd_state(rps->class, rps->class2)) {
+ rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+ rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ rdev->pm.dpm.boot_ps = rps;
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct rv7xx_ps *ps = rv770_get_ps(rps);
+ u32 sclk, mclk;
+ u16 vddc;
+ struct rv7xx_pl *pl;
+
+ switch (index) {
+ case 0:
+ pl = &ps->low;
+ break;
+ case 1:
+ pl = &ps->medium;
+ break;
+ case 2:
+ default:
+ pl = &ps->high;
+ break;
+ }
+
+ if (rdev->family >= CHIP_CEDAR) {
+ sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow);
+ sclk |= clock_info->evergreen.ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow);
+ mclk |= clock_info->evergreen.ucMemoryClockHigh << 16;
+
+ pl->vddc = le16_to_cpu(clock_info->evergreen.usVDDC);
+ pl->vddci = le16_to_cpu(clock_info->evergreen.usVDDCI);
+ pl->flags = le32_to_cpu(clock_info->evergreen.ulFlags);
+ } else {
+ sclk = le16_to_cpu(clock_info->r600.usEngineClockLow);
+ sclk |= clock_info->r600.ucEngineClockHigh << 16;
+ mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow);
+ mclk |= clock_info->r600.ucMemoryClockHigh << 16;
+
+ pl->vddc = le16_to_cpu(clock_info->r600.usVDDC);
+ pl->flags = le32_to_cpu(clock_info->r600.ulFlags);
+ }
+
+ pl->mclk = mclk;
+ pl->sclk = sclk;
+
+ /* patch up vddc if necessary */
+ if (pl->vddc == 0xff01) {
+ if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0)
+ pl->vddc = vddc;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+ pi->acpi_vddc = pl->vddc;
+ if (rdev->family >= CHIP_CEDAR)
+ eg_pi->acpi_vddci = pl->vddci;
+ if (ps->low.flags & ATOM_PPLIB_R600_FLAGS_PCIEGEN2)
+ pi->acpi_pcie_gen2 = true;
+ else
+ pi->acpi_pcie_gen2 = false;
+ }
+
+ if (rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) {
+ if (rdev->family >= CHIP_BARTS) {
+ eg_pi->ulv.supported = true;
+ eg_pi->ulv.pl = pl;
+ }
+ }
+
+ if (pi->min_vddc_in_table > pl->vddc)
+ pi->min_vddc_in_table = pl->vddc;
+
+ if (pi->max_vddc_in_table < pl->vddc)
+ pi->max_vddc_in_table = pl->vddc;
+
+ /* patch up boot state */
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ u16 vddc, vddci, mvdd;
+ radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
+ pl->mclk = rdev->clock.default_mclk;
+ pl->sclk = rdev->clock.default_sclk;
+ pl->vddc = vddc;
+ pl->vddci = vddci;
+ }
+
+ if (rdev->family >= CHIP_BARTS) {
+ if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+ ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+ }
+ }
+}
+
+int rv7xx_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info;
+ union pplib_power_state *power_state;
+ int i, j;
+ union pplib_clock_info *clock_info;
+ union power_info *power_info;
+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+ u16 data_offset;
+ u8 frev, crev;
+ struct rv7xx_ps *ps;
+
+ if (!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);
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ power_info->pplib.ucNumStates, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+ for (i = 0; i < power_info->pplib.ucNumStates; i++) {
+ power_state = (union pplib_power_state *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usStateArrayOffset) +
+ i * power_info->pplib.ucStateEntrySize);
+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) +
+ (power_state->v1.ucNonClockStateIndex *
+ power_info->pplib.ucNonClockSize));
+ if (power_info->pplib.ucStateEntrySize - 1) {
+ ps = kzalloc(sizeof(struct rv7xx_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.ps[i].ps_priv = ps;
+ rv7xx_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info,
+ power_info->pplib.ucNonClockSize);
+ for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) {
+ clock_info = (union pplib_clock_info *)
+ (mode_info->atom_context->bios + data_offset +
+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) +
+ (power_state->v1.ucClockStateIndices[j] *
+ power_info->pplib.ucClockInfoSize));
+ rv7xx_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i], j,
+ clock_info);
+ }
+ }
+ }
+ rdev->pm.dpm.num_ps = power_info->pplib.ucNumStates;
+ return 0;
+}
+
+int rv770_dpm_init(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ uint16_t data_offset, size;
+ uint8_t frev, crev;
+ struct atom_clock_dividers dividers;
+ int ret;
+
+ pi = kzalloc(sizeof(struct rv7xx_power_info), GFP_KERNEL);
+ if (pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = pi;
+
+ rv770_get_max_vddc(rdev);
+
+ pi->acpi_vddc = 0;
+ pi->min_vddc_in_table = 0;
+ pi->max_vddc_in_table = 0;
+
+ ret = rv7xx_parse_power_table(rdev);
+ if (ret)
+ return ret;
+
+ if (rdev->pm.dpm.voltage_response_time == 0)
+ rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+ if (rdev->pm.dpm.backbias_response_time == 0)
+ rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->ref_div = dividers.ref_div + 1;
+ else
+ pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ pi->mclk_strobe_mode_threshold = 30000;
+ pi->mclk_edc_enable_threshold = 30000;
+
+ pi->rlp = RV770_RLP_DFLT;
+ pi->rmp = RV770_RMP_DFLT;
+ pi->lhp = RV770_LHP_DFLT;
+ pi->lmp = RV770_LMP_DFLT;
+
+ pi->voltage_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, 0);
+
+ pi->mvdd_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->sclk_ss = true;
+ pi->mclk_ss = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->sclk_ss = false;
+ pi->mclk_ss = false;
+ pi->dynamic_ss = false;
+ }
+
+ pi->asi = RV770_ASI_DFLT;
+ pi->pasi = RV770_HASI_DFLT;
+ pi->vrc = RV770_VRC_DFLT;
+
+ pi->power_gating = false;
+
+ pi->gfx_clock_gating = true;
+
+ pi->mg_clock_gating = true;
+ pi->mgcgtssm = true;
+
+ pi->dynamic_pcie_gen2 = true;
+
+ if (pi->gfx_clock_gating &&
+ (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ pi->display_gap = true;
+
+ if (rdev->flags & RADEON_IS_MOBILITY)
+ pi->dcodt = true;
+ else
+ pi->dcodt = false;
+
+ pi->ulps = true;
+
+ pi->mclk_stutter_mode_threshold = 0;
+
+ pi->sram_end = SMC_RAM_END;
+ pi->state_table_start = RV770_SMC_TABLE_ADDRESS;
+ pi->soft_regs_start = RV770_SMC_SOFT_REGISTERS_START;
+
+ return 0;
+}
+
+void rv770_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct rv7xx_ps *ps = rv770_get_ps(rps);
+ struct rv7xx_pl *pl;
+
+ r600_dpm_print_class_info(rps->class, rps->class2);
+ r600_dpm_print_cap_info(rps->caps);
+ printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ if (rdev->family >= CHIP_CEDAR) {
+ pl = &ps->low;
+ printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ pl = &ps->medium;
+ printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ pl = &ps->high;
+ printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ } else {
+ pl = &ps->low;
+ printk("\t\tpower level 0 sclk: %u mclk: %u vddc: %u\n",
+ pl->sclk, pl->mclk, pl->vddc);
+ pl = &ps->medium;
+ printk("\t\tpower level 1 sclk: %u mclk: %u vddc: %u\n",
+ pl->sclk, pl->mclk, pl->vddc);
+ pl = &ps->high;
+ printk("\t\tpower level 2 sclk: %u mclk: %u vddc: %u\n",
+ pl->sclk, pl->mclk, pl->vddc);
+ }
+ r600_dpm_print_ps_status(rdev, rps);
+}
+
+void rv770_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct rv7xx_ps *ps = rv770_get_ps(rps);
+ struct rv7xx_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >>
+ CURRENT_PROFILE_INDEX_SHIFT;
+
+ if (current_index > 2) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ if (current_index == 0)
+ pl = &ps->low;
+ else if (current_index == 1)
+ pl = &ps->medium;
+ else /* current_index == 2 */
+ pl = &ps->high;
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ if (rdev->family >= CHIP_CEDAR) {
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci);
+ } else {
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc);
+ }
+ }
+}
+
+void rv770_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+}
+
+u32 rv770_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
+
+ if (low)
+ return requested_state->low.sclk;
+ else
+ return requested_state->high.sclk;
+}
+
+u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct rv7xx_ps *requested_state = rv770_get_ps(rdev->pm.dpm.requested_ps);
+
+ if (low)
+ return requested_state->low.mclk;
+ else
+ return requested_state->high.mclk;
+}
+
+bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
+{
+ u32 vblank_time = r600_dpm_get_vblank_time(rdev);
+
+ if (vblank_time < 300)
+ return true;
+ else
+ return false;
+
+}
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
new file mode 100644
index 000000000000..96b1b2a62a8a
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -0,0 +1,289 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __RV770_DPM_H__
+#define __RV770_DPM_H__
+
+#include "rv770_smc.h"
+
+struct rv770_clock_registers {
+ u32 cg_spll_func_cntl;
+ u32 cg_spll_func_cntl_2;
+ u32 cg_spll_func_cntl_3;
+ u32 cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2;
+ u32 mpll_ad_func_cntl;
+ u32 mpll_ad_func_cntl_2;
+ u32 mpll_dq_func_cntl;
+ u32 mpll_dq_func_cntl_2;
+ u32 mclk_pwrmgt_cntl;
+ u32 dll_cntl;
+ u32 mpll_ss1;
+ u32 mpll_ss2;
+};
+
+struct rv730_clock_registers {
+ u32 cg_spll_func_cntl;
+ u32 cg_spll_func_cntl_2;
+ u32 cg_spll_func_cntl_3;
+ u32 cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2;
+ u32 mclk_pwrmgt_cntl;
+ u32 dll_cntl;
+ u32 mpll_func_cntl;
+ u32 mpll_func_cntl2;
+ u32 mpll_func_cntl3;
+ u32 mpll_ss;
+ u32 mpll_ss2;
+};
+
+union r7xx_clock_registers {
+ struct rv770_clock_registers rv770;
+ struct rv730_clock_registers rv730;
+};
+
+struct vddc_table_entry {
+ u16 vddc;
+ u8 vddc_index;
+ u8 high_smio;
+ u32 low_smio;
+};
+
+#define MAX_NO_OF_MVDD_VALUES 2
+#define MAX_NO_VREG_STEPS 32
+
+struct rv7xx_power_info {
+ /* flags */
+ bool mem_gddr5;
+ bool pcie_gen2;
+ bool dynamic_pcie_gen2;
+ bool acpi_pcie_gen2;
+ bool boot_in_gen2;
+ bool voltage_control; /* vddc */
+ bool mvdd_control;
+ bool sclk_ss;
+ bool mclk_ss;
+ bool dynamic_ss;
+ bool gfx_clock_gating;
+ bool mg_clock_gating;
+ bool mgcgtssm;
+ bool power_gating;
+ bool thermal_protection;
+ bool display_gap;
+ bool dcodt;
+ bool ulps;
+ /* registers */
+ union r7xx_clock_registers clk_regs;
+ u32 s0_vid_lower_smio_cntl;
+ /* voltage */
+ u32 vddc_mask_low;
+ u32 mvdd_mask_low;
+ u32 mvdd_split_frequency;
+ u32 mvdd_low_smio[MAX_NO_OF_MVDD_VALUES];
+ u16 max_vddc;
+ u16 max_vddc_in_table;
+ u16 min_vddc_in_table;
+ struct vddc_table_entry vddc_table[MAX_NO_VREG_STEPS];
+ u8 valid_vddc_entries;
+ /* dc odt */
+ u32 mclk_odt_threshold;
+ u8 odt_value_0[2];
+ u8 odt_value_1[2];
+ /* stored values */
+ u32 boot_sclk;
+ u16 acpi_vddc;
+ u32 ref_div;
+ u32 active_auto_throttle_sources;
+ u32 mclk_stutter_mode_threshold;
+ u32 mclk_strobe_mode_threshold;
+ u32 mclk_edc_enable_threshold;
+ u32 bsp;
+ u32 bsu;
+ u32 pbsp;
+ u32 pbsu;
+ u32 dsp;
+ u32 psp;
+ u32 asi;
+ u32 pasi;
+ u32 vrc;
+ u32 restricted_levels;
+ u32 rlp;
+ u32 rmp;
+ u32 lhp;
+ u32 lmp;
+ /* smc offsets */
+ u16 state_table_start;
+ u16 soft_regs_start;
+ u16 sram_end;
+ /* scratch structs */
+ RV770_SMC_STATETABLE smc_statetable;
+};
+
+struct rv7xx_pl {
+ u32 sclk;
+ u32 mclk;
+ u16 vddc;
+ u16 vddci; /* eg+ only */
+ u32 flags;
+ enum radeon_pcie_gen pcie_gen; /* si+ only */
+};
+
+struct rv7xx_ps {
+ struct rv7xx_pl high;
+ struct rv7xx_pl medium;
+ struct rv7xx_pl low;
+ bool dc_compatible;
+};
+
+#define RV770_RLP_DFLT 10
+#define RV770_RMP_DFLT 25
+#define RV770_LHP_DFLT 25
+#define RV770_LMP_DFLT 10
+#define RV770_VRC_DFLT 0x003f
+#define RV770_ASI_DFLT 1000
+#define RV770_HASI_DFLT 200000
+#define RV770_MGCGTTLOCAL0_DFLT 0x00100000
+#define RV7XX_MGCGTTLOCAL0_DFLT 0
+#define RV770_MGCGTTLOCAL1_DFLT 0xFFFF0000
+#define RV770_MGCGCGTSSMCTRL_DFLT 0x55940000
+
+#define MVDD_LOW_INDEX 0
+#define MVDD_HIGH_INDEX 1
+
+#define MVDD_LOW_VALUE 0
+#define MVDD_HIGH_VALUE 0xffff
+
+#define RV770_DEFAULT_VCLK_FREQ 53300 /* 10 khz */
+#define RV770_DEFAULT_DCLK_FREQ 40000 /* 10 khz */
+
+/* rv730/rv710 */
+int rv730_populate_sclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ RV770_SMC_SCLK_VALUE *sclk);
+int rv730_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock,
+ LPRV7XX_SMC_MCLK_VALUE mclk);
+void rv730_read_clock_registers(struct radeon_device *rdev);
+int rv730_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table);
+int rv730_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_initial_state,
+ RV770_SMC_STATETABLE *table);
+void rv730_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state);
+void rv730_power_gating_enable(struct radeon_device *rdev,
+ bool enable);
+void rv730_start_dpm(struct radeon_device *rdev);
+void rv730_stop_dpm(struct radeon_device *rdev);
+void rv730_program_dcodt(struct radeon_device *rdev, bool use_dcodt);
+void rv730_get_odt_values(struct radeon_device *rdev);
+
+/* rv740 */
+int rv740_populate_sclk_value(struct radeon_device *rdev, u32 engine_clock,
+ RV770_SMC_SCLK_VALUE *sclk);
+int rv740_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock, u32 memory_clock,
+ RV7XX_SMC_MCLK_VALUE *mclk);
+void rv740_read_clock_registers(struct radeon_device *rdev);
+int rv740_populate_smc_acpi_state(struct radeon_device *rdev,
+ RV770_SMC_STATETABLE *table);
+void rv740_enable_mclk_spread_spectrum(struct radeon_device *rdev,
+ bool enable);
+u8 rv740_get_mclk_frequency_ratio(u32 memory_clock);
+u32 rv740_get_dll_speed(bool is_gddr5, u32 memory_clock);
+u32 rv740_get_decoded_reference_divider(u32 encoded_ref);
+
+/* rv770 */
+u32 rv770_map_clkf_to_ibias(struct radeon_device *rdev, u32 clkf);
+int rv770_populate_vddc_value(struct radeon_device *rdev, u16 vddc,
+ RV770_SMC_VOLTAGE_VALUE *voltage);
+int rv770_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
+ RV770_SMC_VOLTAGE_VALUE *voltage);
+u8 rv770_get_seq_value(struct radeon_device *rdev,
+ struct rv7xx_pl *pl);
+int rv770_populate_initial_mvdd_value(struct radeon_device *rdev,
+ RV770_SMC_VOLTAGE_VALUE *voltage);
+u32 rv770_calculate_memory_refresh_rate(struct radeon_device *rdev,
+ u32 engine_clock);
+void rv770_program_response_times(struct radeon_device *rdev);
+int rv770_populate_smc_sp(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_SWSTATE *smc_state);
+int rv770_populate_smc_t(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ RV770_SMC_SWSTATE *smc_state);
+void rv770_read_voltage_smio_registers(struct radeon_device *rdev);
+void rv770_get_memory_type(struct radeon_device *rdev);
+void r7xx_start_smc(struct radeon_device *rdev);
+u8 rv770_get_memory_module_index(struct radeon_device *rdev);
+void rv770_get_max_vddc(struct radeon_device *rdev);
+void rv770_get_pcie_gen2_status(struct radeon_device *rdev);
+void rv770_enable_acpi_pm(struct radeon_device *rdev);
+void rv770_restore_cgcg(struct radeon_device *rdev);
+bool rv770_dpm_enabled(struct radeon_device *rdev);
+void rv770_enable_voltage_control(struct radeon_device *rdev,
+ bool enable);
+void rv770_enable_backbias(struct radeon_device *rdev,
+ bool enable);
+void rv770_enable_thermal_protection(struct radeon_device *rdev,
+ bool enable);
+void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
+ enum radeon_dpm_auto_throttle_src source,
+ bool enable);
+void rv770_setup_bsp(struct radeon_device *rdev);
+void rv770_program_git(struct radeon_device *rdev);
+void rv770_program_tp(struct radeon_device *rdev);
+void rv770_program_tpp(struct radeon_device *rdev);
+void rv770_program_sstp(struct radeon_device *rdev);
+void rv770_program_engine_speed_parameters(struct radeon_device *rdev);
+void rv770_program_vc(struct radeon_device *rdev);
+void rv770_clear_vc(struct radeon_device *rdev);
+int rv770_upload_firmware(struct radeon_device *rdev);
+void rv770_stop_dpm(struct radeon_device *rdev);
+void r7xx_stop_smc(struct radeon_device *rdev);
+void rv770_reset_smio_status(struct radeon_device *rdev);
+int rv770_restrict_performance_levels_before_switch(struct radeon_device *rdev);
+int rv770_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level);
+int rv770_halt_smc(struct radeon_device *rdev);
+int rv770_resume_smc(struct radeon_device *rdev);
+int rv770_set_sw_state(struct radeon_device *rdev);
+int rv770_set_boot_state(struct radeon_device *rdev);
+int rv7xx_parse_power_table(struct radeon_device *rdev);
+void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps);
+void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_ps,
+ struct radeon_ps *old_ps);
+
+/* smc */
+int rv770_read_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 *value);
+int rv770_write_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 value);
+
+/* thermal */
+int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv770_smc.c b/drivers/gpu/drm/radeon/rv770_smc.c
new file mode 100644
index 000000000000..ab95da570215
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_smc.c
@@ -0,0 +1,621 @@
+/*
+ * 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 "radeon.h"
+#include "rv770d.h"
+#include "rv770_dpm.h"
+#include "rv770_smc.h"
+#include "atom.h"
+#include "radeon_ucode.h"
+
+#define FIRST_SMC_INT_VECT_REG 0xFFD8
+#define FIRST_INT_VECT_S19 0xFFC0
+
+static const u8 rv770_smc_int_vectors[] =
+{
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x0C, 0xD7,
+ 0x08, 0x2B, 0x08, 0x10,
+ 0x03, 0x51, 0x03, 0x51,
+ 0x03, 0x51, 0x03, 0x51
+};
+
+static const u8 rv730_smc_int_vectors[] =
+{
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x08, 0x15,
+ 0x08, 0x15, 0x0C, 0xBB,
+ 0x08, 0x30, 0x08, 0x15,
+ 0x03, 0x56, 0x03, 0x56,
+ 0x03, 0x56, 0x03, 0x56
+};
+
+static const u8 rv710_smc_int_vectors[] =
+{
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x08, 0x04,
+ 0x08, 0x04, 0x0C, 0xCB,
+ 0x08, 0x1F, 0x08, 0x04,
+ 0x03, 0x51, 0x03, 0x51,
+ 0x03, 0x51, 0x03, 0x51
+};
+
+static const u8 rv740_smc_int_vectors[] =
+{
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x08, 0x10,
+ 0x08, 0x10, 0x0C, 0xD7,
+ 0x08, 0x2B, 0x08, 0x10,
+ 0x03, 0x51, 0x03, 0x51,
+ 0x03, 0x51, 0x03, 0x51
+};
+
+static const u8 cedar_smc_int_vectors[] =
+{
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x11, 0x8B,
+ 0x0B, 0x20, 0x0B, 0x05,
+ 0x04, 0xF6, 0x04, 0xF6,
+ 0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 redwood_smc_int_vectors[] =
+{
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x11, 0x8B,
+ 0x0B, 0x20, 0x0B, 0x05,
+ 0x04, 0xF6, 0x04, 0xF6,
+ 0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 juniper_smc_int_vectors[] =
+{
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x11, 0x8B,
+ 0x0B, 0x20, 0x0B, 0x05,
+ 0x04, 0xF6, 0x04, 0xF6,
+ 0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 cypress_smc_int_vectors[] =
+{
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x0B, 0x05,
+ 0x0B, 0x05, 0x11, 0x8B,
+ 0x0B, 0x20, 0x0B, 0x05,
+ 0x04, 0xF6, 0x04, 0xF6,
+ 0x04, 0xF6, 0x04, 0xF6
+};
+
+static const u8 barts_smc_int_vectors[] =
+{
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x12, 0xAA,
+ 0x0C, 0x2F, 0x15, 0xF6,
+ 0x15, 0xF6, 0x05, 0x0A,
+ 0x05, 0x0A, 0x05, 0x0A
+};
+
+static const u8 turks_smc_int_vectors[] =
+{
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x12, 0xAA,
+ 0x0C, 0x2F, 0x15, 0xF6,
+ 0x15, 0xF6, 0x05, 0x0A,
+ 0x05, 0x0A, 0x05, 0x0A
+};
+
+static const u8 caicos_smc_int_vectors[] =
+{
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x0C, 0x14,
+ 0x0C, 0x14, 0x12, 0xAA,
+ 0x0C, 0x2F, 0x15, 0xF6,
+ 0x15, 0xF6, 0x05, 0x0A,
+ 0x05, 0x0A, 0x05, 0x0A
+};
+
+static const u8 cayman_smc_int_vectors[] =
+{
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x12, 0x05,
+ 0x12, 0x05, 0x18, 0xEA,
+ 0x12, 0x20, 0x1C, 0x34,
+ 0x1C, 0x34, 0x08, 0x72,
+ 0x08, 0x72, 0x08, 0x72
+};
+
+int rv770_set_smc_sram_address(struct radeon_device *rdev,
+ u16 smc_address, u16 limit)
+{
+ u32 addr;
+
+ if (smc_address & 3)
+ return -EINVAL;
+ if ((smc_address + 3) > limit)
+ return -EINVAL;
+
+ addr = smc_address;
+ addr |= SMC_SRAM_AUTO_INC_DIS;
+
+ WREG32(SMC_SRAM_ADDR, addr);
+
+ return 0;
+}
+
+int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
+ u16 smc_start_address, const u8 *src,
+ u16 byte_count, u16 limit)
+{
+ u32 data, original_data, extra_shift;
+ u16 addr;
+ int ret;
+
+ if (smc_start_address & 3)
+ return -EINVAL;
+ if ((smc_start_address + byte_count) > limit)
+ return -EINVAL;
+
+ addr = smc_start_address;
+
+ while (byte_count >= 4) {
+ /* SMC address space is BE */
+ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+ ret = rv770_set_smc_sram_address(rdev, addr, limit);
+ if (ret)
+ return ret;
+
+ WREG32(SMC_SRAM_DATA, data);
+
+ src += 4;
+ byte_count -= 4;
+ addr += 4;
+ }
+
+ /* RMW for final bytes */
+ if (byte_count > 0) {
+ data = 0;
+
+ ret = rv770_set_smc_sram_address(rdev, addr, limit);
+ if (ret)
+ return ret;
+
+ original_data = RREG32(SMC_SRAM_DATA);
+
+ extra_shift = 8 * (4 - byte_count);
+
+ while (byte_count > 0) {
+ /* SMC address space is BE */
+ data = (data << 8) + *src++;
+ byte_count--;
+ }
+
+ data <<= extra_shift;
+
+ data |= (original_data & ~((~0UL) << extra_shift));
+
+ ret = rv770_set_smc_sram_address(rdev, addr, limit);
+ if (ret)
+ return ret;
+
+ WREG32(SMC_SRAM_DATA, data);
+ }
+
+ return 0;
+}
+
+static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
+ u32 smc_first_vector, const u8 *src,
+ u32 byte_count)
+{
+ u32 tmp, i;
+
+ if (byte_count % 4)
+ return -EINVAL;
+
+ if (smc_first_vector < FIRST_SMC_INT_VECT_REG) {
+ tmp = FIRST_SMC_INT_VECT_REG - smc_first_vector;
+
+ if (tmp > byte_count)
+ return 0;
+
+ byte_count -= tmp;
+ src += tmp;
+ smc_first_vector = FIRST_SMC_INT_VECT_REG;
+ }
+
+ for (i = 0; i < byte_count; i += 4) {
+ /* SMC address space is BE */
+ tmp = (src[i] << 24) | (src[i + 1] << 16) | (src[i + 2] << 8) | src[i + 3];
+
+ WREG32(SMC_ISR_FFD8_FFDB + i, tmp);
+ }
+
+ return 0;
+}
+
+void rv770_start_smc(struct radeon_device *rdev)
+{
+ WREG32_P(SMC_IO, SMC_RST_N, ~SMC_RST_N);
+}
+
+void rv770_reset_smc(struct radeon_device *rdev)
+{
+ WREG32_P(SMC_IO, 0, ~SMC_RST_N);
+}
+
+void rv770_stop_smc_clock(struct radeon_device *rdev)
+{
+ WREG32_P(SMC_IO, 0, ~SMC_CLK_EN);
+}
+
+void rv770_start_smc_clock(struct radeon_device *rdev)
+{
+ WREG32_P(SMC_IO, SMC_CLK_EN, ~SMC_CLK_EN);
+}
+
+bool rv770_is_smc_running(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG32(SMC_IO);
+
+ if ((tmp & SMC_RST_N) && (tmp & SMC_CLK_EN))
+ return true;
+ else
+ return false;
+}
+
+PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
+{
+ u32 tmp;
+ int i;
+ PPSMC_Result result;
+
+ if (!rv770_is_smc_running(rdev))
+ return PPSMC_Result_Failed;
+
+ WREG32_P(SMC_MSG, HOST_SMC_MSG(msg), ~HOST_SMC_MSG_MASK);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
+ tmp >>= HOST_SMC_RESP_SHIFT;
+ if (tmp != 0)
+ break;
+ udelay(1);
+ }
+
+ tmp = RREG32(SMC_MSG) & HOST_SMC_RESP_MASK;
+ tmp >>= HOST_SMC_RESP_SHIFT;
+
+ result = (PPSMC_Result)tmp;
+ return result;
+}
+
+PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
+{
+ int i;
+ PPSMC_Result result = PPSMC_Result_OK;
+
+ if (!rv770_is_smc_running(rdev))
+ return result;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(SMC_IO) & SMC_STOP_MODE)
+ break;
+ udelay(1);
+ }
+
+ return result;
+}
+
+static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
+{
+ u16 i;
+
+ for (i = 0; i < limit; i += 4) {
+ rv770_set_smc_sram_address(rdev, i, limit);
+ WREG32(SMC_SRAM_DATA, 0);
+ }
+}
+
+int rv770_load_smc_ucode(struct radeon_device *rdev,
+ u16 limit)
+{
+ int ret;
+ const u8 *int_vect;
+ u16 int_vect_start_address;
+ u16 int_vect_size;
+ const u8 *ucode_data;
+ u16 ucode_start_address;
+ u16 ucode_size;
+
+ if (!rdev->smc_fw)
+ return -EINVAL;
+
+ rv770_clear_smc_sram(rdev, limit);
+
+ switch (rdev->family) {
+ case CHIP_RV770:
+ ucode_start_address = RV770_SMC_UCODE_START;
+ ucode_size = RV770_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&rv770_smc_int_vectors;
+ int_vect_start_address = RV770_SMC_INT_VECTOR_START;
+ int_vect_size = RV770_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_RV730:
+ ucode_start_address = RV730_SMC_UCODE_START;
+ ucode_size = RV730_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&rv730_smc_int_vectors;
+ int_vect_start_address = RV730_SMC_INT_VECTOR_START;
+ int_vect_size = RV730_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_RV710:
+ ucode_start_address = RV710_SMC_UCODE_START;
+ ucode_size = RV710_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&rv710_smc_int_vectors;
+ int_vect_start_address = RV710_SMC_INT_VECTOR_START;
+ int_vect_size = RV710_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_RV740:
+ ucode_start_address = RV740_SMC_UCODE_START;
+ ucode_size = RV740_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&rv740_smc_int_vectors;
+ int_vect_start_address = RV740_SMC_INT_VECTOR_START;
+ int_vect_size = RV740_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_CEDAR:
+ ucode_start_address = CEDAR_SMC_UCODE_START;
+ ucode_size = CEDAR_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&cedar_smc_int_vectors;
+ int_vect_start_address = CEDAR_SMC_INT_VECTOR_START;
+ int_vect_size = CEDAR_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_REDWOOD:
+ ucode_start_address = REDWOOD_SMC_UCODE_START;
+ ucode_size = REDWOOD_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&redwood_smc_int_vectors;
+ int_vect_start_address = REDWOOD_SMC_INT_VECTOR_START;
+ int_vect_size = REDWOOD_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_JUNIPER:
+ ucode_start_address = JUNIPER_SMC_UCODE_START;
+ ucode_size = JUNIPER_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&juniper_smc_int_vectors;
+ int_vect_start_address = JUNIPER_SMC_INT_VECTOR_START;
+ int_vect_size = JUNIPER_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_CYPRESS:
+ case CHIP_HEMLOCK:
+ ucode_start_address = CYPRESS_SMC_UCODE_START;
+ ucode_size = CYPRESS_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&cypress_smc_int_vectors;
+ int_vect_start_address = CYPRESS_SMC_INT_VECTOR_START;
+ int_vect_size = CYPRESS_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_BARTS:
+ ucode_start_address = BARTS_SMC_UCODE_START;
+ ucode_size = BARTS_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&barts_smc_int_vectors;
+ int_vect_start_address = BARTS_SMC_INT_VECTOR_START;
+ int_vect_size = BARTS_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_TURKS:
+ ucode_start_address = TURKS_SMC_UCODE_START;
+ ucode_size = TURKS_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&turks_smc_int_vectors;
+ int_vect_start_address = TURKS_SMC_INT_VECTOR_START;
+ int_vect_size = TURKS_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_CAICOS:
+ ucode_start_address = CAICOS_SMC_UCODE_START;
+ ucode_size = CAICOS_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&caicos_smc_int_vectors;
+ int_vect_start_address = CAICOS_SMC_INT_VECTOR_START;
+ int_vect_size = CAICOS_SMC_INT_VECTOR_SIZE;
+ break;
+ case CHIP_CAYMAN:
+ ucode_start_address = CAYMAN_SMC_UCODE_START;
+ ucode_size = CAYMAN_SMC_UCODE_SIZE;
+ int_vect = (const u8 *)&cayman_smc_int_vectors;
+ int_vect_start_address = CAYMAN_SMC_INT_VECTOR_START;
+ int_vect_size = CAYMAN_SMC_INT_VECTOR_SIZE;
+ break;
+ default:
+ DRM_ERROR("unknown asic in smc ucode loader\n");
+ BUG();
+ }
+
+ /* load the ucode */
+ ucode_data = (const u8 *)rdev->smc_fw->data;
+ ret = rv770_copy_bytes_to_smc(rdev, ucode_start_address,
+ ucode_data, ucode_size, limit);
+ if (ret)
+ return ret;
+
+ /* set up the int vectors */
+ ret = rv770_program_interrupt_vectors(rdev, int_vect_start_address,
+ int_vect, int_vect_size);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int rv770_read_smc_sram_dword(struct radeon_device *rdev,
+ u16 smc_address, u32 *value, u16 limit)
+{
+ int ret;
+
+ ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
+ if (ret)
+ return ret;
+
+ *value = RREG32(SMC_SRAM_DATA);
+
+ return 0;
+}
+
+int rv770_write_smc_sram_dword(struct radeon_device *rdev,
+ u16 smc_address, u32 value, u16 limit)
+{
+ int ret;
+
+ ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
+ if (ret)
+ return ret;
+
+ WREG32(SMC_SRAM_DATA, value);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/rv770_smc.h b/drivers/gpu/drm/radeon/rv770_smc.h
new file mode 100644
index 000000000000..f78d92a4b325
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv770_smc.h
@@ -0,0 +1,209 @@
+/*
+ * 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.
+ *
+ */
+#ifndef __RV770_SMC_H__
+#define __RV770_SMC_H__
+
+#include "ppsmc.h"
+
+#pragma pack(push, 1)
+
+#define RV770_SMC_TABLE_ADDRESS 0xB000
+
+#define RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 3
+
+struct RV770_SMC_SCLK_VALUE
+{
+ uint32_t vCG_SPLL_FUNC_CNTL;
+ uint32_t vCG_SPLL_FUNC_CNTL_2;
+ uint32_t vCG_SPLL_FUNC_CNTL_3;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t sclk_value;
+};
+
+typedef struct RV770_SMC_SCLK_VALUE RV770_SMC_SCLK_VALUE;
+
+struct RV770_SMC_MCLK_VALUE
+{
+ uint32_t vMPLL_AD_FUNC_CNTL;
+ uint32_t vMPLL_AD_FUNC_CNTL_2;
+ uint32_t vMPLL_DQ_FUNC_CNTL;
+ uint32_t vMPLL_DQ_FUNC_CNTL_2;
+ uint32_t vMCLK_PWRMGT_CNTL;
+ uint32_t vDLL_CNTL;
+ uint32_t vMPLL_SS;
+ uint32_t vMPLL_SS2;
+ uint32_t mclk_value;
+};
+
+typedef struct RV770_SMC_MCLK_VALUE RV770_SMC_MCLK_VALUE;
+
+
+struct RV730_SMC_MCLK_VALUE
+{
+ uint32_t vMCLK_PWRMGT_CNTL;
+ uint32_t vDLL_CNTL;
+ uint32_t vMPLL_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL2;
+ uint32_t vMPLL_FUNC_CNTL3;
+ uint32_t vMPLL_SS;
+ uint32_t vMPLL_SS2;
+ uint32_t mclk_value;
+};
+
+typedef struct RV730_SMC_MCLK_VALUE RV730_SMC_MCLK_VALUE;
+
+struct RV770_SMC_VOLTAGE_VALUE
+{
+ uint16_t value;
+ uint8_t index;
+ uint8_t padding;
+};
+
+typedef struct RV770_SMC_VOLTAGE_VALUE RV770_SMC_VOLTAGE_VALUE;
+
+union RV7XX_SMC_MCLK_VALUE
+{
+ RV770_SMC_MCLK_VALUE mclk770;
+ RV730_SMC_MCLK_VALUE mclk730;
+};
+
+typedef union RV7XX_SMC_MCLK_VALUE RV7XX_SMC_MCLK_VALUE, *LPRV7XX_SMC_MCLK_VALUE;
+
+struct RV770_SMC_HW_PERFORMANCE_LEVEL
+{
+ uint8_t arbValue;
+ union{
+ uint8_t seqValue;
+ uint8_t ACIndex;
+ };
+ uint8_t displayWatermark;
+ uint8_t gen2PCIE;
+ uint8_t gen2XSP;
+ uint8_t backbias;
+ uint8_t strobeMode;
+ uint8_t mcFlags;
+ uint32_t aT;
+ uint32_t bSP;
+ RV770_SMC_SCLK_VALUE sclk;
+ RV7XX_SMC_MCLK_VALUE mclk;
+ RV770_SMC_VOLTAGE_VALUE vddc;
+ RV770_SMC_VOLTAGE_VALUE mvdd;
+ RV770_SMC_VOLTAGE_VALUE vddci;
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint8_t stateFlags;
+ uint8_t padding;
+};
+
+#define SMC_STROBE_RATIO 0x0F
+#define SMC_STROBE_ENABLE 0x10
+
+#define SMC_MC_EDC_RD_FLAG 0x01
+#define SMC_MC_EDC_WR_FLAG 0x02
+#define SMC_MC_RTT_ENABLE 0x04
+#define SMC_MC_STUTTER_EN 0x08
+
+typedef struct RV770_SMC_HW_PERFORMANCE_LEVEL RV770_SMC_HW_PERFORMANCE_LEVEL;
+
+struct RV770_SMC_SWSTATE
+{
+ uint8_t flags;
+ uint8_t padding1;
+ uint8_t padding2;
+ uint8_t padding3;
+ RV770_SMC_HW_PERFORMANCE_LEVEL levels[RV770_SMC_PERFORMANCE_LEVELS_PER_SWSTATE];
+};
+
+typedef struct RV770_SMC_SWSTATE RV770_SMC_SWSTATE;
+
+#define RV770_SMC_VOLTAGEMASK_VDDC 0
+#define RV770_SMC_VOLTAGEMASK_MVDD 1
+#define RV770_SMC_VOLTAGEMASK_VDDCI 2
+#define RV770_SMC_VOLTAGEMASK_MAX 4
+
+struct RV770_SMC_VOLTAGEMASKTABLE
+{
+ uint8_t highMask[RV770_SMC_VOLTAGEMASK_MAX];
+ uint32_t lowMask[RV770_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct RV770_SMC_VOLTAGEMASKTABLE RV770_SMC_VOLTAGEMASKTABLE;
+
+#define MAX_NO_VREG_STEPS 32
+
+struct RV770_SMC_STATETABLE
+{
+ uint8_t thermalProtectType;
+ uint8_t systemFlags;
+ uint8_t maxVDDCIndexInPPTable;
+ uint8_t extraFlags;
+ uint8_t highSMIO[MAX_NO_VREG_STEPS];
+ uint32_t lowSMIO[MAX_NO_VREG_STEPS];
+ RV770_SMC_VOLTAGEMASKTABLE voltageMaskTable;
+ RV770_SMC_SWSTATE initialState;
+ RV770_SMC_SWSTATE ACPIState;
+ RV770_SMC_SWSTATE driverState;
+ RV770_SMC_SWSTATE ULVState;
+};
+
+typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE;
+
+#define PPSMC_STATEFLAG_AUTO_PULSE_SKIP 0x01
+
+#pragma pack(pop)
+
+#define RV770_SMC_SOFT_REGISTERS_START 0x104
+
+#define RV770_SMC_SOFT_REGISTER_mclk_chg_timeout 0x0
+#define RV770_SMC_SOFT_REGISTER_baby_step_timer 0x8
+#define RV770_SMC_SOFT_REGISTER_delay_bbias 0xC
+#define RV770_SMC_SOFT_REGISTER_delay_vreg 0x10
+#define RV770_SMC_SOFT_REGISTER_delay_acpi 0x2C
+#define RV770_SMC_SOFT_REGISTER_seq_index 0x64
+#define RV770_SMC_SOFT_REGISTER_mvdd_chg_time 0x68
+#define RV770_SMC_SOFT_REGISTER_mclk_switch_lim 0x78
+#define RV770_SMC_SOFT_REGISTER_mc_block_delay 0x90
+#define RV770_SMC_SOFT_REGISTER_uvd_enabled 0x9C
+#define RV770_SMC_SOFT_REGISTER_is_asic_lombok 0xA0
+
+int rv770_set_smc_sram_address(struct radeon_device *rdev,
+ u16 smc_address, u16 limit);
+int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
+ u16 smc_start_address, const u8 *src,
+ u16 byte_count, u16 limit);
+void rv770_start_smc(struct radeon_device *rdev);
+void rv770_reset_smc(struct radeon_device *rdev);
+void rv770_stop_smc_clock(struct radeon_device *rdev);
+void rv770_start_smc_clock(struct radeon_device *rdev);
+bool rv770_is_smc_running(struct radeon_device *rdev);
+PPSMC_Result rv770_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg);
+PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev);
+int rv770_read_smc_sram_dword(struct radeon_device *rdev,
+ u16 smc_address, u32 *value, u16 limit);
+int rv770_write_smc_sram_dword(struct radeon_device *rdev,
+ u16 smc_address, u32 value, u16 limit);
+int rv770_load_smc_ucode(struct radeon_device *rdev,
+ u16 limit);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 85b16266f748..6bef2b7d601b 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -62,6 +62,246 @@
# define UPLL_FB_DIV(x) ((x) << 0)
# define UPLL_FB_DIV_MASK 0x01FFFFFF
+/* pm registers */
+#define SMC_SRAM_ADDR 0x200
+#define SMC_SRAM_AUTO_INC_DIS (1 << 16)
+#define SMC_SRAM_DATA 0x204
+#define SMC_IO 0x208
+#define SMC_RST_N (1 << 0)
+#define SMC_STOP_MODE (1 << 2)
+#define SMC_CLK_EN (1 << 11)
+#define SMC_MSG 0x20c
+#define HOST_SMC_MSG(x) ((x) << 0)
+#define HOST_SMC_MSG_MASK (0xff << 0)
+#define HOST_SMC_MSG_SHIFT 0
+#define HOST_SMC_RESP(x) ((x) << 8)
+#define HOST_SMC_RESP_MASK (0xff << 8)
+#define HOST_SMC_RESP_SHIFT 8
+#define SMC_HOST_MSG(x) ((x) << 16)
+#define SMC_HOST_MSG_MASK (0xff << 16)
+#define SMC_HOST_MSG_SHIFT 16
+#define SMC_HOST_RESP(x) ((x) << 24)
+#define SMC_HOST_RESP_MASK (0xff << 24)
+#define SMC_HOST_RESP_SHIFT 24
+
+#define SMC_ISR_FFD8_FFDB 0x218
+
+#define CG_SPLL_FUNC_CNTL 0x600
+#define SPLL_RESET (1 << 0)
+#define SPLL_SLEEP (1 << 1)
+#define SPLL_DIVEN (1 << 2)
+#define SPLL_BYPASS_EN (1 << 3)
+#define SPLL_REF_DIV(x) ((x) << 4)
+#define SPLL_REF_DIV_MASK (0x3f << 4)
+#define SPLL_HILEN(x) ((x) << 12)
+#define SPLL_HILEN_MASK (0xf << 12)
+#define SPLL_LOLEN(x) ((x) << 16)
+#define SPLL_LOLEN_MASK (0xf << 16)
+#define CG_SPLL_FUNC_CNTL_2 0x604
+#define SCLK_MUX_SEL(x) ((x) << 0)
+#define SCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_SPLL_FUNC_CNTL_3 0x608
+#define SPLL_FB_DIV(x) ((x) << 0)
+#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define SPLL_DITHEN (1 << 28)
+
+#define SPLL_CNTL_MODE 0x610
+#define SPLL_DIV_SYNC (1 << 5)
+
+#define MPLL_AD_FUNC_CNTL 0x624
+#define CLKF(x) ((x) << 0)
+#define CLKF_MASK (0x7f << 0)
+#define CLKR(x) ((x) << 7)
+#define CLKR_MASK (0x1f << 7)
+#define CLKFRAC(x) ((x) << 12)
+#define CLKFRAC_MASK (0x1f << 12)
+#define YCLK_POST_DIV(x) ((x) << 17)
+#define YCLK_POST_DIV_MASK (3 << 17)
+#define IBIAS(x) ((x) << 20)
+#define IBIAS_MASK (0x3ff << 20)
+#define RESET (1 << 30)
+#define PDNB (1 << 31)
+#define MPLL_AD_FUNC_CNTL_2 0x628
+#define BYPASS (1 << 19)
+#define BIAS_GEN_PDNB (1 << 24)
+#define RESET_EN (1 << 25)
+#define VCO_MODE (1 << 29)
+#define MPLL_DQ_FUNC_CNTL 0x62c
+#define MPLL_DQ_FUNC_CNTL_2 0x630
+
+#define GENERAL_PWRMGT 0x63c
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define THERMAL_PROTECTION_DIS (1 << 2)
+# define THERMAL_PROTECTION_TYPE (1 << 3)
+# define ENABLE_GEN2PCIE (1 << 4)
+# define ENABLE_GEN2XSP (1 << 5)
+# define SW_SMIO_INDEX(x) ((x) << 6)
+# define SW_SMIO_INDEX_MASK (3 << 6)
+# define SW_SMIO_INDEX_SHIFT 6
+# define LOW_VOLT_D2_ACPI (1 << 8)
+# define LOW_VOLT_D3_ACPI (1 << 9)
+# define VOLT_PWRMGT_EN (1 << 10)
+# define BACKBIAS_PAD_EN (1 << 18)
+# define BACKBIAS_VALUE (1 << 19)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
+# define AC_DC_SW (1 << 24)
+
+#define CG_TPC 0x640
+#define SCLK_PWRMGT_CNTL 0x644
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_LOW_D1 (1 << 1)
+# define FIR_RESET (1 << 4)
+# define FIR_FORCE_TREND_SEL (1 << 5)
+# define FIR_TREND_MODE (1 << 6)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define GFX_CLK_REQUEST_OFF (1 << 9)
+# define GFX_CLK_FORCE_OFF (1 << 10)
+# define GFX_CLK_OFF_ACPI_D1 (1 << 11)
+# define GFX_CLK_OFF_ACPI_D2 (1 << 12)
+# define GFX_CLK_OFF_ACPI_D3 (1 << 13)
+#define MCLK_PWRMGT_CNTL 0x648
+# define DLL_SPEED(x) ((x) << 0)
+# define DLL_SPEED_MASK (0x1f << 0)
+# define MPLL_PWRMGT_OFF (1 << 5)
+# define DLL_READY (1 << 6)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCKA0_SLEEP (1 << 8)
+# define MRDCKA1_SLEEP (1 << 9)
+# define MRDCKB0_SLEEP (1 << 10)
+# define MRDCKB1_SLEEP (1 << 11)
+# define MRDCKC0_SLEEP (1 << 12)
+# define MRDCKC1_SLEEP (1 << 13)
+# define MRDCKD0_SLEEP (1 << 14)
+# define MRDCKD1_SLEEP (1 << 15)
+# define MRDCKA0_RESET (1 << 16)
+# define MRDCKA1_RESET (1 << 17)
+# define MRDCKB0_RESET (1 << 18)
+# define MRDCKB1_RESET (1 << 19)
+# define MRDCKC0_RESET (1 << 20)
+# define MRDCKC1_RESET (1 << 21)
+# define MRDCKD0_RESET (1 << 22)
+# define MRDCKD1_RESET (1 << 23)
+# define DLL_READY_READ (1 << 24)
+# define USE_DISPLAY_GAP (1 << 25)
+# define USE_DISPLAY_URGENT_NORMAL (1 << 26)
+# define MPLL_TURNOFF_D2 (1 << 28)
+#define DLL_CNTL 0x64c
+# define MRDCKA0_BYPASS (1 << 24)
+# define MRDCKA1_BYPASS (1 << 25)
+# define MRDCKB0_BYPASS (1 << 26)
+# define MRDCKB1_BYPASS (1 << 27)
+# define MRDCKC0_BYPASS (1 << 28)
+# define MRDCKC1_BYPASS (1 << 29)
+# define MRDCKD0_BYPASS (1 << 30)
+# define MRDCKD1_BYPASS (1 << 31)
+
+#define MPLL_TIME 0x654
+# define MPLL_LOCK_TIME(x) ((x) << 0)
+# define MPLL_LOCK_TIME_MASK (0xffff << 0)
+# define MPLL_RESET_TIME(x) ((x) << 16)
+# define MPLL_RESET_TIME_MASK (0xffff << 16)
+
+#define CG_CLKPIN_CNTL 0x660
+# define MUX_TCLK_TO_XCLK (1 << 8)
+# define XTALIN_DIVIDE (1 << 9)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c
+# define CURRENT_PROFILE_INDEX_MASK (0xf << 4)
+# define CURRENT_PROFILE_INDEX_SHIFT 4
+
+#define S0_VID_LOWER_SMIO_CNTL 0x678
+#define S1_VID_LOWER_SMIO_CNTL 0x67c
+#define S2_VID_LOWER_SMIO_CNTL 0x680
+#define S3_VID_LOWER_SMIO_CNTL 0x684
+
+#define CG_FTV 0x690
+#define CG_FFCT_0 0x694
+# define UTC_0(x) ((x) << 0)
+# define UTC_0_MASK (0x3ff << 0)
+# define DTC_0(x) ((x) << 10)
+# define DTC_0_MASK (0x3ff << 10)
+
+#define CG_BSP 0x6d0
+# define BSP(x) ((x) << 0)
+# define BSP_MASK (0xffff << 0)
+# define BSU(x) ((x) << 16)
+# define BSU_MASK (0xf << 16)
+#define CG_AT 0x6d4
+# define CG_R(x) ((x) << 0)
+# define CG_R_MASK (0xffff << 0)
+# define CG_L(x) ((x) << 16)
+# define CG_L_MASK (0xffff << 16)
+#define CG_GIT 0x6d8
+# define CG_GICST(x) ((x) << 0)
+# define CG_GICST_MASK (0xffff << 0)
+# define CG_GIPOT(x) ((x) << 16)
+# define CG_GIPOT_MASK (0xffff << 16)
+
+#define CG_SSP 0x6e8
+# define SST(x) ((x) << 0)
+# define SST_MASK (0xffff << 0)
+# define SSTU(x) ((x) << 16)
+# define SSTU_MASK (0xf << 16)
+
+#define CG_DISPLAY_GAP_CNTL 0x714
+# define DISP1_GAP(x) ((x) << 0)
+# define DISP1_GAP_MASK (3 << 0)
+# define DISP2_GAP(x) ((x) << 2)
+# define DISP2_GAP_MASK (3 << 2)
+# define VBI_TIMER_COUNT(x) ((x) << 4)
+# define VBI_TIMER_COUNT_MASK (0x3fff << 4)
+# define VBI_TIMER_UNIT(x) ((x) << 20)
+# define VBI_TIMER_UNIT_MASK (7 << 20)
+# define DISP1_GAP_MCHG(x) ((x) << 24)
+# define DISP1_GAP_MCHG_MASK (3 << 24)
+# define DISP2_GAP_MCHG(x) ((x) << 26)
+# define DISP2_GAP_MCHG_MASK (3 << 26)
+
+#define CG_SPLL_SPREAD_SPECTRUM 0x790
+#define SSEN (1 << 0)
+#define CLKS(x) ((x) << 4)
+#define CLKS_MASK (0xfff << 4)
+#define CG_SPLL_SPREAD_SPECTRUM_2 0x794
+#define CLKV(x) ((x) << 0)
+#define CLKV_MASK (0x3ffffff << 0)
+#define CG_MPLL_SPREAD_SPECTRUM 0x798
+#define CG_UPLL_SPREAD_SPECTRUM 0x79c
+# define SSEN_MASK 0x00000001
+
+#define CG_CGTT_LOCAL_0 0x7d0
+#define CG_CGTT_LOCAL_1 0x7d4
+
+#define BIOS_SCRATCH_4 0x1734
+
+#define MC_SEQ_MISC0 0x2a00
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+
+#define MC_ARB_SQM_RATIO 0x2770
+#define STATE0(x) ((x) << 0)
+#define STATE0_MASK (0xff << 0)
+#define STATE1(x) ((x) << 8)
+#define STATE1_MASK (0xff << 8)
+#define STATE2(x) ((x) << 16)
+#define STATE2_MASK (0xff << 16)
+#define STATE3(x) ((x) << 24)
+#define STATE3_MASK (0xff << 24)
+
+#define MC_ARB_RFSH_RATE 0x27b0
+#define POWERMODE0(x) ((x) << 0)
+#define POWERMODE0_MASK (0xff << 0)
+#define POWERMODE1(x) ((x) << 8)
+#define POWERMODE1_MASK (0xff << 8)
+#define POWERMODE2(x) ((x) << 16)
+#define POWERMODE2_MASK (0xff << 16)
+#define POWERMODE3(x) ((x) << 24)
+#define POWERMODE3_MASK (0xff << 24)
+
+#define CGTS_SM_CTRL_REG 0x9150
+
/* Registers */
#define CB_COLOR0_BASE 0x28040
#define CB_COLOR1_BASE 0x28044
@@ -86,8 +326,8 @@
#define CONFIG_MEMSIZE 0x5428
#define CP_ME_CNTL 0x86D8
-#define CP_ME_HALT (1<<28)
-#define CP_PFP_HALT (1<<26)
+#define CP_ME_HALT (1 << 28)
+#define CP_PFP_HALT (1 << 26)
#define CP_ME_RAM_DATA 0xC160
#define CP_ME_RAM_RADDR 0xC158
#define CP_ME_RAM_WADDR 0xC15C
@@ -157,9 +397,22 @@
#define GUI_ACTIVE (1<<31)
#define GRBM_STATUS2 0x8014
-#define CG_CLKPIN_CNTL 0x660
-# define MUX_TCLK_TO_XCLK (1 << 8)
-# define XTALIN_DIVIDE (1 << 9)
+#define CG_THERMAL_CTRL 0x72C
+#define DPM_EVENT_SRC(x) ((x) << 0)
+#define DPM_EVENT_SRC_MASK (7 << 0)
+#define DIG_THERM_DPM(x) ((x) << 14)
+#define DIG_THERM_DPM_MASK 0x003FC000
+#define DIG_THERM_DPM_SHIFT 14
+
+#define CG_THERMAL_INT 0x734
+#define DIG_THERM_INTH(x) ((x) << 8)
+#define DIG_THERM_INTH_MASK 0x0000FF00
+#define DIG_THERM_INTH_SHIFT 8
+#define DIG_THERM_INTL(x) ((x) << 16)
+#define DIG_THERM_INTL_MASK 0x00FF0000
+#define DIG_THERM_INTL_SHIFT 16
+#define THERM_INT_MASK_HIGH (1 << 24)
+#define THERM_INT_MASK_LOW (1 << 25)
#define CG_MULT_THERMAL_STATUS 0x740
#define ASIC_T(x) ((x) << 16)
@@ -662,7 +915,22 @@
#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c
#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c
-/* PCIE link stuff */
+/* PCIE indirect regs */
+#define PCIE_P_CNTL 0x40
+# define P_PLL_PWRDN_IN_L1L23 (1 << 3)
+# define P_PLL_BUF_PDNB (1 << 4)
+# define P_PLL_PDNB (1 << 9)
+# define P_ALLOW_PRX_FRONTEND_SHUTOFF (1 << 12)
+/* PCIE PORT regs */
+#define PCIE_LC_CNTL 0xa0
+# define LC_L0S_INACTIVITY(x) ((x) << 8)
+# define LC_L0S_INACTIVITY_MASK (0xf << 8)
+# define LC_L0S_INACTIVITY_SHIFT 8
+# define LC_L1_INACTIVITY(x) ((x) << 12)
+# define LC_L1_INACTIVITY_MASK (0xf << 12)
+# define LC_L1_INACTIVITY_SHIFT 12
+# define LC_PMI_TO_L1_DIS (1 << 16)
+# define LC_ASPM_TO_L1_DIS (1 << 24)
#define PCIE_LC_TRAINING_CNTL 0xa1 /* PCIE_P */
#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
# define LC_LINK_WIDTH_SHIFT 0
@@ -690,6 +958,9 @@
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 8)
# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 3
# define LC_CURRENT_DATA_RATE (1 << 11)
+# define LC_HW_VOLTAGE_IF_CONTROL(x) ((x) << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_MASK (3 << 12)
+# define LC_HW_VOLTAGE_IF_CONTROL_SHIFT 12
# define LC_VOLTAGE_TIMER_SEL_MASK (0xf << 14)
# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 21)
# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 23)
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index a1b0da6b5808..234906709067 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -32,40 +32,43 @@
#include "sid.h"
#include "atom.h"
#include "si_blit_shaders.h"
+#include "clearstate_si.h"
+#include "radeon_ucode.h"
-#define SI_PFP_UCODE_SIZE 2144
-#define SI_PM4_UCODE_SIZE 2144
-#define SI_CE_UCODE_SIZE 2144
-#define SI_RLC_UCODE_SIZE 2048
-#define SI_MC_UCODE_SIZE 7769
-#define OLAND_MC_UCODE_SIZE 7863
MODULE_FIRMWARE("radeon/TAHITI_pfp.bin");
MODULE_FIRMWARE("radeon/TAHITI_me.bin");
MODULE_FIRMWARE("radeon/TAHITI_ce.bin");
MODULE_FIRMWARE("radeon/TAHITI_mc.bin");
MODULE_FIRMWARE("radeon/TAHITI_rlc.bin");
+MODULE_FIRMWARE("radeon/TAHITI_smc.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_ce.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_mc.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_rlc.bin");
+MODULE_FIRMWARE("radeon/PITCAIRN_smc.bin");
MODULE_FIRMWARE("radeon/VERDE_pfp.bin");
MODULE_FIRMWARE("radeon/VERDE_me.bin");
MODULE_FIRMWARE("radeon/VERDE_ce.bin");
MODULE_FIRMWARE("radeon/VERDE_mc.bin");
MODULE_FIRMWARE("radeon/VERDE_rlc.bin");
+MODULE_FIRMWARE("radeon/VERDE_smc.bin");
MODULE_FIRMWARE("radeon/OLAND_pfp.bin");
MODULE_FIRMWARE("radeon/OLAND_me.bin");
MODULE_FIRMWARE("radeon/OLAND_ce.bin");
MODULE_FIRMWARE("radeon/OLAND_mc.bin");
MODULE_FIRMWARE("radeon/OLAND_rlc.bin");
+MODULE_FIRMWARE("radeon/OLAND_smc.bin");
MODULE_FIRMWARE("radeon/HAINAN_pfp.bin");
MODULE_FIRMWARE("radeon/HAINAN_me.bin");
MODULE_FIRMWARE("radeon/HAINAN_ce.bin");
MODULE_FIRMWARE("radeon/HAINAN_mc.bin");
MODULE_FIRMWARE("radeon/HAINAN_rlc.bin");
+MODULE_FIRMWARE("radeon/HAINAN_smc.bin");
+static void si_pcie_gen3_enable(struct radeon_device *rdev);
+static void si_program_aspm(struct radeon_device *rdev);
extern int r600_ih_ring_alloc(struct radeon_device *rdev);
extern void r600_ih_ring_fini(struct radeon_device *rdev);
extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
@@ -75,6 +78,228 @@ extern u32 evergreen_get_number_of_dram_channels(struct radeon_device *rdev);
extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
extern bool evergreen_is_display_hung(struct radeon_device *rdev);
+static const u32 verde_rlc_save_restore_register_list[] =
+{
+ (0x8000 << 16) | (0x98f4 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x98f4 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0xe80 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0xe80 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x89bc >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x89bc >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x8c1c >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x8c1c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x98f0 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xe7c >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x9148 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x9148 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9150 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x897c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8d8c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xac54 >> 2),
+ 0X00000000,
+ 0x3,
+ (0x9c00 << 16) | (0x98f8 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9910 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9914 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9918 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x991c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9920 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9924 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9928 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x992c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9930 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9934 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9938 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x993c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9940 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9944 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9948 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x994c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9950 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9954 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9958 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x995c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9960 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9964 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9968 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x996c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9970 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9974 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9978 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x997c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9980 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9984 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9988 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x998c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8c00 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8c14 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8c04 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8c08 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x9b7c >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x9b7c >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0xe84 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0xe84 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x89c0 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x89c0 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x914c >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x914c >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x8c20 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x8c20 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x9354 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x9354 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9060 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9364 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9100 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x913c >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x90e0 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x90e4 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x90e8 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x90e0 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x90e4 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x90e8 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8bcc >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8b24 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x88c4 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8e50 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8c0c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8e58 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8e5c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9508 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x950c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9494 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xac0c >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xac10 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xac14 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xae00 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0xac08 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x88d4 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x88c8 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x88cc >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x89b0 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8b10 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x8a14 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9830 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9834 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9838 >> 2),
+ 0x00000000,
+ (0x9c00 << 16) | (0x9a10 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x9870 >> 2),
+ 0x00000000,
+ (0x8000 << 16) | (0x9874 >> 2),
+ 0x00000000,
+ (0x8001 << 16) | (0x9870 >> 2),
+ 0x00000000,
+ (0x8001 << 16) | (0x9874 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x9870 >> 2),
+ 0x00000000,
+ (0x8040 << 16) | (0x9874 >> 2),
+ 0x00000000,
+ (0x8041 << 16) | (0x9870 >> 2),
+ 0x00000000,
+ (0x8041 << 16) | (0x9874 >> 2),
+ 0x00000000,
+ 0x00000000
+};
+
static const u32 tahiti_golden_rlc_registers[] =
{
0xc424, 0xffffffff, 0x00601005,
@@ -1320,6 +1545,7 @@ static int si_init_microcode(struct radeon_device *rdev)
const char *chip_name;
const char *rlc_chip_name;
size_t pfp_req_size, me_req_size, ce_req_size, rlc_req_size, mc_req_size;
+ size_t smc_req_size;
char fw_name[30];
int err;
@@ -1341,6 +1567,7 @@ static int si_init_microcode(struct radeon_device *rdev)
ce_req_size = SI_CE_UCODE_SIZE * 4;
rlc_req_size = SI_RLC_UCODE_SIZE * 4;
mc_req_size = SI_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(TAHITI_SMC_UCODE_SIZE, 4);
break;
case CHIP_PITCAIRN:
chip_name = "PITCAIRN";
@@ -1350,6 +1577,7 @@ static int si_init_microcode(struct radeon_device *rdev)
ce_req_size = SI_CE_UCODE_SIZE * 4;
rlc_req_size = SI_RLC_UCODE_SIZE * 4;
mc_req_size = SI_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(PITCAIRN_SMC_UCODE_SIZE, 4);
break;
case CHIP_VERDE:
chip_name = "VERDE";
@@ -1359,6 +1587,7 @@ static int si_init_microcode(struct radeon_device *rdev)
ce_req_size = SI_CE_UCODE_SIZE * 4;
rlc_req_size = SI_RLC_UCODE_SIZE * 4;
mc_req_size = SI_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(VERDE_SMC_UCODE_SIZE, 4);
break;
case CHIP_OLAND:
chip_name = "OLAND";
@@ -1368,6 +1597,7 @@ static int si_init_microcode(struct radeon_device *rdev)
ce_req_size = SI_CE_UCODE_SIZE * 4;
rlc_req_size = SI_RLC_UCODE_SIZE * 4;
mc_req_size = OLAND_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(OLAND_SMC_UCODE_SIZE, 4);
break;
case CHIP_HAINAN:
chip_name = "HAINAN";
@@ -1377,6 +1607,7 @@ static int si_init_microcode(struct radeon_device *rdev)
ce_req_size = SI_CE_UCODE_SIZE * 4;
rlc_req_size = SI_RLC_UCODE_SIZE * 4;
mc_req_size = OLAND_MC_UCODE_SIZE * 4;
+ smc_req_size = ALIGN(HAINAN_SMC_UCODE_SIZE, 4);
break;
default: BUG();
}
@@ -1439,6 +1670,17 @@ static int si_init_microcode(struct radeon_device *rdev)
err = -EINVAL;
}
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
+ err = request_firmware(&rdev->smc_fw, fw_name, &pdev->dev);
+ if (err)
+ goto out;
+ if (rdev->smc_fw->size != smc_req_size) {
+ printk(KERN_ERR
+ "si_smc: Bogus length %zu in firmware \"%s\"\n",
+ rdev->smc_fw->size, fw_name);
+ err = -EINVAL;
+ }
+
out:
platform_device_unregister(pdev);
@@ -1457,6 +1699,8 @@ out:
rdev->rlc_fw = NULL;
release_firmware(rdev->mc_fw);
rdev->mc_fw = NULL;
+ release_firmware(rdev->smc_fw);
+ rdev->smc_fw = NULL;
}
return err;
}
@@ -1792,7 +2036,8 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
u32 lb_size, u32 num_heads)
{
struct drm_display_mode *mode = &radeon_crtc->base.mode;
- struct dce6_wm_params wm;
+ struct dce6_wm_params wm_low, wm_high;
+ u32 dram_channels;
u32 pixel_period;
u32 line_time = 0;
u32 latency_watermark_a = 0, latency_watermark_b = 0;
@@ -1808,38 +2053,83 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
priority_a_cnt = 0;
priority_b_cnt = 0;
- wm.yclk = rdev->pm.current_mclk * 10;
- wm.sclk = rdev->pm.current_sclk * 10;
- wm.disp_clk = mode->clock;
- wm.src_width = mode->crtc_hdisplay;
- wm.active_time = mode->crtc_hdisplay * pixel_period;
- wm.blank_time = line_time - wm.active_time;
- wm.interlaced = false;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- wm.interlaced = true;
- wm.vsc = radeon_crtc->vsc;
- wm.vtaps = 1;
- if (radeon_crtc->rmx_type != RMX_OFF)
- wm.vtaps = 2;
- wm.bytes_per_pixel = 4; /* XXX: get this from fb config */
- wm.lb_size = lb_size;
if (rdev->family == CHIP_ARUBA)
- wm.dram_channels = evergreen_get_number_of_dram_channels(rdev);
+ dram_channels = evergreen_get_number_of_dram_channels(rdev);
else
- wm.dram_channels = si_get_number_of_dram_channels(rdev);
- wm.num_heads = num_heads;
+ dram_channels = si_get_number_of_dram_channels(rdev);
+
+ /* watermark for high clocks */
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+ wm_high.yclk =
+ radeon_dpm_get_mclk(rdev, false) * 10;
+ wm_high.sclk =
+ radeon_dpm_get_sclk(rdev, false) * 10;
+ } else {
+ wm_high.yclk = rdev->pm.current_mclk * 10;
+ wm_high.sclk = rdev->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 = radeon_crtc->vsc;
+ wm_high.vtaps = 1;
+ if (radeon_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 = dram_channels;
+ wm_high.num_heads = num_heads;
+
+ /* watermark for low clocks */
+ if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+ wm_low.yclk =
+ radeon_dpm_get_mclk(rdev, true) * 10;
+ wm_low.sclk =
+ radeon_dpm_get_sclk(rdev, true) * 10;
+ } else {
+ wm_low.yclk = rdev->pm.current_mclk * 10;
+ wm_low.sclk = rdev->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 = radeon_crtc->vsc;
+ wm_low.vtaps = 1;
+ if (radeon_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 = dram_channels;
+ wm_low.num_heads = num_heads;
/* set for high clocks */
- latency_watermark_a = min(dce6_latency_watermark(&wm), (u32)65535);
+ latency_watermark_a = min(dce6_latency_watermark(&wm_high), (u32)65535);
/* set for low clocks */
- /* wm.yclk = low clk; wm.sclk = low clk */
- latency_watermark_b = min(dce6_latency_watermark(&wm), (u32)65535);
+ latency_watermark_b = min(dce6_latency_watermark(&wm_low), (u32)65535);
/* possibly force display priority to high */
/* should really do this at mode validation time... */
- if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm) ||
- !dce6_average_bandwidth_vs_available_bandwidth(&wm) ||
- !dce6_check_latency_hiding(&wm) ||
+ if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm_high) ||
+ !dce6_average_bandwidth_vs_available_bandwidth(&wm_high) ||
+ !dce6_check_latency_hiding(&wm_high) ||
+ (rdev->disp_priority == 2)) {
+ DRM_DEBUG_KMS("force priority to high\n");
+ priority_a_cnt |= PRIORITY_ALWAYS_ON;
+ priority_b_cnt |= PRIORITY_ALWAYS_ON;
+ }
+ if (!dce6_average_bandwidth_vs_dram_bandwidth_for_display(&wm_low) ||
+ !dce6_average_bandwidth_vs_available_bandwidth(&wm_low) ||
+ !dce6_check_latency_hiding(&wm_low) ||
(rdev->disp_priority == 2)) {
DRM_DEBUG_KMS("force priority to high\n");
priority_a_cnt |= PRIORITY_ALWAYS_ON;
@@ -1895,6 +2185,10 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
WREG32(PRIORITY_A_CNT + radeon_crtc->crtc_offset, priority_a_cnt);
WREG32(PRIORITY_B_CNT + radeon_crtc->crtc_offset, priority_b_cnt);
+ /* save values for DPM */
+ radeon_crtc->line_time = line_time;
+ radeon_crtc->wm_high = latency_watermark_a;
+ radeon_crtc->wm_low = latency_watermark_b;
}
void dce6_bandwidth_update(struct radeon_device *rdev)
@@ -3535,8 +3829,8 @@ static void si_mc_program(struct radeon_device *rdev)
}
}
-static void si_vram_gtt_location(struct radeon_device *rdev,
- struct radeon_mc *mc)
+void si_vram_gtt_location(struct radeon_device *rdev,
+ struct radeon_mc *mc)
{
if (mc->mc_vram_size > 0xFFC0000000ULL) {
/* leave room for at least 1024M GTT */
@@ -4282,6 +4576,450 @@ void si_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
}
/*
+ * Power and clock gating
+ */
+static void si_wait_for_rlc_serdes(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(RLC_SERDES_MASTER_BUSY_0) == 0)
+ break;
+ udelay(1);
+ }
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(RLC_SERDES_MASTER_BUSY_1) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 tmp = RREG32(CP_INT_CNTL_RING0);
+ u32 mask;
+ int i;
+
+ if (enable)
+ tmp |= (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+ else
+ tmp &= ~(CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+ WREG32(CP_INT_CNTL_RING0, tmp);
+
+ if (!enable) {
+ /* read a gfx register */
+ tmp = RREG32(DB_DEPTH_INFO);
+
+ mask = RLC_BUSY_STATUS | GFX_POWER_STATUS | GFX_CLOCK_STATUS | GFX_LS_STATUS;
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(RLC_STAT) & mask) == (GFX_CLOCK_STATUS | GFX_POWER_STATUS))
+ break;
+ udelay(1);
+ }
+ }
+}
+
+static void si_set_uvd_dcm(struct radeon_device *rdev,
+ bool sw_mode)
+{
+ u32 tmp, tmp2;
+
+ tmp = RREG32(UVD_CGC_CTRL);
+ tmp &= ~(CLK_OD_MASK | CG_DT_MASK);
+ tmp |= DCM | CG_DT(1) | CLK_OD(4);
+
+ if (sw_mode) {
+ tmp &= ~0x7ffff800;
+ tmp2 = DYN_OR_EN | DYN_RR_EN | G_DIV_ID(7);
+ } else {
+ tmp |= 0x7ffff800;
+ tmp2 = 0;
+ }
+
+ WREG32(UVD_CGC_CTRL, tmp);
+ WREG32_UVD_CTX(UVD_CGC_CTRL2, tmp2);
+}
+
+static void si_init_uvd_internal_cg(struct radeon_device *rdev)
+{
+ bool hw_mode = true;
+
+ if (hw_mode) {
+ si_set_uvd_dcm(rdev, false);
+ } else {
+ u32 tmp = RREG32(UVD_CGC_CTRL);
+ tmp &= ~DCM;
+ WREG32(UVD_CGC_CTRL, tmp);
+ }
+}
+
+static u32 si_halt_rlc(struct radeon_device *rdev)
+{
+ u32 data, orig;
+
+ orig = data = RREG32(RLC_CNTL);
+
+ if (data & RLC_ENABLE) {
+ data &= ~RLC_ENABLE;
+ WREG32(RLC_CNTL, data);
+
+ si_wait_for_rlc_serdes(rdev);
+ }
+
+ return orig;
+}
+
+static void si_update_rlc(struct radeon_device *rdev, u32 rlc)
+{
+ u32 tmp;
+
+ tmp = RREG32(RLC_CNTL);
+ if (tmp != rlc)
+ WREG32(RLC_CNTL, rlc);
+}
+
+static void si_enable_dma_pg(struct radeon_device *rdev, bool enable)
+{
+ u32 data, orig;
+
+ orig = data = RREG32(DMA_PG);
+ if (enable)
+ data |= PG_CNTL_ENABLE;
+ else
+ data &= ~PG_CNTL_ENABLE;
+ if (orig != data)
+ WREG32(DMA_PG, data);
+}
+
+static void si_init_dma_pg(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ WREG32(DMA_PGFSM_WRITE, 0x00002000);
+ WREG32(DMA_PGFSM_CONFIG, 0x100010ff);
+
+ for (tmp = 0; tmp < 5; tmp++)
+ WREG32(DMA_PGFSM_WRITE, 0);
+}
+
+static void si_enable_gfx_cgpg(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 tmp;
+
+ if (enable) {
+ tmp = RLC_PUD(0x10) | RLC_PDD(0x10) | RLC_TTPD(0x10) | RLC_MSD(0x10);
+ WREG32(RLC_TTOP_D, tmp);
+
+ tmp = RREG32(RLC_PG_CNTL);
+ tmp |= GFX_PG_ENABLE;
+ WREG32(RLC_PG_CNTL, tmp);
+
+ tmp = RREG32(RLC_AUTO_PG_CTRL);
+ tmp |= AUTO_PG_EN;
+ WREG32(RLC_AUTO_PG_CTRL, tmp);
+ } else {
+ tmp = RREG32(RLC_AUTO_PG_CTRL);
+ tmp &= ~AUTO_PG_EN;
+ WREG32(RLC_AUTO_PG_CTRL, tmp);
+
+ tmp = RREG32(DB_RENDER_CONTROL);
+ }
+}
+
+static void si_init_gfx_cgpg(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+
+ tmp = RREG32(RLC_PG_CNTL);
+ tmp |= GFX_PG_SRC;
+ WREG32(RLC_PG_CNTL, tmp);
+
+ WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+
+ tmp = RREG32(RLC_AUTO_PG_CTRL);
+
+ tmp &= ~GRBM_REG_SGIT_MASK;
+ tmp |= GRBM_REG_SGIT(0x700);
+ tmp &= ~PG_AFTER_GRBM_REG_ST_MASK;
+ WREG32(RLC_AUTO_PG_CTRL, tmp);
+}
+
+static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh)
+{
+ u32 mask = 0, tmp, tmp1;
+ int i;
+
+ si_select_se_sh(rdev, se, sh);
+ tmp = RREG32(CC_GC_SHADER_ARRAY_CONFIG);
+ tmp1 = RREG32(GC_USER_SHADER_ARRAY_CONFIG);
+ si_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+
+ tmp &= 0xffff0000;
+
+ tmp |= tmp1;
+ tmp >>= 16;
+
+ for (i = 0; i < rdev->config.si.max_cu_per_sh; i ++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+
+ return (~tmp) & mask;
+}
+
+static void si_init_ao_cu_mask(struct radeon_device *rdev)
+{
+ u32 i, j, k, active_cu_number = 0;
+ u32 mask, counter, cu_bitmap;
+ u32 tmp = 0;
+
+ for (i = 0; i < rdev->config.si.max_shader_engines; i++) {
+ for (j = 0; j < rdev->config.si.max_sh_per_se; j++) {
+ mask = 1;
+ cu_bitmap = 0;
+ counter = 0;
+ for (k = 0; k < rdev->config.si.max_cu_per_sh; k++) {
+ if (si_get_cu_active_bitmap(rdev, i, j) & mask) {
+ if (counter < 2)
+ cu_bitmap |= mask;
+ counter++;
+ }
+ mask <<= 1;
+ }
+
+ active_cu_number += counter;
+ tmp |= (cu_bitmap << (i * 16 + j * 8));
+ }
+ }
+
+ WREG32(RLC_PG_AO_CU_MASK, tmp);
+
+ tmp = RREG32(RLC_MAX_PG_CU);
+ tmp &= ~MAX_PU_CU_MASK;
+ tmp |= MAX_PU_CU(active_cu_number);
+ WREG32(RLC_MAX_PG_CU, tmp);
+}
+
+static void si_enable_cgcg(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 data, orig, tmp;
+
+ orig = data = RREG32(RLC_CGCG_CGLS_CTRL);
+
+ si_enable_gui_idle_interrupt(rdev, enable);
+
+ if (enable) {
+ WREG32(RLC_GCPM_GENERAL_3, 0x00000080);
+
+ tmp = si_halt_rlc(rdev);
+
+ WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff);
+ WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff);
+ WREG32(RLC_SERDES_WR_CTRL, 0x00b000ff);
+
+ si_wait_for_rlc_serdes(rdev);
+
+ si_update_rlc(rdev, tmp);
+
+ WREG32(RLC_SERDES_WR_CTRL, 0x007000ff);
+
+ data |= CGCG_EN | CGLS_EN;
+ } else {
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+
+ data &= ~(CGCG_EN | CGLS_EN);
+ }
+
+ if (orig != data)
+ WREG32(RLC_CGCG_CGLS_CTRL, data);
+}
+
+static void si_enable_mgcg(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 data, orig, tmp = 0;
+
+ if (enable) {
+ orig = data = RREG32(CGTS_SM_CTRL_REG);
+ data = 0x96940200;
+ if (orig != data)
+ WREG32(CGTS_SM_CTRL_REG, data);
+
+ orig = data = RREG32(CP_MEM_SLP_CNTL);
+ data |= CP_MEM_LS_EN;
+ if (orig != data)
+ WREG32(CP_MEM_SLP_CNTL, data);
+
+ orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
+ data &= 0xffffffc0;
+ if (orig != data)
+ WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
+
+ tmp = si_halt_rlc(rdev);
+
+ WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff);
+ WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff);
+ WREG32(RLC_SERDES_WR_CTRL, 0x00d000ff);
+
+ si_update_rlc(rdev, tmp);
+ } else {
+ orig = data = RREG32(RLC_CGTT_MGCG_OVERRIDE);
+ data |= 0x00000003;
+ if (orig != data)
+ WREG32(RLC_CGTT_MGCG_OVERRIDE, data);
+
+ data = RREG32(CP_MEM_SLP_CNTL);
+ if (data & CP_MEM_LS_EN) {
+ data &= ~CP_MEM_LS_EN;
+ WREG32(CP_MEM_SLP_CNTL, data);
+ }
+ orig = data = RREG32(CGTS_SM_CTRL_REG);
+ data |= LS_OVERRIDE | OVERRIDE;
+ if (orig != data)
+ WREG32(CGTS_SM_CTRL_REG, data);
+
+ tmp = si_halt_rlc(rdev);
+
+ WREG32(RLC_SERDES_WR_MASTER_MASK_0, 0xffffffff);
+ WREG32(RLC_SERDES_WR_MASTER_MASK_1, 0xffffffff);
+ WREG32(RLC_SERDES_WR_CTRL, 0x00e000ff);
+
+ si_update_rlc(rdev, tmp);
+ }
+}
+
+static void si_enable_uvd_mgcg(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 orig, data, tmp;
+
+ if (enable) {
+ tmp = RREG32_UVD_CTX(UVD_CGC_MEM_CTRL);
+ tmp |= 0x3fff;
+ WREG32_UVD_CTX(UVD_CGC_MEM_CTRL, tmp);
+
+ orig = data = RREG32(UVD_CGC_CTRL);
+ data |= DCM;
+ if (orig != data)
+ WREG32(UVD_CGC_CTRL, data);
+
+ WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_0, 0);
+ WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_1, 0);
+ } else {
+ tmp = RREG32_UVD_CTX(UVD_CGC_MEM_CTRL);
+ tmp &= ~0x3fff;
+ WREG32_UVD_CTX(UVD_CGC_MEM_CTRL, tmp);
+
+ orig = data = RREG32(UVD_CGC_CTRL);
+ data &= ~DCM;
+ if (orig != data)
+ WREG32(UVD_CGC_CTRL, data);
+
+ WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_0, 0xffffffff);
+ WREG32_SMC(SMC_CG_IND_START + CG_CGTT_LOCAL_1, 0xffffffff);
+ }
+}
+
+static const u32 mc_cg_registers[] =
+{
+ MC_HUB_MISC_HUB_CG,
+ MC_HUB_MISC_SIP_CG,
+ MC_HUB_MISC_VM_CG,
+ MC_XPB_CLK_GAT,
+ ATC_MISC_CG,
+ MC_CITF_MISC_WR_CG,
+ MC_CITF_MISC_RD_CG,
+ MC_CITF_MISC_VM_CG,
+ VM_L2_CG,
+};
+
+static void si_enable_mc_ls(struct radeon_device *rdev,
+ bool enable)
+{
+ int i;
+ u32 orig, data;
+
+ for (i = 0; i < ARRAY_SIZE(mc_cg_registers); i++) {
+ orig = data = RREG32(mc_cg_registers[i]);
+ if (enable)
+ data |= MC_LS_ENABLE;
+ else
+ data &= ~MC_LS_ENABLE;
+ if (data != orig)
+ WREG32(mc_cg_registers[i], data);
+ }
+}
+
+
+static void si_init_cg(struct radeon_device *rdev)
+{
+ bool has_uvd = true;
+
+ si_enable_mgcg(rdev, true);
+ si_enable_cgcg(rdev, true);
+ /* disable MC LS on Tahiti */
+ if (rdev->family == CHIP_TAHITI)
+ si_enable_mc_ls(rdev, false);
+ if (has_uvd) {
+ si_enable_uvd_mgcg(rdev, true);
+ si_init_uvd_internal_cg(rdev);
+ }
+}
+
+static void si_fini_cg(struct radeon_device *rdev)
+{
+ bool has_uvd = true;
+
+ if (has_uvd)
+ si_enable_uvd_mgcg(rdev, false);
+ si_enable_cgcg(rdev, false);
+ si_enable_mgcg(rdev, false);
+}
+
+static void si_init_pg(struct radeon_device *rdev)
+{
+ bool has_pg = false;
+
+ /* only cape verde supports PG */
+ if (rdev->family == CHIP_VERDE)
+ has_pg = true;
+
+ if (has_pg) {
+ si_init_ao_cu_mask(rdev);
+ si_init_dma_pg(rdev);
+ si_enable_dma_pg(rdev, true);
+ si_init_gfx_cgpg(rdev);
+ si_enable_gfx_cgpg(rdev, true);
+ } else {
+ WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+ WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+ }
+}
+
+static void si_fini_pg(struct radeon_device *rdev)
+{
+ bool has_pg = false;
+
+ /* only cape verde supports PG */
+ if (rdev->family == CHIP_VERDE)
+ has_pg = true;
+
+ if (has_pg) {
+ si_enable_dma_pg(rdev, false);
+ si_enable_gfx_cgpg(rdev, false);
+ }
+}
+
+/*
* RLC
*/
void si_rlc_fini(struct radeon_device *rdev)
@@ -4313,8 +5051,15 @@ void si_rlc_fini(struct radeon_device *rdev)
}
}
+#define RLC_CLEAR_STATE_END_MARKER 0x00000001
+
int si_rlc_init(struct radeon_device *rdev)
{
+ volatile u32 *dst_ptr;
+ u32 dws, data, i, j, k, reg_num;
+ u32 reg_list_num, reg_list_hdr_blk_index, reg_list_blk_index;
+ u64 reg_list_mc_addr;
+ const struct cs_section_def *cs_data = si_cs_data;
int r;
/* save restore block */
@@ -4335,18 +5080,44 @@ int si_rlc_init(struct radeon_device *rdev)
}
r = radeon_bo_pin(rdev->rlc.save_restore_obj, RADEON_GEM_DOMAIN_VRAM,
&rdev->rlc.save_restore_gpu_addr);
- radeon_bo_unreserve(rdev->rlc.save_restore_obj);
if (r) {
+ radeon_bo_unreserve(rdev->rlc.save_restore_obj);
dev_warn(rdev->dev, "(%d) pin RLC sr bo failed\n", r);
si_rlc_fini(rdev);
return r;
}
+ if (rdev->family == CHIP_VERDE) {
+ r = radeon_bo_kmap(rdev->rlc.save_restore_obj, (void **)&rdev->rlc.sr_ptr);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map RLC sr bo failed\n", r);
+ si_rlc_fini(rdev);
+ return r;
+ }
+ /* write the sr buffer */
+ dst_ptr = rdev->rlc.sr_ptr;
+ for (i = 0; i < ARRAY_SIZE(verde_rlc_save_restore_register_list); i++) {
+ dst_ptr[i] = verde_rlc_save_restore_register_list[i];
+ }
+ radeon_bo_kunmap(rdev->rlc.save_restore_obj);
+ }
+ radeon_bo_unreserve(rdev->rlc.save_restore_obj);
+
/* clear state block */
+ reg_list_num = 0;
+ dws = 0;
+ for (i = 0; cs_data[i].section != NULL; i++) {
+ for (j = 0; cs_data[i].section[j].extent != NULL; j++) {
+ reg_list_num++;
+ dws += cs_data[i].section[j].reg_count;
+ }
+ }
+ reg_list_blk_index = (3 * reg_list_num + 2);
+ dws += reg_list_blk_index;
+
if (rdev->rlc.clear_state_obj == NULL) {
- r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_VRAM, NULL,
- &rdev->rlc.clear_state_obj);
+ r = radeon_bo_create(rdev, dws * 4, PAGE_SIZE, true,
+ RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->rlc.clear_state_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
si_rlc_fini(rdev);
@@ -4360,24 +5131,113 @@ int si_rlc_init(struct radeon_device *rdev)
}
r = radeon_bo_pin(rdev->rlc.clear_state_obj, RADEON_GEM_DOMAIN_VRAM,
&rdev->rlc.clear_state_gpu_addr);
- radeon_bo_unreserve(rdev->rlc.clear_state_obj);
if (r) {
+
+ radeon_bo_unreserve(rdev->rlc.clear_state_obj);
dev_warn(rdev->dev, "(%d) pin RLC c bo failed\n", r);
si_rlc_fini(rdev);
return r;
}
+ r = radeon_bo_kmap(rdev->rlc.clear_state_obj, (void **)&rdev->rlc.cs_ptr);
+ if (r) {
+ dev_warn(rdev->dev, "(%d) map RLC c bo failed\n", r);
+ si_rlc_fini(rdev);
+ return r;
+ }
+ /* set up the cs buffer */
+ dst_ptr = rdev->rlc.cs_ptr;
+ reg_list_hdr_blk_index = 0;
+ reg_list_mc_addr = rdev->rlc.clear_state_gpu_addr + (reg_list_blk_index * 4);
+ data = upper_32_bits(reg_list_mc_addr);
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+ for (i = 0; cs_data[i].section != NULL; i++) {
+ for (j = 0; cs_data[i].section[j].extent != NULL; j++) {
+ reg_num = cs_data[i].section[j].reg_count;
+ data = reg_list_mc_addr & 0xffffffff;
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+
+ data = (cs_data[i].section[j].reg_index * 4) & 0xffffffff;
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+
+ data = 0x08000000 | (reg_num * 4);
+ dst_ptr[reg_list_hdr_blk_index] = data;
+ reg_list_hdr_blk_index++;
+
+ for (k = 0; k < reg_num; k++) {
+ data = cs_data[i].section[j].extent[k];
+ dst_ptr[reg_list_blk_index + k] = data;
+ }
+ reg_list_mc_addr += reg_num * 4;
+ reg_list_blk_index += reg_num;
+ }
+ }
+ dst_ptr[reg_list_hdr_blk_index] = RLC_CLEAR_STATE_END_MARKER;
+
+ radeon_bo_kunmap(rdev->rlc.clear_state_obj);
+ radeon_bo_unreserve(rdev->rlc.clear_state_obj);
return 0;
}
+static void si_rlc_reset(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(GRBM_SOFT_RESET);
+
+ tmp |= SOFT_RESET_RLC;
+ WREG32(GRBM_SOFT_RESET, tmp);
+ udelay(50);
+ tmp &= ~SOFT_RESET_RLC;
+ WREG32(GRBM_SOFT_RESET, tmp);
+ udelay(50);
+}
+
static void si_rlc_stop(struct radeon_device *rdev)
{
WREG32(RLC_CNTL, 0);
+
+ si_enable_gui_idle_interrupt(rdev, false);
+
+ si_wait_for_rlc_serdes(rdev);
}
static void si_rlc_start(struct radeon_device *rdev)
{
WREG32(RLC_CNTL, RLC_ENABLE);
+
+ si_enable_gui_idle_interrupt(rdev, true);
+
+ udelay(50);
+}
+
+static bool si_lbpw_supported(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ /* Enable LBPW only for DDR3 */
+ tmp = RREG32(MC_SEQ_MISC0);
+ if ((tmp & 0xF0000000) == 0xB0000000)
+ return true;
+ return false;
+}
+
+static void si_enable_lbpw(struct radeon_device *rdev, bool enable)
+{
+ u32 tmp;
+
+ tmp = RREG32(RLC_LB_CNTL);
+ if (enable)
+ tmp |= LOAD_BALANCE_ENABLE;
+ else
+ tmp &= ~LOAD_BALANCE_ENABLE;
+ WREG32(RLC_LB_CNTL, tmp);
+
+ if (!enable) {
+ si_select_se_sh(rdev, 0xffffffff, 0xffffffff);
+ WREG32(SPI_LB_CU_MASK, 0x00ff);
+ }
}
static int si_rlc_resume(struct radeon_device *rdev)
@@ -4390,14 +5250,18 @@ static int si_rlc_resume(struct radeon_device *rdev)
si_rlc_stop(rdev);
+ si_rlc_reset(rdev);
+
+ si_init_pg(rdev);
+
+ si_init_cg(rdev);
+
WREG32(RLC_RL_BASE, 0);
WREG32(RLC_RL_SIZE, 0);
WREG32(RLC_LB_CNTL, 0);
WREG32(RLC_LB_CNTR_MAX, 0xffffffff);
WREG32(RLC_LB_CNTR_INIT, 0);
-
- WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
- WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
+ WREG32(RLC_LB_INIT_CU_MASK, 0xffffffff);
WREG32(RLC_MC_CNTL, 0);
WREG32(RLC_UCODE_CNTL, 0);
@@ -4409,6 +5273,8 @@ static int si_rlc_resume(struct radeon_device *rdev)
}
WREG32(RLC_UCODE_ADDR, 0);
+ si_enable_lbpw(rdev, si_lbpw_supported(rdev));
+
si_rlc_start(rdev);
return 0;
@@ -4578,6 +5444,7 @@ int si_irq_set(struct radeon_device *rdev)
u32 grbm_int_cntl = 0;
u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
u32 dma_cntl, dma_cntl1;
+ u32 thermal_int = 0;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -4603,6 +5470,9 @@ int si_irq_set(struct radeon_device *rdev)
dma_cntl = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
dma_cntl1 = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
+ thermal_int = RREG32(CG_THERMAL_INT) &
+ ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
+
/* enable CP interrupts on all rings */
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
DRM_DEBUG("si_irq_set: sw int gfx\n");
@@ -4689,6 +5559,11 @@ int si_irq_set(struct radeon_device *rdev)
WREG32(GRBM_INT_CNTL, grbm_int_cntl);
+ if (rdev->irq.dpm_thermal) {
+ DRM_DEBUG("dpm thermal\n");
+ thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
+ }
+
if (rdev->num_crtc >= 2) {
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2);
@@ -4724,6 +5599,8 @@ int si_irq_set(struct radeon_device *rdev)
WREG32(DC_HPD6_INT_CONTROL, hpd6);
}
+ WREG32(CG_THERMAL_INT, thermal_int);
+
return 0;
}
@@ -4888,6 +5765,7 @@ int si_irq_process(struct radeon_device *rdev)
u32 src_id, src_data, ring_id;
u32 ring_index;
bool queue_hotplug = false;
+ bool queue_thermal = false;
if (!rdev->ih.enabled || rdev->shutdown)
return IRQ_NONE;
@@ -5158,6 +6036,16 @@ restart_ih:
DRM_DEBUG("IH: DMA trap\n");
radeon_fence_process(rdev, R600_RING_TYPE_DMA_INDEX);
break;
+ case 230: /* thermal low to high */
+ DRM_DEBUG("IH: thermal low to high\n");
+ rdev->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");
+ rdev->pm.dpm.thermal.high_to_low = true;
+ queue_thermal = true;
+ break;
case 233: /* GUI IDLE */
DRM_DEBUG("IH: GUI idle\n");
break;
@@ -5176,6 +6064,8 @@ restart_ih:
}
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
+ if (queue_thermal && rdev->pm.dpm_enabled)
+ schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
atomic_set(&rdev->ih.lock, 0);
@@ -5270,6 +6160,11 @@ static int si_startup(struct radeon_device *rdev)
struct radeon_ring *ring;
int r;
+ /* enable pcie gen2/3 link */
+ si_pcie_gen3_enable(rdev);
+ /* enable aspm */
+ si_program_aspm(rdev);
+
if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
!rdev->rlc_fw || !rdev->mc_fw) {
r = si_init_microcode(rdev);
@@ -5609,6 +6504,8 @@ void si_fini(struct radeon_device *rdev)
cayman_dma_fini(rdev);
si_irq_fini(rdev);
si_rlc_fini(rdev);
+ si_fini_cg(rdev);
+ si_fini_pg(rdev);
radeon_wb_fini(rdev);
radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev);
@@ -5735,3 +6632,361 @@ int si_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
return 0;
}
+
+static void si_pcie_gen3_enable(struct radeon_device *rdev)
+{
+ struct pci_dev *root = rdev->pdev->bus->self;
+ int bridge_pos, gpu_pos;
+ u32 speed_cntl, mask, current_data_rate;
+ int ret, i;
+ u16 tmp16;
+
+ if (radeon_pcie_gen2 == 0)
+ return;
+
+ if (rdev->flags & RADEON_IS_IGP)
+ return;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask);
+ if (ret != 0)
+ return;
+
+ if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+ return;
+
+ speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >>
+ 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 radeon.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 radeon.pcie_gen2=0\n");
+ }
+
+ bridge_pos = pci_pcie_cap(root);
+ if (!bridge_pos)
+ return;
+
+ gpu_pos = pci_pcie_cap(rdev->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(rdev->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(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, tmp16);
+
+ tmp = RREG32_PCIE(PCIE_LC_STATUS1);
+ max_lw = (tmp & LC_DETECTED_LINK_WIDTH_MASK) >> LC_DETECTED_LINK_WIDTH_SHIFT;
+ current_lw = (tmp & LC_OPERATING_LINK_WIDTH_MASK) >> LC_OPERATING_LINK_WIDTH_SHIFT;
+
+ if (current_lw < max_lw) {
+ tmp = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+ if (tmp & LC_RENEGOTIATION_SUPPORT) {
+ tmp &= ~(LC_LINK_WIDTH_MASK | LC_UPCONFIGURE_DIS);
+ tmp |= (max_lw << LC_LINK_WIDTH_SHIFT);
+ tmp |= LC_UPCONFIGURE_SUPPORT | LC_RENEGOTIATE_EN | LC_RECONFIG_NOW;
+ WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, tmp);
+ }
+ }
+
+ for (i = 0; i < 10; i++) {
+ /* check status */
+ pci_read_config_word(rdev->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(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &gpu_cfg);
+
+ pci_read_config_word(root, bridge_pos + PCI_EXP_LNKCTL2, &bridge_cfg2);
+ pci_read_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &gpu_cfg2);
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
+ tmp |= LC_SET_QUIESCE;
+ WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp);
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
+ tmp |= LC_REDO_EQ;
+ WREG32_PCIE_PORT(PCIE_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(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL, &tmp16);
+ tmp16 &= ~PCI_EXP_LNKCTL_HAWD;
+ tmp16 |= (gpu_cfg & PCI_EXP_LNKCTL_HAWD);
+ pci_write_config_word(rdev->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(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
+ tmp16 &= ~((1 << 4) | (7 << 9));
+ tmp16 |= (gpu_cfg2 & ((1 << 4) | (7 << 9)));
+ pci_write_config_word(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+
+ tmp = RREG32_PCIE_PORT(PCIE_LC_CNTL4);
+ tmp &= ~LC_SET_QUIESCE;
+ WREG32_PCIE_PORT(PCIE_LC_CNTL4, tmp);
+ }
+ }
+ }
+
+ /* set the link speed */
+ speed_cntl |= LC_FORCE_EN_SW_SPEED_CHANGE | LC_FORCE_DIS_HW_SPEED_CHANGE;
+ speed_cntl &= ~LC_FORCE_DIS_SW_SPEED_CHANGE;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ pci_read_config_word(rdev->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(rdev->pdev, gpu_pos + PCI_EXP_LNKCTL2, tmp16);
+
+ speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ speed_cntl |= LC_INITIATE_LINK_SPEED_CHANGE;
+ WREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL, speed_cntl);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
+ if ((speed_cntl & LC_INITIATE_LINK_SPEED_CHANGE) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void si_program_aspm(struct radeon_device *rdev)
+{
+ u32 data, orig;
+ bool disable_l0s = false, disable_l1 = false, disable_plloff_in_l1 = false;
+ bool disable_clkreq = false;
+
+ if (!(rdev->flags & RADEON_IS_PCIE))
+ return;
+
+ orig = data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL);
+ data &= ~LC_XMIT_N_FTS_MASK;
+ data |= LC_XMIT_N_FTS(0x24) | LC_XMIT_N_FTS_OVERRIDE_EN;
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL, data);
+
+ orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL3);
+ data |= LC_GO_TO_RECOVERY;
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_CNTL3, data);
+
+ orig = data = RREG32_PCIE(PCIE_P_CNTL);
+ data |= P_IGNORE_EDB_ERR;
+ if (orig != data)
+ WREG32_PCIE(PCIE_P_CNTL, data);
+
+ orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+ data &= ~(LC_L0S_INACTIVITY_MASK | LC_L1_INACTIVITY_MASK);
+ data |= LC_PMI_TO_L1_DIS;
+ if (!disable_l0s)
+ data |= LC_L0S_INACTIVITY(7);
+
+ if (!disable_l1) {
+ data |= LC_L1_INACTIVITY(7);
+ data &= ~LC_PMI_TO_L1_DIS;
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, data);
+
+ if (!disable_plloff_in_l1) {
+ bool clk_req_support;
+
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
+ data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
+
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
+ data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
+ data &= ~(PLL_POWER_STATE_IN_OFF_0_MASK | PLL_POWER_STATE_IN_TXS2_0_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_0(7) | PLL_POWER_STATE_IN_TXS2_0(7);
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
+ data &= ~(PLL_POWER_STATE_IN_OFF_1_MASK | PLL_POWER_STATE_IN_TXS2_1_MASK);
+ data |= PLL_POWER_STATE_IN_OFF_1(7) | PLL_POWER_STATE_IN_TXS2_1(7);
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
+
+ if ((rdev->family != CHIP_OLAND) && (rdev->family != CHIP_HAINAN)) {
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0);
+ data &= ~PLL_RAMP_UP_TIME_0_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_0, data);
+
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1);
+ data &= ~PLL_RAMP_UP_TIME_1_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_1, data);
+
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_2);
+ data &= ~PLL_RAMP_UP_TIME_2_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_2, data);
+
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_PWRDOWN_3);
+ data &= ~PLL_RAMP_UP_TIME_3_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_PWRDOWN_3, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0);
+ data &= ~PLL_RAMP_UP_TIME_0_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_0, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1);
+ data &= ~PLL_RAMP_UP_TIME_1_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_1, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_2);
+ data &= ~PLL_RAMP_UP_TIME_2_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_2, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_PWRDOWN_3);
+ data &= ~PLL_RAMP_UP_TIME_3_MASK;
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_PWRDOWN_3, data);
+ }
+ orig = data = RREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL);
+ data &= ~LC_DYN_LANES_PWR_STATE_MASK;
+ data |= LC_DYN_LANES_PWR_STATE(3);
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_LINK_WIDTH_CNTL, data);
+
+ orig = data = RREG32_PIF_PHY0(PB0_PIF_CNTL);
+ data &= ~LS2_EXIT_TIME_MASK;
+ if ((rdev->family == CHIP_OLAND) || (rdev->family == CHIP_HAINAN))
+ data |= LS2_EXIT_TIME(5);
+ if (orig != data)
+ WREG32_PIF_PHY0(PB0_PIF_CNTL, data);
+
+ orig = data = RREG32_PIF_PHY1(PB1_PIF_CNTL);
+ data &= ~LS2_EXIT_TIME_MASK;
+ if ((rdev->family == CHIP_OLAND) || (rdev->family == CHIP_HAINAN))
+ data |= LS2_EXIT_TIME(5);
+ if (orig != data)
+ WREG32_PIF_PHY1(PB1_PIF_CNTL, data);
+
+ if (!disable_clkreq) {
+ struct pci_dev *root = rdev->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_PORT(PCIE_LC_CNTL2);
+ data |= LC_ALLOW_PDWN_IN_L1 | LC_ALLOW_PDWN_IN_L23;
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_CNTL2, data);
+
+ orig = data = RREG32(THM_CLK_CNTL);
+ data &= ~(CMON_CLK_SEL_MASK | TMON_CLK_SEL_MASK);
+ data |= CMON_CLK_SEL(1) | TMON_CLK_SEL(1);
+ if (orig != data)
+ WREG32(THM_CLK_CNTL, data);
+
+ orig = data = RREG32(MISC_CLK_CNTL);
+ data &= ~(DEEP_SLEEP_CLK_SEL_MASK | ZCLK_SEL_MASK);
+ data |= DEEP_SLEEP_CLK_SEL(1) | ZCLK_SEL(1);
+ if (orig != data)
+ WREG32(MISC_CLK_CNTL, data);
+
+ orig = data = RREG32(CG_CLKPIN_CNTL);
+ data &= ~BCLK_AS_XCLK;
+ if (orig != data)
+ WREG32(CG_CLKPIN_CNTL, data);
+
+ orig = data = RREG32(CG_CLKPIN_CNTL_2);
+ data &= ~FORCE_BIF_REFCLK_EN;
+ if (orig != data)
+ WREG32(CG_CLKPIN_CNTL_2, data);
+
+ orig = data = RREG32(MPLL_BYPASSCLK_SEL);
+ data &= ~MPLL_CLKOUT_SEL_MASK;
+ data |= MPLL_CLKOUT_SEL(4);
+ if (orig != data)
+ WREG32(MPLL_BYPASSCLK_SEL, data);
+
+ orig = data = RREG32(SPLL_CNTL_MODE);
+ data &= ~SPLL_REFCLK_SEL_MASK;
+ if (orig != data)
+ WREG32(SPLL_CNTL_MODE, data);
+ }
+ }
+ } else {
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, data);
+ }
+
+ orig = data = RREG32_PCIE(PCIE_CNTL2);
+ data |= SLV_MEM_LS_EN | MST_MEM_LS_EN | REPLAY_MEM_LS_EN;
+ if (orig != data)
+ WREG32_PCIE(PCIE_CNTL2, data);
+
+ if (!disable_l0s) {
+ data = RREG32_PCIE_PORT(PCIE_LC_N_FTS_CNTL);
+ if((data & LC_N_FTS_MASK) == LC_N_FTS_MASK) {
+ data = RREG32_PCIE(PCIE_LC_STATUS1);
+ if ((data & LC_REVERSE_XMIT) && (data & LC_REVERSE_RCVR)) {
+ orig = data = RREG32_PCIE_PORT(PCIE_LC_CNTL);
+ data &= ~LC_L0S_INACTIVITY_MASK;
+ if (orig != data)
+ WREG32_PCIE_PORT(PCIE_LC_CNTL, data);
+ }
+ }
+ }
+}
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
new file mode 100644
index 000000000000..73aaa2e4c312
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -0,0 +1,6432 @@
+/*
+ * 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 "drmP.h"
+#include "radeon.h"
+#include "sid.h"
+#include "r600_dpm.h"
+#include "si_dpm.h"
+#include "atom.h"
+#include <linux/math64.h>
+#include <linux/seq_file.h>
+
+#define MC_CG_ARB_FREQ_F0 0x0a
+#define MC_CG_ARB_FREQ_F1 0x0b
+#define MC_CG_ARB_FREQ_F2 0x0c
+#define MC_CG_ARB_FREQ_F3 0x0d
+
+#define SMC_RAM_END 0x20000
+
+#define DDR3_DRAM_ROWS 0x2000
+
+#define SCLK_MIN_DEEPSLEEP_FREQ 1350
+
+static const struct si_cac_config_reg cac_weights_tahiti[] =
+{
+ { 0x0, 0x0000ffff, 0, 0xc, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x101, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0xc, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x8fc, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x95, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x34e, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x1a1, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0xda, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x46, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x208, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0xe7, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x948, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x167, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x31, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x18e, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_tahiti[] =
+{
+ { 0x143, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x146, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x149, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14c, 0x0001fffe, 1, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x92, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x95, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x152, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x155, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x158, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x113, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x116, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x119, 0x0001fffe, 1, 0x8, SISLANDS_CACCONFIG_CGIND },
+ { 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+
+};
+
+static const struct si_cac_config_reg cac_override_tahiti[] =
+{
+ { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_tahiti =
+{
+ ((1 << 16) | 27027),
+ 6,
+ 0,
+ 4,
+ 95,
+ {
+ 0UL,
+ 0UL,
+ 4521550UL,
+ 309631529UL,
+ -1270850L,
+ 4513710L,
+ 40
+ },
+ 595000000UL,
+ 12,
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ true
+};
+
+static const struct si_dte_data dte_data_tahiti =
+{
+ { 1159409, 0, 0, 0, 0 },
+ { 777, 0, 0, 0, 0 },
+ 2,
+ 54000,
+ 127000,
+ 25,
+ 2,
+ 10,
+ 13,
+ { 27, 31, 35, 39, 43, 47, 54, 61, 67, 74, 81, 88, 95, 0, 0, 0 },
+ { 240888759, 221057860, 235370597, 162287531, 158510299, 131423027, 116673180, 103067515, 87941937, 76209048, 68209175, 64090048, 58301890, 0, 0, 0 },
+ { 12024, 11189, 11451, 8411, 7939, 6666, 5681, 4905, 4241, 3720, 3354, 3122, 2890, 0, 0, 0 },
+ 85,
+ false
+};
+
+static const struct si_dte_data dte_data_tahiti_le =
+{
+ { 0x1E8480, 0x7A1200, 0x2160EC0, 0x3938700, 0 },
+ { 0x7D, 0x7D, 0x4E4, 0xB00, 0 },
+ 0x5,
+ 0xAFC8,
+ 0x64,
+ 0x32,
+ 1,
+ 0,
+ 0x10,
+ { 0x78, 0x7C, 0x82, 0x88, 0x8E, 0x94, 0x9A, 0xA0, 0xA6, 0xAC, 0xB0, 0xB4, 0xB8, 0xBC, 0xC0, 0xC4 },
+ { 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700, 0x3938700 },
+ { 0x2AF8, 0x2AF8, 0x29BB, 0x27F9, 0x2637, 0x2475, 0x22B3, 0x20F1, 0x1F2F, 0x1D6D, 0x1734, 0x1414, 0x10F4, 0xDD4, 0xAB4, 0x794 },
+ 85,
+ true
+};
+
+static const struct si_dte_data dte_data_tahiti_pro =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 45000,
+ 100,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0x7D0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_new_zealand =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0 },
+ { 0x29B, 0x3E9, 0x537, 0x7D2, 0 },
+ 0x5,
+ 0xAFC8,
+ 0x69,
+ 0x32,
+ 1,
+ 0,
+ 0x10,
+ { 0x82, 0xA0, 0xB4, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0xDAC, 0x1388, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685, 0x685 },
+ 85,
+ true
+};
+
+static const struct si_dte_data dte_data_aruba_pro =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 45000,
+ 100,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0x1000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_malta =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 45000,
+ 100,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+struct si_cac_config_reg cac_weights_pitcairn[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x8a, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x24d, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x19, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0xc11, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x7f3, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x403, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x367, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x4c9, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x45d, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x36d, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x534, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x5da, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x880, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0x201, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x1f, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5de, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x7b, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x13, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0xf9, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x66, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x13, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x186, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_pitcairn[] =
+{
+ { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x146, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x9e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x9e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x116, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x116, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x155, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x155, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x92, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x92, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x149, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x149, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x101, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x101, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x119, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x119, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x158, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x158, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x95, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x95, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x14c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x122, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x122, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x125, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x125, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x128, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x128, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x12b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x12b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_override_pitcairn[] =
+{
+ { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_pitcairn =
+{
+ ((1 << 16) | 27027),
+ 5,
+ 0,
+ 6,
+ 100,
+ {
+ 51600000UL,
+ 1800000UL,
+ 7194395UL,
+ 309631529UL,
+ -1270850L,
+ 4513710L,
+ 100
+ },
+ 117830498UL,
+ 12,
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ true
+};
+
+static const struct si_dte_data dte_data_pitcairn =
+{
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 0,
+ false
+};
+
+static const struct si_dte_data dte_data_curacao_xt =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 45000,
+ 100,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_curacao_pro =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 45000,
+ 100,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0x1D17, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_neptune_xt =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 45000,
+ 100,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0x3A2F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_cac_config_reg cac_weights_chelsea_pro[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x2BD, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_chelsea_xt[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x30A, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_heathrow[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x362, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_cape_verde_pro[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x315, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_cape_verde[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_cape_verde[] =
+{
+ { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x9b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x9b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x107, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x107, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x113, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x113, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x152, 0x0001fffe, 1, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x152, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x146, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x146, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_override_cape_verde[] =
+{
+ { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_cape_verde =
+{
+ ((1 << 16) | 0x6993),
+ 5,
+ 0,
+ 7,
+ 105,
+ {
+ 0UL,
+ 0UL,
+ 7194395UL,
+ 309631529UL,
+ -1270850L,
+ 4513710L,
+ 100
+ },
+ 117830498UL,
+ 12,
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ true
+};
+
+static const struct si_dte_data dte_data_cape_verde =
+{
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 0,
+ false
+};
+
+static const struct si_dte_data dte_data_venus_xtx =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x71C, 0xAAB, 0xE39, 0x11C7, 0x0 },
+ 5,
+ 55000,
+ 0x69,
+ 0xA,
+ 1,
+ 0,
+ 0x3,
+ { 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ { 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ { 0xD6D8, 0x88B8, 0x1555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_venus_xt =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0xBDA, 0x11C7, 0x17B4, 0x1DA1, 0x0 },
+ 5,
+ 55000,
+ 0x69,
+ 0xA,
+ 1,
+ 0,
+ 0x3,
+ { 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ { 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ { 0xAFC8, 0x88B8, 0x238E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_venus_pro =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x11C7, 0x1AAB, 0x238E, 0x2C72, 0x0 },
+ 5,
+ 55000,
+ 0x69,
+ 0xA,
+ 1,
+ 0,
+ 0x3,
+ { 0x96, 0xB4, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ { 0x895440, 0x3D0900, 0x989680, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ { 0x88B8, 0x88B8, 0x3555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+struct si_cac_config_reg cac_weights_oland[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x82, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x153, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x52, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x4F, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x135, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0xAC, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x118, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0xBE, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x110, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x4CD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x37, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x27, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0xC3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x35, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0x28, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x26C, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3B2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x99D, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA3F, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0xA, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x34, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x3BA, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x30, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7A, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x100, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_mars_pro[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_mars_xt[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x60, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_oland_pro[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x90, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_weights_oland_xt[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x43, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0xAF, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x2A, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x29, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0xA0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x59, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x1A5, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x1D6, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0x2A3, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x8FD, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x76, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x8A, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0xA3, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x71, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0xA6, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x81, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0x3D2, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0x27C, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xA96, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x5, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0xB, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x15, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x36, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x10, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x120, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x32, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x7E, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0x280, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0x7, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0x3C, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0x203, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0xB4, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_oland[] =
+{
+ { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x0001fffe, 1, 0x4, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg lcac_mars_pro[] =
+{
+ { 0x98, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x98, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x104, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x110, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x14f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x0001fffe, 1, 0x6, SISLANDS_CACCONFIG_CGIND },
+ { 0x8c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x143, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x11f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x164, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x167, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16a, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15e, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x161, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x15b, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x0001fffe, 1, 0x2, SISLANDS_CACCONFIG_CGIND },
+ { 0x16d, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x170, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x173, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x176, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x179, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17c, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x0001fffe, 1, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0x17f, 0x00000001, 0, 0x1, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_cac_config_reg cac_override_oland[] =
+{
+ { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_oland =
+{
+ ((1 << 16) | 0x6993),
+ 5,
+ 0,
+ 7,
+ 105,
+ {
+ 0UL,
+ 0UL,
+ 7194395UL,
+ 309631529UL,
+ -1270850L,
+ 4513710L,
+ 100
+ },
+ 117830498UL,
+ 12,
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ true
+};
+
+static const struct si_powertune_data powertune_data_mars_pro =
+{
+ ((1 << 16) | 0x6993),
+ 5,
+ 0,
+ 7,
+ 105,
+ {
+ 0UL,
+ 0UL,
+ 7194395UL,
+ 309631529UL,
+ -1270850L,
+ 4513710L,
+ 100
+ },
+ 117830498UL,
+ 12,
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ true
+};
+
+static const struct si_dte_data dte_data_oland =
+{
+ { 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0 },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ 0,
+ false
+};
+
+static const struct si_dte_data dte_data_mars_pro =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 55000,
+ 105,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0xF627, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+static const struct si_dte_data dte_data_sun_xt =
+{
+ { 0x1E8480, 0x3D0900, 0x989680, 0x2625A00, 0x0 },
+ { 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 5,
+ 55000,
+ 105,
+ 0xA,
+ 1,
+ 0,
+ 0x10,
+ { 0x96, 0xB4, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 0x895440, 0x3D0900, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680, 0x989680 },
+ { 0xD555, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 },
+ 90,
+ true
+};
+
+
+static const struct si_cac_config_reg cac_weights_hainan[] =
+{
+ { 0x0, 0x0000ffff, 0, 0x2d9, SISLANDS_CACCONFIG_CGIND },
+ { 0x0, 0xffff0000, 16, 0x22b, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0x0000ffff, 0, 0x21c, SISLANDS_CACCONFIG_CGIND },
+ { 0x1, 0xffff0000, 16, 0x1dc, SISLANDS_CACCONFIG_CGIND },
+ { 0x2, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0x0000ffff, 0, 0x24e, SISLANDS_CACCONFIG_CGIND },
+ { 0x3, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0x0000ffff, 0, 0x35e, SISLANDS_CACCONFIG_CGIND },
+ { 0x5, 0xffff0000, 16, 0x1143, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0x0000ffff, 0, 0xe17, SISLANDS_CACCONFIG_CGIND },
+ { 0x6, 0xffff0000, 16, 0x441, SISLANDS_CACCONFIG_CGIND },
+ { 0x18f, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0x0000ffff, 0, 0x28b, SISLANDS_CACCONFIG_CGIND },
+ { 0x7, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x8, 0xffff0000, 16, 0xabe, SISLANDS_CACCONFIG_CGIND },
+ { 0x9, 0x0000ffff, 0, 0xf11, SISLANDS_CACCONFIG_CGIND },
+ { 0xa, 0x0000ffff, 0, 0x907, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0x0000ffff, 0, 0xb45, SISLANDS_CACCONFIG_CGIND },
+ { 0xb, 0xffff0000, 16, 0xd1e, SISLANDS_CACCONFIG_CGIND },
+ { 0xc, 0x0000ffff, 0, 0xa2c, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0x0000ffff, 0, 0x62, SISLANDS_CACCONFIG_CGIND },
+ { 0xd, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0xe, 0x0000ffff, 0, 0x1f3, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0x0000ffff, 0, 0x42, SISLANDS_CACCONFIG_CGIND },
+ { 0xf, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x10, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0x0000ffff, 0, 0x709, SISLANDS_CACCONFIG_CGIND },
+ { 0x11, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x12, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x13, 0xffff0000, 16, 0x3a, SISLANDS_CACCONFIG_CGIND },
+ { 0x14, 0x0000ffff, 0, 0x357, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0x0000ffff, 0, 0x9f, SISLANDS_CACCONFIG_CGIND },
+ { 0x15, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x4e, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0x0000ffff, 0, 0x314, SISLANDS_CACCONFIG_CGIND },
+ { 0x16, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x17, 0x0000ffff, 0, 0x6d, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x18, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0x0000ffff, 0, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x19, 0xffff0000, 16, 0x0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1a, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1b, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1c, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1d, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1e, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x1f, 0xffff0000, 16, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x20, 0x0000ffff, 0, 0, SISLANDS_CACCONFIG_CGIND },
+ { 0x6d, 0x0000ffff, 0, 0x1b9, SISLANDS_CACCONFIG_CGIND },
+ { 0xFFFFFFFF }
+};
+
+static const struct si_powertune_data powertune_data_hainan =
+{
+ ((1 << 16) | 0x6993),
+ 5,
+ 0,
+ 9,
+ 105,
+ {
+ 0UL,
+ 0UL,
+ 7194395UL,
+ 309631529UL,
+ -1270850L,
+ 4513710L,
+ 100
+ },
+ 117830498UL,
+ 12,
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ true
+};
+
+struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
+struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
+struct ni_power_info *ni_get_pi(struct radeon_device *rdev);
+struct ni_ps *ni_get_ps(struct radeon_ps *rps);
+
+static int si_populate_voltage_value(struct radeon_device *rdev,
+ const struct atom_voltage_table *table,
+ u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage);
+static int si_get_std_voltage_value(struct radeon_device *rdev,
+ SISLANDS_SMC_VOLTAGE_VALUE *voltage,
+ u16 *std_voltage);
+static int si_write_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 value);
+static int si_convert_power_level_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level);
+static int si_calculate_sclk_params(struct radeon_device *rdev,
+ u32 engine_clock,
+ SISLANDS_SMC_SCLK_VALUE *sclk);
+
+static struct si_power_info *si_get_pi(struct radeon_device *rdev)
+{
+ struct si_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coeffients *coeff,
+ u16 v, s32 t, u32 ileakage, u32 *leakage)
+{
+ s64 kt, kv, leakage_w, i_leakage, vddc;
+ s64 temperature, t_slope, t_intercept, av, bv, t_ref;
+
+ i_leakage = drm_int2fixp(ileakage / 100);
+ vddc = div64_s64(drm_int2fixp(v), 1000);
+ temperature = div64_s64(drm_int2fixp(t), 1000);
+
+ t_slope = div64_s64(drm_int2fixp(coeff->t_slope), 100000000);
+ t_intercept = div64_s64(drm_int2fixp(coeff->t_intercept), 100000000);
+ av = div64_s64(drm_int2fixp(coeff->av), 100000000);
+ bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
+ t_ref = drm_int2fixp(coeff->t_ref);
+
+ kt = drm_fixp_div(drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, temperature)),
+ drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, t_ref)));
+ kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));
+
+ leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
+
+ *leakage = drm_fixp2int(leakage_w * 1000);
+}
+
+static void si_calculate_leakage_for_v_and_t(struct radeon_device *rdev,
+ const struct ni_leakage_coeffients *coeff,
+ u16 v,
+ s32 t,
+ u32 i_leakage,
+ u32 *leakage)
+{
+ si_calculate_leakage_for_v_and_t_formula(coeff, v, t, i_leakage, leakage);
+}
+
+static void si_calculate_leakage_for_v_formula(const struct ni_leakage_coeffients *coeff,
+ const u32 fixed_kt, u16 v,
+ u32 ileakage, u32 *leakage)
+{
+ s64 kt, kv, leakage_w, i_leakage, vddc;
+
+ i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
+ vddc = div64_s64(drm_int2fixp(v), 1000);
+
+ kt = div64_s64(drm_int2fixp(fixed_kt), 100000000);
+ kv = drm_fixp_mul(div64_s64(drm_int2fixp(coeff->av), 100000000),
+ drm_fixp_exp(drm_fixp_mul(div64_s64(drm_int2fixp(coeff->bv), 100000000), vddc)));
+
+ leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
+
+ *leakage = drm_fixp2int(leakage_w * 1000);
+}
+
+static void si_calculate_leakage_for_v(struct radeon_device *rdev,
+ const struct ni_leakage_coeffients *coeff,
+ const u32 fixed_kt,
+ u16 v,
+ u32 i_leakage,
+ u32 *leakage)
+{
+ si_calculate_leakage_for_v_formula(coeff, fixed_kt, v, i_leakage, leakage);
+}
+
+
+static void si_update_dte_from_pl2(struct radeon_device *rdev,
+ struct si_dte_data *dte_data)
+{
+ u32 p_limit1 = rdev->pm.dpm.tdp_limit;
+ u32 p_limit2 = rdev->pm.dpm.near_tdp_limit;
+ u32 k = dte_data->k;
+ u32 t_max = dte_data->max_t;
+ u32 t_split[5] = { 10, 15, 20, 25, 30 };
+ u32 t_0 = dte_data->t0;
+ u32 i;
+
+ if (p_limit2 != 0 && p_limit2 <= p_limit1) {
+ dte_data->tdep_count = 3;
+
+ for (i = 0; i < k; i++) {
+ dte_data->r[i] =
+ (t_split[i] * (t_max - t_0/(u32)1000) * (1 << 14)) /
+ (p_limit2 * (u32)100);
+ }
+
+ dte_data->tdep_r[1] = dte_data->r[4] * 2;
+
+ for (i = 2; i < SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE; i++) {
+ dte_data->tdep_r[i] = dte_data->r[4];
+ }
+ } else {
+ DRM_ERROR("Invalid PL2! DTE will not be updated.\n");
+ }
+}
+
+static void si_initialize_powertune_defaults(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ bool update_dte_from_pl2 = false;
+
+ if (rdev->family == CHIP_TAHITI) {
+ si_pi->cac_weights = cac_weights_tahiti;
+ si_pi->lcac_config = lcac_tahiti;
+ si_pi->cac_override = cac_override_tahiti;
+ si_pi->powertune_data = &powertune_data_tahiti;
+ si_pi->dte_data = dte_data_tahiti;
+
+ switch (rdev->pdev->device) {
+ case 0x6798:
+ si_pi->dte_data.enable_dte_by_default = true;
+ break;
+ case 0x6799:
+ si_pi->dte_data = dte_data_new_zealand;
+ break;
+ case 0x6790:
+ case 0x6791:
+ case 0x6792:
+ case 0x679E:
+ si_pi->dte_data = dte_data_aruba_pro;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x679B:
+ si_pi->dte_data = dte_data_malta;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x679A:
+ si_pi->dte_data = dte_data_tahiti_pro;
+ update_dte_from_pl2 = true;
+ break;
+ default:
+ if (si_pi->dte_data.enable_dte_by_default == true)
+ DRM_ERROR("DTE is not enabled!\n");
+ break;
+ }
+ } else if (rdev->family == CHIP_PITCAIRN) {
+ switch (rdev->pdev->device) {
+ case 0x6810:
+ case 0x6818:
+ si_pi->cac_weights = cac_weights_pitcairn;
+ si_pi->lcac_config = lcac_pitcairn;
+ si_pi->cac_override = cac_override_pitcairn;
+ si_pi->powertune_data = &powertune_data_pitcairn;
+ si_pi->dte_data = dte_data_curacao_xt;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x6819:
+ case 0x6811:
+ si_pi->cac_weights = cac_weights_pitcairn;
+ si_pi->lcac_config = lcac_pitcairn;
+ si_pi->cac_override = cac_override_pitcairn;
+ si_pi->powertune_data = &powertune_data_pitcairn;
+ si_pi->dte_data = dte_data_curacao_pro;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x6800:
+ case 0x6806:
+ si_pi->cac_weights = cac_weights_pitcairn;
+ si_pi->lcac_config = lcac_pitcairn;
+ si_pi->cac_override = cac_override_pitcairn;
+ si_pi->powertune_data = &powertune_data_pitcairn;
+ si_pi->dte_data = dte_data_neptune_xt;
+ update_dte_from_pl2 = true;
+ break;
+ default:
+ si_pi->cac_weights = cac_weights_pitcairn;
+ si_pi->lcac_config = lcac_pitcairn;
+ si_pi->cac_override = cac_override_pitcairn;
+ si_pi->powertune_data = &powertune_data_pitcairn;
+ si_pi->dte_data = dte_data_pitcairn;
+ }
+ } else if (rdev->family == CHIP_VERDE) {
+ si_pi->lcac_config = lcac_cape_verde;
+ si_pi->cac_override = cac_override_cape_verde;
+ si_pi->powertune_data = &powertune_data_cape_verde;
+
+ switch (rdev->pdev->device) {
+ case 0x683B:
+ case 0x683F:
+ case 0x6829:
+ si_pi->cac_weights = cac_weights_cape_verde_pro;
+ si_pi->dte_data = dte_data_cape_verde;
+ break;
+ case 0x6825:
+ case 0x6827:
+ si_pi->cac_weights = cac_weights_heathrow;
+ si_pi->dte_data = dte_data_cape_verde;
+ break;
+ case 0x6824:
+ case 0x682D:
+ si_pi->cac_weights = cac_weights_chelsea_xt;
+ si_pi->dte_data = dte_data_cape_verde;
+ break;
+ case 0x682F:
+ si_pi->cac_weights = cac_weights_chelsea_pro;
+ si_pi->dte_data = dte_data_cape_verde;
+ break;
+ case 0x6820:
+ si_pi->cac_weights = cac_weights_heathrow;
+ si_pi->dte_data = dte_data_venus_xtx;
+ break;
+ case 0x6821:
+ si_pi->cac_weights = cac_weights_heathrow;
+ si_pi->dte_data = dte_data_venus_xt;
+ break;
+ case 0x6823:
+ si_pi->cac_weights = cac_weights_chelsea_pro;
+ si_pi->dte_data = dte_data_venus_pro;
+ break;
+ case 0x682B:
+ si_pi->cac_weights = cac_weights_chelsea_pro;
+ si_pi->dte_data = dte_data_venus_pro;
+ break;
+ default:
+ si_pi->cac_weights = cac_weights_cape_verde;
+ si_pi->dte_data = dte_data_cape_verde;
+ break;
+ }
+ } else if (rdev->family == CHIP_OLAND) {
+ switch (rdev->pdev->device) {
+ case 0x6601:
+ case 0x6621:
+ case 0x6603:
+ si_pi->cac_weights = cac_weights_mars_pro;
+ si_pi->lcac_config = lcac_mars_pro;
+ si_pi->cac_override = cac_override_oland;
+ si_pi->powertune_data = &powertune_data_mars_pro;
+ si_pi->dte_data = dte_data_mars_pro;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x6600:
+ case 0x6606:
+ case 0x6620:
+ si_pi->cac_weights = cac_weights_mars_xt;
+ si_pi->lcac_config = lcac_mars_pro;
+ si_pi->cac_override = cac_override_oland;
+ si_pi->powertune_data = &powertune_data_mars_pro;
+ si_pi->dte_data = dte_data_mars_pro;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x6611:
+ si_pi->cac_weights = cac_weights_oland_pro;
+ si_pi->lcac_config = lcac_mars_pro;
+ si_pi->cac_override = cac_override_oland;
+ si_pi->powertune_data = &powertune_data_mars_pro;
+ si_pi->dte_data = dte_data_mars_pro;
+ update_dte_from_pl2 = true;
+ break;
+ case 0x6610:
+ si_pi->cac_weights = cac_weights_oland_xt;
+ si_pi->lcac_config = lcac_mars_pro;
+ si_pi->cac_override = cac_override_oland;
+ si_pi->powertune_data = &powertune_data_mars_pro;
+ si_pi->dte_data = dte_data_mars_pro;
+ update_dte_from_pl2 = true;
+ break;
+ default:
+ si_pi->cac_weights = cac_weights_oland;
+ si_pi->lcac_config = lcac_oland;
+ si_pi->cac_override = cac_override_oland;
+ si_pi->powertune_data = &powertune_data_oland;
+ si_pi->dte_data = dte_data_oland;
+ break;
+ }
+ } else if (rdev->family == CHIP_HAINAN) {
+ si_pi->cac_weights = cac_weights_hainan;
+ si_pi->lcac_config = lcac_oland;
+ si_pi->cac_override = cac_override_oland;
+ si_pi->powertune_data = &powertune_data_hainan;
+ si_pi->dte_data = dte_data_sun_xt;
+ update_dte_from_pl2 = true;
+ } else {
+ DRM_ERROR("Unknown SI asic revision, failed to initialize PowerTune!\n");
+ return;
+ }
+
+ ni_pi->enable_power_containment = false;
+ ni_pi->enable_cac = false;
+ ni_pi->enable_sq_ramping = false;
+ si_pi->enable_dte = false;
+
+ if (si_pi->powertune_data->enable_powertune_by_default) {
+ ni_pi->enable_power_containment= true;
+ ni_pi->enable_cac = true;
+ if (si_pi->dte_data.enable_dte_by_default) {
+ si_pi->enable_dte = true;
+ if (update_dte_from_pl2)
+ si_update_dte_from_pl2(rdev, &si_pi->dte_data);
+
+ }
+ ni_pi->enable_sq_ramping = true;
+ }
+
+ ni_pi->driver_calculate_cac_leakage = true;
+ ni_pi->cac_configuration_required = true;
+
+ if (ni_pi->cac_configuration_required) {
+ ni_pi->support_cac_long_term_average = true;
+ si_pi->dyn_powertune_data.l2_lta_window_size =
+ si_pi->powertune_data->l2_lta_window_size_default;
+ si_pi->dyn_powertune_data.lts_truncate =
+ si_pi->powertune_data->lts_truncate_default;
+ } else {
+ ni_pi->support_cac_long_term_average = false;
+ si_pi->dyn_powertune_data.l2_lta_window_size = 0;
+ si_pi->dyn_powertune_data.lts_truncate = 0;
+ }
+
+ si_pi->dyn_powertune_data.disable_uvd_powertune = false;
+}
+
+static u32 si_get_smc_power_scaling_factor(struct radeon_device *rdev)
+{
+ return 1;
+}
+
+static u32 si_calculate_cac_wintime(struct radeon_device *rdev)
+{
+ u32 xclk;
+ u32 wintime;
+ u32 cac_window;
+ u32 cac_window_size;
+
+ xclk = radeon_get_xclk(rdev);
+
+ if (xclk == 0)
+ return 0;
+
+ cac_window = RREG32(CG_CAC_CTRL) & CAC_WINDOW_MASK;
+ cac_window_size = ((cac_window & 0xFFFF0000) >> 16) * (cac_window & 0x0000FFFF);
+
+ wintime = (cac_window_size * 100) / xclk;
+
+ return wintime;
+}
+
+static u32 si_scale_power_for_smc(u32 power_in_watts, u32 scaling_factor)
+{
+ return power_in_watts;
+}
+
+static int si_calculate_adjusted_tdp_limits(struct radeon_device *rdev,
+ bool adjust_polarity,
+ u32 tdp_adjustment,
+ u32 *tdp_limit,
+ u32 *near_tdp_limit)
+{
+ u32 adjustment_delta, max_tdp_limit;
+
+ if (tdp_adjustment > (u32)rdev->pm.dpm.tdp_od_limit)
+ return -EINVAL;
+
+ max_tdp_limit = ((100 + 100) * rdev->pm.dpm.tdp_limit) / 100;
+
+ if (adjust_polarity) {
+ *tdp_limit = ((100 + tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
+ *near_tdp_limit = rdev->pm.dpm.near_tdp_limit_adjusted + (*tdp_limit - rdev->pm.dpm.tdp_limit);
+ } else {
+ *tdp_limit = ((100 - tdp_adjustment) * rdev->pm.dpm.tdp_limit) / 100;
+ adjustment_delta = rdev->pm.dpm.tdp_limit - *tdp_limit;
+ if (adjustment_delta < rdev->pm.dpm.near_tdp_limit_adjusted)
+ *near_tdp_limit = rdev->pm.dpm.near_tdp_limit_adjusted - adjustment_delta;
+ else
+ *near_tdp_limit = 0;
+ }
+
+ if ((*tdp_limit <= 0) || (*tdp_limit > max_tdp_limit))
+ return -EINVAL;
+ if ((*near_tdp_limit <= 0) || (*near_tdp_limit > *tdp_limit))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int si_populate_smc_tdp_limits(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ if (ni_pi->enable_power_containment) {
+ SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
+ PP_SIslands_PAPMParameters *papm_parm;
+ struct radeon_ppm_table *ppm = rdev->pm.dpm.dyn_state.ppm_table;
+ u32 scaling_factor = si_get_smc_power_scaling_factor(rdev);
+ u32 tdp_limit;
+ u32 near_tdp_limit;
+ int ret;
+
+ if (scaling_factor == 0)
+ return -EINVAL;
+
+ memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));
+
+ ret = si_calculate_adjusted_tdp_limits(rdev,
+ false, /* ??? */
+ rdev->pm.dpm.tdp_adjustment,
+ &tdp_limit,
+ &near_tdp_limit);
+ if (ret)
+ return ret;
+
+ smc_table->dpm2Params.TDPLimit =
+ cpu_to_be32(si_scale_power_for_smc(tdp_limit, scaling_factor) * 1000);
+ smc_table->dpm2Params.NearTDPLimit =
+ cpu_to_be32(si_scale_power_for_smc(near_tdp_limit, scaling_factor) * 1000);
+ smc_table->dpm2Params.SafePowerLimit =
+ cpu_to_be32(si_scale_power_for_smc((near_tdp_limit * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);
+
+ ret = si_copy_bytes_to_smc(rdev,
+ (si_pi->state_table_start + offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
+ offsetof(PP_SIslands_DPM2Parameters, TDPLimit)),
+ (u8 *)(&(smc_table->dpm2Params.TDPLimit)),
+ sizeof(u32) * 3,
+ si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ if (si_pi->enable_ppm) {
+ papm_parm = &si_pi->papm_parm;
+ memset(papm_parm, 0, sizeof(PP_SIslands_PAPMParameters));
+ papm_parm->NearTDPLimitTherm = cpu_to_be32(ppm->dgpu_tdp);
+ papm_parm->dGPU_T_Limit = cpu_to_be32(ppm->tj_max);
+ papm_parm->dGPU_T_Warning = cpu_to_be32(95);
+ papm_parm->dGPU_T_Hysteresis = cpu_to_be32(5);
+ papm_parm->PlatformPowerLimit = 0xffffffff;
+ papm_parm->NearTDPLimitPAPM = 0xffffffff;
+
+ ret = si_copy_bytes_to_smc(rdev, si_pi->papm_cfg_table_start,
+ (u8 *)papm_parm,
+ sizeof(PP_SIslands_PAPMParameters),
+ si_pi->sram_end);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int si_populate_smc_tdp_limits_2(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ if (ni_pi->enable_power_containment) {
+ SISLANDS_SMC_STATETABLE *smc_table = &si_pi->smc_statetable;
+ u32 scaling_factor = si_get_smc_power_scaling_factor(rdev);
+ int ret;
+
+ memset(smc_table, 0, sizeof(SISLANDS_SMC_STATETABLE));
+
+ smc_table->dpm2Params.NearTDPLimit =
+ cpu_to_be32(si_scale_power_for_smc(rdev->pm.dpm.near_tdp_limit_adjusted, scaling_factor) * 1000);
+ smc_table->dpm2Params.SafePowerLimit =
+ cpu_to_be32(si_scale_power_for_smc((rdev->pm.dpm.near_tdp_limit_adjusted * SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT) / 100, scaling_factor) * 1000);
+
+ ret = si_copy_bytes_to_smc(rdev,
+ (si_pi->state_table_start +
+ offsetof(SISLANDS_SMC_STATETABLE, dpm2Params) +
+ offsetof(PP_SIslands_DPM2Parameters, NearTDPLimit)),
+ (u8 *)(&(smc_table->dpm2Params.NearTDPLimit)),
+ sizeof(u32) * 2,
+ si_pi->sram_end);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static u16 si_calculate_power_efficiency_ratio(struct radeon_device *rdev,
+ const u16 prev_std_vddc,
+ const u16 curr_std_vddc)
+{
+ u64 margin = (u64)SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN;
+ u64 prev_vddc = (u64)prev_std_vddc;
+ u64 curr_vddc = (u64)curr_std_vddc;
+ u64 pwr_efficiency_ratio, n, d;
+
+ if ((prev_vddc == 0) || (curr_vddc == 0))
+ return 0;
+
+ n = div64_u64((u64)1024 * curr_vddc * curr_vddc * ((u64)1000 + margin), (u64)1000);
+ d = prev_vddc * prev_vddc;
+ pwr_efficiency_ratio = div64_u64(n, d);
+
+ if (pwr_efficiency_ratio > (u64)0xFFFF)
+ return 0;
+
+ return (u16)pwr_efficiency_ratio;
+}
+
+static bool si_should_disable_uvd_powertune(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ if (si_pi->dyn_powertune_data.disable_uvd_powertune &&
+ radeon_state->vclk && radeon_state->dclk)
+ return true;
+
+ return false;
+}
+
+static int si_populate_power_containment_values(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ SISLANDS_SMC_VOLTAGE_VALUE vddc;
+ u32 prev_sclk;
+ u32 max_sclk;
+ u32 min_sclk;
+ u16 prev_std_vddc;
+ u16 curr_std_vddc;
+ int i;
+ u16 pwr_efficiency_ratio;
+ u8 max_ps_percent;
+ bool disable_uvd_power_tune;
+ int ret;
+
+ if (ni_pi->enable_power_containment == false)
+ return 0;
+
+ if (state->performance_level_count == 0)
+ return -EINVAL;
+
+ if (smc_state->levelCount != state->performance_level_count)
+ return -EINVAL;
+
+ disable_uvd_power_tune = si_should_disable_uvd_powertune(rdev, radeon_state);
+
+ smc_state->levels[0].dpm2.MaxPS = 0;
+ smc_state->levels[0].dpm2.NearTDPDec = 0;
+ smc_state->levels[0].dpm2.AboveSafeInc = 0;
+ smc_state->levels[0].dpm2.BelowSafeInc = 0;
+ smc_state->levels[0].dpm2.PwrEfficiencyRatio = 0;
+
+ for (i = 1; i < state->performance_level_count; i++) {
+ prev_sclk = state->performance_levels[i-1].sclk;
+ max_sclk = state->performance_levels[i].sclk;
+ if (i == 1)
+ max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_M;
+ else
+ max_ps_percent = SISLANDS_DPM2_MAXPS_PERCENT_H;
+
+ if (prev_sclk > max_sclk)
+ return -EINVAL;
+
+ if ((max_ps_percent == 0) ||
+ (prev_sclk == max_sclk) ||
+ disable_uvd_power_tune) {
+ min_sclk = max_sclk;
+ } else if (i == 1) {
+ min_sclk = prev_sclk;
+ } else {
+ min_sclk = (prev_sclk * (u32)max_ps_percent) / 100;
+ }
+
+ if (min_sclk < state->performance_levels[0].sclk)
+ min_sclk = state->performance_levels[0].sclk;
+
+ if (min_sclk == 0)
+ return -EINVAL;
+
+ ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ state->performance_levels[i-1].vddc, &vddc);
+ if (ret)
+ return ret;
+
+ ret = si_get_std_voltage_value(rdev, &vddc, &prev_std_vddc);
+ if (ret)
+ return ret;
+
+ ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ state->performance_levels[i].vddc, &vddc);
+ if (ret)
+ return ret;
+
+ ret = si_get_std_voltage_value(rdev, &vddc, &curr_std_vddc);
+ if (ret)
+ return ret;
+
+ pwr_efficiency_ratio = si_calculate_power_efficiency_ratio(rdev,
+ prev_std_vddc, curr_std_vddc);
+
+ smc_state->levels[i].dpm2.MaxPS = (u8)((SISLANDS_DPM2_MAX_PULSE_SKIP * (max_sclk - min_sclk)) / max_sclk);
+ smc_state->levels[i].dpm2.NearTDPDec = SISLANDS_DPM2_NEAR_TDP_DEC;
+ smc_state->levels[i].dpm2.AboveSafeInc = SISLANDS_DPM2_ABOVE_SAFE_INC;
+ smc_state->levels[i].dpm2.BelowSafeInc = SISLANDS_DPM2_BELOW_SAFE_INC;
+ smc_state->levels[i].dpm2.PwrEfficiencyRatio = cpu_to_be16(pwr_efficiency_ratio);
+ }
+
+ return 0;
+}
+
+static int si_populate_sq_ramping_values(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ u32 sq_power_throttle, sq_power_throttle2;
+ bool enable_sq_ramping = ni_pi->enable_sq_ramping;
+ int i;
+
+ if (state->performance_level_count == 0)
+ return -EINVAL;
+
+ if (smc_state->levelCount != state->performance_level_count)
+ return -EINVAL;
+
+ if (rdev->pm.dpm.sq_ramping_threshold == 0)
+ return -EINVAL;
+
+ if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER > (MAX_POWER_MASK >> MAX_POWER_SHIFT))
+ enable_sq_ramping = false;
+
+ if (SISLANDS_DPM2_SQ_RAMP_MIN_POWER > (MIN_POWER_MASK >> MIN_POWER_SHIFT))
+ enable_sq_ramping = false;
+
+ if (SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA > (MAX_POWER_DELTA_MASK >> MAX_POWER_DELTA_SHIFT))
+ enable_sq_ramping = false;
+
+ if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
+ enable_sq_ramping = false;
+
+ if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+ enable_sq_ramping = false;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ sq_power_throttle = 0;
+ sq_power_throttle2 = 0;
+
+ if ((state->performance_levels[i].sclk >= rdev->pm.dpm.sq_ramping_threshold) &&
+ enable_sq_ramping) {
+ sq_power_throttle |= MAX_POWER(SISLANDS_DPM2_SQ_RAMP_MAX_POWER);
+ sq_power_throttle |= MIN_POWER(SISLANDS_DPM2_SQ_RAMP_MIN_POWER);
+ sq_power_throttle2 |= MAX_POWER_DELTA(SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA);
+ sq_power_throttle2 |= STI_SIZE(SISLANDS_DPM2_SQ_RAMP_STI_SIZE);
+ sq_power_throttle2 |= LTI_RATIO(SISLANDS_DPM2_SQ_RAMP_LTI_RATIO);
+ } else {
+ sq_power_throttle |= MAX_POWER_MASK | MIN_POWER_MASK;
+ sq_power_throttle2 |= MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ }
+
+ smc_state->levels[i].SQPowerThrottle = cpu_to_be32(sq_power_throttle);
+ smc_state->levels[i].SQPowerThrottle_2 = cpu_to_be32(sq_power_throttle2);
+ }
+
+ return 0;
+}
+
+static int si_enable_power_containment(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ bool enable)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ PPSMC_Result smc_result;
+ int ret = 0;
+
+ if (ni_pi->enable_power_containment) {
+ if (enable) {
+ if (!si_should_disable_uvd_powertune(rdev, radeon_new_state)) {
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_TDPClampingActive);
+ if (smc_result != PPSMC_Result_OK) {
+ ret = -EINVAL;
+ ni_pi->pc_enabled = false;
+ } else {
+ ni_pi->pc_enabled = true;
+ }
+ }
+ } else {
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_TDPClampingInactive);
+ if (smc_result != PPSMC_Result_OK)
+ ret = -EINVAL;
+ ni_pi->pc_enabled = false;
+ }
+ }
+
+ return ret;
+}
+
+static int si_initialize_smc_dte_tables(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ int ret = 0;
+ struct si_dte_data *dte_data = &si_pi->dte_data;
+ Smc_SIslands_DTE_Configuration *dte_tables = NULL;
+ u32 table_size;
+ u8 tdep_count;
+ u32 i;
+
+ if (dte_data == NULL)
+ si_pi->enable_dte = false;
+
+ if (si_pi->enable_dte == false)
+ return 0;
+
+ if (dte_data->k <= 0)
+ return -EINVAL;
+
+ dte_tables = kzalloc(sizeof(Smc_SIslands_DTE_Configuration), GFP_KERNEL);
+ if (dte_tables == NULL) {
+ si_pi->enable_dte = false;
+ return -ENOMEM;
+ }
+
+ table_size = dte_data->k;
+
+ if (table_size > SMC_SISLANDS_DTE_MAX_FILTER_STAGES)
+ table_size = SMC_SISLANDS_DTE_MAX_FILTER_STAGES;
+
+ tdep_count = dte_data->tdep_count;
+ if (tdep_count > SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE)
+ tdep_count = SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE;
+
+ dte_tables->K = cpu_to_be32(table_size);
+ dte_tables->T0 = cpu_to_be32(dte_data->t0);
+ dte_tables->MaxT = cpu_to_be32(dte_data->max_t);
+ dte_tables->WindowSize = dte_data->window_size;
+ dte_tables->temp_select = dte_data->temp_select;
+ dte_tables->DTE_mode = dte_data->dte_mode;
+ dte_tables->Tthreshold = cpu_to_be32(dte_data->t_threshold);
+
+ if (tdep_count > 0)
+ table_size--;
+
+ for (i = 0; i < table_size; i++) {
+ dte_tables->tau[i] = cpu_to_be32(dte_data->tau[i]);
+ dte_tables->R[i] = cpu_to_be32(dte_data->r[i]);
+ }
+
+ dte_tables->Tdep_count = tdep_count;
+
+ for (i = 0; i < (u32)tdep_count; i++) {
+ dte_tables->T_limits[i] = dte_data->t_limits[i];
+ dte_tables->Tdep_tau[i] = cpu_to_be32(dte_data->tdep_tau[i]);
+ dte_tables->Tdep_R[i] = cpu_to_be32(dte_data->tdep_r[i]);
+ }
+
+ ret = si_copy_bytes_to_smc(rdev, si_pi->dte_table_start, (u8 *)dte_tables,
+ sizeof(Smc_SIslands_DTE_Configuration), si_pi->sram_end);
+ kfree(dte_tables);
+
+ return ret;
+}
+
+static int si_get_cac_std_voltage_max_min(struct radeon_device *rdev,
+ u16 *max, u16 *min)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct radeon_cac_leakage_table *table =
+ &rdev->pm.dpm.dyn_state.cac_leakage_table;
+ u32 i;
+ u32 v0_loadline;
+
+
+ if (table == NULL)
+ return -EINVAL;
+
+ *max = 0;
+ *min = 0xFFFF;
+
+ for (i = 0; i < table->count; i++) {
+ if (table->entries[i].vddc > *max)
+ *max = table->entries[i].vddc;
+ if (table->entries[i].vddc < *min)
+ *min = table->entries[i].vddc;
+ }
+
+ if (si_pi->powertune_data->lkge_lut_v0_percent > 100)
+ return -EINVAL;
+
+ v0_loadline = (*min) * (100 - si_pi->powertune_data->lkge_lut_v0_percent) / 100;
+
+ if (v0_loadline > 0xFFFFUL)
+ return -EINVAL;
+
+ *min = (u16)v0_loadline;
+
+ if ((*min > *max) || (*max == 0) || (*min == 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+static u16 si_get_cac_std_voltage_step(u16 max, u16 min)
+{
+ return ((max - min) + (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1)) /
+ SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES;
+}
+
+static int si_init_dte_leakage_table(struct radeon_device *rdev,
+ PP_SIslands_CacConfig *cac_tables,
+ u16 vddc_max, u16 vddc_min, u16 vddc_step,
+ u16 t0, u16 t_step)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 leakage;
+ unsigned int i, j;
+ s32 t;
+ u32 smc_leakage;
+ u32 scaling_factor;
+ u16 voltage;
+
+ scaling_factor = si_get_smc_power_scaling_factor(rdev);
+
+ for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++) {
+ t = (1000 * (i * t_step + t0));
+
+ for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+ voltage = vddc_max - (vddc_step * j);
+
+ si_calculate_leakage_for_v_and_t(rdev,
+ &si_pi->powertune_data->leakage_coefficients,
+ voltage,
+ t,
+ si_pi->dyn_powertune_data.cac_leakage,
+ &leakage);
+
+ smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4;
+
+ if (smc_leakage > 0xFFFF)
+ smc_leakage = 0xFFFF;
+
+ cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] =
+ cpu_to_be16((u16)smc_leakage);
+ }
+ }
+ return 0;
+}
+
+static int si_init_simplified_leakage_table(struct radeon_device *rdev,
+ PP_SIslands_CacConfig *cac_tables,
+ u16 vddc_max, u16 vddc_min, u16 vddc_step)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 leakage;
+ unsigned int i, j;
+ u32 smc_leakage;
+ u32 scaling_factor;
+ u16 voltage;
+
+ scaling_factor = si_get_smc_power_scaling_factor(rdev);
+
+ for (j = 0; j < SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES; j++) {
+ voltage = vddc_max - (vddc_step * j);
+
+ si_calculate_leakage_for_v(rdev,
+ &si_pi->powertune_data->leakage_coefficients,
+ si_pi->powertune_data->fixed_kt,
+ voltage,
+ si_pi->dyn_powertune_data.cac_leakage,
+ &leakage);
+
+ smc_leakage = si_scale_power_for_smc(leakage, scaling_factor) / 4;
+
+ if (smc_leakage > 0xFFFF)
+ smc_leakage = 0xFFFF;
+
+ for (i = 0; i < SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES ; i++)
+ cac_tables->cac_lkge_lut[i][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES-1-j] =
+ cpu_to_be16((u16)smc_leakage);
+ }
+ return 0;
+}
+
+static int si_initialize_smc_cac_tables(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ PP_SIslands_CacConfig *cac_tables = NULL;
+ u16 vddc_max, vddc_min, vddc_step;
+ u16 t0, t_step;
+ u32 load_line_slope, reg;
+ int ret = 0;
+ u32 ticks_per_us = radeon_get_xclk(rdev) / 100;
+
+ if (ni_pi->enable_cac == false)
+ return 0;
+
+ cac_tables = kzalloc(sizeof(PP_SIslands_CacConfig), GFP_KERNEL);
+ if (!cac_tables)
+ return -ENOMEM;
+
+ reg = RREG32(CG_CAC_CTRL) & ~CAC_WINDOW_MASK;
+ reg |= CAC_WINDOW(si_pi->powertune_data->cac_window);
+ WREG32(CG_CAC_CTRL, reg);
+
+ si_pi->dyn_powertune_data.cac_leakage = rdev->pm.dpm.cac_leakage;
+ si_pi->dyn_powertune_data.dc_pwr_value =
+ si_pi->powertune_data->dc_cac[NISLANDS_DCCAC_LEVEL_0];
+ si_pi->dyn_powertune_data.wintime = si_calculate_cac_wintime(rdev);
+ si_pi->dyn_powertune_data.shift_n = si_pi->powertune_data->shift_n_default;
+
+ si_pi->dyn_powertune_data.leakage_minimum_temperature = 80 * 1000;
+
+ ret = si_get_cac_std_voltage_max_min(rdev, &vddc_max, &vddc_min);
+ if (ret)
+ goto done_free;
+
+ vddc_step = si_get_cac_std_voltage_step(vddc_max, vddc_min);
+ vddc_min = vddc_max - (vddc_step * (SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES - 1));
+ t_step = 4;
+ t0 = 60;
+
+ if (si_pi->enable_dte || ni_pi->driver_calculate_cac_leakage)
+ ret = si_init_dte_leakage_table(rdev, cac_tables,
+ vddc_max, vddc_min, vddc_step,
+ t0, t_step);
+ else
+ ret = si_init_simplified_leakage_table(rdev, cac_tables,
+ vddc_max, vddc_min, vddc_step);
+ if (ret)
+ goto done_free;
+
+ load_line_slope = ((u32)rdev->pm.dpm.load_line_slope << SMC_SISLANDS_SCALE_R) / 100;
+
+ cac_tables->l2numWin_TDP = cpu_to_be32(si_pi->dyn_powertune_data.l2_lta_window_size);
+ cac_tables->lts_truncate_n = si_pi->dyn_powertune_data.lts_truncate;
+ cac_tables->SHIFT_N = si_pi->dyn_powertune_data.shift_n;
+ cac_tables->lkge_lut_V0 = cpu_to_be32((u32)vddc_min);
+ cac_tables->lkge_lut_Vstep = cpu_to_be32((u32)vddc_step);
+ cac_tables->R_LL = cpu_to_be32(load_line_slope);
+ cac_tables->WinTime = cpu_to_be32(si_pi->dyn_powertune_data.wintime);
+ cac_tables->calculation_repeats = cpu_to_be32(2);
+ cac_tables->dc_cac = cpu_to_be32(0);
+ cac_tables->log2_PG_LKG_SCALE = 12;
+ cac_tables->cac_temp = si_pi->powertune_data->operating_temp;
+ cac_tables->lkge_lut_T0 = cpu_to_be32((u32)t0);
+ cac_tables->lkge_lut_Tstep = cpu_to_be32((u32)t_step);
+
+ ret = si_copy_bytes_to_smc(rdev, si_pi->cac_table_start, (u8 *)cac_tables,
+ sizeof(PP_SIslands_CacConfig), si_pi->sram_end);
+
+ if (ret)
+ goto done_free;
+
+ ret = si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_ticks_per_us, ticks_per_us);
+
+done_free:
+ if (ret) {
+ ni_pi->enable_cac = false;
+ ni_pi->enable_power_containment = false;
+ }
+
+ kfree(cac_tables);
+
+ return 0;
+}
+
+static int si_program_cac_config_registers(struct radeon_device *rdev,
+ const struct si_cac_config_reg *cac_config_regs)
+{
+ const struct si_cac_config_reg *config_regs = cac_config_regs;
+ u32 data = 0, offset;
+
+ if (!config_regs)
+ return -EINVAL;
+
+ while (config_regs->offset != 0xFFFFFFFF) {
+ switch (config_regs->type) {
+ case SISLANDS_CACCONFIG_CGIND:
+ offset = SMC_CG_IND_START + config_regs->offset;
+ if (offset < SMC_CG_IND_END)
+ data = RREG32_SMC(offset);
+ break;
+ default:
+ data = RREG32(config_regs->offset << 2);
+ break;
+ }
+
+ data &= ~config_regs->mask;
+ data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
+
+ switch (config_regs->type) {
+ case SISLANDS_CACCONFIG_CGIND:
+ offset = SMC_CG_IND_START + config_regs->offset;
+ if (offset < SMC_CG_IND_END)
+ WREG32_SMC(offset, data);
+ break;
+ default:
+ WREG32(config_regs->offset << 2, data);
+ break;
+ }
+ config_regs++;
+ }
+ return 0;
+}
+
+static int si_initialize_hardware_cac_manager(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ int ret;
+
+ if ((ni_pi->enable_cac == false) ||
+ (ni_pi->cac_configuration_required == false))
+ return 0;
+
+ ret = si_program_cac_config_registers(rdev, si_pi->lcac_config);
+ if (ret)
+ return ret;
+ ret = si_program_cac_config_registers(rdev, si_pi->cac_override);
+ if (ret)
+ return ret;
+ ret = si_program_cac_config_registers(rdev, si_pi->cac_weights);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int si_enable_smc_cac(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ bool enable)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ PPSMC_Result smc_result;
+ int ret = 0;
+
+ if (ni_pi->enable_cac) {
+ if (enable) {
+ if (!si_should_disable_uvd_powertune(rdev, radeon_new_state)) {
+ if (ni_pi->support_cac_long_term_average) {
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgEnable);
+ if (smc_result != PPSMC_Result_OK)
+ ni_pi->support_cac_long_term_average = false;
+ }
+
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableCac);
+ if (smc_result != PPSMC_Result_OK) {
+ ret = -EINVAL;
+ ni_pi->cac_enabled = false;
+ } else {
+ ni_pi->cac_enabled = true;
+ }
+
+ if (si_pi->enable_dte) {
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableDTE);
+ if (smc_result != PPSMC_Result_OK)
+ ret = -EINVAL;
+ }
+ }
+ } else if (ni_pi->cac_enabled) {
+ if (si_pi->enable_dte)
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_DisableDTE);
+
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_MSG_DisableCac);
+
+ ni_pi->cac_enabled = false;
+
+ if (ni_pi->support_cac_long_term_average)
+ smc_result = si_send_msg_to_smc(rdev, PPSMC_CACLongTermAvgDisable);
+ }
+ }
+ return ret;
+}
+
+static int si_init_smc_spll_table(struct radeon_device *rdev)
+{
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ SMC_SISLANDS_SPLL_DIV_TABLE *spll_table;
+ SISLANDS_SMC_SCLK_VALUE sclk_params;
+ u32 fb_div, p_div;
+ u32 clk_s, clk_v;
+ u32 sclk = 0;
+ int ret = 0;
+ u32 tmp;
+ int i;
+
+ if (si_pi->spll_table_start == 0)
+ return -EINVAL;
+
+ spll_table = kzalloc(sizeof(SMC_SISLANDS_SPLL_DIV_TABLE), GFP_KERNEL);
+ if (spll_table == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < 256; i++) {
+ ret = si_calculate_sclk_params(rdev, sclk, &sclk_params);
+ if (ret)
+ break;
+
+ p_div = (sclk_params.vCG_SPLL_FUNC_CNTL & SPLL_PDIV_A_MASK) >> SPLL_PDIV_A_SHIFT;
+ fb_div = (sclk_params.vCG_SPLL_FUNC_CNTL_3 & SPLL_FB_DIV_MASK) >> SPLL_FB_DIV_SHIFT;
+ clk_s = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM & CLK_S_MASK) >> CLK_S_SHIFT;
+ clk_v = (sclk_params.vCG_SPLL_SPREAD_SPECTRUM_2 & CLK_V_MASK) >> CLK_V_SHIFT;
+
+ fb_div &= ~0x00001FFF;
+ fb_div >>= 1;
+ clk_v >>= 6;
+
+ if (p_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT))
+ ret = -EINVAL;
+ if (fb_div & ~(SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT))
+ ret = -EINVAL;
+ if (clk_s & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT))
+ ret = -EINVAL;
+ if (clk_v & ~(SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK >> SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT))
+ ret = -EINVAL;
+
+ if (ret)
+ break;
+
+ tmp = ((fb_div << SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK) |
+ ((p_div << SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK);
+ spll_table->freq[i] = cpu_to_be32(tmp);
+
+ tmp = ((clk_v << SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK) |
+ ((clk_s << SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT) & SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK);
+ spll_table->ss[i] = cpu_to_be32(tmp);
+
+ sclk += 512;
+ }
+
+
+ if (!ret)
+ ret = si_copy_bytes_to_smc(rdev, si_pi->spll_table_start,
+ (u8 *)spll_table, sizeof(SMC_SISLANDS_SPLL_DIV_TABLE),
+ si_pi->sram_end);
+
+ if (ret)
+ ni_pi->enable_power_containment = false;
+
+ kfree(spll_table);
+
+ return ret;
+}
+
+static void si_apply_state_adjust_rules(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct ni_ps *ps = ni_get_ps(rps);
+ struct radeon_clock_and_voltage_limits *max_limits;
+ bool disable_mclk_switching;
+ u32 mclk, sclk;
+ u16 vddc, vddci;
+ int i;
+
+ if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
+ ni_dpm_vblank_too_short(rdev))
+ disable_mclk_switching = true;
+ else
+ disable_mclk_switching = false;
+
+ if (rdev->pm.dpm.ac_power)
+ max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
+ else
+ max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc;
+
+ for (i = ps->performance_level_count - 2; i >= 0; i--) {
+ if (ps->performance_levels[i].vddc > ps->performance_levels[i+1].vddc)
+ ps->performance_levels[i].vddc = ps->performance_levels[i+1].vddc;
+ }
+ if (rdev->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;
+ if (ps->performance_levels[i].vddc > max_limits->vddc)
+ ps->performance_levels[i].vddc = max_limits->vddc;
+ if (ps->performance_levels[i].vddci > max_limits->vddci)
+ ps->performance_levels[i].vddci = max_limits->vddci;
+ }
+ }
+
+ /* 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;
+ vddc = ps->performance_levels[0].vddc;
+ vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
+ } else {
+ sclk = ps->performance_levels[0].sclk;
+ mclk = ps->performance_levels[0].mclk;
+ vddc = ps->performance_levels[0].vddc;
+ vddci = ps->performance_levels[0].vddci;
+ }
+
+ /* adjusted low state */
+ ps->performance_levels[0].sclk = sclk;
+ ps->performance_levels[0].mclk = mclk;
+ ps->performance_levels[0].vddc = vddc;
+ ps->performance_levels[0].vddci = vddci;
+
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
+ ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
+ if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
+ ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+ }
+
+ if (disable_mclk_switching) {
+ mclk = ps->performance_levels[0].mclk;
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (mclk < ps->performance_levels[i].mclk)
+ mclk = ps->performance_levels[i].mclk;
+ }
+ for (i = 0; i < ps->performance_level_count; i++) {
+ ps->performance_levels[i].mclk = mclk;
+ ps->performance_levels[i].vddci = vddci;
+ }
+ } else {
+ for (i = 1; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].mclk < ps->performance_levels[i - 1].mclk)
+ ps->performance_levels[i].mclk = ps->performance_levels[i - 1].mclk;
+ if (ps->performance_levels[i].vddci < ps->performance_levels[i - 1].vddci)
+ ps->performance_levels[i].vddci = ps->performance_levels[i - 1].vddci;
+ }
+ }
+
+ for (i = 0; i < ps->performance_level_count; i++)
+ btc_adjust_clock_combinations(rdev, max_limits,
+ &ps->performance_levels[i]);
+
+ for (i = 0; i < ps->performance_level_count; i++) {
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
+ ps->performance_levels[i].sclk,
+ max_limits->vddc, &ps->performance_levels[i].vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
+ ps->performance_levels[i].mclk,
+ max_limits->vddci, &ps->performance_levels[i].vddci);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
+ ps->performance_levels[i].mclk,
+ max_limits->vddc, &ps->performance_levels[i].vddc);
+ btc_apply_voltage_dependency_rules(&rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk,
+ rdev->clock.current_dispclk,
+ max_limits->vddc, &ps->performance_levels[i].vddc);
+ }
+
+ for (i = 0; i < ps->performance_level_count; i++) {
+ btc_apply_voltage_delta_rules(rdev,
+ max_limits->vddc, max_limits->vddci,
+ &ps->performance_levels[i].vddc,
+ &ps->performance_levels[i].vddci);
+ }
+
+ ps->dc_compatible = true;
+ for (i = 0; i < ps->performance_level_count; i++) {
+ if (ps->performance_levels[i].vddc > rdev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc)
+ ps->dc_compatible = false;
+ }
+
+}
+
+#if 0
+static int si_read_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 *value)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ return si_read_smc_sram_dword(rdev,
+ si_pi->soft_regs_start + reg_offset, value,
+ si_pi->sram_end);
+}
+#endif
+
+static int si_write_smc_soft_register(struct radeon_device *rdev,
+ u16 reg_offset, u32 value)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ return si_write_smc_sram_dword(rdev,
+ si_pi->soft_regs_start + reg_offset,
+ value, si_pi->sram_end);
+}
+
+static bool si_is_special_1gb_platform(struct radeon_device *rdev)
+{
+ bool ret = false;
+ u32 tmp, width, row, column, bank, density;
+ bool is_memory_gddr5, is_special;
+
+ tmp = RREG32(MC_SEQ_MISC0);
+ is_memory_gddr5 = (MC_SEQ_MISC0_GDDR5_VALUE == ((tmp & MC_SEQ_MISC0_GDDR5_MASK) >> MC_SEQ_MISC0_GDDR5_SHIFT));
+ is_special = (MC_SEQ_MISC0_REV_ID_VALUE == ((tmp & MC_SEQ_MISC0_REV_ID_MASK) >> MC_SEQ_MISC0_REV_ID_SHIFT))
+ & (MC_SEQ_MISC0_VEN_ID_VALUE == ((tmp & MC_SEQ_MISC0_VEN_ID_MASK) >> MC_SEQ_MISC0_VEN_ID_SHIFT));
+
+ WREG32(MC_SEQ_IO_DEBUG_INDEX, 0xb);
+ width = ((RREG32(MC_SEQ_IO_DEBUG_DATA) >> 1) & 1) ? 16 : 32;
+
+ tmp = RREG32(MC_ARB_RAMCFG);
+ row = ((tmp & NOOFROWS_MASK) >> NOOFROWS_SHIFT) + 10;
+ column = ((tmp & NOOFCOLS_MASK) >> NOOFCOLS_SHIFT) + 8;
+ bank = ((tmp & NOOFBANK_MASK) >> NOOFBANK_SHIFT) + 2;
+
+ density = (1 << (row + column - 20 + bank)) * width;
+
+ if ((rdev->pdev->device == 0x6819) &&
+ is_memory_gddr5 && is_special && (density == 0x400))
+ ret = true;
+
+ return ret;
+}
+
+static void si_get_leakage_vddc(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u16 vddc, count = 0;
+ int i, ret;
+
+ for (i = 0; i < SISLANDS_MAX_LEAKAGE_COUNT; i++) {
+ ret = radeon_atom_get_leakage_vddc_based_on_leakage_idx(rdev, &vddc, SISLANDS_LEAKAGE_INDEX0 + i);
+
+ if (!ret && (vddc > 0) && (vddc != (SISLANDS_LEAKAGE_INDEX0 + i))) {
+ si_pi->leakage_voltage.entries[count].voltage = vddc;
+ si_pi->leakage_voltage.entries[count].leakage_index =
+ SISLANDS_LEAKAGE_INDEX0 + i;
+ count++;
+ }
+ }
+ si_pi->leakage_voltage.count = count;
+}
+
+static int si_get_leakage_voltage_from_leakage_index(struct radeon_device *rdev,
+ u32 index, u16 *leakage_voltage)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ int i;
+
+ if (leakage_voltage == NULL)
+ return -EINVAL;
+
+ if ((index & 0xff00) != 0xff00)
+ return -EINVAL;
+
+ if ((index & 0xff) > SISLANDS_MAX_LEAKAGE_COUNT + 1)
+ return -EINVAL;
+
+ if (index < SISLANDS_LEAKAGE_INDEX0)
+ return -EINVAL;
+
+ for (i = 0; i < si_pi->leakage_voltage.count; i++) {
+ if (si_pi->leakage_voltage.entries[i].leakage_index == index) {
+ *leakage_voltage = si_pi->leakage_voltage.entries[i].voltage;
+ return 0;
+ }
+ }
+ return -EAGAIN;
+}
+
+static void si_set_dpm_event_sources(struct radeon_device *rdev, u32 sources)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ bool want_thermal_protection;
+ enum radeon_dpm_event_src dpm_event_src;
+
+ switch (sources) {
+ case 0:
+ default:
+ want_thermal_protection = false;
+ break;
+ case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_DIGITAL;
+ break;
+ case (1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_EXTERNAL;
+ break;
+ case ((1 << RADEON_DPM_AUTO_THROTTLE_SRC_EXTERNAL) |
+ (1 << RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL)):
+ want_thermal_protection = true;
+ dpm_event_src = RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL;
+ break;
+ }
+
+ if (want_thermal_protection) {
+ WREG32_P(CG_THERMAL_CTRL, DPM_EVENT_SRC(dpm_event_src), ~DPM_EVENT_SRC_MASK);
+ if (pi->thermal_protection)
+ WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ } else {
+ WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+ }
+}
+
+static void si_enable_auto_throttle_source(struct radeon_device *rdev,
+ enum radeon_dpm_auto_throttle_src source,
+ bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (enable) {
+ if (!(pi->active_auto_throttle_sources & (1 << source))) {
+ pi->active_auto_throttle_sources |= 1 << source;
+ si_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+ }
+ } else {
+ if (pi->active_auto_throttle_sources & (1 << source)) {
+ pi->active_auto_throttle_sources &= ~(1 << source);
+ si_set_dpm_event_sources(rdev, pi->active_auto_throttle_sources);
+ }
+ }
+}
+
+static void si_start_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+}
+
+static void si_stop_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
+}
+
+static void si_enable_sclk_control(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
+ else
+ WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+
+}
+
+#if 0
+static int si_notify_hardware_of_thermal_state(struct radeon_device *rdev,
+ u32 thermal_level)
+{
+ PPSMC_Result ret;
+
+ if (thermal_level == 0) {
+ ret = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+ if (ret == PPSMC_Result_OK)
+ return 0;
+ else
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void si_notify_hardware_vpu_recovery_event(struct radeon_device *rdev)
+{
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen, true);
+}
+#endif
+
+#if 0
+static int si_notify_hw_of_powersource(struct radeon_device *rdev, bool ac_power)
+{
+ if (ac_power)
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_RunningOnAC) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+
+ return 0;
+}
+#endif
+
+static PPSMC_Result si_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
+ PPSMC_Msg msg, u32 parameter)
+{
+ WREG32(SMC_SCRATCH0, parameter);
+ return si_send_msg_to_smc(rdev, msg);
+}
+
+static int si_restrict_performance_levels_before_switch(struct radeon_device *rdev)
+{
+ if (si_send_msg_to_smc(rdev, PPSMC_MSG_NoForcedLevel) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+int si_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct ni_ps *ps = ni_get_ps(rps);
+ u32 levels;
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
+ return -EINVAL;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ levels = ps->performance_level_count - 1;
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+ return -EINVAL;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+ return -EINVAL;
+ }
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}
+
+static int si_set_boot_state(struct radeon_device *rdev)
+{
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int si_set_sw_state(struct radeon_device *rdev)
+{
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int si_halt_smc(struct radeon_device *rdev)
+{
+ if (si_send_msg_to_smc(rdev, PPSMC_MSG_Halt) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return (si_wait_for_smc_inactive(rdev) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int si_resume_smc(struct radeon_device *rdev)
+{
+ if (si_send_msg_to_smc(rdev, PPSMC_FlushDataCache) != PPSMC_Result_OK)
+ return -EINVAL;
+
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_Resume) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static void si_dpm_start_smc(struct radeon_device *rdev)
+{
+ si_program_jump_on_start(rdev);
+ si_start_smc(rdev);
+ si_start_smc_clock(rdev);
+}
+
+static void si_dpm_stop_smc(struct radeon_device *rdev)
+{
+ si_reset_smc(rdev);
+ si_stop_smc_clock(rdev);
+}
+
+static int si_process_firmware_header(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_stateTable,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->state_table_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_softRegisters,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->soft_regs_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->mc_reg_table_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->arb_table_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->cac_table_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->dte_table_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_spllTable,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->spll_table_start = tmp;
+
+ ret = si_read_smc_sram_dword(rdev,
+ SISLANDS_SMC_FIRMWARE_HEADER_LOCATION +
+ SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ si_pi->papm_cfg_table_start = tmp;
+
+ return ret;
+}
+
+static void si_read_clock_registers(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ si_pi->clock_registers.cg_spll_func_cntl = RREG32(CG_SPLL_FUNC_CNTL);
+ si_pi->clock_registers.cg_spll_func_cntl_2 = RREG32(CG_SPLL_FUNC_CNTL_2);
+ si_pi->clock_registers.cg_spll_func_cntl_3 = RREG32(CG_SPLL_FUNC_CNTL_3);
+ si_pi->clock_registers.cg_spll_func_cntl_4 = RREG32(CG_SPLL_FUNC_CNTL_4);
+ si_pi->clock_registers.cg_spll_spread_spectrum = RREG32(CG_SPLL_SPREAD_SPECTRUM);
+ si_pi->clock_registers.cg_spll_spread_spectrum_2 = RREG32(CG_SPLL_SPREAD_SPECTRUM_2);
+ si_pi->clock_registers.dll_cntl = RREG32(DLL_CNTL);
+ si_pi->clock_registers.mclk_pwrmgt_cntl = RREG32(MCLK_PWRMGT_CNTL);
+ si_pi->clock_registers.mpll_ad_func_cntl = RREG32(MPLL_AD_FUNC_CNTL);
+ si_pi->clock_registers.mpll_dq_func_cntl = RREG32(MPLL_DQ_FUNC_CNTL);
+ si_pi->clock_registers.mpll_func_cntl = RREG32(MPLL_FUNC_CNTL);
+ si_pi->clock_registers.mpll_func_cntl_1 = RREG32(MPLL_FUNC_CNTL_1);
+ si_pi->clock_registers.mpll_func_cntl_2 = RREG32(MPLL_FUNC_CNTL_2);
+ si_pi->clock_registers.mpll_ss1 = RREG32(MPLL_SS1);
+ si_pi->clock_registers.mpll_ss2 = RREG32(MPLL_SS2);
+}
+
+static void si_enable_thermal_protection(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, 0, ~THERMAL_PROTECTION_DIS);
+ else
+ WREG32_P(GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, ~THERMAL_PROTECTION_DIS);
+}
+
+static void si_enable_acpi_power_management(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+#if 0
+static int si_enter_ulp_state(struct radeon_device *rdev)
+{
+ WREG32(SMC_MESSAGE_0, PPSMC_MSG_SwitchToMinimumPower);
+
+ udelay(25000);
+
+ return 0;
+}
+
+static int si_exit_ulp_state(struct radeon_device *rdev)
+{
+ int i;
+
+ WREG32(SMC_MESSAGE_0, PPSMC_MSG_ResumeFromMinimumPower);
+
+ udelay(7000);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(SMC_RESP_0) == 1)
+ break;
+ udelay(1000);
+ }
+
+ return 0;
+}
+#endif
+
+static int si_notify_smc_display_change(struct radeon_device *rdev,
+ bool has_display)
+{
+ PPSMC_Msg msg = has_display ?
+ PPSMC_MSG_HasDisplay : PPSMC_MSG_NoDisplay;
+
+ return (si_send_msg_to_smc(rdev, msg) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static void si_program_response_times(struct radeon_device *rdev)
+{
+ u32 voltage_response_time, backbias_response_time, acpi_delay_time, vbi_time_out;
+ u32 vddc_dly, acpi_dly, vbi_dly;
+ u32 reference_clock;
+
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_mvdd_chg_time, 1);
+
+ voltage_response_time = (u32)rdev->pm.dpm.voltage_response_time;
+ backbias_response_time = (u32)rdev->pm.dpm.backbias_response_time;
+
+ if (voltage_response_time == 0)
+ voltage_response_time = 1000;
+
+ acpi_delay_time = 15000;
+ vbi_time_out = 100000;
+
+ reference_clock = radeon_get_xclk(rdev);
+
+ vddc_dly = (voltage_response_time * reference_clock) / 100;
+ acpi_dly = (acpi_delay_time * reference_clock) / 100;
+ vbi_dly = (vbi_time_out * reference_clock) / 100;
+
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_delay_vreg, vddc_dly);
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_delay_acpi, acpi_dly);
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_mclk_chg_timeout, vbi_dly);
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_mc_block_delay, 0xAA);
+}
+
+static void si_program_ds_registers(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ u32 tmp = 1; /* XXX: 0x10 on tahiti A0 */
+
+ if (eg_pi->sclk_deep_sleep) {
+ WREG32_P(MISC_CLK_CNTL, DEEP_SLEEP_CLK_SEL(tmp), ~DEEP_SLEEP_CLK_SEL_MASK);
+ WREG32_P(CG_SPLL_AUTOSCALE_CNTL, AUTOSCALE_ON_SS_CLEAR,
+ ~AUTOSCALE_ON_SS_CLEAR);
+ }
+}
+
+static void si_program_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp, pipe;
+ int i;
+
+ tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+ if (rdev->pm.dpm.new_active_crtc_count > 0)
+ tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+ else
+ tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+ if (rdev->pm.dpm.new_active_crtc_count > 1)
+ tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM);
+ else
+ tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE);
+
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+
+ tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG);
+ pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT;
+
+ if ((rdev->pm.dpm.new_active_crtc_count > 0) &&
+ (!(rdev->pm.dpm.new_active_crtcs & (1 << pipe)))) {
+ /* find the first active crtc */
+ for (i = 0; i < rdev->num_crtc; i++) {
+ if (rdev->pm.dpm.new_active_crtcs & (1 << i))
+ break;
+ }
+ if (i == rdev->num_crtc)
+ pipe = 0;
+ else
+ pipe = i;
+
+ tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK;
+ tmp |= DCCG_DISP1_SLOW_SELECT(pipe);
+ WREG32(DCCG_DISP_SLOW_SELECT_REG, tmp);
+ }
+
+ si_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0);
+}
+
+static void si_enable_spread_spectrum(struct radeon_device *rdev, bool enable)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ if (enable) {
+ if (pi->sclk_ss)
+ WREG32_P(GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, ~DYN_SPREAD_SPECTRUM_EN);
+ } else {
+ WREG32_P(CG_SPLL_SPREAD_SPECTRUM, 0, ~SSEN);
+ WREG32_P(GENERAL_PWRMGT, 0, ~DYN_SPREAD_SPECTRUM_EN);
+ }
+}
+
+static void si_setup_bsp(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 xclk = radeon_get_xclk(rdev);
+
+ r600_calculate_u_and_p(pi->asi,
+ xclk,
+ 16,
+ &pi->bsp,
+ &pi->bsu);
+
+ r600_calculate_u_and_p(pi->pasi,
+ xclk,
+ 16,
+ &pi->pbsp,
+ &pi->pbsu);
+
+
+ pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
+ pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+
+ WREG32(CG_BSP, pi->dsp);
+}
+
+static void si_program_git(struct radeon_device *rdev)
+{
+ WREG32_P(CG_GIT, CG_GICST(R600_GICST_DFLT), ~CG_GICST_MASK);
+}
+
+static void si_program_tp(struct radeon_device *rdev)
+{
+ int i;
+ enum r600_td td = R600_TD_DFLT;
+
+ for (i = 0; i < R600_PM_NUMBER_OF_TC; i++)
+ WREG32(CG_FFCT_0 + (i * 4), (UTC_0(r600_utc[i]) | DTC_0(r600_dtc[i])));
+
+ if (td == R600_TD_AUTO)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+ else
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+
+ if (td == R600_TD_UP)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+
+ if (td == R600_TD_DOWN)
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+static void si_program_tpp(struct radeon_device *rdev)
+{
+ WREG32(CG_TPC, R600_TPC_DFLT);
+}
+
+static void si_program_sstp(struct radeon_device *rdev)
+{
+ WREG32(CG_SSP, (SSTU(R600_SSTU_DFLT) | SST(R600_SST_DFLT)));
+}
+
+static void si_enable_display_gap(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
+
+ tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
+ tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+ DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
+ WREG32(CG_DISPLAY_GAP_CNTL, tmp);
+}
+
+static void si_program_vc(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ WREG32(CG_FTV, pi->vrc);
+}
+
+static void si_clear_vc(struct radeon_device *rdev)
+{
+ WREG32(CG_FTV, 0);
+}
+
+static u8 si_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 si_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 u8 si_get_strobe_mode_settings(struct radeon_device *rdev, u32 mclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ bool strobe_mode = false;
+ u8 result = 0;
+
+ if (mclk <= pi->mclk_strobe_mode_threshold)
+ strobe_mode = true;
+
+ if (pi->mem_gddr5)
+ result = si_get_mclk_frequency_ratio(mclk, strobe_mode);
+ else
+ result = si_get_ddr3_mclk_frequency_ratio(mclk);
+
+ if (strobe_mode)
+ result |= SISLANDS_SMC_STROBE_ENABLE;
+
+ return result;
+}
+
+static int si_upload_firmware(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ int ret;
+
+ si_reset_smc(rdev);
+ si_stop_smc_clock(rdev);
+
+ ret = si_load_smc_ucode(rdev, si_pi->sram_end);
+
+ return ret;
+}
+
+static bool si_validate_phase_shedding_tables(struct radeon_device *rdev,
+ const struct atom_voltage_table *table,
+ const struct radeon_phase_shedding_limits_table *limits)
+{
+ u32 data, num_bits, num_levels;
+
+ if ((table == NULL) || (limits == NULL))
+ return false;
+
+ data = table->mask_low;
+
+ num_bits = hweight32(data);
+
+ if (num_bits == 0)
+ return false;
+
+ num_levels = (1 << num_bits);
+
+ if (table->count != num_levels)
+ return false;
+
+ if (limits->count != (num_levels - 1))
+ return false;
+
+ return true;
+}
+
+static void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
+ struct atom_voltage_table *voltage_table)
+{
+ unsigned int i, diff;
+
+ if (voltage_table->count <= SISLANDS_MAX_NO_VREG_STEPS)
+ return;
+
+ diff = voltage_table->count - SISLANDS_MAX_NO_VREG_STEPS;
+
+ for (i= 0; i < SISLANDS_MAX_NO_VREG_STEPS; i++)
+ voltage_table->entries[i] = voltage_table->entries[i + diff];
+
+ voltage_table->count = SISLANDS_MAX_NO_VREG_STEPS;
+}
+
+static int si_construct_voltage_tables(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ int ret;
+
+ ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
+ VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddc_voltage_table);
+ if (ret)
+ return ret;
+
+ if (eg_pi->vddc_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
+ si_trim_voltage_table_to_fit_state_table(rdev, &eg_pi->vddc_voltage_table);
+
+ if (eg_pi->vddci_control) {
+ ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDCI,
+ VOLTAGE_OBJ_GPIO_LUT, &eg_pi->vddci_voltage_table);
+ if (ret)
+ return ret;
+
+ if (eg_pi->vddci_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
+ si_trim_voltage_table_to_fit_state_table(rdev, &eg_pi->vddci_voltage_table);
+ }
+
+ if (pi->mvdd_control) {
+ ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_MVDDC,
+ VOLTAGE_OBJ_GPIO_LUT, &si_pi->mvdd_voltage_table);
+
+ if (ret) {
+ pi->mvdd_control = false;
+ return ret;
+ }
+
+ if (si_pi->mvdd_voltage_table.count == 0) {
+ pi->mvdd_control = false;
+ return -EINVAL;
+ }
+
+ if (si_pi->mvdd_voltage_table.count > SISLANDS_MAX_NO_VREG_STEPS)
+ si_trim_voltage_table_to_fit_state_table(rdev, &si_pi->mvdd_voltage_table);
+ }
+
+ if (si_pi->vddc_phase_shed_control) {
+ ret = radeon_atom_get_voltage_table(rdev, VOLTAGE_TYPE_VDDC,
+ VOLTAGE_OBJ_PHASE_LUT, &si_pi->vddc_phase_shed_table);
+ if (ret)
+ si_pi->vddc_phase_shed_control = false;
+
+ if ((si_pi->vddc_phase_shed_table.count == 0) ||
+ (si_pi->vddc_phase_shed_table.count > SISLANDS_MAX_NO_VREG_STEPS))
+ si_pi->vddc_phase_shed_control = false;
+ }
+
+ return 0;
+}
+
+static void si_populate_smc_voltage_table(struct radeon_device *rdev,
+ const struct atom_voltage_table *voltage_table,
+ SISLANDS_SMC_STATETABLE *table)
+{
+ unsigned int i;
+
+ for (i = 0; i < voltage_table->count; i++)
+ table->lowSMIO[i] |= cpu_to_be32(voltage_table->entries[i].smio_low);
+}
+
+static int si_populate_smc_voltage_tables(struct radeon_device *rdev,
+ SISLANDS_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u8 i;
+
+ if (eg_pi->vddc_voltage_table.count) {
+ si_populate_smc_voltage_table(rdev, &eg_pi->vddc_voltage_table, table);
+ table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
+ cpu_to_be32(eg_pi->vddc_voltage_table.mask_low);
+
+ for (i = 0; i < eg_pi->vddc_voltage_table.count; i++) {
+ if (pi->max_vddc_in_table <= eg_pi->vddc_voltage_table.entries[i].value) {
+ table->maxVDDCIndexInPPTable = i;
+ break;
+ }
+ }
+ }
+
+ if (eg_pi->vddci_voltage_table.count) {
+ si_populate_smc_voltage_table(rdev, &eg_pi->vddci_voltage_table, table);
+
+ table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDCI] =
+ cpu_to_be32(eg_pi->vddci_voltage_table.mask_low);
+ }
+
+
+ if (si_pi->mvdd_voltage_table.count) {
+ si_populate_smc_voltage_table(rdev, &si_pi->mvdd_voltage_table, table);
+
+ table->voltageMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_MVDD] =
+ cpu_to_be32(si_pi->mvdd_voltage_table.mask_low);
+ }
+
+ if (si_pi->vddc_phase_shed_control) {
+ if (si_validate_phase_shedding_tables(rdev, &si_pi->vddc_phase_shed_table,
+ &rdev->pm.dpm.dyn_state.phase_shedding_limits_table)) {
+ si_populate_smc_voltage_table(rdev, &si_pi->vddc_phase_shed_table, table);
+
+ table->phaseMaskTable.lowMask[SISLANDS_SMC_VOLTAGEMASK_VDDC] =
+ cpu_to_be32(si_pi->vddc_phase_shed_table.mask_low);
+
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_phase_shedding_delay,
+ (u32)si_pi->vddc_phase_shed_table.phase_delay);
+ } else {
+ si_pi->vddc_phase_shed_control = false;
+ }
+ }
+
+ return 0;
+}
+
+static int si_populate_voltage_value(struct radeon_device *rdev,
+ const struct atom_voltage_table *table,
+ u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ unsigned int i;
+
+ for (i = 0; i < table->count; i++) {
+ if (value <= table->entries[i].value) {
+ voltage->index = (u8)i;
+ voltage->value = cpu_to_be16(table->entries[i].value);
+ break;
+ }
+ }
+
+ if (i >= table->count)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int si_populate_mvdd_value(struct radeon_device *rdev, u32 mclk,
+ SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ if (pi->mvdd_control) {
+ if (mclk <= pi->mvdd_split_frequency)
+ voltage->index = 0;
+ else
+ voltage->index = (u8)(si_pi->mvdd_voltage_table.count) - 1;
+
+ voltage->value = cpu_to_be16(si_pi->mvdd_voltage_table.entries[voltage->index].value);
+ }
+ return 0;
+}
+
+static int si_get_std_voltage_value(struct radeon_device *rdev,
+ SISLANDS_SMC_VOLTAGE_VALUE *voltage,
+ u16 *std_voltage)
+{
+ u16 v_index;
+ bool voltage_found = false;
+ *std_voltage = be16_to_cpu(voltage->value);
+
+ if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries) {
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE) {
+ if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries == NULL)
+ return -EINVAL;
+
+ for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
+ if (be16_to_cpu(voltage->value) ==
+ (u16)rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
+ voltage_found = true;
+ if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
+ *std_voltage =
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc;
+ else
+ *std_voltage =
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries[rdev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc;
+ break;
+ }
+ }
+
+ if (!voltage_found) {
+ for (v_index = 0; (u32)v_index < rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.count; v_index++) {
+ if (be16_to_cpu(voltage->value) <=
+ (u16)rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[v_index].v) {
+ voltage_found = true;
+ if ((u32)v_index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
+ *std_voltage =
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries[v_index].vddc;
+ else
+ *std_voltage =
+ rdev->pm.dpm.dyn_state.cac_leakage_table.entries[rdev->pm.dpm.dyn_state.cac_leakage_table.count-1].vddc;
+ break;
+ }
+ }
+ }
+ } else {
+ if ((u32)voltage->index < rdev->pm.dpm.dyn_state.cac_leakage_table.count)
+ *std_voltage = rdev->pm.dpm.dyn_state.cac_leakage_table.entries[voltage->index].vddc;
+ }
+ }
+
+ return 0;
+}
+
+static int si_populate_std_voltage_value(struct radeon_device *rdev,
+ u16 value, u8 index,
+ SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ voltage->index = index;
+ voltage->value = cpu_to_be16(value);
+
+ return 0;
+}
+
+static int si_populate_phase_shedding_value(struct radeon_device *rdev,
+ const struct radeon_phase_shedding_limits_table *limits,
+ u16 voltage, u32 sclk, u32 mclk,
+ SISLANDS_SMC_VOLTAGE_VALUE *smc_voltage)
+{
+ unsigned int i;
+
+ for (i = 0; i < limits->count; i++) {
+ if ((voltage <= limits->entries[i].voltage) &&
+ (sclk <= limits->entries[i].sclk) &&
+ (mclk <= limits->entries[i].mclk))
+ break;
+ }
+
+ smc_voltage->phase_settings = (u8)i;
+
+ return 0;
+}
+
+static int si_init_arb_table_index(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = si_read_smc_sram_dword(rdev, si_pi->arb_table_start, &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ tmp &= 0x00FFFFFF;
+ tmp |= MC_CG_ARB_FREQ_F1 << 24;
+
+ return si_write_smc_sram_dword(rdev, si_pi->arb_table_start, tmp, si_pi->sram_end);
+}
+
+static int si_initial_switch_from_arb_f0_to_f1(struct radeon_device *rdev)
+{
+ return ni_copy_and_switch_arb_sets(rdev, MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
+}
+
+static int si_reset_to_default(struct radeon_device *rdev)
+{
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_ResetToDefaults) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+}
+
+static int si_force_switch_to_arb_f0(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 tmp;
+ int ret;
+
+ ret = si_read_smc_sram_dword(rdev, si_pi->arb_table_start,
+ &tmp, si_pi->sram_end);
+ if (ret)
+ return ret;
+
+ tmp = (tmp >> 24) & 0xff;
+
+ if (tmp == MC_CG_ARB_FREQ_F0)
+ return 0;
+
+ return ni_copy_and_switch_arb_sets(rdev, tmp, MC_CG_ARB_FREQ_F0);
+}
+
+static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev,
+ u32 engine_clock)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u32 dram_rows;
+ u32 dram_refresh_rate;
+ u32 mc_arb_rfsh_rate;
+ u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
+
+ if (pi->mem_gddr5)
+ dram_rows = 1 << (tmp + 10);
+ else
+ dram_rows = DDR3_DRAM_ROWS;
+
+ dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
+ mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
+
+ return mc_arb_rfsh_rate;
+}
+
+static int si_populate_memory_timing_parameters(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SMC_SIslands_MCArbDramTimingRegisterSet *arb_regs)
+{
+ u32 dram_timing;
+ u32 dram_timing2;
+ u32 burst_time;
+
+ arb_regs->mc_arb_rfsh_rate =
+ (u8)si_calculate_memory_refresh_rate(rdev, pl->sclk);
+
+ radeon_atom_set_engine_dram_timings(rdev,
+ pl->sclk,
+ pl->mclk);
+
+ dram_timing = RREG32(MC_ARB_DRAM_TIMING);
+ dram_timing2 = RREG32(MC_ARB_DRAM_TIMING2);
+ burst_time = RREG32(MC_ARB_BURST_TIME) & STATE0_MASK;
+
+ arb_regs->mc_arb_dram_timing = cpu_to_be32(dram_timing);
+ arb_regs->mc_arb_dram_timing2 = cpu_to_be32(dram_timing2);
+ arb_regs->mc_arb_burst_time = (u8)burst_time;
+
+ return 0;
+}
+
+static int si_do_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ unsigned int first_arb_set)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
+ int i, ret = 0;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ ret = si_populate_memory_timing_parameters(rdev, &state->performance_levels[i], &arb_regs);
+ if (ret)
+ break;
+ ret = si_copy_bytes_to_smc(rdev,
+ si_pi->arb_table_start +
+ offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) +
+ sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * (first_arb_set + i),
+ (u8 *)&arb_regs,
+ sizeof(SMC_SIslands_MCArbDramTimingRegisterSet),
+ si_pi->sram_end);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int si_program_memory_timing_parameters(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ return si_do_program_memory_timing_parameters(rdev, radeon_new_state,
+ SISLANDS_DRIVER_STATE_ARB_INDEX);
+}
+
+static int si_populate_initial_mvdd_value(struct radeon_device *rdev,
+ struct SISLANDS_SMC_VOLTAGE_VALUE *voltage)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ if (pi->mvdd_control)
+ return si_populate_voltage_value(rdev, &si_pi->mvdd_voltage_table,
+ si_pi->mvdd_bootup_value, voltage);
+
+ return 0;
+}
+
+static int si_populate_smc_initial_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_initial_state,
+ SISLANDS_SMC_STATETABLE *table)
+{
+ struct ni_ps *initial_state = ni_get_ps(radeon_initial_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 reg;
+ int ret;
+
+ table->initialState.levels[0].mclk.vDLL_CNTL =
+ cpu_to_be32(si_pi->clock_registers.dll_cntl);
+ table->initialState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(si_pi->clock_registers.mclk_pwrmgt_cntl);
+ table->initialState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
+ cpu_to_be32(si_pi->clock_registers.mpll_ad_func_cntl);
+ table->initialState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
+ cpu_to_be32(si_pi->clock_registers.mpll_dq_func_cntl);
+ table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL =
+ cpu_to_be32(si_pi->clock_registers.mpll_func_cntl);
+ table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
+ cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_1);
+ table->initialState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
+ cpu_to_be32(si_pi->clock_registers.mpll_func_cntl_2);
+ table->initialState.levels[0].mclk.vMPLL_SS =
+ cpu_to_be32(si_pi->clock_registers.mpll_ss1);
+ table->initialState.levels[0].mclk.vMPLL_SS2 =
+ cpu_to_be32(si_pi->clock_registers.mpll_ss2);
+
+ table->initialState.levels[0].mclk.mclk_value =
+ cpu_to_be32(initial_state->performance_levels[0].mclk);
+
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_2);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_3);
+ table->initialState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
+ cpu_to_be32(si_pi->clock_registers.cg_spll_func_cntl_4);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM =
+ cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum);
+ table->initialState.levels[0].sclk.vCG_SPLL_SPREAD_SPECTRUM_2 =
+ cpu_to_be32(si_pi->clock_registers.cg_spll_spread_spectrum_2);
+
+ table->initialState.levels[0].sclk.sclk_value =
+ cpu_to_be32(initial_state->performance_levels[0].sclk);
+
+ table->initialState.levels[0].arbRefreshState =
+ SISLANDS_INITIAL_STATE_ARB_INDEX;
+
+ table->initialState.levels[0].ACIndex = 0;
+
+ ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ initial_state->performance_levels[0].vddc,
+ &table->initialState.levels[0].vddc);
+
+ if (!ret) {
+ u16 std_vddc;
+
+ ret = si_get_std_voltage_value(rdev,
+ &table->initialState.levels[0].vddc,
+ &std_vddc);
+ if (!ret)
+ si_populate_std_voltage_value(rdev, std_vddc,
+ table->initialState.levels[0].vddc.index,
+ &table->initialState.levels[0].std_vddc);
+ }
+
+ if (eg_pi->vddci_control)
+ si_populate_voltage_value(rdev,
+ &eg_pi->vddci_voltage_table,
+ initial_state->performance_levels[0].vddci,
+ &table->initialState.levels[0].vddci);
+
+ if (si_pi->vddc_phase_shed_control)
+ si_populate_phase_shedding_value(rdev,
+ &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
+ initial_state->performance_levels[0].vddc,
+ initial_state->performance_levels[0].sclk,
+ initial_state->performance_levels[0].mclk,
+ &table->initialState.levels[0].vddc);
+
+ si_populate_initial_mvdd_value(rdev, &table->initialState.levels[0].mvdd);
+
+ reg = CG_R(0xffff) | CG_L(0);
+ table->initialState.levels[0].aT = cpu_to_be32(reg);
+
+ table->initialState.levels[0].bSP = cpu_to_be32(pi->dsp);
+
+ table->initialState.levels[0].gen2PCIE = (u8)si_pi->boot_pcie_gen;
+
+ if (pi->mem_gddr5) {
+ table->initialState.levels[0].strobeMode =
+ si_get_strobe_mode_settings(rdev,
+ initial_state->performance_levels[0].mclk);
+
+ if (initial_state->performance_levels[0].mclk > pi->mclk_edc_enable_threshold)
+ table->initialState.levels[0].mcFlags = SISLANDS_SMC_MC_EDC_RD_FLAG | SISLANDS_SMC_MC_EDC_WR_FLAG;
+ else
+ table->initialState.levels[0].mcFlags = 0;
+ }
+
+ table->initialState.levelCount = 1;
+
+ table->initialState.flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ table->initialState.levels[0].dpm2.MaxPS = 0;
+ table->initialState.levels[0].dpm2.NearTDPDec = 0;
+ table->initialState.levels[0].dpm2.AboveSafeInc = 0;
+ table->initialState.levels[0].dpm2.BelowSafeInc = 0;
+ table->initialState.levels[0].dpm2.PwrEfficiencyRatio = 0;
+
+ reg = MIN_POWER_MASK | MAX_POWER_MASK;
+ table->initialState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+ reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ table->initialState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+ return 0;
+}
+
+static int si_populate_smc_acpi_state(struct radeon_device *rdev,
+ SISLANDS_SMC_STATETABLE *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3;
+ u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4;
+ u32 dll_cntl = si_pi->clock_registers.dll_cntl;
+ u32 mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl;
+ u32 mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl;
+ u32 mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl;
+ u32 mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl;
+ u32 mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1;
+ u32 mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2;
+ u32 reg;
+ int ret;
+
+ table->ACPIState = table->initialState;
+
+ table->ACPIState.flags &= ~PPSMC_SWSTATE_FLAG_DC;
+
+ if (pi->acpi_vddc) {
+ ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ pi->acpi_vddc, &table->ACPIState.levels[0].vddc);
+ if (!ret) {
+ u16 std_vddc;
+
+ ret = si_get_std_voltage_value(rdev,
+ &table->ACPIState.levels[0].vddc, &std_vddc);
+ if (!ret)
+ si_populate_std_voltage_value(rdev, std_vddc,
+ table->ACPIState.levels[0].vddc.index,
+ &table->ACPIState.levels[0].std_vddc);
+ }
+ table->ACPIState.levels[0].gen2PCIE = si_pi->acpi_pcie_gen;
+
+ if (si_pi->vddc_phase_shed_control) {
+ si_populate_phase_shedding_value(rdev,
+ &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
+ pi->acpi_vddc,
+ 0,
+ 0,
+ &table->ACPIState.levels[0].vddc);
+ }
+ } else {
+ ret = si_populate_voltage_value(rdev, &eg_pi->vddc_voltage_table,
+ pi->min_vddc_in_table, &table->ACPIState.levels[0].vddc);
+ if (!ret) {
+ u16 std_vddc;
+
+ ret = si_get_std_voltage_value(rdev,
+ &table->ACPIState.levels[0].vddc, &std_vddc);
+
+ if (!ret)
+ si_populate_std_voltage_value(rdev, std_vddc,
+ table->ACPIState.levels[0].vddc.index,
+ &table->ACPIState.levels[0].std_vddc);
+ }
+ table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(rdev,
+ si_pi->sys_pcie_mask,
+ si_pi->boot_pcie_gen,
+ RADEON_PCIE_GEN1);
+
+ if (si_pi->vddc_phase_shed_control)
+ si_populate_phase_shedding_value(rdev,
+ &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
+ pi->min_vddc_in_table,
+ 0,
+ 0,
+ &table->ACPIState.levels[0].vddc);
+ }
+
+ if (pi->acpi_vddc) {
+ if (eg_pi->acpi_vddci)
+ si_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table,
+ eg_pi->acpi_vddci,
+ &table->ACPIState.levels[0].vddci);
+ }
+
+ mclk_pwrmgt_cntl |= MRDCK0_RESET | MRDCK1_RESET;
+ mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
+
+ dll_cntl &= ~(MRDCK0_BYPASS | MRDCK1_BYPASS);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(4);
+
+ table->ACPIState.levels[0].mclk.vDLL_CNTL =
+ cpu_to_be32(dll_cntl);
+ table->ACPIState.levels[0].mclk.vMCLK_PWRMGT_CNTL =
+ cpu_to_be32(mclk_pwrmgt_cntl);
+ table->ACPIState.levels[0].mclk.vMPLL_AD_FUNC_CNTL =
+ cpu_to_be32(mpll_ad_func_cntl);
+ table->ACPIState.levels[0].mclk.vMPLL_DQ_FUNC_CNTL =
+ cpu_to_be32(mpll_dq_func_cntl);
+ table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL =
+ cpu_to_be32(mpll_func_cntl);
+ table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_1 =
+ cpu_to_be32(mpll_func_cntl_1);
+ table->ACPIState.levels[0].mclk.vMPLL_FUNC_CNTL_2 =
+ cpu_to_be32(mpll_func_cntl_2);
+ table->ACPIState.levels[0].mclk.vMPLL_SS =
+ cpu_to_be32(si_pi->clock_registers.mpll_ss1);
+ table->ACPIState.levels[0].mclk.vMPLL_SS2 =
+ cpu_to_be32(si_pi->clock_registers.mpll_ss2);
+
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL =
+ cpu_to_be32(spll_func_cntl);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_2 =
+ cpu_to_be32(spll_func_cntl_2);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_3 =
+ cpu_to_be32(spll_func_cntl_3);
+ table->ACPIState.levels[0].sclk.vCG_SPLL_FUNC_CNTL_4 =
+ cpu_to_be32(spll_func_cntl_4);
+
+ table->ACPIState.levels[0].mclk.mclk_value = 0;
+ table->ACPIState.levels[0].sclk.sclk_value = 0;
+
+ si_populate_mvdd_value(rdev, 0, &table->ACPIState.levels[0].mvdd);
+
+ if (eg_pi->dynamic_ac_timing)
+ table->ACPIState.levels[0].ACIndex = 0;
+
+ table->ACPIState.levels[0].dpm2.MaxPS = 0;
+ table->ACPIState.levels[0].dpm2.NearTDPDec = 0;
+ table->ACPIState.levels[0].dpm2.AboveSafeInc = 0;
+ table->ACPIState.levels[0].dpm2.BelowSafeInc = 0;
+ table->ACPIState.levels[0].dpm2.PwrEfficiencyRatio = 0;
+
+ reg = MIN_POWER_MASK | MAX_POWER_MASK;
+ table->ACPIState.levels[0].SQPowerThrottle = cpu_to_be32(reg);
+
+ reg = MAX_POWER_DELTA_MASK | STI_SIZE_MASK | LTI_RATIO_MASK;
+ table->ACPIState.levels[0].SQPowerThrottle_2 = cpu_to_be32(reg);
+
+ return 0;
+}
+
+static int si_populate_ulv_state(struct radeon_device *rdev,
+ SISLANDS_SMC_SWSTATE *state)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct si_ulv_param *ulv = &si_pi->ulv;
+ u32 sclk_in_sr = 1350; /* ??? */
+ int ret;
+
+ ret = si_convert_power_level_to_smc(rdev, &ulv->pl,
+ &state->levels[0]);
+ if (!ret) {
+ if (eg_pi->sclk_deep_sleep) {
+ if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ)
+ state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
+ else
+ state->levels[0].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
+ }
+ if (ulv->one_pcie_lane_in_ulv)
+ state->flags |= PPSMC_SWSTATE_FLAG_PCIE_X1;
+ state->levels[0].arbRefreshState = (u8)(SISLANDS_ULV_STATE_ARB_INDEX);
+ state->levels[0].ACIndex = 1;
+ state->levels[0].std_vddc = state->levels[0].vddc;
+ state->levelCount = 1;
+
+ state->flags |= PPSMC_SWSTATE_FLAG_DC;
+ }
+
+ return ret;
+}
+
+static int si_program_ulv_memory_timing_parameters(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct si_ulv_param *ulv = &si_pi->ulv;
+ SMC_SIslands_MCArbDramTimingRegisterSet arb_regs = { 0 };
+ int ret;
+
+ ret = si_populate_memory_timing_parameters(rdev, &ulv->pl,
+ &arb_regs);
+ if (ret)
+ return ret;
+
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_ulv_volt_change_delay,
+ ulv->volt_change_delay);
+
+ ret = si_copy_bytes_to_smc(rdev,
+ si_pi->arb_table_start +
+ offsetof(SMC_SIslands_MCArbDramTimingRegisters, data) +
+ sizeof(SMC_SIslands_MCArbDramTimingRegisterSet) * SISLANDS_ULV_STATE_ARB_INDEX,
+ (u8 *)&arb_regs,
+ sizeof(SMC_SIslands_MCArbDramTimingRegisterSet),
+ si_pi->sram_end);
+
+ return ret;
+}
+
+static void si_get_mvdd_configuration(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+
+ pi->mvdd_split_frequency = 30000;
+}
+
+static int si_init_smc_table(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct radeon_ps *radeon_boot_state = rdev->pm.dpm.boot_ps;
+ const struct si_ulv_param *ulv = &si_pi->ulv;
+ SISLANDS_SMC_STATETABLE *table = &si_pi->smc_statetable;
+ int ret;
+ u32 lane_width;
+ u32 vr_hot_gpio;
+
+ si_populate_smc_voltage_tables(rdev, table);
+
+ switch (rdev->pm.int_thermal_type) {
+ case THERMAL_TYPE_SI:
+ case THERMAL_TYPE_EMC2103_WITH_INTERNAL:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_INTERNAL;
+ break;
+ case THERMAL_TYPE_NONE:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_NONE;
+ break;
+ default:
+ table->thermalProtectType = PPSMC_THERMAL_PROTECT_TYPE_EXTERNAL;
+ break;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) {
+ if ((rdev->pdev->device != 0x6818) && (rdev->pdev->device != 0x6819))
+ table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT;
+ }
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_STEPVDDC;
+
+ if (pi->mem_gddr5)
+ table->systemFlags |= PPSMC_SYSTEMFLAG_GDDR5;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY)
+ table->systemFlags |= PPSMC_EXTRAFLAGS_AC2DC_GPIO5_POLARITY_HIGH;
+
+ if (rdev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE) {
+ table->systemFlags |= PPSMC_SYSTEMFLAG_REGULATOR_HOT_PROG_GPIO;
+ vr_hot_gpio = rdev->pm.dpm.backbias_response_time;
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_vr_hot_gpio,
+ vr_hot_gpio);
+ }
+
+ ret = si_populate_smc_initial_state(rdev, radeon_boot_state, table);
+ if (ret)
+ return ret;
+
+ ret = si_populate_smc_acpi_state(rdev, table);
+ if (ret)
+ return ret;
+
+ table->driverState = table->initialState;
+
+ ret = si_do_program_memory_timing_parameters(rdev, radeon_boot_state,
+ SISLANDS_INITIAL_STATE_ARB_INDEX);
+ if (ret)
+ return ret;
+
+ if (ulv->supported && ulv->pl.vddc) {
+ ret = si_populate_ulv_state(rdev, &table->ULVState);
+ if (ret)
+ return ret;
+
+ ret = si_program_ulv_memory_timing_parameters(rdev);
+ if (ret)
+ return ret;
+
+ WREG32(CG_ULV_CONTROL, ulv->cg_ulv_control);
+ WREG32(CG_ULV_PARAMETER, ulv->cg_ulv_parameter);
+
+ lane_width = radeon_get_pcie_lanes(rdev);
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width);
+ } else {
+ table->ULVState = table->initialState;
+ }
+
+ return si_copy_bytes_to_smc(rdev, si_pi->state_table_start,
+ (u8 *)table, sizeof(SISLANDS_SMC_STATETABLE),
+ si_pi->sram_end);
+}
+
+static int si_calculate_sclk_params(struct radeon_device *rdev,
+ u32 engine_clock,
+ SISLANDS_SMC_SCLK_VALUE *sclk)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ u32 spll_func_cntl = si_pi->clock_registers.cg_spll_func_cntl;
+ u32 spll_func_cntl_2 = si_pi->clock_registers.cg_spll_func_cntl_2;
+ u32 spll_func_cntl_3 = si_pi->clock_registers.cg_spll_func_cntl_3;
+ u32 spll_func_cntl_4 = si_pi->clock_registers.cg_spll_func_cntl_4;
+ u32 cg_spll_spread_spectrum = si_pi->clock_registers.cg_spll_spread_spectrum;
+ u32 cg_spll_spread_spectrum_2 = si_pi->clock_registers.cg_spll_spread_spectrum_2;
+ u64 tmp;
+ u32 reference_clock = rdev->clock.spll.reference_freq;
+ u32 reference_divider;
+ u32 fbdiv;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ engine_clock, false, &dividers);
+ if (ret)
+ return ret;
+
+ reference_divider = 1 + dividers.ref_div;
+
+ tmp = (u64) engine_clock * reference_divider * dividers.post_div * 16384;
+ do_div(tmp, reference_clock);
+ fbdiv = (u32) tmp;
+
+ spll_func_cntl &= ~(SPLL_PDIV_A_MASK | SPLL_REF_DIV_MASK);
+ spll_func_cntl |= SPLL_REF_DIV(dividers.ref_div);
+ spll_func_cntl |= SPLL_PDIV_A(dividers.post_div);
+
+ spll_func_cntl_2 &= ~SCLK_MUX_SEL_MASK;
+ spll_func_cntl_2 |= SCLK_MUX_SEL(2);
+
+ spll_func_cntl_3 &= ~SPLL_FB_DIV_MASK;
+ spll_func_cntl_3 |= SPLL_FB_DIV(fbdiv);
+ spll_func_cntl_3 |= SPLL_DITHEN;
+
+ if (pi->sclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 vco_freq = engine_clock * dividers.post_div;
+
+ if (radeon_atombios_get_asic_ss_info(rdev, &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 &= ~CLK_S_MASK;
+ cg_spll_spread_spectrum |= CLK_S(clk_s);
+ cg_spll_spread_spectrum |= SSEN;
+
+ cg_spll_spread_spectrum_2 &= ~CLK_V_MASK;
+ cg_spll_spread_spectrum_2 |= CLK_V(clk_v);
+ }
+ }
+
+ sclk->sclk_value = engine_clock;
+ sclk->vCG_SPLL_FUNC_CNTL = spll_func_cntl;
+ sclk->vCG_SPLL_FUNC_CNTL_2 = spll_func_cntl_2;
+ sclk->vCG_SPLL_FUNC_CNTL_3 = spll_func_cntl_3;
+ sclk->vCG_SPLL_FUNC_CNTL_4 = spll_func_cntl_4;
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cg_spll_spread_spectrum;
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cg_spll_spread_spectrum_2;
+
+ return 0;
+}
+
+static int si_populate_sclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ SISLANDS_SMC_SCLK_VALUE *sclk)
+{
+ SISLANDS_SMC_SCLK_VALUE sclk_tmp;
+ int ret;
+
+ ret = si_calculate_sclk_params(rdev, engine_clock, &sclk_tmp);
+ if (!ret) {
+ sclk->sclk_value = cpu_to_be32(sclk_tmp.sclk_value);
+ sclk->vCG_SPLL_FUNC_CNTL = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL);
+ sclk->vCG_SPLL_FUNC_CNTL_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_2);
+ sclk->vCG_SPLL_FUNC_CNTL_3 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_3);
+ sclk->vCG_SPLL_FUNC_CNTL_4 = cpu_to_be32(sclk_tmp.vCG_SPLL_FUNC_CNTL_4);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM);
+ sclk->vCG_SPLL_SPREAD_SPECTRUM_2 = cpu_to_be32(sclk_tmp.vCG_SPLL_SPREAD_SPECTRUM_2);
+ }
+
+ return ret;
+}
+
+static int si_populate_mclk_value(struct radeon_device *rdev,
+ u32 engine_clock,
+ u32 memory_clock,
+ SISLANDS_SMC_MCLK_VALUE *mclk,
+ bool strobe_mode,
+ bool dll_state_on)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 dll_cntl = si_pi->clock_registers.dll_cntl;
+ u32 mclk_pwrmgt_cntl = si_pi->clock_registers.mclk_pwrmgt_cntl;
+ u32 mpll_ad_func_cntl = si_pi->clock_registers.mpll_ad_func_cntl;
+ u32 mpll_dq_func_cntl = si_pi->clock_registers.mpll_dq_func_cntl;
+ u32 mpll_func_cntl = si_pi->clock_registers.mpll_func_cntl;
+ u32 mpll_func_cntl_1 = si_pi->clock_registers.mpll_func_cntl_1;
+ u32 mpll_func_cntl_2 = si_pi->clock_registers.mpll_func_cntl_2;
+ u32 mpll_ss1 = si_pi->clock_registers.mpll_ss1;
+ u32 mpll_ss2 = si_pi->clock_registers.mpll_ss2;
+ struct atom_mpll_param mpll_param;
+ int ret;
+
+ ret = radeon_atom_get_memory_pll_dividers(rdev, memory_clock, strobe_mode, &mpll_param);
+ if (ret)
+ return ret;
+
+ mpll_func_cntl &= ~BWCTRL_MASK;
+ mpll_func_cntl |= BWCTRL(mpll_param.bwcntl);
+
+ mpll_func_cntl_1 &= ~(CLKF_MASK | CLKFRAC_MASK | VCO_MODE_MASK);
+ mpll_func_cntl_1 |= CLKF(mpll_param.clkf) |
+ CLKFRAC(mpll_param.clkfrac) | VCO_MODE(mpll_param.vco_mode);
+
+ mpll_ad_func_cntl &= ~YCLK_POST_DIV_MASK;
+ mpll_ad_func_cntl |= YCLK_POST_DIV(mpll_param.post_div);
+
+ if (pi->mem_gddr5) {
+ mpll_dq_func_cntl &= ~(YCLK_SEL_MASK | YCLK_POST_DIV_MASK);
+ mpll_dq_func_cntl |= YCLK_SEL(mpll_param.yclk_sel) |
+ YCLK_POST_DIV(mpll_param.post_div);
+ }
+
+ if (pi->mclk_ss) {
+ struct radeon_atom_ss ss;
+ u32 freq_nom;
+ u32 tmp;
+ u32 reference_clock = rdev->clock.mpll.reference_freq;
+
+ if (pi->mem_gddr5)
+ freq_nom = memory_clock * 4;
+ else
+ freq_nom = memory_clock * 2;
+
+ tmp = freq_nom / reference_clock;
+ tmp = tmp * tmp;
+ if (radeon_atombios_get_asic_ss_info(rdev, &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 &= ~CLKV_MASK;
+ mpll_ss1 |= CLKV(clkv);
+
+ mpll_ss2 &= ~CLKS_MASK;
+ mpll_ss2 |= CLKS(clks);
+ }
+ }
+
+ mclk_pwrmgt_cntl &= ~DLL_SPEED_MASK;
+ mclk_pwrmgt_cntl |= DLL_SPEED(mpll_param.dll_speed);
+
+ if (dll_state_on)
+ mclk_pwrmgt_cntl |= MRDCK0_PDNB | MRDCK1_PDNB;
+ else
+ mclk_pwrmgt_cntl &= ~(MRDCK0_PDNB | MRDCK1_PDNB);
+
+ mclk->mclk_value = cpu_to_be32(memory_clock);
+ mclk->vMPLL_FUNC_CNTL = cpu_to_be32(mpll_func_cntl);
+ mclk->vMPLL_FUNC_CNTL_1 = cpu_to_be32(mpll_func_cntl_1);
+ mclk->vMPLL_FUNC_CNTL_2 = cpu_to_be32(mpll_func_cntl_2);
+ mclk->vMPLL_AD_FUNC_CNTL = cpu_to_be32(mpll_ad_func_cntl);
+ mclk->vMPLL_DQ_FUNC_CNTL = cpu_to_be32(mpll_dq_func_cntl);
+ mclk->vMCLK_PWRMGT_CNTL = cpu_to_be32(mclk_pwrmgt_cntl);
+ mclk->vDLL_CNTL = cpu_to_be32(dll_cntl);
+ mclk->vMPLL_SS = cpu_to_be32(mpll_ss1);
+ mclk->vMPLL_SS2 = cpu_to_be32(mpll_ss2);
+
+ return 0;
+}
+
+static void si_populate_smc_sp(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct ni_ps *ps = ni_get_ps(radeon_state);
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ int i;
+
+ for (i = 0; i < ps->performance_level_count - 1; i++)
+ smc_state->levels[i].bSP = cpu_to_be32(pi->dsp);
+
+ smc_state->levels[ps->performance_level_count - 1].bSP =
+ cpu_to_be32(pi->psp);
+}
+
+static int si_convert_power_level_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SISLANDS_SMC_HW_PERFORMANCE_LEVEL *level)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ int ret;
+ bool dll_state_on;
+ u16 std_vddc;
+ bool gmc_pg = false;
+
+ if (eg_pi->pcie_performance_request &&
+ (si_pi->force_pcie_gen != RADEON_PCIE_GEN_INVALID))
+ level->gen2PCIE = (u8)si_pi->force_pcie_gen;
+ else
+ level->gen2PCIE = (u8)pl->pcie_gen;
+
+ ret = si_populate_sclk_value(rdev, pl->sclk, &level->sclk);
+ if (ret)
+ return ret;
+
+ level->mcFlags = 0;
+
+ if (pi->mclk_stutter_mode_threshold &&
+ (pl->mclk <= pi->mclk_stutter_mode_threshold) &&
+ !eg_pi->uvd_enabled &&
+ (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) &&
+ (rdev->pm.dpm.new_active_crtc_count <= 2)) {
+ level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN;
+
+ if (gmc_pg)
+ level->mcFlags |= SISLANDS_SMC_MC_PG_EN;
+ }
+
+ if (pi->mem_gddr5) {
+ if (pl->mclk > pi->mclk_edc_enable_threshold)
+ level->mcFlags |= SISLANDS_SMC_MC_EDC_RD_FLAG;
+
+ if (pl->mclk > eg_pi->mclk_edc_wr_enable_threshold)
+ level->mcFlags |= SISLANDS_SMC_MC_EDC_WR_FLAG;
+
+ level->strobeMode = si_get_strobe_mode_settings(rdev, pl->mclk);
+
+ if (level->strobeMode & SISLANDS_SMC_STROBE_ENABLE) {
+ if (si_get_mclk_frequency_ratio(pl->mclk, true) >=
+ ((RREG32(MC_SEQ_MISC7) >> 16) & 0xf))
+ dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+ else
+ dll_state_on = ((RREG32(MC_SEQ_MISC6) >> 1) & 0x1) ? true : false;
+ } else {
+ dll_state_on = false;
+ }
+ } else {
+ level->strobeMode = si_get_strobe_mode_settings(rdev,
+ pl->mclk);
+
+ dll_state_on = ((RREG32(MC_SEQ_MISC5) >> 1) & 0x1) ? true : false;
+ }
+
+ ret = si_populate_mclk_value(rdev,
+ pl->sclk,
+ pl->mclk,
+ &level->mclk,
+ (level->strobeMode & SISLANDS_SMC_STROBE_ENABLE) != 0, dll_state_on);
+ if (ret)
+ return ret;
+
+ ret = si_populate_voltage_value(rdev,
+ &eg_pi->vddc_voltage_table,
+ pl->vddc, &level->vddc);
+ if (ret)
+ return ret;
+
+
+ ret = si_get_std_voltage_value(rdev, &level->vddc, &std_vddc);
+ if (ret)
+ return ret;
+
+ ret = si_populate_std_voltage_value(rdev, std_vddc,
+ level->vddc.index, &level->std_vddc);
+ if (ret)
+ return ret;
+
+ if (eg_pi->vddci_control) {
+ ret = si_populate_voltage_value(rdev, &eg_pi->vddci_voltage_table,
+ pl->vddci, &level->vddci);
+ if (ret)
+ return ret;
+ }
+
+ if (si_pi->vddc_phase_shed_control) {
+ ret = si_populate_phase_shedding_value(rdev,
+ &rdev->pm.dpm.dyn_state.phase_shedding_limits_table,
+ pl->vddc,
+ pl->sclk,
+ pl->mclk,
+ &level->vddc);
+ if (ret)
+ return ret;
+ }
+
+ level->MaxPoweredUpCU = si_pi->max_cu;
+
+ ret = si_populate_mvdd_value(rdev, pl->mclk, &level->mvdd);
+
+ return ret;
+}
+
+static int si_populate_smc_t(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ u32 a_t;
+ u32 t_l, t_h;
+ u32 high_bsp;
+ int i, ret;
+
+ if (state->performance_level_count >= 9)
+ return -EINVAL;
+
+ if (state->performance_level_count < 2) {
+ a_t = CG_R(0xffff) | CG_L(0);
+ smc_state->levels[0].aT = cpu_to_be32(a_t);
+ return 0;
+ }
+
+ smc_state->levels[0].aT = cpu_to_be32(0);
+
+ for (i = 0; i <= state->performance_level_count - 2; i++) {
+ ret = r600_calculate_at(
+ (50 / SISLANDS_MAX_HARDWARE_POWERLEVELS) * 100 * (i + 1),
+ 100 * R600_AH_DFLT,
+ state->performance_levels[i + 1].sclk,
+ state->performance_levels[i].sclk,
+ &t_l,
+ &t_h);
+
+ if (ret) {
+ t_h = (i + 1) * 1000 - 50 * R600_AH_DFLT;
+ t_l = (i + 1) * 1000 + 50 * R600_AH_DFLT;
+ }
+
+ a_t = be32_to_cpu(smc_state->levels[i].aT) & ~CG_R_MASK;
+ a_t |= CG_R(t_l * pi->bsp / 20000);
+ smc_state->levels[i].aT = cpu_to_be32(a_t);
+
+ high_bsp = (i == state->performance_level_count - 2) ?
+ pi->pbsp : pi->bsp;
+ a_t = CG_R(0xffff) | CG_L(t_h * high_bsp / 20000);
+ smc_state->levels[i + 1].aT = cpu_to_be32(a_t);
+ }
+
+ return 0;
+}
+
+static int si_disable_ulv(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct si_ulv_param *ulv = &si_pi->ulv;
+
+ if (ulv->supported)
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_DisableULV) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+
+ return 0;
+}
+
+static bool si_is_state_ulv_compatible(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ const struct si_power_info *si_pi = si_get_pi(rdev);
+ const struct si_ulv_param *ulv = &si_pi->ulv;
+ const struct ni_ps *state = ni_get_ps(radeon_state);
+ int i;
+
+ if (state->performance_levels[0].mclk != ulv->pl.mclk)
+ return false;
+
+ /* XXX validate against display requirements! */
+
+ for (i = 0; i < rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) {
+ if (rdev->clock.current_dispclk <=
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) {
+ if (ulv->pl.vddc <
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v)
+ return false;
+ }
+ }
+
+ if ((radeon_state->vclk != 0) || (radeon_state->dclk != 0))
+ return false;
+
+ return true;
+}
+
+static int si_set_power_state_conditionally_enable_ulv(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ const struct si_power_info *si_pi = si_get_pi(rdev);
+ const struct si_ulv_param *ulv = &si_pi->ulv;
+
+ if (ulv->supported) {
+ if (si_is_state_ulv_compatible(rdev, radeon_new_state))
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_EnableULV) == PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+ }
+ return 0;
+}
+
+static int si_convert_power_state_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SISLANDS_SMC_SWSTATE *smc_state)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct ni_power_info *ni_pi = ni_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ int i, ret;
+ u32 threshold;
+ u32 sclk_in_sr = 1350; /* ??? */
+
+ if (state->performance_level_count > SISLANDS_MAX_HARDWARE_POWERLEVELS)
+ return -EINVAL;
+
+ threshold = state->performance_levels[state->performance_level_count-1].sclk * 100 / 100;
+
+ if (radeon_state->vclk && radeon_state->dclk) {
+ eg_pi->uvd_enabled = true;
+ if (eg_pi->smu_uvd_hs)
+ smc_state->flags |= PPSMC_SWSTATE_FLAG_UVD;
+ } else {
+ eg_pi->uvd_enabled = false;
+ }
+
+ if (state->dc_compatible)
+ smc_state->flags |= PPSMC_SWSTATE_FLAG_DC;
+
+ smc_state->levelCount = 0;
+ for (i = 0; i < state->performance_level_count; i++) {
+ if (eg_pi->sclk_deep_sleep) {
+ if ((i == 0) || si_pi->sclk_deep_sleep_above_low) {
+ if (sclk_in_sr <= SCLK_MIN_DEEPSLEEP_FREQ)
+ smc_state->levels[i].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_BYPASS;
+ else
+ smc_state->levels[i].stateFlags |= PPSMC_STATEFLAG_DEEPSLEEP_THROTTLE;
+ }
+ }
+
+ ret = si_convert_power_level_to_smc(rdev, &state->performance_levels[i],
+ &smc_state->levels[i]);
+ smc_state->levels[i].arbRefreshState =
+ (u8)(SISLANDS_DRIVER_STATE_ARB_INDEX + i);
+
+ if (ret)
+ return ret;
+
+ if (ni_pi->enable_power_containment)
+ smc_state->levels[i].displayWatermark =
+ (state->performance_levels[i].sclk < threshold) ?
+ PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+ else
+ smc_state->levels[i].displayWatermark = (i < 2) ?
+ PPSMC_DISPLAY_WATERMARK_LOW : PPSMC_DISPLAY_WATERMARK_HIGH;
+
+ if (eg_pi->dynamic_ac_timing)
+ smc_state->levels[i].ACIndex = SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i;
+ else
+ smc_state->levels[i].ACIndex = 0;
+
+ smc_state->levelCount++;
+ }
+
+ si_write_smc_soft_register(rdev,
+ SI_SMC_SOFT_REGISTER_watermark_threshold,
+ threshold / 512);
+
+ si_populate_smc_sp(rdev, radeon_state, smc_state);
+
+ ret = si_populate_power_containment_values(rdev, radeon_state, smc_state);
+ if (ret)
+ ni_pi->enable_power_containment = false;
+
+ ret = si_populate_sq_ramping_values(rdev, radeon_state, smc_state);
+ if (ret)
+ ni_pi->enable_sq_ramping = false;
+
+ return si_populate_smc_t(rdev, radeon_state, smc_state);
+}
+
+static int si_upload_sw_state(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct ni_ps *new_state = ni_get_ps(radeon_new_state);
+ int ret;
+ u32 address = si_pi->state_table_start +
+ offsetof(SISLANDS_SMC_STATETABLE, driverState);
+ u32 state_size = sizeof(SISLANDS_SMC_SWSTATE) +
+ ((new_state->performance_level_count - 1) *
+ sizeof(SISLANDS_SMC_HW_PERFORMANCE_LEVEL));
+ SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.driverState;
+
+ memset(smc_state, 0, state_size);
+
+ ret = si_convert_power_state_to_smc(rdev, radeon_new_state, smc_state);
+ if (ret)
+ return ret;
+
+ ret = si_copy_bytes_to_smc(rdev, address, (u8 *)smc_state,
+ state_size, si_pi->sram_end);
+
+ return ret;
+}
+
+static int si_upload_ulv_state(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct si_ulv_param *ulv = &si_pi->ulv;
+ int ret = 0;
+
+ if (ulv->supported && ulv->pl.vddc) {
+ u32 address = si_pi->state_table_start +
+ offsetof(SISLANDS_SMC_STATETABLE, ULVState);
+ SISLANDS_SMC_SWSTATE *smc_state = &si_pi->smc_statetable.ULVState;
+ u32 state_size = sizeof(SISLANDS_SMC_SWSTATE);
+
+ memset(smc_state, 0, state_size);
+
+ ret = si_populate_ulv_state(rdev, smc_state);
+ if (!ret)
+ ret = si_copy_bytes_to_smc(rdev, address, (u8 *)smc_state,
+ state_size, si_pi->sram_end);
+ }
+
+ return ret;
+}
+
+static int si_upload_smc_data(struct radeon_device *rdev)
+{
+ struct radeon_crtc *radeon_crtc = NULL;
+ int i;
+
+ if (rdev->pm.dpm.new_active_crtc_count == 0)
+ return 0;
+
+ for (i = 0; i < rdev->num_crtc; i++) {
+ if (rdev->pm.dpm.new_active_crtcs & (1 << i)) {
+ radeon_crtc = rdev->mode_info.crtcs[i];
+ break;
+ }
+ }
+
+ if (radeon_crtc == NULL)
+ return 0;
+
+ if (radeon_crtc->line_time <= 0)
+ return 0;
+
+ if (si_write_smc_soft_register(rdev,
+ SI_SMC_SOFT_REGISTER_crtc_index,
+ radeon_crtc->crtc_id) != PPSMC_Result_OK)
+ return 0;
+
+ if (si_write_smc_soft_register(rdev,
+ SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min,
+ radeon_crtc->wm_high / radeon_crtc->line_time) != PPSMC_Result_OK)
+ return 0;
+
+ if (si_write_smc_soft_register(rdev,
+ SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max,
+ radeon_crtc->wm_low / radeon_crtc->line_time) != PPSMC_Result_OK)
+ return 0;
+
+ return 0;
+}
+
+static int si_set_mc_special_registers(struct radeon_device *rdev,
+ struct si_mc_reg_table *table)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ u8 i, j, k;
+ u32 temp_reg;
+
+ for (i = 0, j = table->last; i < table->last; i++) {
+ if (j >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ switch (table->mc_reg_address[i].s1 << 2) {
+ case MC_SEQ_MISC1:
+ temp_reg = RREG32(MC_PMG_CMD_EMRS);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_EMRS >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ 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 >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ temp_reg = RREG32(MC_PMG_CMD_MRS);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ 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 (!pi->mem_gddr5)
+ table->mc_reg_table_entry[k].mc_data[j] |= 0x100;
+ }
+ j++;
+ if (j > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+
+ if (!pi->mem_gddr5) {
+ table->mc_reg_address[j].s1 = MC_PMG_AUTO_CMD >> 2;
+ table->mc_reg_address[j].s0 = MC_PMG_AUTO_CMD >> 2;
+ 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 > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ }
+ break;
+ case MC_SEQ_RESERVE_M:
+ temp_reg = RREG32(MC_PMG_CMD_MRS1);
+ table->mc_reg_address[j].s1 = MC_PMG_CMD_MRS1 >> 2;
+ table->mc_reg_address[j].s0 = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ 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 > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+ }
+
+ table->last = j;
+
+ return 0;
+}
+
+static bool si_check_s0_mc_reg_index(u16 in_reg, u16 *out_reg)
+{
+ bool result = true;
+
+ switch (in_reg) {
+ case MC_SEQ_RAS_TIMING >> 2:
+ *out_reg = MC_SEQ_RAS_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_CAS_TIMING >> 2:
+ *out_reg = MC_SEQ_CAS_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_MISC_TIMING >> 2:
+ *out_reg = MC_SEQ_MISC_TIMING_LP >> 2;
+ break;
+ case MC_SEQ_MISC_TIMING2 >> 2:
+ *out_reg = MC_SEQ_MISC_TIMING2_LP >> 2;
+ break;
+ case MC_SEQ_RD_CTL_D0 >> 2:
+ *out_reg = MC_SEQ_RD_CTL_D0_LP >> 2;
+ break;
+ case MC_SEQ_RD_CTL_D1 >> 2:
+ *out_reg = MC_SEQ_RD_CTL_D1_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_D0 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_D0_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_D1 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_D1_LP >> 2;
+ break;
+ case MC_PMG_CMD_EMRS >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_EMRS_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS1 >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS1_LP >> 2;
+ break;
+ case MC_SEQ_PMG_TIMING >> 2:
+ *out_reg = MC_SEQ_PMG_TIMING_LP >> 2;
+ break;
+ case MC_PMG_CMD_MRS2 >> 2:
+ *out_reg = MC_SEQ_PMG_CMD_MRS2_LP >> 2;
+ break;
+ case MC_SEQ_WR_CTL_2 >> 2:
+ *out_reg = MC_SEQ_WR_CTL_2_LP >> 2;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+static void si_set_valid_flag(struct si_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 si_set_s0_mc_reg_index(struct si_mc_reg_table *table)
+{
+ u32 i;
+ u16 address;
+
+ for (i = 0; i < table->last; i++)
+ table->mc_reg_address[i].s0 = si_check_s0_mc_reg_index(table->mc_reg_address[i].s1, &address) ?
+ address : table->mc_reg_address[i].s1;
+
+}
+
+static int si_copy_vbios_mc_reg_table(struct atom_mc_reg_table *table,
+ struct si_mc_reg_table *si_table)
+{
+ u8 i, j;
+
+ if (table->last > SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
+ return -EINVAL;
+ if (table->num_entries > MAX_AC_TIMING_ENTRIES)
+ return -EINVAL;
+
+ for (i = 0; i < table->last; i++)
+ si_table->mc_reg_address[i].s1 = table->mc_reg_address[i].s1;
+ si_table->last = table->last;
+
+ for (i = 0; i < table->num_entries; i++) {
+ si_table->mc_reg_table_entry[i].mclk_max =
+ table->mc_reg_table_entry[i].mclk_max;
+ for (j = 0; j < table->last; j++) {
+ si_table->mc_reg_table_entry[i].mc_data[j] =
+ table->mc_reg_table_entry[i].mc_data[j];
+ }
+ }
+ si_table->num_entries = table->num_entries;
+
+ return 0;
+}
+
+static int si_initialize_mc_reg_table(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct atom_mc_reg_table *table;
+ struct si_mc_reg_table *si_table = &si_pi->mc_reg_table;
+ u8 module_index = rv770_get_memory_module_index(rdev);
+ int ret;
+
+ table = kzalloc(sizeof(struct atom_mc_reg_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ WREG32(MC_SEQ_RAS_TIMING_LP, RREG32(MC_SEQ_RAS_TIMING));
+ WREG32(MC_SEQ_CAS_TIMING_LP, RREG32(MC_SEQ_CAS_TIMING));
+ WREG32(MC_SEQ_MISC_TIMING_LP, RREG32(MC_SEQ_MISC_TIMING));
+ WREG32(MC_SEQ_MISC_TIMING2_LP, RREG32(MC_SEQ_MISC_TIMING2));
+ WREG32(MC_SEQ_PMG_CMD_EMRS_LP, RREG32(MC_PMG_CMD_EMRS));
+ WREG32(MC_SEQ_PMG_CMD_MRS_LP, RREG32(MC_PMG_CMD_MRS));
+ WREG32(MC_SEQ_PMG_CMD_MRS1_LP, RREG32(MC_PMG_CMD_MRS1));
+ WREG32(MC_SEQ_WR_CTL_D0_LP, RREG32(MC_SEQ_WR_CTL_D0));
+ WREG32(MC_SEQ_WR_CTL_D1_LP, RREG32(MC_SEQ_WR_CTL_D1));
+ WREG32(MC_SEQ_RD_CTL_D0_LP, RREG32(MC_SEQ_RD_CTL_D0));
+ WREG32(MC_SEQ_RD_CTL_D1_LP, RREG32(MC_SEQ_RD_CTL_D1));
+ WREG32(MC_SEQ_PMG_TIMING_LP, RREG32(MC_SEQ_PMG_TIMING));
+ WREG32(MC_SEQ_PMG_CMD_MRS2_LP, RREG32(MC_PMG_CMD_MRS2));
+ WREG32(MC_SEQ_WR_CTL_2_LP, RREG32(MC_SEQ_WR_CTL_2));
+
+ ret = radeon_atom_init_mc_reg_table(rdev, module_index, table);
+ if (ret)
+ goto init_mc_done;
+
+ ret = si_copy_vbios_mc_reg_table(table, si_table);
+ if (ret)
+ goto init_mc_done;
+
+ si_set_s0_mc_reg_index(si_table);
+
+ ret = si_set_mc_special_registers(rdev, si_table);
+ if (ret)
+ goto init_mc_done;
+
+ si_set_valid_flag(si_table);
+
+init_mc_done:
+ kfree(table);
+
+ return ret;
+
+}
+
+static void si_populate_mc_reg_addresses(struct radeon_device *rdev,
+ SMC_SIslands_MCRegisters *mc_reg_table)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 i, j;
+
+ for (i = 0, j = 0; j < si_pi->mc_reg_table.last; j++) {
+ if (si_pi->mc_reg_table.valid_flag & (1 << j)) {
+ if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+ break;
+ mc_reg_table->address[i].s0 =
+ cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s0);
+ mc_reg_table->address[i].s1 =
+ cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s1);
+ i++;
+ }
+ }
+ mc_reg_table->last = (u8)i;
+}
+
+static void si_convert_mc_registers(const struct si_mc_reg_entry *entry,
+ SMC_SIslands_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 si_convert_mc_reg_table_entry_to_smc(struct radeon_device *rdev,
+ struct rv7xx_pl *pl,
+ SMC_SIslands_MCRegisterSet *mc_reg_table_data)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 i = 0;
+
+ for (i = 0; i < si_pi->mc_reg_table.num_entries; i++) {
+ if (pl->mclk <= si_pi->mc_reg_table.mc_reg_table_entry[i].mclk_max)
+ break;
+ }
+
+ if ((i == si_pi->mc_reg_table.num_entries) && (i > 0))
+ --i;
+
+ si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[i],
+ mc_reg_table_data, si_pi->mc_reg_table.last,
+ si_pi->mc_reg_table.valid_flag);
+}
+
+static void si_convert_mc_reg_table_to_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state,
+ SMC_SIslands_MCRegisters *mc_reg_table)
+{
+ struct ni_ps *state = ni_get_ps(radeon_state);
+ int i;
+
+ for (i = 0; i < state->performance_level_count; i++) {
+ si_convert_mc_reg_table_entry_to_smc(rdev,
+ &state->performance_levels[i],
+ &mc_reg_table->data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT + i]);
+ }
+}
+
+static int si_populate_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_boot_state)
+{
+ struct ni_ps *boot_state = ni_get_ps(radeon_boot_state);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct si_ulv_param *ulv = &si_pi->ulv;
+ SMC_SIslands_MCRegisters *smc_mc_reg_table = &si_pi->smc_mc_reg_table;
+
+ memset(smc_mc_reg_table, 0, sizeof(SMC_SIslands_MCRegisters));
+
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_seq_index, 1);
+
+ si_populate_mc_reg_addresses(rdev, smc_mc_reg_table);
+
+ si_convert_mc_reg_table_entry_to_smc(rdev, &boot_state->performance_levels[0],
+ &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_INITIAL_SLOT]);
+
+ si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[0],
+ &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ACPI_SLOT],
+ si_pi->mc_reg_table.last,
+ si_pi->mc_reg_table.valid_flag);
+
+ if (ulv->supported && ulv->pl.vddc != 0)
+ si_convert_mc_reg_table_entry_to_smc(rdev, &ulv->pl,
+ &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ULV_SLOT]);
+ else
+ si_convert_mc_registers(&si_pi->mc_reg_table.mc_reg_table_entry[0],
+ &smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_ULV_SLOT],
+ si_pi->mc_reg_table.last,
+ si_pi->mc_reg_table.valid_flag);
+
+ si_convert_mc_reg_table_to_smc(rdev, radeon_boot_state, smc_mc_reg_table);
+
+ return si_copy_bytes_to_smc(rdev, si_pi->mc_reg_table_start,
+ (u8 *)smc_mc_reg_table,
+ sizeof(SMC_SIslands_MCRegisters), si_pi->sram_end);
+}
+
+static int si_upload_mc_reg_table(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state)
+{
+ struct ni_ps *new_state = ni_get_ps(radeon_new_state);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 address = si_pi->mc_reg_table_start +
+ offsetof(SMC_SIslands_MCRegisters,
+ data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT]);
+ SMC_SIslands_MCRegisters *smc_mc_reg_table = &si_pi->smc_mc_reg_table;
+
+ memset(smc_mc_reg_table, 0, sizeof(SMC_SIslands_MCRegisters));
+
+ si_convert_mc_reg_table_to_smc(rdev, radeon_new_state, smc_mc_reg_table);
+
+
+ return si_copy_bytes_to_smc(rdev, address,
+ (u8 *)&smc_mc_reg_table->data[SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT],
+ sizeof(SMC_SIslands_MCRegisterSet) * new_state->performance_level_count,
+ si_pi->sram_end);
+
+}
+
+static void si_enable_voltage_control(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(GENERAL_PWRMGT, VOLT_PWRMGT_EN, ~VOLT_PWRMGT_EN);
+ else
+ WREG32_P(GENERAL_PWRMGT, 0, ~VOLT_PWRMGT_EN);
+}
+
+static enum radeon_pcie_gen si_get_maximum_link_speed(struct radeon_device *rdev,
+ struct radeon_ps *radeon_state)
+{
+ struct ni_ps *state = ni_get_ps(radeon_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 si_get_current_pcie_speed(struct radeon_device *rdev)
+{
+ u32 speed_cntl;
+
+ speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL) & LC_CURRENT_DATA_RATE_MASK;
+ speed_cntl >>= LC_CURRENT_DATA_RATE_SHIFT;
+
+ return (u16)speed_cntl;
+}
+
+static void si_request_link_speed_change_before_state_change(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ enum radeon_pcie_gen target_link_speed = si_get_maximum_link_speed(rdev, radeon_new_state);
+ enum radeon_pcie_gen current_link_speed;
+
+ if (si_pi->force_pcie_gen == RADEON_PCIE_GEN_INVALID)
+ current_link_speed = si_get_maximum_link_speed(rdev, radeon_current_state);
+ else
+ current_link_speed = si_pi->force_pcie_gen;
+
+ si_pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID;
+ si_pi->pspp_notify_required = false;
+ if (target_link_speed > current_link_speed) {
+ switch (target_link_speed) {
+#if defined(CONFIG_ACPI)
+ case RADEON_PCIE_GEN3:
+ if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN3, false) == 0)
+ break;
+ si_pi->force_pcie_gen = RADEON_PCIE_GEN2;
+ if (current_link_speed == RADEON_PCIE_GEN2)
+ break;
+ case RADEON_PCIE_GEN2:
+ if (radeon_acpi_pcie_performance_request(rdev, PCIE_PERF_REQ_PECI_GEN2, false) == 0)
+ break;
+#endif
+ default:
+ si_pi->force_pcie_gen = si_get_current_pcie_speed(rdev);
+ break;
+ }
+ } else {
+ if (target_link_speed < current_link_speed)
+ si_pi->pspp_notify_required = true;
+ }
+}
+
+static void si_notify_link_speed_change_after_state_change(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ enum radeon_pcie_gen target_link_speed = si_get_maximum_link_speed(rdev, radeon_new_state);
+ u8 request;
+
+ if (si_pi->pspp_notify_required) {
+ if (target_link_speed == RADEON_PCIE_GEN3)
+ request = PCIE_PERF_REQ_PECI_GEN3;
+ else if (target_link_speed == RADEON_PCIE_GEN2)
+ request = PCIE_PERF_REQ_PECI_GEN2;
+ else
+ request = PCIE_PERF_REQ_PECI_GEN1;
+
+ if ((request == PCIE_PERF_REQ_PECI_GEN1) &&
+ (si_get_current_pcie_speed(rdev) > 0))
+ return;
+
+#if defined(CONFIG_ACPI)
+ radeon_acpi_pcie_performance_request(rdev, request, false);
+#endif
+ }
+}
+
+#if 0
+static int si_ds_request(struct radeon_device *rdev,
+ bool ds_status_on, u32 count_write)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+
+ if (eg_pi->sclk_deep_sleep) {
+ if (ds_status_on)
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_CancelThrottleOVRDSCLKDS) ==
+ PPSMC_Result_OK) ?
+ 0 : -EINVAL;
+ else
+ return (si_send_msg_to_smc(rdev, PPSMC_MSG_ThrottleOVRDSCLKDS) ==
+ PPSMC_Result_OK) ? 0 : -EINVAL;
+ }
+ return 0;
+}
+#endif
+
+static void si_set_max_cu_value(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+
+ if (rdev->family == CHIP_VERDE) {
+ switch (rdev->pdev->device) {
+ case 0x6820:
+ case 0x6825:
+ case 0x6821:
+ case 0x6823:
+ case 0x6827:
+ si_pi->max_cu = 10;
+ break;
+ case 0x682D:
+ case 0x6824:
+ case 0x682F:
+ case 0x6826:
+ si_pi->max_cu = 8;
+ break;
+ case 0x6828:
+ case 0x6830:
+ case 0x6831:
+ case 0x6838:
+ case 0x6839:
+ case 0x683D:
+ si_pi->max_cu = 10;
+ break;
+ case 0x683B:
+ case 0x683F:
+ case 0x6829:
+ si_pi->max_cu = 8;
+ break;
+ default:
+ si_pi->max_cu = 0;
+ break;
+ }
+ } else {
+ si_pi->max_cu = 0;
+ }
+}
+
+static int si_patch_single_dependency_table_based_on_leakage(struct radeon_device *rdev,
+ struct radeon_clock_voltage_dependency_table *table)
+{
+ u32 i;
+ int j;
+ u16 leakage_voltage;
+
+ if (table) {
+ for (i = 0; i < table->count; i++) {
+ switch (si_get_leakage_voltage_from_leakage_index(rdev,
+ table->entries[i].v,
+ &leakage_voltage)) {
+ case 0:
+ table->entries[i].v = leakage_voltage;
+ break;
+ case -EAGAIN:
+ return -EINVAL;
+ case -EINVAL:
+ default:
+ break;
+ }
+ }
+
+ for (j = (table->count - 2); j >= 0; j--) {
+ table->entries[j].v = (table->entries[j].v <= table->entries[j + 1].v) ?
+ table->entries[j].v : table->entries[j + 1].v;
+ }
+ }
+ return 0;
+}
+
+static int si_patch_dependency_tables_based_on_leakage(struct radeon_device *rdev)
+{
+ int ret = 0;
+
+ ret = si_patch_single_dependency_table_based_on_leakage(rdev,
+ &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk);
+ ret = si_patch_single_dependency_table_based_on_leakage(rdev,
+ &rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk);
+ ret = si_patch_single_dependency_table_based_on_leakage(rdev,
+ &rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk);
+ return ret;
+}
+
+static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev,
+ struct radeon_ps *radeon_new_state,
+ struct radeon_ps *radeon_current_state)
+{
+ u32 lane_width;
+ u32 new_lane_width =
+ (radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+ u32 current_lane_width =
+ (radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+
+ if (new_lane_width != current_lane_width) {
+ radeon_set_pcie_lanes(rdev, new_lane_width);
+ lane_width = radeon_get_pcie_lanes(rdev);
+ si_write_smc_soft_register(rdev, SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width, lane_width);
+ }
+}
+
+void si_dpm_setup_asic(struct radeon_device *rdev)
+{
+ rv770_get_memory_type(rdev);
+ si_read_clock_registers(rdev);
+ si_enable_acpi_power_management(rdev);
+}
+
+static int si_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp)
+{
+ int low_temp = 0 * 1000;
+ int high_temp = 255 * 1000;
+
+ 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;
+ }
+
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(high_temp / 1000), ~DIG_THERM_INTH_MASK);
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(low_temp / 1000), ~DIG_THERM_INTL_MASK);
+ WREG32_P(CG_THERMAL_CTRL, DIG_THERM_DPM(high_temp / 1000), ~DIG_THERM_DPM_MASK);
+
+ rdev->pm.dpm.thermal.min_temp = low_temp;
+ rdev->pm.dpm.thermal.max_temp = high_temp;
+
+ return 0;
+}
+
+int si_dpm_enable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+ int ret;
+
+ if (si_is_smc_running(rdev))
+ return -EINVAL;
+ if (pi->voltage_control)
+ si_enable_voltage_control(rdev, true);
+ if (pi->mvdd_control)
+ si_get_mvdd_configuration(rdev);
+ if (pi->voltage_control) {
+ ret = si_construct_voltage_tables(rdev);
+ if (ret) {
+ DRM_ERROR("si_construct_voltage_tables failed\n");
+ return ret;
+ }
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = si_initialize_mc_reg_table(rdev);
+ if (ret)
+ eg_pi->dynamic_ac_timing = false;
+ }
+ if (pi->dynamic_ss)
+ si_enable_spread_spectrum(rdev, true);
+ if (pi->thermal_protection)
+ si_enable_thermal_protection(rdev, true);
+ si_setup_bsp(rdev);
+ si_program_git(rdev);
+ si_program_tp(rdev);
+ si_program_tpp(rdev);
+ si_program_sstp(rdev);
+ si_enable_display_gap(rdev);
+ si_program_vc(rdev);
+ ret = si_upload_firmware(rdev);
+ if (ret) {
+ DRM_ERROR("si_upload_firmware failed\n");
+ return ret;
+ }
+ ret = si_process_firmware_header(rdev);
+ if (ret) {
+ DRM_ERROR("si_process_firmware_header failed\n");
+ return ret;
+ }
+ ret = si_initial_switch_from_arb_f0_to_f1(rdev);
+ if (ret) {
+ DRM_ERROR("si_initial_switch_from_arb_f0_to_f1 failed\n");
+ return ret;
+ }
+ ret = si_init_smc_table(rdev);
+ if (ret) {
+ DRM_ERROR("si_init_smc_table failed\n");
+ return ret;
+ }
+ ret = si_init_smc_spll_table(rdev);
+ if (ret) {
+ DRM_ERROR("si_init_smc_spll_table failed\n");
+ return ret;
+ }
+ ret = si_init_arb_table_index(rdev);
+ if (ret) {
+ DRM_ERROR("si_init_arb_table_index failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = si_populate_mc_reg_table(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("si_populate_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+ ret = si_initialize_smc_cac_tables(rdev);
+ if (ret) {
+ DRM_ERROR("si_initialize_smc_cac_tables failed\n");
+ return ret;
+ }
+ ret = si_initialize_hardware_cac_manager(rdev);
+ if (ret) {
+ DRM_ERROR("si_initialize_hardware_cac_manager failed\n");
+ return ret;
+ }
+ ret = si_initialize_smc_dte_tables(rdev);
+ if (ret) {
+ DRM_ERROR("si_initialize_smc_dte_tables failed\n");
+ return ret;
+ }
+ ret = si_populate_smc_tdp_limits(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("si_populate_smc_tdp_limits failed\n");
+ return ret;
+ }
+ ret = si_populate_smc_tdp_limits_2(rdev, boot_ps);
+ if (ret) {
+ DRM_ERROR("si_populate_smc_tdp_limits_2 failed\n");
+ return ret;
+ }
+ si_program_response_times(rdev);
+ si_program_ds_registers(rdev);
+ si_dpm_start_smc(rdev);
+ ret = si_notify_smc_display_change(rdev, false);
+ if (ret) {
+ DRM_ERROR("si_notify_smc_display_change failed\n");
+ return ret;
+ }
+ si_enable_sclk_control(rdev, true);
+ si_start_dpm(rdev);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ PPSMC_Result result;
+
+ ret = si_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ result = si_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
+
+ if (result != PPSMC_Result_OK)
+ DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
+ }
+
+ si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+ ni_update_current_ps(rdev, boot_ps);
+
+ return 0;
+}
+
+void si_dpm_disable(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
+
+ if (!si_is_smc_running(rdev))
+ return;
+ si_disable_ulv(rdev);
+ si_clear_vc(rdev);
+ if (pi->thermal_protection)
+ si_enable_thermal_protection(rdev, false);
+ si_enable_power_containment(rdev, boot_ps, false);
+ si_enable_smc_cac(rdev, boot_ps, false);
+ si_enable_spread_spectrum(rdev, false);
+ si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, false);
+ si_stop_dpm(rdev);
+ si_reset_to_default(rdev);
+ si_dpm_stop_smc(rdev);
+ si_force_switch_to_arb_f0(rdev);
+
+ ni_update_current_ps(rdev, boot_ps);
+}
+
+int si_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+ struct radeon_ps *new_ps = &requested_ps;
+
+ ni_update_requested_ps(rdev, new_ps);
+
+ si_apply_state_adjust_rules(rdev, &eg_pi->requested_rps);
+
+ return 0;
+}
+
+static int si_power_control_set_level(struct radeon_device *rdev)
+{
+ struct radeon_ps *new_ps = rdev->pm.dpm.requested_ps;
+ int ret;
+
+ ret = si_restrict_performance_levels_before_switch(rdev);
+ if (ret)
+ return ret;
+ ret = si_halt_smc(rdev);
+ if (ret)
+ return ret;
+ ret = si_populate_smc_tdp_limits(rdev, new_ps);
+ if (ret)
+ return ret;
+ ret = si_populate_smc_tdp_limits_2(rdev, new_ps);
+ if (ret)
+ return ret;
+ ret = si_resume_smc(rdev);
+ if (ret)
+ return ret;
+ ret = si_set_sw_state(rdev);
+ if (ret)
+ return ret;
+ return 0;
+}
+
+int si_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = &eg_pi->requested_rps;
+ struct radeon_ps *old_ps = &eg_pi->current_rps;
+ int ret;
+
+ ret = si_disable_ulv(rdev);
+ if (ret) {
+ DRM_ERROR("si_disable_ulv failed\n");
+ return ret;
+ }
+ ret = si_restrict_performance_levels_before_switch(rdev);
+ if (ret) {
+ DRM_ERROR("si_restrict_performance_levels_before_switch failed\n");
+ return ret;
+ }
+ if (eg_pi->pcie_performance_request)
+ si_request_link_speed_change_before_state_change(rdev, new_ps, old_ps);
+ ni_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ ret = si_enable_power_containment(rdev, new_ps, false);
+ if (ret) {
+ DRM_ERROR("si_enable_power_containment failed\n");
+ return ret;
+ }
+ ret = si_enable_smc_cac(rdev, new_ps, false);
+ if (ret) {
+ DRM_ERROR("si_enable_smc_cac failed\n");
+ return ret;
+ }
+ ret = si_halt_smc(rdev);
+ if (ret) {
+ DRM_ERROR("si_halt_smc failed\n");
+ return ret;
+ }
+ ret = si_upload_sw_state(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("si_upload_sw_state failed\n");
+ return ret;
+ }
+ ret = si_upload_smc_data(rdev);
+ if (ret) {
+ DRM_ERROR("si_upload_smc_data failed\n");
+ return ret;
+ }
+ ret = si_upload_ulv_state(rdev);
+ if (ret) {
+ DRM_ERROR("si_upload_ulv_state failed\n");
+ return ret;
+ }
+ if (eg_pi->dynamic_ac_timing) {
+ ret = si_upload_mc_reg_table(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("si_upload_mc_reg_table failed\n");
+ return ret;
+ }
+ }
+ ret = si_program_memory_timing_parameters(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("si_program_memory_timing_parameters failed\n");
+ return ret;
+ }
+ si_set_pcie_lane_width_in_smc(rdev, new_ps, old_ps);
+
+ ret = si_resume_smc(rdev);
+ if (ret) {
+ DRM_ERROR("si_resume_smc failed\n");
+ return ret;
+ }
+ ret = si_set_sw_state(rdev);
+ if (ret) {
+ DRM_ERROR("si_set_sw_state failed\n");
+ return ret;
+ }
+ ni_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+ if (eg_pi->pcie_performance_request)
+ si_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
+ ret = si_set_power_state_conditionally_enable_ulv(rdev, new_ps);
+ if (ret) {
+ DRM_ERROR("si_set_power_state_conditionally_enable_ulv failed\n");
+ return ret;
+ }
+ ret = si_enable_smc_cac(rdev, new_ps, true);
+ if (ret) {
+ DRM_ERROR("si_enable_smc_cac failed\n");
+ return ret;
+ }
+ ret = si_enable_power_containment(rdev, new_ps, true);
+ if (ret) {
+ DRM_ERROR("si_enable_power_containment failed\n");
+ return ret;
+ }
+
+ ret = si_power_control_set_level(rdev);
+ if (ret) {
+ DRM_ERROR("si_power_control_set_level failed\n");
+ return ret;
+ }
+
+#if 0
+ /* XXX */
+ ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
+ if (ret) {
+ DRM_ERROR("si_dpm_force_performance_level failed\n");
+ return ret;
+ }
+#else
+ rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+#endif
+
+ return 0;
+}
+
+void si_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct radeon_ps *new_ps = &eg_pi->requested_rps;
+
+ ni_update_current_ps(rdev, new_ps);
+}
+
+
+void si_dpm_reset_asic(struct radeon_device *rdev)
+{
+ si_restrict_performance_levels_before_switch(rdev);
+ si_disable_ulv(rdev);
+ si_set_boot_state(rdev);
+}
+
+void si_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+ si_program_display_gap(rdev);
+}
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void si_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_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 if (r600_is_uvd_state(rps->class, rps->class2)) {
+ rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+ rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+ } else {
+ rps->vclk = 0;
+ rps->dclk = 0;
+ }
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
+ rdev->pm.dpm.boot_ps = rps;
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void si_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+ struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ struct ni_ps *ps = ni_get_ps(rps);
+ u16 leakage_voltage;
+ struct rv7xx_pl *pl = &ps->performance_levels[index];
+ int ret;
+
+ ps->performance_level_count = index + 1;
+
+ pl->sclk = le16_to_cpu(clock_info->si.usEngineClockLow);
+ pl->sclk |= clock_info->si.ucEngineClockHigh << 16;
+ pl->mclk = le16_to_cpu(clock_info->si.usMemoryClockLow);
+ pl->mclk |= clock_info->si.ucMemoryClockHigh << 16;
+
+ pl->vddc = le16_to_cpu(clock_info->si.usVDDC);
+ pl->vddci = le16_to_cpu(clock_info->si.usVDDCI);
+ pl->flags = le32_to_cpu(clock_info->si.ulFlags);
+ pl->pcie_gen = r600_get_pcie_gen_support(rdev,
+ si_pi->sys_pcie_mask,
+ si_pi->boot_pcie_gen,
+ clock_info->si.ucPCIEGen);
+
+ /* patch up vddc if necessary */
+ ret = si_get_leakage_voltage_from_leakage_index(rdev, pl->vddc,
+ &leakage_voltage);
+ if (ret == 0)
+ pl->vddc = leakage_voltage;
+
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) {
+ pi->acpi_vddc = pl->vddc;
+ eg_pi->acpi_vddci = pl->vddci;
+ si_pi->acpi_pcie_gen = pl->pcie_gen;
+ }
+
+ if ((rps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) &&
+ index == 0) {
+ /* XXX disable for A0 tahiti */
+ si_pi->ulv.supported = true;
+ si_pi->ulv.pl = *pl;
+ si_pi->ulv.one_pcie_lane_in_ulv = false;
+ si_pi->ulv.volt_change_delay = SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT;
+ si_pi->ulv.cg_ulv_parameter = SISLANDS_CGULVPARAMETER_DFLT;
+ si_pi->ulv.cg_ulv_control = SISLANDS_CGULVCONTROL_DFLT;
+ }
+
+ if (pi->min_vddc_in_table > pl->vddc)
+ pi->min_vddc_in_table = pl->vddc;
+
+ if (pi->max_vddc_in_table < pl->vddc)
+ pi->max_vddc_in_table = pl->vddc;
+
+ /* patch up boot state */
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT) {
+ u16 vddc, vddci, mvdd;
+ radeon_atombios_get_default_voltages(rdev, &vddc, &vddci, &mvdd);
+ pl->mclk = rdev->clock.default_mclk;
+ pl->sclk = rdev->clock.default_sclk;
+ pl->vddc = vddc;
+ pl->vddci = vddci;
+ si_pi->mvdd_bootup_value = mvdd;
+ }
+
+ if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+ ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+ rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
+ }
+}
+
+static int si_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->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 ni_ps *ps;
+
+ if (!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));
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ state_array->ucNumEntries, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ power_state_offset = (u8 *)state_array->states;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->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];
+ if (!rdev->pm.power_state[i].clock_info)
+ return -EINVAL;
+ ps = kzalloc(sizeof(struct ni_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.ps[i].ps_priv = ps;
+ si_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info,
+ non_clock_info_array->ucEntrySize);
+ 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 >= SISLANDS_MAX_HARDWARE_POWERLEVELS)
+ break;
+ clock_info = (union pplib_clock_info *)
+ &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+ si_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i], k,
+ clock_info);
+ k++;
+ }
+ power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+ }
+ rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+ return 0;
+}
+
+int si_dpm_init(struct radeon_device *rdev)
+{
+ struct rv7xx_power_info *pi;
+ struct evergreen_power_info *eg_pi;
+ struct ni_power_info *ni_pi;
+ struct si_power_info *si_pi;
+ int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
+ u16 data_offset, size;
+ u8 frev, crev;
+ struct atom_clock_dividers dividers;
+ int ret;
+ u32 mask;
+
+ si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL);
+ if (si_pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = si_pi;
+ ni_pi = &si_pi->ni;
+ eg_pi = &ni_pi->eg;
+ pi = &eg_pi->rv7xx;
+
+ ret = drm_pcie_get_speed_cap_mask(rdev->ddev, &mask);
+ if (ret)
+ si_pi->sys_pcie_mask = 0;
+ else
+ si_pi->sys_pcie_mask = mask;
+ si_pi->force_pcie_gen = RADEON_PCIE_GEN_INVALID;
+ si_pi->boot_pcie_gen = si_get_current_pcie_speed(rdev);
+
+ si_set_max_cu_value(rdev);
+
+ rv770_get_max_vddc(rdev);
+ si_get_leakage_vddc(rdev);
+ si_patch_dependency_tables_based_on_leakage(rdev);
+
+ pi->acpi_vddc = 0;
+ eg_pi->acpi_vddci = 0;
+ pi->min_vddc_in_table = 0;
+ pi->max_vddc_in_table = 0;
+
+ ret = si_parse_power_table(rdev);
+ if (ret)
+ return ret;
+ ret = r600_parse_extended_power_table(rdev);
+ if (ret)
+ return ret;
+
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries =
+ kzalloc(4 * sizeof(struct radeon_clock_voltage_dependency_entry), GFP_KERNEL);
+ if (!rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries) {
+ r600_free_extended_power_table(rdev);
+ return -ENOMEM;
+ }
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count = 4;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].clk = 0;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[0].v = 0;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].clk = 36000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[1].v = 720;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].clk = 54000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[2].v = 810;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].clk = 72000;
+ rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[3].v = 900;
+
+ if (rdev->pm.dpm.voltage_response_time == 0)
+ rdev->pm.dpm.voltage_response_time = R600_VOLTAGERESPONSETIME_DFLT;
+ if (rdev->pm.dpm.backbias_response_time == 0)
+ rdev->pm.dpm.backbias_response_time = R600_BACKBIASRESPONSETIME_DFLT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 0, false, &dividers);
+ if (ret)
+ pi->ref_div = dividers.ref_div + 1;
+ else
+ pi->ref_div = R600_REFERENCEDIVIDER_DFLT;
+
+ eg_pi->smu_uvd_hs = false;
+
+ pi->mclk_strobe_mode_threshold = 40000;
+ if (si_is_special_1gb_platform(rdev))
+ pi->mclk_stutter_mode_threshold = 0;
+ else
+ pi->mclk_stutter_mode_threshold = pi->mclk_strobe_mode_threshold;
+ pi->mclk_edc_enable_threshold = 40000;
+ eg_pi->mclk_edc_wr_enable_threshold = 40000;
+
+ ni_pi->mclk_rtt_mode_threshold = eg_pi->mclk_edc_wr_enable_threshold;
+
+ pi->voltage_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_GPIO_LUT);
+
+ pi->mvdd_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, VOLTAGE_OBJ_GPIO_LUT);
+
+ eg_pi->vddci_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, VOLTAGE_OBJ_GPIO_LUT);
+
+ si_pi->vddc_phase_shed_control =
+ radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_PHASE_LUT);
+
+ if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
+ &frev, &crev, &data_offset)) {
+ pi->sclk_ss = true;
+ pi->mclk_ss = true;
+ pi->dynamic_ss = true;
+ } else {
+ pi->sclk_ss = false;
+ pi->mclk_ss = false;
+ pi->dynamic_ss = true;
+ }
+
+ pi->asi = RV770_ASI_DFLT;
+ pi->pasi = CYPRESS_HASI_DFLT;
+ pi->vrc = SISLANDS_VRC_DFLT;
+
+ pi->gfx_clock_gating = true;
+
+ eg_pi->sclk_deep_sleep = true;
+ si_pi->sclk_deep_sleep_above_low = false;
+
+ if (pi->gfx_clock_gating &&
+ (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+ pi->thermal_protection = true;
+ else
+ pi->thermal_protection = false;
+
+ eg_pi->dynamic_ac_timing = true;
+
+ eg_pi->light_sleep = true;
+#if defined(CONFIG_ACPI)
+ eg_pi->pcie_performance_request =
+ radeon_acpi_is_pcie_performance_request_supported(rdev);
+#else
+ eg_pi->pcie_performance_request = false;
+#endif
+
+ si_pi->sram_end = SMC_RAM_END;
+
+ rdev->pm.dpm.dyn_state.mclk_sclk_ratio = 4;
+ rdev->pm.dpm.dyn_state.sclk_mclk_delta = 15000;
+ rdev->pm.dpm.dyn_state.vddc_vddci_delta = 200;
+ rdev->pm.dpm.dyn_state.valid_sclk_values.count = 0;
+ rdev->pm.dpm.dyn_state.valid_sclk_values.values = NULL;
+ rdev->pm.dpm.dyn_state.valid_mclk_values.count = 0;
+ rdev->pm.dpm.dyn_state.valid_mclk_values.values = NULL;
+
+ si_initialize_powertune_defaults(rdev);
+
+ return 0;
+}
+
+void si_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+ kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries);
+ r600_free_extended_power_table(rdev);
+}
+
+void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct ni_ps *ps = ni_get_ps(rps);
+ struct rv7xx_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_INDEX_MASK) >>
+ CURRENT_STATE_INDEX_SHIFT;
+
+ if (current_index >= ps->performance_level_count) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ pl = &ps->performance_levels[current_index];
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u pcie gen: %u\n",
+ current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci, pl->pcie_gen + 1);
+ }
+}
diff --git a/drivers/gpu/drm/radeon/si_dpm.h b/drivers/gpu/drm/radeon/si_dpm.h
new file mode 100644
index 000000000000..4ce5032cdf49
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si_dpm.h
@@ -0,0 +1,227 @@
+/*
+ * 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 __SI_DPM_H__
+#define __SI_DPM_H__
+
+#include "ni_dpm.h"
+#include "sislands_smc.h"
+
+enum si_cac_config_reg_type
+{
+ SISLANDS_CACCONFIG_MMR = 0,
+ SISLANDS_CACCONFIG_CGIND,
+ SISLANDS_CACCONFIG_MAX
+};
+
+struct si_cac_config_reg
+{
+ u32 offset;
+ u32 mask;
+ u32 shift;
+ u32 value;
+ enum si_cac_config_reg_type type;
+};
+
+struct si_powertune_data
+{
+ u32 cac_window;
+ u32 l2_lta_window_size_default;
+ u8 lts_truncate_default;
+ u8 shift_n_default;
+ u8 operating_temp;
+ struct ni_leakage_coeffients leakage_coefficients;
+ u32 fixed_kt;
+ u32 lkge_lut_v0_percent;
+ u8 dc_cac[NISLANDS_DCCAC_MAX_LEVELS];
+ bool enable_powertune_by_default;
+};
+
+struct si_dyn_powertune_data
+{
+ u32 cac_leakage;
+ s32 leakage_minimum_temperature;
+ u32 wintime;
+ u32 l2_lta_window_size;
+ u8 lts_truncate;
+ u8 shift_n;
+ u8 dc_pwr_value;
+ bool disable_uvd_powertune;
+};
+
+struct si_dte_data
+{
+ u32 tau[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+ u32 r[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+ u32 k;
+ u32 t0;
+ u32 max_t;
+ u8 window_size;
+ u8 temp_select;
+ u8 dte_mode;
+ u8 tdep_count;
+ u8 t_limits[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+ u32 tdep_tau[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+ u32 tdep_r[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+ u32 t_threshold;
+ bool enable_dte_by_default;
+};
+
+struct si_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 si_mc_reg_entry {
+ u32 mclk_max;
+ u32 mc_data[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+struct si_mc_reg_table {
+ u8 last;
+ u8 num_entries;
+ u16 valid_flag;
+ struct si_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
+ SMC_NIslands_MCRegisterAddress mc_reg_address[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+#define SISLANDS_MCREGISTERTABLE_INITIAL_SLOT 0
+#define SISLANDS_MCREGISTERTABLE_ACPI_SLOT 1
+#define SISLANDS_MCREGISTERTABLE_ULV_SLOT 2
+#define SISLANDS_MCREGISTERTABLE_FIRST_DRIVERSTATE_SLOT 3
+
+struct si_leakage_voltage_entry
+{
+ u16 voltage;
+ u16 leakage_index;
+};
+
+#define SISLANDS_LEAKAGE_INDEX0 0xff01
+#define SISLANDS_MAX_LEAKAGE_COUNT 4
+
+struct si_leakage_voltage
+{
+ u16 count;
+ struct si_leakage_voltage_entry entries[SISLANDS_MAX_LEAKAGE_COUNT];
+};
+
+#define SISLANDS_MAX_HARDWARE_POWERLEVELS 5
+
+struct si_ulv_param {
+ bool supported;
+ u32 cg_ulv_control;
+ u32 cg_ulv_parameter;
+ u32 volt_change_delay;
+ struct rv7xx_pl pl;
+ bool one_pcie_lane_in_ulv;
+};
+
+struct si_power_info {
+ /* must be first! */
+ struct ni_power_info ni;
+ struct si_clock_registers clock_registers;
+ struct si_mc_reg_table mc_reg_table;
+ struct atom_voltage_table mvdd_voltage_table;
+ struct atom_voltage_table vddc_phase_shed_table;
+ struct si_leakage_voltage leakage_voltage;
+ u16 mvdd_bootup_value;
+ struct si_ulv_param ulv;
+ u32 max_cu;
+ /* pcie gen */
+ enum radeon_pcie_gen force_pcie_gen;
+ enum radeon_pcie_gen boot_pcie_gen;
+ enum radeon_pcie_gen acpi_pcie_gen;
+ u32 sys_pcie_mask;
+ /* flags */
+ bool enable_dte;
+ bool enable_ppm;
+ bool vddc_phase_shed_control;
+ bool pspp_notify_required;
+ bool sclk_deep_sleep_above_low;
+ /* smc offsets */
+ u32 sram_end;
+ u32 state_table_start;
+ u32 soft_regs_start;
+ u32 mc_reg_table_start;
+ u32 arb_table_start;
+ u32 cac_table_start;
+ u32 dte_table_start;
+ u32 spll_table_start;
+ u32 papm_cfg_table_start;
+ /* CAC stuff */
+ const struct si_cac_config_reg *cac_weights;
+ const struct si_cac_config_reg *lcac_config;
+ const struct si_cac_config_reg *cac_override;
+ const struct si_powertune_data *powertune_data;
+ struct si_dyn_powertune_data dyn_powertune_data;
+ /* DTE stuff */
+ struct si_dte_data dte_data;
+ /* scratch structs */
+ SMC_SIslands_MCRegisters smc_mc_reg_table;
+ SISLANDS_SMC_STATETABLE smc_statetable;
+ PP_SIslands_PAPMParameters papm_parm;
+};
+
+#define SISLANDS_INITIAL_STATE_ARB_INDEX 0
+#define SISLANDS_ACPI_STATE_ARB_INDEX 1
+#define SISLANDS_ULV_STATE_ARB_INDEX 2
+#define SISLANDS_DRIVER_STATE_ARB_INDEX 3
+
+#define SISLANDS_DPM2_MAX_PULSE_SKIP 256
+
+#define SISLANDS_DPM2_NEAR_TDP_DEC 10
+#define SISLANDS_DPM2_ABOVE_SAFE_INC 5
+#define SISLANDS_DPM2_BELOW_SAFE_INC 20
+
+#define SISLANDS_DPM2_TDP_SAFE_LIMIT_PERCENT 80
+
+#define SISLANDS_DPM2_MAXPS_PERCENT_H 99
+#define SISLANDS_DPM2_MAXPS_PERCENT_M 99
+
+#define SISLANDS_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
+#define SISLANDS_DPM2_SQ_RAMP_MIN_POWER 0x12
+#define SISLANDS_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
+#define SISLANDS_DPM2_SQ_RAMP_STI_SIZE 0x1E
+#define SISLANDS_DPM2_SQ_RAMP_LTI_RATIO 0xF
+
+#define SISLANDS_DPM2_PWREFFICIENCYRATIO_MARGIN 10
+
+#define SISLANDS_VRC_DFLT 0xC000B3
+#define SISLANDS_ULVVOLTAGECHANGEDELAY_DFLT 1687
+#define SISLANDS_CGULVPARAMETER_DFLT 0x00040035
+#define SISLANDS_CGULVCONTROL_DFLT 0x1f007550
+
+
+#endif
diff --git a/drivers/gpu/drm/radeon/si_smc.c b/drivers/gpu/drm/radeon/si_smc.c
new file mode 100644
index 000000000000..5f524c0a541e
--- /dev/null
+++ b/drivers/gpu/drm/radeon/si_smc.c
@@ -0,0 +1,284 @@
+/*
+ * 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 "radeon.h"
+#include "sid.h"
+#include "ppsmc.h"
+#include "radeon_ucode.h"
+
+int si_set_smc_sram_address(struct radeon_device *rdev,
+ u32 smc_address, u32 limit)
+{
+ if (smc_address & 3)
+ return -EINVAL;
+ if ((smc_address + 3) > limit)
+ return -EINVAL;
+
+ WREG32(SMC_IND_INDEX_0, smc_address);
+ WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+
+ return 0;
+}
+
+int si_copy_bytes_to_smc(struct radeon_device *rdev,
+ u32 smc_start_address,
+ const u8 *src, u32 byte_count, u32 limit)
+{
+ int ret;
+ u32 data, original_data, addr, extra_shift;
+
+ if (smc_start_address & 3)
+ return -EINVAL;
+ if ((smc_start_address + byte_count) > limit)
+ return -EINVAL;
+
+ addr = smc_start_address;
+
+ while (byte_count >= 4) {
+ /* SMC address space is BE */
+ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+ ret = si_set_smc_sram_address(rdev, addr, limit);
+ if (ret)
+ return ret;
+
+ WREG32(SMC_IND_DATA_0, data);
+
+ src += 4;
+ byte_count -= 4;
+ addr += 4;
+ }
+
+ /* RMW for the final bytes */
+ if (byte_count > 0) {
+ data = 0;
+
+ ret = si_set_smc_sram_address(rdev, addr, limit);
+ if (ret)
+ return ret;
+
+ original_data = RREG32(SMC_IND_DATA_0);
+
+ extra_shift = 8 * (4 - byte_count);
+
+ while (byte_count > 0) {
+ /* SMC address space is BE */
+ data = (data << 8) + *src++;
+ byte_count--;
+ }
+
+ data <<= extra_shift;
+
+ data |= (original_data & ~((~0UL) << extra_shift));
+
+ ret = si_set_smc_sram_address(rdev, addr, limit);
+ if (ret)
+ return ret;
+
+ WREG32(SMC_IND_DATA_0, data);
+ }
+ return 0;
+}
+
+void si_start_smc(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
+
+ tmp &= ~RST_REG;
+
+ WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
+}
+
+void si_reset_smc(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+ RREG32(CB_CGTT_SCLK_CTRL);
+
+ tmp = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
+ tmp |= RST_REG;
+ WREG32_SMC(SMC_SYSCON_RESET_CNTL, tmp);
+}
+
+int si_program_jump_on_start(struct radeon_device *rdev)
+{
+ static u8 data[] = { 0x0E, 0x00, 0x40, 0x40 };
+
+ return si_copy_bytes_to_smc(rdev, 0x0, data, 4, sizeof(data)+1);
+}
+
+void si_stop_smc_clock(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+
+ tmp |= CK_DISABLE;
+
+ WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
+}
+
+void si_start_smc_clock(struct radeon_device *rdev)
+{
+ u32 tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+
+ tmp &= ~CK_DISABLE;
+
+ WREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0, tmp);
+}
+
+bool si_is_smc_running(struct radeon_device *rdev)
+{
+ u32 rst = RREG32_SMC(SMC_SYSCON_RESET_CNTL);
+ u32 clk = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+
+ if (!(rst & RST_REG) && !(clk & CK_DISABLE))
+ return true;
+
+ return false;
+}
+
+PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
+{
+ u32 tmp;
+ int i;
+
+ if (!si_is_smc_running(rdev))
+ return PPSMC_Result_Failed;
+
+ WREG32(SMC_MESSAGE_0, msg);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = RREG32(SMC_RESP_0);
+ if (tmp != 0)
+ break;
+ udelay(1);
+ }
+ tmp = RREG32(SMC_RESP_0);
+
+ return (PPSMC_Result)tmp;
+}
+
+PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int i;
+
+ if (!si_is_smc_running(rdev))
+ return PPSMC_Result_OK;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ tmp = RREG32_SMC(SMC_SYSCON_CLOCK_CNTL_0);
+ if ((tmp & CKEN) == 0)
+ break;
+ udelay(1);
+ }
+
+ return PPSMC_Result_OK;
+}
+
+int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
+{
+ u32 ucode_start_address;
+ u32 ucode_size;
+ const u8 *src;
+ u32 data;
+
+ if (!rdev->smc_fw)
+ return -EINVAL;
+
+ switch (rdev->family) {
+ case CHIP_TAHITI:
+ ucode_start_address = TAHITI_SMC_UCODE_START;
+ ucode_size = TAHITI_SMC_UCODE_SIZE;
+ break;
+ case CHIP_PITCAIRN:
+ ucode_start_address = PITCAIRN_SMC_UCODE_START;
+ ucode_size = PITCAIRN_SMC_UCODE_SIZE;
+ break;
+ case CHIP_VERDE:
+ ucode_start_address = VERDE_SMC_UCODE_START;
+ ucode_size = VERDE_SMC_UCODE_SIZE;
+ break;
+ case CHIP_OLAND:
+ ucode_start_address = OLAND_SMC_UCODE_START;
+ ucode_size = OLAND_SMC_UCODE_SIZE;
+ break;
+ case CHIP_HAINAN:
+ ucode_start_address = HAINAN_SMC_UCODE_START;
+ ucode_size = HAINAN_SMC_UCODE_SIZE;
+ break;
+ default:
+ DRM_ERROR("unknown asic in smc ucode loader\n");
+ BUG();
+ }
+
+ if (ucode_size & 3)
+ return -EINVAL;
+
+ src = (const u8 *)rdev->smc_fw->data;
+ WREG32(SMC_IND_INDEX_0, ucode_start_address);
+ WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
+ while (ucode_size >= 4) {
+ /* SMC address space is BE */
+ data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+
+ WREG32(SMC_IND_DATA_0, data);
+
+ src += 4;
+ ucode_size -= 4;
+ }
+ WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+
+ return 0;
+}
+
+int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
+ u32 *value, u32 limit)
+{
+ int ret;
+
+ ret = si_set_smc_sram_address(rdev, smc_address, limit);
+ if (ret)
+ return ret;
+
+ *value = RREG32(SMC_IND_DATA_0);
+ return 0;
+}
+
+int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
+ u32 value, u32 limit)
+{
+ int ret;
+
+ ret = si_set_smc_sram_address(rdev, smc_address, limit);
+ if (ret)
+ return ret;
+
+ WREG32(SMC_IND_DATA_0, value);
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 8f2d7d4f9b28..12a20eb77d0c 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -30,6 +30,94 @@
#define VERDE_GB_ADDR_CONFIG_GOLDEN 0x12010002
#define HAINAN_GB_ADDR_CONFIG_GOLDEN 0x02010001
+#define SI_MAX_SH_GPRS 256
+#define SI_MAX_TEMP_GPRS 16
+#define SI_MAX_SH_THREADS 256
+#define SI_MAX_SH_STACK_ENTRIES 4096
+#define SI_MAX_FRC_EOV_CNT 16384
+#define SI_MAX_BACKENDS 8
+#define SI_MAX_BACKENDS_MASK 0xFF
+#define SI_MAX_BACKENDS_PER_SE_MASK 0x0F
+#define SI_MAX_SIMDS 12
+#define SI_MAX_SIMDS_MASK 0x0FFF
+#define SI_MAX_SIMDS_PER_SE_MASK 0x00FF
+#define SI_MAX_PIPES 8
+#define SI_MAX_PIPES_MASK 0xFF
+#define SI_MAX_PIPES_PER_SIMD_MASK 0x3F
+#define SI_MAX_LDS_NUM 0xFFFF
+#define SI_MAX_TCC 16
+#define SI_MAX_TCC_MASK 0xFFFF
+
+/* SMC IND accessor regs */
+#define SMC_IND_INDEX_0 0x200
+#define SMC_IND_DATA_0 0x204
+
+#define SMC_IND_ACCESS_CNTL 0x228
+# define AUTO_INCREMENT_IND_0 (1 << 0)
+#define SMC_MESSAGE_0 0x22c
+#define SMC_RESP_0 0x230
+
+/* CG IND registers are accessed via SMC indirect space + SMC_CG_IND_START */
+#define SMC_CG_IND_START 0xc0030000
+#define SMC_CG_IND_END 0xc0040000
+
+#define CG_CGTT_LOCAL_0 0x400
+#define CG_CGTT_LOCAL_1 0x401
+
+/* SMC IND registers */
+#define SMC_SYSCON_RESET_CNTL 0x80000000
+# define RST_REG (1 << 0)
+#define SMC_SYSCON_CLOCK_CNTL_0 0x80000004
+# define CK_DISABLE (1 << 0)
+# define CKEN (1 << 24)
+
+#define VGA_HDP_CONTROL 0x328
+#define VGA_MEMORY_DISABLE (1 << 4)
+
+#define DCCG_DISP_SLOW_SELECT_REG 0x4fc
+#define DCCG_DISP1_SLOW_SELECT(x) ((x) << 0)
+#define DCCG_DISP1_SLOW_SELECT_MASK (7 << 0)
+#define DCCG_DISP1_SLOW_SELECT_SHIFT 0
+#define DCCG_DISP2_SLOW_SELECT(x) ((x) << 4)
+#define DCCG_DISP2_SLOW_SELECT_MASK (7 << 4)
+#define DCCG_DISP2_SLOW_SELECT_SHIFT 4
+
+#define CG_SPLL_FUNC_CNTL 0x600
+#define SPLL_RESET (1 << 0)
+#define SPLL_SLEEP (1 << 1)
+#define SPLL_BYPASS_EN (1 << 3)
+#define SPLL_REF_DIV(x) ((x) << 4)
+#define SPLL_REF_DIV_MASK (0x3f << 4)
+#define SPLL_PDIV_A(x) ((x) << 20)
+#define SPLL_PDIV_A_MASK (0x7f << 20)
+#define SPLL_PDIV_A_SHIFT 20
+#define CG_SPLL_FUNC_CNTL_2 0x604
+#define SCLK_MUX_SEL(x) ((x) << 0)
+#define SCLK_MUX_SEL_MASK (0x1ff << 0)
+#define CG_SPLL_FUNC_CNTL_3 0x608
+#define SPLL_FB_DIV(x) ((x) << 0)
+#define SPLL_FB_DIV_MASK (0x3ffffff << 0)
+#define SPLL_FB_DIV_SHIFT 0
+#define SPLL_DITHEN (1 << 28)
+#define CG_SPLL_FUNC_CNTL_4 0x60c
+
+#define SPLL_CNTL_MODE 0x618
+# define SPLL_REFCLK_SEL(x) ((x) << 8)
+# define SPLL_REFCLK_SEL_MASK 0xFF00
+
+#define CG_SPLL_SPREAD_SPECTRUM 0x620
+#define SSEN (1 << 0)
+#define CLK_S(x) ((x) << 4)
+#define CLK_S_MASK (0xfff << 4)
+#define CLK_S_SHIFT 4
+#define CG_SPLL_SPREAD_SPECTRUM_2 0x624
+#define CLK_V(x) ((x) << 0)
+#define CLK_V_MASK (0x3ffffff << 0)
+#define CLK_V_SHIFT 0
+
+#define CG_SPLL_AUTOSCALE_CNTL 0x62c
+# define AUTOSCALE_ON_SS_CLEAR (1 << 9)
+
/* discrete uvd clocks */
#define CG_UPLL_FUNC_CNTL 0x634
# define UPLL_RESET_MASK 0x00000001
@@ -59,6 +147,45 @@
#define CG_UPLL_SPREAD_SPECTRUM 0x650
# define SSEN_MASK 0x00000001
+#define MPLL_BYPASSCLK_SEL 0x65c
+# define MPLL_CLKOUT_SEL(x) ((x) << 8)
+# define MPLL_CLKOUT_SEL_MASK 0xFF00
+
+#define CG_CLKPIN_CNTL 0x660
+# define XTALIN_DIVIDE (1 << 1)
+# define BCLK_AS_XCLK (1 << 2)
+#define CG_CLKPIN_CNTL_2 0x664
+# define FORCE_BIF_REFCLK_EN (1 << 3)
+# define MUX_TCLK_TO_XCLK (1 << 8)
+
+#define THM_CLK_CNTL 0x66c
+# define CMON_CLK_SEL(x) ((x) << 0)
+# define CMON_CLK_SEL_MASK 0xFF
+# define TMON_CLK_SEL(x) ((x) << 8)
+# define TMON_CLK_SEL_MASK 0xFF00
+#define MISC_CLK_CNTL 0x670
+# define DEEP_SLEEP_CLK_SEL(x) ((x) << 0)
+# define DEEP_SLEEP_CLK_SEL_MASK 0xFF
+# define ZCLK_SEL(x) ((x) << 8)
+# define ZCLK_SEL_MASK 0xFF00
+
+#define CG_THERMAL_CTRL 0x700
+#define DPM_EVENT_SRC(x) ((x) << 0)
+#define DPM_EVENT_SRC_MASK (7 << 0)
+#define DIG_THERM_DPM(x) ((x) << 14)
+#define DIG_THERM_DPM_MASK 0x003FC000
+#define DIG_THERM_DPM_SHIFT 14
+
+#define CG_THERMAL_INT 0x708
+#define DIG_THERM_INTH(x) ((x) << 8)
+#define DIG_THERM_INTH_MASK 0x0000FF00
+#define DIG_THERM_INTH_SHIFT 8
+#define DIG_THERM_INTL(x) ((x) << 16)
+#define DIG_THERM_INTL_MASK 0x00FF0000
+#define DIG_THERM_INTL_SHIFT 16
+#define THERM_INT_MASK_HIGH (1 << 24)
+#define THERM_INT_MASK_LOW (1 << 25)
+
#define CG_MULT_THERMAL_STATUS 0x714
#define ASIC_MAX_TEMP(x) ((x) << 0)
#define ASIC_MAX_TEMP_MASK 0x000001ff
@@ -67,31 +194,89 @@
#define CTF_TEMP_MASK 0x0003fe00
#define CTF_TEMP_SHIFT 9
-#define SI_MAX_SH_GPRS 256
-#define SI_MAX_TEMP_GPRS 16
-#define SI_MAX_SH_THREADS 256
-#define SI_MAX_SH_STACK_ENTRIES 4096
-#define SI_MAX_FRC_EOV_CNT 16384
-#define SI_MAX_BACKENDS 8
-#define SI_MAX_BACKENDS_MASK 0xFF
-#define SI_MAX_BACKENDS_PER_SE_MASK 0x0F
-#define SI_MAX_SIMDS 12
-#define SI_MAX_SIMDS_MASK 0x0FFF
-#define SI_MAX_SIMDS_PER_SE_MASK 0x00FF
-#define SI_MAX_PIPES 8
-#define SI_MAX_PIPES_MASK 0xFF
-#define SI_MAX_PIPES_PER_SIMD_MASK 0x3F
-#define SI_MAX_LDS_NUM 0xFFFF
-#define SI_MAX_TCC 16
-#define SI_MAX_TCC_MASK 0xFFFF
-
-#define VGA_HDP_CONTROL 0x328
-#define VGA_MEMORY_DISABLE (1 << 4)
-
-#define CG_CLKPIN_CNTL 0x660
-# define XTALIN_DIVIDE (1 << 1)
-#define CG_CLKPIN_CNTL_2 0x664
-# define MUX_TCLK_TO_XCLK (1 << 8)
+#define GENERAL_PWRMGT 0x780
+# define GLOBAL_PWRMGT_EN (1 << 0)
+# define STATIC_PM_EN (1 << 1)
+# define THERMAL_PROTECTION_DIS (1 << 2)
+# define THERMAL_PROTECTION_TYPE (1 << 3)
+# define SW_SMIO_INDEX(x) ((x) << 6)
+# define SW_SMIO_INDEX_MASK (1 << 6)
+# define SW_SMIO_INDEX_SHIFT 6
+# define VOLT_PWRMGT_EN (1 << 10)
+# define DYN_SPREAD_SPECTRUM_EN (1 << 23)
+#define CG_TPC 0x784
+#define SCLK_PWRMGT_CNTL 0x788
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_LOW_D1 (1 << 1)
+# define FIR_RESET (1 << 4)
+# define FIR_FORCE_TREND_SEL (1 << 5)
+# define FIR_TREND_MODE (1 << 6)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define GFX_CLK_REQUEST_OFF (1 << 9)
+# define GFX_CLK_FORCE_OFF (1 << 10)
+# define GFX_CLK_OFF_ACPI_D1 (1 << 11)
+# define GFX_CLK_OFF_ACPI_D2 (1 << 12)
+# define GFX_CLK_OFF_ACPI_D3 (1 << 13)
+# define DYN_LIGHT_SLEEP_EN (1 << 14)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x798
+# define CURRENT_STATE_INDEX_MASK (0xf << 4)
+# define CURRENT_STATE_INDEX_SHIFT 4
+
+#define CG_FTV 0x7bc
+
+#define CG_FFCT_0 0x7c0
+# define UTC_0(x) ((x) << 0)
+# define UTC_0_MASK (0x3ff << 0)
+# define DTC_0(x) ((x) << 10)
+# define DTC_0_MASK (0x3ff << 10)
+
+#define CG_BSP 0x7fc
+# define BSP(x) ((x) << 0)
+# define BSP_MASK (0xffff << 0)
+# define BSU(x) ((x) << 16)
+# define BSU_MASK (0xf << 16)
+#define CG_AT 0x800
+# define CG_R(x) ((x) << 0)
+# define CG_R_MASK (0xffff << 0)
+# define CG_L(x) ((x) << 16)
+# define CG_L_MASK (0xffff << 16)
+
+#define CG_GIT 0x804
+# define CG_GICST(x) ((x) << 0)
+# define CG_GICST_MASK (0xffff << 0)
+# define CG_GIPOT(x) ((x) << 16)
+# define CG_GIPOT_MASK (0xffff << 16)
+
+#define CG_SSP 0x80c
+# define SST(x) ((x) << 0)
+# define SST_MASK (0xffff << 0)
+# define SSTU(x) ((x) << 16)
+# define SSTU_MASK (0xf << 16)
+
+#define CG_DISPLAY_GAP_CNTL 0x828
+# define DISP1_GAP(x) ((x) << 0)
+# define DISP1_GAP_MASK (3 << 0)
+# define DISP2_GAP(x) ((x) << 2)
+# define DISP2_GAP_MASK (3 << 2)
+# define VBI_TIMER_COUNT(x) ((x) << 4)
+# define VBI_TIMER_COUNT_MASK (0x3fff << 4)
+# define VBI_TIMER_UNIT(x) ((x) << 20)
+# define VBI_TIMER_UNIT_MASK (7 << 20)
+# define DISP1_GAP_MCHG(x) ((x) << 24)
+# define DISP1_GAP_MCHG_MASK (3 << 24)
+# define DISP2_GAP_MCHG(x) ((x) << 26)
+# define DISP2_GAP_MCHG_MASK (3 << 26)
+
+#define CG_ULV_CONTROL 0x878
+#define CG_ULV_PARAMETER 0x87c
+
+#define SMC_SCRATCH0 0x884
+
+#define CG_CAC_CTRL 0x8b8
+# define CAC_WINDOW(x) ((x) << 0)
+# define CAC_WINDOW_MASK 0x00ffffff
#define DMIF_ADDR_CONFIG 0xBD4
@@ -203,6 +388,10 @@
#define VM_CONTEXT0_PAGE_TABLE_END_ADDR 0x157C
#define VM_CONTEXT1_PAGE_TABLE_END_ADDR 0x1580
+#define VM_L2_CG 0x15c0
+#define MC_CG_ENABLE (1 << 18)
+#define MC_LS_ENABLE (1 << 19)
+
#define MC_SHARED_CHMAP 0x2004
#define NOOFCHAN_SHIFT 12
#define NOOFCHAN_MASK 0x0000f000
@@ -228,6 +417,17 @@
#define MC_SHARED_BLACKOUT_CNTL 0x20ac
+#define MC_HUB_MISC_HUB_CG 0x20b8
+#define MC_HUB_MISC_VM_CG 0x20bc
+
+#define MC_HUB_MISC_SIP_CG 0x20c0
+
+#define MC_XPB_CLK_GAT 0x2478
+
+#define MC_CITF_MISC_RD_CG 0x2648
+#define MC_CITF_MISC_WR_CG 0x264c
+#define MC_CITF_MISC_VM_CG 0x2650
+
#define MC_ARB_RAMCFG 0x2760
#define NOOFBANK_SHIFT 0
#define NOOFBANK_MASK 0x00000003
@@ -243,6 +443,23 @@
#define NOOFGROUPS_SHIFT 12
#define NOOFGROUPS_MASK 0x00001000
+#define MC_ARB_DRAM_TIMING 0x2774
+#define MC_ARB_DRAM_TIMING2 0x2778
+
+#define MC_ARB_BURST_TIME 0x2808
+#define STATE0(x) ((x) << 0)
+#define STATE0_MASK (0x1f << 0)
+#define STATE0_SHIFT 0
+#define STATE1(x) ((x) << 5)
+#define STATE1_MASK (0x1f << 5)
+#define STATE1_SHIFT 5
+#define STATE2(x) ((x) << 10)
+#define STATE2_MASK (0x1f << 10)
+#define STATE2_SHIFT 10
+#define STATE3(x) ((x) << 15)
+#define STATE3_MASK (0x1f << 15)
+#define STATE3_SHIFT 15
+
#define MC_SEQ_TRAIN_WAKEUP_CNTL 0x2808
#define TRAIN_DONE_D0 (1 << 30)
#define TRAIN_DONE_D1 (1 << 31)
@@ -250,13 +467,105 @@
#define MC_SEQ_SUP_CNTL 0x28c8
#define RUN_MASK (1 << 0)
#define MC_SEQ_SUP_PGM 0x28cc
+#define MC_PMG_AUTO_CMD 0x28d0
#define MC_IO_PAD_CNTL_D0 0x29d0
#define MEM_FALL_OUT_CMD (1 << 8)
+#define MC_SEQ_RAS_TIMING 0x28a0
+#define MC_SEQ_CAS_TIMING 0x28a4
+#define MC_SEQ_MISC_TIMING 0x28a8
+#define MC_SEQ_MISC_TIMING2 0x28ac
+#define MC_SEQ_PMG_TIMING 0x28b0
+#define MC_SEQ_RD_CTL_D0 0x28b4
+#define MC_SEQ_RD_CTL_D1 0x28b8
+#define MC_SEQ_WR_CTL_D0 0x28bc
+#define MC_SEQ_WR_CTL_D1 0x28c0
+
+#define MC_SEQ_MISC0 0x2a00
+#define MC_SEQ_MISC0_VEN_ID_SHIFT 8
+#define MC_SEQ_MISC0_VEN_ID_MASK 0x00000f00
+#define MC_SEQ_MISC0_VEN_ID_VALUE 3
+#define MC_SEQ_MISC0_REV_ID_SHIFT 12
+#define MC_SEQ_MISC0_REV_ID_MASK 0x0000f000
+#define MC_SEQ_MISC0_REV_ID_VALUE 1
+#define MC_SEQ_MISC0_GDDR5_SHIFT 28
+#define MC_SEQ_MISC0_GDDR5_MASK 0xf0000000
+#define MC_SEQ_MISC0_GDDR5_VALUE 5
+#define MC_SEQ_MISC1 0x2a04
+#define MC_SEQ_RESERVE_M 0x2a08
+#define MC_PMG_CMD_EMRS 0x2a0c
+
#define MC_SEQ_IO_DEBUG_INDEX 0x2a44
#define MC_SEQ_IO_DEBUG_DATA 0x2a48
+#define MC_SEQ_MISC5 0x2a54
+#define MC_SEQ_MISC6 0x2a58
+
+#define MC_SEQ_MISC7 0x2a64
+
+#define MC_SEQ_RAS_TIMING_LP 0x2a6c
+#define MC_SEQ_CAS_TIMING_LP 0x2a70
+#define MC_SEQ_MISC_TIMING_LP 0x2a74
+#define MC_SEQ_MISC_TIMING2_LP 0x2a78
+#define MC_SEQ_WR_CTL_D0_LP 0x2a7c
+#define MC_SEQ_WR_CTL_D1_LP 0x2a80
+#define MC_SEQ_PMG_CMD_EMRS_LP 0x2a84
+#define MC_SEQ_PMG_CMD_MRS_LP 0x2a88
+
+#define MC_PMG_CMD_MRS 0x2aac
+
+#define MC_SEQ_RD_CTL_D0_LP 0x2b1c
+#define MC_SEQ_RD_CTL_D1_LP 0x2b20
+
+#define MC_PMG_CMD_MRS1 0x2b44
+#define MC_SEQ_PMG_CMD_MRS1_LP 0x2b48
+#define MC_SEQ_PMG_TIMING_LP 0x2b4c
+
+#define MC_SEQ_WR_CTL_2 0x2b54
+#define MC_SEQ_WR_CTL_2_LP 0x2b58
+#define MC_PMG_CMD_MRS2 0x2b5c
+#define MC_SEQ_PMG_CMD_MRS2_LP 0x2b60
+
+#define MCLK_PWRMGT_CNTL 0x2ba0
+# define DLL_SPEED(x) ((x) << 0)
+# define DLL_SPEED_MASK (0x1f << 0)
+# define DLL_READY (1 << 6)
+# define MC_INT_CNTL (1 << 7)
+# define MRDCK0_PDNB (1 << 8)
+# define MRDCK1_PDNB (1 << 9)
+# define MRDCK0_RESET (1 << 16)
+# define MRDCK1_RESET (1 << 17)
+# define DLL_READY_READ (1 << 24)
+#define DLL_CNTL 0x2ba4
+# define MRDCK0_BYPASS (1 << 24)
+# define MRDCK1_BYPASS (1 << 25)
+
+#define MPLL_FUNC_CNTL 0x2bb4
+#define BWCTRL(x) ((x) << 20)
+#define BWCTRL_MASK (0xff << 20)
+#define MPLL_FUNC_CNTL_1 0x2bb8
+#define VCO_MODE(x) ((x) << 0)
+#define VCO_MODE_MASK (3 << 0)
+#define CLKFRAC(x) ((x) << 4)
+#define CLKFRAC_MASK (0xfff << 4)
+#define CLKF(x) ((x) << 16)
+#define CLKF_MASK (0xfff << 16)
+#define MPLL_FUNC_CNTL_2 0x2bbc
+#define MPLL_AD_FUNC_CNTL 0x2bc0
+#define YCLK_POST_DIV(x) ((x) << 0)
+#define YCLK_POST_DIV_MASK (7 << 0)
+#define MPLL_DQ_FUNC_CNTL 0x2bc4
+#define YCLK_SEL(x) ((x) << 4)
+#define YCLK_SEL_MASK (1 << 4)
+
+#define MPLL_SS1 0x2bcc
+#define CLKV(x) ((x) << 0)
+#define CLKV_MASK (0x3ffffff << 0)
+#define MPLL_SS2 0x2bd0
+#define CLKS(x) ((x) << 0)
+#define CLKS_MASK (0xfff << 0)
+
#define HDP_HOST_PATH_CNTL 0x2C00
#define HDP_NONSURFACE_BASE 0x2C04
#define HDP_NONSURFACE_INFO 0x2C08
@@ -266,6 +575,8 @@
#define HDP_MISC_CNTL 0x2F4C
#define HDP_FLUSH_INVALIDATE_CACHE (1 << 0)
+#define ATC_MISC_CG 0x3350
+
#define IH_RB_CNTL 0x3e00
# define IH_RB_ENABLE (1 << 0)
# define IH_IB_SIZE(x) ((x) << 1) /* log2 */
@@ -424,6 +735,9 @@
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16)
# define DC_HPDx_EN (1 << 28)
+#define DPG_PIPE_STUTTER_CONTROL 0x6cd4
+# define STUTTER_ENABLE (1 << 0)
+
/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
#define CRTC_STATUS_FRAME_COUNT 0x6e98
@@ -599,6 +913,24 @@
#define SQC_CACHES 0x8C08
+#define SQ_POWER_THROTTLE 0x8e58
+#define MIN_POWER(x) ((x) << 0)
+#define MIN_POWER_MASK (0x3fff << 0)
+#define MIN_POWER_SHIFT 0
+#define MAX_POWER(x) ((x) << 16)
+#define MAX_POWER_MASK (0x3fff << 16)
+#define MAX_POWER_SHIFT 0
+#define SQ_POWER_THROTTLE2 0x8e5c
+#define MAX_POWER_DELTA(x) ((x) << 0)
+#define MAX_POWER_DELTA_MASK (0x3fff << 0)
+#define MAX_POWER_DELTA_SHIFT 0
+#define STI_SIZE(x) ((x) << 16)
+#define STI_SIZE_MASK (0x3ff << 16)
+#define STI_SIZE_SHIFT 16
+#define LTI_RATIO(x) ((x) << 27)
+#define LTI_RATIO_MASK (0xf << 27)
+#define LTI_RATIO_SHIFT 27
+
#define SX_DEBUG_1 0x9060
#define SPI_STATIC_THREAD_MGMT_1 0x90E0
@@ -616,6 +948,11 @@
#define CGTS_USER_TCC_DISABLE 0x914C
#define TCC_DISABLE_MASK 0xFFFF0000
#define TCC_DISABLE_SHIFT 16
+#define CGTS_SM_CTRL_REG 0x9150
+#define OVERRIDE (1 << 21)
+#define LS_OVERRIDE (1 << 22)
+
+#define SPI_LB_CU_MASK 0x9354
#define TA_CNTL_AUX 0x9508
@@ -705,6 +1042,8 @@
#define CB_PERFCOUNTER3_SELECT0 0x9a38
#define CB_PERFCOUNTER3_SELECT1 0x9a3c
+#define CB_CGTT_SCLK_CTRL 0x9a60
+
#define GC_USER_RB_BACKEND_DISABLE 0x9B7C
#define BACKEND_DISABLE_MASK 0x00FF0000
#define BACKEND_DISABLE_SHIFT 16
@@ -762,6 +1101,9 @@
# define CP_RINGID1_INT_STAT (1 << 30)
# define CP_RINGID0_INT_STAT (1 << 31)
+#define CP_MEM_SLP_CNTL 0xC1E4
+# define CP_MEM_LS_EN (1 << 0)
+
#define CP_DEBUG 0xC1FC
#define RLC_CNTL 0xC300
@@ -769,6 +1111,7 @@
#define RLC_RL_BASE 0xC304
#define RLC_RL_SIZE 0xC308
#define RLC_LB_CNTL 0xC30C
+# define LOAD_BALANCE_ENABLE (1 << 0)
#define RLC_SAVE_AND_RESTORE_BASE 0xC310
#define RLC_LB_CNTR_MAX 0xC314
#define RLC_LB_CNTR_INIT 0xC318
@@ -783,6 +1126,56 @@
#define RLC_CAPTURE_GPU_CLOCK_COUNT 0xC340
#define RLC_MC_CNTL 0xC344
#define RLC_UCODE_CNTL 0xC348
+#define RLC_STAT 0xC34C
+# define RLC_BUSY_STATUS (1 << 0)
+# define GFX_POWER_STATUS (1 << 1)
+# define GFX_CLOCK_STATUS (1 << 2)
+# define GFX_LS_STATUS (1 << 3)
+
+#define RLC_PG_CNTL 0xC35C
+# define GFX_PG_ENABLE (1 << 0)
+# define GFX_PG_SRC (1 << 1)
+
+#define RLC_CGTT_MGCG_OVERRIDE 0xC400
+#define RLC_CGCG_CGLS_CTRL 0xC404
+# define CGCG_EN (1 << 0)
+# define CGLS_EN (1 << 1)
+
+#define RLC_TTOP_D 0xC414
+# define RLC_PUD(x) ((x) << 0)
+# define RLC_PUD_MASK (0xff << 0)
+# define RLC_PDD(x) ((x) << 8)
+# define RLC_PDD_MASK (0xff << 8)
+# define RLC_TTPD(x) ((x) << 16)
+# define RLC_TTPD_MASK (0xff << 16)
+# define RLC_MSD(x) ((x) << 24)
+# define RLC_MSD_MASK (0xff << 24)
+
+#define RLC_LB_INIT_CU_MASK 0xC41C
+
+#define RLC_PG_AO_CU_MASK 0xC42C
+#define RLC_MAX_PG_CU 0xC430
+# define MAX_PU_CU(x) ((x) << 0)
+# define MAX_PU_CU_MASK (0xff << 0)
+#define RLC_AUTO_PG_CTRL 0xC434
+# define AUTO_PG_EN (1 << 0)
+# define GRBM_REG_SGIT(x) ((x) << 3)
+# define GRBM_REG_SGIT_MASK (0xffff << 3)
+# define PG_AFTER_GRBM_REG_ST(x) ((x) << 19)
+# define PG_AFTER_GRBM_REG_ST_MASK (0x1fff << 19)
+
+#define RLC_SERDES_WR_MASTER_MASK_0 0xC454
+#define RLC_SERDES_WR_MASTER_MASK_1 0xC458
+#define RLC_SERDES_WR_CTRL 0xC45C
+
+#define RLC_SERDES_MASTER_BUSY_0 0xC464
+#define RLC_SERDES_MASTER_BUSY_1 0xC468
+
+#define RLC_GCPM_GENERAL_3 0xC478
+
+#define DB_RENDER_CONTROL 0x28000
+
+#define DB_DEPTH_INFO 0x2803c
#define PA_SC_RASTER_CONFIG 0x28350
# define RASTER_CONFIG_RB_MAP_0 0
@@ -829,6 +1222,146 @@
# define THREAD_TRACE_FLUSH (54 << 0)
# define THREAD_TRACE_FINISH (55 << 0)
+/* PIF PHY0 registers idx/data 0x8/0xc */
+#define PB0_PIF_CNTL 0x10
+# define LS2_EXIT_TIME(x) ((x) << 17)
+# define LS2_EXIT_TIME_MASK (0x7 << 17)
+# define LS2_EXIT_TIME_SHIFT 17
+#define PB0_PIF_PAIRING 0x11
+# define MULTI_PIF (1 << 25)
+#define PB0_PIF_PWRDOWN_0 0x12
+# define PLL_POWER_STATE_IN_TXS2_0(x) ((x) << 7)
+# define PLL_POWER_STATE_IN_TXS2_0_MASK (0x7 << 7)
+# define PLL_POWER_STATE_IN_TXS2_0_SHIFT 7
+# define PLL_POWER_STATE_IN_OFF_0(x) ((x) << 10)
+# define PLL_POWER_STATE_IN_OFF_0_MASK (0x7 << 10)
+# define PLL_POWER_STATE_IN_OFF_0_SHIFT 10
+# define PLL_RAMP_UP_TIME_0(x) ((x) << 24)
+# define PLL_RAMP_UP_TIME_0_MASK (0x7 << 24)
+# define PLL_RAMP_UP_TIME_0_SHIFT 24
+#define PB0_PIF_PWRDOWN_1 0x13
+# define PLL_POWER_STATE_IN_TXS2_1(x) ((x) << 7)
+# define PLL_POWER_STATE_IN_TXS2_1_MASK (0x7 << 7)
+# define PLL_POWER_STATE_IN_TXS2_1_SHIFT 7
+# define PLL_POWER_STATE_IN_OFF_1(x) ((x) << 10)
+# define PLL_POWER_STATE_IN_OFF_1_MASK (0x7 << 10)
+# define PLL_POWER_STATE_IN_OFF_1_SHIFT 10
+# define PLL_RAMP_UP_TIME_1(x) ((x) << 24)
+# define PLL_RAMP_UP_TIME_1_MASK (0x7 << 24)
+# define PLL_RAMP_UP_TIME_1_SHIFT 24
+
+#define PB0_PIF_PWRDOWN_2 0x17
+# define PLL_POWER_STATE_IN_TXS2_2(x) ((x) << 7)
+# define PLL_POWER_STATE_IN_TXS2_2_MASK (0x7 << 7)
+# define PLL_POWER_STATE_IN_TXS2_2_SHIFT 7
+# define PLL_POWER_STATE_IN_OFF_2(x) ((x) << 10)
+# define PLL_POWER_STATE_IN_OFF_2_MASK (0x7 << 10)
+# define PLL_POWER_STATE_IN_OFF_2_SHIFT 10
+# define PLL_RAMP_UP_TIME_2(x) ((x) << 24)
+# define PLL_RAMP_UP_TIME_2_MASK (0x7 << 24)
+# define PLL_RAMP_UP_TIME_2_SHIFT 24
+#define PB0_PIF_PWRDOWN_3 0x18
+# define PLL_POWER_STATE_IN_TXS2_3(x) ((x) << 7)
+# define PLL_POWER_STATE_IN_TXS2_3_MASK (0x7 << 7)
+# define PLL_POWER_STATE_IN_TXS2_3_SHIFT 7
+# define PLL_POWER_STATE_IN_OFF_3(x) ((x) << 10)
+# define PLL_POWER_STATE_IN_OFF_3_MASK (0x7 << 10)
+# define PLL_POWER_STATE_IN_OFF_3_SHIFT 10
+# define PLL_RAMP_UP_TIME_3(x) ((x) << 24)
+# define PLL_RAMP_UP_TIME_3_MASK (0x7 << 24)
+# define PLL_RAMP_UP_TIME_3_SHIFT 24
+/* PIF PHY1 registers idx/data 0x10/0x14 */
+#define PB1_PIF_CNTL 0x10
+#define PB1_PIF_PAIRING 0x11
+#define PB1_PIF_PWRDOWN_0 0x12
+#define PB1_PIF_PWRDOWN_1 0x13
+
+#define PB1_PIF_PWRDOWN_2 0x17
+#define PB1_PIF_PWRDOWN_3 0x18
+/* PCIE registers idx/data 0x30/0x34 */
+#define PCIE_CNTL2 0x1c /* PCIE */
+# define SLV_MEM_LS_EN (1 << 16)
+# define MST_MEM_LS_EN (1 << 18)
+# define REPLAY_MEM_LS_EN (1 << 19)
+#define PCIE_LC_STATUS1 0x28 /* PCIE */
+# define LC_REVERSE_RCVR (1 << 0)
+# define LC_REVERSE_XMIT (1 << 1)
+# define LC_OPERATING_LINK_WIDTH_MASK (0x7 << 2)
+# define LC_OPERATING_LINK_WIDTH_SHIFT 2
+# define LC_DETECTED_LINK_WIDTH_MASK (0x7 << 5)
+# define LC_DETECTED_LINK_WIDTH_SHIFT 5
+
+#define PCIE_P_CNTL 0x40 /* PCIE */
+# define P_IGNORE_EDB_ERR (1 << 6)
+
+/* PCIE PORT registers idx/data 0x38/0x3c */
+#define PCIE_LC_CNTL 0xa0
+# define LC_L0S_INACTIVITY(x) ((x) << 8)
+# define LC_L0S_INACTIVITY_MASK (0xf << 8)
+# define LC_L0S_INACTIVITY_SHIFT 8
+# define LC_L1_INACTIVITY(x) ((x) << 12)
+# define LC_L1_INACTIVITY_MASK (0xf << 12)
+# define LC_L1_INACTIVITY_SHIFT 12
+# define LC_PMI_TO_L1_DIS (1 << 16)
+# define LC_ASPM_TO_L1_DIS (1 << 24)
+#define PCIE_LC_LINK_WIDTH_CNTL 0xa2 /* PCIE_P */
+# define LC_LINK_WIDTH_SHIFT 0
+# define LC_LINK_WIDTH_MASK 0x7
+# define LC_LINK_WIDTH_X0 0
+# define LC_LINK_WIDTH_X1 1
+# define LC_LINK_WIDTH_X2 2
+# define LC_LINK_WIDTH_X4 3
+# define LC_LINK_WIDTH_X8 4
+# define LC_LINK_WIDTH_X16 6
+# define LC_LINK_WIDTH_RD_SHIFT 4
+# define LC_LINK_WIDTH_RD_MASK 0x70
+# define LC_RECONFIG_ARC_MISSING_ESCAPE (1 << 7)
+# define LC_RECONFIG_NOW (1 << 8)
+# define LC_RENEGOTIATION_SUPPORT (1 << 9)
+# define LC_RENEGOTIATE_EN (1 << 10)
+# define LC_SHORT_RECONFIG_EN (1 << 11)
+# define LC_UPCONFIGURE_SUPPORT (1 << 12)
+# define LC_UPCONFIGURE_DIS (1 << 13)
+# define LC_DYN_LANES_PWR_STATE(x) ((x) << 21)
+# define LC_DYN_LANES_PWR_STATE_MASK (0x3 << 21)
+# define LC_DYN_LANES_PWR_STATE_SHIFT 21
+#define PCIE_LC_N_FTS_CNTL 0xa3 /* PCIE_P */
+# define LC_XMIT_N_FTS(x) ((x) << 0)
+# define LC_XMIT_N_FTS_MASK (0xff << 0)
+# define LC_XMIT_N_FTS_SHIFT 0
+# define LC_XMIT_N_FTS_OVERRIDE_EN (1 << 8)
+# define LC_N_FTS_MASK (0xff << 24)
+#define PCIE_LC_SPEED_CNTL 0xa4 /* PCIE_P */
+# define LC_GEN2_EN_STRAP (1 << 0)
+# define LC_GEN3_EN_STRAP (1 << 1)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_EN (1 << 2)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_MASK (0x3 << 3)
+# define LC_TARGET_LINK_SPEED_OVERRIDE_SHIFT 3
+# define LC_FORCE_EN_SW_SPEED_CHANGE (1 << 5)
+# define LC_FORCE_DIS_SW_SPEED_CHANGE (1 << 6)
+# define LC_FORCE_EN_HW_SPEED_CHANGE (1 << 7)
+# define LC_FORCE_DIS_HW_SPEED_CHANGE (1 << 8)
+# define LC_INITIATE_LINK_SPEED_CHANGE (1 << 9)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_MASK (0x3 << 10)
+# define LC_SPEED_CHANGE_ATTEMPTS_ALLOWED_SHIFT 10
+# define LC_CURRENT_DATA_RATE_MASK (0x3 << 13) /* 0/1/2 = gen1/2/3 */
+# define LC_CURRENT_DATA_RATE_SHIFT 13
+# define LC_CLR_FAILED_SPD_CHANGE_CNT (1 << 16)
+# define LC_OTHER_SIDE_EVER_SENT_GEN2 (1 << 18)
+# define LC_OTHER_SIDE_SUPPORTS_GEN2 (1 << 19)
+# define LC_OTHER_SIDE_EVER_SENT_GEN3 (1 << 20)
+# define LC_OTHER_SIDE_SUPPORTS_GEN3 (1 << 21)
+
+#define PCIE_LC_CNTL2 0xb1
+# define LC_ALLOW_PDWN_IN_L1 (1 << 17)
+# define LC_ALLOW_PDWN_IN_L23 (1 << 18)
+
+#define PCIE_LC_CNTL3 0xb5 /* PCIE_P */
+# define LC_GO_TO_RECOVERY (1 << 30)
+#define PCIE_LC_CNTL4 0xb6 /* PCIE_P */
+# define LC_REDO_EQ (1 << 5)
+# define LC_SET_QUIESCE (1 << 13)
+
/*
* UVD
*/
@@ -838,6 +1371,21 @@
#define UVD_RBC_RB_RPTR 0xF690
#define UVD_RBC_RB_WPTR 0xF694
+#define UVD_CGC_CTRL 0xF4B0
+# define DCM (1 << 0)
+# define CG_DT(x) ((x) << 2)
+# define CG_DT_MASK (0xf << 2)
+# define CLK_OD(x) ((x) << 6)
+# define CLK_OD_MASK (0x1f << 6)
+
+ /* UVD CTX indirect */
+#define UVD_CGC_MEM_CTRL 0xC0
+#define UVD_CGC_CTRL2 0xC1
+# define DYN_OR_EN (1 << 0)
+# define DYN_RR_EN (1 << 1)
+# define G_DIV_ID(x) ((x) << 2)
+# define G_DIV_ID_MASK (0x7 << 2)
+
/*
* PM4
*/
@@ -1082,6 +1630,11 @@
# define DMA_IDLE (1 << 0)
#define DMA_TILING_CONFIG 0xd0b8
+#define DMA_PG 0xd0d4
+# define PG_CNTL_ENABLE (1 << 0)
+#define DMA_PGFSM_CONFIG 0xd0d8
+#define DMA_PGFSM_WRITE 0xd0dc
+
#define DMA_PACKET(cmd, b, t, s, n) ((((cmd) & 0xF) << 28) | \
(((b) & 0x1) << 26) | \
(((t) & 0x1) << 23) | \
diff --git a/drivers/gpu/drm/radeon/sislands_smc.h b/drivers/gpu/drm/radeon/sislands_smc.h
new file mode 100644
index 000000000000..5578e9837026
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sislands_smc.h
@@ -0,0 +1,397 @@
+/*
+ * 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 PP_SISLANDS_SMC_H
+#define PP_SISLANDS_SMC_H
+
+#include "ppsmc.h"
+
+#pragma pack(push, 1)
+
+#define SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE 16
+
+struct PP_SIslands_Dpm2PerfLevel
+{
+ uint8_t MaxPS;
+ uint8_t TgtAct;
+ uint8_t MaxPS_StepInc;
+ uint8_t MaxPS_StepDec;
+ uint8_t PSSamplingTime;
+ uint8_t NearTDPDec;
+ uint8_t AboveSafeInc;
+ uint8_t BelowSafeInc;
+ uint8_t PSDeltaLimit;
+ uint8_t PSDeltaWin;
+ uint16_t PwrEfficiencyRatio;
+ uint8_t Reserved[4];
+};
+
+typedef struct PP_SIslands_Dpm2PerfLevel PP_SIslands_Dpm2PerfLevel;
+
+struct PP_SIslands_DPM2Status
+{
+ uint32_t dpm2Flags;
+ uint8_t CurrPSkip;
+ uint8_t CurrPSkipPowerShift;
+ uint8_t CurrPSkipTDP;
+ uint8_t CurrPSkipOCP;
+ uint8_t MaxSPLLIndex;
+ uint8_t MinSPLLIndex;
+ uint8_t CurrSPLLIndex;
+ uint8_t InfSweepMode;
+ uint8_t InfSweepDir;
+ uint8_t TDPexceeded;
+ uint8_t reserved;
+ uint8_t SwitchDownThreshold;
+ uint32_t SwitchDownCounter;
+ uint32_t SysScalingFactor;
+};
+
+typedef struct PP_SIslands_DPM2Status PP_SIslands_DPM2Status;
+
+struct PP_SIslands_DPM2Parameters
+{
+ uint32_t TDPLimit;
+ uint32_t NearTDPLimit;
+ uint32_t SafePowerLimit;
+ uint32_t PowerBoostLimit;
+ uint32_t MinLimitDelta;
+};
+typedef struct PP_SIslands_DPM2Parameters PP_SIslands_DPM2Parameters;
+
+struct PP_SIslands_PAPMStatus
+{
+ uint32_t EstimatedDGPU_T;
+ uint32_t EstimatedDGPU_P;
+ uint32_t EstimatedAPU_T;
+ uint32_t EstimatedAPU_P;
+ uint8_t dGPU_T_Limit_Exceeded;
+ uint8_t reserved[3];
+};
+typedef struct PP_SIslands_PAPMStatus PP_SIslands_PAPMStatus;
+
+struct PP_SIslands_PAPMParameters
+{
+ uint32_t NearTDPLimitTherm;
+ uint32_t NearTDPLimitPAPM;
+ uint32_t PlatformPowerLimit;
+ uint32_t dGPU_T_Limit;
+ uint32_t dGPU_T_Warning;
+ uint32_t dGPU_T_Hysteresis;
+};
+typedef struct PP_SIslands_PAPMParameters PP_SIslands_PAPMParameters;
+
+struct SISLANDS_SMC_SCLK_VALUE
+{
+ uint32_t vCG_SPLL_FUNC_CNTL;
+ uint32_t vCG_SPLL_FUNC_CNTL_2;
+ uint32_t vCG_SPLL_FUNC_CNTL_3;
+ uint32_t vCG_SPLL_FUNC_CNTL_4;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM;
+ uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
+ uint32_t sclk_value;
+};
+
+typedef struct SISLANDS_SMC_SCLK_VALUE SISLANDS_SMC_SCLK_VALUE;
+
+struct SISLANDS_SMC_MCLK_VALUE
+{
+ uint32_t vMPLL_FUNC_CNTL;
+ uint32_t vMPLL_FUNC_CNTL_1;
+ uint32_t vMPLL_FUNC_CNTL_2;
+ uint32_t vMPLL_AD_FUNC_CNTL;
+ uint32_t vMPLL_DQ_FUNC_CNTL;
+ uint32_t vMCLK_PWRMGT_CNTL;
+ uint32_t vDLL_CNTL;
+ uint32_t vMPLL_SS;
+ uint32_t vMPLL_SS2;
+ uint32_t mclk_value;
+};
+
+typedef struct SISLANDS_SMC_MCLK_VALUE SISLANDS_SMC_MCLK_VALUE;
+
+struct SISLANDS_SMC_VOLTAGE_VALUE
+{
+ uint16_t value;
+ uint8_t index;
+ uint8_t phase_settings;
+};
+
+typedef struct SISLANDS_SMC_VOLTAGE_VALUE SISLANDS_SMC_VOLTAGE_VALUE;
+
+struct SISLANDS_SMC_HW_PERFORMANCE_LEVEL
+{
+ uint8_t ACIndex;
+ uint8_t displayWatermark;
+ uint8_t gen2PCIE;
+ uint8_t UVDWatermark;
+ uint8_t VCEWatermark;
+ uint8_t strobeMode;
+ uint8_t mcFlags;
+ uint8_t padding;
+ uint32_t aT;
+ uint32_t bSP;
+ SISLANDS_SMC_SCLK_VALUE sclk;
+ SISLANDS_SMC_MCLK_VALUE mclk;
+ SISLANDS_SMC_VOLTAGE_VALUE vddc;
+ SISLANDS_SMC_VOLTAGE_VALUE mvdd;
+ SISLANDS_SMC_VOLTAGE_VALUE vddci;
+ SISLANDS_SMC_VOLTAGE_VALUE std_vddc;
+ uint8_t hysteresisUp;
+ uint8_t hysteresisDown;
+ uint8_t stateFlags;
+ uint8_t arbRefreshState;
+ uint32_t SQPowerThrottle;
+ uint32_t SQPowerThrottle_2;
+ uint32_t MaxPoweredUpCU;
+ SISLANDS_SMC_VOLTAGE_VALUE high_temp_vddc;
+ SISLANDS_SMC_VOLTAGE_VALUE low_temp_vddc;
+ uint32_t reserved[2];
+ PP_SIslands_Dpm2PerfLevel dpm2;
+};
+
+#define SISLANDS_SMC_STROBE_RATIO 0x0F
+#define SISLANDS_SMC_STROBE_ENABLE 0x10
+
+#define SISLANDS_SMC_MC_EDC_RD_FLAG 0x01
+#define SISLANDS_SMC_MC_EDC_WR_FLAG 0x02
+#define SISLANDS_SMC_MC_RTT_ENABLE 0x04
+#define SISLANDS_SMC_MC_STUTTER_EN 0x08
+#define SISLANDS_SMC_MC_PG_EN 0x10
+
+typedef struct SISLANDS_SMC_HW_PERFORMANCE_LEVEL SISLANDS_SMC_HW_PERFORMANCE_LEVEL;
+
+struct SISLANDS_SMC_SWSTATE
+{
+ uint8_t flags;
+ uint8_t levelCount;
+ uint8_t padding2;
+ uint8_t padding3;
+ SISLANDS_SMC_HW_PERFORMANCE_LEVEL levels[1];
+};
+
+typedef struct SISLANDS_SMC_SWSTATE SISLANDS_SMC_SWSTATE;
+
+#define SISLANDS_SMC_VOLTAGEMASK_VDDC 0
+#define SISLANDS_SMC_VOLTAGEMASK_MVDD 1
+#define SISLANDS_SMC_VOLTAGEMASK_VDDCI 2
+#define SISLANDS_SMC_VOLTAGEMASK_MAX 4
+
+struct SISLANDS_SMC_VOLTAGEMASKTABLE
+{
+ uint32_t lowMask[SISLANDS_SMC_VOLTAGEMASK_MAX];
+};
+
+typedef struct SISLANDS_SMC_VOLTAGEMASKTABLE SISLANDS_SMC_VOLTAGEMASKTABLE;
+
+#define SISLANDS_MAX_NO_VREG_STEPS 32
+
+struct SISLANDS_SMC_STATETABLE
+{
+ uint8_t thermalProtectType;
+ uint8_t systemFlags;
+ uint8_t maxVDDCIndexInPPTable;
+ uint8_t extraFlags;
+ uint32_t lowSMIO[SISLANDS_MAX_NO_VREG_STEPS];
+ SISLANDS_SMC_VOLTAGEMASKTABLE voltageMaskTable;
+ SISLANDS_SMC_VOLTAGEMASKTABLE phaseMaskTable;
+ PP_SIslands_DPM2Parameters dpm2Params;
+ SISLANDS_SMC_SWSTATE initialState;
+ SISLANDS_SMC_SWSTATE ACPIState;
+ SISLANDS_SMC_SWSTATE ULVState;
+ SISLANDS_SMC_SWSTATE driverState;
+ SISLANDS_SMC_HW_PERFORMANCE_LEVEL dpmLevels[SISLANDS_MAX_SMC_PERFORMANCE_LEVELS_PER_SWSTATE - 1];
+};
+
+typedef struct SISLANDS_SMC_STATETABLE SISLANDS_SMC_STATETABLE;
+
+#define SI_SMC_SOFT_REGISTER_mclk_chg_timeout 0x0
+#define SI_SMC_SOFT_REGISTER_delay_vreg 0xC
+#define SI_SMC_SOFT_REGISTER_delay_acpi 0x28
+#define SI_SMC_SOFT_REGISTER_seq_index 0x5C
+#define SI_SMC_SOFT_REGISTER_mvdd_chg_time 0x60
+#define SI_SMC_SOFT_REGISTER_mclk_switch_lim 0x70
+#define SI_SMC_SOFT_REGISTER_watermark_threshold 0x78
+#define SI_SMC_SOFT_REGISTER_phase_shedding_delay 0x88
+#define SI_SMC_SOFT_REGISTER_ulv_volt_change_delay 0x8C
+#define SI_SMC_SOFT_REGISTER_mc_block_delay 0x98
+#define SI_SMC_SOFT_REGISTER_ticks_per_us 0xA8
+#define SI_SMC_SOFT_REGISTER_crtc_index 0xC4
+#define SI_SMC_SOFT_REGISTER_mclk_change_block_cp_min 0xC8
+#define SI_SMC_SOFT_REGISTER_mclk_change_block_cp_max 0xCC
+#define SI_SMC_SOFT_REGISTER_non_ulv_pcie_link_width 0xF4
+#define SI_SMC_SOFT_REGISTER_tdr_is_about_to_happen 0xFC
+#define SI_SMC_SOFT_REGISTER_vr_hot_gpio 0x100
+
+#define SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES 16
+#define SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES 32
+
+#define SMC_SISLANDS_SCALE_I 7
+#define SMC_SISLANDS_SCALE_R 12
+
+struct PP_SIslands_CacConfig
+{
+ uint16_t cac_lkge_lut[SMC_SISLANDS_LKGE_LUT_NUM_OF_TEMP_ENTRIES][SMC_SISLANDS_LKGE_LUT_NUM_OF_VOLT_ENTRIES];
+ uint32_t lkge_lut_V0;
+ uint32_t lkge_lut_Vstep;
+ uint32_t WinTime;
+ uint32_t R_LL;
+ uint32_t calculation_repeats;
+ uint32_t l2numWin_TDP;
+ uint32_t dc_cac;
+ uint8_t lts_truncate_n;
+ uint8_t SHIFT_N;
+ uint8_t log2_PG_LKG_SCALE;
+ uint8_t cac_temp;
+ uint32_t lkge_lut_T0;
+ uint32_t lkge_lut_Tstep;
+};
+
+typedef struct PP_SIslands_CacConfig PP_SIslands_CacConfig;
+
+#define SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE 16
+#define SMC_SISLANDS_MC_REGISTER_ARRAY_SET_COUNT 20
+
+struct SMC_SIslands_MCRegisterAddress
+{
+ uint16_t s0;
+ uint16_t s1;
+};
+
+typedef struct SMC_SIslands_MCRegisterAddress SMC_SIslands_MCRegisterAddress;
+
+struct SMC_SIslands_MCRegisterSet
+{
+ uint32_t value[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+};
+
+typedef struct SMC_SIslands_MCRegisterSet SMC_SIslands_MCRegisterSet;
+
+struct SMC_SIslands_MCRegisters
+{
+ uint8_t last;
+ uint8_t reserved[3];
+ SMC_SIslands_MCRegisterAddress address[SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE];
+ SMC_SIslands_MCRegisterSet data[SMC_SISLANDS_MC_REGISTER_ARRAY_SET_COUNT];
+};
+
+typedef struct SMC_SIslands_MCRegisters SMC_SIslands_MCRegisters;
+
+struct SMC_SIslands_MCArbDramTimingRegisterSet
+{
+ uint32_t mc_arb_dram_timing;
+ uint32_t mc_arb_dram_timing2;
+ uint8_t mc_arb_rfsh_rate;
+ uint8_t mc_arb_burst_time;
+ uint8_t padding[2];
+};
+
+typedef struct SMC_SIslands_MCArbDramTimingRegisterSet SMC_SIslands_MCArbDramTimingRegisterSet;
+
+struct SMC_SIslands_MCArbDramTimingRegisters
+{
+ uint8_t arb_current;
+ uint8_t reserved[3];
+ SMC_SIslands_MCArbDramTimingRegisterSet data[16];
+};
+
+typedef struct SMC_SIslands_MCArbDramTimingRegisters SMC_SIslands_MCArbDramTimingRegisters;
+
+struct SMC_SISLANDS_SPLL_DIV_TABLE
+{
+ uint32_t freq[256];
+ uint32_t ss[256];
+};
+
+#define SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_MASK 0x01ffffff
+#define SMC_SISLANDS_SPLL_DIV_TABLE_FBDIV_SHIFT 0
+#define SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_MASK 0xfe000000
+#define SMC_SISLANDS_SPLL_DIV_TABLE_PDIV_SHIFT 25
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_MASK 0x000fffff
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKV_SHIFT 0
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_MASK 0xfff00000
+#define SMC_SISLANDS_SPLL_DIV_TABLE_CLKS_SHIFT 20
+
+typedef struct SMC_SISLANDS_SPLL_DIV_TABLE SMC_SISLANDS_SPLL_DIV_TABLE;
+
+#define SMC_SISLANDS_DTE_MAX_FILTER_STAGES 5
+
+#define SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE 16
+
+struct Smc_SIslands_DTE_Configuration
+{
+ uint32_t tau[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+ uint32_t R[SMC_SISLANDS_DTE_MAX_FILTER_STAGES];
+ uint32_t K;
+ uint32_t T0;
+ uint32_t MaxT;
+ uint8_t WindowSize;
+ uint8_t Tdep_count;
+ uint8_t temp_select;
+ uint8_t DTE_mode;
+ uint8_t T_limits[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+ uint32_t Tdep_tau[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+ uint32_t Tdep_R[SMC_SISLANDS_DTE_MAX_TEMPERATURE_DEPENDENT_ARRAY_SIZE];
+ uint32_t Tthreshold;
+};
+
+typedef struct Smc_SIslands_DTE_Configuration Smc_SIslands_DTE_Configuration;
+
+#define SMC_SISLANDS_DTE_STATUS_FLAG_DTE_ON 1
+
+#define SISLANDS_SMC_FIRMWARE_HEADER_LOCATION 0x10000
+
+#define SISLANDS_SMC_FIRMWARE_HEADER_version 0x0
+#define SISLANDS_SMC_FIRMWARE_HEADER_flags 0x4
+#define SISLANDS_SMC_FIRMWARE_HEADER_softRegisters 0xC
+#define SISLANDS_SMC_FIRMWARE_HEADER_stateTable 0x10
+#define SISLANDS_SMC_FIRMWARE_HEADER_fanTable 0x14
+#define SISLANDS_SMC_FIRMWARE_HEADER_CacConfigTable 0x18
+#define SISLANDS_SMC_FIRMWARE_HEADER_mcRegisterTable 0x24
+#define SISLANDS_SMC_FIRMWARE_HEADER_mcArbDramAutoRefreshTable 0x30
+#define SISLANDS_SMC_FIRMWARE_HEADER_spllTable 0x38
+#define SISLANDS_SMC_FIRMWARE_HEADER_DteConfiguration 0x40
+#define SISLANDS_SMC_FIRMWARE_HEADER_PAPMParameters 0x48
+
+#pragma pack(pop)
+
+int si_set_smc_sram_address(struct radeon_device *rdev,
+ u32 smc_address, u32 limit);
+int si_copy_bytes_to_smc(struct radeon_device *rdev,
+ u32 smc_start_address,
+ const u8 *src, u32 byte_count, u32 limit);
+void si_start_smc(struct radeon_device *rdev);
+void si_reset_smc(struct radeon_device *rdev);
+int si_program_jump_on_start(struct radeon_device *rdev);
+void si_stop_smc_clock(struct radeon_device *rdev);
+void si_start_smc_clock(struct radeon_device *rdev);
+bool si_is_smc_running(struct radeon_device *rdev);
+PPSMC_Result si_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg);
+PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev);
+int si_load_smc_ucode(struct radeon_device *rdev, u32 limit);
+int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
+ u32 *value, u32 limit);
+int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
+ u32 value, u32 limit);
+
+#endif
+
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
new file mode 100644
index 000000000000..11b6b9924f1b
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -0,0 +1,1876 @@
+/*
+ * 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 "radeon.h"
+#include "sumod.h"
+#include "r600_dpm.h"
+#include "cypress_dpm.h"
+#include "sumo_dpm.h"
+#include <linux/seq_file.h>
+
+#define SUMO_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define SUMO_MINIMUM_ENGINE_CLOCK 800
+#define BOOST_DPM_LEVEL 7
+
+static const u32 sumo_utc[SUMO_PM_NUMBER_OF_TC] =
+{
+ SUMO_UTC_DFLT_00,
+ SUMO_UTC_DFLT_01,
+ SUMO_UTC_DFLT_02,
+ SUMO_UTC_DFLT_03,
+ SUMO_UTC_DFLT_04,
+ SUMO_UTC_DFLT_05,
+ SUMO_UTC_DFLT_06,
+ SUMO_UTC_DFLT_07,
+ SUMO_UTC_DFLT_08,
+ SUMO_UTC_DFLT_09,
+ SUMO_UTC_DFLT_10,
+ SUMO_UTC_DFLT_11,
+ SUMO_UTC_DFLT_12,
+ SUMO_UTC_DFLT_13,
+ SUMO_UTC_DFLT_14,
+};
+
+static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] =
+{
+ SUMO_DTC_DFLT_00,
+ SUMO_DTC_DFLT_01,
+ SUMO_DTC_DFLT_02,
+ SUMO_DTC_DFLT_03,
+ SUMO_DTC_DFLT_04,
+ SUMO_DTC_DFLT_05,
+ SUMO_DTC_DFLT_06,
+ SUMO_DTC_DFLT_07,
+ SUMO_DTC_DFLT_08,
+ SUMO_DTC_DFLT_09,
+ SUMO_DTC_DFLT_10,
+ SUMO_DTC_DFLT_11,
+ SUMO_DTC_DFLT_12,
+ SUMO_DTC_DFLT_13,
+ SUMO_DTC_DFLT_14,
+};
+
+struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)
+{
+ struct sumo_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+static void sumo_gfx_clockgating_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+ else {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+ RREG32(GB_ADDR_CONFIG);
+ }
+}
+
+#define CGCG_CGTT_LOCAL0_MASK 0xE5BFFFFF
+#define CGCG_CGTT_LOCAL1_MASK 0xEFFF07FF
+
+static void sumo_mg_clockgating_enable(struct radeon_device *rdev, bool enable)
+{
+ u32 local0;
+ u32 local1;
+
+ local0 = RREG32(CG_CGTT_LOCAL_0);
+ local1 = RREG32(CG_CGTT_LOCAL_1);
+
+ if (enable) {
+ WREG32(CG_CGTT_LOCAL_0, (0 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+ WREG32(CG_CGTT_LOCAL_1, (0 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+ } else {
+ WREG32(CG_CGTT_LOCAL_0, (0xFFFFFFFF & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+ WREG32(CG_CGTT_LOCAL_1, (0xFFFFCFFF & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+ }
+}
+
+static void sumo_program_git(struct radeon_device *rdev)
+{
+ u32 p, u;
+ u32 xclk = radeon_get_xclk(rdev);
+
+ r600_calculate_u_and_p(SUMO_GICST_DFLT,
+ xclk, 16, &p, &u);
+
+ WREG32_P(CG_GIT, CG_GICST(p), ~CG_GICST_MASK);
+}
+
+static void sumo_program_grsd(struct radeon_device *rdev)
+{
+ u32 p, u;
+ u32 xclk = radeon_get_xclk(rdev);
+ u32 grs = 256 * 25 / 100;
+
+ r600_calculate_u_and_p(1, xclk, 14, &p, &u);
+
+ WREG32(CG_GCOOR, PHC(grs) | SDC(p) | SU(u));
+}
+
+void sumo_gfx_clockgating_initialize(struct radeon_device *rdev)
+{
+ sumo_program_git(rdev);
+ sumo_program_grsd(rdev);
+}
+
+static void sumo_gfx_powergating_initialize(struct radeon_device *rdev)
+{
+ u32 rcu_pwr_gating_cntl;
+ u32 p, u;
+ u32 p_c, p_p, d_p;
+ u32 r_t, i_t;
+ u32 xclk = radeon_get_xclk(rdev);
+
+ if (rdev->family == CHIP_PALM) {
+ p_c = 4;
+ d_p = 10;
+ r_t = 10;
+ i_t = 4;
+ p_p = 50 + 1000/200 + 6 * 32;
+ } else {
+ p_c = 16;
+ d_p = 50;
+ r_t = 50;
+ i_t = 50;
+ p_p = 113;
+ }
+
+ WREG32(CG_SCRATCH2, 0x01B60A17);
+
+ r600_calculate_u_and_p(SUMO_GFXPOWERGATINGT_DFLT,
+ xclk, 16, &p, &u);
+
+ WREG32_P(CG_PWR_GATING_CNTL, PGP(p) | PGU(u),
+ ~(PGP_MASK | PGU_MASK));
+
+ r600_calculate_u_and_p(SUMO_VOLTAGEDROPT_DFLT,
+ xclk, 16, &p, &u);
+
+ WREG32_P(CG_CG_VOLTAGE_CNTL, PGP(p) | PGU(u),
+ ~(PGP_MASK | PGU_MASK));
+
+ if (rdev->family == CHIP_PALM) {
+ WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x10103210);
+ WREG32_RCU(RCU_PWR_GATING_SEQ1, 0x10101010);
+ } else {
+ WREG32_RCU(RCU_PWR_GATING_SEQ0, 0x76543210);
+ WREG32_RCU(RCU_PWR_GATING_SEQ1, 0xFEDCBA98);
+ }
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
+ rcu_pwr_gating_cntl &=
+ ~(RSVD_MASK | PCV_MASK | PGS_MASK);
+ rcu_pwr_gating_cntl |= PCV(p_c) | PGS(1) | PWR_GATING_EN;
+ if (rdev->family == CHIP_PALM) {
+ rcu_pwr_gating_cntl &= ~PCP_MASK;
+ rcu_pwr_gating_cntl |= PCP(0x77);
+ }
+ WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
+ rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
+ rcu_pwr_gating_cntl |= MPPU(p_p) | MPPD(50);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
+ rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
+ rcu_pwr_gating_cntl |= DPPU(d_p) | DPPD(50);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_4);
+ rcu_pwr_gating_cntl &= ~(RT_MASK | IT_MASK);
+ rcu_pwr_gating_cntl |= RT(r_t) | IT(i_t);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_4, rcu_pwr_gating_cntl);
+
+ if (rdev->family == CHIP_PALM)
+ WREG32_RCU(RCU_PWR_GATING_CNTL_5, 0xA02);
+
+ sumo_smu_pg_init(rdev);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
+ rcu_pwr_gating_cntl &=
+ ~(RSVD_MASK | PCV_MASK | PGS_MASK);
+ rcu_pwr_gating_cntl |= PCV(p_c) | PGS(4) | PWR_GATING_EN;
+ if (rdev->family == CHIP_PALM) {
+ rcu_pwr_gating_cntl &= ~PCP_MASK;
+ rcu_pwr_gating_cntl |= PCP(0x77);
+ }
+ WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
+
+ if (rdev->family == CHIP_PALM) {
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
+ rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
+ rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
+ rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
+ rcu_pwr_gating_cntl |= DPPU(16) | DPPD(50);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
+ }
+
+ sumo_smu_pg_init(rdev);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL);
+ rcu_pwr_gating_cntl &=
+ ~(RSVD_MASK | PCV_MASK | PGS_MASK);
+ rcu_pwr_gating_cntl |= PGS(5) | PWR_GATING_EN;
+
+ if (rdev->family == CHIP_PALM) {
+ rcu_pwr_gating_cntl |= PCV(4);
+ rcu_pwr_gating_cntl &= ~PCP_MASK;
+ rcu_pwr_gating_cntl |= PCP(0x77);
+ } else
+ rcu_pwr_gating_cntl |= PCV(11);
+ WREG32_RCU(RCU_PWR_GATING_CNTL, rcu_pwr_gating_cntl);
+
+ if (rdev->family == CHIP_PALM) {
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_2);
+ rcu_pwr_gating_cntl &= ~(MPPU_MASK | MPPD_MASK);
+ rcu_pwr_gating_cntl |= MPPU(113) | MPPD(50);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_2, rcu_pwr_gating_cntl);
+
+ rcu_pwr_gating_cntl = RREG32_RCU(RCU_PWR_GATING_CNTL_3);
+ rcu_pwr_gating_cntl &= ~(DPPU_MASK | DPPD_MASK);
+ rcu_pwr_gating_cntl |= DPPU(22) | DPPD(50);
+ WREG32_RCU(RCU_PWR_GATING_CNTL_3, rcu_pwr_gating_cntl);
+ }
+
+ sumo_smu_pg_init(rdev);
+}
+
+static void sumo_gfx_powergating_enable(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(CG_PWR_GATING_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
+ else {
+ WREG32_P(CG_PWR_GATING_CNTL, 0, ~DYN_PWR_DOWN_EN);
+ RREG32(GB_ADDR_CONFIG);
+ }
+}
+
+static int sumo_enable_clock_power_gating(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ if (pi->enable_gfx_clock_gating)
+ sumo_gfx_clockgating_initialize(rdev);
+ if (pi->enable_gfx_power_gating)
+ sumo_gfx_powergating_initialize(rdev);
+ if (pi->enable_mg_clock_gating)
+ sumo_mg_clockgating_enable(rdev, true);
+ if (pi->enable_gfx_clock_gating)
+ sumo_gfx_clockgating_enable(rdev, true);
+ if (pi->enable_gfx_power_gating)
+ sumo_gfx_powergating_enable(rdev, true);
+
+ return 0;
+}
+
+static void sumo_disable_clock_power_gating(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ if (pi->enable_gfx_clock_gating)
+ sumo_gfx_clockgating_enable(rdev, false);
+ if (pi->enable_gfx_power_gating)
+ sumo_gfx_powergating_enable(rdev, false);
+ if (pi->enable_mg_clock_gating)
+ sumo_mg_clockgating_enable(rdev, false);
+}
+
+static void sumo_calculate_bsp(struct radeon_device *rdev,
+ u32 high_clk)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 xclk = radeon_get_xclk(rdev);
+
+ pi->pasi = 65535 * 100 / high_clk;
+ pi->asi = 65535 * 100 / high_clk;
+
+ r600_calculate_u_and_p(pi->asi,
+ xclk, 16, &pi->bsp, &pi->bsu);
+
+ r600_calculate_u_and_p(pi->pasi,
+ xclk, 16, &pi->pbsp, &pi->pbsu);
+
+ pi->dsp = BSP(pi->bsp) | BSU(pi->bsu);
+ pi->psp = BSP(pi->pbsp) | BSU(pi->pbsu);
+}
+
+static void sumo_init_bsp(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ WREG32(CG_BSP_0, pi->psp);
+}
+
+
+static void sumo_program_bsp(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *ps = sumo_get_ps(rps);
+ u32 i;
+ u32 highest_engine_clock = ps->levels[ps->num_levels - 1].sclk;
+
+ if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+ highest_engine_clock = pi->boost_pl.sclk;
+
+ sumo_calculate_bsp(rdev, highest_engine_clock);
+
+ for (i = 0; i < ps->num_levels - 1; i++)
+ WREG32(CG_BSP_0 + (i * 4), pi->dsp);
+
+ WREG32(CG_BSP_0 + (i * 4), pi->psp);
+
+ if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+ WREG32(CG_BSP_0 + (BOOST_DPM_LEVEL * 4), pi->psp);
+}
+
+static void sumo_write_at(struct radeon_device *rdev,
+ u32 index, u32 value)
+{
+ if (index == 0)
+ WREG32(CG_AT_0, value);
+ else if (index == 1)
+ WREG32(CG_AT_1, value);
+ else if (index == 2)
+ WREG32(CG_AT_2, value);
+ else if (index == 3)
+ WREG32(CG_AT_3, value);
+ else if (index == 4)
+ WREG32(CG_AT_4, value);
+ else if (index == 5)
+ WREG32(CG_AT_5, value);
+ else if (index == 6)
+ WREG32(CG_AT_6, value);
+ else if (index == 7)
+ WREG32(CG_AT_7, value);
+}
+
+static void sumo_program_at(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *ps = sumo_get_ps(rps);
+ u32 asi;
+ u32 i;
+ u32 m_a;
+ u32 a_t;
+ u32 r[SUMO_MAX_HARDWARE_POWERLEVELS];
+ u32 l[SUMO_MAX_HARDWARE_POWERLEVELS];
+
+ r[0] = SUMO_R_DFLT0;
+ r[1] = SUMO_R_DFLT1;
+ r[2] = SUMO_R_DFLT2;
+ r[3] = SUMO_R_DFLT3;
+ r[4] = SUMO_R_DFLT4;
+
+ l[0] = SUMO_L_DFLT0;
+ l[1] = SUMO_L_DFLT1;
+ l[2] = SUMO_L_DFLT2;
+ l[3] = SUMO_L_DFLT3;
+ l[4] = SUMO_L_DFLT4;
+
+ for (i = 0; i < ps->num_levels; i++) {
+ asi = (i == ps->num_levels - 1) ? pi->pasi : pi->asi;
+
+ m_a = asi * ps->levels[i].sclk / 100;
+
+ a_t = CG_R(m_a * r[i] / 100) | CG_L(m_a * l[i] / 100);
+
+ sumo_write_at(rdev, i, a_t);
+ }
+
+ if (ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
+ asi = pi->pasi;
+
+ m_a = asi * pi->boost_pl.sclk / 100;
+
+ a_t = CG_R(m_a * r[ps->num_levels - 1] / 100) |
+ CG_L(m_a * l[ps->num_levels - 1] / 100);
+
+ sumo_write_at(rdev, BOOST_DPM_LEVEL, a_t);
+ }
+}
+
+static void sumo_program_tp(struct radeon_device *rdev)
+{
+ int i;
+ enum r600_td td = R600_TD_DFLT;
+
+ for (i = 0; i < SUMO_PM_NUMBER_OF_TC; i++) {
+ WREG32_P(CG_FFCT_0 + (i * 4), UTC_0(sumo_utc[i]), ~UTC_0_MASK);
+ WREG32_P(CG_FFCT_0 + (i * 4), DTC_0(sumo_dtc[i]), ~DTC_0_MASK);
+ }
+
+ if (td == R600_TD_AUTO)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_FORCE_TREND_SEL);
+ else
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_FORCE_TREND_SEL, ~FIR_FORCE_TREND_SEL);
+
+ if (td == R600_TD_UP)
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_TREND_MODE);
+
+ if (td == R600_TD_DOWN)
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_TREND_MODE, ~FIR_TREND_MODE);
+}
+
+void sumo_program_vc(struct radeon_device *rdev, u32 vrc)
+{
+ WREG32(CG_FTV, vrc);
+}
+
+void sumo_clear_vc(struct radeon_device *rdev)
+{
+ WREG32(CG_FTV, 0);
+}
+
+void sumo_program_sstp(struct radeon_device *rdev)
+{
+ u32 p, u;
+ u32 xclk = radeon_get_xclk(rdev);
+
+ r600_calculate_u_and_p(SUMO_SST_DFLT,
+ xclk, 16, &p, &u);
+
+ WREG32(CG_SSP, SSTU(u) | SST(p));
+}
+
+static void sumo_set_divider_value(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ u32 reg_index = index / 4;
+ u32 field_index = index % 4;
+
+ if (field_index == 0)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ SCLK_FSTATE_0_DIV(divider), ~SCLK_FSTATE_0_DIV_MASK);
+ else if (field_index == 1)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ SCLK_FSTATE_1_DIV(divider), ~SCLK_FSTATE_1_DIV_MASK);
+ else if (field_index == 2)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ SCLK_FSTATE_2_DIV(divider), ~SCLK_FSTATE_2_DIV_MASK);
+ else if (field_index == 3)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ SCLK_FSTATE_3_DIV(divider), ~SCLK_FSTATE_3_DIV_MASK);
+}
+
+static void sumo_set_ds_dividers(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ if (pi->enable_sclk_ds) {
+ u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_6);
+
+ dpm_ctrl &= ~(0x7 << (index * 3));
+ dpm_ctrl |= (divider << (index * 3));
+ WREG32(CG_SCLK_DPM_CTRL_6, dpm_ctrl);
+ }
+}
+
+static void sumo_set_ss_dividers(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ if (pi->enable_sclk_ds) {
+ u32 dpm_ctrl = RREG32(CG_SCLK_DPM_CTRL_11);
+
+ dpm_ctrl &= ~(0x7 << (index * 3));
+ dpm_ctrl |= (divider << (index * 3));
+ WREG32(CG_SCLK_DPM_CTRL_11, dpm_ctrl);
+ }
+}
+
+static void sumo_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
+{
+ u32 voltage_cntl = RREG32(CG_DPM_VOLTAGE_CNTL);
+
+ voltage_cntl &= ~(DPM_STATE0_LEVEL_MASK << (index * 2));
+ voltage_cntl |= (vid << (DPM_STATE0_LEVEL_SHIFT + index * 2));
+ WREG32(CG_DPM_VOLTAGE_CNTL, voltage_cntl);
+}
+
+static void sumo_set_allos_gnb_slow(struct radeon_device *rdev, u32 index, u32 gnb_slow)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 temp = gnb_slow;
+ u32 cg_sclk_dpm_ctrl_3;
+
+ if (pi->driver_nbps_policy_disable)
+ temp = 1;
+
+ cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
+ cg_sclk_dpm_ctrl_3 &= ~(GNB_SLOW_FSTATE_0_MASK << index);
+ cg_sclk_dpm_ctrl_3 |= (temp << (GNB_SLOW_FSTATE_0_SHIFT + index));
+
+ WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
+}
+
+static void sumo_program_power_level(struct radeon_device *rdev,
+ struct sumo_pl *pl, u32 index)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ int ret;
+ struct atom_clock_dividers dividers;
+ u32 ds_en = RREG32(DEEP_SLEEP_CNTL) & ENABLE_DS;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ pl->sclk, false, &dividers);
+ if (ret)
+ return;
+
+ sumo_set_divider_value(rdev, index, dividers.post_div);
+
+ sumo_set_vid(rdev, index, pl->vddc_index);
+
+ if (pl->ss_divider_index == 0 || pl->ds_divider_index == 0) {
+ if (ds_en)
+ WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
+ } else {
+ sumo_set_ss_dividers(rdev, index, pl->ss_divider_index);
+ sumo_set_ds_dividers(rdev, index, pl->ds_divider_index);
+
+ if (!ds_en)
+ WREG32_P(DEEP_SLEEP_CNTL, ENABLE_DS, ~ENABLE_DS);
+ }
+
+ sumo_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
+
+ if (pi->enable_boost)
+ sumo_set_tdp_limit(rdev, index, pl->sclk_dpm_tdp_limit);
+}
+
+static void sumo_power_level_enable(struct radeon_device *rdev, u32 index, bool enable)
+{
+ u32 reg_index = index / 4;
+ u32 field_index = index % 4;
+
+ if (field_index == 0)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ enable ? SCLK_FSTATE_0_VLD : 0, ~SCLK_FSTATE_0_VLD);
+ else if (field_index == 1)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ enable ? SCLK_FSTATE_1_VLD : 0, ~SCLK_FSTATE_1_VLD);
+ else if (field_index == 2)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ enable ? SCLK_FSTATE_2_VLD : 0, ~SCLK_FSTATE_2_VLD);
+ else if (field_index == 3)
+ WREG32_P(CG_SCLK_DPM_CTRL + (reg_index * 4),
+ enable ? SCLK_FSTATE_3_VLD : 0, ~SCLK_FSTATE_3_VLD);
+}
+
+static bool sumo_dpm_enabled(struct radeon_device *rdev)
+{
+ if (RREG32(CG_SCLK_DPM_CTRL_3) & DPM_SCLK_ENABLE)
+ return true;
+ else
+ return false;
+}
+
+static void sumo_start_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(CG_SCLK_DPM_CTRL_3, DPM_SCLK_ENABLE, ~DPM_SCLK_ENABLE);
+}
+
+static void sumo_stop_dpm(struct radeon_device *rdev)
+{
+ WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~DPM_SCLK_ENABLE);
+}
+
+static void sumo_set_forced_mode(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE_EN, ~FORCE_SCLK_STATE_EN);
+ else
+ WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_SCLK_STATE_EN);
+}
+
+static void sumo_set_forced_mode_enabled(struct radeon_device *rdev)
+{
+ int i;
+
+ sumo_set_forced_mode(rdev, true);
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(CG_SCLK_STATUS) & SCLK_OVERCLK_DETECT)
+ break;
+ udelay(1);
+ }
+}
+
+static void sumo_wait_for_level_0(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_SCLK_INDEX_MASK) == 0)
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void sumo_set_forced_mode_disabled(struct radeon_device *rdev)
+{
+ sumo_set_forced_mode(rdev, false);
+}
+
+static void sumo_enable_power_level_0(struct radeon_device *rdev)
+{
+ sumo_power_level_enable(rdev, 0, true);
+}
+
+static void sumo_patch_boost_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *new_ps = sumo_get_ps(rps);
+
+ if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE) {
+ pi->boost_pl = new_ps->levels[new_ps->num_levels - 1];
+ pi->boost_pl.sclk = pi->sys_info.boost_sclk;
+ pi->boost_pl.vddc_index = pi->sys_info.boost_vid_2bit;
+ pi->boost_pl.sclk_dpm_tdp_limit = pi->sys_info.sclk_dpm_tdp_limit_boost;
+ }
+}
+
+static void sumo_pre_notify_alt_vddnb_change(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+ struct sumo_ps *old_ps = sumo_get_ps(old_rps);
+ u32 nbps1_old = 0;
+ u32 nbps1_new = 0;
+
+ if (old_ps != NULL)
+ nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
+
+ nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE) ? 1 : 0;
+
+ if (nbps1_old == 1 && nbps1_new == 0)
+ sumo_smu_notify_alt_vddnb_change(rdev, 0, 0);
+}
+
+static void sumo_post_notify_alt_vddnb_change(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+ struct sumo_ps *old_ps = sumo_get_ps(old_rps);
+ u32 nbps1_old = 0;
+ u32 nbps1_new = 0;
+
+ if (old_ps != NULL)
+ nbps1_old = (old_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
+
+ nbps1_new = (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)? 1 : 0;
+
+ if (nbps1_old == 0 && nbps1_new == 1)
+ sumo_smu_notify_alt_vddnb_change(rdev, 1, 1);
+}
+
+static void sumo_enable_boost(struct radeon_device *rdev,
+ struct radeon_ps *rps,
+ bool enable)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(rps);
+
+ if (enable) {
+ if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+ sumo_boost_state_enable(rdev, true);
+ } else
+ sumo_boost_state_enable(rdev, false);
+}
+
+static void sumo_set_forced_level(struct radeon_device *rdev, u32 index)
+{
+ WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_SCLK_STATE(index), ~FORCE_SCLK_STATE_MASK);
+}
+
+static void sumo_set_forced_level_0(struct radeon_device *rdev)
+{
+ sumo_set_forced_level(rdev, 0);
+}
+
+static void sumo_program_wl(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(rps);
+ u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
+
+ dpm_ctrl4 &= 0xFFFFFF00;
+ dpm_ctrl4 |= (1 << (new_ps->num_levels - 1));
+
+ if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+ dpm_ctrl4 |= (1 << BOOST_DPM_LEVEL);
+
+ WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
+}
+
+static void sumo_program_power_levels_0_to_n(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+ struct sumo_ps *old_ps = sumo_get_ps(old_rps);
+ u32 i;
+ u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
+
+ for (i = 0; i < new_ps->num_levels; i++) {
+ sumo_program_power_level(rdev, &new_ps->levels[i], i);
+ sumo_power_level_enable(rdev, i, true);
+ }
+
+ for (i = new_ps->num_levels; i < n_current_state_levels; i++)
+ sumo_power_level_enable(rdev, i, false);
+
+ if (new_ps->flags & SUMO_POWERSTATE_FLAGS_BOOST_STATE)
+ sumo_program_power_level(rdev, &pi->boost_pl, BOOST_DPM_LEVEL);
+}
+
+static void sumo_enable_acpi_pm(struct radeon_device *rdev)
+{
+ WREG32_P(GENERAL_PWRMGT, STATIC_PM_EN, ~STATIC_PM_EN);
+}
+
+static void sumo_program_power_level_enter_state(struct radeon_device *rdev)
+{
+ WREG32_P(CG_SCLK_DPM_CTRL_5, SCLK_FSTATE_BOOTUP(0), ~SCLK_FSTATE_BOOTUP_MASK);
+}
+
+static void sumo_program_acpi_power_level(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct atom_clock_dividers dividers;
+ int ret;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ pi->acpi_pl.sclk,
+ false, &dividers);
+ if (ret)
+ return;
+
+ WREG32_P(CG_ACPI_CNTL, SCLK_ACPI_DIV(dividers.post_div), ~SCLK_ACPI_DIV_MASK);
+ WREG32_P(CG_ACPI_VOLTAGE_CNTL, 0, ~ACPI_VOLTAGE_EN);
+}
+
+static void sumo_program_bootup_state(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 dpm_ctrl4 = RREG32(CG_SCLK_DPM_CTRL_4);
+ u32 i;
+
+ sumo_program_power_level(rdev, &pi->boot_pl, 0);
+
+ dpm_ctrl4 &= 0xFFFFFF00;
+ WREG32(CG_SCLK_DPM_CTRL_4, dpm_ctrl4);
+
+ for (i = 1; i < 8; i++)
+ sumo_power_level_enable(rdev, i, false);
+}
+
+static void sumo_setup_uvd_clocks(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ if (pi->enable_gfx_power_gating) {
+ sumo_gfx_powergating_enable(rdev, false);
+ }
+
+ radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+
+ if (pi->enable_gfx_power_gating) {
+ if (!pi->disable_gfx_power_gating_in_uvd ||
+ !r600_is_uvd_state(new_rps->class, new_rps->class2))
+ sumo_gfx_powergating_enable(rdev, true);
+ }
+}
+
+static void sumo_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+ struct sumo_ps *current_ps = sumo_get_ps(old_rps);
+
+ if ((new_rps->vclk == old_rps->vclk) &&
+ (new_rps->dclk == old_rps->dclk))
+ return;
+
+ if (new_ps->levels[new_ps->num_levels - 1].sclk >=
+ current_ps->levels[current_ps->num_levels - 1].sclk)
+ return;
+
+ sumo_setup_uvd_clocks(rdev, new_rps, old_rps);
+}
+
+static void sumo_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(new_rps);
+ struct sumo_ps *current_ps = sumo_get_ps(old_rps);
+
+ if ((new_rps->vclk == old_rps->vclk) &&
+ (new_rps->dclk == old_rps->dclk))
+ return;
+
+ if (new_ps->levels[new_ps->num_levels - 1].sclk <
+ current_ps->levels[current_ps->num_levels - 1].sclk)
+ return;
+
+ sumo_setup_uvd_clocks(rdev, new_rps, old_rps);
+}
+
+void sumo_take_smu_control(struct radeon_device *rdev, bool enable)
+{
+/* This bit selects who handles display phy powergating.
+ * Clear the bit to let atom handle it.
+ * Set it to let the driver handle it.
+ * For now we just let atom handle it.
+ */
+#if 0
+ u32 v = RREG32(DOUT_SCRATCH3);
+
+ if (enable)
+ v |= 0x4;
+ else
+ v &= 0xFFFFFFFB;
+
+ WREG32(DOUT_SCRATCH3, v);
+#endif
+}
+
+static void sumo_enable_sclk_ds(struct radeon_device *rdev, bool enable)
+{
+ if (enable) {
+ u32 deep_sleep_cntl = RREG32(DEEP_SLEEP_CNTL);
+ u32 deep_sleep_cntl2 = RREG32(DEEP_SLEEP_CNTL2);
+ u32 t = 1;
+
+ deep_sleep_cntl &= ~R_DIS;
+ deep_sleep_cntl &= ~HS_MASK;
+ deep_sleep_cntl |= HS(t > 4095 ? 4095 : t);
+
+ deep_sleep_cntl2 |= LB_UFP_EN;
+ deep_sleep_cntl2 &= INOUT_C_MASK;
+ deep_sleep_cntl2 |= INOUT_C(0xf);
+
+ WREG32(DEEP_SLEEP_CNTL2, deep_sleep_cntl2);
+ WREG32(DEEP_SLEEP_CNTL, deep_sleep_cntl);
+ } else
+ WREG32_P(DEEP_SLEEP_CNTL, 0, ~ENABLE_DS);
+}
+
+static void sumo_program_bootup_at(struct radeon_device *rdev)
+{
+ WREG32_P(CG_AT_0, CG_R(0xffff), ~CG_R_MASK);
+ WREG32_P(CG_AT_0, CG_L(0), ~CG_L_MASK);
+}
+
+static void sumo_reset_am(struct radeon_device *rdev)
+{
+ WREG32_P(SCLK_PWRMGT_CNTL, FIR_RESET, ~FIR_RESET);
+}
+
+static void sumo_start_am(struct radeon_device *rdev)
+{
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~FIR_RESET);
+}
+
+static void sumo_program_ttp(struct radeon_device *rdev)
+{
+ u32 xclk = radeon_get_xclk(rdev);
+ u32 p, u;
+ u32 cg_sclk_dpm_ctrl_5 = RREG32(CG_SCLK_DPM_CTRL_5);
+
+ r600_calculate_u_and_p(1000,
+ xclk, 16, &p, &u);
+
+ cg_sclk_dpm_ctrl_5 &= ~(TT_TP_MASK | TT_TU_MASK);
+ cg_sclk_dpm_ctrl_5 |= TT_TP(p) | TT_TU(u);
+
+ WREG32(CG_SCLK_DPM_CTRL_5, cg_sclk_dpm_ctrl_5);
+}
+
+static void sumo_program_ttt(struct radeon_device *rdev)
+{
+ u32 cg_sclk_dpm_ctrl_3 = RREG32(CG_SCLK_DPM_CTRL_3);
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ cg_sclk_dpm_ctrl_3 &= ~(GNB_TT_MASK | GNB_THERMTHRO_MASK);
+ cg_sclk_dpm_ctrl_3 |= GNB_TT(pi->thermal_auto_throttling + 49);
+
+ WREG32(CG_SCLK_DPM_CTRL_3, cg_sclk_dpm_ctrl_3);
+}
+
+
+static void sumo_enable_voltage_scaling(struct radeon_device *rdev, bool enable)
+{
+ if (enable) {
+ WREG32_P(CG_DPM_VOLTAGE_CNTL, DPM_VOLTAGE_EN, ~DPM_VOLTAGE_EN);
+ WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~CG_VOLTAGE_EN);
+ } else {
+ WREG32_P(CG_CG_VOLTAGE_CNTL, CG_VOLTAGE_EN, ~CG_VOLTAGE_EN);
+ WREG32_P(CG_DPM_VOLTAGE_CNTL, 0, ~DPM_VOLTAGE_EN);
+ }
+}
+
+static void sumo_override_cnb_thermal_events(struct radeon_device *rdev)
+{
+ WREG32_P(CG_SCLK_DPM_CTRL_3, CNB_THERMTHRO_MASK_SCLK,
+ ~CNB_THERMTHRO_MASK_SCLK);
+}
+
+static void sumo_program_dc_hto(struct radeon_device *rdev)
+{
+ u32 cg_sclk_dpm_ctrl_4 = RREG32(CG_SCLK_DPM_CTRL_4);
+ u32 p, u;
+ u32 xclk = radeon_get_xclk(rdev);
+
+ r600_calculate_u_and_p(100000,
+ xclk, 14, &p, &u);
+
+ cg_sclk_dpm_ctrl_4 &= ~(DC_HDC_MASK | DC_HU_MASK);
+ cg_sclk_dpm_ctrl_4 |= DC_HDC(p) | DC_HU(u);
+
+ WREG32(CG_SCLK_DPM_CTRL_4, cg_sclk_dpm_ctrl_4);
+}
+
+static void sumo_force_nbp_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *new_ps = sumo_get_ps(rps);
+
+ if (!pi->driver_nbps_policy_disable) {
+ if (new_ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
+ WREG32_P(CG_SCLK_DPM_CTRL_3, FORCE_NB_PSTATE_1, ~FORCE_NB_PSTATE_1);
+ else
+ WREG32_P(CG_SCLK_DPM_CTRL_3, 0, ~FORCE_NB_PSTATE_1);
+ }
+}
+
+u32 sumo_get_sleep_divider_from_id(u32 id)
+{
+ return 1 << id;
+}
+
+u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+ u32 sclk,
+ u32 min_sclk_in_sr)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 i;
+ u32 temp;
+ u32 min = (min_sclk_in_sr > SUMO_MINIMUM_ENGINE_CLOCK) ?
+ min_sclk_in_sr : SUMO_MINIMUM_ENGINE_CLOCK;
+
+ if (sclk < min)
+ return 0;
+
+ if (!pi->enable_sclk_ds)
+ return 0;
+
+ for (i = SUMO_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) {
+ temp = sclk / sumo_get_sleep_divider_from_id(i);
+
+ if (temp >= min || i == 0)
+ break;
+ }
+ return i;
+}
+
+static u32 sumo_get_valid_engine_clock(struct radeon_device *rdev,
+ u32 lower_limit)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 i;
+
+ for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
+ if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
+ return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
+ }
+
+ return pi->sys_info.sclk_voltage_mapping_table.entries[pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries - 1].sclk_frequency;
+}
+
+static void sumo_patch_thermal_state(struct radeon_device *rdev,
+ struct sumo_ps *ps,
+ struct sumo_ps *current_ps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+ u32 current_vddc;
+ u32 current_sclk;
+ u32 current_index = 0;
+
+ if (current_ps) {
+ current_vddc = current_ps->levels[current_index].vddc_index;
+ current_sclk = current_ps->levels[current_index].sclk;
+ } else {
+ current_vddc = pi->boot_pl.vddc_index;
+ current_sclk = pi->boot_pl.sclk;
+ }
+
+ ps->levels[0].vddc_index = current_vddc;
+
+ if (ps->levels[0].sclk > current_sclk)
+ ps->levels[0].sclk = current_sclk;
+
+ ps->levels[0].ss_divider_index =
+ sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
+
+ ps->levels[0].ds_divider_index =
+ sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
+
+ if (ps->levels[0].ds_divider_index > ps->levels[0].ss_divider_index + 1)
+ ps->levels[0].ds_divider_index = ps->levels[0].ss_divider_index + 1;
+
+ if (ps->levels[0].ss_divider_index == ps->levels[0].ds_divider_index) {
+ if (ps->levels[0].ss_divider_index > 1)
+ ps->levels[0].ss_divider_index = ps->levels[0].ss_divider_index - 1;
+ }
+
+ if (ps->levels[0].ss_divider_index == 0)
+ ps->levels[0].ds_divider_index = 0;
+
+ if (ps->levels[0].ds_divider_index == 0)
+ ps->levels[0].ss_divider_index = 0;
+}
+
+static void sumo_apply_state_adjust_rules(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct sumo_ps *ps = sumo_get_ps(new_rps);
+ struct sumo_ps *current_ps = sumo_get_ps(old_rps);
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 min_voltage = 0; /* ??? */
+ u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
+ u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+ u32 i;
+
+ if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+ return sumo_patch_thermal_state(rdev, ps, current_ps);
+
+ if (pi->enable_boost) {
+ if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE)
+ ps->flags |= SUMO_POWERSTATE_FLAGS_BOOST_STATE;
+ }
+
+ if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) ||
+ (new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ||
+ (new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE))
+ ps->flags |= SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE;
+
+ for (i = 0; i < ps->num_levels; i++) {
+ if (ps->levels[i].vddc_index < min_voltage)
+ ps->levels[i].vddc_index = min_voltage;
+
+ if (ps->levels[i].sclk < min_sclk)
+ ps->levels[i].sclk =
+ sumo_get_valid_engine_clock(rdev, min_sclk);
+
+ ps->levels[i].ss_divider_index =
+ sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
+
+ ps->levels[i].ds_divider_index =
+ sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, SUMO_MINIMUM_ENGINE_CLOCK);
+
+ if (ps->levels[i].ds_divider_index > ps->levels[i].ss_divider_index + 1)
+ ps->levels[i].ds_divider_index = ps->levels[i].ss_divider_index + 1;
+
+ if (ps->levels[i].ss_divider_index == ps->levels[i].ds_divider_index) {
+ if (ps->levels[i].ss_divider_index > 1)
+ ps->levels[i].ss_divider_index = ps->levels[i].ss_divider_index - 1;
+ }
+
+ if (ps->levels[i].ss_divider_index == 0)
+ ps->levels[i].ds_divider_index = 0;
+
+ if (ps->levels[i].ds_divider_index == 0)
+ ps->levels[i].ss_divider_index = 0;
+
+ if (ps->flags & SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE)
+ ps->levels[i].allow_gnb_slow = 1;
+ else if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ||
+ (new_rps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC))
+ ps->levels[i].allow_gnb_slow = 0;
+ else if (i == ps->num_levels - 1)
+ ps->levels[i].allow_gnb_slow = 0;
+ else
+ ps->levels[i].allow_gnb_slow = 1;
+ }
+}
+
+static void sumo_cleanup_asic(struct radeon_device *rdev)
+{
+ sumo_take_smu_control(rdev, false);
+}
+
+static int sumo_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp)
+{
+ int low_temp = 0 * 1000;
+ int high_temp = 255 * 1000;
+
+ 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;
+ }
+
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
+ WREG32_P(CG_THERMAL_INT, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
+
+ rdev->pm.dpm.thermal.min_temp = low_temp;
+ rdev->pm.dpm.thermal.max_temp = high_temp;
+
+ return 0;
+}
+
+static void sumo_update_current_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(rps);
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ pi->current_rps = *rps;
+ pi->current_ps = *new_ps;
+ pi->current_rps.ps_priv = &pi->current_ps;
+}
+
+static void sumo_update_requested_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct sumo_ps *new_ps = sumo_get_ps(rps);
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ pi->requested_rps = *rps;
+ pi->requested_ps = *new_ps;
+ pi->requested_rps.ps_priv = &pi->requested_ps;
+}
+
+int sumo_dpm_enable(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ int ret;
+
+ if (sumo_dpm_enabled(rdev))
+ return -EINVAL;
+
+ ret = sumo_enable_clock_power_gating(rdev);
+ if (ret)
+ return ret;
+ sumo_program_bootup_state(rdev);
+ sumo_init_bsp(rdev);
+ sumo_reset_am(rdev);
+ sumo_program_tp(rdev);
+ sumo_program_bootup_at(rdev);
+ sumo_start_am(rdev);
+ if (pi->enable_auto_thermal_throttling) {
+ sumo_program_ttp(rdev);
+ sumo_program_ttt(rdev);
+ }
+ sumo_program_dc_hto(rdev);
+ sumo_program_power_level_enter_state(rdev);
+ sumo_enable_voltage_scaling(rdev, true);
+ sumo_program_sstp(rdev);
+ sumo_program_vc(rdev, SUMO_VRC_DFLT);
+ sumo_override_cnb_thermal_events(rdev);
+ sumo_start_dpm(rdev);
+ sumo_wait_for_level_0(rdev);
+ if (pi->enable_sclk_ds)
+ sumo_enable_sclk_ds(rdev, true);
+ if (pi->enable_boost)
+ sumo_enable_boost_timer(rdev);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ ret = sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret)
+ return ret;
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ }
+
+ sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
+ return 0;
+}
+
+void sumo_dpm_disable(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ if (!sumo_dpm_enabled(rdev))
+ return;
+ sumo_disable_clock_power_gating(rdev);
+ if (pi->enable_sclk_ds)
+ sumo_enable_sclk_ds(rdev, false);
+ sumo_clear_vc(rdev);
+ sumo_wait_for_level_0(rdev);
+ sumo_stop_dpm(rdev);
+ sumo_enable_voltage_scaling(rdev, false);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+}
+
+int sumo_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+ struct radeon_ps *new_ps = &requested_ps;
+
+ sumo_update_requested_ps(rdev, new_ps);
+
+ if (pi->enable_dynamic_patch_ps)
+ sumo_apply_state_adjust_rules(rdev,
+ &pi->requested_rps,
+ &pi->current_rps);
+
+ return 0;
+}
+
+int sumo_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct radeon_ps *new_ps = &pi->requested_rps;
+ struct radeon_ps *old_ps = &pi->current_rps;
+
+ if (pi->enable_dpm)
+ sumo_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ if (pi->enable_boost) {
+ sumo_enable_boost(rdev, new_ps, false);
+ sumo_patch_boost_state(rdev, new_ps);
+ }
+ if (pi->enable_dpm) {
+ sumo_pre_notify_alt_vddnb_change(rdev, new_ps, old_ps);
+ sumo_enable_power_level_0(rdev);
+ sumo_set_forced_level_0(rdev);
+ sumo_set_forced_mode_enabled(rdev);
+ sumo_wait_for_level_0(rdev);
+ sumo_program_power_levels_0_to_n(rdev, new_ps, old_ps);
+ sumo_program_wl(rdev, new_ps);
+ sumo_program_bsp(rdev, new_ps);
+ sumo_program_at(rdev, new_ps);
+ sumo_force_nbp_state(rdev, new_ps);
+ sumo_set_forced_mode_disabled(rdev);
+ sumo_set_forced_mode_enabled(rdev);
+ sumo_set_forced_mode_disabled(rdev);
+ sumo_post_notify_alt_vddnb_change(rdev, new_ps, old_ps);
+ }
+ if (pi->enable_boost)
+ sumo_enable_boost(rdev, new_ps, true);
+ if (pi->enable_dpm)
+ sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+
+ rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+
+ return 0;
+}
+
+void sumo_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct radeon_ps *new_ps = &pi->requested_rps;
+
+ sumo_update_current_ps(rdev, new_ps);
+}
+
+void sumo_dpm_reset_asic(struct radeon_device *rdev)
+{
+ sumo_program_bootup_state(rdev);
+ sumo_enable_power_level_0(rdev);
+ sumo_set_forced_level_0(rdev);
+ sumo_set_forced_mode_enabled(rdev);
+ sumo_wait_for_level_0(rdev);
+ sumo_set_forced_mode_disabled(rdev);
+ sumo_set_forced_mode_enabled(rdev);
+ sumo_set_forced_mode_disabled(rdev);
+}
+
+void sumo_dpm_setup_asic(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ sumo_initialize_m3_arb(rdev);
+ pi->fw_version = sumo_get_running_fw_version(rdev);
+ DRM_INFO("Found smc ucode version: 0x%08x\n", pi->fw_version);
+ sumo_program_acpi_power_level(rdev);
+ sumo_enable_acpi_pm(rdev);
+ sumo_take_smu_control(rdev, true);
+}
+
+void sumo_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+
+}
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void sumo_patch_boot_state(struct radeon_device *rdev,
+ struct sumo_ps *ps)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ ps->num_levels = 1;
+ ps->flags = 0;
+ ps->levels[0] = pi->boot_pl;
+}
+
+static void sumo_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps,
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+ u8 table_rev)
+{
+ struct sumo_ps *ps = sumo_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) {
+ rdev->pm.dpm.boot_ps = rps;
+ sumo_patch_boot_state(rdev, ps);
+ }
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void sumo_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *ps = sumo_get_ps(rps);
+ struct sumo_pl *pl = &ps->levels[index];
+ u32 sclk;
+
+ sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
+ sclk |= clock_info->sumo.ucEngineClockHigh << 16;
+ pl->sclk = sclk;
+ pl->vddc_index = clock_info->sumo.vddcIndex;
+ pl->sclk_dpm_tdp_limit = clock_info->sumo.tdpLimit;
+
+ ps->num_levels = index + 1;
+
+ if (pi->enable_sclk_ds) {
+ pl->ds_divider_index = 5;
+ pl->ss_divider_index = 4;
+ }
+}
+
+static int sumo_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->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 sumo_ps *ps;
+
+ if (!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));
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ state_array->ucNumEntries, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ power_state_offset = (u8 *)state_array->states;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->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];
+ if (!rdev->pm.power_state[i].clock_info)
+ return -EINVAL;
+ ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->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 (k >= SUMO_MAX_HARDWARE_POWERLEVELS)
+ break;
+ clock_info = (union pplib_clock_info *)
+ &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+ sumo_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i], k,
+ clock_info);
+ k++;
+ }
+ sumo_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info,
+ non_clock_info_array->ucEntrySize);
+ power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+ }
+ rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+ return 0;
+}
+
+u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
+ struct sumo_vid_mapping_table *vid_mapping_table,
+ u32 vid_2bit)
+{
+ u32 i;
+
+ for (i = 0; i < vid_mapping_table->num_entries; i++) {
+ if (vid_mapping_table->entries[i].vid_2bit == vid_2bit)
+ return vid_mapping_table->entries[i].vid_7bit;
+ }
+
+ return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
+}
+
+static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
+ u32 vid_2bit)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
+
+ if (vid_7bit > 0x7C)
+ return 0;
+
+ return (15500 - vid_7bit * 125 + 5) / 10;
+}
+
+static void sumo_construct_display_voltage_mapping_table(struct radeon_device *rdev,
+ struct sumo_disp_clock_voltage_mapping_table *disp_clk_voltage_mapping_table,
+ ATOM_CLK_VOLT_CAPABILITY *table)
+{
+ u32 i;
+
+ for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
+ if (table[i].ulMaximumSupportedCLK == 0)
+ break;
+
+ disp_clk_voltage_mapping_table->display_clock_frequency[i] =
+ table[i].ulMaximumSupportedCLK;
+ }
+
+ disp_clk_voltage_mapping_table->num_max_voltage_levels = i;
+
+ if (disp_clk_voltage_mapping_table->num_max_voltage_levels == 0) {
+ disp_clk_voltage_mapping_table->display_clock_frequency[0] = 80000;
+ disp_clk_voltage_mapping_table->num_max_voltage_levels = 1;
+ }
+}
+
+void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
+ struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table,
+ ATOM_AVAILABLE_SCLK_LIST *table)
+{
+ u32 i;
+ u32 n = 0;
+ u32 prev_sclk = 0;
+
+ for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
+ if (table[i].ulSupportedSCLK > prev_sclk) {
+ sclk_voltage_mapping_table->entries[n].sclk_frequency =
+ table[i].ulSupportedSCLK;
+ sclk_voltage_mapping_table->entries[n].vid_2bit =
+ table[i].usVoltageIndex;
+ prev_sclk = table[i].ulSupportedSCLK;
+ n++;
+ }
+ }
+
+ sclk_voltage_mapping_table->num_max_dpm_entries = n;
+}
+
+void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
+ struct sumo_vid_mapping_table *vid_mapping_table,
+ ATOM_AVAILABLE_SCLK_LIST *table)
+{
+ u32 i, j;
+
+ for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++) {
+ if (table[i].ulSupportedSCLK != 0) {
+ vid_mapping_table->entries[table[i].usVoltageIndex].vid_7bit =
+ table[i].usVoltageID;
+ vid_mapping_table->entries[table[i].usVoltageIndex].vid_2bit =
+ table[i].usVoltageIndex;
+ }
+ }
+
+ for (i = 0; i < SUMO_MAX_NUMBER_VOLTAGES; i++) {
+ if (vid_mapping_table->entries[i].vid_7bit == 0) {
+ for (j = i + 1; j < SUMO_MAX_NUMBER_VOLTAGES; j++) {
+ if (vid_mapping_table->entries[j].vid_7bit != 0) {
+ vid_mapping_table->entries[i] =
+ vid_mapping_table->entries[j];
+ vid_mapping_table->entries[j].vid_7bit = 0;
+ break;
+ }
+ }
+
+ if (j == SUMO_MAX_NUMBER_VOLTAGES)
+ break;
+ }
+ }
+
+ vid_mapping_table->num_entries = i;
+}
+
+union igp_info {
+ struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+};
+
+static int sumo_parse_sys_info_table(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ union igp_info *igp_info;
+ u8 frev, crev;
+ u16 data_offset;
+ int i;
+
+ if (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 != 6) {
+ DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+ return -EINVAL;
+ }
+ pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_6.ulBootUpEngineClock);
+ pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_6.ulMinEngineClock);
+ pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_6.ulBootUpUMAClock);
+ pi->sys_info.bootup_nb_voltage_index =
+ le16_to_cpu(igp_info->info_6.usBootUpNBVoltage);
+ if (igp_info->info_6.ucHtcTmpLmt == 0)
+ pi->sys_info.htc_tmp_lmt = 203;
+ else
+ pi->sys_info.htc_tmp_lmt = igp_info->info_6.ucHtcTmpLmt;
+ if (igp_info->info_6.ucHtcHystLmt == 0)
+ pi->sys_info.htc_hyst_lmt = 5;
+ else
+ pi->sys_info.htc_hyst_lmt = igp_info->info_6.ucHtcHystLmt;
+ if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
+ DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
+ }
+ for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++) {
+ pi->sys_info.csr_m3_arb_cntl_default[i] =
+ le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_DEFAULT[i]);
+ pi->sys_info.csr_m3_arb_cntl_uvd[i] =
+ le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_UVD[i]);
+ pi->sys_info.csr_m3_arb_cntl_fs3d[i] =
+ le32_to_cpu(igp_info->info_6.ulCSR_M3_ARB_CNTL_FS3D[i]);
+ }
+ pi->sys_info.sclk_dpm_boost_margin =
+ le32_to_cpu(igp_info->info_6.SclkDpmBoostMargin);
+ pi->sys_info.sclk_dpm_throttle_margin =
+ le32_to_cpu(igp_info->info_6.SclkDpmThrottleMargin);
+ pi->sys_info.sclk_dpm_tdp_limit_pg =
+ le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitPG);
+ pi->sys_info.gnb_tdp_limit = le16_to_cpu(igp_info->info_6.GnbTdpLimit);
+ pi->sys_info.sclk_dpm_tdp_limit_boost =
+ le16_to_cpu(igp_info->info_6.SclkDpmTdpLimitBoost);
+ pi->sys_info.boost_sclk = le32_to_cpu(igp_info->info_6.ulBoostEngineCLock);
+ pi->sys_info.boost_vid_2bit = igp_info->info_6.ulBoostVid_2bit;
+ if (igp_info->info_6.EnableBoost)
+ pi->sys_info.enable_boost = true;
+ else
+ pi->sys_info.enable_boost = false;
+ sumo_construct_display_voltage_mapping_table(rdev,
+ &pi->sys_info.disp_clk_voltage_mapping_table,
+ igp_info->info_6.sDISPCLK_Voltage);
+ sumo_construct_sclk_voltage_mapping_table(rdev,
+ &pi->sys_info.sclk_voltage_mapping_table,
+ igp_info->info_6.sAvail_SCLK);
+ sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
+ igp_info->info_6.sAvail_SCLK);
+
+ }
+ return 0;
+}
+
+static void sumo_construct_boot_and_acpi_state(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ 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->acpi_pl = pi->boot_pl;
+ pi->current_ps.num_levels = 1;
+ pi->current_ps.levels[0] = pi->boot_pl;
+}
+
+int sumo_dpm_init(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi;
+ u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
+ int ret;
+
+ pi = kzalloc(sizeof(struct sumo_power_info), GFP_KERNEL);
+ if (pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = pi;
+
+ pi->driver_nbps_policy_disable = false;
+ if ((rdev->family == CHIP_PALM) && (hw_rev < 3))
+ pi->disable_gfx_power_gating_in_uvd = true;
+ else
+ pi->disable_gfx_power_gating_in_uvd = false;
+ pi->enable_alt_vddnb = true;
+ pi->enable_sclk_ds = true;
+ pi->enable_dynamic_m3_arbiter = false;
+ pi->enable_dynamic_patch_ps = true;
+ pi->enable_gfx_power_gating = true;
+ pi->enable_gfx_clock_gating = true;
+ pi->enable_mg_clock_gating = true;
+ pi->enable_auto_thermal_throttling = true;
+
+ ret = sumo_parse_sys_info_table(rdev);
+ if (ret)
+ return ret;
+
+ sumo_construct_boot_and_acpi_state(rdev);
+
+ ret = sumo_parse_power_table(rdev);
+ if (ret)
+ return ret;
+
+ pi->pasi = CYPRESS_HASI_DFLT;
+ pi->asi = RV770_ASI_DFLT;
+ pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
+ pi->enable_boost = pi->sys_info.enable_boost;
+ pi->enable_dpm = true;
+
+ return 0;
+}
+
+void sumo_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ int i;
+ struct sumo_ps *ps = sumo_get_ps(rps);
+
+ r600_dpm_print_class_info(rps->class, rps->class2);
+ r600_dpm_print_cap_info(rps->caps);
+ printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ for (i = 0; i < ps->num_levels; i++) {
+ struct sumo_pl *pl = &ps->levels[i];
+ printk("\t\tpower level %d sclk: %u vddc: %u\n",
+ i, pl->sclk,
+ sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
+ }
+ r600_dpm_print_ps_status(rdev, rps);
+}
+
+void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct sumo_ps *ps = sumo_get_ps(rps);
+ struct sumo_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURR_INDEX_MASK) >>
+ CURR_INDEX_SHIFT;
+
+ if (current_index == BOOST_DPM_LEVEL) {
+ pl = &pi->boost_pl;
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "power level %d sclk: %u vddc: %u\n",
+ current_index, pl->sclk,
+ sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
+ } else if (current_index >= ps->num_levels) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ pl = &ps->levels[current_index];
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "power level %d sclk: %u vddc: %u\n",
+ current_index, pl->sclk,
+ sumo_convert_voltage_index_to_value(rdev, pl->vddc_index));
+ }
+}
+
+void sumo_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ sumo_cleanup_asic(rdev); /* ??? */
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+}
+
+u32 sumo_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct sumo_ps *requested_state = sumo_get_ps(&pi->requested_rps);
+
+ if (low)
+ return requested_state->levels[0].sclk;
+ else
+ return requested_state->levels[requested_state->num_levels - 1].sclk;
+}
+
+u32 sumo_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+
+ return pi->sys_info.bootup_uma_clk;
+}
+
+int sumo_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ struct radeon_ps *rps = &pi->current_rps;
+ struct sumo_ps *ps = sumo_get_ps(rps);
+ int i;
+
+ if (ps->num_levels <= 1)
+ return 0;
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ sumo_power_level_enable(rdev, ps->num_levels - 1, true);
+ sumo_set_forced_level(rdev, ps->num_levels - 1);
+ sumo_set_forced_mode_enabled(rdev);
+ for (i = 0; i < ps->num_levels - 1; i++) {
+ sumo_power_level_enable(rdev, i, false);
+ }
+ sumo_set_forced_mode(rdev, false);
+ sumo_set_forced_mode_enabled(rdev);
+ sumo_set_forced_mode(rdev, false);
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ sumo_power_level_enable(rdev, 0, true);
+ sumo_set_forced_level(rdev, 0);
+ sumo_set_forced_mode_enabled(rdev);
+ for (i = 1; i < ps->num_levels; i++) {
+ sumo_power_level_enable(rdev, i, false);
+ }
+ sumo_set_forced_mode(rdev, false);
+ sumo_set_forced_mode_enabled(rdev);
+ sumo_set_forced_mode(rdev, false);
+ } else {
+ for (i = 0; i < ps->num_levels; i++) {
+ sumo_power_level_enable(rdev, i, true);
+ }
+ }
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
new file mode 100644
index 000000000000..07dda299c784
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -0,0 +1,220 @@
+/*
+ * 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 __SUMO_DPM_H__
+#define __SUMO_DPM_H__
+
+#include "atom.h"
+
+#define SUMO_MAX_HARDWARE_POWERLEVELS 5
+#define SUMO_PM_NUMBER_OF_TC 15
+
+struct sumo_pl {
+ u32 sclk;
+ u32 vddc_index;
+ u32 ds_divider_index;
+ u32 ss_divider_index;
+ u32 allow_gnb_slow;
+ u32 sclk_dpm_tdp_limit;
+};
+
+/* used for the flags field */
+#define SUMO_POWERSTATE_FLAGS_FORCE_NBPS1_STATE (1 << 0)
+#define SUMO_POWERSTATE_FLAGS_BOOST_STATE (1 << 1)
+
+struct sumo_ps {
+ struct sumo_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS];
+ u32 num_levels;
+ /* flags */
+ u32 flags;
+};
+
+#define NUMBER_OF_M3ARB_PARAM_SETS 10
+#define SUMO_MAX_NUMBER_VOLTAGES 4
+
+struct sumo_disp_clock_voltage_mapping_table {
+ u32 num_max_voltage_levels;
+ u32 display_clock_frequency[SUMO_MAX_NUMBER_VOLTAGES];
+};
+
+struct sumo_vid_mapping_entry {
+ u16 vid_2bit;
+ u16 vid_7bit;
+};
+
+struct sumo_vid_mapping_table {
+ u32 num_entries;
+ struct sumo_vid_mapping_entry entries[SUMO_MAX_NUMBER_VOLTAGES];
+};
+
+struct sumo_sclk_voltage_mapping_entry {
+ u32 sclk_frequency;
+ u16 vid_2bit;
+ u16 rsv;
+};
+
+struct sumo_sclk_voltage_mapping_table {
+ u32 num_max_dpm_entries;
+ struct sumo_sclk_voltage_mapping_entry entries[SUMO_MAX_HARDWARE_POWERLEVELS];
+};
+
+struct sumo_sys_info {
+ u32 bootup_sclk;
+ u32 min_sclk;
+ u32 bootup_uma_clk;
+ u16 bootup_nb_voltage_index;
+ u8 htc_tmp_lmt;
+ u8 htc_hyst_lmt;
+ struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
+ struct sumo_disp_clock_voltage_mapping_table disp_clk_voltage_mapping_table;
+ struct sumo_vid_mapping_table vid_mapping_table;
+ u32 csr_m3_arb_cntl_default[NUMBER_OF_M3ARB_PARAM_SETS];
+ u32 csr_m3_arb_cntl_uvd[NUMBER_OF_M3ARB_PARAM_SETS];
+ u32 csr_m3_arb_cntl_fs3d[NUMBER_OF_M3ARB_PARAM_SETS];
+ u32 sclk_dpm_boost_margin;
+ u32 sclk_dpm_throttle_margin;
+ u32 sclk_dpm_tdp_limit_pg;
+ u32 gnb_tdp_limit;
+ u32 sclk_dpm_tdp_limit_boost;
+ u32 boost_sclk;
+ u32 boost_vid_2bit;
+ bool enable_boost;
+};
+
+struct sumo_power_info {
+ u32 asi;
+ u32 pasi;
+ u32 bsp;
+ u32 bsu;
+ u32 pbsp;
+ u32 pbsu;
+ u32 dsp;
+ u32 psp;
+ u32 thermal_auto_throttling;
+ u32 uvd_m3_arbiter;
+ u32 fw_version;
+ struct sumo_sys_info sys_info;
+ struct sumo_pl acpi_pl;
+ struct sumo_pl boot_pl;
+ struct sumo_pl boost_pl;
+ bool disable_gfx_power_gating_in_uvd;
+ bool driver_nbps_policy_disable;
+ bool enable_alt_vddnb;
+ bool enable_dynamic_m3_arbiter;
+ bool enable_gfx_clock_gating;
+ bool enable_gfx_power_gating;
+ bool enable_mg_clock_gating;
+ bool enable_sclk_ds;
+ bool enable_auto_thermal_throttling;
+ bool enable_dynamic_patch_ps;
+ bool enable_dpm;
+ bool enable_boost;
+ struct radeon_ps current_rps;
+ struct sumo_ps current_ps;
+ struct radeon_ps requested_rps;
+ struct sumo_ps requested_ps;
+};
+
+#define SUMO_UTC_DFLT_00 0x48
+#define SUMO_UTC_DFLT_01 0x44
+#define SUMO_UTC_DFLT_02 0x44
+#define SUMO_UTC_DFLT_03 0x44
+#define SUMO_UTC_DFLT_04 0x44
+#define SUMO_UTC_DFLT_05 0x44
+#define SUMO_UTC_DFLT_06 0x44
+#define SUMO_UTC_DFLT_07 0x44
+#define SUMO_UTC_DFLT_08 0x44
+#define SUMO_UTC_DFLT_09 0x44
+#define SUMO_UTC_DFLT_10 0x44
+#define SUMO_UTC_DFLT_11 0x44
+#define SUMO_UTC_DFLT_12 0x44
+#define SUMO_UTC_DFLT_13 0x44
+#define SUMO_UTC_DFLT_14 0x44
+
+#define SUMO_DTC_DFLT_00 0x48
+#define SUMO_DTC_DFLT_01 0x44
+#define SUMO_DTC_DFLT_02 0x44
+#define SUMO_DTC_DFLT_03 0x44
+#define SUMO_DTC_DFLT_04 0x44
+#define SUMO_DTC_DFLT_05 0x44
+#define SUMO_DTC_DFLT_06 0x44
+#define SUMO_DTC_DFLT_07 0x44
+#define SUMO_DTC_DFLT_08 0x44
+#define SUMO_DTC_DFLT_09 0x44
+#define SUMO_DTC_DFLT_10 0x44
+#define SUMO_DTC_DFLT_11 0x44
+#define SUMO_DTC_DFLT_12 0x44
+#define SUMO_DTC_DFLT_13 0x44
+#define SUMO_DTC_DFLT_14 0x44
+
+#define SUMO_AH_DFLT 5
+
+#define SUMO_R_DFLT0 70
+#define SUMO_R_DFLT1 70
+#define SUMO_R_DFLT2 70
+#define SUMO_R_DFLT3 70
+#define SUMO_R_DFLT4 100
+
+#define SUMO_L_DFLT0 0
+#define SUMO_L_DFLT1 20
+#define SUMO_L_DFLT2 20
+#define SUMO_L_DFLT3 20
+#define SUMO_L_DFLT4 20
+#define SUMO_VRC_DFLT 0x30033
+#define SUMO_MGCGTTLOCAL0_DFLT 0
+#define SUMO_MGCGTTLOCAL1_DFLT 0
+#define SUMO_GICST_DFLT 19
+#define SUMO_SST_DFLT 8
+#define SUMO_VOLTAGEDROPT_DFLT 1
+#define SUMO_GFXPOWERGATINGT_DFLT 100
+
+/* sumo_dpm.c */
+void sumo_gfx_clockgating_initialize(struct radeon_device *rdev);
+void sumo_program_vc(struct radeon_device *rdev, u32 vrc);
+void sumo_clear_vc(struct radeon_device *rdev);
+void sumo_program_sstp(struct radeon_device *rdev);
+void sumo_take_smu_control(struct radeon_device *rdev, bool enable);
+void sumo_construct_sclk_voltage_mapping_table(struct radeon_device *rdev,
+ struct sumo_sclk_voltage_mapping_table *sclk_voltage_mapping_table,
+ ATOM_AVAILABLE_SCLK_LIST *table);
+void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
+ struct sumo_vid_mapping_table *vid_mapping_table,
+ ATOM_AVAILABLE_SCLK_LIST *table);
+u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
+ struct sumo_vid_mapping_table *vid_mapping_table,
+ u32 vid_2bit);
+u32 sumo_get_sleep_divider_from_id(u32 id);
+u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+ u32 sclk,
+ u32 min_sclk_in_sr);
+
+/* sumo_smc.c */
+void sumo_initialize_m3_arb(struct radeon_device *rdev);
+void sumo_smu_pg_init(struct radeon_device *rdev);
+void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit);
+void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
+ bool powersaving, bool force_nbps1);
+void sumo_boost_state_enable(struct radeon_device *rdev, bool enable);
+void sumo_enable_boost_timer(struct radeon_device *rdev);
+u32 sumo_get_running_fw_version(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c
new file mode 100644
index 000000000000..18abba5b5810
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumo_smc.c
@@ -0,0 +1,222 @@
+/*
+ * 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 "radeon.h"
+#include "sumod.h"
+#include "sumo_dpm.h"
+#include "ppsmc.h"
+
+#define SUMO_SMU_SERVICE_ROUTINE_PG_INIT 1
+#define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY 27
+#define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20 20
+
+struct sumo_ps *sumo_get_ps(struct radeon_ps *rps);
+struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);
+
+static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
+{
+ u32 gfx_int_req;
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(GFX_INT_STATUS) & INT_DONE)
+ break;
+ udelay(1);
+ }
+
+ gfx_int_req = SERV_INDEX(id) | INT_REQ;
+ WREG32(GFX_INT_REQ, gfx_int_req);
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(GFX_INT_REQ) & INT_REQ)
+ break;
+ udelay(1);
+ }
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(GFX_INT_STATUS) & INT_ACK)
+ break;
+ udelay(1);
+ }
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(GFX_INT_STATUS) & INT_DONE)
+ break;
+ udelay(1);
+ }
+
+ gfx_int_req &= ~INT_REQ;
+ WREG32(GFX_INT_REQ, gfx_int_req);
+}
+
+void sumo_initialize_m3_arb(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 i;
+
+ if (!pi->enable_dynamic_m3_arbiter)
+ return;
+
+ for (i = 0; i < NUMBER_OF_M3ARB_PARAM_SETS; i++)
+ WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
+ pi->sys_info.csr_m3_arb_cntl_default[i]);
+
+ for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 2; i++)
+ WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
+ pi->sys_info.csr_m3_arb_cntl_uvd[i % NUMBER_OF_M3ARB_PARAM_SETS]);
+
+ for (; i < NUMBER_OF_M3ARB_PARAM_SETS * 3; i++)
+ WREG32_RCU(MCU_M3ARB_PARAMS + (i * 4),
+ pi->sys_info.csr_m3_arb_cntl_fs3d[i % NUMBER_OF_M3ARB_PARAM_SETS]);
+}
+
+static bool sumo_is_alt_vddnb_supported(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ bool return_code = false;
+
+ if (!pi->enable_alt_vddnb)
+ return return_code;
+
+ if ((rdev->family == CHIP_SUMO) || (rdev->family == CHIP_SUMO2)) {
+ if (pi->fw_version >= 0x00010C00)
+ return_code = true;
+ }
+
+ return return_code;
+}
+
+void sumo_smu_notify_alt_vddnb_change(struct radeon_device *rdev,
+ bool powersaving, bool force_nbps1)
+{
+ u32 param = 0;
+
+ if (!sumo_is_alt_vddnb_supported(rdev))
+ return;
+
+ if (powersaving)
+ param |= 1;
+
+ if (force_nbps1)
+ param |= 2;
+
+ WREG32_RCU(RCU_ALTVDDNB_NOTIFY, param);
+
+ sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY);
+}
+
+void sumo_smu_pg_init(struct radeon_device *rdev)
+{
+ sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_PG_INIT);
+}
+
+static u32 sumo_power_of_4(u32 unit)
+{
+ u32 ret = 1;
+ u32 i;
+
+ for (i = 0; i < unit; i++)
+ ret *= 4;
+
+ return ret;
+}
+
+void sumo_enable_boost_timer(struct radeon_device *rdev)
+{
+ struct sumo_power_info *pi = sumo_get_pi(rdev);
+ u32 period, unit, timer_value;
+ u32 xclk = radeon_get_xclk(rdev);
+
+ unit = (RREG32_RCU(RCU_LCLK_SCALING_CNTL) & LCLK_SCALING_TIMER_PRESCALER_MASK)
+ >> LCLK_SCALING_TIMER_PRESCALER_SHIFT;
+
+ period = 100 * (xclk / 100 / sumo_power_of_4(unit));
+
+ timer_value = (period << 16) | (unit << 4);
+
+ WREG32_RCU(RCU_GNB_PWR_REP_TIMER_CNTL, timer_value);
+ WREG32_RCU(RCU_BOOST_MARGIN, pi->sys_info.sclk_dpm_boost_margin);
+ WREG32_RCU(RCU_THROTTLE_MARGIN, pi->sys_info.sclk_dpm_throttle_margin);
+ WREG32_RCU(GNB_TDP_LIMIT, pi->sys_info.gnb_tdp_limit);
+ WREG32_RCU(RCU_SclkDpmTdpLimitPG, pi->sys_info.sclk_dpm_tdp_limit_pg);
+
+ sumo_send_msg_to_smu(rdev, SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20);
+}
+
+void sumo_set_tdp_limit(struct radeon_device *rdev, u32 index, u32 tdp_limit)
+{
+ u32 regoffset = 0;
+ u32 shift = 0;
+ u32 mask = 0xFFF;
+ u32 sclk_dpm_tdp_limit;
+
+ switch (index) {
+ case 0:
+ regoffset = RCU_SclkDpmTdpLimit01;
+ shift = 16;
+ break;
+ case 1:
+ regoffset = RCU_SclkDpmTdpLimit01;
+ shift = 0;
+ break;
+ case 2:
+ regoffset = RCU_SclkDpmTdpLimit23;
+ shift = 16;
+ break;
+ case 3:
+ regoffset = RCU_SclkDpmTdpLimit23;
+ shift = 0;
+ break;
+ case 4:
+ regoffset = RCU_SclkDpmTdpLimit47;
+ shift = 16;
+ break;
+ case 7:
+ regoffset = RCU_SclkDpmTdpLimit47;
+ shift = 0;
+ break;
+ default:
+ break;
+ }
+
+ sclk_dpm_tdp_limit = RREG32_RCU(regoffset);
+ sclk_dpm_tdp_limit &= ~(mask << shift);
+ sclk_dpm_tdp_limit |= (tdp_limit << shift);
+ WREG32_RCU(regoffset, sclk_dpm_tdp_limit);
+}
+
+void sumo_boost_state_enable(struct radeon_device *rdev, bool enable)
+{
+ u32 boost_disable = RREG32_RCU(RCU_GPU_BOOST_DISABLE);
+
+ boost_disable &= 0xFFFFFFFE;
+ boost_disable |= (enable ? 0 : 1);
+ WREG32_RCU(RCU_GPU_BOOST_DISABLE, boost_disable);
+}
+
+u32 sumo_get_running_fw_version(struct radeon_device *rdev)
+{
+ return RREG32_RCU(RCU_FW_VERSION);
+}
+
diff --git a/drivers/gpu/drm/radeon/sumod.h b/drivers/gpu/drm/radeon/sumod.h
new file mode 100644
index 000000000000..7c9c2d4b86c0
--- /dev/null
+++ b/drivers/gpu/drm/radeon/sumod.h
@@ -0,0 +1,372 @@
+/*
+ * 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 _SUMOD_H_
+#define _SUMOD_H_
+
+/* pm registers */
+
+/* rcu */
+#define RCU_FW_VERSION 0x30c
+
+#define RCU_PWR_GATING_SEQ0 0x408
+#define RCU_PWR_GATING_SEQ1 0x40c
+#define RCU_PWR_GATING_CNTL 0x410
+# define PWR_GATING_EN (1 << 0)
+# define RSVD_MASK (0x3 << 1)
+# define PCV(x) ((x) << 3)
+# define PCV_MASK (0x1f << 3)
+# define PCV_SHIFT 3
+# define PCP(x) ((x) << 8)
+# define PCP_MASK (0xf << 8)
+# define PCP_SHIFT 8
+# define RPW(x) ((x) << 16)
+# define RPW_MASK (0xf << 16)
+# define RPW_SHIFT 16
+# define ID(x) ((x) << 24)
+# define ID_MASK (0xf << 24)
+# define ID_SHIFT 24
+# define PGS(x) ((x) << 28)
+# define PGS_MASK (0xf << 28)
+# define PGS_SHIFT 28
+
+#define RCU_ALTVDDNB_NOTIFY 0x430
+#define RCU_LCLK_SCALING_CNTL 0x434
+# define LCLK_SCALING_EN (1 << 0)
+# define LCLK_SCALING_TYPE (1 << 1)
+# define LCLK_SCALING_TIMER_PRESCALER(x) ((x) << 4)
+# define LCLK_SCALING_TIMER_PRESCALER_MASK (0xf << 4)
+# define LCLK_SCALING_TIMER_PRESCALER_SHIFT 4
+# define LCLK_SCALING_TIMER_PERIOD(x) ((x) << 16)
+# define LCLK_SCALING_TIMER_PERIOD_MASK (0xf << 16)
+# define LCLK_SCALING_TIMER_PERIOD_SHIFT 16
+
+#define RCU_PWR_GATING_CNTL_2 0x4a0
+# define MPPU(x) ((x) << 0)
+# define MPPU_MASK (0xffff << 0)
+# define MPPU_SHIFT 0
+# define MPPD(x) ((x) << 16)
+# define MPPD_MASK (0xffff << 16)
+# define MPPD_SHIFT 16
+#define RCU_PWR_GATING_CNTL_3 0x4a4
+# define DPPU(x) ((x) << 0)
+# define DPPU_MASK (0xffff << 0)
+# define DPPU_SHIFT 0
+# define DPPD(x) ((x) << 16)
+# define DPPD_MASK (0xffff << 16)
+# define DPPD_SHIFT 16
+#define RCU_PWR_GATING_CNTL_4 0x4a8
+# define RT(x) ((x) << 0)
+# define RT_MASK (0xffff << 0)
+# define RT_SHIFT 0
+# define IT(x) ((x) << 16)
+# define IT_MASK (0xffff << 16)
+# define IT_SHIFT 16
+
+/* yes these two have the same address */
+#define RCU_PWR_GATING_CNTL_5 0x504
+#define RCU_GPU_BOOST_DISABLE 0x508
+
+#define MCU_M3ARB_INDEX 0x504
+#define MCU_M3ARB_PARAMS 0x508
+
+#define RCU_GNB_PWR_REP_TIMER_CNTL 0x50C
+
+#define RCU_SclkDpmTdpLimit01 0x514
+#define RCU_SclkDpmTdpLimit23 0x518
+#define RCU_SclkDpmTdpLimit47 0x51C
+#define RCU_SclkDpmTdpLimitPG 0x520
+
+#define GNB_TDP_LIMIT 0x540
+#define RCU_BOOST_MARGIN 0x544
+#define RCU_THROTTLE_MARGIN 0x548
+
+#define SMU_PCIE_PG_ARGS 0x58C
+#define SMU_PCIE_PG_ARGS_2 0x598
+#define SMU_PCIE_PG_ARGS_3 0x59C
+
+/* mmio */
+#define RCU_STATUS 0x11c
+# define GMC_PWR_GATER_BUSY (1 << 8)
+# define GFX_PWR_GATER_BUSY (1 << 9)
+# define UVD_PWR_GATER_BUSY (1 << 10)
+# define PCIE_PWR_GATER_BUSY (1 << 11)
+# define GMC_PWR_GATER_STATE (1 << 12)
+# define GFX_PWR_GATER_STATE (1 << 13)
+# define UVD_PWR_GATER_STATE (1 << 14)
+# define PCIE_PWR_GATER_STATE (1 << 15)
+# define GFX1_PWR_GATER_BUSY (1 << 16)
+# define GFX2_PWR_GATER_BUSY (1 << 17)
+# define GFX1_PWR_GATER_STATE (1 << 18)
+# define GFX2_PWR_GATER_STATE (1 << 19)
+
+#define GFX_INT_REQ 0x120
+# define INT_REQ (1 << 0)
+# define SERV_INDEX(x) ((x) << 1)
+# define SERV_INDEX_MASK (0xff << 1)
+# define SERV_INDEX_SHIFT 1
+#define GFX_INT_STATUS 0x124
+# define INT_ACK (1 << 0)
+# define INT_DONE (1 << 1)
+
+#define CG_SCLK_CNTL 0x600
+# define SCLK_DIVIDER(x) ((x) << 0)
+# define SCLK_DIVIDER_MASK (0x7f << 0)
+# define SCLK_DIVIDER_SHIFT 0
+#define CG_SCLK_STATUS 0x604
+# define SCLK_OVERCLK_DETECT (1 << 2)
+
+#define CG_DCLK_CNTL 0x610
+# define DCLK_DIVIDER_MASK 0x7f
+# define DCLK_DIR_CNTL_EN (1 << 8)
+#define CG_DCLK_STATUS 0x614
+# define DCLK_STATUS (1 << 0)
+#define CG_VCLK_CNTL 0x618
+# define VCLK_DIVIDER_MASK 0x7f
+# define VCLK_DIR_CNTL_EN (1 << 8)
+#define CG_VCLK_STATUS 0x61c
+
+#define GENERAL_PWRMGT 0x63c
+# define STATIC_PM_EN (1 << 1)
+
+#define SCLK_PWRMGT_CNTL 0x644
+# define SCLK_PWRMGT_OFF (1 << 0)
+# define SCLK_LOW_D1 (1 << 1)
+# define FIR_RESET (1 << 4)
+# define FIR_FORCE_TREND_SEL (1 << 5)
+# define FIR_TREND_MODE (1 << 6)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define GFX_CLK_REQUEST_OFF (1 << 9)
+# define GFX_CLK_FORCE_OFF (1 << 10)
+# define GFX_CLK_OFF_ACPI_D1 (1 << 11)
+# define GFX_CLK_OFF_ACPI_D2 (1 << 12)
+# define GFX_CLK_OFF_ACPI_D3 (1 << 13)
+# define GFX_VOLTAGE_CHANGE_EN (1 << 16)
+# define GFX_VOLTAGE_CHANGE_MODE (1 << 17)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c
+# define TARG_SCLK_INDEX(x) ((x) << 6)
+# define TARG_SCLK_INDEX_MASK (0x7 << 6)
+# define TARG_SCLK_INDEX_SHIFT 6
+# define CURR_SCLK_INDEX(x) ((x) << 9)
+# define CURR_SCLK_INDEX_MASK (0x7 << 9)
+# define CURR_SCLK_INDEX_SHIFT 9
+# define TARG_INDEX(x) ((x) << 12)
+# define TARG_INDEX_MASK (0x7 << 12)
+# define TARG_INDEX_SHIFT 12
+# define CURR_INDEX(x) ((x) << 15)
+# define CURR_INDEX_MASK (0x7 << 15)
+# define CURR_INDEX_SHIFT 15
+
+#define CG_SCLK_DPM_CTRL 0x684
+# define SCLK_FSTATE_0_DIV(x) ((x) << 0)
+# define SCLK_FSTATE_0_DIV_MASK (0x7f << 0)
+# define SCLK_FSTATE_0_DIV_SHIFT 0
+# define SCLK_FSTATE_0_VLD (1 << 7)
+# define SCLK_FSTATE_1_DIV(x) ((x) << 8)
+# define SCLK_FSTATE_1_DIV_MASK (0x7f << 8)
+# define SCLK_FSTATE_1_DIV_SHIFT 8
+# define SCLK_FSTATE_1_VLD (1 << 15)
+# define SCLK_FSTATE_2_DIV(x) ((x) << 16)
+# define SCLK_FSTATE_2_DIV_MASK (0x7f << 16)
+# define SCLK_FSTATE_2_DIV_SHIFT 16
+# define SCLK_FSTATE_2_VLD (1 << 23)
+# define SCLK_FSTATE_3_DIV(x) ((x) << 24)
+# define SCLK_FSTATE_3_DIV_MASK (0x7f << 24)
+# define SCLK_FSTATE_3_DIV_SHIFT 24
+# define SCLK_FSTATE_3_VLD (1 << 31)
+#define CG_SCLK_DPM_CTRL_2 0x688
+#define CG_GCOOR 0x68c
+# define PHC(x) ((x) << 0)
+# define PHC_MASK (0x1f << 0)
+# define PHC_SHIFT 0
+# define SDC(x) ((x) << 9)
+# define SDC_MASK (0x3ff << 9)
+# define SDC_SHIFT 9
+# define SU(x) ((x) << 23)
+# define SU_MASK (0xf << 23)
+# define SU_SHIFT 23
+# define DIV_ID(x) ((x) << 28)
+# define DIV_ID_MASK (0x7 << 28)
+# define DIV_ID_SHIFT 28
+
+#define CG_FTV 0x690
+#define CG_FFCT_0 0x694
+# define UTC_0(x) ((x) << 0)
+# define UTC_0_MASK (0x3ff << 0)
+# define UTC_0_SHIFT 0
+# define DTC_0(x) ((x) << 10)
+# define DTC_0_MASK (0x3ff << 10)
+# define DTC_0_SHIFT 10
+
+#define CG_GIT 0x6d8
+# define CG_GICST(x) ((x) << 0)
+# define CG_GICST_MASK (0xffff << 0)
+# define CG_GICST_SHIFT 0
+# define CG_GIPOT(x) ((x) << 16)
+# define CG_GIPOT_MASK (0xffff << 16)
+# define CG_GIPOT_SHIFT 16
+
+#define CG_SCLK_DPM_CTRL_3 0x6e0
+# define FORCE_SCLK_STATE(x) ((x) << 0)
+# define FORCE_SCLK_STATE_MASK (0x7 << 0)
+# define FORCE_SCLK_STATE_SHIFT 0
+# define FORCE_SCLK_STATE_EN (1 << 3)
+# define GNB_TT(x) ((x) << 8)
+# define GNB_TT_MASK (0xff << 8)
+# define GNB_TT_SHIFT 8
+# define GNB_THERMTHRO_MASK (1 << 16)
+# define CNB_THERMTHRO_MASK_SCLK (1 << 17)
+# define DPM_SCLK_ENABLE (1 << 18)
+# define GNB_SLOW_FSTATE_0_MASK (1 << 23)
+# define GNB_SLOW_FSTATE_0_SHIFT 23
+# define FORCE_NB_PSTATE_1 (1 << 31)
+
+#define CG_SSP 0x6e8
+# define SST(x) ((x) << 0)
+# define SST_MASK (0xffff << 0)
+# define SST_SHIFT 0
+# define SSTU(x) ((x) << 16)
+# define SSTU_MASK (0xffff << 16)
+# define SSTU_SHIFT 16
+
+#define CG_ACPI_CNTL 0x70c
+# define SCLK_ACPI_DIV(x) ((x) << 0)
+# define SCLK_ACPI_DIV_MASK (0x7f << 0)
+# define SCLK_ACPI_DIV_SHIFT 0
+
+#define CG_SCLK_DPM_CTRL_4 0x71c
+# define DC_HDC(x) ((x) << 14)
+# define DC_HDC_MASK (0x3fff << 14)
+# define DC_HDC_SHIFT 14
+# define DC_HU(x) ((x) << 28)
+# define DC_HU_MASK (0xf << 28)
+# define DC_HU_SHIFT 28
+#define CG_SCLK_DPM_CTRL_5 0x720
+# define SCLK_FSTATE_BOOTUP(x) ((x) << 0)
+# define SCLK_FSTATE_BOOTUP_MASK (0x7 << 0)
+# define SCLK_FSTATE_BOOTUP_SHIFT 0
+# define TT_TP(x) ((x) << 3)
+# define TT_TP_MASK (0xffff << 3)
+# define TT_TP_SHIFT 3
+# define TT_TU(x) ((x) << 19)
+# define TT_TU_MASK (0xff << 19)
+# define TT_TU_SHIFT 19
+#define CG_SCLK_DPM_CTRL_6 0x724
+#define CG_AT_0 0x728
+# define CG_R(x) ((x) << 0)
+# define CG_R_MASK (0xffff << 0)
+# define CG_R_SHIFT 0
+# define CG_L(x) ((x) << 16)
+# define CG_L_MASK (0xffff << 16)
+# define CG_L_SHIFT 16
+#define CG_AT_1 0x72c
+#define CG_AT_2 0x730
+#define CG_THERMAL_INT 0x734
+#define DIG_THERM_INTH(x) ((x) << 8)
+#define DIG_THERM_INTH_MASK 0x0000FF00
+#define DIG_THERM_INTH_SHIFT 8
+#define DIG_THERM_INTL(x) ((x) << 16)
+#define DIG_THERM_INTL_MASK 0x00FF0000
+#define DIG_THERM_INTL_SHIFT 16
+#define THERM_INT_MASK_HIGH (1 << 24)
+#define THERM_INT_MASK_LOW (1 << 25)
+#define CG_AT_3 0x738
+#define CG_AT_4 0x73c
+#define CG_AT_5 0x740
+#define CG_AT_6 0x744
+#define CG_AT_7 0x748
+
+#define CG_BSP_0 0x750
+# define BSP(x) ((x) << 0)
+# define BSP_MASK (0xffff << 0)
+# define BSP_SHIFT 0
+# define BSU(x) ((x) << 16)
+# define BSU_MASK (0xf << 16)
+# define BSU_SHIFT 16
+
+#define CG_CG_VOLTAGE_CNTL 0x770
+# define REQ (1 << 0)
+# define LEVEL(x) ((x) << 1)
+# define LEVEL_MASK (0x3 << 1)
+# define LEVEL_SHIFT 1
+# define CG_VOLTAGE_EN (1 << 3)
+# define FORCE (1 << 4)
+# define PERIOD(x) ((x) << 8)
+# define PERIOD_MASK (0xffff << 8)
+# define PERIOD_SHIFT 8
+# define UNIT(x) ((x) << 24)
+# define UNIT_MASK (0xf << 24)
+# define UNIT_SHIFT 24
+
+#define CG_ACPI_VOLTAGE_CNTL 0x780
+# define ACPI_VOLTAGE_EN (1 << 8)
+
+#define CG_DPM_VOLTAGE_CNTL 0x788
+# define DPM_STATE0_LEVEL_MASK (0x3 << 0)
+# define DPM_STATE0_LEVEL_SHIFT 0
+# define DPM_VOLTAGE_EN (1 << 16)
+
+#define CG_PWR_GATING_CNTL 0x7ac
+# define DYN_PWR_DOWN_EN (1 << 0)
+# define ACPI_PWR_DOWN_EN (1 << 1)
+# define GFX_CLK_OFF_PWR_DOWN_EN (1 << 2)
+# define IOC_DISGPU_PWR_DOWN_EN (1 << 3)
+# define FORCE_POWR_ON (1 << 4)
+# define PGP(x) ((x) << 8)
+# define PGP_MASK (0xffff << 8)
+# define PGP_SHIFT 8
+# define PGU(x) ((x) << 24)
+# define PGU_MASK (0xf << 24)
+# define PGU_SHIFT 24
+
+#define CG_CGTT_LOCAL_0 0x7d0
+#define CG_CGTT_LOCAL_1 0x7d4
+
+#define DEEP_SLEEP_CNTL 0x818
+# define R_DIS (1 << 3)
+# define HS(x) ((x) << 4)
+# define HS_MASK (0xfff << 4)
+# define HS_SHIFT 4
+# define ENABLE_DS (1 << 31)
+#define DEEP_SLEEP_CNTL2 0x81c
+# define LB_UFP_EN (1 << 0)
+# define INOUT_C(x) ((x) << 4)
+# define INOUT_C_MASK (0xff << 4)
+# define INOUT_C_SHIFT 4
+
+#define CG_SCRATCH2 0x824
+
+#define CG_SCLK_DPM_CTRL_11 0x830
+
+#define HW_REV 0x5564
+# define ATI_REV_ID_MASK (0xf << 28)
+# define ATI_REV_ID_SHIFT 28
+/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */
+
+#define DOUT_SCRATCH3 0x611c
+
+#define GB_ADDR_CONFIG 0x98f8
+
+#endif
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
new file mode 100644
index 000000000000..a1eb5f59939f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -0,0 +1,1949 @@
+/*
+ * 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 "radeon.h"
+#include "trinityd.h"
+#include "r600_dpm.h"
+#include "trinity_dpm.h"
+#include <linux/seq_file.h>
+
+#define TRINITY_MAX_DEEPSLEEP_DIVIDER_ID 5
+#define TRINITY_MINIMUM_ENGINE_CLOCK 800
+#define SCLK_MIN_DIV_INTV_SHIFT 12
+#define TRINITY_DISPCLK_BYPASS_THRESHOLD 10000
+
+#ifndef TRINITY_MGCG_SEQUENCE
+#define TRINITY_MGCG_SEQUENCE 100
+
+static const u32 trinity_mgcg_shls_default[] =
+{
+ /* Register, Value, Mask */
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00003fc4, 0xc0000000, 0xffffffff,
+ 0x00005448, 0x00000100, 0xffffffff,
+ 0x000055e4, 0x00000100, 0xffffffff,
+ 0x0000160c, 0x00000100, 0xffffffff,
+ 0x00008984, 0x06000100, 0xffffffff,
+ 0x0000c164, 0x00000100, 0xffffffff,
+ 0x00008a18, 0x00000100, 0xffffffff,
+ 0x0000897c, 0x06000100, 0xffffffff,
+ 0x00008b28, 0x00000100, 0xffffffff,
+ 0x00009144, 0x00800200, 0xffffffff,
+ 0x00009a60, 0x00000100, 0xffffffff,
+ 0x00009868, 0x00000100, 0xffffffff,
+ 0x00008d58, 0x00000100, 0xffffffff,
+ 0x00009510, 0x00000100, 0xffffffff,
+ 0x0000949c, 0x00000100, 0xffffffff,
+ 0x00009654, 0x00000100, 0xffffffff,
+ 0x00009030, 0x00000100, 0xffffffff,
+ 0x00009034, 0x00000100, 0xffffffff,
+ 0x00009038, 0x00000100, 0xffffffff,
+ 0x0000903c, 0x00000100, 0xffffffff,
+ 0x00009040, 0x00000100, 0xffffffff,
+ 0x0000a200, 0x00000100, 0xffffffff,
+ 0x0000a204, 0x00000100, 0xffffffff,
+ 0x0000a208, 0x00000100, 0xffffffff,
+ 0x0000a20c, 0x00000100, 0xffffffff,
+ 0x00009744, 0x00000100, 0xffffffff,
+ 0x00003f80, 0x00000100, 0xffffffff,
+ 0x0000a210, 0x00000100, 0xffffffff,
+ 0x0000a214, 0x00000100, 0xffffffff,
+ 0x000004d8, 0x00000100, 0xffffffff,
+ 0x00009664, 0x00000100, 0xffffffff,
+ 0x00009698, 0x00000100, 0xffffffff,
+ 0x000004d4, 0x00000200, 0xffffffff,
+ 0x000004d0, 0x00000000, 0xffffffff,
+ 0x000030cc, 0x00000104, 0xffffffff,
+ 0x0000d0c0, 0x00000100, 0xffffffff,
+ 0x0000d8c0, 0x00000100, 0xffffffff,
+ 0x0000951c, 0x00010000, 0xffffffff,
+ 0x00009160, 0x00030002, 0xffffffff,
+ 0x00009164, 0x00050004, 0xffffffff,
+ 0x00009168, 0x00070006, 0xffffffff,
+ 0x00009178, 0x00070000, 0xffffffff,
+ 0x0000917c, 0x00030002, 0xffffffff,
+ 0x00009180, 0x00050004, 0xffffffff,
+ 0x0000918c, 0x00010006, 0xffffffff,
+ 0x00009190, 0x00090008, 0xffffffff,
+ 0x00009194, 0x00070000, 0xffffffff,
+ 0x00009198, 0x00030002, 0xffffffff,
+ 0x0000919c, 0x00050004, 0xffffffff,
+ 0x000091a8, 0x00010006, 0xffffffff,
+ 0x000091ac, 0x00090008, 0xffffffff,
+ 0x000091b0, 0x00070000, 0xffffffff,
+ 0x000091b4, 0x00030002, 0xffffffff,
+ 0x000091b8, 0x00050004, 0xffffffff,
+ 0x000091c4, 0x00010006, 0xffffffff,
+ 0x000091c8, 0x00090008, 0xffffffff,
+ 0x000091cc, 0x00070000, 0xffffffff,
+ 0x000091d0, 0x00030002, 0xffffffff,
+ 0x000091d4, 0x00050004, 0xffffffff,
+ 0x000091e0, 0x00010006, 0xffffffff,
+ 0x000091e4, 0x00090008, 0xffffffff,
+ 0x000091e8, 0x00000000, 0xffffffff,
+ 0x000091ec, 0x00070000, 0xffffffff,
+ 0x000091f0, 0x00030002, 0xffffffff,
+ 0x000091f4, 0x00050004, 0xffffffff,
+ 0x00009200, 0x00010006, 0xffffffff,
+ 0x00009204, 0x00090008, 0xffffffff,
+ 0x00009208, 0x00070000, 0xffffffff,
+ 0x0000920c, 0x00030002, 0xffffffff,
+ 0x00009210, 0x00050004, 0xffffffff,
+ 0x0000921c, 0x00010006, 0xffffffff,
+ 0x00009220, 0x00090008, 0xffffffff,
+ 0x00009294, 0x00000000, 0xffffffff
+};
+
+static const u32 trinity_mgcg_shls_enable[] =
+{
+ /* Register, Value, Mask */
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0x00000000, 0x000133FF,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0x00000000, 0xE00B03FC,
+ 0x00009150, 0x96944200, 0xffffffff
+};
+
+static const u32 trinity_mgcg_shls_disable[] =
+{
+ /* Register, Value, Mask */
+ 0x0000802c, 0xc0000000, 0xffffffff,
+ 0x00009150, 0x00600000, 0xffffffff,
+ 0x000008f8, 0x00000000, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0x000133FF,
+ 0x000008f8, 0x00000001, 0xffffffff,
+ 0x000008fc, 0xffffffff, 0xE00B03FC
+};
+#endif
+
+#ifndef TRINITY_SYSLS_SEQUENCE
+#define TRINITY_SYSLS_SEQUENCE 100
+
+static const u32 trinity_sysls_default[] =
+{
+ /* Register, Value, Mask */
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x0000d8bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x00002f50, 0x00000404, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x0000641c, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+
+static const u32 trinity_sysls_disable[] =
+{
+ /* Register, Value, Mask */
+ 0x0000d0c0, 0x00000000, 0xffffffff,
+ 0x0000d8c0, 0x00000000, 0xffffffff,
+ 0x000055e8, 0x00000000, 0xffffffff,
+ 0x0000d0bc, 0x00000000, 0xffffffff,
+ 0x0000d8bc, 0x00000000, 0xffffffff,
+ 0x000015c0, 0x00041401, 0xffffffff,
+ 0x0000264c, 0x00040400, 0xffffffff,
+ 0x00002648, 0x00040400, 0xffffffff,
+ 0x00002650, 0x00040400, 0xffffffff,
+ 0x000020b8, 0x00040400, 0xffffffff,
+ 0x000020bc, 0x00040400, 0xffffffff,
+ 0x000020c0, 0x00040c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680000, 0xffffffff,
+ 0x00002f50, 0x00000404, 0xffffffff,
+ 0x000004c8, 0x00000001, 0xffffffff,
+ 0x0000641c, 0x00007ffd, 0xffffffff,
+ 0x00000c7c, 0x0000ff00, 0xffffffff,
+ 0x00006dfc, 0x0000007f, 0xffffffff
+};
+
+static const u32 trinity_sysls_enable[] =
+{
+ /* Register, Value, Mask */
+ 0x000055e8, 0x00000001, 0xffffffff,
+ 0x0000d0bc, 0x00000100, 0xffffffff,
+ 0x0000d8bc, 0x00000100, 0xffffffff,
+ 0x000015c0, 0x000c1401, 0xffffffff,
+ 0x0000264c, 0x000c0400, 0xffffffff,
+ 0x00002648, 0x000c0400, 0xffffffff,
+ 0x00002650, 0x000c0400, 0xffffffff,
+ 0x000020b8, 0x000c0400, 0xffffffff,
+ 0x000020bc, 0x000c0400, 0xffffffff,
+ 0x000020c0, 0x000c0c80, 0xffffffff,
+ 0x0000f4a0, 0x000000c0, 0xffffffff,
+ 0x0000f4a4, 0x00680fff, 0xffffffff,
+ 0x00002f50, 0x00000903, 0xffffffff,
+ 0x000004c8, 0x00000000, 0xffffffff,
+ 0x0000641c, 0x00000000, 0xffffffff,
+ 0x00000c7c, 0x00000000, 0xffffffff,
+ 0x00006dfc, 0x00000000, 0xffffffff
+};
+#endif
+
+static const u32 trinity_override_mgpg_sequences[] =
+{
+ /* Register, Value */
+ 0x00000200, 0xE030032C,
+ 0x00000204, 0x00000FFF,
+ 0x00000200, 0xE0300058,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE0300054,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE0300074,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE0300070,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE0300090,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE030008C,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE03000AC,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE03000A8,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE03000C8,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE03000C4,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE03000E4,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE03000E0,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE0300100,
+ 0x00000204, 0x00030301,
+ 0x00000200, 0xE03000FC,
+ 0x00000204, 0x500010FF,
+ 0x00000200, 0xE0300058,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE0300054,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE0300074,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE0300070,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE0300090,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE030008C,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE03000AC,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000A8,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE03000C8,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000C4,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE03000E4,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000E0,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE0300100,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000FC,
+ 0x00000204, 0x600010FF,
+ 0x00000200, 0xE0300058,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE0300054,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE0300074,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE0300070,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE0300090,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE030008C,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE03000AC,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000A8,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE03000C8,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000C4,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE03000E4,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000E0,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE0300100,
+ 0x00000204, 0x00030303,
+ 0x00000200, 0xE03000FC,
+ 0x00000204, 0x700010FF,
+ 0x00000200, 0xE0300058,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE0300054,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0xE0300074,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE0300070,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0xE0300090,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE030008C,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0xE03000AC,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE03000A8,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0xE03000C4,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0xE03000C8,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE03000E4,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE03000E0,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0xE0300100,
+ 0x00000204, 0x00010303,
+ 0x00000200, 0xE03000FC,
+ 0x00000204, 0x800010FF,
+ 0x00000200, 0x0001f198,
+ 0x00000204, 0x0003ffff,
+ 0x00000200, 0x0001f19C,
+ 0x00000204, 0x3fffffff,
+ 0x00000200, 0xE030032C,
+ 0x00000204, 0x00000000,
+};
+
+static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
+ const u32 *seq, u32 count);
+static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev);
+static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps);
+
+struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
+{
+ struct trinity_ps *ps = rps->ps_priv;
+
+ return ps;
+}
+
+struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = rdev->pm.dpm.priv;
+
+ return pi;
+}
+
+static void trinity_gfx_powergating_initialize(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 p, u;
+ u32 value;
+ struct atom_clock_dividers dividers;
+ u32 xclk = radeon_get_xclk(rdev);
+ u32 sssd = 1;
+ int ret;
+ u32 hw_rev = (RREG32(HW_REV) & ATI_REV_ID_MASK) >> ATI_REV_ID_SHIFT;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ 25000, false, &dividers);
+ if (ret)
+ return;
+
+ value = RREG32_SMC(GFX_POWER_GATING_CNTL);
+ value &= ~(SSSD_MASK | PDS_DIV_MASK);
+ if (sssd)
+ value |= SSSD(1);
+ value |= PDS_DIV(dividers.post_div);
+ WREG32_SMC(GFX_POWER_GATING_CNTL, value);
+
+ r600_calculate_u_and_p(500, xclk, 16, &p, &u);
+
+ WREG32(CG_PG_CTRL, SP(p) | SU(u));
+
+ WREG32_P(CG_GIPOTS, CG_GIPOT(p), ~CG_GIPOT_MASK);
+
+ /* XXX double check hw_rev */
+ if (pi->override_dynamic_mgpg && (hw_rev == 0))
+ trinity_override_dynamic_mg_powergating(rdev);
+
+}
+
+#define CGCG_CGTT_LOCAL0_MASK 0xFFFF33FF
+#define CGCG_CGTT_LOCAL1_MASK 0xFFFB0FFE
+#define CGTS_SM_CTRL_REG_DISABLE 0x00600000
+#define CGTS_SM_CTRL_REG_ENABLE 0x96944200
+
+static void trinity_mg_clockgating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 local0;
+ u32 local1;
+
+ if (enable) {
+ local0 = RREG32_CG(CG_CGTT_LOCAL_0);
+ local1 = RREG32_CG(CG_CGTT_LOCAL_1);
+
+ WREG32_CG(CG_CGTT_LOCAL_0,
+ (0x00380000 & CGCG_CGTT_LOCAL0_MASK) | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+ WREG32_CG(CG_CGTT_LOCAL_1,
+ (0x0E000000 & CGCG_CGTT_LOCAL1_MASK) | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+
+ WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_ENABLE);
+ } else {
+ WREG32(CGTS_SM_CTRL_REG, CGTS_SM_CTRL_REG_DISABLE);
+
+ local0 = RREG32_CG(CG_CGTT_LOCAL_0);
+ local1 = RREG32_CG(CG_CGTT_LOCAL_1);
+
+ WREG32_CG(CG_CGTT_LOCAL_0,
+ CGCG_CGTT_LOCAL0_MASK | (local0 & ~CGCG_CGTT_LOCAL0_MASK) );
+ WREG32_CG(CG_CGTT_LOCAL_1,
+ CGCG_CGTT_LOCAL1_MASK | (local1 & ~CGCG_CGTT_LOCAL1_MASK) );
+ }
+}
+
+static void trinity_mg_clockgating_initialize(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *seq = NULL;
+
+ seq = &trinity_mgcg_shls_default[0];
+ count = sizeof(trinity_mgcg_shls_default) / (3 * sizeof(u32));
+
+ trinity_program_clk_gating_hw_sequence(rdev, seq, count);
+}
+
+static void trinity_gfx_clockgating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable) {
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_GFX_CLK_OFF_EN, ~DYN_GFX_CLK_OFF_EN);
+ } else {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_GFX_CLK_OFF_EN);
+ WREG32_P(SCLK_PWRMGT_CNTL, GFX_CLK_FORCE_ON, ~GFX_CLK_FORCE_ON);
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~GFX_CLK_FORCE_ON);
+ RREG32(GB_ADDR_CONFIG);
+ }
+}
+
+static void trinity_program_clk_gating_hw_sequence(struct radeon_device *rdev,
+ const u32 *seq, u32 count)
+{
+ u32 i, length = count * 3;
+
+ for (i = 0; i < length; i += 3)
+ WREG32_P(seq[i], seq[i+1], ~seq[i+2]);
+}
+
+static void trinity_program_override_mgpg_sequences(struct radeon_device *rdev,
+ const u32 *seq, u32 count)
+{
+ u32 i, length = count * 2;
+
+ for (i = 0; i < length; i += 2)
+ WREG32(seq[i], seq[i+1]);
+
+}
+
+static void trinity_override_dynamic_mg_powergating(struct radeon_device *rdev)
+{
+ u32 count;
+ const u32 *seq = NULL;
+
+ seq = &trinity_override_mgpg_sequences[0];
+ count = sizeof(trinity_override_mgpg_sequences) / (2 * sizeof(u32));
+
+ trinity_program_override_mgpg_sequences(rdev, seq, count);
+}
+
+static void trinity_ls_clockgating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 count;
+ const u32 *seq = NULL;
+
+ if (enable) {
+ seq = &trinity_sysls_enable[0];
+ count = sizeof(trinity_sysls_enable) / (3 * sizeof(u32));
+ } else {
+ seq = &trinity_sysls_disable[0];
+ count = sizeof(trinity_sysls_disable) / (3 * sizeof(u32));
+ }
+
+ trinity_program_clk_gating_hw_sequence(rdev, seq, count);
+}
+
+static void trinity_gfx_powergating_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable) {
+ if (RREG32_SMC(CC_SMU_TST_EFUSE1_MISC) & RB_BACKEND_DISABLE_MASK)
+ WREG32_SMC(SMU_SCRATCH_A, (RREG32_SMC(SMU_SCRATCH_A) | 0x01));
+
+ WREG32_P(SCLK_PWRMGT_CNTL, DYN_PWR_DOWN_EN, ~DYN_PWR_DOWN_EN);
+ } else {
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~DYN_PWR_DOWN_EN);
+ RREG32(GB_ADDR_CONFIG);
+ }
+}
+
+static void trinity_gfx_dynamic_mgpg_enable(struct radeon_device *rdev,
+ bool enable)
+{
+ u32 value;
+
+ if (enable) {
+ value = RREG32_SMC(PM_I_CNTL_1);
+ value &= ~DS_PG_CNTL_MASK;
+ value |= DS_PG_CNTL(1);
+ WREG32_SMC(PM_I_CNTL_1, value);
+
+ value = RREG32_SMC(SMU_S_PG_CNTL);
+ value &= ~DS_PG_EN_MASK;
+ value |= DS_PG_EN(1);
+ WREG32_SMC(SMU_S_PG_CNTL, value);
+ } else {
+ value = RREG32_SMC(SMU_S_PG_CNTL);
+ value &= ~DS_PG_EN_MASK;
+ WREG32_SMC(SMU_S_PG_CNTL, value);
+
+ value = RREG32_SMC(PM_I_CNTL_1);
+ value &= ~DS_PG_CNTL_MASK;
+ WREG32_SMC(PM_I_CNTL_1, value);
+ }
+
+ trinity_gfx_dynamic_mgpg_config(rdev);
+
+}
+
+static void trinity_enable_clock_power_gating(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ if (pi->enable_gfx_clock_gating)
+ sumo_gfx_clockgating_initialize(rdev);
+ if (pi->enable_mg_clock_gating)
+ trinity_mg_clockgating_initialize(rdev);
+ if (pi->enable_gfx_power_gating)
+ trinity_gfx_powergating_initialize(rdev);
+ if (pi->enable_mg_clock_gating) {
+ trinity_ls_clockgating_enable(rdev, true);
+ trinity_mg_clockgating_enable(rdev, true);
+ }
+ if (pi->enable_gfx_clock_gating)
+ trinity_gfx_clockgating_enable(rdev, true);
+ if (pi->enable_gfx_dynamic_mgpg)
+ trinity_gfx_dynamic_mgpg_enable(rdev, true);
+ if (pi->enable_gfx_power_gating)
+ trinity_gfx_powergating_enable(rdev, true);
+}
+
+static void trinity_disable_clock_power_gating(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ if (pi->enable_gfx_power_gating)
+ trinity_gfx_powergating_enable(rdev, false);
+ if (pi->enable_gfx_dynamic_mgpg)
+ trinity_gfx_dynamic_mgpg_enable(rdev, false);
+ if (pi->enable_gfx_clock_gating)
+ trinity_gfx_clockgating_enable(rdev, false);
+ if (pi->enable_mg_clock_gating) {
+ trinity_mg_clockgating_enable(rdev, false);
+ trinity_ls_clockgating_enable(rdev, false);
+ }
+}
+
+static void trinity_set_divider_value(struct radeon_device *rdev,
+ u32 index, u32 sclk)
+{
+ struct atom_clock_dividers dividers;
+ int ret;
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ sclk, false, &dividers);
+ if (ret)
+ return;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+ value &= ~CLK_DIVIDER_MASK;
+ value |= CLK_DIVIDER(dividers.post_div);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+
+ ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+ sclk/2, false, &dividers);
+ if (ret)
+ return;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix);
+ value &= ~PD_SCLK_DIVIDER_MASK;
+ value |= PD_SCLK_DIVIDER(dividers.post_div);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_PG_CNTL + ix, value);
+}
+
+static void trinity_set_ds_dividers(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+ value &= ~DS_DIV_MASK;
+ value |= DS_DIV(divider);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_ss_dividers(struct radeon_device *rdev,
+ u32 index, u32 divider)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+ value &= ~DS_SH_DIV_MASK;
+ value |= DS_SH_DIV(divider);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_vid(struct radeon_device *rdev, u32 index, u32 vid)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid);
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+ value &= ~VID_MASK;
+ value |= VID(vid_7bit);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+ value &= ~LVRT_MASK;
+ value |= LVRT(0);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+}
+
+static void trinity_set_allos_gnb_slow(struct radeon_device *rdev,
+ u32 index, u32 gnb_slow)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
+ value &= ~GNB_SLOW_MASK;
+ value |= GNB_SLOW(gnb_slow);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
+}
+
+static void trinity_set_force_nbp_state(struct radeon_device *rdev,
+ u32 index, u32 force_nbp_state)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix);
+ value &= ~FORCE_NBPS1_MASK;
+ value |= FORCE_NBPS1(force_nbp_state);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_3 + ix, value);
+}
+
+static void trinity_set_display_wm(struct radeon_device *rdev,
+ u32 index, u32 wm)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+ value &= ~DISPLAY_WM_MASK;
+ value |= DISPLAY_WM(wm);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_vce_wm(struct radeon_device *rdev,
+ u32 index, u32 wm)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix);
+ value &= ~VCE_WM_MASK;
+ value |= VCE_WM(wm);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_1 + ix, value);
+}
+
+static void trinity_set_at(struct radeon_device *rdev,
+ u32 index, u32 at)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix);
+ value &= ~AT_MASK;
+ value |= AT(at);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_AT + ix, value);
+}
+
+static void trinity_program_power_level(struct radeon_device *rdev,
+ struct trinity_pl *pl, u32 index)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ if (index >= SUMO_MAX_HARDWARE_POWERLEVELS)
+ return;
+
+ trinity_set_divider_value(rdev, index, pl->sclk);
+ trinity_set_vid(rdev, index, pl->vddc_index);
+ trinity_set_ss_dividers(rdev, index, pl->ss_divider_index);
+ trinity_set_ds_dividers(rdev, index, pl->ds_divider_index);
+ trinity_set_allos_gnb_slow(rdev, index, pl->allow_gnb_slow);
+ trinity_set_force_nbp_state(rdev, index, pl->force_nbp_state);
+ trinity_set_display_wm(rdev, index, pl->display_wm);
+ trinity_set_vce_wm(rdev, index, pl->vce_wm);
+ trinity_set_at(rdev, index, pi->at[index]);
+}
+
+static void trinity_power_level_enable_disable(struct radeon_device *rdev,
+ u32 index, bool enable)
+{
+ u32 value;
+ u32 ix = index * TRINITY_SIZEOF_DPM_STATE_TABLE;
+
+ value = RREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix);
+ value &= ~STATE_VALID_MASK;
+ if (enable)
+ value |= STATE_VALID(1);
+ WREG32_SMC(SMU_SCLK_DPM_STATE_0_CNTL_0 + ix, value);
+}
+
+static bool trinity_dpm_enabled(struct radeon_device *rdev)
+{
+ if (RREG32_SMC(SMU_SCLK_DPM_CNTL) & SCLK_DPM_EN(1))
+ return true;
+ else
+ return false;
+}
+
+static void trinity_start_dpm(struct radeon_device *rdev)
+{
+ u32 value = RREG32_SMC(SMU_SCLK_DPM_CNTL);
+
+ value &= ~(SCLK_DPM_EN_MASK | SCLK_DPM_BOOT_STATE_MASK | VOLTAGE_CHG_EN_MASK);
+ value |= SCLK_DPM_EN(1) | SCLK_DPM_BOOT_STATE(0) | VOLTAGE_CHG_EN(1);
+ WREG32_SMC(SMU_SCLK_DPM_CNTL, value);
+
+ WREG32_P(GENERAL_PWRMGT, GLOBAL_PWRMGT_EN, ~GLOBAL_PWRMGT_EN);
+ WREG32_P(CG_CG_VOLTAGE_CNTL, 0, ~EN);
+
+ trinity_dpm_config(rdev, true);
+}
+
+static void trinity_wait_for_dpm_enabled(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(SCLK_PWRMGT_CNTL) & DYNAMIC_PM_EN)
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & TARGET_STATE_MASK) == 0)
+ break;
+ udelay(1);
+ }
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void trinity_stop_dpm(struct radeon_device *rdev)
+{
+ u32 sclk_dpm_cntl;
+
+ WREG32_P(CG_CG_VOLTAGE_CNTL, EN, ~EN);
+
+ sclk_dpm_cntl = RREG32_SMC(SMU_SCLK_DPM_CNTL);
+ sclk_dpm_cntl &= ~(SCLK_DPM_EN_MASK | VOLTAGE_CHG_EN_MASK);
+ WREG32_SMC(SMU_SCLK_DPM_CNTL, sclk_dpm_cntl);
+
+ trinity_dpm_config(rdev, false);
+}
+
+static void trinity_start_am(struct radeon_device *rdev)
+{
+ WREG32_P(SCLK_PWRMGT_CNTL, 0, ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
+}
+
+static void trinity_reset_am(struct radeon_device *rdev)
+{
+ WREG32_P(SCLK_PWRMGT_CNTL, RESET_SCLK_CNT | RESET_BUSY_CNT,
+ ~(RESET_SCLK_CNT | RESET_BUSY_CNT));
+}
+
+static void trinity_wait_for_level_0(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) == 0)
+ break;
+ udelay(1);
+ }
+}
+
+static void trinity_enable_power_level_0(struct radeon_device *rdev)
+{
+ trinity_power_level_enable_disable(rdev, 0, true);
+}
+
+static void trinity_force_level_0(struct radeon_device *rdev)
+{
+ trinity_dpm_force_state(rdev, 0);
+}
+
+static void trinity_unforce_levels(struct radeon_device *rdev)
+{
+ trinity_dpm_no_forced_level(rdev);
+}
+
+static void trinity_program_power_levels_0_to_n(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct trinity_ps *new_ps = trinity_get_ps(new_rps);
+ struct trinity_ps *old_ps = trinity_get_ps(old_rps);
+ u32 i;
+ u32 n_current_state_levels = (old_ps == NULL) ? 1 : old_ps->num_levels;
+
+ for (i = 0; i < new_ps->num_levels; i++) {
+ trinity_program_power_level(rdev, &new_ps->levels[i], i);
+ trinity_power_level_enable_disable(rdev, i, true);
+ }
+
+ for (i = new_ps->num_levels; i < n_current_state_levels; i++)
+ trinity_power_level_enable_disable(rdev, i, false);
+}
+
+static void trinity_program_bootup_state(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 i;
+
+ trinity_program_power_level(rdev, &pi->boot_pl, 0);
+ trinity_power_level_enable_disable(rdev, 0, true);
+
+ for (i = 1; i < 8; i++)
+ trinity_power_level_enable_disable(rdev, i, false);
+}
+
+static void trinity_setup_uvd_clock_table(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct trinity_ps *ps = trinity_get_ps(rps);
+ u32 uvdstates = (ps->vclk_low_divider |
+ ps->vclk_high_divider << 8 |
+ ps->dclk_low_divider << 16 |
+ ps->dclk_high_divider << 24);
+
+ WREG32_SMC(SMU_UVD_DPM_STATES, uvdstates);
+}
+
+static void trinity_setup_uvd_dpm_interval(struct radeon_device *rdev,
+ u32 interval)
+{
+ u32 p, u;
+ u32 tp = RREG32_SMC(PM_TP);
+ u32 val;
+ u32 xclk = radeon_get_xclk(rdev);
+
+ r600_calculate_u_and_p(interval, xclk, 16, &p, &u);
+
+ val = (p + tp - 1) / tp;
+
+ WREG32_SMC(SMU_UVD_DPM_CNTL, val);
+}
+
+static bool trinity_uvd_clocks_zero(struct radeon_ps *rps)
+{
+ if ((rps->vclk == 0) && (rps->dclk == 0))
+ return true;
+ else
+ return false;
+}
+
+static bool trinity_uvd_clocks_equal(struct radeon_ps *rps1,
+ struct radeon_ps *rps2)
+{
+ struct trinity_ps *ps1 = trinity_get_ps(rps1);
+ struct trinity_ps *ps2 = trinity_get_ps(rps2);
+
+ if ((rps1->vclk == rps2->vclk) &&
+ (rps1->dclk == rps2->dclk) &&
+ (ps1->vclk_low_divider == ps2->vclk_low_divider) &&
+ (ps1->vclk_high_divider == ps2->vclk_high_divider) &&
+ (ps1->dclk_low_divider == ps2->dclk_low_divider) &&
+ (ps1->dclk_high_divider == ps2->dclk_high_divider))
+ return true;
+ else
+ return false;
+}
+
+static void trinity_setup_uvd_clocks(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ if (pi->enable_gfx_power_gating) {
+ trinity_gfx_powergating_enable(rdev, false);
+ }
+
+ if (pi->uvd_dpm) {
+ if (trinity_uvd_clocks_zero(new_rps) &&
+ !trinity_uvd_clocks_zero(old_rps)) {
+ trinity_setup_uvd_dpm_interval(rdev, 0);
+ } else if (!trinity_uvd_clocks_zero(new_rps)) {
+ trinity_setup_uvd_clock_table(rdev, new_rps);
+
+ if (trinity_uvd_clocks_zero(old_rps)) {
+ u32 tmp = RREG32(CG_MISC_REG);
+ tmp &= 0xfffffffd;
+ WREG32(CG_MISC_REG, tmp);
+
+ radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+
+ trinity_setup_uvd_dpm_interval(rdev, 3000);
+ }
+ }
+ trinity_uvd_dpm_config(rdev);
+ } else {
+ if (trinity_uvd_clocks_zero(new_rps) ||
+ trinity_uvd_clocks_equal(new_rps, old_rps))
+ return;
+
+ radeon_set_uvd_clocks(rdev, new_rps->vclk, new_rps->dclk);
+ }
+
+ if (pi->enable_gfx_power_gating) {
+ trinity_gfx_powergating_enable(rdev, true);
+ }
+}
+
+static void trinity_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct trinity_ps *new_ps = trinity_get_ps(new_rps);
+ struct trinity_ps *current_ps = trinity_get_ps(new_rps);
+
+ if (new_ps->levels[new_ps->num_levels - 1].sclk >=
+ current_ps->levels[current_ps->num_levels - 1].sclk)
+ return;
+
+ trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
+}
+
+static void trinity_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct trinity_ps *new_ps = trinity_get_ps(new_rps);
+ struct trinity_ps *current_ps = trinity_get_ps(old_rps);
+
+ if (new_ps->levels[new_ps->num_levels - 1].sclk <
+ current_ps->levels[current_ps->num_levels - 1].sclk)
+ return;
+
+ trinity_setup_uvd_clocks(rdev, new_rps, old_rps);
+}
+
+static void trinity_program_ttt(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 value = RREG32_SMC(SMU_SCLK_DPM_TTT);
+
+ value &= ~(HT_MASK | LT_MASK);
+ value |= HT((pi->thermal_auto_throttling + 49) * 8);
+ value |= LT((pi->thermal_auto_throttling + 49 - pi->sys_info.htc_hyst_lmt) * 8);
+ WREG32_SMC(SMU_SCLK_DPM_TTT, value);
+}
+
+static void trinity_enable_att(struct radeon_device *rdev)
+{
+ u32 value = RREG32_SMC(SMU_SCLK_DPM_TT_CNTL);
+
+ value &= ~SCLK_TT_EN_MASK;
+ value |= SCLK_TT_EN(1);
+ WREG32_SMC(SMU_SCLK_DPM_TT_CNTL, value);
+}
+
+static void trinity_program_sclk_dpm(struct radeon_device *rdev)
+{
+ u32 p, u;
+ u32 tp = RREG32_SMC(PM_TP);
+ u32 ni;
+ u32 xclk = radeon_get_xclk(rdev);
+ u32 value;
+
+ r600_calculate_u_and_p(400, xclk, 16, &p, &u);
+
+ ni = (p + tp - 1) / tp;
+
+ value = RREG32_SMC(PM_I_CNTL_1);
+ value &= ~SCLK_DPM_MASK;
+ value |= SCLK_DPM(ni);
+ WREG32_SMC(PM_I_CNTL_1, value);
+}
+
+static int trinity_set_thermal_temperature_range(struct radeon_device *rdev,
+ int min_temp, int max_temp)
+{
+ int low_temp = 0 * 1000;
+ int high_temp = 255 * 1000;
+
+ 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;
+ }
+
+ WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTH(49 + (high_temp / 1000)), ~DIG_THERM_INTH_MASK);
+ WREG32_P(CG_THERMAL_INT_CTRL, DIG_THERM_INTL(49 + (low_temp / 1000)), ~DIG_THERM_INTL_MASK);
+
+ rdev->pm.dpm.thermal.min_temp = low_temp;
+ rdev->pm.dpm.thermal.max_temp = high_temp;
+
+ return 0;
+}
+
+static void trinity_update_current_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct trinity_ps *new_ps = trinity_get_ps(rps);
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ pi->current_rps = *rps;
+ pi->current_ps = *new_ps;
+ pi->current_rps.ps_priv = &pi->current_ps;
+}
+
+static void trinity_update_requested_ps(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct trinity_ps *new_ps = trinity_get_ps(rps);
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ pi->requested_rps = *rps;
+ pi->requested_ps = *new_ps;
+ pi->requested_rps.ps_priv = &pi->requested_ps;
+}
+
+int trinity_dpm_enable(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ int ret;
+
+ trinity_acquire_mutex(rdev);
+
+ if (trinity_dpm_enabled(rdev)) {
+ trinity_release_mutex(rdev);
+ return -EINVAL;
+ }
+
+ trinity_enable_clock_power_gating(rdev);
+ trinity_program_bootup_state(rdev);
+ sumo_program_vc(rdev, 0x00C00033);
+ trinity_start_am(rdev);
+ if (pi->enable_auto_thermal_throttling) {
+ trinity_program_ttt(rdev);
+ trinity_enable_att(rdev);
+ }
+ trinity_program_sclk_dpm(rdev);
+ trinity_start_dpm(rdev);
+ trinity_wait_for_dpm_enabled(rdev);
+ trinity_release_mutex(rdev);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+ if (ret) {
+ trinity_release_mutex(rdev);
+ return ret;
+ }
+ rdev->irq.dpm_thermal = true;
+ radeon_irq_set(rdev);
+ }
+
+ trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
+ return 0;
+}
+
+void trinity_dpm_disable(struct radeon_device *rdev)
+{
+ trinity_acquire_mutex(rdev);
+ if (!trinity_dpm_enabled(rdev)) {
+ trinity_release_mutex(rdev);
+ return;
+ }
+ trinity_disable_clock_power_gating(rdev);
+ sumo_clear_vc(rdev);
+ trinity_wait_for_level_0(rdev);
+ trinity_stop_dpm(rdev);
+ trinity_reset_am(rdev);
+ trinity_release_mutex(rdev);
+
+ if (rdev->irq.installed &&
+ r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+ rdev->irq.dpm_thermal = false;
+ radeon_irq_set(rdev);
+ }
+
+ trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+}
+
+static void trinity_get_min_sclk_divider(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ pi->min_sclk_did =
+ (RREG32_SMC(CC_SMU_MISC_FUSES) & MinSClkDid_MASK) >> MinSClkDid_SHIFT;
+}
+
+static void trinity_setup_nbp_sim(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct trinity_ps *new_ps = trinity_get_ps(rps);
+ u32 nbpsconfig;
+
+ if (pi->sys_info.nb_dpm_enable) {
+ nbpsconfig = RREG32_SMC(NB_PSTATE_CONFIG);
+ nbpsconfig &= ~(Dpm0PgNbPsLo_MASK | Dpm0PgNbPsHi_MASK | DpmXNbPsLo_MASK | DpmXNbPsHi_MASK);
+ nbpsconfig |= (Dpm0PgNbPsLo(new_ps->Dpm0PgNbPsLo) |
+ Dpm0PgNbPsHi(new_ps->Dpm0PgNbPsHi) |
+ DpmXNbPsLo(new_ps->DpmXNbPsLo) |
+ DpmXNbPsHi(new_ps->DpmXNbPsHi));
+ WREG32_SMC(NB_PSTATE_CONFIG, nbpsconfig);
+ }
+}
+
+int trinity_dpm_force_performance_level(struct radeon_device *rdev,
+ enum radeon_dpm_forced_level level)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct radeon_ps *rps = &pi->current_rps;
+ struct trinity_ps *ps = trinity_get_ps(rps);
+ int i, ret;
+
+ if (ps->num_levels <= 1)
+ return 0;
+
+ if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+ /* not supported by the hw */
+ return -EINVAL;
+ } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+ ret = trinity_dpm_n_levels_disabled(rdev, ps->num_levels - 1);
+ if (ret)
+ return ret;
+ } else {
+ for (i = 0; i < ps->num_levels; i++) {
+ ret = trinity_dpm_n_levels_disabled(rdev, 0);
+ if (ret)
+ return ret;
+ }
+ }
+
+ rdev->pm.dpm.forced_level = level;
+
+ return 0;
+}
+
+int trinity_dpm_pre_set_power_state(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct radeon_ps requested_ps = *rdev->pm.dpm.requested_ps;
+ struct radeon_ps *new_ps = &requested_ps;
+
+ trinity_update_requested_ps(rdev, new_ps);
+
+ trinity_apply_state_adjust_rules(rdev,
+ &pi->requested_rps,
+ &pi->current_rps);
+
+ return 0;
+}
+
+int trinity_dpm_set_power_state(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct radeon_ps *new_ps = &pi->requested_rps;
+ struct radeon_ps *old_ps = &pi->current_rps;
+
+ trinity_acquire_mutex(rdev);
+ if (pi->enable_dpm) {
+ trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
+ trinity_enable_power_level_0(rdev);
+ trinity_force_level_0(rdev);
+ trinity_wait_for_level_0(rdev);
+ trinity_setup_nbp_sim(rdev, new_ps);
+ trinity_program_power_levels_0_to_n(rdev, new_ps, old_ps);
+ trinity_force_level_0(rdev);
+ trinity_unforce_levels(rdev);
+ trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
+ rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+ }
+ trinity_release_mutex(rdev);
+
+ return 0;
+}
+
+void trinity_dpm_post_set_power_state(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct radeon_ps *new_ps = &pi->requested_rps;
+
+ trinity_update_current_ps(rdev, new_ps);
+}
+
+void trinity_dpm_setup_asic(struct radeon_device *rdev)
+{
+ trinity_acquire_mutex(rdev);
+ sumo_program_sstp(rdev);
+ sumo_take_smu_control(rdev, true);
+ trinity_get_min_sclk_divider(rdev);
+ trinity_release_mutex(rdev);
+}
+
+void trinity_dpm_reset_asic(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ trinity_acquire_mutex(rdev);
+ if (pi->enable_dpm) {
+ trinity_enable_power_level_0(rdev);
+ trinity_force_level_0(rdev);
+ trinity_wait_for_level_0(rdev);
+ trinity_program_bootup_state(rdev);
+ trinity_force_level_0(rdev);
+ trinity_unforce_levels(rdev);
+ }
+ trinity_release_mutex(rdev);
+}
+
+static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
+ u32 vid_2bit)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 vid_7bit = sumo_convert_vid2_to_vid7(rdev, &pi->sys_info.vid_mapping_table, vid_2bit);
+ u32 svi_mode = (RREG32_SMC(PM_CONFIG) & SVI_Mode) ? 1 : 0;
+ u32 step = (svi_mode == 0) ? 1250 : 625;
+ u32 delta = vid_7bit * step + 50;
+
+ if (delta > 155000)
+ return 0;
+
+ return (155000 - delta) / 100;
+}
+
+static void trinity_patch_boot_state(struct radeon_device *rdev,
+ struct trinity_ps *ps)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ ps->num_levels = 1;
+ ps->nbps_flags = 0;
+ ps->bapm_flags = 0;
+ ps->levels[0] = pi->boot_pl;
+}
+
+static u8 trinity_calculate_vce_wm(struct radeon_device *rdev, u32 sclk)
+{
+ if (sclk < 20000)
+ return 1;
+ return 0;
+}
+
+static void trinity_construct_boot_state(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ 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;
+ pi->current_ps.num_levels = 1;
+ pi->current_ps.levels[0] = pi->boot_pl;
+}
+
+static u8 trinity_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
+ u32 sclk, u32 min_sclk_in_sr)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 i;
+ u32 temp;
+ u32 min = (min_sclk_in_sr > TRINITY_MINIMUM_ENGINE_CLOCK) ?
+ min_sclk_in_sr : TRINITY_MINIMUM_ENGINE_CLOCK;
+
+ if (sclk < min)
+ return 0;
+
+ if (!pi->enable_sclk_ds)
+ return 0;
+
+ for (i = TRINITY_MAX_DEEPSLEEP_DIVIDER_ID; ; i--) {
+ temp = sclk / sumo_get_sleep_divider_from_id(i);
+ if (temp >= min || i == 0)
+ break;
+ }
+
+ return (u8)i;
+}
+
+static u32 trinity_get_valid_engine_clock(struct radeon_device *rdev,
+ u32 lower_limit)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 i;
+
+ for (i = 0; i < pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries; i++) {
+ if (pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency >= lower_limit)
+ return pi->sys_info.sclk_voltage_mapping_table.entries[i].sclk_frequency;
+ }
+
+ if (i == pi->sys_info.sclk_voltage_mapping_table.num_max_dpm_entries)
+ DRM_ERROR("engine clock out of range!");
+
+ return 0;
+}
+
+static void trinity_patch_thermal_state(struct radeon_device *rdev,
+ struct trinity_ps *ps,
+ struct trinity_ps *current_ps)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+ u32 current_vddc;
+ u32 current_sclk;
+ u32 current_index = 0;
+
+ if (current_ps) {
+ current_vddc = current_ps->levels[current_index].vddc_index;
+ current_sclk = current_ps->levels[current_index].sclk;
+ } else {
+ current_vddc = pi->boot_pl.vddc_index;
+ current_sclk = pi->boot_pl.sclk;
+ }
+
+ ps->levels[0].vddc_index = current_vddc;
+
+ if (ps->levels[0].sclk > current_sclk)
+ ps->levels[0].sclk = current_sclk;
+
+ ps->levels[0].ds_divider_index =
+ trinity_get_sleep_divider_id_from_clock(rdev, ps->levels[0].sclk, sclk_in_sr);
+ ps->levels[0].ss_divider_index = ps->levels[0].ds_divider_index;
+ ps->levels[0].allow_gnb_slow = 1;
+ ps->levels[0].force_nbp_state = 0;
+ ps->levels[0].display_wm = 0;
+ ps->levels[0].vce_wm =
+ trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
+}
+
+static u8 trinity_calculate_display_wm(struct radeon_device *rdev,
+ struct trinity_ps *ps, u32 index)
+{
+ if (ps == NULL || ps->num_levels <= 1)
+ return 0;
+ else if (ps->num_levels == 2) {
+ if (index == 0)
+ return 0;
+ else
+ return 1;
+ } else {
+ if (index == 0)
+ return 0;
+ else if (ps->levels[index].sclk < 30000)
+ return 0;
+ else
+ return 1;
+ }
+}
+
+static u32 trinity_get_uvd_clock_index(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 i = 0;
+
+ for (i = 0; i < 4; i++) {
+ if ((rps->vclk == pi->sys_info.uvd_clock_table_entries[i].vclk) &&
+ (rps->dclk == pi->sys_info.uvd_clock_table_entries[i].dclk))
+ break;
+ }
+
+ if (i >= 4) {
+ DRM_ERROR("UVD clock index not found!\n");
+ i = 3;
+ }
+ return i;
+}
+
+static void trinity_adjust_uvd_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ struct trinity_ps *ps = trinity_get_ps(rps);
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 high_index = 0;
+ u32 low_index = 0;
+
+ if (pi->uvd_dpm && r600_is_uvd_state(rps->class, rps->class2)) {
+ high_index = trinity_get_uvd_clock_index(rdev, rps);
+
+ switch(high_index) {
+ case 3:
+ case 2:
+ low_index = 1;
+ break;
+ case 1:
+ case 0:
+ default:
+ low_index = 0;
+ break;
+ }
+
+ ps->vclk_low_divider =
+ pi->sys_info.uvd_clock_table_entries[high_index].vclk_did;
+ ps->dclk_low_divider =
+ pi->sys_info.uvd_clock_table_entries[high_index].dclk_did;
+ ps->vclk_high_divider =
+ pi->sys_info.uvd_clock_table_entries[low_index].vclk_did;
+ ps->dclk_high_divider =
+ pi->sys_info.uvd_clock_table_entries[low_index].dclk_did;
+ }
+}
+
+
+
+static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
+ struct radeon_ps *new_rps,
+ struct radeon_ps *old_rps)
+{
+ struct trinity_ps *ps = trinity_get_ps(new_rps);
+ struct trinity_ps *current_ps = trinity_get_ps(old_rps);
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 min_voltage = 0; /* ??? */
+ u32 min_sclk = pi->sys_info.min_sclk; /* XXX check against disp reqs */
+ u32 sclk_in_sr = pi->sys_info.min_sclk; /* ??? */
+ u32 i;
+ bool force_high;
+ u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
+
+ if (new_rps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
+ return trinity_patch_thermal_state(rdev, ps, current_ps);
+
+ trinity_adjust_uvd_state(rdev, new_rps);
+
+ for (i = 0; i < ps->num_levels; i++) {
+ if (ps->levels[i].vddc_index < min_voltage)
+ ps->levels[i].vddc_index = min_voltage;
+
+ if (ps->levels[i].sclk < min_sclk)
+ ps->levels[i].sclk =
+ trinity_get_valid_engine_clock(rdev, min_sclk);
+
+ ps->levels[i].ds_divider_index =
+ sumo_get_sleep_divider_id_from_clock(rdev, ps->levels[i].sclk, sclk_in_sr);
+
+ ps->levels[i].ss_divider_index = ps->levels[i].ds_divider_index;
+
+ ps->levels[i].allow_gnb_slow = 1;
+ ps->levels[i].force_nbp_state = 0;
+ ps->levels[i].display_wm =
+ trinity_calculate_display_wm(rdev, ps, i);
+ ps->levels[i].vce_wm =
+ trinity_calculate_vce_wm(rdev, ps->levels[0].sclk);
+ }
+
+ if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
+ ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY))
+ ps->bapm_flags |= TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE;
+
+ if (pi->sys_info.nb_dpm_enable) {
+ ps->Dpm0PgNbPsLo = 0x1;
+ ps->Dpm0PgNbPsHi = 0x0;
+ ps->DpmXNbPsLo = 0x2;
+ ps->DpmXNbPsHi = 0x1;
+
+ if ((new_rps->class & (ATOM_PPLIB_CLASSIFICATION_HDSTATE | ATOM_PPLIB_CLASSIFICATION_SDSTATE)) ||
+ ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)) {
+ force_high = ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ||
+ ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) &&
+ (pi->sys_info.uma_channel_number == 1)));
+ force_high = (num_active_displays >= 3) || force_high;
+ ps->Dpm0PgNbPsLo = force_high ? 0x2 : 0x3;
+ ps->Dpm0PgNbPsHi = 0x1;
+ ps->DpmXNbPsLo = force_high ? 0x2 : 0x3;
+ ps->DpmXNbPsHi = 0x2;
+ ps->levels[ps->num_levels - 1].allow_gnb_slow = 0;
+ }
+ }
+}
+
+static void trinity_cleanup_asic(struct radeon_device *rdev)
+{
+ sumo_take_smu_control(rdev, false);
+}
+
+#if 0
+static void trinity_pre_display_configuration_change(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ if (pi->voltage_drop_in_dce)
+ trinity_dce_enable_voltage_adjustment(rdev, false);
+}
+#endif
+
+static void trinity_add_dccac_value(struct radeon_device *rdev)
+{
+ u32 gpu_cac_avrg_cntl_window_size;
+ u32 num_active_displays = rdev->pm.dpm.new_active_crtc_count;
+ u64 disp_clk = rdev->clock.default_dispclk / 100;
+ u32 dc_cac_value;
+
+ gpu_cac_avrg_cntl_window_size =
+ (RREG32_SMC(GPU_CAC_AVRG_CNTL) & WINDOW_SIZE_MASK) >> WINDOW_SIZE_SHIFT;
+
+ dc_cac_value = (u32)((14213 * disp_clk * disp_clk * (u64)num_active_displays) >>
+ (32 - gpu_cac_avrg_cntl_window_size));
+
+ WREG32_SMC(DC_CAC_VALUE, dc_cac_value);
+}
+
+void trinity_dpm_display_configuration_changed(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ if (pi->voltage_drop_in_dce)
+ trinity_dce_enable_voltage_adjustment(rdev, true);
+ trinity_add_dccac_value(rdev);
+}
+
+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;
+};
+
+union pplib_power_state {
+ struct _ATOM_PPLIB_STATE v1;
+ struct _ATOM_PPLIB_STATE_V2 v2;
+};
+
+static void trinity_parse_pplib_non_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps,
+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info,
+ u8 table_rev)
+{
+ struct trinity_ps *ps = trinity_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) {
+ rdev->pm.dpm.boot_ps = rps;
+ trinity_patch_boot_state(rdev, ps);
+ }
+ if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
+ rdev->pm.dpm.uvd_ps = rps;
+}
+
+static void trinity_parse_pplib_clock_info(struct radeon_device *rdev,
+ struct radeon_ps *rps, int index,
+ union pplib_clock_info *clock_info)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct trinity_ps *ps = trinity_get_ps(rps);
+ struct trinity_pl *pl = &ps->levels[index];
+ u32 sclk;
+
+ sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
+ sclk |= clock_info->sumo.ucEngineClockHigh << 16;
+ pl->sclk = sclk;
+ pl->vddc_index = clock_info->sumo.vddcIndex;
+
+ ps->num_levels = index + 1;
+
+ if (pi->enable_sclk_ds) {
+ pl->ds_divider_index = 5;
+ pl->ss_divider_index = 5;
+ }
+}
+
+static int trinity_parse_power_table(struct radeon_device *rdev)
+{
+ struct radeon_mode_info *mode_info = &rdev->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 sumo_ps *ps;
+
+ if (!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));
+
+ rdev->pm.dpm.ps = kzalloc(sizeof(struct radeon_ps) *
+ state_array->ucNumEntries, GFP_KERNEL);
+ if (!rdev->pm.dpm.ps)
+ return -ENOMEM;
+ power_state_offset = (u8 *)state_array->states;
+ rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+ rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+ rdev->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];
+ if (!rdev->pm.power_state[i].clock_info)
+ return -EINVAL;
+ ps = kzalloc(sizeof(struct sumo_ps), GFP_KERNEL);
+ if (ps == NULL) {
+ kfree(rdev->pm.dpm.ps);
+ return -ENOMEM;
+ }
+ rdev->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 >= SUMO_MAX_HARDWARE_POWERLEVELS)
+ break;
+ clock_info = (union pplib_clock_info *)
+ &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+ trinity_parse_pplib_clock_info(rdev,
+ &rdev->pm.dpm.ps[i], k,
+ clock_info);
+ k++;
+ }
+ trinity_parse_pplib_non_clock_info(rdev, &rdev->pm.dpm.ps[i],
+ non_clock_info,
+ non_clock_info_array->ucEntrySize);
+ power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
+ }
+ rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+ return 0;
+}
+
+union igp_info {
+ struct _ATOM_INTEGRATED_SYSTEM_INFO info;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V5 info_5;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
+};
+
+static u32 trinity_convert_did_to_freq(struct radeon_device *rdev, u8 did)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ u32 divider;
+
+ if (did >= 8 && did <= 0x3f)
+ divider = did * 25;
+ else if (did > 0x3f && did <= 0x5f)
+ divider = (did - 64) * 50 + 1600;
+ else if (did > 0x5f && did <= 0x7e)
+ divider = (did - 96) * 100 + 3200;
+ else if (did == 0x7f)
+ divider = 128 * 100;
+ else
+ return 10000;
+
+ return ((pi->sys_info.dentist_vco_freq * 100) + (divider - 1)) / divider;
+}
+
+static int trinity_parse_sys_info_table(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct radeon_mode_info *mode_info = &rdev->mode_info;
+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
+ union igp_info *igp_info;
+ u8 frev, crev;
+ u16 data_offset;
+ int i;
+
+ if (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 != 7) {
+ DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
+ return -EINVAL;
+ }
+ pi->sys_info.bootup_sclk = le32_to_cpu(igp_info->info_7.ulBootUpEngineClock);
+ pi->sys_info.min_sclk = le32_to_cpu(igp_info->info_7.ulMinEngineClock);
+ pi->sys_info.bootup_uma_clk = le32_to_cpu(igp_info->info_7.ulBootUpUMAClock);
+ pi->sys_info.dentist_vco_freq = le32_to_cpu(igp_info->info_7.ulDentistVCOFreq);
+ pi->sys_info.bootup_nb_voltage_index =
+ le16_to_cpu(igp_info->info_7.usBootUpNBVoltage);
+ if (igp_info->info_7.ucHtcTmpLmt == 0)
+ pi->sys_info.htc_tmp_lmt = 203;
+ else
+ pi->sys_info.htc_tmp_lmt = igp_info->info_7.ucHtcTmpLmt;
+ if (igp_info->info_7.ucHtcHystLmt == 0)
+ pi->sys_info.htc_hyst_lmt = 5;
+ else
+ pi->sys_info.htc_hyst_lmt = igp_info->info_7.ucHtcHystLmt;
+ if (pi->sys_info.htc_tmp_lmt <= pi->sys_info.htc_hyst_lmt) {
+ DRM_ERROR("The htcTmpLmt should be larger than htcHystLmt.\n");
+ }
+
+ if (pi->enable_nbps_policy)
+ pi->sys_info.nb_dpm_enable = igp_info->info_7.ucNBDPMEnable;
+ else
+ pi->sys_info.nb_dpm_enable = 0;
+
+ for (i = 0; i < TRINITY_NUM_NBPSTATES; i++) {
+ pi->sys_info.nbp_mclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateMemclkFreq[i]);
+ pi->sys_info.nbp_nclk[i] = le32_to_cpu(igp_info->info_7.ulNbpStateNClkFreq[i]);
+ }
+
+ pi->sys_info.nbp_voltage_index[0] = le16_to_cpu(igp_info->info_7.usNBP0Voltage);
+ pi->sys_info.nbp_voltage_index[1] = le16_to_cpu(igp_info->info_7.usNBP1Voltage);
+ pi->sys_info.nbp_voltage_index[2] = le16_to_cpu(igp_info->info_7.usNBP2Voltage);
+ pi->sys_info.nbp_voltage_index[3] = le16_to_cpu(igp_info->info_7.usNBP3Voltage);
+
+ if (!pi->sys_info.nb_dpm_enable) {
+ for (i = 1; i < TRINITY_NUM_NBPSTATES; i++) {
+ pi->sys_info.nbp_mclk[i] = pi->sys_info.nbp_mclk[0];
+ pi->sys_info.nbp_nclk[i] = pi->sys_info.nbp_nclk[0];
+ pi->sys_info.nbp_voltage_index[i] = pi->sys_info.nbp_voltage_index[0];
+ }
+ }
+
+ pi->sys_info.uma_channel_number = igp_info->info_7.ucUMAChannelNumber;
+
+ sumo_construct_sclk_voltage_mapping_table(rdev,
+ &pi->sys_info.sclk_voltage_mapping_table,
+ igp_info->info_7.sAvail_SCLK);
+ sumo_construct_vid_mapping_table(rdev, &pi->sys_info.vid_mapping_table,
+ igp_info->info_7.sAvail_SCLK);
+
+ pi->sys_info.uvd_clock_table_entries[0].vclk_did =
+ igp_info->info_7.ucDPMState0VclkFid;
+ pi->sys_info.uvd_clock_table_entries[1].vclk_did =
+ igp_info->info_7.ucDPMState1VclkFid;
+ pi->sys_info.uvd_clock_table_entries[2].vclk_did =
+ igp_info->info_7.ucDPMState2VclkFid;
+ pi->sys_info.uvd_clock_table_entries[3].vclk_did =
+ igp_info->info_7.ucDPMState3VclkFid;
+
+ pi->sys_info.uvd_clock_table_entries[0].dclk_did =
+ igp_info->info_7.ucDPMState0DclkFid;
+ pi->sys_info.uvd_clock_table_entries[1].dclk_did =
+ igp_info->info_7.ucDPMState1DclkFid;
+ pi->sys_info.uvd_clock_table_entries[2].dclk_did =
+ igp_info->info_7.ucDPMState2DclkFid;
+ pi->sys_info.uvd_clock_table_entries[3].dclk_did =
+ igp_info->info_7.ucDPMState3DclkFid;
+
+ for (i = 0; i < 4; i++) {
+ pi->sys_info.uvd_clock_table_entries[i].vclk =
+ trinity_convert_did_to_freq(rdev,
+ pi->sys_info.uvd_clock_table_entries[i].vclk_did);
+ pi->sys_info.uvd_clock_table_entries[i].dclk =
+ trinity_convert_did_to_freq(rdev,
+ pi->sys_info.uvd_clock_table_entries[i].dclk_did);
+ }
+
+
+
+ }
+ return 0;
+}
+
+int trinity_dpm_init(struct radeon_device *rdev)
+{
+ struct trinity_power_info *pi;
+ int ret, i;
+
+ pi = kzalloc(sizeof(struct trinity_power_info), GFP_KERNEL);
+ if (pi == NULL)
+ return -ENOMEM;
+ rdev->pm.dpm.priv = pi;
+
+ for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
+ pi->at[i] = TRINITY_AT_DFLT;
+
+ pi->enable_nbps_policy = true;
+ pi->enable_sclk_ds = true;
+ pi->enable_gfx_power_gating = true;
+ pi->enable_gfx_clock_gating = true;
+ pi->enable_mg_clock_gating = true;
+ pi->enable_gfx_dynamic_mgpg = true; /* ??? */
+ pi->override_dynamic_mgpg = true;
+ pi->enable_auto_thermal_throttling = true;
+ pi->voltage_drop_in_dce = false; /* need to restructure dpm/modeset interaction */
+ pi->uvd_dpm = true; /* ??? */
+
+ ret = trinity_parse_sys_info_table(rdev);
+ if (ret)
+ return ret;
+
+ trinity_construct_boot_state(rdev);
+
+ ret = trinity_parse_power_table(rdev);
+ if (ret)
+ return ret;
+
+ pi->thermal_auto_throttling = pi->sys_info.htc_tmp_lmt;
+ pi->enable_dpm = true;
+
+ return 0;
+}
+
+void trinity_dpm_print_power_state(struct radeon_device *rdev,
+ struct radeon_ps *rps)
+{
+ int i;
+ struct trinity_ps *ps = trinity_get_ps(rps);
+
+ r600_dpm_print_class_info(rps->class, rps->class2);
+ r600_dpm_print_cap_info(rps->caps);
+ printk("\tuvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ for (i = 0; i < ps->num_levels; i++) {
+ struct trinity_pl *pl = &ps->levels[i];
+ printk("\t\tpower level %d sclk: %u vddc: %u\n",
+ i, pl->sclk,
+ trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
+ }
+ r600_dpm_print_ps_status(rdev, rps);
+}
+
+void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
+ struct seq_file *m)
+{
+ struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+ struct trinity_ps *ps = trinity_get_ps(rps);
+ struct trinity_pl *pl;
+ u32 current_index =
+ (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_STATE_MASK) >>
+ CURRENT_STATE_SHIFT;
+
+ if (current_index >= ps->num_levels) {
+ seq_printf(m, "invalid dpm profile %d\n", current_index);
+ } else {
+ pl = &ps->levels[current_index];
+ seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk);
+ seq_printf(m, "power level %d sclk: %u vddc: %u\n",
+ current_index, pl->sclk,
+ trinity_convert_voltage_index_to_value(rdev, pl->vddc_index));
+ }
+}
+
+void trinity_dpm_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ trinity_cleanup_asic(rdev); /* ??? */
+
+ for (i = 0; i < rdev->pm.dpm.num_ps; i++) {
+ kfree(rdev->pm.dpm.ps[i].ps_priv);
+ }
+ kfree(rdev->pm.dpm.ps);
+ kfree(rdev->pm.dpm.priv);
+}
+
+u32 trinity_dpm_get_sclk(struct radeon_device *rdev, bool low)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+ struct trinity_ps *requested_state = trinity_get_ps(&pi->requested_rps);
+
+ if (low)
+ return requested_state->levels[0].sclk;
+ else
+ return requested_state->levels[requested_state->num_levels - 1].sclk;
+}
+
+u32 trinity_dpm_get_mclk(struct radeon_device *rdev, bool low)
+{
+ struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+ return pi->sys_info.bootup_uma_clk;
+}
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.h b/drivers/gpu/drm/radeon/trinity_dpm.h
new file mode 100644
index 000000000000..e82df071f8b3
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinity_dpm.h
@@ -0,0 +1,132 @@
+/*
+ * 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 __TRINITY_DPM_H__
+#define __TRINITY_DPM_H__
+
+#include "sumo_dpm.h"
+
+#define TRINITY_SIZEOF_DPM_STATE_TABLE (SMU_SCLK_DPM_STATE_1_CNTL_0 - SMU_SCLK_DPM_STATE_0_CNTL_0)
+
+struct trinity_pl {
+ u32 sclk;
+ u8 vddc_index;
+ u8 ds_divider_index;
+ u8 ss_divider_index;
+ u8 allow_gnb_slow;
+ u8 force_nbp_state;
+ u8 display_wm;
+ u8 vce_wm;
+};
+
+#define TRINITY_POWERSTATE_FLAGS_NBPS_FORCEHIGH (1 << 0)
+#define TRINITY_POWERSTATE_FLAGS_NBPS_LOCKTOHIGH (1 << 1)
+#define TRINITY_POWERSTATE_FLAGS_NBPS_LOCKTOLOW (1 << 2)
+
+#define TRINITY_POWERSTATE_FLAGS_BAPM_DISABLE (1 << 0)
+
+struct trinity_ps {
+ u32 num_levels;
+ struct trinity_pl levels[SUMO_MAX_HARDWARE_POWERLEVELS];
+
+ u32 nbps_flags;
+ u32 bapm_flags;
+
+ u8 Dpm0PgNbPsLo;
+ u8 Dpm0PgNbPsHi;
+ u8 DpmXNbPsLo;
+ u8 DpmXNbPsHi;
+
+ u32 vclk_low_divider;
+ u32 vclk_high_divider;
+ u32 dclk_low_divider;
+ u32 dclk_high_divider;
+};
+
+#define TRINITY_NUM_NBPSTATES 4
+
+struct trinity_uvd_clock_table_entry
+{
+ u32 vclk;
+ u32 dclk;
+ u8 vclk_did;
+ u8 dclk_did;
+ u8 rsv[2];
+};
+
+struct trinity_sys_info {
+ u32 bootup_uma_clk;
+ u32 bootup_sclk;
+ u32 min_sclk;
+ u32 dentist_vco_freq;
+ u32 nb_dpm_enable;
+ u32 nbp_mclk[TRINITY_NUM_NBPSTATES];
+ u32 nbp_nclk[TRINITY_NUM_NBPSTATES];
+ u16 nbp_voltage_index[TRINITY_NUM_NBPSTATES];
+ u16 bootup_nb_voltage_index;
+ u8 htc_tmp_lmt;
+ u8 htc_hyst_lmt;
+ struct sumo_sclk_voltage_mapping_table sclk_voltage_mapping_table;
+ struct sumo_vid_mapping_table vid_mapping_table;
+ u32 uma_channel_number;
+ struct trinity_uvd_clock_table_entry uvd_clock_table_entries[4];
+};
+
+struct trinity_power_info {
+ u32 at[SUMO_MAX_HARDWARE_POWERLEVELS];
+ u32 dpm_interval;
+ u32 thermal_auto_throttling;
+ struct trinity_sys_info sys_info;
+ struct trinity_pl boot_pl;
+ u32 min_sclk_did;
+ bool enable_nbps_policy;
+ bool voltage_drop_in_dce;
+ bool override_dynamic_mgpg;
+ bool enable_gfx_clock_gating;
+ bool enable_gfx_power_gating;
+ bool enable_mg_clock_gating;
+ bool enable_gfx_dynamic_mgpg;
+ bool enable_auto_thermal_throttling;
+ bool enable_dpm;
+ bool enable_sclk_ds;
+ bool uvd_dpm;
+ struct radeon_ps current_rps;
+ struct trinity_ps current_ps;
+ struct radeon_ps requested_rps;
+ struct trinity_ps requested_ps;
+};
+
+#define TRINITY_AT_DFLT 30
+
+/* trinity_smc.c */
+int trinity_dpm_config(struct radeon_device *rdev, bool enable);
+int trinity_uvd_dpm_config(struct radeon_device *rdev);
+int trinity_dpm_force_state(struct radeon_device *rdev, u32 n);
+int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n);
+int trinity_dpm_no_forced_level(struct radeon_device *rdev);
+int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
+ bool enable);
+int trinity_gfx_dynamic_mgpg_config(struct radeon_device *rdev);
+void trinity_acquire_mutex(struct radeon_device *rdev);
+void trinity_release_mutex(struct radeon_device *rdev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c
new file mode 100644
index 000000000000..a42d89f1830c
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinity_smc.c
@@ -0,0 +1,122 @@
+/*
+ * 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 "radeon.h"
+#include "trinityd.h"
+#include "trinity_dpm.h"
+#include "ppsmc.h"
+
+struct trinity_ps *trinity_get_ps(struct radeon_ps *rps);
+struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev);
+
+static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id)
+{
+ int i;
+ u32 v = 0;
+
+ WREG32(SMC_MESSAGE_0, id);
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if (RREG32(SMC_RESP_0) != 0)
+ break;
+ udelay(1);
+ }
+ v = RREG32(SMC_RESP_0);
+
+ if (v != 1) {
+ if (v == 0xFF) {
+ DRM_ERROR("SMC failed to handle the message!\n");
+ return -EINVAL;
+ } else if (v == 0xFE) {
+ DRM_ERROR("Unknown SMC message!\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int trinity_dpm_config(struct radeon_device *rdev, bool enable)
+{
+ if (enable)
+ WREG32_SMC(SMU_SCRATCH0, 1);
+ else
+ WREG32_SMC(SMU_SCRATCH0, 0);
+
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Config);
+}
+
+int trinity_dpm_force_state(struct radeon_device *rdev, u32 n)
+{
+ WREG32_SMC(SMU_SCRATCH0, n);
+
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_ForceState);
+}
+
+int trinity_dpm_n_levels_disabled(struct radeon_device *rdev, u32 n)
+{
+ WREG32_SMC(SMU_SCRATCH0, n);
+
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DPM_N_LevelsDisabled);
+}
+
+int trinity_uvd_dpm_config(struct radeon_device *rdev)
+{
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_UVD_DPM_Config);
+}
+
+int trinity_dpm_no_forced_level(struct radeon_device *rdev)
+{
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
+}
+
+int trinity_dce_enable_voltage_adjustment(struct radeon_device *rdev,
+ bool enable)
+{
+ if (enable)
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DCE_AllowVoltageAdjustment);
+ else
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DCE_RemoveVoltageAdjustment);
+}
+
+int trinity_gfx_dynamic_mgpg_config(struct radeon_device *rdev)
+{
+ return trinity_notify_message_to_smu(rdev, PPSMC_MSG_PG_SIMD_Config);
+}
+
+void trinity_acquire_mutex(struct radeon_device *rdev)
+{
+ int i;
+
+ WREG32(SMC_INT_REQ, 1);
+ for (i = 0; i < rdev->usec_timeout; i++) {
+ if ((RREG32(SMC_INT_REQ) & 0xffff) == 1)
+ break;
+ udelay(1);
+ }
+}
+
+void trinity_release_mutex(struct radeon_device *rdev)
+{
+ WREG32(SMC_INT_REQ, 0);
+}
diff --git a/drivers/gpu/drm/radeon/trinityd.h b/drivers/gpu/drm/radeon/trinityd.h
new file mode 100644
index 000000000000..fd32e2771755
--- /dev/null
+++ b/drivers/gpu/drm/radeon/trinityd.h
@@ -0,0 +1,228 @@
+/*
+ * 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 _TRINITYD_H_
+#define _TRINITYD_H_
+
+/* pm registers */
+
+/* cg */
+#define CG_CGTT_LOCAL_0 0x0
+#define CG_CGTT_LOCAL_1 0x1
+
+/* smc */
+#define SMU_SCLK_DPM_STATE_0_CNTL_0 0x1f000
+# define STATE_VALID(x) ((x) << 0)
+# define STATE_VALID_MASK (0xff << 0)
+# define STATE_VALID_SHIFT 0
+# define CLK_DIVIDER(x) ((x) << 8)
+# define CLK_DIVIDER_MASK (0xff << 8)
+# define CLK_DIVIDER_SHIFT 8
+# define VID(x) ((x) << 16)
+# define VID_MASK (0xff << 16)
+# define VID_SHIFT 16
+# define LVRT(x) ((x) << 24)
+# define LVRT_MASK (0xff << 24)
+# define LVRT_SHIFT 24
+#define SMU_SCLK_DPM_STATE_0_CNTL_1 0x1f004
+# define DS_DIV(x) ((x) << 0)
+# define DS_DIV_MASK (0xff << 0)
+# define DS_DIV_SHIFT 0
+# define DS_SH_DIV(x) ((x) << 8)
+# define DS_SH_DIV_MASK (0xff << 8)
+# define DS_SH_DIV_SHIFT 8
+# define DISPLAY_WM(x) ((x) << 16)
+# define DISPLAY_WM_MASK (0xff << 16)
+# define DISPLAY_WM_SHIFT 16
+# define VCE_WM(x) ((x) << 24)
+# define VCE_WM_MASK (0xff << 24)
+# define VCE_WM_SHIFT 24
+
+#define SMU_SCLK_DPM_STATE_0_CNTL_3 0x1f00c
+# define GNB_SLOW(x) ((x) << 0)
+# define GNB_SLOW_MASK (0xff << 0)
+# define GNB_SLOW_SHIFT 0
+# define FORCE_NBPS1(x) ((x) << 8)
+# define FORCE_NBPS1_MASK (0xff << 8)
+# define FORCE_NBPS1_SHIFT 8
+#define SMU_SCLK_DPM_STATE_0_AT 0x1f010
+# define AT(x) ((x) << 0)
+# define AT_MASK (0xff << 0)
+# define AT_SHIFT 0
+
+#define SMU_SCLK_DPM_STATE_0_PG_CNTL 0x1f014
+# define PD_SCLK_DIVIDER(x) ((x) << 16)
+# define PD_SCLK_DIVIDER_MASK (0xff << 16)
+# define PD_SCLK_DIVIDER_SHIFT 16
+
+#define SMU_SCLK_DPM_STATE_1_CNTL_0 0x1f020
+
+#define SMU_SCLK_DPM_CNTL 0x1f100
+# define SCLK_DPM_EN(x) ((x) << 0)
+# define SCLK_DPM_EN_MASK (0xff << 0)
+# define SCLK_DPM_EN_SHIFT 0
+# define SCLK_DPM_BOOT_STATE(x) ((x) << 16)
+# define SCLK_DPM_BOOT_STATE_MASK (0xff << 16)
+# define SCLK_DPM_BOOT_STATE_SHIFT 16
+# define VOLTAGE_CHG_EN(x) ((x) << 24)
+# define VOLTAGE_CHG_EN_MASK (0xff << 24)
+# define VOLTAGE_CHG_EN_SHIFT 24
+
+#define SMU_SCLK_DPM_TT_CNTL 0x1f108
+# define SCLK_TT_EN(x) ((x) << 0)
+# define SCLK_TT_EN_MASK (0xff << 0)
+# define SCLK_TT_EN_SHIFT 0
+#define SMU_SCLK_DPM_TTT 0x1f10c
+# define LT(x) ((x) << 0)
+# define LT_MASK (0xffff << 0)
+# define LT_SHIFT 0
+# define HT(x) ((x) << 16)
+# define HT_MASK (0xffff << 16)
+# define HT_SHIFT 16
+
+#define SMU_UVD_DPM_STATES 0x1f1a0
+#define SMU_UVD_DPM_CNTL 0x1f1a4
+
+#define SMU_S_PG_CNTL 0x1f118
+# define DS_PG_EN(x) ((x) << 16)
+# define DS_PG_EN_MASK (0xff << 16)
+# define DS_PG_EN_SHIFT 16
+
+#define GFX_POWER_GATING_CNTL 0x1f38c
+# define PDS_DIV(x) ((x) << 0)
+# define PDS_DIV_MASK (0xff << 0)
+# define PDS_DIV_SHIFT 0
+# define SSSD(x) ((x) << 8)
+# define SSSD_MASK (0xff << 8)
+# define SSSD_SHIFT 8
+
+#define PM_CONFIG 0x1f428
+# define SVI_Mode (1 << 29)
+
+#define PM_I_CNTL_1 0x1f464
+# define SCLK_DPM(x) ((x) << 0)
+# define SCLK_DPM_MASK (0xff << 0)
+# define SCLK_DPM_SHIFT 0
+# define DS_PG_CNTL(x) ((x) << 16)
+# define DS_PG_CNTL_MASK (0xff << 16)
+# define DS_PG_CNTL_SHIFT 16
+#define PM_TP 0x1f468
+
+#define NB_PSTATE_CONFIG 0x1f5f8
+# define Dpm0PgNbPsLo(x) ((x) << 0)
+# define Dpm0PgNbPsLo_MASK (3 << 0)
+# define Dpm0PgNbPsLo_SHIFT 0
+# define Dpm0PgNbPsHi(x) ((x) << 2)
+# define Dpm0PgNbPsHi_MASK (3 << 2)
+# define Dpm0PgNbPsHi_SHIFT 2
+# define DpmXNbPsLo(x) ((x) << 4)
+# define DpmXNbPsLo_MASK (3 << 4)
+# define DpmXNbPsLo_SHIFT 4
+# define DpmXNbPsHi(x) ((x) << 6)
+# define DpmXNbPsHi_MASK (3 << 6)
+# define DpmXNbPsHi_SHIFT 6
+
+#define DC_CAC_VALUE 0x1f908
+
+#define GPU_CAC_AVRG_CNTL 0x1f920
+# define WINDOW_SIZE(x) ((x) << 0)
+# define WINDOW_SIZE_MASK (0xff << 0)
+# define WINDOW_SIZE_SHIFT 0
+
+#define CC_SMU_MISC_FUSES 0xe0001004
+# define MinSClkDid(x) ((x) << 2)
+# define MinSClkDid_MASK (0x7f << 2)
+# define MinSClkDid_SHIFT 2
+
+#define CC_SMU_TST_EFUSE1_MISC 0xe000101c
+# define RB_BACKEND_DISABLE(x) ((x) << 16)
+# define RB_BACKEND_DISABLE_MASK (3 << 16)
+# define RB_BACKEND_DISABLE_SHIFT 16
+
+#define SMU_SCRATCH_A 0xe0003024
+
+#define SMU_SCRATCH0 0xe0003040
+
+/* mmio */
+#define SMC_INT_REQ 0x220
+
+#define SMC_MESSAGE_0 0x22c
+#define SMC_RESP_0 0x230
+
+#define GENERAL_PWRMGT 0x670
+# define GLOBAL_PWRMGT_EN (1 << 0)
+
+#define SCLK_PWRMGT_CNTL 0x678
+# define DYN_PWR_DOWN_EN (1 << 2)
+# define RESET_BUSY_CNT (1 << 4)
+# define RESET_SCLK_CNT (1 << 5)
+# define DYN_GFX_CLK_OFF_EN (1 << 7)
+# define GFX_CLK_FORCE_ON (1 << 8)
+# define DYNAMIC_PM_EN (1 << 21)
+
+#define TARGET_AND_CURRENT_PROFILE_INDEX 0x684
+# define TARGET_STATE(x) ((x) << 0)
+# define TARGET_STATE_MASK (0xf << 0)
+# define TARGET_STATE_SHIFT 0
+# define CURRENT_STATE(x) ((x) << 4)
+# define CURRENT_STATE_MASK (0xf << 4)
+# define CURRENT_STATE_SHIFT 4
+
+#define CG_GIPOTS 0x6d8
+# define CG_GIPOT(x) ((x) << 16)
+# define CG_GIPOT_MASK (0xffff << 16)
+# define CG_GIPOT_SHIFT 16
+
+#define CG_PG_CTRL 0x6e0
+# define SP(x) ((x) << 0)
+# define SP_MASK (0xffff << 0)
+# define SP_SHIFT 0
+# define SU(x) ((x) << 16)
+# define SU_MASK (0xffff << 16)
+# define SU_SHIFT 16
+
+#define CG_MISC_REG 0x708
+
+#define CG_THERMAL_INT_CTRL 0x738
+# define DIG_THERM_INTH(x) ((x) << 0)
+# define DIG_THERM_INTH_MASK (0xff << 0)
+# define DIG_THERM_INTH_SHIFT 0
+# define DIG_THERM_INTL(x) ((x) << 8)
+# define DIG_THERM_INTL_MASK (0xff << 8)
+# define DIG_THERM_INTL_SHIFT 8
+# define THERM_INTH_MASK (1 << 24)
+# define THERM_INTL_MASK (1 << 25)
+
+#define CG_CG_VOLTAGE_CNTL 0x770
+# define EN (1 << 9)
+
+#define HW_REV 0x5564
+# define ATI_REV_ID_MASK (0xf << 28)
+# define ATI_REV_ID_SHIFT 28
+/* 0 = A0, 1 = A1, 2 = B0, 3 = C0, etc. */
+
+#define CGTS_SM_CTRL_REG 0x9150
+
+#define GB_ADDR_CONFIG 0x98f8
+
+#endif
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
new file mode 100644
index 000000000000..72887df8dd76
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -0,0 +1,9 @@
+config DRM_RCAR_DU
+ tristate "DRM Support for R-Car Display Unit"
+ depends on DRM && ARM
+ select DRM_KMS_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
+ help
+ Choose this option if you have an R-Car chipset.
+ If M is selected the module will be called rcar-du-drm.
diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile
new file mode 100644
index 000000000000..7333c0094015
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/Makefile
@@ -0,0 +1,8 @@
+rcar-du-drm-y := rcar_du_crtc.o \
+ rcar_du_drv.o \
+ rcar_du_kms.o \
+ rcar_du_lvds.o \
+ rcar_du_plane.o \
+ rcar_du_vga.o
+
+obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
new file mode 100644
index 000000000000..24183fb93592
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -0,0 +1,595 @@
+/*
+ * rcar_du_crtc.c -- R-Car Display Unit CRTCs
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/mutex.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_lvds.h"
+#include "rcar_du_plane.h"
+#include "rcar_du_regs.h"
+#include "rcar_du_vga.h"
+
+#define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc)
+
+static u32 rcar_du_crtc_read(struct rcar_du_crtc *rcrtc, u32 reg)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ return rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
+}
+
+static void rcar_du_crtc_write(struct rcar_du_crtc *rcrtc, u32 reg, u32 data)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ rcar_du_write(rcdu, rcrtc->mmio_offset + reg, data);
+}
+
+static void rcar_du_crtc_clr(struct rcar_du_crtc *rcrtc, u32 reg, u32 clr)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
+ rcar_du_read(rcdu, rcrtc->mmio_offset + reg) & ~clr);
+}
+
+static void rcar_du_crtc_set(struct rcar_du_crtc *rcrtc, u32 reg, u32 set)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ rcar_du_write(rcdu, rcrtc->mmio_offset + reg,
+ rcar_du_read(rcdu, rcrtc->mmio_offset + reg) | set);
+}
+
+static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
+ u32 clr, u32 set)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+ u32 value = rcar_du_read(rcdu, rcrtc->mmio_offset + reg);
+
+ rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set);
+}
+
+static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
+{
+ struct drm_crtc *crtc = &rcrtc->crtc;
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+ const struct drm_display_mode *mode = &crtc->mode;
+ unsigned long clk;
+ u32 value;
+ u32 div;
+
+ /* Dot clock */
+ clk = clk_get_rate(rcdu->clock);
+ div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
+ div = clamp(div, 1U, 64U) - 1;
+
+ rcar_du_write(rcdu, rcrtc->index ? ESCR2 : ESCR,
+ ESCR_DCLKSEL_CLKS | div);
+ rcar_du_write(rcdu, rcrtc->index ? OTAR2 : OTAR, 0);
+
+ /* Signal polarities */
+ value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
+ | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
+ | DSMR_DIPM_DE;
+ rcar_du_crtc_write(rcrtc, DSMR, value);
+
+ /* Display timings */
+ rcar_du_crtc_write(rcrtc, HDSR, mode->htotal - mode->hsync_start - 19);
+ rcar_du_crtc_write(rcrtc, HDER, mode->htotal - mode->hsync_start +
+ mode->hdisplay - 19);
+ rcar_du_crtc_write(rcrtc, HSWR, mode->hsync_end -
+ mode->hsync_start - 1);
+ rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1);
+
+ rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
+ rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
+ mode->vdisplay - 2);
+ rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
+ mode->vsync_start - 1);
+ rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1);
+
+ rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start);
+ rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
+}
+
+static void rcar_du_crtc_set_routing(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+ u32 dorcr = rcar_du_read(rcdu, DORCR);
+
+ dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK);
+
+ /* Set the DU1 pins sources. Select CRTC 0 if explicitly requested and
+ * CRTC 1 in all other cases to avoid cloning CRTC 0 to DU0 and DU1 by
+ * default.
+ */
+ if (rcrtc->outputs & (1 << 1) && rcrtc->index == 0)
+ dorcr |= DORCR_PG2D_DS1;
+ else
+ dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2;
+
+ rcar_du_write(rcdu, DORCR, dorcr);
+}
+
+static void __rcar_du_start_stop(struct rcar_du_device *rcdu, bool start)
+{
+ rcar_du_write(rcdu, DSYSR,
+ (rcar_du_read(rcdu, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
+ (start ? DSYSR_DEN : DSYSR_DRES));
+}
+
+static void rcar_du_start_stop(struct rcar_du_device *rcdu, bool start)
+{
+ /* Many of the configuration bits are only updated when the display
+ * reset (DRES) bit in DSYSR is set to 1, disabling *both* CRTCs. Some
+ * of those bits could be pre-configured, but others (especially the
+ * bits related to plane assignment to display timing controllers) need
+ * to be modified at runtime.
+ *
+ * Restart the display controller if a start is requested. Sorry for the
+ * flicker. It should be possible to move most of the "DRES-update" bits
+ * setup to driver initialization time and minimize the number of cases
+ * when the display controller will have to be restarted.
+ */
+ if (start) {
+ if (rcdu->used_crtcs++ != 0)
+ __rcar_du_start_stop(rcdu, false);
+ __rcar_du_start_stop(rcdu, true);
+ } else {
+ if (--rcdu->used_crtcs == 0)
+ __rcar_du_start_stop(rcdu, false);
+ }
+}
+
+void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ /* Store the route from the CRTC output to the DU output. The DU will be
+ * configured when starting the CRTC.
+ */
+ rcrtc->outputs |= 1 << output;
+}
+
+void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
+{
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
+ unsigned int num_planes = 0;
+ unsigned int prio = 0;
+ unsigned int i;
+ u32 dptsr = 0;
+ u32 dspr = 0;
+
+ for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
+ struct rcar_du_plane *plane = &rcdu->planes.planes[i];
+ unsigned int j;
+
+ if (plane->crtc != &rcrtc->crtc || !plane->enabled)
+ continue;
+
+ /* Insert the plane in the sorted planes array. */
+ for (j = num_planes++; j > 0; --j) {
+ if (planes[j-1]->zpos <= plane->zpos)
+ break;
+ planes[j] = planes[j-1];
+ }
+
+ planes[j] = plane;
+ prio += plane->format->planes * 4;
+ }
+
+ for (i = 0; i < num_planes; ++i) {
+ struct rcar_du_plane *plane = planes[i];
+ unsigned int index = plane->hwindex;
+
+ prio -= 4;
+ dspr |= (index + 1) << prio;
+ dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
+
+ if (plane->format->planes == 2) {
+ index = (index + 1) % 8;
+
+ prio -= 4;
+ dspr |= (index + 1) << prio;
+ dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
+ }
+ }
+
+ /* Select display timing and dot clock generator 2 for planes associated
+ * with superposition controller 2.
+ */
+ if (rcrtc->index) {
+ u32 value = rcar_du_read(rcdu, DPTSR);
+
+ /* The DPTSR register is updated when the display controller is
+ * stopped. We thus need to restart the DU. Once again, sorry
+ * for the flicker. One way to mitigate the issue would be to
+ * pre-associate planes with CRTCs (either with a fixed 4/4
+ * split, or through a module parameter). Flicker would then
+ * occur only if we need to break the pre-association.
+ */
+ if (value != dptsr) {
+ rcar_du_write(rcdu, DPTSR, dptsr);
+ if (rcdu->used_crtcs) {
+ __rcar_du_start_stop(rcdu, false);
+ __rcar_du_start_stop(rcdu, true);
+ }
+ }
+ }
+
+ rcar_du_write(rcdu, rcrtc->index ? DS2PR : DS1PR, dspr);
+}
+
+static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
+{
+ struct drm_crtc *crtc = &rcrtc->crtc;
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+ unsigned int i;
+
+ if (rcrtc->started)
+ return;
+
+ if (WARN_ON(rcrtc->plane->format == NULL))
+ return;
+
+ /* Set display off and background to black */
+ rcar_du_crtc_write(rcrtc, DOOR, DOOR_RGB(0, 0, 0));
+ rcar_du_crtc_write(rcrtc, BPOR, BPOR_RGB(0, 0, 0));
+
+ /* Configure display timings and output routing */
+ rcar_du_crtc_set_display_timing(rcrtc);
+ rcar_du_crtc_set_routing(rcrtc);
+
+ mutex_lock(&rcdu->planes.lock);
+ rcrtc->plane->enabled = true;
+ rcar_du_crtc_update_planes(crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
+ /* Setup planes. */
+ for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
+ struct rcar_du_plane *plane = &rcdu->planes.planes[i];
+
+ if (plane->crtc != crtc || !plane->enabled)
+ continue;
+
+ rcar_du_plane_setup(plane);
+ }
+
+ /* Select master sync mode. This enables display operation in master
+ * sync mode (with the HSYNC and VSYNC signals configured as outputs and
+ * actively driven).
+ */
+ rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
+
+ rcar_du_start_stop(rcdu, true);
+
+ rcrtc->started = true;
+}
+
+static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
+{
+ struct drm_crtc *crtc = &rcrtc->crtc;
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+
+ if (!rcrtc->started)
+ return;
+
+ mutex_lock(&rcdu->planes.lock);
+ rcrtc->plane->enabled = false;
+ rcar_du_crtc_update_planes(crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
+ /* Select switch sync mode. This stops display operation and configures
+ * the HSYNC and VSYNC signals as inputs.
+ */
+ rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
+
+ rcar_du_start_stop(rcdu, false);
+
+ rcrtc->started = false;
+}
+
+void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ rcar_du_crtc_stop(rcrtc);
+ rcar_du_put(rcdu);
+}
+
+void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->crtc.dev->dev_private;
+
+ if (rcrtc->dpms != DRM_MODE_DPMS_ON)
+ return;
+
+ rcar_du_get(rcdu);
+ rcar_du_crtc_start(rcrtc);
+}
+
+static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
+{
+ struct drm_crtc *crtc = &rcrtc->crtc;
+
+ rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
+ rcar_du_plane_update_base(rcrtc->plane);
+}
+
+static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ if (rcrtc->dpms == mode)
+ return;
+
+ if (mode == DRM_MODE_DPMS_ON) {
+ rcar_du_get(rcdu);
+ rcar_du_crtc_start(rcrtc);
+ } else {
+ rcar_du_crtc_stop(rcrtc);
+ rcar_du_put(rcdu);
+ }
+
+ rcrtc->dpms = mode;
+}
+
+static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ /* TODO Fixup modes */
+ return true;
+}
+
+static void rcar_du_crtc_mode_prepare(struct drm_crtc *crtc)
+{
+ struct rcar_du_device *rcdu = crtc->dev->dev_private;
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ /* We need to access the hardware during mode set, acquire a reference
+ * to the DU.
+ */
+ rcar_du_get(rcdu);
+
+ /* Stop the CRTC and release the plane. Force the DPMS mode to off as a
+ * result.
+ */
+ rcar_du_crtc_stop(rcrtc);
+ rcar_du_plane_release(rcrtc->plane);
+
+ rcrtc->dpms = DRM_MODE_DPMS_OFF;
+}
+
+static int rcar_du_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 rcar_du_device *rcdu = crtc->dev->dev_private;
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ const struct rcar_du_format_info *format;
+ int ret;
+
+ format = rcar_du_format_info(crtc->fb->pixel_format);
+ if (format == NULL) {
+ dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n",
+ crtc->fb->pixel_format);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = rcar_du_plane_reserve(rcrtc->plane, format);
+ if (ret < 0)
+ goto error;
+
+ rcrtc->plane->format = format;
+ rcrtc->plane->pitch = crtc->fb->pitches[0];
+
+ rcrtc->plane->src_x = x;
+ rcrtc->plane->src_y = y;
+ rcrtc->plane->width = mode->hdisplay;
+ rcrtc->plane->height = mode->vdisplay;
+
+ rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
+
+ rcrtc->outputs = 0;
+
+ return 0;
+
+error:
+ /* There's no rollback/abort operation to clean up in case of error. We
+ * thus need to release the reference to the DU acquired in prepare()
+ * here.
+ */
+ rcar_du_put(rcdu);
+ return ret;
+}
+
+static void rcar_du_crtc_mode_commit(struct drm_crtc *crtc)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ /* We're done, restart the CRTC and set the DPMS mode to on. The
+ * reference to the DU acquired at prepare() time will thus be released
+ * by the DPMS handler (possibly called by the disable() handler).
+ */
+ rcar_du_crtc_start(rcrtc);
+ rcrtc->dpms = DRM_MODE_DPMS_ON;
+}
+
+static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ rcrtc->plane->src_x = x;
+ rcrtc->plane->src_y = y;
+
+ rcar_du_crtc_update_base(to_rcar_crtc(crtc));
+
+ return 0;
+}
+
+static void rcar_du_crtc_disable(struct drm_crtc *crtc)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+
+ rcar_du_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+ rcar_du_plane_release(rcrtc->plane);
+}
+
+static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
+ .dpms = rcar_du_crtc_dpms,
+ .mode_fixup = rcar_du_crtc_mode_fixup,
+ .prepare = rcar_du_crtc_mode_prepare,
+ .commit = rcar_du_crtc_mode_commit,
+ .mode_set = rcar_du_crtc_mode_set,
+ .mode_set_base = rcar_du_crtc_mode_set_base,
+ .disable = rcar_du_crtc_disable,
+};
+
+void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
+ struct drm_file *file)
+{
+ struct drm_pending_vblank_event *event;
+ struct drm_device *dev = rcrtc->crtc.dev;
+ unsigned long flags;
+
+ /* Destroy the pending vertical blanking event associated with the
+ * pending page flip, if any, and disable vertical blanking interrupts.
+ */
+ spin_lock_irqsave(&dev->event_lock, flags);
+ event = rcrtc->event;
+ if (event && event->base.file_priv == file) {
+ rcrtc->event = NULL;
+ event->base.destroy(&event->base);
+ drm_vblank_put(dev, rcrtc->index);
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
+{
+ struct drm_pending_vblank_event *event;
+ struct drm_device *dev = rcrtc->crtc.dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ event = rcrtc->event;
+ rcrtc->event = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ if (event == NULL)
+ return;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ drm_send_vblank_event(dev, rcrtc->index, event);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ drm_vblank_put(dev, rcrtc->index);
+}
+
+static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event)
+{
+ struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ struct drm_device *dev = rcrtc->crtc.dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (rcrtc->event != NULL) {
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ return -EBUSY;
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ crtc->fb = fb;
+ rcar_du_crtc_update_base(rcrtc);
+
+ if (event) {
+ event->pipe = rcrtc->index;
+ drm_vblank_get(dev, rcrtc->index);
+ spin_lock_irqsave(&dev->event_lock, flags);
+ rcrtc->event = event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+
+ return 0;
+}
+
+static const struct drm_crtc_funcs crtc_funcs = {
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_crtc_helper_set_config,
+ .page_flip = rcar_du_crtc_page_flip,
+};
+
+int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index)
+{
+ struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
+ struct drm_crtc *crtc = &rcrtc->crtc;
+ int ret;
+
+ rcrtc->mmio_offset = index ? DISP2_REG_OFFSET : 0;
+ rcrtc->index = index;
+ rcrtc->dpms = DRM_MODE_DPMS_OFF;
+ rcrtc->plane = &rcdu->planes.planes[index];
+
+ rcrtc->plane->crtc = crtc;
+
+ ret = drm_crtc_init(rcdu->ddev, crtc, &crtc_funcs);
+ if (ret < 0)
+ return ret;
+
+ drm_crtc_helper_add(crtc, &crtc_helper_funcs);
+
+ return 0;
+}
+
+void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable)
+{
+ if (enable) {
+ rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL);
+ rcar_du_crtc_set(rcrtc, DIER, DIER_VBE);
+ } else {
+ rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE);
+ }
+}
+
+void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc)
+{
+ u32 status;
+
+ status = rcar_du_crtc_read(rcrtc, DSSR);
+ rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
+
+ if (status & DSSR_VBK) {
+ drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
+ rcar_du_crtc_finish_page_flip(rcrtc);
+ }
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
new file mode 100644
index 000000000000..2a0365bcbd14
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -0,0 +1,50 @@
+/*
+ * rcar_du_crtc.h -- R-Car Display Unit CRTCs
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_CRTC_H__
+#define __RCAR_DU_CRTC_H__
+
+#include <linux/mutex.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+
+struct rcar_du_device;
+struct rcar_du_plane;
+
+struct rcar_du_crtc {
+ struct drm_crtc crtc;
+
+ unsigned int mmio_offset;
+ unsigned int index;
+ bool started;
+
+ struct drm_pending_vblank_event *event;
+ unsigned int outputs;
+ int dpms;
+
+ struct rcar_du_plane *plane;
+};
+
+int rcar_du_crtc_create(struct rcar_du_device *rcdu, unsigned int index);
+void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable);
+void rcar_du_crtc_irq(struct rcar_du_crtc *rcrtc);
+void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc,
+ struct drm_file *file);
+void rcar_du_crtc_suspend(struct rcar_du_crtc *rcrtc);
+void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc);
+
+void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output);
+void rcar_du_crtc_update_planes(struct drm_crtc *crtc);
+
+#endif /* __RCAR_DU_CRTC_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
new file mode 100644
index 000000000000..ff82877de876
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -0,0 +1,325 @@
+/*
+ * rcar_du_drv.c -- R-Car Display Unit DRM driver
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_regs.h"
+
+/* -----------------------------------------------------------------------------
+ * Core device operations
+ */
+
+/*
+ * rcar_du_get - Acquire a reference to the DU
+ *
+ * Acquiring a reference enables the device clock and setup core registers. A
+ * reference must be held before accessing any hardware registers.
+ *
+ * This function must be called with the DRM mode_config lock held.
+ *
+ * Return 0 in case of success or a negative error code otherwise.
+ */
+int rcar_du_get(struct rcar_du_device *rcdu)
+{
+ int ret;
+
+ if (rcdu->use_count)
+ goto done;
+
+ /* Enable clocks before accessing the hardware. */
+ ret = clk_prepare_enable(rcdu->clock);
+ if (ret < 0)
+ return ret;
+
+ /* Enable extended features */
+ rcar_du_write(rcdu, DEFR, DEFR_CODE | DEFR_DEFE);
+ rcar_du_write(rcdu, DEFR2, DEFR2_CODE | DEFR2_DEFE2G);
+ rcar_du_write(rcdu, DEFR3, DEFR3_CODE | DEFR3_DEFE3);
+ rcar_du_write(rcdu, DEFR4, DEFR4_CODE);
+ rcar_du_write(rcdu, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
+
+ /* Use DS1PR and DS2PR to configure planes priorities and connects the
+ * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
+ */
+ rcar_du_write(rcdu, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
+
+done:
+ rcdu->use_count++;
+ return 0;
+}
+
+/*
+ * rcar_du_put - Release a reference to the DU
+ *
+ * Releasing the last reference disables the device clock.
+ *
+ * This function must be called with the DRM mode_config lock held.
+ */
+void rcar_du_put(struct rcar_du_device *rcdu)
+{
+ if (--rcdu->use_count)
+ return;
+
+ clk_disable_unprepare(rcdu->clock);
+}
+
+/* -----------------------------------------------------------------------------
+ * DRM operations
+ */
+
+static int rcar_du_unload(struct drm_device *dev)
+{
+ drm_kms_helper_poll_fini(dev);
+ drm_mode_config_cleanup(dev);
+ drm_vblank_cleanup(dev);
+ drm_irq_uninstall(dev);
+
+ dev->dev_private = NULL;
+
+ return 0;
+}
+
+static int rcar_du_load(struct drm_device *dev, unsigned long flags)
+{
+ struct platform_device *pdev = dev->platformdev;
+ struct rcar_du_platform_data *pdata = pdev->dev.platform_data;
+ struct rcar_du_device *rcdu;
+ struct resource *ioarea;
+ struct resource *mem;
+ int ret;
+
+ if (pdata == NULL) {
+ dev_err(dev->dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
+ if (rcdu == NULL) {
+ dev_err(dev->dev, "failed to allocate private data\n");
+ return -ENOMEM;
+ }
+
+ rcdu->dev = &pdev->dev;
+ rcdu->pdata = pdata;
+ rcdu->ddev = dev;
+ dev->dev_private = rcdu;
+
+ /* I/O resources and clocks */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (mem == NULL) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ return -EINVAL;
+ }
+
+ ioarea = devm_request_mem_region(&pdev->dev, mem->start,
+ resource_size(mem), pdev->name);
+ if (ioarea == NULL) {
+ dev_err(&pdev->dev, "failed to request memory region\n");
+ return -EBUSY;
+ }
+
+ rcdu->mmio = devm_ioremap_nocache(&pdev->dev, ioarea->start,
+ resource_size(ioarea));
+ if (rcdu->mmio == NULL) {
+ dev_err(&pdev->dev, "failed to remap memory resource\n");
+ return -ENOMEM;
+ }
+
+ rcdu->clock = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rcdu->clock)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ return -ENOENT;
+ }
+
+ /* DRM/KMS objects */
+ ret = rcar_du_modeset_init(rcdu);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to initialize DRM/KMS\n");
+ goto done;
+ }
+
+ /* IRQ and vblank handling */
+ ret = drm_vblank_init(dev, (1 << rcdu->num_crtcs) - 1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to initialize vblank\n");
+ goto done;
+ }
+
+ ret = drm_irq_install(dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to install IRQ handler\n");
+ goto done;
+ }
+
+ platform_set_drvdata(pdev, rcdu);
+
+done:
+ if (ret)
+ rcar_du_unload(dev);
+
+ return ret;
+}
+
+static void rcar_du_preclose(struct drm_device *dev, struct drm_file *file)
+{
+ struct rcar_du_device *rcdu = dev->dev_private;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i)
+ rcar_du_crtc_cancel_page_flip(&rcdu->crtcs[i], file);
+}
+
+static irqreturn_t rcar_du_irq(int irq, void *arg)
+{
+ struct drm_device *dev = arg;
+ struct rcar_du_device *rcdu = dev->dev_private;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i)
+ rcar_du_crtc_irq(&rcdu->crtcs[i]);
+
+ return IRQ_HANDLED;
+}
+
+static int rcar_du_enable_vblank(struct drm_device *dev, int crtc)
+{
+ struct rcar_du_device *rcdu = dev->dev_private;
+
+ rcar_du_crtc_enable_vblank(&rcdu->crtcs[crtc], true);
+
+ return 0;
+}
+
+static void rcar_du_disable_vblank(struct drm_device *dev, int crtc)
+{
+ struct rcar_du_device *rcdu = dev->dev_private;
+
+ rcar_du_crtc_enable_vblank(&rcdu->crtcs[crtc], false);
+}
+
+static const struct file_operations rcar_du_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .fasync = drm_fasync,
+ .llseek = no_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver rcar_du_driver = {
+ .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
+ | DRIVER_PRIME,
+ .load = rcar_du_load,
+ .unload = rcar_du_unload,
+ .preclose = rcar_du_preclose,
+ .irq_handler = rcar_du_irq,
+ .get_vblank_counter = drm_vblank_count,
+ .enable_vblank = rcar_du_enable_vblank,
+ .disable_vblank = rcar_du_disable_vblank,
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = drm_gem_cma_dmabuf_import,
+ .gem_prime_export = drm_gem_cma_dmabuf_export,
+ .dumb_create = rcar_du_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_cma_dumb_destroy,
+ .fops = &rcar_du_fops,
+ .name = "rcar-du",
+ .desc = "Renesas R-Car Display Unit",
+ .date = "20130110",
+ .major = 1,
+ .minor = 0,
+};
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+#if CONFIG_PM_SLEEP
+static int rcar_du_pm_suspend(struct device *dev)
+{
+ struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+
+ drm_kms_helper_poll_disable(rcdu->ddev);
+ /* TODO Suspend the CRTC */
+
+ return 0;
+}
+
+static int rcar_du_pm_resume(struct device *dev)
+{
+ struct rcar_du_device *rcdu = dev_get_drvdata(dev);
+
+ /* TODO Resume the CRTC */
+
+ drm_kms_helper_poll_enable(rcdu->ddev);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops rcar_du_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(rcar_du_pm_suspend, rcar_du_pm_resume)
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform driver
+ */
+
+static int rcar_du_probe(struct platform_device *pdev)
+{
+ return drm_platform_init(&rcar_du_driver, pdev);
+}
+
+static int rcar_du_remove(struct platform_device *pdev)
+{
+ drm_platform_exit(&rcar_du_driver, pdev);
+
+ return 0;
+}
+
+static struct platform_driver rcar_du_platform_driver = {
+ .probe = rcar_du_probe,
+ .remove = rcar_du_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rcar-du",
+ .pm = &rcar_du_pm_ops,
+ },
+};
+
+module_platform_driver(rcar_du_platform_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Renesas R-Car Display Unit DRM Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
new file mode 100644
index 000000000000..193cc59d495c
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -0,0 +1,66 @@
+/*
+ * rcar_du_drv.h -- R-Car Display Unit DRM driver
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_DRV_H__
+#define __RCAR_DU_DRV_H__
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/rcar-du.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_plane.h"
+
+struct clk;
+struct device;
+struct drm_device;
+
+struct rcar_du_device {
+ struct device *dev;
+ const struct rcar_du_platform_data *pdata;
+
+ void __iomem *mmio;
+ struct clk *clock;
+ unsigned int use_count;
+
+ struct drm_device *ddev;
+
+ struct rcar_du_crtc crtcs[2];
+ unsigned int used_crtcs;
+ unsigned int num_crtcs;
+
+ struct {
+ struct rcar_du_plane planes[RCAR_DU_NUM_SW_PLANES];
+ unsigned int free;
+ struct mutex lock;
+
+ struct drm_property *alpha;
+ struct drm_property *colorkey;
+ struct drm_property *zpos;
+ } planes;
+};
+
+int rcar_du_get(struct rcar_du_device *rcdu);
+void rcar_du_put(struct rcar_du_device *rcdu);
+
+static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg)
+{
+ return ioread32(rcdu->mmio + reg);
+}
+
+static inline void rcar_du_write(struct rcar_du_device *rcdu, u32 reg, u32 data)
+{
+ iowrite32(data, rcdu->mmio + reg);
+}
+
+#endif /* __RCAR_DU_DRV_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
new file mode 100644
index 000000000000..d30c2e29bee2
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -0,0 +1,265 @@
+/*
+ * rcar_du_kms.c -- R-Car Display Unit Mode Setting
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "rcar_du_crtc.h"
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_lvds.h"
+#include "rcar_du_regs.h"
+#include "rcar_du_vga.h"
+
+/* -----------------------------------------------------------------------------
+ * Format helpers
+ */
+
+static const struct rcar_du_format_info rcar_du_format_infos[] = {
+ {
+ .fourcc = DRM_FORMAT_RGB565,
+ .bpp = 16,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ .fourcc = DRM_FORMAT_ARGB1555,
+ .bpp = 16,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ .fourcc = DRM_FORMAT_XRGB1555,
+ .bpp = 16,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ .fourcc = DRM_FORMAT_XRGB8888,
+ .bpp = 32,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
+ .edf = PnDDCR4_EDF_RGB888,
+ }, {
+ .fourcc = DRM_FORMAT_ARGB8888,
+ .bpp = 32,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP,
+ .edf = PnDDCR4_EDF_ARGB8888,
+ }, {
+ .fourcc = DRM_FORMAT_UYVY,
+ .bpp = 16,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ .fourcc = DRM_FORMAT_YUYV,
+ .bpp = 16,
+ .planes = 1,
+ .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ .fourcc = DRM_FORMAT_NV12,
+ .bpp = 12,
+ .planes = 2,
+ .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ .fourcc = DRM_FORMAT_NV21,
+ .bpp = 12,
+ .planes = 2,
+ .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
+ .edf = PnDDCR4_EDF_NONE,
+ }, {
+ /* In YUV 4:2:2, only NV16 is supported (NV61 isn't) */
+ .fourcc = DRM_FORMAT_NV16,
+ .bpp = 16,
+ .planes = 2,
+ .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
+ .edf = PnDDCR4_EDF_NONE,
+ },
+};
+
+const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) {
+ if (rcar_du_format_infos[i].fourcc == fourcc)
+ return &rcar_du_format_infos[i];
+ }
+
+ return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * Common connector and encoder functions
+ */
+
+struct drm_encoder *
+rcar_du_connector_best_encoder(struct drm_connector *connector)
+{
+ struct rcar_du_connector *rcon = to_rcar_connector(connector);
+
+ return &rcon->encoder->encoder;
+}
+
+void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder)
+{
+}
+
+void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
+
+ rcar_du_crtc_route_output(encoder->crtc, renc->output);
+}
+
+void rcar_du_encoder_mode_commit(struct drm_encoder *encoder)
+{
+}
+
+/* -----------------------------------------------------------------------------
+ * Frame buffer
+ */
+
+int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+ unsigned int align;
+
+ /* The pitch must be aligned to a 16 pixels boundary. */
+ align = 16 * args->bpp / 8;
+ args->pitch = roundup(max(args->pitch, min_pitch), align);
+
+ return drm_gem_cma_dumb_create(file, dev, args);
+}
+
+static struct drm_framebuffer *
+rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ const struct rcar_du_format_info *format;
+ unsigned int align;
+
+ format = rcar_du_format_info(mode_cmd->pixel_format);
+ if (format == NULL) {
+ dev_dbg(dev->dev, "unsupported pixel format %08x\n",
+ mode_cmd->pixel_format);
+ return ERR_PTR(-EINVAL);
+ }
+
+ align = 16 * format->bpp / 8;
+
+ if (mode_cmd->pitches[0] & (align - 1) ||
+ mode_cmd->pitches[0] >= 8192) {
+ dev_dbg(dev->dev, "invalid pitch value %u\n",
+ mode_cmd->pitches[0]);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (format->planes == 2) {
+ if (mode_cmd->pitches[1] != mode_cmd->pitches[0]) {
+ dev_dbg(dev->dev,
+ "luma and chroma pitches do not match\n");
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
+ .fb_create = rcar_du_fb_create,
+};
+
+int rcar_du_modeset_init(struct rcar_du_device *rcdu)
+{
+ struct drm_device *dev = rcdu->ddev;
+ struct drm_encoder *encoder;
+ unsigned int i;
+ int ret;
+
+ drm_mode_config_init(rcdu->ddev);
+
+ rcdu->ddev->mode_config.min_width = 0;
+ rcdu->ddev->mode_config.min_height = 0;
+ rcdu->ddev->mode_config.max_width = 4095;
+ rcdu->ddev->mode_config.max_height = 2047;
+ rcdu->ddev->mode_config.funcs = &rcar_du_mode_config_funcs;
+
+ ret = rcar_du_plane_init(rcdu);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) {
+ ret = rcar_du_crtc_create(rcdu, i);
+ if (ret < 0)
+ return ret;
+ }
+
+ rcdu->used_crtcs = 0;
+ rcdu->num_crtcs = i;
+
+ for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
+ const struct rcar_du_encoder_data *pdata =
+ &rcdu->pdata->encoders[i];
+
+ if (pdata->output >= ARRAY_SIZE(rcdu->crtcs)) {
+ dev_warn(rcdu->dev,
+ "encoder %u references unexisting output %u, skipping\n",
+ i, pdata->output);
+ continue;
+ }
+
+ switch (pdata->encoder) {
+ case RCAR_DU_ENCODER_VGA:
+ rcar_du_vga_init(rcdu, &pdata->u.vga, pdata->output);
+ break;
+
+ case RCAR_DU_ENCODER_LVDS:
+ rcar_du_lvds_init(rcdu, &pdata->u.lvds, pdata->output);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* Set the possible CRTCs and possible clones. All encoders can be
+ * driven by the CRTC associated with the output they're connected to,
+ * as well as by CRTC 0.
+ */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
+
+ encoder->possible_crtcs = (1 << 0) | (1 << renc->output);
+ encoder->possible_clones = 1 << 0;
+ }
+
+ ret = rcar_du_plane_register(rcdu);
+ if (ret < 0)
+ return ret;
+
+ drm_kms_helper_poll_init(rcdu->ddev);
+
+ drm_helper_disable_unused_functions(rcdu->ddev);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.h b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
new file mode 100644
index 000000000000..dba472263486
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.h
@@ -0,0 +1,62 @@
+/*
+ * rcar_du_kms.h -- R-Car Display Unit Mode Setting
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_KMS_H__
+#define __RCAR_DU_KMS_H__
+
+#include <linux/types.h>
+
+#include <drm/drm_crtc.h>
+
+struct rcar_du_device;
+
+struct rcar_du_format_info {
+ u32 fourcc;
+ unsigned int bpp;
+ unsigned int planes;
+ unsigned int pnmr;
+ unsigned int edf;
+};
+
+struct rcar_du_encoder {
+ struct drm_encoder encoder;
+ unsigned int output;
+};
+
+#define to_rcar_encoder(e) \
+ container_of(e, struct rcar_du_encoder, encoder)
+
+struct rcar_du_connector {
+ struct drm_connector connector;
+ struct rcar_du_encoder *encoder;
+};
+
+#define to_rcar_connector(c) \
+ container_of(c, struct rcar_du_connector, connector)
+
+const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc);
+
+struct drm_encoder *
+rcar_du_connector_best_encoder(struct drm_connector *connector);
+void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder);
+void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+void rcar_du_encoder_mode_commit(struct drm_encoder *encoder);
+
+int rcar_du_modeset_init(struct rcar_du_device *rcdu);
+
+int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+
+#endif /* __RCAR_DU_KMS_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvds.c b/drivers/gpu/drm/rcar-du/rcar_du_lvds.c
new file mode 100644
index 000000000000..7aefe7267e1d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvds.c
@@ -0,0 +1,216 @@
+/*
+ * rcar_du_lvds.c -- R-Car Display Unit LVDS Encoder and Connector
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_lvds.h"
+
+struct rcar_du_lvds_connector {
+ struct rcar_du_connector connector;
+
+ const struct rcar_du_panel_data *panel;
+};
+
+#define to_rcar_lvds_connector(c) \
+ container_of(c, struct rcar_du_lvds_connector, connector.connector)
+
+/* -----------------------------------------------------------------------------
+ * Connector
+ */
+
+static int rcar_du_lvds_connector_get_modes(struct drm_connector *connector)
+{
+ struct rcar_du_lvds_connector *lvdscon = to_rcar_lvds_connector(connector);
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_create(connector->dev);
+ if (mode == NULL)
+ return 0;
+
+ mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+ mode->clock = lvdscon->panel->mode.clock;
+ mode->hdisplay = lvdscon->panel->mode.hdisplay;
+ mode->hsync_start = lvdscon->panel->mode.hsync_start;
+ mode->hsync_end = lvdscon->panel->mode.hsync_end;
+ mode->htotal = lvdscon->panel->mode.htotal;
+ mode->vdisplay = lvdscon->panel->mode.vdisplay;
+ mode->vsync_start = lvdscon->panel->mode.vsync_start;
+ mode->vsync_end = lvdscon->panel->mode.vsync_end;
+ mode->vtotal = lvdscon->panel->mode.vtotal;
+ mode->flags = lvdscon->panel->mode.flags;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static int rcar_du_lvds_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+ .get_modes = rcar_du_lvds_connector_get_modes,
+ .mode_valid = rcar_du_lvds_connector_mode_valid,
+ .best_encoder = rcar_du_connector_best_encoder,
+};
+
+static void rcar_du_lvds_connector_destroy(struct drm_connector *connector)
+{
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+rcar_du_lvds_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = rcar_du_lvds_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = rcar_du_lvds_connector_destroy,
+};
+
+static int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
+ struct rcar_du_encoder *renc,
+ const struct rcar_du_panel_data *panel)
+{
+ struct rcar_du_lvds_connector *lvdscon;
+ struct drm_connector *connector;
+ int ret;
+
+ lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL);
+ if (lvdscon == NULL)
+ return -ENOMEM;
+
+ lvdscon->panel = panel;
+
+ connector = &lvdscon->connector.connector;
+ connector->display_info.width_mm = panel->width_mm;
+ connector->display_info.height_mm = panel->height_mm;
+
+ ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
+ DRM_MODE_CONNECTOR_LVDS);
+ if (ret < 0)
+ return ret;
+
+ drm_connector_helper_add(connector, &connector_helper_funcs);
+ ret = drm_sysfs_connector_add(connector);
+ if (ret < 0)
+ return ret;
+
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ drm_object_property_set_value(&connector->base,
+ rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+
+ ret = drm_mode_connector_attach_encoder(connector, &renc->encoder);
+ if (ret < 0)
+ return ret;
+
+ connector->encoder = &renc->encoder;
+ lvdscon->connector.encoder = renc;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
+static void rcar_du_lvds_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool rcar_du_lvds_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ const struct drm_display_mode *panel_mode;
+ struct drm_device *dev = encoder->dev;
+ struct drm_connector *connector;
+ bool found = false;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ dev_dbg(dev->dev, "mode_fixup: no connector found\n");
+ return false;
+ }
+
+ if (list_empty(&connector->modes)) {
+ dev_dbg(dev->dev, "mode_fixup: empty modes list\n");
+ return false;
+ }
+
+ panel_mode = list_first_entry(&connector->modes,
+ struct drm_display_mode, head);
+
+ /* We're not allowed to modify the resolution. */
+ if (mode->hdisplay != panel_mode->hdisplay ||
+ mode->vdisplay != panel_mode->vdisplay)
+ return false;
+
+ /* The flat panel mode is fixed, just copy it to the adjusted mode. */
+ drm_mode_copy(adjusted_mode, panel_mode);
+
+ return true;
+}
+
+static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
+ .dpms = rcar_du_lvds_encoder_dpms,
+ .mode_fixup = rcar_du_lvds_encoder_mode_fixup,
+ .prepare = rcar_du_encoder_mode_prepare,
+ .commit = rcar_du_encoder_mode_commit,
+ .mode_set = rcar_du_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+int rcar_du_lvds_init(struct rcar_du_device *rcdu,
+ const struct rcar_du_encoder_lvds_data *data,
+ unsigned int output)
+{
+ struct rcar_du_encoder *renc;
+ int ret;
+
+ renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
+ if (renc == NULL)
+ return -ENOMEM;
+
+ renc->output = output;
+
+ ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
+ if (ret < 0)
+ return ret;
+
+ drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
+
+ return rcar_du_lvds_connector_init(rcdu, renc, &data->panel);
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvds.h b/drivers/gpu/drm/rcar-du/rcar_du_lvds.h
new file mode 100644
index 000000000000..b47f8328e103
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_lvds.h
@@ -0,0 +1,24 @@
+/*
+ * rcar_du_lvds.h -- R-Car Display Unit LVDS Encoder and Connector
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_LVDS_H__
+#define __RCAR_DU_LVDS_H__
+
+struct rcar_du_device;
+struct rcar_du_encoder_lvds_data;
+
+int rcar_du_lvds_init(struct rcar_du_device *rcdu,
+ const struct rcar_du_encoder_lvds_data *data,
+ unsigned int output);
+
+#endif /* __RCAR_DU_LVDS_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
new file mode 100644
index 000000000000..a65f81ddf51d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -0,0 +1,507 @@
+/*
+ * rcar_du_plane.c -- R-Car Display Unit Planes
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_plane.h"
+#include "rcar_du_regs.h"
+
+#define RCAR_DU_COLORKEY_NONE (0 << 24)
+#define RCAR_DU_COLORKEY_SOURCE (1 << 24)
+#define RCAR_DU_COLORKEY_MASK (1 << 24)
+
+struct rcar_du_kms_plane {
+ struct drm_plane plane;
+ struct rcar_du_plane *hwplane;
+};
+
+static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
+{
+ return container_of(plane, struct rcar_du_kms_plane, plane)->hwplane;
+}
+
+static u32 rcar_du_plane_read(struct rcar_du_device *rcdu,
+ unsigned int index, u32 reg)
+{
+ return rcar_du_read(rcdu, index * PLANE_OFF + reg);
+}
+
+static void rcar_du_plane_write(struct rcar_du_device *rcdu,
+ unsigned int index, u32 reg, u32 data)
+{
+ rcar_du_write(rcdu, index * PLANE_OFF + reg, data);
+}
+
+int rcar_du_plane_reserve(struct rcar_du_plane *plane,
+ const struct rcar_du_format_info *format)
+{
+ struct rcar_du_device *rcdu = plane->dev;
+ unsigned int i;
+ int ret = -EBUSY;
+
+ mutex_lock(&rcdu->planes.lock);
+
+ for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
+ if (!(rcdu->planes.free & (1 << i)))
+ continue;
+
+ if (format->planes == 1 ||
+ rcdu->planes.free & (1 << ((i + 1) % 8)))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(rcdu->planes.planes))
+ goto done;
+
+ rcdu->planes.free &= ~(1 << i);
+ if (format->planes == 2)
+ rcdu->planes.free &= ~(1 << ((i + 1) % 8));
+
+ plane->hwindex = i;
+
+ ret = 0;
+
+done:
+ mutex_unlock(&rcdu->planes.lock);
+ return ret;
+}
+
+void rcar_du_plane_release(struct rcar_du_plane *plane)
+{
+ struct rcar_du_device *rcdu = plane->dev;
+
+ if (plane->hwindex == -1)
+ return;
+
+ mutex_lock(&rcdu->planes.lock);
+ rcdu->planes.free |= 1 << plane->hwindex;
+ if (plane->format->planes == 2)
+ rcdu->planes.free |= 1 << ((plane->hwindex + 1) % 8);
+ mutex_unlock(&rcdu->planes.lock);
+
+ plane->hwindex = -1;
+}
+
+void rcar_du_plane_update_base(struct rcar_du_plane *plane)
+{
+ struct rcar_du_device *rcdu = plane->dev;
+ unsigned int index = plane->hwindex;
+
+ /* According to the datasheet the Y position is expressed in raster line
+ * units. However, 32bpp formats seem to require a doubled Y position
+ * value. Similarly, for the second plane, NV12 and NV21 formats seem to
+ * require a halved Y position value.
+ */
+ rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x);
+ rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y *
+ (plane->format->bpp == 32 ? 2 : 1));
+ rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[0]);
+
+ if (plane->format->planes == 2) {
+ index = (index + 1) % 8;
+
+ rcar_du_plane_write(rcdu, index, PnSPXR, plane->src_x);
+ rcar_du_plane_write(rcdu, index, PnSPYR, plane->src_y *
+ (plane->format->bpp == 16 ? 2 : 1) / 2);
+ rcar_du_plane_write(rcdu, index, PnDSA0R, plane->dma[1]);
+ }
+}
+
+void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
+ struct drm_framebuffer *fb)
+{
+ struct drm_gem_cma_object *gem;
+
+ gem = drm_fb_cma_get_gem_obj(fb, 0);
+ plane->dma[0] = gem->paddr + fb->offsets[0];
+
+ if (plane->format->planes == 2) {
+ gem = drm_fb_cma_get_gem_obj(fb, 1);
+ plane->dma[1] = gem->paddr + fb->offsets[1];
+ }
+}
+
+static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
+ unsigned int index)
+{
+ struct rcar_du_device *rcdu = plane->dev;
+ u32 colorkey;
+ u32 pnmr;
+
+ /* The PnALPHAR register controls alpha-blending in 16bpp formats
+ * (ARGB1555 and XRGB1555).
+ *
+ * For ARGB, set the alpha value to 0, and enable alpha-blending when
+ * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255.
+ *
+ * For XRGB, set the alpha value to the plane-wide alpha value and
+ * enable alpha-blending regardless of the X bit value.
+ */
+ if (plane->format->fourcc != DRM_FORMAT_XRGB1555)
+ rcar_du_plane_write(rcdu, index, PnALPHAR, PnALPHAR_ABIT_0);
+ else
+ rcar_du_plane_write(rcdu, index, PnALPHAR,
+ PnALPHAR_ABIT_X | plane->alpha);
+
+ pnmr = PnMR_BM_MD | plane->format->pnmr;
+
+ /* Disable color keying when requested. YUV formats have the
+ * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying
+ * automatically.
+ */
+ if ((plane->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE)
+ pnmr |= PnMR_SPIM_TP_OFF;
+
+ /* For packed YUV formats we need to select the U/V order. */
+ if (plane->format->fourcc == DRM_FORMAT_YUYV)
+ pnmr |= PnMR_YCDF_YUYV;
+
+ rcar_du_plane_write(rcdu, index, PnMR, pnmr);
+
+ switch (plane->format->fourcc) {
+ case DRM_FORMAT_RGB565:
+ colorkey = ((plane->colorkey & 0xf80000) >> 8)
+ | ((plane->colorkey & 0x00fc00) >> 5)
+ | ((plane->colorkey & 0x0000f8) >> 3);
+ rcar_du_plane_write(rcdu, index, PnTC2R, colorkey);
+ break;
+
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_XRGB1555:
+ colorkey = ((plane->colorkey & 0xf80000) >> 9)
+ | ((plane->colorkey & 0x00f800) >> 6)
+ | ((plane->colorkey & 0x0000f8) >> 3);
+ rcar_du_plane_write(rcdu, index, PnTC2R, colorkey);
+ break;
+
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_ARGB8888:
+ rcar_du_plane_write(rcdu, index, PnTC3R,
+ PnTC3R_CODE | (plane->colorkey & 0xffffff));
+ break;
+ }
+}
+
+static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
+ unsigned int index)
+{
+ struct rcar_du_device *rcdu = plane->dev;
+ u32 ddcr2 = PnDDCR2_CODE;
+ u32 ddcr4;
+ u32 mwr;
+
+ /* Data format
+ *
+ * The data format is selected by the DDDF field in PnMR and the EDF
+ * field in DDCR4.
+ */
+ ddcr4 = rcar_du_plane_read(rcdu, index, PnDDCR4);
+ ddcr4 &= ~PnDDCR4_EDF_MASK;
+ ddcr4 |= plane->format->edf | PnDDCR4_CODE;
+
+ rcar_du_plane_setup_mode(plane, index);
+
+ if (plane->format->planes == 2) {
+ if (plane->hwindex != index) {
+ if (plane->format->fourcc == DRM_FORMAT_NV12 ||
+ plane->format->fourcc == DRM_FORMAT_NV21)
+ ddcr2 |= PnDDCR2_Y420;
+
+ if (plane->format->fourcc == DRM_FORMAT_NV21)
+ ddcr2 |= PnDDCR2_NV21;
+
+ ddcr2 |= PnDDCR2_DIVU;
+ } else {
+ ddcr2 |= PnDDCR2_DIVY;
+ }
+ }
+
+ rcar_du_plane_write(rcdu, index, PnDDCR2, ddcr2);
+ rcar_du_plane_write(rcdu, index, PnDDCR4, ddcr4);
+
+ /* Memory pitch (expressed in pixels) */
+ if (plane->format->planes == 2)
+ mwr = plane->pitch;
+ else
+ mwr = plane->pitch * 8 / plane->format->bpp;
+
+ rcar_du_plane_write(rcdu, index, PnMWR, mwr);
+
+ /* Destination position and size */
+ rcar_du_plane_write(rcdu, index, PnDSXR, plane->width);
+ rcar_du_plane_write(rcdu, index, PnDSYR, plane->height);
+ rcar_du_plane_write(rcdu, index, PnDPXR, plane->dst_x);
+ rcar_du_plane_write(rcdu, index, PnDPYR, plane->dst_y);
+
+ /* Wrap-around and blinking, disabled */
+ rcar_du_plane_write(rcdu, index, PnWASPR, 0);
+ rcar_du_plane_write(rcdu, index, PnWAMWR, 4095);
+ rcar_du_plane_write(rcdu, index, PnBTR, 0);
+ rcar_du_plane_write(rcdu, index, PnMLR, 0);
+}
+
+void rcar_du_plane_setup(struct rcar_du_plane *plane)
+{
+ __rcar_du_plane_setup(plane, plane->hwindex);
+ if (plane->format->planes == 2)
+ __rcar_du_plane_setup(plane, (plane->hwindex + 1) % 8);
+
+ rcar_du_plane_update_base(plane);
+}
+
+static int
+rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h)
+{
+ struct rcar_du_plane *rplane = to_rcar_plane(plane);
+ struct rcar_du_device *rcdu = plane->dev->dev_private;
+ const struct rcar_du_format_info *format;
+ unsigned int nplanes;
+ int ret;
+
+ format = rcar_du_format_info(fb->pixel_format);
+ if (format == NULL) {
+ dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
+ fb->pixel_format);
+ return -EINVAL;
+ }
+
+ if (src_w >> 16 != crtc_w || src_h >> 16 != crtc_h) {
+ dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
+ return -EINVAL;
+ }
+
+ nplanes = rplane->format ? rplane->format->planes : 0;
+
+ /* Reallocate hardware planes if the number of required planes has
+ * changed.
+ */
+ if (format->planes != nplanes) {
+ rcar_du_plane_release(rplane);
+ ret = rcar_du_plane_reserve(rplane, format);
+ if (ret < 0)
+ return ret;
+ }
+
+ rplane->crtc = crtc;
+ rplane->format = format;
+ rplane->pitch = fb->pitches[0];
+
+ rplane->src_x = src_x >> 16;
+ rplane->src_y = src_y >> 16;
+ rplane->dst_x = crtc_x;
+ rplane->dst_y = crtc_y;
+ rplane->width = crtc_w;
+ rplane->height = crtc_h;
+
+ rcar_du_plane_compute_base(rplane, fb);
+ rcar_du_plane_setup(rplane);
+
+ mutex_lock(&rcdu->planes.lock);
+ rplane->enabled = true;
+ rcar_du_crtc_update_planes(rplane->crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
+ return 0;
+}
+
+static int rcar_du_plane_disable(struct drm_plane *plane)
+{
+ struct rcar_du_device *rcdu = plane->dev->dev_private;
+ struct rcar_du_plane *rplane = to_rcar_plane(plane);
+
+ if (!rplane->enabled)
+ return 0;
+
+ mutex_lock(&rcdu->planes.lock);
+ rplane->enabled = false;
+ rcar_du_crtc_update_planes(rplane->crtc);
+ mutex_unlock(&rcdu->planes.lock);
+
+ rcar_du_plane_release(rplane);
+
+ rplane->crtc = NULL;
+ rplane->format = NULL;
+
+ return 0;
+}
+
+/* Both the .set_property and the .update_plane operations are called with the
+ * mode_config lock held. There is this no need to explicitly protect access to
+ * the alpha and colorkey fields and the mode register.
+ */
+static void rcar_du_plane_set_alpha(struct rcar_du_plane *plane, u32 alpha)
+{
+ if (plane->alpha == alpha)
+ return;
+
+ plane->alpha = alpha;
+ if (!plane->enabled || plane->format->fourcc != DRM_FORMAT_XRGB1555)
+ return;
+
+ rcar_du_plane_setup_mode(plane, plane->hwindex);
+}
+
+static void rcar_du_plane_set_colorkey(struct rcar_du_plane *plane,
+ u32 colorkey)
+{
+ if (plane->colorkey == colorkey)
+ return;
+
+ plane->colorkey = colorkey;
+ if (!plane->enabled)
+ return;
+
+ rcar_du_plane_setup_mode(plane, plane->hwindex);
+}
+
+static void rcar_du_plane_set_zpos(struct rcar_du_plane *plane,
+ unsigned int zpos)
+{
+ struct rcar_du_device *rcdu = plane->dev;
+
+ mutex_lock(&rcdu->planes.lock);
+ if (plane->zpos == zpos)
+ goto done;
+
+ plane->zpos = zpos;
+ if (!plane->enabled)
+ goto done;
+
+ rcar_du_crtc_update_planes(plane->crtc);
+
+done:
+ mutex_unlock(&rcdu->planes.lock);
+}
+
+static int rcar_du_plane_set_property(struct drm_plane *plane,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct rcar_du_device *rcdu = plane->dev->dev_private;
+ struct rcar_du_plane *rplane = to_rcar_plane(plane);
+
+ if (property == rcdu->planes.alpha)
+ rcar_du_plane_set_alpha(rplane, value);
+ else if (property == rcdu->planes.colorkey)
+ rcar_du_plane_set_colorkey(rplane, value);
+ else if (property == rcdu->planes.zpos)
+ rcar_du_plane_set_zpos(rplane, value);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct drm_plane_funcs rcar_du_plane_funcs = {
+ .update_plane = rcar_du_plane_update,
+ .disable_plane = rcar_du_plane_disable,
+ .set_property = rcar_du_plane_set_property,
+ .destroy = drm_plane_cleanup,
+};
+
+static const uint32_t formats[] = {
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_NV12,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV16,
+};
+
+int rcar_du_plane_init(struct rcar_du_device *rcdu)
+{
+ unsigned int i;
+
+ mutex_init(&rcdu->planes.lock);
+ rcdu->planes.free = 0xff;
+
+ rcdu->planes.alpha =
+ drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
+ if (rcdu->planes.alpha == NULL)
+ return -ENOMEM;
+
+ /* The color key is expressed as an RGB888 triplet stored in a 32-bit
+ * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
+ * or enable source color keying (1).
+ */
+ rcdu->planes.colorkey =
+ drm_property_create_range(rcdu->ddev, 0, "colorkey",
+ 0, 0x01ffffff);
+ if (rcdu->planes.colorkey == NULL)
+ return -ENOMEM;
+
+ rcdu->planes.zpos =
+ drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
+ if (rcdu->planes.zpos == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(rcdu->planes.planes); ++i) {
+ struct rcar_du_plane *plane = &rcdu->planes.planes[i];
+
+ plane->dev = rcdu;
+ plane->hwindex = -1;
+ plane->alpha = 255;
+ plane->colorkey = RCAR_DU_COLORKEY_NONE;
+ plane->zpos = 0;
+ }
+
+ return 0;
+}
+
+int rcar_du_plane_register(struct rcar_du_device *rcdu)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
+ struct rcar_du_kms_plane *plane;
+
+ plane = devm_kzalloc(rcdu->dev, sizeof(*plane), GFP_KERNEL);
+ if (plane == NULL)
+ return -ENOMEM;
+
+ plane->hwplane = &rcdu->planes.planes[i + 2];
+ plane->hwplane->zpos = 1;
+
+ ret = drm_plane_init(rcdu->ddev, &plane->plane,
+ (1 << rcdu->num_crtcs) - 1,
+ &rcar_du_plane_funcs, formats,
+ ARRAY_SIZE(formats), false);
+ if (ret < 0)
+ return ret;
+
+ drm_object_attach_property(&plane->plane.base,
+ rcdu->planes.alpha, 255);
+ drm_object_attach_property(&plane->plane.base,
+ rcdu->planes.colorkey,
+ RCAR_DU_COLORKEY_NONE);
+ drm_object_attach_property(&plane->plane.base,
+ rcdu->planes.zpos, 1);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h
new file mode 100644
index 000000000000..5397dba2fe57
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h
@@ -0,0 +1,67 @@
+/*
+ * rcar_du_plane.h -- R-Car Display Unit Planes
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_PLANE_H__
+#define __RCAR_DU_PLANE_H__
+
+struct drm_crtc;
+struct drm_framebuffer;
+struct rcar_du_device;
+struct rcar_du_format_info;
+
+/* The RCAR DU has 8 hardware planes, shared between KMS planes and CRTCs. As
+ * using KMS planes requires at least one of the CRTCs being enabled, no more
+ * than 7 KMS planes can be available. We thus create 7 KMS planes and
+ * 9 software planes (one for each KMS planes and one for each CRTC).
+ */
+
+#define RCAR_DU_NUM_KMS_PLANES 7
+#define RCAR_DU_NUM_HW_PLANES 8
+#define RCAR_DU_NUM_SW_PLANES 9
+
+struct rcar_du_plane {
+ struct rcar_du_device *dev;
+ struct drm_crtc *crtc;
+
+ bool enabled;
+
+ int hwindex; /* 0-based, -1 means unused */
+ unsigned int alpha;
+ unsigned int colorkey;
+ unsigned int zpos;
+
+ const struct rcar_du_format_info *format;
+
+ unsigned long dma[2];
+ unsigned int pitch;
+
+ unsigned int width;
+ unsigned int height;
+
+ unsigned int src_x;
+ unsigned int src_y;
+ unsigned int dst_x;
+ unsigned int dst_y;
+};
+
+int rcar_du_plane_init(struct rcar_du_device *rcdu);
+int rcar_du_plane_register(struct rcar_du_device *rcdu);
+void rcar_du_plane_setup(struct rcar_du_plane *plane);
+void rcar_du_plane_update_base(struct rcar_du_plane *plane);
+void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
+ struct drm_framebuffer *fb);
+int rcar_du_plane_reserve(struct rcar_du_plane *plane,
+ const struct rcar_du_format_info *format);
+void rcar_du_plane_release(struct rcar_du_plane *plane);
+
+#endif /* __RCAR_DU_PLANE_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
new file mode 100644
index 000000000000..69f21f19b51c
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -0,0 +1,445 @@
+/*
+ * rcar_du_regs.h -- R-Car Display Unit Registers Definitions
+ *
+ * Copyright (C) 2013 Renesas Electronics Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef __RCAR_DU_REGS_H__
+#define __RCAR_DU_REGS_H__
+
+#define DISP2_REG_OFFSET 0x30000
+
+/* -----------------------------------------------------------------------------
+ * Display Control Registers
+ */
+
+#define DSYSR 0x00000 /* display 1 */
+#define D2SYSR 0x30000 /* display 2 */
+#define DSYSR_ILTS (1 << 29)
+#define DSYSR_DSEC (1 << 20)
+#define DSYSR_IUPD (1 << 16)
+#define DSYSR_DRES (1 << 9)
+#define DSYSR_DEN (1 << 8)
+#define DSYSR_TVM_MASTER (0 << 6)
+#define DSYSR_TVM_SWITCH (1 << 6)
+#define DSYSR_TVM_TVSYNC (2 << 6)
+#define DSYSR_TVM_MASK (3 << 6)
+#define DSYSR_SCM_INT_NONE (0 << 4)
+#define DSYSR_SCM_INT_SYNC (2 << 4)
+#define DSYSR_SCM_INT_VIDEO (3 << 4)
+
+#define DSMR 0x00004
+#define D2SMR 0x30004
+#define DSMR_VSPM (1 << 28)
+#define DSMR_ODPM (1 << 27)
+#define DSMR_DIPM_DISP (0 << 25)
+#define DSMR_DIPM_CSYNC (1 << 25)
+#define DSMR_DIPM_DE (3 << 25)
+#define DSMR_DIPM_MASK (3 << 25)
+#define DSMR_CSPM (1 << 24)
+#define DSMR_DIL (1 << 19)
+#define DSMR_VSL (1 << 18)
+#define DSMR_HSL (1 << 17)
+#define DSMR_DDIS (1 << 16)
+#define DSMR_CDEL (1 << 15)
+#define DSMR_CDEM_CDE (0 << 13)
+#define DSMR_CDEM_LOW (2 << 13)
+#define DSMR_CDEM_HIGH (3 << 13)
+#define DSMR_CDEM_MASK (3 << 13)
+#define DSMR_CDED (1 << 12)
+#define DSMR_ODEV (1 << 8)
+#define DSMR_CSY_VH_OR (0 << 6)
+#define DSMR_CSY_333 (2 << 6)
+#define DSMR_CSY_222 (3 << 6)
+#define DSMR_CSY_MASK (3 << 6)
+
+#define DSSR 0x00008
+#define D2SSR 0x30008
+#define DSSR_VC1FB_DSA0 (0 << 30)
+#define DSSR_VC1FB_DSA1 (1 << 30)
+#define DSSR_VC1FB_DSA2 (2 << 30)
+#define DSSR_VC1FB_INIT (3 << 30)
+#define DSSR_VC1FB_MASK (3 << 30)
+#define DSSR_VC0FB_DSA0 (0 << 28)
+#define DSSR_VC0FB_DSA1 (1 << 28)
+#define DSSR_VC0FB_DSA2 (2 << 28)
+#define DSSR_VC0FB_INIT (3 << 28)
+#define DSSR_VC0FB_MASK (3 << 28)
+#define DSSR_DFB(n) (1 << ((n)+15))
+#define DSSR_TVR (1 << 15)
+#define DSSR_FRM (1 << 14)
+#define DSSR_VBK (1 << 11)
+#define DSSR_RINT (1 << 9)
+#define DSSR_HBK (1 << 8)
+#define DSSR_ADC(n) (1 << ((n)-1))
+
+#define DSRCR 0x0000c
+#define D2SRCR 0x3000c
+#define DSRCR_TVCL (1 << 15)
+#define DSRCR_FRCL (1 << 14)
+#define DSRCR_VBCL (1 << 11)
+#define DSRCR_RICL (1 << 9)
+#define DSRCR_HBCL (1 << 8)
+#define DSRCR_ADCL(n) (1 << ((n)-1))
+#define DSRCR_MASK 0x0000cbff
+
+#define DIER 0x00010
+#define D2IER 0x30010
+#define DIER_TVE (1 << 15)
+#define DIER_FRE (1 << 14)
+#define DIER_VBE (1 << 11)
+#define DIER_RIE (1 << 9)
+#define DIER_HBE (1 << 8)
+#define DIER_ADCE(n) (1 << ((n)-1))
+
+#define CPCR 0x00014
+#define CPCR_CP4CE (1 << 19)
+#define CPCR_CP3CE (1 << 18)
+#define CPCR_CP2CE (1 << 17)
+#define CPCR_CP1CE (1 << 16)
+
+#define DPPR 0x00018
+#define DPPR_DPE(n) (1 << ((n)*4-1))
+#define DPPR_DPS(n, p) (((p)-1) << DPPR_DPS_SHIFT(n))
+#define DPPR_DPS_SHIFT(n) (((n)-1)*4)
+#define DPPR_BPP16 (DPPR_DPE(8) | DPPR_DPS(8, 1)) /* plane1 */
+#define DPPR_BPP32_P1 (DPPR_DPE(7) | DPPR_DPS(7, 1))
+#define DPPR_BPP32_P2 (DPPR_DPE(8) | DPPR_DPS(8, 2))
+#define DPPR_BPP32 (DPPR_BPP32_P1 | DPPR_BPP32_P2) /* plane1 & 2 */
+
+#define DEFR 0x00020
+#define D2EFR 0x30020
+#define DEFR_CODE (0x7773 << 16)
+#define DEFR_EXSL (1 << 12)
+#define DEFR_EXVL (1 << 11)
+#define DEFR_EXUP (1 << 5)
+#define DEFR_VCUP (1 << 4)
+#define DEFR_DEFE (1 << 0)
+
+#define DAPCR 0x00024
+#define DAPCR_CODE (0x7773 << 16)
+#define DAPCR_AP2E (1 << 4)
+#define DAPCR_AP1E (1 << 0)
+
+#define DCPCR 0x00028
+#define DCPCR_CODE (0x7773 << 16)
+#define DCPCR_CA2B (1 << 13)
+#define DCPCR_CD2F (1 << 12)
+#define DCPCR_DC2E (1 << 8)
+#define DCPCR_CAB (1 << 5)
+#define DCPCR_CDF (1 << 4)
+#define DCPCR_DCE (1 << 0)
+
+#define DEFR2 0x00034
+#define D2EFR2 0x30034
+#define DEFR2_CODE (0x7775 << 16)
+#define DEFR2_DEFE2G (1 << 0)
+
+#define DEFR3 0x00038
+#define D2EFR3 0x30038
+#define DEFR3_CODE (0x7776 << 16)
+#define DEFR3_EVDA (1 << 14)
+#define DEFR3_EVDM_1 (1 << 12)
+#define DEFR3_EVDM_2 (2 << 12)
+#define DEFR3_EVDM_3 (3 << 12)
+#define DEFR3_VMSM2_EMA (1 << 6)
+#define DEFR3_VMSM1_ENA (1 << 4)
+#define DEFR3_DEFE3 (1 << 0)
+
+#define DEFR4 0x0003c
+#define D2EFR4 0x3003c
+#define DEFR4_CODE (0x7777 << 16)
+#define DEFR4_LRUO (1 << 5)
+#define DEFR4_SPCE (1 << 4)
+
+#define DVCSR 0x000d0
+#define DVCSR_VCnFB2_DSA0(n) (0 << ((n)*2+16))
+#define DVCSR_VCnFB2_DSA1(n) (1 << ((n)*2+16))
+#define DVCSR_VCnFB2_DSA2(n) (2 << ((n)*2+16))
+#define DVCSR_VCnFB2_INIT(n) (3 << ((n)*2+16))
+#define DVCSR_VCnFB2_MASK(n) (3 << ((n)*2+16))
+#define DVCSR_VCnFB_DSA0(n) (0 << ((n)*2))
+#define DVCSR_VCnFB_DSA1(n) (1 << ((n)*2))
+#define DVCSR_VCnFB_DSA2(n) (2 << ((n)*2))
+#define DVCSR_VCnFB_INIT(n) (3 << ((n)*2))
+#define DVCSR_VCnFB_MASK(n) (3 << ((n)*2))
+
+#define DEFR5 0x000e0
+#define DEFR5_CODE (0x66 << 24)
+#define DEFR5_YCRGB2_DIS (0 << 14)
+#define DEFR5_YCRGB2_PRI1 (1 << 14)
+#define DEFR5_YCRGB2_PRI2 (2 << 14)
+#define DEFR5_YCRGB2_PRI3 (3 << 14)
+#define DEFR5_YCRGB2_MASK (3 << 14)
+#define DEFR5_YCRGB1_DIS (0 << 12)
+#define DEFR5_YCRGB1_PRI1 (1 << 12)
+#define DEFR5_YCRGB1_PRI2 (2 << 12)
+#define DEFR5_YCRGB1_PRI3 (3 << 12)
+#define DEFR5_YCRGB1_MASK (3 << 12)
+#define DEFR5_DEFE5 (1 << 0)
+
+#define DDLTR 0x000e4
+#define DDLTR_CODE (0x7766 << 16)
+#define DDLTR_DLAR2 (1 << 6)
+#define DDLTR_DLAY2 (1 << 5)
+#define DDLTR_DLAY1 (1 << 1)
+
+#define DEFR6 0x000e8
+#define DEFR6_CODE (0x7778 << 16)
+#define DEFR6_ODPM22_D2SMR (0 << 10)
+#define DEFR6_ODPM22_DISP (2 << 10)
+#define DEFR6_ODPM22_CDE (3 << 10)
+#define DEFR6_ODPM22_MASK (3 << 10)
+#define DEFR6_ODPM12_DSMR (0 << 8)
+#define DEFR6_ODPM12_DISP (2 << 8)
+#define DEFR6_ODPM12_CDE (3 << 8)
+#define DEFR6_ODPM12_MASK (3 << 8)
+#define DEFR6_TCNE2 (1 << 6)
+#define DEFR6_MLOS1 (1 << 2)
+#define DEFR6_DEFAULT (DEFR6_CODE | DEFR6_TCNE2)
+
+/* -----------------------------------------------------------------------------
+ * Display Timing Generation Registers
+ */
+
+#define HDSR 0x00040
+#define HDER 0x00044
+#define VDSR 0x00048
+#define VDER 0x0004c
+#define HCR 0x00050
+#define HSWR 0x00054
+#define VCR 0x00058
+#define VSPR 0x0005c
+#define EQWR 0x00060
+#define SPWR 0x00064
+#define CLAMPSR 0x00070
+#define CLAMPWR 0x00074
+#define DESR 0x00078
+#define DEWR 0x0007c
+
+/* -----------------------------------------------------------------------------
+ * Display Attribute Registers
+ */
+
+#define CP1TR 0x00080
+#define CP2TR 0x00084
+#define CP3TR 0x00088
+#define CP4TR 0x0008c
+
+#define DOOR 0x00090
+#define DOOR_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2))
+#define CDER 0x00094
+#define CDER_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2))
+#define BPOR 0x00098
+#define BPOR_RGB(r, g, b) (((r) << 18) | ((g) << 10) | ((b) << 2))
+
+#define RINTOFSR 0x0009c
+
+#define DSHPR 0x000c8
+#define DSHPR_CODE (0x7776 << 16)
+#define DSHPR_PRIH (0xa << 4)
+#define DSHPR_PRIL_BPP16 (0x8 << 0)
+#define DSHPR_PRIL_BPP32 (0x9 << 0)
+
+/* -----------------------------------------------------------------------------
+ * Display Plane Registers
+ */
+
+#define PLANE_OFF 0x00100
+
+#define PnMR 0x00100 /* plane 1 */
+#define PnMR_VISL_VIN0 (0 << 26) /* use Video Input 0 */
+#define PnMR_VISL_VIN1 (1 << 26) /* use Video Input 1 */
+#define PnMR_VISL_VIN2 (2 << 26) /* use Video Input 2 */
+#define PnMR_VISL_VIN3 (3 << 26) /* use Video Input 3 */
+#define PnMR_YCDF_YUYV (1 << 20) /* YUYV format */
+#define PnMR_TC_R (0 << 17) /* Tranparent color is PnTC1R */
+#define PnMR_TC_CP (1 << 17) /* Tranparent color is color palette */
+#define PnMR_WAE (1 << 16) /* Wrap around Enable */
+#define PnMR_SPIM_TP (0 << 12) /* Transparent Color */
+#define PnMR_SPIM_ALP (1 << 12) /* Alpha Blending */
+#define PnMR_SPIM_EOR (2 << 12) /* EOR */
+#define PnMR_SPIM_TP_OFF (1 << 14) /* No Transparent Color */
+#define PnMR_CPSL_CP1 (0 << 8) /* Color Palette selected 1 */
+#define PnMR_CPSL_CP2 (1 << 8) /* Color Palette selected 2 */
+#define PnMR_CPSL_CP3 (2 << 8) /* Color Palette selected 3 */
+#define PnMR_CPSL_CP4 (3 << 8) /* Color Palette selected 4 */
+#define PnMR_DC (1 << 7) /* Display Area Change */
+#define PnMR_BM_MD (0 << 4) /* Manual Display Change Mode */
+#define PnMR_BM_AR (1 << 4) /* Auto Rendering Mode */
+#define PnMR_BM_AD (2 << 4) /* Auto Display Change Mode */
+#define PnMR_BM_VC (3 << 4) /* Video Capture Mode */
+#define PnMR_DDDF_8BPP (0 << 0) /* 8bit */
+#define PnMR_DDDF_16BPP (1 << 0) /* 16bit or 32bit */
+#define PnMR_DDDF_ARGB (2 << 0) /* ARGB */
+#define PnMR_DDDF_YC (3 << 0) /* YC */
+#define PnMR_DDDF_MASK (3 << 0)
+
+#define PnMWR 0x00104
+
+#define PnALPHAR 0x00108
+#define PnALPHAR_ABIT_1 (0 << 12)
+#define PnALPHAR_ABIT_0 (1 << 12)
+#define PnALPHAR_ABIT_X (2 << 12)
+
+#define PnDSXR 0x00110
+#define PnDSYR 0x00114
+#define PnDPXR 0x00118
+#define PnDPYR 0x0011c
+
+#define PnDSA0R 0x00120
+#define PnDSA1R 0x00124
+#define PnDSA2R 0x00128
+#define PnDSA_MASK 0xfffffff0
+
+#define PnSPXR 0x00130
+#define PnSPYR 0x00134
+#define PnWASPR 0x00138
+#define PnWAMWR 0x0013c
+
+#define PnBTR 0x00140
+
+#define PnTC1R 0x00144
+#define PnTC2R 0x00148
+#define PnTC3R 0x0014c
+#define PnTC3R_CODE (0x66 << 24)
+
+#define PnMLR 0x00150
+
+#define PnSWAPR 0x00180
+#define PnSWAPR_DIGN (1 << 4)
+#define PnSWAPR_SPQW (1 << 3)
+#define PnSWAPR_SPLW (1 << 2)
+#define PnSWAPR_SPWD (1 << 1)
+#define PnSWAPR_SPBY (1 << 0)
+
+#define PnDDCR 0x00184
+#define PnDDCR_CODE (0x7775 << 16)
+#define PnDDCR_LRGB1 (1 << 11)
+#define PnDDCR_LRGB0 (1 << 10)
+
+#define PnDDCR2 0x00188
+#define PnDDCR2_CODE (0x7776 << 16)
+#define PnDDCR2_NV21 (1 << 5)
+#define PnDDCR2_Y420 (1 << 4)
+#define PnDDCR2_DIVU (1 << 1)
+#define PnDDCR2_DIVY (1 << 0)
+
+#define PnDDCR4 0x00190
+#define PnDDCR4_CODE (0x7766 << 16)
+#define PnDDCR4_SDFS_RGB (0 << 4)
+#define PnDDCR4_SDFS_YC (5 << 4)
+#define PnDDCR4_SDFS_MASK (7 << 4)
+#define PnDDCR4_EDF_NONE (0 << 0)
+#define PnDDCR4_EDF_ARGB8888 (1 << 0)
+#define PnDDCR4_EDF_RGB888 (2 << 0)
+#define PnDDCR4_EDF_RGB666 (3 << 0)
+#define PnDDCR4_EDF_MASK (7 << 0)
+
+#define APnMR 0x0a100
+#define APnMR_WAE (1 << 16) /* Wrap around Enable */
+#define APnMR_DC (1 << 7) /* Display Area Change */
+#define APnMR_BM_MD (0 << 4) /* Manual Display Change Mode */
+#define APnMR_BM_AD (2 << 4) /* Auto Display Change Mode */
+
+#define APnMWR 0x0a104
+#define APnDSA0R 0x0a120
+#define APnDSA1R 0x0a124
+#define APnDSA2R 0x0a128
+#define APnMLR 0x0a150
+
+/* -----------------------------------------------------------------------------
+ * Display Capture Registers
+ */
+
+#define DCMWR 0x0c104
+#define DC2MWR 0x0c204
+#define DCSAR 0x0c120
+#define DC2SAR 0x0c220
+#define DCMLR 0x0c150
+#define DC2MLR 0x0c250
+
+/* -----------------------------------------------------------------------------
+ * Color Palette Registers
+ */
+
+#define CP1_000R 0x01000
+#define CP1_255R 0x013fc
+#define CP2_000R 0x02000
+#define CP2_255R 0x023fc
+#define CP3_000R 0x03000
+#define CP3_255R 0x033fc
+#define CP4_000R 0x04000
+#define CP4_255R 0x043fc
+
+/* -----------------------------------------------------------------------------
+ * External Synchronization Control Registers
+ */
+
+#define ESCR 0x10000
+#define ESCR2 0x31000
+#define ESCR_DCLKOINV (1 << 25)
+#define ESCR_DCLKSEL_DCLKIN (0 << 20)
+#define ESCR_DCLKSEL_CLKS (1 << 20)
+#define ESCR_DCLKSEL_MASK (1 << 20)
+#define ESCR_DCLKDIS (1 << 16)
+#define ESCR_SYNCSEL_OFF (0 << 8)
+#define ESCR_SYNCSEL_EXVSYNC (2 << 8)
+#define ESCR_SYNCSEL_EXHSYNC (3 << 8)
+#define ESCR_FRQSEL_MASK (0x3f << 0)
+
+#define OTAR 0x10004
+#define OTAR2 0x31004
+
+/* -----------------------------------------------------------------------------
+ * Dual Display Output Control Registers
+ */
+
+#define DORCR 0x11000
+#define DORCR_PG2T (1 << 30)
+#define DORCR_DK2S (1 << 28)
+#define DORCR_PG2D_DS1 (0 << 24)
+#define DORCR_PG2D_DS2 (1 << 24)
+#define DORCR_PG2D_FIX0 (2 << 24)
+#define DORCR_PG2D_DOOR (3 << 24)
+#define DORCR_PG2D_MASK (3 << 24)
+#define DORCR_DR1D (1 << 21)
+#define DORCR_PG1D_DS1 (0 << 16)
+#define DORCR_PG1D_DS2 (1 << 16)
+#define DORCR_PG1D_FIX0 (2 << 16)
+#define DORCR_PG1D_DOOR (3 << 16)
+#define DORCR_PG1D_MASK (3 << 16)
+#define DORCR_RGPV (1 << 4)
+#define DORCR_DPRS (1 << 0)
+
+#define DPTSR 0x11004
+#define DPTSR_PnDK(n) (1 << ((n) + 16))
+#define DPTSR_PnTS(n) (1 << (n))
+
+#define DAPTSR 0x11008
+#define DAPTSR_APnDK(n) (1 << ((n) + 16))
+#define DAPTSR_APnTS(n) (1 << (n))
+
+#define DS1PR 0x11020
+#define DS2PR 0x11024
+
+/* -----------------------------------------------------------------------------
+ * YC-RGB Conversion Coefficient Registers
+ */
+
+#define YNCR 0x11080
+#define YNOR 0x11084
+#define CRNOR 0x11088
+#define CBNOR 0x1108c
+#define RCRCR 0x11090
+#define GCRCR 0x11094
+#define GCBCR 0x11098
+#define BCBCR 0x1109c
+
+#endif /* __RCAR_DU_REGS_H__ */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vga.c b/drivers/gpu/drm/rcar-du/rcar_du_vga.c
new file mode 100644
index 000000000000..327289ec380d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vga.c
@@ -0,0 +1,149 @@
+/*
+ * rcar_du_vga.c -- R-Car Display Unit VGA DAC and Connector
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "rcar_du_drv.h"
+#include "rcar_du_kms.h"
+#include "rcar_du_vga.h"
+
+/* -----------------------------------------------------------------------------
+ * Connector
+ */
+
+static int rcar_du_vga_connector_get_modes(struct drm_connector *connector)
+{
+ return 0;
+}
+
+static int rcar_du_vga_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs connector_helper_funcs = {
+ .get_modes = rcar_du_vga_connector_get_modes,
+ .mode_valid = rcar_du_vga_connector_mode_valid,
+ .best_encoder = rcar_du_connector_best_encoder,
+};
+
+static void rcar_du_vga_connector_destroy(struct drm_connector *connector)
+{
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+}
+
+static enum drm_connector_status
+rcar_du_vga_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_unknown;
+}
+
+static const struct drm_connector_funcs connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = rcar_du_vga_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = rcar_du_vga_connector_destroy,
+};
+
+static int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
+ struct rcar_du_encoder *renc)
+{
+ struct rcar_du_connector *rcon;
+ struct drm_connector *connector;
+ int ret;
+
+ rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL);
+ if (rcon == NULL)
+ return -ENOMEM;
+
+ connector = &rcon->connector;
+ connector->display_info.width_mm = 0;
+ connector->display_info.height_mm = 0;
+
+ ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
+ DRM_MODE_CONNECTOR_VGA);
+ if (ret < 0)
+ return ret;
+
+ drm_connector_helper_add(connector, &connector_helper_funcs);
+ ret = drm_sysfs_connector_add(connector);
+ if (ret < 0)
+ return ret;
+
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ drm_object_property_set_value(&connector->base,
+ rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF);
+
+ ret = drm_mode_connector_attach_encoder(connector, &renc->encoder);
+ if (ret < 0)
+ return ret;
+
+ connector->encoder = &renc->encoder;
+ rcon->encoder = renc;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Encoder
+ */
+
+static void rcar_du_vga_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static bool rcar_du_vga_encoder_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 encoder_helper_funcs = {
+ .dpms = rcar_du_vga_encoder_dpms,
+ .mode_fixup = rcar_du_vga_encoder_mode_fixup,
+ .prepare = rcar_du_encoder_mode_prepare,
+ .commit = rcar_du_encoder_mode_commit,
+ .mode_set = rcar_du_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+int rcar_du_vga_init(struct rcar_du_device *rcdu,
+ const struct rcar_du_encoder_vga_data *data,
+ unsigned int output)
+{
+ struct rcar_du_encoder *renc;
+ int ret;
+
+ renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
+ if (renc == NULL)
+ return -ENOMEM;
+
+ renc->output = output;
+
+ ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs,
+ DRM_MODE_ENCODER_DAC);
+ if (ret < 0)
+ return ret;
+
+ drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs);
+
+ return rcar_du_vga_connector_init(rcdu, renc);
+}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vga.h b/drivers/gpu/drm/rcar-du/rcar_du_vga.h
new file mode 100644
index 000000000000..66b4d2d7190d
--- /dev/null
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vga.h
@@ -0,0 +1,24 @@
+/*
+ * rcar_du_vga.h -- R-Car Display Unit VGA DAC and Connector
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __RCAR_DU_VGA_H__
+#define __RCAR_DU_VGA_H__
+
+struct rcar_du_device;
+struct rcar_du_encoder_vga_data;
+
+int rcar_du_vga_init(struct rcar_du_device *rcdu,
+ const struct rcar_du_encoder_vga_data *data,
+ unsigned int output);
+
+#endif /* __RCAR_DU_VGA_H__ */
diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c
index b55c1d661147..bd6b2cf508d5 100644
--- a/drivers/gpu/drm/savage/savage_bci.c
+++ b/drivers/gpu/drm/savage/savage_bci.c
@@ -570,9 +570,6 @@ int savage_driver_firstopen(struct drm_device *dev)
unsigned int fb_rsrc, aper_rsrc;
int ret = 0;
- dev_priv->mtrr[0].handle = -1;
- dev_priv->mtrr[1].handle = -1;
- dev_priv->mtrr[2].handle = -1;
if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
fb_rsrc = 0;
fb_base = pci_resource_start(dev->pdev, 0);
@@ -584,21 +581,14 @@ int savage_driver_firstopen(struct drm_device *dev)
if (pci_resource_len(dev->pdev, 0) == 0x08000000) {
/* Don't make MMIO write-cobining! We need 3
* MTRRs. */
- dev_priv->mtrr[0].base = fb_base;
- dev_priv->mtrr[0].size = 0x01000000;
- dev_priv->mtrr[0].handle =
- drm_mtrr_add(dev_priv->mtrr[0].base,
- dev_priv->mtrr[0].size, DRM_MTRR_WC);
- dev_priv->mtrr[1].base = fb_base + 0x02000000;
- dev_priv->mtrr[1].size = 0x02000000;
- dev_priv->mtrr[1].handle =
- drm_mtrr_add(dev_priv->mtrr[1].base,
- dev_priv->mtrr[1].size, DRM_MTRR_WC);
- dev_priv->mtrr[2].base = fb_base + 0x04000000;
- dev_priv->mtrr[2].size = 0x04000000;
- dev_priv->mtrr[2].handle =
- drm_mtrr_add(dev_priv->mtrr[2].base,
- dev_priv->mtrr[2].size, DRM_MTRR_WC);
+ dev_priv->mtrr_handles[0] =
+ arch_phys_wc_add(fb_base, 0x01000000);
+ dev_priv->mtrr_handles[1] =
+ arch_phys_wc_add(fb_base + 0x02000000,
+ 0x02000000);
+ dev_priv->mtrr_handles[2] =
+ arch_phys_wc_add(fb_base + 0x04000000,
+ 0x04000000);
} else {
DRM_ERROR("strange pci_resource_len %08llx\n",
(unsigned long long)
@@ -616,11 +606,9 @@ int savage_driver_firstopen(struct drm_device *dev)
if (pci_resource_len(dev->pdev, 1) == 0x08000000) {
/* Can use one MTRR to cover both fb and
* aperture. */
- dev_priv->mtrr[0].base = fb_base;
- dev_priv->mtrr[0].size = 0x08000000;
- dev_priv->mtrr[0].handle =
- drm_mtrr_add(dev_priv->mtrr[0].base,
- dev_priv->mtrr[0].size, DRM_MTRR_WC);
+ dev_priv->mtrr_handles[0] =
+ arch_phys_wc_add(fb_base,
+ 0x08000000);
} else {
DRM_ERROR("strange pci_resource_len %08llx\n",
(unsigned long long)
@@ -660,11 +648,10 @@ void savage_driver_lastclose(struct drm_device *dev)
drm_savage_private_t *dev_priv = dev->dev_private;
int i;
- for (i = 0; i < 3; ++i)
- if (dev_priv->mtrr[i].handle >= 0)
- drm_mtrr_del(dev_priv->mtrr[i].handle,
- dev_priv->mtrr[i].base,
- dev_priv->mtrr[i].size, DRM_MTRR_WC);
+ for (i = 0; i < 3; ++i) {
+ arch_phys_wc_del(dev_priv->mtrr_handles[i]);
+ dev_priv->mtrr_handles[i] = 0;
+ }
}
int savage_driver_unload(struct drm_device *dev)
diff --git a/drivers/gpu/drm/savage/savage_drv.h b/drivers/gpu/drm/savage/savage_drv.h
index df2aac6636f7..c05082a59f6f 100644
--- a/drivers/gpu/drm/savage/savage_drv.h
+++ b/drivers/gpu/drm/savage/savage_drv.h
@@ -160,10 +160,7 @@ typedef struct drm_savage_private {
drm_local_map_t *cmd_dma;
drm_local_map_t fake_dma;
- struct {
- int handle;
- unsigned long base, size;
- } mtrr[3];
+ int mtrr_handles[3];
/* BCI and status-related stuff */
volatile uint32_t *status_ptr, *bci_ptr;
diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig
index 7e7d52b2a2fc..ca498d151a76 100644
--- a/drivers/gpu/drm/shmobile/Kconfig
+++ b/drivers/gpu/drm/shmobile/Kconfig
@@ -1,6 +1,6 @@
config DRM_SHMOBILE
tristate "DRM Support for SH Mobile"
- depends on DRM && (SUPERH || ARCH_SHMOBILE)
+ depends on DRM && (ARM || SUPERH)
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
select DRM_GEM_CMA_HELPER
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index f6e0b5395051..edc10181f551 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -90,7 +90,7 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
return -EINVAL;
}
- clk = clk_get(sdev->dev, clkname);
+ clk = devm_clk_get(sdev->dev, clkname);
if (IS_ERR(clk)) {
dev_err(sdev->dev, "cannot get dot clock %s\n", clkname);
return PTR_ERR(clk);
@@ -106,21 +106,12 @@ static int shmob_drm_setup_clocks(struct shmob_drm_device *sdev,
static int shmob_drm_unload(struct drm_device *dev)
{
- struct shmob_drm_device *sdev = dev->dev_private;
-
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
drm_vblank_cleanup(dev);
drm_irq_uninstall(dev);
- if (sdev->clock)
- clk_put(sdev->clock);
-
- if (sdev->mmio)
- iounmap(sdev->mmio);
-
dev->dev_private = NULL;
- kfree(sdev);
return 0;
}
@@ -139,7 +130,7 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags)
return -EINVAL;
}
- sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+ sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
if (sdev == NULL) {
dev_err(dev->dev, "failed to allocate private data\n");
return -ENOMEM;
@@ -156,29 +147,28 @@ static int shmob_drm_load(struct drm_device *dev, unsigned long flags)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "failed to get memory resource\n");
- ret = -EINVAL;
- goto done;
+ return -EINVAL;
}
- sdev->mmio = ioremap_nocache(res->start, resource_size(res));
+ sdev->mmio = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
if (sdev->mmio == NULL) {
dev_err(&pdev->dev, "failed to remap memory resource\n");
- ret = -ENOMEM;
- goto done;
+ return -ENOMEM;
}
ret = shmob_drm_setup_clocks(sdev, pdata->clk_source);
if (ret < 0)
- goto done;
+ return ret;
ret = shmob_drm_init_interface(sdev);
if (ret < 0)
- goto done;
+ return ret;
ret = shmob_drm_modeset_init(sdev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to initialize mode setting\n");
- goto done;
+ return ret;
}
for (i = 0; i < 4; ++i) {
@@ -273,7 +263,8 @@ static const struct file_operations shmob_drm_fops = {
};
static struct drm_driver shmob_drm_driver = {
- .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+ .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET
+ | DRIVER_PRIME,
.load = shmob_drm_load,
.unload = shmob_drm_unload,
.preclose = shmob_drm_preclose,
@@ -283,6 +274,10 @@ static struct drm_driver shmob_drm_driver = {
.disable_vblank = shmob_drm_disable_vblank,
.gem_free_object = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = drm_gem_cma_dmabuf_import,
+ .gem_prime_export = drm_gem_cma_dmabuf_export,
.dumb_create = drm_gem_cma_dumb_create,
.dumb_map_offset = drm_gem_cma_dumb_map_offset,
.dumb_destroy = drm_gem_cma_dumb_destroy,
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
index c291ee385b4f..fc0ef0ca7d04 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c
@@ -116,7 +116,7 @@ shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
}
if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
- dev_dbg(dev->dev, "valid pitch value %u\n",
+ dev_dbg(dev->dev, "invalid pitch value %u\n",
mode_cmd->pitches[0]);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/gpu/drm/shmobile/shmob_drm_plane.c b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
index e1eb899b0288..060ae03e5f9b 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_plane.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_plane.c
@@ -166,7 +166,7 @@ void shmob_drm_plane_setup(struct drm_plane *plane)
{
struct shmob_drm_plane *splane = to_shmob_plane(plane);
- if (plane->fb == NULL || !plane->enabled)
+ if (plane->fb == NULL)
return;
__shmob_drm_plane_setup(splane, plane->fb);
@@ -221,11 +221,8 @@ static int shmob_drm_plane_disable(struct drm_plane *plane)
static void shmob_drm_plane_destroy(struct drm_plane *plane)
{
- struct shmob_drm_plane *splane = to_shmob_plane(plane);
-
shmob_drm_plane_disable(plane);
drm_plane_cleanup(plane);
- kfree(splane);
}
static const struct drm_plane_funcs shmob_drm_plane_funcs = {
@@ -251,7 +248,7 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
struct shmob_drm_plane *splane;
int ret;
- splane = kzalloc(sizeof(*splane), GFP_KERNEL);
+ splane = devm_kzalloc(sdev->dev, sizeof(*splane), GFP_KERNEL);
if (splane == NULL)
return -ENOMEM;
@@ -261,8 +258,6 @@ int shmob_drm_plane_create(struct shmob_drm_device *sdev, unsigned int index)
ret = drm_plane_init(sdev->ddev, &splane->plane, 1,
&shmob_drm_plane_funcs, formats,
ARRAY_SIZE(formats), false);
- if (ret < 0)
- kfree(splane);
return ret;
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 5dd3c7d031d5..7418dcd986d3 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -42,7 +42,8 @@ struct tilcdc_crtc {
static void unref_worker(struct work_struct *work)
{
- struct tilcdc_crtc *tilcdc_crtc = container_of(work, struct tilcdc_crtc, work);
+ struct tilcdc_crtc *tilcdc_crtc =
+ container_of(work, struct tilcdc_crtc, work);
struct drm_device *dev = tilcdc_crtc->base.dev;
struct drm_framebuffer *fb;
@@ -55,10 +56,12 @@ static void unref_worker(struct work_struct *work)
static void set_scanout(struct drm_crtc *crtc, int n)
{
static const uint32_t base_reg[] = {
- LCDC_DMA_FB_BASE_ADDR_0_REG, LCDC_DMA_FB_BASE_ADDR_1_REG,
+ LCDC_DMA_FB_BASE_ADDR_0_REG,
+ LCDC_DMA_FB_BASE_ADDR_1_REG,
};
static const uint32_t ceil_reg[] = {
- LCDC_DMA_FB_CEILING_ADDR_0_REG, LCDC_DMA_FB_CEILING_ADDR_1_REG,
+ LCDC_DMA_FB_CEILING_ADDR_0_REG,
+ LCDC_DMA_FB_CEILING_ADDR_1_REG,
};
static const uint32_t stat[] = {
LCDC_END_OF_FRAME0, LCDC_END_OF_FRAME1,
@@ -194,7 +197,8 @@ static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode)
tilcdc_crtc->frame_done = false;
stop(crtc);
- /* if necessary wait for framedone irq which will still come
+ /*
+ * if necessary wait for framedone irq which will still come
* before putting things to sleep..
*/
if (priv->rev == 2) {
@@ -289,17 +293,24 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
reg = tilcdc_read(dev, LCDC_RASTER_TIMING_2_REG) & ~0x000fff00;
reg |= LCDC_AC_BIAS_FREQUENCY(info->ac_bias) |
LCDC_AC_BIAS_TRANSITIONS_PER_INT(info->ac_bias_intrpt);
+
+ /*
+ * subtract one from hfp, hbp, hsw because the hardware uses
+ * a value of 0 as 1
+ */
if (priv->rev == 2) {
- reg |= (hfp & 0x300) >> 8;
- reg |= (hbp & 0x300) >> 4;
- reg |= (hsw & 0x3c0) << 21;
+ /* clear bits we're going to set */
+ reg &= ~0x78000033;
+ reg |= ((hfp-1) & 0x300) >> 8;
+ reg |= ((hbp-1) & 0x300) >> 4;
+ reg |= ((hsw-1) & 0x3c0) << 21;
}
tilcdc_write(dev, LCDC_RASTER_TIMING_2_REG, reg);
reg = (((mode->hdisplay >> 4) - 1) << 4) |
- ((hbp & 0xff) << 24) |
- ((hfp & 0xff) << 16) |
- ((hsw & 0x3f) << 10);
+ (((hbp-1) & 0xff) << 24) |
+ (((hfp-1) & 0xff) << 16) |
+ (((hsw-1) & 0x3f) << 10);
if (priv->rev == 2)
reg |= (((mode->hdisplay >> 4) - 1) & 0x40) >> 3;
tilcdc_write(dev, LCDC_RASTER_TIMING_0_REG, reg);
@@ -307,9 +318,24 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
reg = ((mode->vdisplay - 1) & 0x3ff) |
((vbp & 0xff) << 24) |
((vfp & 0xff) << 16) |
- ((vsw & 0x3f) << 10);
+ (((vsw-1) & 0x3f) << 10);
tilcdc_write(dev, LCDC_RASTER_TIMING_1_REG, reg);
+ /*
+ * be sure to set Bit 10 for the V2 LCDC controller,
+ * otherwise limited to 1024 pixels width, stopping
+ * 1920x1080 being suppoted.
+ */
+ if (priv->rev == 2) {
+ if ((mode->vdisplay - 1) & 0x400) {
+ tilcdc_set(dev, LCDC_RASTER_TIMING_2_REG,
+ LCDC_LPP_B10);
+ } else {
+ tilcdc_clear(dev, LCDC_RASTER_TIMING_2_REG,
+ LCDC_LPP_B10);
+ }
+ }
+
/* Configure display type: */
reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG) &
~(LCDC_TFT_MODE | LCDC_MONO_8BIT_MODE | LCDC_MONOCHROME_MODE |
@@ -384,10 +410,6 @@ static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
-static void tilcdc_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
static const struct drm_crtc_funcs tilcdc_crtc_funcs = {
.destroy = tilcdc_crtc_destroy,
.set_config = drm_crtc_helper_set_config,
@@ -401,7 +423,6 @@ static const struct drm_crtc_helper_funcs tilcdc_crtc_helper_funcs = {
.commit = tilcdc_crtc_commit,
.mode_set = tilcdc_crtc_mode_set,
.mode_set_base = tilcdc_crtc_mode_set_base,
- .load_lut = tilcdc_crtc_load_lut,
};
int tilcdc_crtc_max_width(struct drm_crtc *crtc)
@@ -422,7 +443,12 @@ int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode)
{
struct tilcdc_drm_private *priv = crtc->dev->dev_private;
unsigned int bandwidth;
+ uint32_t hbp, hfp, hsw, vbp, vfp, vsw;
+ /*
+ * check to see if the width is within the range that
+ * the LCD Controller physically supports
+ */
if (mode->hdisplay > tilcdc_crtc_max_width(crtc))
return MODE_VIRTUAL_X;
@@ -433,10 +459,70 @@ int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode)
if (mode->vdisplay > 2048)
return MODE_VIRTUAL_Y;
+ DBG("Processing mode %dx%d@%d with pixel clock %d",
+ mode->hdisplay, mode->vdisplay,
+ drm_mode_vrefresh(mode), mode->clock);
+
+ hbp = mode->htotal - mode->hsync_end;
+ hfp = mode->hsync_start - mode->hdisplay;
+ hsw = mode->hsync_end - mode->hsync_start;
+ vbp = mode->vtotal - mode->vsync_end;
+ vfp = mode->vsync_start - mode->vdisplay;
+ vsw = mode->vsync_end - mode->vsync_start;
+
+ if ((hbp-1) & ~0x3ff) {
+ DBG("Pruning mode: Horizontal Back Porch out of range");
+ return MODE_HBLANK_WIDE;
+ }
+
+ if ((hfp-1) & ~0x3ff) {
+ DBG("Pruning mode: Horizontal Front Porch out of range");
+ return MODE_HBLANK_WIDE;
+ }
+
+ if ((hsw-1) & ~0x3ff) {
+ DBG("Pruning mode: Horizontal Sync Width out of range");
+ return MODE_HSYNC_WIDE;
+ }
+
+ if (vbp & ~0xff) {
+ DBG("Pruning mode: Vertical Back Porch out of range");
+ return MODE_VBLANK_WIDE;
+ }
+
+ if (vfp & ~0xff) {
+ DBG("Pruning mode: Vertical Front Porch out of range");
+ return MODE_VBLANK_WIDE;
+ }
+
+ if ((vsw-1) & ~0x3f) {
+ DBG("Pruning mode: Vertical Sync Width out of range");
+ return MODE_VSYNC_WIDE;
+ }
+
+ /*
+ * some devices have a maximum allowed pixel clock
+ * configured from the DT
+ */
+ if (mode->clock > priv->max_pixelclock) {
+ DBG("Pruning mode: pixel clock too high");
+ return MODE_CLOCK_HIGH;
+ }
+
+ /*
+ * some devices further limit the max horizontal resolution
+ * configured from the DT
+ */
+ if (mode->hdisplay > priv->max_width)
+ return MODE_BAD_WIDTH;
+
/* filter out modes that would require too much memory bandwidth: */
- bandwidth = mode->hdisplay * mode->vdisplay * drm_mode_vrefresh(mode);
- if (bandwidth > priv->max_bandwidth)
+ bandwidth = mode->hdisplay * mode->vdisplay *
+ drm_mode_vrefresh(mode);
+ if (bandwidth > priv->max_bandwidth) {
+ DBG("Pruning mode: exceeds defined bandwidth limit");
return MODE_BAD;
+ }
return MODE_OK;
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 2b5461bcd9fb..40b71da5a214 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -26,6 +26,7 @@
#include "drm_fb_helper.h"
static LIST_HEAD(module_list);
+static bool slave_probing;
void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
const struct tilcdc_module_ops *funcs)
@@ -41,6 +42,11 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod)
list_del(&mod->list);
}
+void tilcdc_slave_probedefer(bool defered)
+{
+ slave_probing = defered;
+}
+
static struct of_device_id tilcdc_of_match[];
static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
@@ -157,7 +163,9 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
struct platform_device *pdev = dev->platformdev;
struct device_node *node = pdev->dev.of_node;
struct tilcdc_drm_private *priv;
+ struct tilcdc_module *mod;
struct resource *res;
+ u32 bpp = 0;
int ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -210,7 +218,20 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
#endif
if (of_property_read_u32(node, "max-bandwidth", &priv->max_bandwidth))
- priv->max_bandwidth = 1280 * 1024 * 60;
+ priv->max_bandwidth = TILCDC_DEFAULT_MAX_BANDWIDTH;
+
+ DBG("Maximum Bandwidth Value %d", priv->max_bandwidth);
+
+ if (of_property_read_u32(node, "ti,max-width", &priv->max_width))
+ priv->max_width = TILCDC_DEFAULT_MAX_WIDTH;
+
+ DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width);
+
+ if (of_property_read_u32(node, "ti,max-pixelclock",
+ &priv->max_pixelclock))
+ priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK;
+
+ DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock);
pm_runtime_enable(dev->dev);
@@ -256,7 +277,15 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
platform_set_drvdata(pdev, dev);
- priv->fbdev = drm_fbdev_cma_init(dev, 16,
+
+ list_for_each_entry(mod, &module_list, list) {
+ DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp);
+ bpp = mod->preferred_bpp;
+ if (bpp > 0)
+ break;
+ }
+
+ priv->fbdev = drm_fbdev_cma_init(dev, bpp,
dev->mode_config.num_crtc,
dev->mode_config.num_connector);
@@ -557,6 +586,10 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)
return -ENXIO;
}
+ /* defer probing if slave is in deferred probing */
+ if (slave_probing == true)
+ return -EPROBE_DEFER;
+
return drm_platform_init(&tilcdc_driver, pdev);
}
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 8242b5a4307b..093803683b25 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -34,6 +34,18 @@
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
+/* Defaulting to pixel clock defined on AM335x */
+#define TILCDC_DEFAULT_MAX_PIXELCLOCK 126000
+/* Defaulting to max width as defined on AM335x */
+#define TILCDC_DEFAULT_MAX_WIDTH 2048
+/*
+ * This may need some tweaking, but want to allow at least 1280x1024@60
+ * with optimized DDR & EMIF settings tweaked 1920x1080@24 appears to
+ * be supportable
+ */
+#define TILCDC_DEFAULT_MAX_BANDWIDTH (1280*1024*60)
+
+
struct tilcdc_drm_private {
void __iomem *mmio;
@@ -43,6 +55,16 @@ struct tilcdc_drm_private {
/* don't attempt resolutions w/ higher W * H * Hz: */
uint32_t max_bandwidth;
+ /*
+ * Pixel Clock will be restricted to some value as
+ * defined in the device datasheet measured in KHz
+ */
+ uint32_t max_pixelclock;
+ /*
+ * Max allowable width is limited on a per device basis
+ * measured in pixels
+ */
+ uint32_t max_width;
/* register contents saved across suspend/resume: */
u32 saved_register[12];
@@ -89,12 +111,13 @@ struct tilcdc_module {
const char *name;
struct list_head list;
const struct tilcdc_module_ops *funcs;
+ unsigned int preferred_bpp;
};
void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
const struct tilcdc_module_ops *funcs);
void tilcdc_module_cleanup(struct tilcdc_module *mod);
-
+void tilcdc_slave_probedefer(bool defered);
/* Panel config that needs to be set in the crtc, but is not coming from
* the mode timings. The display module is expected to call
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
index 09176654fddb..86c67329b605 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c
@@ -393,6 +393,8 @@ static int panel_probe(struct platform_device *pdev)
goto fail;
}
+ mod->preferred_bpp = panel_mod->info->bpp;
+
panel_mod->backlight = of_find_backlight_by_node(node);
if (panel_mod->backlight)
dev_info(&pdev->dev, "found backlight\n");
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
index 17fd1b45428a..1bf5e2553acc 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h
@@ -80,6 +80,7 @@
#define LCDC_INVERT_PIXEL_CLOCK BIT(22)
#define LCDC_INVERT_HSYNC BIT(21)
#define LCDC_INVERT_VSYNC BIT(20)
+#define LCDC_LPP_B10 BIT(26)
/* LCDC Block */
#define LCDC_PID_REG 0x0
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_slave.c b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
index db1d2fc9dfb5..dfffaf014022 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_slave.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_slave.c
@@ -298,6 +298,7 @@ static int slave_probe(struct platform_device *pdev)
struct tilcdc_module *mod;
struct pinctrl *pinctrl;
uint32_t i2c_phandle;
+ struct i2c_adapter *slavei2c;
int ret = -EINVAL;
/* bail out early if no DT data: */
@@ -306,42 +307,48 @@ static int slave_probe(struct platform_device *pdev)
return -ENXIO;
}
- slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL);
- if (!slave_mod)
- return -ENOMEM;
-
- mod = &slave_mod->base;
-
- tilcdc_module_init(mod, "slave", &slave_module_ops);
-
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&pdev->dev, "pins are not configured\n");
-
+ /* Bail out early if i2c not specified */
if (of_property_read_u32(node, "i2c", &i2c_phandle)) {
dev_err(&pdev->dev, "could not get i2c bus phandle\n");
- goto fail;
+ return ret;
}
i2c_node = of_find_node_by_phandle(i2c_phandle);
if (!i2c_node) {
dev_err(&pdev->dev, "could not get i2c bus node\n");
- goto fail;
+ return ret;
}
- slave_mod->i2c = of_find_i2c_adapter_by_node(i2c_node);
- if (!slave_mod->i2c) {
+ /* but defer the probe if it can't be initialized it might come later */
+ slavei2c = of_find_i2c_adapter_by_node(i2c_node);
+ of_node_put(i2c_node);
+
+ if (!slavei2c) {
+ ret = -EPROBE_DEFER;
+ tilcdc_slave_probedefer(true);
dev_err(&pdev->dev, "could not get i2c\n");
- goto fail;
+ return ret;
}
- of_node_put(i2c_node);
+ slave_mod = kzalloc(sizeof(*slave_mod), GFP_KERNEL);
+ if (!slave_mod)
+ return -ENOMEM;
- return 0;
+ mod = &slave_mod->base;
-fail:
- slave_destroy(mod);
- return ret;
+ mod->preferred_bpp = slave_info.bpp;
+
+ slave_mod->i2c = slavei2c;
+
+ tilcdc_module_init(mod, "slave", &slave_module_ops);
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev, "pins are not configured\n");
+
+ tilcdc_slave_probedefer(false);
+
+ return 0;
}
static int slave_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
index a36788fbcd98..925c7cddeff9 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c
@@ -354,6 +354,8 @@ static int tfp410_probe(struct platform_device *pdev)
goto fail;
}
+ mod->preferred_bpp = dvi_info.bpp;
+
i2c_node = of_find_node_by_phandle(i2c_phandle);
if (!i2c_node) {
dev_err(&pdev->dev, "could not get i2c bus node\n");
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 9b07b7d44a58..cb9dd674670c 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -150,6 +150,9 @@ static void ttm_bo_release_list(struct kref *list_kref)
if (bo->ttm)
ttm_tt_destroy(bo->ttm);
atomic_dec(&bo->glob->bo_count);
+ if (bo->resv == &bo->ttm_resv)
+ reservation_object_fini(&bo->ttm_resv);
+
if (bo->destroy)
bo->destroy(bo);
else {
@@ -158,24 +161,12 @@ static void ttm_bo_release_list(struct kref *list_kref)
ttm_mem_global_free(bdev->glob->mem_glob, acc_size);
}
-static int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo,
- bool interruptible)
-{
- if (interruptible) {
- return wait_event_interruptible(bo->event_queue,
- !ttm_bo_is_reserved(bo));
- } else {
- wait_event(bo->event_queue, !ttm_bo_is_reserved(bo));
- return 0;
- }
-}
-
void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
{
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_mem_type_manager *man;
- BUG_ON(!ttm_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->resv->lock.base);
if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
@@ -191,6 +182,7 @@ void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
}
}
}
+EXPORT_SYMBOL(ttm_bo_add_to_lru);
int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
{
@@ -213,71 +205,6 @@ int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
return put_count;
}
-int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo,
- bool interruptible,
- bool no_wait, bool use_sequence, uint32_t sequence)
-{
- int ret;
-
- while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) {
- /**
- * Deadlock avoidance for multi-bo reserving.
- */
- if (use_sequence && bo->seq_valid) {
- /**
- * We've already reserved this one.
- */
- if (unlikely(sequence == bo->val_seq))
- return -EDEADLK;
- /**
- * Already reserved by a thread that will not back
- * off for us. We need to back off.
- */
- if (unlikely(sequence - bo->val_seq < (1 << 31)))
- return -EAGAIN;
- }
-
- if (no_wait)
- return -EBUSY;
-
- ret = ttm_bo_wait_unreserved(bo, interruptible);
-
- if (unlikely(ret))
- return ret;
- }
-
- if (use_sequence) {
- bool wake_up = false;
- /**
- * Wake up waiters that may need to recheck for deadlock,
- * if we decreased the sequence number.
- */
- if (unlikely((bo->val_seq - sequence < (1 << 31))
- || !bo->seq_valid))
- wake_up = true;
-
- /*
- * In the worst case with memory ordering these values can be
- * seen in the wrong order. However since we call wake_up_all
- * in that case, this will hopefully not pose a problem,
- * and the worst case would only cause someone to accidentally
- * hit -EAGAIN in ttm_bo_reserve when they see old value of
- * val_seq. However this would only happen if seq_valid was
- * written before val_seq was, and just means some slightly
- * increased cpu usage
- */
- bo->val_seq = sequence;
- bo->seq_valid = true;
- if (wake_up)
- wake_up_all(&bo->event_queue);
- } else {
- bo->seq_valid = false;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(ttm_bo_reserve);
-
static void ttm_bo_ref_bug(struct kref *list_kref)
{
BUG();
@@ -290,89 +217,16 @@ void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count,
(never_free) ? ttm_bo_ref_bug : ttm_bo_release_list);
}
-int ttm_bo_reserve(struct ttm_buffer_object *bo,
- bool interruptible,
- bool no_wait, bool use_sequence, uint32_t sequence)
-{
- struct ttm_bo_global *glob = bo->glob;
- int put_count = 0;
- int ret;
-
- ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_sequence,
- sequence);
- if (likely(ret == 0)) {
- spin_lock(&glob->lru_lock);
- put_count = ttm_bo_del_from_lru(bo);
- spin_unlock(&glob->lru_lock);
- ttm_bo_list_ref_sub(bo, put_count, true);
- }
-
- return ret;
-}
-
-int ttm_bo_reserve_slowpath_nolru(struct ttm_buffer_object *bo,
- bool interruptible, uint32_t sequence)
-{
- bool wake_up = false;
- int ret;
-
- while (unlikely(atomic_xchg(&bo->reserved, 1) != 0)) {
- WARN_ON(bo->seq_valid && sequence == bo->val_seq);
-
- ret = ttm_bo_wait_unreserved(bo, interruptible);
-
- if (unlikely(ret))
- return ret;
- }
-
- if ((bo->val_seq - sequence < (1 << 31)) || !bo->seq_valid)
- wake_up = true;
-
- /**
- * Wake up waiters that may need to recheck for deadlock,
- * if we decreased the sequence number.
- */
- bo->val_seq = sequence;
- bo->seq_valid = true;
- if (wake_up)
- wake_up_all(&bo->event_queue);
-
- return 0;
-}
-
-int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
- bool interruptible, uint32_t sequence)
-{
- struct ttm_bo_global *glob = bo->glob;
- int put_count, ret;
-
- ret = ttm_bo_reserve_slowpath_nolru(bo, interruptible, sequence);
- if (likely(!ret)) {
- spin_lock(&glob->lru_lock);
- put_count = ttm_bo_del_from_lru(bo);
- spin_unlock(&glob->lru_lock);
- ttm_bo_list_ref_sub(bo, put_count, true);
- }
- return ret;
-}
-EXPORT_SYMBOL(ttm_bo_reserve_slowpath);
-
-void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo)
-{
- ttm_bo_add_to_lru(bo);
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
-}
-
-void ttm_bo_unreserve(struct ttm_buffer_object *bo)
+void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo)
{
- struct ttm_bo_global *glob = bo->glob;
+ int put_count;
- spin_lock(&glob->lru_lock);
- ttm_bo_unreserve_locked(bo);
- spin_unlock(&glob->lru_lock);
+ spin_lock(&bo->glob->lru_lock);
+ put_count = ttm_bo_del_from_lru(bo);
+ spin_unlock(&bo->glob->lru_lock);
+ ttm_bo_list_ref_sub(bo, put_count, true);
}
-EXPORT_SYMBOL(ttm_bo_unreserve);
+EXPORT_SYMBOL(ttm_bo_del_sub_from_lru);
/*
* Call bo->mutex locked.
@@ -544,17 +398,7 @@ static void ttm_bo_cleanup_memtype_use(struct ttm_buffer_object *bo)
}
ttm_bo_mem_put(bo, &bo->mem);
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
-
- /*
- * Since the final reference to this bo may not be dropped by
- * the current task we have to put a memory barrier here to make
- * sure the changes done in this function are always visible.
- *
- * This function only needs protection against the final kref_put.
- */
- smp_mb__before_atomic_dec();
+ ww_mutex_unlock (&bo->resv->lock);
}
static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
@@ -586,10 +430,8 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
sync_obj = driver->sync_obj_ref(bo->sync_obj);
spin_unlock(&bdev->fence_lock);
- if (!ret) {
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
- }
+ if (!ret)
+ ww_mutex_unlock(&bo->resv->lock);
kref_get(&bo->list_kref);
list_add_tail(&bo->ddestroy, &bdev->ddestroy);
@@ -639,8 +481,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
sync_obj = driver->sync_obj_ref(bo->sync_obj);
spin_unlock(&bdev->fence_lock);
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
+ ww_mutex_unlock(&bo->resv->lock);
spin_unlock(&glob->lru_lock);
ret = driver->sync_obj_wait(sync_obj, false, interruptible);
@@ -678,8 +519,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
spin_unlock(&bdev->fence_lock);
if (ret || unlikely(list_empty(&bo->ddestroy))) {
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
+ ww_mutex_unlock(&bo->resv->lock);
spin_unlock(&glob->lru_lock);
return ret;
}
@@ -831,7 +671,7 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, bool interruptible,
goto out;
}
- BUG_ON(!ttm_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->resv->lock.base);
evict_mem = bo->mem;
evict_mem.mm_node = NULL;
@@ -1121,7 +961,7 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
struct ttm_mem_reg mem;
struct ttm_bo_device *bdev = bo->bdev;
- BUG_ON(!ttm_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->resv->lock.base);
/*
* FIXME: It's possible to pipeline buffer moves.
@@ -1180,7 +1020,7 @@ int ttm_bo_validate(struct ttm_buffer_object *bo,
{
int ret;
- BUG_ON(!ttm_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->resv->lock.base);
/* Check that range is valid */
if (placement->lpfn || placement->fpfn)
if (placement->fpfn > placement->lpfn ||
@@ -1239,6 +1079,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
int ret = 0;
unsigned long num_pages;
struct ttm_mem_global *mem_glob = bdev->glob->mem_glob;
+ bool locked;
ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false);
if (ret) {
@@ -1265,8 +1106,6 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
kref_init(&bo->kref);
kref_init(&bo->list_kref);
atomic_set(&bo->cpu_writers, 0);
- atomic_set(&bo->reserved, 1);
- init_waitqueue_head(&bo->event_queue);
INIT_LIST_HEAD(&bo->lru);
INIT_LIST_HEAD(&bo->ddestroy);
INIT_LIST_HEAD(&bo->swap);
@@ -1284,37 +1123,34 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bo->mem.bus.io_reserved_count = 0;
bo->priv_flags = 0;
bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
- bo->seq_valid = false;
bo->persistent_swap_storage = persistent_swap_storage;
bo->acc_size = acc_size;
bo->sg = sg;
+ bo->resv = &bo->ttm_resv;
+ reservation_object_init(bo->resv);
atomic_inc(&bo->glob->bo_count);
ret = ttm_bo_check_placement(bo, placement);
- if (unlikely(ret != 0))
- goto out_err;
/*
* For ttm_bo_type_device buffers, allocate
* address space from the device.
*/
- if (bo->type == ttm_bo_type_device ||
- bo->type == ttm_bo_type_sg) {
+ if (likely(!ret) &&
+ (bo->type == ttm_bo_type_device ||
+ bo->type == ttm_bo_type_sg))
ret = ttm_bo_setup_vm(bo);
- if (ret)
- goto out_err;
- }
- ret = ttm_bo_validate(bo, placement, interruptible, false);
- if (ret)
- goto out_err;
+ locked = ww_mutex_trylock(&bo->resv->lock);
+ WARN_ON(!locked);
- ttm_bo_unreserve(bo);
- return 0;
+ if (likely(!ret))
+ ret = ttm_bo_validate(bo, placement, interruptible, false);
-out_err:
ttm_bo_unreserve(bo);
- ttm_bo_unref(&bo);
+
+ if (unlikely(ret))
+ ttm_bo_unref(&bo);
return ret;
}
@@ -1619,9 +1455,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
goto out_no_sys;
bdev->addr_space_rb = RB_ROOT;
- ret = drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000);
- if (unlikely(ret != 0))
- goto out_no_addr_mm;
+ drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000);
INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
INIT_LIST_HEAD(&bdev->ddestroy);
@@ -1635,8 +1469,6 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
mutex_unlock(&glob->device_list_mutex);
return 0;
-out_no_addr_mm:
- ttm_bo_clean_mm(bdev, 0);
out_no_sys:
return ret;
}
@@ -1927,8 +1759,7 @@ out:
* already swapped buffer.
*/
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
+ ww_mutex_unlock(&bo->resv->lock);
kref_put(&bo->list_kref, ttm_bo_release_list);
return ret;
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c
index 9212494e9072..e4367f91472a 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_manager.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c
@@ -103,18 +103,12 @@ static int ttm_bo_man_init(struct ttm_mem_type_manager *man,
unsigned long p_size)
{
struct ttm_range_manager *rman;
- int ret;
rman = kzalloc(sizeof(*rman), GFP_KERNEL);
if (!rman)
return -ENOMEM;
- ret = drm_mm_init(&rman->mm, 0, p_size);
- if (ret) {
- kfree(rman);
- return ret;
- }
-
+ drm_mm_init(&rman->mm, 0, p_size);
spin_lock_init(&rman->lock);
man->priv = rman;
return 0;
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index af894584dd90..319cf4127c5b 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -433,6 +433,7 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
struct ttm_buffer_object *fbo;
struct ttm_bo_device *bdev = bo->bdev;
struct ttm_bo_driver *driver = bdev->driver;
+ int ret;
fbo = kmalloc(sizeof(*fbo), GFP_KERNEL);
if (!fbo)
@@ -445,7 +446,6 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
* TODO: Explicit member copy would probably be better here.
*/
- init_waitqueue_head(&fbo->event_queue);
INIT_LIST_HEAD(&fbo->ddestroy);
INIT_LIST_HEAD(&fbo->lru);
INIT_LIST_HEAD(&fbo->swap);
@@ -463,6 +463,10 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
kref_init(&fbo->kref);
fbo->destroy = &ttm_transfered_destroy;
fbo->acc_size = 0;
+ fbo->resv = &fbo->ttm_resv;
+ reservation_object_init(fbo->resv);
+ ret = ww_mutex_trylock(&fbo->resv->lock);
+ WARN_ON(!ret);
*new_obj = fbo;
return 0;
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index 7b90def15674..6c911789ae5c 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -32,7 +32,8 @@
#include <linux/sched.h>
#include <linux/module.h>
-static void ttm_eu_backoff_reservation_locked(struct list_head *list)
+static void ttm_eu_backoff_reservation_locked(struct list_head *list,
+ struct ww_acquire_ctx *ticket)
{
struct ttm_validate_buffer *entry;
@@ -41,14 +42,12 @@ static void ttm_eu_backoff_reservation_locked(struct list_head *list)
if (!entry->reserved)
continue;
+ entry->reserved = false;
if (entry->removed) {
ttm_bo_add_to_lru(bo);
entry->removed = false;
-
}
- entry->reserved = false;
- atomic_set(&bo->reserved, 0);
- wake_up_all(&bo->event_queue);
+ ww_mutex_unlock(&bo->resv->lock);
}
}
@@ -82,7 +81,8 @@ static void ttm_eu_list_ref_sub(struct list_head *list)
}
}
-void ttm_eu_backoff_reservation(struct list_head *list)
+void ttm_eu_backoff_reservation(struct ww_acquire_ctx *ticket,
+ struct list_head *list)
{
struct ttm_validate_buffer *entry;
struct ttm_bo_global *glob;
@@ -93,7 +93,8 @@ void ttm_eu_backoff_reservation(struct list_head *list)
entry = list_first_entry(list, struct ttm_validate_buffer, head);
glob = entry->bo->glob;
spin_lock(&glob->lru_lock);
- ttm_eu_backoff_reservation_locked(list);
+ ttm_eu_backoff_reservation_locked(list, ticket);
+ ww_acquire_fini(ticket);
spin_unlock(&glob->lru_lock);
}
EXPORT_SYMBOL(ttm_eu_backoff_reservation);
@@ -110,12 +111,12 @@ EXPORT_SYMBOL(ttm_eu_backoff_reservation);
* buffers in different orders.
*/
-int ttm_eu_reserve_buffers(struct list_head *list)
+int ttm_eu_reserve_buffers(struct ww_acquire_ctx *ticket,
+ struct list_head *list)
{
struct ttm_bo_global *glob;
struct ttm_validate_buffer *entry;
int ret;
- uint32_t val_seq;
if (list_empty(list))
return 0;
@@ -129,9 +130,7 @@ int ttm_eu_reserve_buffers(struct list_head *list)
entry = list_first_entry(list, struct ttm_validate_buffer, head);
glob = entry->bo->glob;
- spin_lock(&glob->lru_lock);
- val_seq = entry->bo->bdev->val_seq++;
-
+ ww_acquire_init(ticket, &reservation_ww_class);
retry:
list_for_each_entry(entry, list, head) {
struct ttm_buffer_object *bo = entry->bo;
@@ -140,49 +139,34 @@ retry:
if (entry->reserved)
continue;
- ret = ttm_bo_reserve_nolru(bo, true, true, true, val_seq);
- switch (ret) {
- case 0:
- break;
- case -EBUSY:
- ttm_eu_del_from_lru_locked(list);
- spin_unlock(&glob->lru_lock);
- ret = ttm_bo_reserve_nolru(bo, true, false,
- true, val_seq);
- spin_lock(&glob->lru_lock);
- if (!ret)
- break;
-
- if (unlikely(ret != -EAGAIN))
- goto err;
- /* fallthrough */
- case -EAGAIN:
- ttm_eu_backoff_reservation_locked(list);
+ ret = ttm_bo_reserve_nolru(bo, true, false, true, ticket);
- /*
- * temporarily increase sequence number every retry,
- * to prevent us from seeing our old reservation
- * sequence when someone else reserved the buffer,
- * but hasn't updated the seq_valid/seqno members yet.
+ if (ret == -EDEADLK) {
+ /* uh oh, we lost out, drop every reservation and try
+ * to only reserve this buffer, then start over if
+ * this succeeds.
*/
- val_seq = entry->bo->bdev->val_seq++;
-
+ spin_lock(&glob->lru_lock);
+ ttm_eu_backoff_reservation_locked(list, ticket);
spin_unlock(&glob->lru_lock);
ttm_eu_list_ref_sub(list);
- ret = ttm_bo_reserve_slowpath_nolru(bo, true, val_seq);
- if (unlikely(ret != 0))
- return ret;
- spin_lock(&glob->lru_lock);
+ ret = ww_mutex_lock_slow_interruptible(&bo->resv->lock,
+ ticket);
+ if (unlikely(ret != 0)) {
+ if (ret == -EINTR)
+ ret = -ERESTARTSYS;
+ goto err_fini;
+ }
+
entry->reserved = true;
if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
ret = -EBUSY;
goto err;
}
goto retry;
- default:
+ } else if (ret)
goto err;
- }
entry->reserved = true;
if (unlikely(atomic_read(&bo->cpu_writers) > 0)) {
@@ -191,21 +175,27 @@ retry:
}
}
+ ww_acquire_done(ticket);
+ spin_lock(&glob->lru_lock);
ttm_eu_del_from_lru_locked(list);
spin_unlock(&glob->lru_lock);
ttm_eu_list_ref_sub(list);
-
return 0;
err:
- ttm_eu_backoff_reservation_locked(list);
+ spin_lock(&glob->lru_lock);
+ ttm_eu_backoff_reservation_locked(list, ticket);
spin_unlock(&glob->lru_lock);
ttm_eu_list_ref_sub(list);
+err_fini:
+ ww_acquire_done(ticket);
+ ww_acquire_fini(ticket);
return ret;
}
EXPORT_SYMBOL(ttm_eu_reserve_buffers);
-void ttm_eu_fence_buffer_objects(struct list_head *list, void *sync_obj)
+void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
+ struct list_head *list, void *sync_obj)
{
struct ttm_validate_buffer *entry;
struct ttm_buffer_object *bo;
@@ -228,11 +218,13 @@ void ttm_eu_fence_buffer_objects(struct list_head *list, void *sync_obj)
bo = entry->bo;
entry->old_sync_obj = bo->sync_obj;
bo->sync_obj = driver->sync_obj_ref(sync_obj);
- ttm_bo_unreserve_locked(bo);
+ ttm_bo_add_to_lru(bo);
+ ww_mutex_unlock(&bo->resv->lock);
entry->reserved = false;
}
spin_unlock(&bdev->fence_lock);
spin_unlock(&glob->lru_lock);
+ ww_acquire_fini(ticket);
list_for_each_entry(entry, list, head) {
if (entry->old_sync_obj)
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index dc0c065f8d39..97e9d614700f 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -393,19 +393,6 @@ static struct fb_ops udlfb_ops = {
.fb_release = udl_fb_release,
};
-static void udl_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
- u16 blue, int regno)
-{
-}
-
-static void udl_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
- u16 *blue, int regno)
-{
- *red = 0;
- *green = 0;
- *blue = 0;
-}
-
static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
struct drm_file *file,
unsigned flags, unsigned color,
@@ -558,8 +545,6 @@ out:
}
static struct drm_fb_helper_funcs udl_fb_helper_funcs = {
- .gamma_set = udl_crtc_fb_gamma_set,
- .gamma_get = udl_crtc_fb_gamma_get,
.fb_probe = udlfb_create,
};
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index e96d2349bd54..2ae1eb7d1635 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -363,10 +363,6 @@ static void udl_crtc_destroy(struct drm_crtc *crtc)
kfree(crtc);
}
-static void udl_load_lut(struct drm_crtc *crtc)
-{
-}
-
static void udl_crtc_prepare(struct drm_crtc *crtc)
{
}
@@ -383,7 +379,6 @@ static struct drm_crtc_helper_funcs udl_helper_funcs = {
.prepare = udl_crtc_prepare,
.commit = udl_crtc_commit,
.disable = udl_crtc_disable,
- .load_lut = udl_load_lut,
};
static const struct drm_crtc_funcs udl_crtc_funcs = {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
index 5fae06ad7e25..d4e54fcc0acd 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
@@ -302,7 +302,7 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
uint32_t old_mem_type = bo->mem.mem_type;
int ret;
- BUG_ON(!ttm_bo_is_reserved(bo));
+ lockdep_assert_held(&bo->resv->lock.base);
BUG_ON(old_mem_type != TTM_PL_VRAM &&
old_mem_type != VMW_PL_GMR);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 07dfd823cc30..78e21649d48a 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -565,8 +565,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
dev_priv->has_gmr = false;
}
- dev_priv->mmio_mtrr = drm_mtrr_add(dev_priv->mmio_start,
- dev_priv->mmio_size, DRM_MTRR_WC);
+ dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start,
+ dev_priv->mmio_size);
dev_priv->mmio_virt = ioremap_wc(dev_priv->mmio_start,
dev_priv->mmio_size);
@@ -664,8 +664,7 @@ out_no_device:
out_err4:
iounmap(dev_priv->mmio_virt);
out_err3:
- drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
- dev_priv->mmio_size, DRM_MTRR_WC);
+ arch_phys_wc_del(dev_priv->mmio_mtrr);
if (dev_priv->has_gmr)
(void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
@@ -709,8 +708,7 @@ static int vmw_driver_unload(struct drm_device *dev)
ttm_object_device_release(&dev_priv->tdev);
iounmap(dev_priv->mmio_virt);
- drm_mtrr_del(dev_priv->mmio_mtrr, dev_priv->mmio_start,
- dev_priv->mmio_size, DRM_MTRR_WC);
+ arch_phys_wc_del(dev_priv->mmio_mtrr);
if (dev_priv->has_gmr)
(void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
(void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index 394e6476105b..599f6469a1eb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -1432,6 +1432,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
struct vmw_fence_obj *fence = NULL;
struct vmw_resource *error_resource;
struct list_head resource_list;
+ struct ww_acquire_ctx ticket;
uint32_t handle;
void *cmd;
int ret;
@@ -1488,7 +1489,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
if (unlikely(ret != 0))
goto out_err;
- ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes);
+ ret = ttm_eu_reserve_buffers(&ticket, &sw_context->validate_nodes);
if (unlikely(ret != 0))
goto out_err;
@@ -1537,7 +1538,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
DRM_ERROR("Fence submission error. Syncing.\n");
vmw_resource_list_unreserve(&sw_context->resource_list, false);
- ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
+ ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
(void *) fence);
if (unlikely(dev_priv->pinned_bo != NULL &&
@@ -1570,7 +1571,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
out_err:
vmw_resource_relocations_free(&sw_context->res_relocations);
vmw_free_relocations(sw_context);
- ttm_eu_backoff_reservation(&sw_context->validate_nodes);
+ ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes);
vmw_resource_list_unreserve(&sw_context->resource_list, true);
vmw_clear_validations(sw_context);
if (unlikely(dev_priv->pinned_bo != NULL &&
@@ -1644,6 +1645,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
struct list_head validate_list;
struct ttm_validate_buffer pinned_val, query_val;
struct vmw_fence_obj *lfence = NULL;
+ struct ww_acquire_ctx ticket;
if (dev_priv->pinned_bo == NULL)
goto out_unlock;
@@ -1657,7 +1659,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
list_add_tail(&query_val.head, &validate_list);
do {
- ret = ttm_eu_reserve_buffers(&validate_list);
+ ret = ttm_eu_reserve_buffers(&ticket, &validate_list);
} while (ret == -ERESTARTSYS);
if (unlikely(ret != 0)) {
@@ -1684,7 +1686,7 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
NULL);
fence = lfence;
}
- ttm_eu_fence_buffer_objects(&validate_list, (void *) fence);
+ ttm_eu_fence_buffer_objects(&ticket, &validate_list, (void *) fence);
if (lfence != NULL)
vmw_fence_obj_unreference(&lfence);
@@ -1696,7 +1698,7 @@ out_unlock:
return;
out_no_emit:
- ttm_eu_backoff_reservation(&validate_list);
+ ttm_eu_backoff_reservation(&ticket, &validate_list);
out_no_reserve:
ttm_bo_unref(&query_val.bo);
ttm_bo_unref(&pinned_val.bo);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 3e3c7ab33ca2..d4607b2530d6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -174,7 +174,6 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height)
{
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
- struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_surface *surface = NULL;
struct vmw_dma_buffer *dmabuf = NULL;
@@ -197,6 +196,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
}
if (handle) {
+ struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+
ret = vmw_user_lookup_handle(dev_priv, tfile,
handle, &surface, &dmabuf);
if (ret) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index bc784254e78e..7953d1f90b63 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -958,13 +958,13 @@ void vmw_resource_unreserve(struct vmw_resource *res,
if (new_backup && new_backup != res->backup) {
if (res->backup) {
- BUG_ON(!ttm_bo_is_reserved(&res->backup->base));
+ lockdep_assert_held(&res->backup->base.resv->lock.base);
list_del_init(&res->mob_head);
vmw_dmabuf_unreference(&res->backup);
}
res->backup = vmw_dmabuf_reference(new_backup);
- BUG_ON(!ttm_bo_is_reserved(&new_backup->base));
+ lockdep_assert_held(&new_backup->base.resv->lock.base);
list_add_tail(&res->mob_head, &new_backup->res_list);
}
if (new_backup)
@@ -990,9 +990,11 @@ void vmw_resource_unreserve(struct vmw_resource *res,
* @val_buf: On successful return contains data about the
* reserved and validated backup buffer.
*/
-int vmw_resource_check_buffer(struct vmw_resource *res,
- bool interruptible,
- struct ttm_validate_buffer *val_buf)
+static int
+vmw_resource_check_buffer(struct vmw_resource *res,
+ struct ww_acquire_ctx *ticket,
+ bool interruptible,
+ struct ttm_validate_buffer *val_buf)
{
struct list_head val_list;
bool backup_dirty = false;
@@ -1007,7 +1009,7 @@ int vmw_resource_check_buffer(struct vmw_resource *res,
INIT_LIST_HEAD(&val_list);
val_buf->bo = ttm_bo_reference(&res->backup->base);
list_add_tail(&val_buf->head, &val_list);
- ret = ttm_eu_reserve_buffers(&val_list);
+ ret = ttm_eu_reserve_buffers(ticket, &val_list);
if (unlikely(ret != 0))
goto out_no_reserve;
@@ -1025,7 +1027,7 @@ int vmw_resource_check_buffer(struct vmw_resource *res,
return 0;
out_no_validate:
- ttm_eu_backoff_reservation(&val_list);
+ ttm_eu_backoff_reservation(ticket, &val_list);
out_no_reserve:
ttm_bo_unref(&val_buf->bo);
if (backup_dirty)
@@ -1069,7 +1071,9 @@ int vmw_resource_reserve(struct vmw_resource *res, bool no_backup)
*.
* @val_buf: Backup buffer information.
*/
-void vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf)
+static void
+vmw_resource_backoff_reservation(struct ww_acquire_ctx *ticket,
+ struct ttm_validate_buffer *val_buf)
{
struct list_head val_list;
@@ -1078,7 +1082,7 @@ void vmw_resource_backoff_reservation(struct ttm_validate_buffer *val_buf)
INIT_LIST_HEAD(&val_list);
list_add_tail(&val_buf->head, &val_list);
- ttm_eu_backoff_reservation(&val_list);
+ ttm_eu_backoff_reservation(ticket, &val_list);
ttm_bo_unref(&val_buf->bo);
}
@@ -1092,12 +1096,13 @@ int vmw_resource_do_evict(struct vmw_resource *res)
{
struct ttm_validate_buffer val_buf;
const struct vmw_res_func *func = res->func;
+ struct ww_acquire_ctx ticket;
int ret;
BUG_ON(!func->may_evict);
val_buf.bo = NULL;
- ret = vmw_resource_check_buffer(res, true, &val_buf);
+ ret = vmw_resource_check_buffer(res, &ticket, true, &val_buf);
if (unlikely(ret != 0))
return ret;
@@ -1112,7 +1117,7 @@ int vmw_resource_do_evict(struct vmw_resource *res)
res->backup_dirty = true;
res->res_dirty = false;
out_no_unbind:
- vmw_resource_backoff_reservation(&val_buf);
+ vmw_resource_backoff_reservation(&ticket, &val_buf);
return ret;
}
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index a1607d6e135b..790ddf114e58 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -73,7 +73,7 @@ struct host1x_syncpt_ops {
void (*restore_wait_base)(struct host1x_syncpt *syncpt);
void (*load_wait_base)(struct host1x_syncpt *syncpt);
u32 (*load)(struct host1x_syncpt *syncpt);
- void (*cpu_incr)(struct host1x_syncpt *syncpt);
+ int (*cpu_incr)(struct host1x_syncpt *syncpt);
int (*patch_wait)(struct host1x_syncpt *syncpt, void *patch_addr);
};
@@ -157,10 +157,10 @@ static inline u32 host1x_hw_syncpt_load(struct host1x *host,
return host->syncpt_op->load(sp);
}
-static inline void host1x_hw_syncpt_cpu_incr(struct host1x *host,
- struct host1x_syncpt *sp)
+static inline int host1x_hw_syncpt_cpu_incr(struct host1x *host,
+ struct host1x_syncpt *sp)
{
- host->syncpt_op->cpu_incr(sp);
+ return host->syncpt_op->cpu_incr(sp);
}
static inline int host1x_hw_syncpt_patch_wait(struct host1x *host,
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c
index 8c04943f82e3..5360e5a57ecc 100644
--- a/drivers/gpu/host1x/drm/dc.c
+++ b/drivers/gpu/host1x/drm/dc.c
@@ -79,6 +79,9 @@ static int tegra_plane_disable(struct drm_plane *plane)
struct tegra_plane *p = to_tegra_plane(plane);
unsigned long value;
+ if (!plane->crtc)
+ return 0;
+
value = WINDOW_A_SELECT << p->index;
tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -140,6 +143,7 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
struct drm_framebuffer *fb)
{
+ unsigned int format = tegra_dc_format(fb->pixel_format);
struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
unsigned long value;
@@ -150,6 +154,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
+ tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
value = GENERAL_UPDATE | WIN_A_UPDATE;
tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c
index 2b561c9118c6..e184b00faacd 100644
--- a/drivers/gpu/host1x/drm/drm.c
+++ b/drivers/gpu/host1x/drm/drm.c
@@ -148,6 +148,7 @@ int host1x_drm_init(struct host1x_drm *host1x, struct drm_device *drm)
dev_err(host1x->dev,
"DRM setup failed for %s: %d\n",
dev_name(client->dev), err);
+ mutex_unlock(&host1x->clients_lock);
return err;
}
}
@@ -175,6 +176,7 @@ int host1x_drm_exit(struct host1x_drm *host1x)
dev_err(host1x->dev,
"DRM cleanup failed for %s: %d\n",
dev_name(client->dev), err);
+ mutex_unlock(&host1x->clients_lock);
return err;
}
}
@@ -257,6 +259,13 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (err < 0)
return err;
+ /*
+ * We don't use the drm_irq_install() helpers provided by the DRM
+ * core, so we need to set this manually in order to allow the
+ * DRM_IOCTL_WAIT_VBLANK to operate correctly.
+ */
+ drm->irq_enabled = 1;
+
err = drm_vblank_init(drm, drm->mode_config.num_crtc);
if (err < 0)
return err;
@@ -378,8 +387,7 @@ static int tegra_syncpt_incr(struct drm_device *drm, void *data,
if (!sp)
return -EINVAL;
- host1x_syncpt_incr(sp);
- return 0;
+ return host1x_syncpt_incr(sp);
}
static int tegra_syncpt_wait(struct drm_device *drm, void *data,
@@ -605,7 +613,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor)
#endif
struct drm_driver tegra_drm_driver = {
- .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM,
.load = tegra_drm_load,
.unload = tegra_drm_unload,
.open = tegra_drm_open,
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c
index 6a45ae090ee7..27ffcf15a4b4 100644
--- a/drivers/gpu/host1x/drm/gr2d.c
+++ b/drivers/gpu/host1x/drm/gr2d.c
@@ -84,7 +84,7 @@ static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm,
gem = drm_gem_object_lookup(drm, file, handle);
if (!gem)
- return 0;
+ return NULL;
mutex_lock(&drm->struct_mutex);
drm_gem_object_unreference(gem);
@@ -135,8 +135,10 @@ static int gr2d_submit(struct host1x_drm_context *context,
goto fail;
bo = host1x_bo_lookup(drm, file, cmdbuf.handle);
- if (!bo)
+ if (!bo) {
+ err = -ENOENT;
goto fail;
+ }
host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset);
num_cmdbufs--;
@@ -158,8 +160,10 @@ static int gr2d_submit(struct host1x_drm_context *context,
reloc->cmdbuf = cmdbuf;
reloc->target = target;
- if (!reloc->target || !reloc->cmdbuf)
+ if (!reloc->target || !reloc->cmdbuf) {
+ err = -ENOENT;
goto fail;
+ }
}
err = copy_from_user(job->waitchk, waitchks,
@@ -281,7 +285,7 @@ static int gr2d_probe(struct platform_device *pdev)
if (!gr2d->channel)
return -ENOMEM;
- *syncpts = host1x_syncpt_request(dev, 0);
+ *syncpts = host1x_syncpt_request(dev, false);
if (!(*syncpts)) {
host1x_channel_free(gr2d->channel);
return -ENOMEM;
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c
index 590b69d91dab..2ee4ad55c4db 100644
--- a/drivers/gpu/host1x/hw/cdma_hw.c
+++ b/drivers/gpu/host1x/hw/cdma_hw.c
@@ -44,7 +44,7 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
u32 i;
for (i = 0; i < syncpt_incrs; i++)
- host1x_syncpt_cpu_incr(cdma->timeout.syncpt);
+ host1x_syncpt_incr(cdma->timeout.syncpt);
/* after CPU incr, ensure shadow is up to date */
host1x_syncpt_load(cdma->timeout.syncpt);
diff --git a/drivers/gpu/host1x/hw/syncpt_hw.c b/drivers/gpu/host1x/hw/syncpt_hw.c
index 61174990102a..0cf6095d3367 100644
--- a/drivers/gpu/host1x/hw/syncpt_hw.c
+++ b/drivers/gpu/host1x/hw/syncpt_hw.c
@@ -77,21 +77,19 @@ static u32 syncpt_load(struct host1x_syncpt *sp)
* Write a cpu syncpoint increment to the hardware, without touching
* the cache.
*/
-static void syncpt_cpu_incr(struct host1x_syncpt *sp)
+static int syncpt_cpu_incr(struct host1x_syncpt *sp)
{
struct host1x *host = sp->host;
u32 reg_offset = sp->id / 32;
if (!host1x_syncpt_client_managed(sp) &&
- host1x_syncpt_idle(sp)) {
- dev_err(host->dev, "Trying to increment syncpoint id %d beyond max\n",
- sp->id);
- host1x_debug_dump(sp->host);
- return;
- }
+ host1x_syncpt_idle(sp))
+ return -EINVAL;
host1x_sync_writel(host, BIT_MASK(sp->id),
HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset));
wmb();
+
+ return 0;
}
/* remove a wait pointed to by patch_addr */
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index f665d679031c..cc807667d8f1 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -228,17 +228,15 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
void *cmdbuf_page_addr = NULL;
/* pin & patch the relocs for one gather */
- while (i < job->num_relocs) {
+ for (i = 0; i < job->num_relocs; i++) {
struct host1x_reloc *reloc = &job->relocarray[i];
u32 reloc_addr = (job->reloc_addr_phys[i] +
reloc->target_offset) >> reloc->shift;
u32 *target;
/* skip all other gathers */
- if (!(reloc->cmdbuf && cmdbuf == reloc->cmdbuf)) {
- i++;
+ if (cmdbuf != reloc->cmdbuf)
continue;
- }
if (last_page != reloc->cmdbuf_offset >> PAGE_SHIFT) {
if (cmdbuf_page_addr)
@@ -257,9 +255,6 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
target = cmdbuf_page_addr + (reloc->cmdbuf_offset & ~PAGE_MASK);
*target = reloc_addr;
-
- /* mark this gather as handled */
- reloc->cmdbuf = 0;
}
if (cmdbuf_page_addr)
@@ -268,15 +263,15 @@ static unsigned int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
return 0;
}
-static int check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
+static bool check_reloc(struct host1x_reloc *reloc, struct host1x_bo *cmdbuf,
unsigned int offset)
{
offset *= sizeof(u32);
if (reloc->cmdbuf != cmdbuf || reloc->cmdbuf_offset != offset)
- return -EINVAL;
+ return false;
- return 0;
+ return true;
}
struct host1x_firewall {
@@ -307,10 +302,10 @@ static int check_mask(struct host1x_firewall *fw)
if (mask & 1) {
if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) {
- bool bad_reloc = check_reloc(fw->reloc,
- fw->cmdbuf_id,
- fw->offset);
- if (!fw->num_relocs || bad_reloc)
+ if (!fw->num_relocs)
+ return -EINVAL;
+ if (!check_reloc(fw->reloc, fw->cmdbuf_id,
+ fw->offset))
return -EINVAL;
fw->reloc++;
fw->num_relocs--;
@@ -330,14 +325,14 @@ static int check_incr(struct host1x_firewall *fw)
u32 count = fw->count;
u32 reg = fw->reg;
- while (fw) {
+ while (count) {
if (fw->words == 0)
return -EINVAL;
if (fw->job->is_addr_reg(fw->dev, fw->class, reg)) {
- bool bad_reloc = check_reloc(fw->reloc, fw->cmdbuf_id,
- fw->offset);
- if (!fw->num_relocs || bad_reloc)
+ if (!fw->num_relocs)
+ return -EINVAL;
+ if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset))
return -EINVAL;
fw->reloc++;
fw->num_relocs--;
@@ -361,9 +356,9 @@ static int check_nonincr(struct host1x_firewall *fw)
return -EINVAL;
if (is_addr_reg) {
- bool bad_reloc = check_reloc(fw->reloc, fw->cmdbuf_id,
- fw->offset);
- if (!fw->num_relocs || bad_reloc)
+ if (!fw->num_relocs)
+ return -EINVAL;
+ if (!check_reloc(fw->reloc, fw->cmdbuf_id, fw->offset))
return -EINVAL;
fw->reloc++;
fw->num_relocs--;
@@ -376,69 +371,58 @@ static int check_nonincr(struct host1x_firewall *fw)
return 0;
}
-static int validate(struct host1x_job *job, struct device *dev,
- struct host1x_job_gather *g)
+static int validate(struct host1x_firewall *fw, struct host1x_job_gather *g)
{
- u32 *cmdbuf_base;
+ u32 *cmdbuf_base = (u32 *)fw->job->gather_copy_mapped +
+ (g->offset / sizeof(u32));
int err = 0;
- struct host1x_firewall fw;
- fw.job = job;
- fw.dev = dev;
- fw.reloc = job->relocarray;
- fw.num_relocs = job->num_relocs;
- fw.cmdbuf_id = g->bo;
-
- fw.offset = 0;
- fw.class = 0;
-
- if (!job->is_addr_reg)
+ if (!fw->job->is_addr_reg)
return 0;
- cmdbuf_base = host1x_bo_mmap(g->bo);
- if (!cmdbuf_base)
- return -ENOMEM;
+ fw->words = g->words;
+ fw->cmdbuf_id = g->bo;
+ fw->offset = 0;
- fw.words = g->words;
- while (fw.words && !err) {
- u32 word = cmdbuf_base[fw.offset];
+ while (fw->words && !err) {
+ u32 word = cmdbuf_base[fw->offset];
u32 opcode = (word & 0xf0000000) >> 28;
- fw.mask = 0;
- fw.reg = 0;
- fw.count = 0;
- fw.words--;
- fw.offset++;
+ fw->mask = 0;
+ fw->reg = 0;
+ fw->count = 0;
+ fw->words--;
+ fw->offset++;
switch (opcode) {
case 0:
- fw.class = word >> 6 & 0x3ff;
- fw.mask = word & 0x3f;
- fw.reg = word >> 16 & 0xfff;
- err = check_mask(&fw);
+ fw->class = word >> 6 & 0x3ff;
+ fw->mask = word & 0x3f;
+ fw->reg = word >> 16 & 0xfff;
+ err = check_mask(fw);
if (err)
goto out;
break;
case 1:
- fw.reg = word >> 16 & 0xfff;
- fw.count = word & 0xffff;
- err = check_incr(&fw);
+ fw->reg = word >> 16 & 0xfff;
+ fw->count = word & 0xffff;
+ err = check_incr(fw);
if (err)
goto out;
break;
case 2:
- fw.reg = word >> 16 & 0xfff;
- fw.count = word & 0xffff;
- err = check_nonincr(&fw);
+ fw->reg = word >> 16 & 0xfff;
+ fw->count = word & 0xffff;
+ err = check_nonincr(fw);
if (err)
goto out;
break;
case 3:
- fw.mask = word & 0xffff;
- fw.reg = word >> 16 & 0xfff;
- err = check_mask(&fw);
+ fw->mask = word & 0xffff;
+ fw->reg = word >> 16 & 0xfff;
+ err = check_mask(fw);
if (err)
goto out;
break;
@@ -453,21 +437,26 @@ static int validate(struct host1x_job *job, struct device *dev,
}
/* No relocs should remain at this point */
- if (fw.num_relocs)
+ if (fw->num_relocs)
err = -EINVAL;
out:
- host1x_bo_munmap(g->bo, cmdbuf_base);
-
return err;
}
static inline int copy_gathers(struct host1x_job *job, struct device *dev)
{
+ struct host1x_firewall fw;
size_t size = 0;
size_t offset = 0;
int i;
+ fw.job = job;
+ fw.dev = dev;
+ fw.reloc = job->relocarray;
+ fw.num_relocs = job->num_relocs;
+ fw.class = 0;
+
for (i = 0; i < job->num_gathers; i++) {
struct host1x_job_gather *g = &job->gathers[i];
size += g->words * sizeof(u32);
@@ -488,14 +477,19 @@ static inline int copy_gathers(struct host1x_job *job, struct device *dev)
struct host1x_job_gather *g = &job->gathers[i];
void *gather;
+ /* Copy the gather */
gather = host1x_bo_mmap(g->bo);
memcpy(job->gather_copy_mapped + offset, gather + g->offset,
g->words * sizeof(u32));
host1x_bo_munmap(g->bo, gather);
+ /* Store the location in the buffer */
g->base = job->gather_copy;
g->offset = offset;
- g->bo = NULL;
+
+ /* Validate the job */
+ if (validate(&fw, g))
+ return -EINVAL;
offset += g->words * sizeof(u32);
}
@@ -540,20 +534,11 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
if (job->gathers[j].bo == g->bo)
job->gathers[j].handled = true;
- err = 0;
-
- if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL))
- err = validate(job, dev, g);
-
+ err = do_relocs(job, g->bo);
if (err)
- dev_err(dev, "Job invalid (err=%d)\n", err);
-
- if (!err)
- err = do_relocs(job, g->bo);
-
- if (!err)
- err = do_waitchks(job, host, g->bo);
+ break;
+ err = do_waitchks(job, host, g->bo);
if (err)
break;
}
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index 4b493453e805..409745b949db 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -32,7 +32,7 @@
static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
struct device *dev,
- int client_managed)
+ bool client_managed)
{
int i;
struct host1x_syncpt *sp = host->syncpt;
@@ -40,7 +40,8 @@ static struct host1x_syncpt *_host1x_syncpt_alloc(struct host1x *host,
for (i = 0; i < host->info->nb_pts && sp->name; i++, sp++)
;
- if (sp->dev)
+
+ if (i >= host->info->nb_pts)
return NULL;
name = kasprintf(GFP_KERNEL, "%02d-%s", sp->id,
@@ -128,22 +129,11 @@ u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp)
}
/*
- * Write a cpu syncpoint increment to the hardware, without touching
- * the cache. Caller is responsible for host being powered.
- */
-void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp)
-{
- host1x_hw_syncpt_cpu_incr(sp->host, sp);
-}
-
-/*
* Increment syncpoint value from cpu, updating cache
*/
-void host1x_syncpt_incr(struct host1x_syncpt *sp)
+int host1x_syncpt_incr(struct host1x_syncpt *sp)
{
- if (host1x_syncpt_client_managed(sp))
- host1x_syncpt_incr_max(sp, 1);
- host1x_syncpt_cpu_incr(sp);
+ return host1x_hw_syncpt_cpu_incr(sp->host, sp);
}
/*
@@ -331,7 +321,7 @@ int host1x_syncpt_init(struct host1x *host)
host1x_syncpt_restore(host);
/* Allocate sync point to use for clearing waits for expired fences */
- host->nop_sp = _host1x_syncpt_alloc(host, NULL, 0);
+ host->nop_sp = _host1x_syncpt_alloc(host, NULL, false);
if (!host->nop_sp)
return -ENOMEM;
@@ -339,7 +329,7 @@ int host1x_syncpt_init(struct host1x *host)
}
struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
- int client_managed)
+ bool client_managed)
{
struct host1x *host = dev_get_drvdata(dev->parent);
return _host1x_syncpt_alloc(host, dev, client_managed);
@@ -353,7 +343,7 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
kfree(sp->name);
sp->dev = NULL;
sp->name = NULL;
- sp->client_managed = 0;
+ sp->client_managed = false;
}
void host1x_syncpt_deinit(struct host1x *host)
diff --git a/drivers/gpu/host1x/syncpt.h b/drivers/gpu/host1x/syncpt.h
index c99806130f2e..267c0b9d3647 100644
--- a/drivers/gpu/host1x/syncpt.h
+++ b/drivers/gpu/host1x/syncpt.h
@@ -36,7 +36,7 @@ struct host1x_syncpt {
atomic_t max_val;
u32 base_val;
const char *name;
- int client_managed;
+ bool client_managed;
struct host1x *host;
struct device *dev;
@@ -94,7 +94,7 @@ static inline bool host1x_syncpt_check_max(struct host1x_syncpt *sp, u32 real)
}
/* Return true if sync point is client managed. */
-static inline int host1x_syncpt_client_managed(struct host1x_syncpt *sp)
+static inline bool host1x_syncpt_client_managed(struct host1x_syncpt *sp)
{
return sp->client_managed;
}
@@ -115,9 +115,6 @@ static inline bool host1x_syncpt_idle(struct host1x_syncpt *sp)
/* Return pointer to struct denoting sync point id. */
struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id);
-/* Request incrementing a sync point. */
-void host1x_syncpt_cpu_incr(struct host1x_syncpt *sp);
-
/* Load current value from hardware to the shadow register. */
u32 host1x_syncpt_load(struct host1x_syncpt *sp);
@@ -133,8 +130,8 @@ void host1x_syncpt_restore(struct host1x *host);
/* Read current wait base value into shadow register and return it. */
u32 host1x_syncpt_load_wait_base(struct host1x_syncpt *sp);
-/* Increment sync point and its max. */
-void host1x_syncpt_incr(struct host1x_syncpt *sp);
+/* Request incrementing a sync point. */
+int host1x_syncpt_incr(struct host1x_syncpt *sp);
/* Indicate future operations by incrementing the sync point max. */
u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
@@ -157,7 +154,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp);
/* Allocate a sync point for a device. */
struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
- int client_managed);
+ bool client_managed);
/* Free a sync point. */
void host1x_syncpt_free(struct host1x_syncpt *sp);
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index fb52f3f6de80..14ef6ab69790 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -217,6 +217,13 @@ config HID_ELECOM
---help---
Support for the ELECOM BM084 (bluetooth mouse).
+config HID_ELO
+ tristate "ELO USB 4000/4500 touchscreen"
+ depends on USB_HID
+ ---help---
+ Support for the ELO USB 4000/4500 touchscreens. Note that this is for
+ different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO.
+
config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard" if EXPERT
depends on HID
@@ -231,6 +238,9 @@ config HID_HOLTEK
Support for Holtek based devices:
- Holtek On Line Grip based game controller
- Trust GXT 18 Gaming Keyboard
+ - Sharkoon Drakonia / Perixx MX-2000 gaming mice
+ - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 /
+ Zalman ZM-GM1
config HOLTEK_FF
bool "Holtek On Line Grip force feedback support"
@@ -240,6 +250,12 @@ config HOLTEK_FF
Say Y here if you have a Holtek On Line Grip based game controller
and want to have force feedback support for it.
+config HID_HUION
+ tristate "Huion tablets"
+ depends on USB_HID
+ ---help---
+ Support for Huion 580 tablet.
+
config HID_KEYTOUCH
tristate "Keytouch HID devices"
depends on HID
@@ -561,15 +577,6 @@ config HID_PRIMAX
Support for Primax devices that are not fully compliant with the
HID standard.
-config HID_PS3REMOTE
- tristate "Sony PS3 BD Remote Control"
- depends on HID
- ---help---
- Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
- Harmony Adapter for PS3, which connect over Bluetooth.
-
- Support for the 6-axis controllers is provided by HID_SONY.
-
config HID_ROCCAT
tristate "Roccat device support"
depends on USB_HID
@@ -594,12 +601,17 @@ config HID_SAMSUNG
Support for Samsung InfraRed remote control or keyboards.
config HID_SONY
- tristate "Sony PS3 controller"
+ tristate "Sony PS2/3 accessories"
depends on USB_HID
+ depends on NEW_LEDS
+ depends on LEDS_CLASS
---help---
- Support for Sony PS3 6-axis controllers.
+ Support for
- Support for the Sony PS3 BD Remote is provided by HID_PS3REMOTE.
+ * Sony PS3 6-axis controllers
+ * Buzz controllers
+ * Sony PS3 Blue-ray Disk Remote Control (Bluetooth)
+ * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth)
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
@@ -707,22 +719,29 @@ config HID_WACOM
Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
config HID_WIIMOTE
- tristate "Nintendo Wii Remote support"
+ tristate "Nintendo Wii / Wii U peripherals"
depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
select INPUT_FF_MEMLESS
---help---
- Support for the Nintendo Wii Remote bluetooth device.
+ Support for Nintendo Wii and Wii U Bluetooth peripherals. Supported
+ devices are the Wii Remote and its extension devices, but also devices
+ based on the Wii Remote like the Wii U Pro Controller or the
+ Wii Balance Board.
-config HID_WIIMOTE_EXT
- bool "Nintendo Wii Remote Extension support"
- depends on HID_WIIMOTE
- default HID_WIIMOTE
- ---help---
- Support for extension controllers of the Nintendo Wii Remote. Say yes
- here if you want to use the Nintendo Motion+, Nunchuck or Classic
- extension controllers with your Wii Remote.
+ Support for all official Nintendo extensions is available, however, 3rd
+ party extensions might not be supported. Please report these devices to:
+ http://github.com/dvdhrm/xwiimote/issues
+
+ Other Nintendo Wii U peripherals that are IEEE 802.11 based (including
+ the Wii U Gamepad) might be supported in the future. But currently
+ support is limited to Bluetooth based devices.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hid-wiimote.
config HID_ZEROPLUS
tristate "Zeroplus based game controller support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 2065694f57ab..6f687287e212 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -28,10 +28,7 @@ ifdef CONFIG_LOGIWHEELS_FF
hid-logitech-y += hid-lg4ff.o
endif
-hid-wiimote-y := hid-wiimote-core.o
-ifdef CONFIG_HID_WIIMOTE_EXT
- hid-wiimote-y += hid-wiimote-ext.o
-endif
+hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
ifdef CONFIG_DEBUG_FS
hid-wiimote-y += hid-wiimote-debug.o
endif
@@ -48,10 +45,13 @@ obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o
obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
+obj-$(CONFIG_HID_ELO) += hid-elo.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o
+obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
+obj-$(CONFIG_HID_HUION) += hid-huion.o
obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
obj-$(CONFIG_HID_ICADE) += hid-icade.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
@@ -92,7 +92,6 @@ hid-picolcd-y += hid-picolcd_debugfs.o
endif
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
-obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index feae88b53fcd..c7710b5c69af 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -524,6 +524,12 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 264f55099940..36668d1aca8f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1293,7 +1293,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
ret = hdrv->raw_event(hid, report, data, size);
- if (ret != 0) {
+ if (ret < 0) {
ret = ret < 0 ? ret : 0;
goto unlock;
}
@@ -1547,6 +1547,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1573,6 +1576,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
@@ -1584,10 +1589,14 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
@@ -1680,6 +1689,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
@@ -2042,6 +2053,8 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
@@ -2179,6 +2192,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c
new file mode 100644
index 000000000000..f042a6cf8b18
--- /dev/null
+++ b/drivers/hid/hid-elo.c
@@ -0,0 +1,273 @@
+/*
+ * HID driver for ELO usb touchscreen 4000/4500
+ *
+ * Copyright (c) 2013 Jiri Slaby
+ *
+ * Data parsing taken from elousb driver by Vojtech Pavlik.
+ *
+ * This driver is licensed under the terms of GPLv2.
+ */
+
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+#include "hid-ids.h"
+
+#define ELO_PERIODIC_READ_INTERVAL HZ
+#define ELO_SMARTSET_CMD_TIMEOUT 2000 /* msec */
+
+/* Elo SmartSet commands */
+#define ELO_FLUSH_SMARTSET_RESPONSES 0x02 /* Flush all pending smartset responses */
+#define ELO_SEND_SMARTSET_COMMAND 0x05 /* Send a smartset command */
+#define ELO_GET_SMARTSET_RESPONSE 0x06 /* Get a smartset response */
+#define ELO_DIAG 0x64 /* Diagnostics command */
+#define ELO_SMARTSET_PACKET_SIZE 8
+
+struct elo_priv {
+ struct usb_device *usbdev;
+ struct delayed_work work;
+ unsigned char buffer[ELO_SMARTSET_PACKET_SIZE];
+};
+
+static struct workqueue_struct *wq;
+static bool use_fw_quirk = true;
+module_param(use_fw_quirk, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fw_quirk, "Do periodic pokes for broken M firmwares (default = true)");
+
+static void elo_input_configured(struct hid_device *hdev,
+ struct hid_input *hidinput)
+{
+ struct input_dev *input = hidinput->input;
+
+ set_bit(BTN_TOUCH, input->keybit);
+ set_bit(ABS_PRESSURE, input->absbit);
+ input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0);
+}
+
+static void elo_process_data(struct input_dev *input, const u8 *data, int size)
+{
+ int press;
+
+ input_report_abs(input, ABS_X, (data[3] << 8) | data[2]);
+ input_report_abs(input, ABS_Y, (data[5] << 8) | data[4]);
+
+ press = 0;
+ if (data[1] & 0x80)
+ press = (data[7] << 8) | data[6];
+ input_report_abs(input, ABS_PRESSURE, press);
+
+ if (data[1] & 0x03) {
+ input_report_key(input, BTN_TOUCH, 1);
+ input_sync(input);
+ }
+
+ if (data[1] & 0x04)
+ input_report_key(input, BTN_TOUCH, 0);
+
+ input_sync(input);
+}
+
+static int elo_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ struct hid_input *hidinput;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || list_empty(&hdev->inputs))
+ return 0;
+
+ hidinput = list_first_entry(&hdev->inputs, struct hid_input, list);
+
+ switch (report->id) {
+ case 0:
+ if (data[0] == 'T') { /* Mandatory ELO packet marker */
+ elo_process_data(hidinput->input, data, size);
+ return 1;
+ }
+ break;
+ default: /* unknown report */
+ /* Unknown report type; pass upstream */
+ hid_info(hdev, "unknown report type %d\n", report->id);
+ break;
+ }
+
+ return 0;
+}
+
+static int elo_smartset_send_get(struct usb_device *dev, u8 command,
+ void *data)
+{
+ unsigned int pipe;
+ u8 dir;
+
+ if (command == ELO_SEND_SMARTSET_COMMAND) {
+ pipe = usb_sndctrlpipe(dev, 0);
+ dir = USB_DIR_OUT;
+ } else if (command == ELO_GET_SMARTSET_RESPONSE) {
+ pipe = usb_rcvctrlpipe(dev, 0);
+ dir = USB_DIR_IN;
+ } else
+ return -EINVAL;
+
+ return usb_control_msg(dev, pipe, command,
+ dir | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, data, ELO_SMARTSET_PACKET_SIZE,
+ ELO_SMARTSET_CMD_TIMEOUT);
+}
+
+static int elo_flush_smartset_responses(struct usb_device *dev)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ ELO_FLUSH_SMARTSET_RESPONSES,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+static void elo_work(struct work_struct *work)
+{
+ struct elo_priv *priv = container_of(work, struct elo_priv, work.work);
+ struct usb_device *dev = priv->usbdev;
+ unsigned char *buffer = priv->buffer;
+ int ret;
+
+ ret = elo_flush_smartset_responses(dev);
+ if (ret < 0) {
+ dev_err(&dev->dev, "initial FLUSH_SMARTSET_RESPONSES failed, error %d\n",
+ ret);
+ goto fail;
+ }
+
+ /* send Diagnostics command */
+ *buffer = ELO_DIAG;
+ ret = elo_smartset_send_get(dev, ELO_SEND_SMARTSET_COMMAND, buffer);
+ if (ret < 0) {
+ dev_err(&dev->dev, "send Diagnostics Command failed, error %d\n",
+ ret);
+ goto fail;
+ }
+
+ /* get the result */
+ ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE, buffer);
+ if (ret < 0) {
+ dev_err(&dev->dev, "get Diagnostics Command response failed, error %d\n",
+ ret);
+ goto fail;
+ }
+
+ /* read the ack */
+ if (*buffer != 'A') {
+ ret = elo_smartset_send_get(dev, ELO_GET_SMARTSET_RESPONSE,
+ buffer);
+ if (ret < 0) {
+ dev_err(&dev->dev, "get acknowledge response failed, error %d\n",
+ ret);
+ goto fail;
+ }
+ }
+
+fail:
+ ret = elo_flush_smartset_responses(dev);
+ if (ret < 0)
+ dev_err(&dev->dev, "final FLUSH_SMARTSET_RESPONSES failed, error %d\n",
+ ret);
+ queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);
+}
+
+/*
+ * Not all Elo devices need the periodic HID descriptor reads.
+ * Only firmware version M needs this.
+ */
+static bool elo_broken_firmware(struct usb_device *dev)
+{
+ return use_fw_quirk && le16_to_cpu(dev->descriptor.bcdDevice) == 0x10d;
+}
+
+static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct elo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ INIT_DELAYED_WORK(&priv->work, elo_work);
+ priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
+
+ hid_set_drvdata(hdev, priv);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err_free;
+ }
+
+ if (elo_broken_firmware(priv->usbdev)) {
+ hid_info(hdev, "broken firmware found, installing workaround\n");
+ queue_delayed_work(wq, &priv->work, ELO_PERIODIC_READ_INTERVAL);
+ }
+
+ return 0;
+err_free:
+ kfree(priv);
+ return ret;
+}
+
+static void elo_remove(struct hid_device *hdev)
+{
+ struct elo_priv *priv = hid_get_drvdata(hdev);
+
+ hid_hw_stop(hdev);
+ flush_workqueue(wq);
+ kfree(priv);
+}
+
+static const struct hid_device_id elo_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030), },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, elo_devices);
+
+static struct hid_driver elo_driver = {
+ .name = "elo",
+ .id_table = elo_devices,
+ .probe = elo_probe,
+ .remove = elo_remove,
+ .raw_event = elo_raw_event,
+ .input_configured = elo_input_configured,
+};
+
+static int __init elo_driver_init(void)
+{
+ int ret;
+
+ wq = create_singlethread_workqueue("elousb");
+ if (!wq)
+ return -ENOMEM;
+
+ ret = hid_register_driver(&elo_driver);
+ if (ret)
+ destroy_workqueue(wq);
+
+ return ret;
+}
+module_init(elo_driver_init);
+
+static void __exit elo_driver_exit(void)
+{
+ hid_unregister_driver(&elo_driver);
+ destroy_workqueue(wq);
+}
+module_exit(elo_driver_exit);
+
+MODULE_AUTHOR("Jiri Slaby <jslaby@suse.cz>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-holtek-mouse.c b/drivers/hid/hid-holtek-mouse.c
new file mode 100644
index 000000000000..7e6db3cf46f9
--- /dev/null
+++ b/drivers/hid/hid-holtek-mouse.c
@@ -0,0 +1,77 @@
+/*
+ * HID driver for Holtek gaming mice
+ * Copyright (c) 2013 Christian Ohm
+ * Heavily inspired by various other HID drivers that adjust the report
+ * descriptor.
+*/
+
+/*
+ * 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/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+/*
+ * The report descriptor of some Holtek based gaming mice specifies an
+ * excessively large number of consumer usages (2^15), which is more than
+ * HID_MAX_USAGES. This prevents proper parsing of the report descriptor.
+ *
+ * This driver fixes the report descriptor for:
+ * - USB ID 04d9:a067, sold as Sharkoon Drakonia and Perixx MX-2000
+ * - USB ID 04d9:a04a, sold as Tracer Sniper TRM-503, NOVA Gaming Slider X200
+ * and Zalman ZM-GM1
+ */
+
+static __u8 *holtek_mouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+
+ if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
+ /* Change usage maximum and logical maximum from 0x7fff to
+ * 0x2fff, so they don't exceed HID_MAX_USAGES */
+ switch (hdev->product) {
+ case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067:
+ if (*rsize >= 122 && rdesc[115] == 0xff && rdesc[116] == 0x7f
+ && rdesc[120] == 0xff && rdesc[121] == 0x7f) {
+ hid_info(hdev, "Fixing up report descriptor\n");
+ rdesc[116] = rdesc[121] = 0x2f;
+ }
+ break;
+ case USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A:
+ if (*rsize >= 113 && rdesc[106] == 0xff && rdesc[107] == 0x7f
+ && rdesc[111] == 0xff && rdesc[112] == 0x7f) {
+ hid_info(hdev, "Fixing up report descriptor\n");
+ rdesc[107] = rdesc[112] = 0x2f;
+ }
+ break;
+ }
+
+ }
+ return rdesc;
+}
+
+static const struct hid_device_id holtek_mouse_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+ USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
+ USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, holtek_mouse_devices);
+
+static struct hid_driver holtek_mouse_driver = {
+ .name = "holtek_mouse",
+ .id_table = holtek_mouse_devices,
+ .report_fixup = holtek_mouse_report_fixup,
+};
+
+module_hid_driver(holtek_mouse_driver);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-huion.c b/drivers/hid/hid-huion.c
new file mode 100644
index 000000000000..cbf4da4689ba
--- /dev/null
+++ b/drivers/hid/hid-huion.c
@@ -0,0 +1,177 @@
+/*
+ * HID driver for Huion devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2013 Martin Rusko
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usbhid/usbhid.h"
+
+#include "hid-ids.h"
+
+/* Original Huion 580 report descriptor size */
+#define HUION_580_RDESC_ORIG_SIZE 177
+
+/* Fixed Huion 580 report descriptor */
+static __u8 huion_580_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x07, /* Report ID (7), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x07, /* Logical Maximum (2047), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+static __u8 *huion_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ switch (hdev->product) {
+ case USB_DEVICE_ID_HUION_580:
+ if (*rsize == HUION_580_RDESC_ORIG_SIZE) {
+ rdesc = huion_580_rdesc_fixed;
+ *rsize = sizeof(huion_580_rdesc_fixed);
+ }
+ break;
+ }
+ return rdesc;
+}
+
+/**
+ * Enable fully-functional tablet mode by reading special string
+ * descriptor.
+ *
+ * @hdev: HID device
+ *
+ * The specific string descriptor and data were discovered by sniffing
+ * the Windows driver traffic.
+ */
+static int huion_tablet_enable(struct hid_device *hdev)
+{
+ int rc;
+ char buf[22];
+
+ rc = usb_string(hid_to_usb_dev(hdev), 0x64, buf, sizeof(buf));
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int huion_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+
+ /* Ignore interfaces 1 (mouse) and 2 (keyboard) for Huion 580 tablet,
+ * as they are not used
+ */
+ switch (id->product) {
+ case USB_DEVICE_ID_HUION_580:
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0x00)
+ return -ENODEV;
+ break;
+ }
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ switch (id->product) {
+ case USB_DEVICE_ID_HUION_580:
+ ret = huion_tablet_enable(hdev);
+ if (ret) {
+ hid_err(hdev, "tablet enabling failed\n");
+ goto enabling_err;
+ }
+ break;
+ }
+
+ return 0;
+enabling_err:
+ hid_hw_stop(hdev);
+err:
+ return ret;
+}
+
+static int huion_raw_event(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size)
+{
+ /* If this is a pen input report then invert the in-range bit */
+ if (report->type == HID_INPUT_REPORT && report->id == 0x07 && size >= 2)
+ data[1] ^= 0x40;
+
+ return 0;
+}
+
+static const struct hid_device_id huion_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_580) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, huion_devices);
+
+static struct hid_driver huion_driver = {
+ .name = "huion",
+ .id_table = huion_devices,
+ .probe = huion_probe,
+ .report_fixup = huion_report_fixup,
+ .raw_event = huion_raw_event,
+};
+module_hid_driver(huion_driver);
+
+MODULE_AUTHOR("Martin Rusko");
+MODULE_DESCRIPTION("Huion HID driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index aa3fec0d9dc6..713217380b44 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -199,13 +199,11 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
if (desc->bLength == 0)
goto cleanup;
- input_device->hid_desc = kzalloc(desc->bLength, GFP_ATOMIC);
+ input_device->hid_desc = kmemdup(desc, desc->bLength, GFP_ATOMIC);
if (!input_device->hid_desc)
goto cleanup;
- memcpy(input_device->hid_desc, desc, desc->bLength);
-
input_device->report_desc_size = desc->desc[0].wDescriptorLength;
if (input_device->report_desc_size == 0) {
input_device->dev_info_status = -EINVAL;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 38535c9243d5..ffe4c7ae3340 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -135,6 +135,9 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
+#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0291
+#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0292
+#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0293
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
@@ -248,6 +251,9 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81
#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
+#define USB_VENDOR_ID_DATA_MODUL 0x7374
+#define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201
+
#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
@@ -272,16 +278,15 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E 0x725e
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262 0x7262
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA 0x72aa
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA 0x72aa
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224 0x7224
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0
-#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
@@ -425,6 +430,9 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+#define USB_VENDOR_ID_HUION 0x256c
+#define USB_DEVICE_ID_HUION_580 0x006e
+
#define USB_VENDOR_ID_IDEACOM 0x1cb6
#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651
@@ -440,6 +448,8 @@
#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067
+#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
@@ -447,6 +457,10 @@
#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
+#define USB_VENDOR_ID_JABRA 0x0b0e
+#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
+#define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420
+
#define USB_VENDOR_ID_JESS 0x0c45
#define USB_DEVICE_ID_JESS_YUREX 0x1010
@@ -467,6 +481,7 @@
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
+#define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
#define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010
#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011
@@ -734,6 +749,8 @@
#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
+#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002
+#define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000
#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 945b8158ec4c..7480799e535c 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -354,10 +354,10 @@ static int hidinput_get_battery_property(struct power_supply *psy,
dev->battery_report_type);
if (ret != 2) {
- if (ret >= 0)
- ret = -EINVAL;
+ ret = -ENODATA;
break;
}
+ ret = 0;
if (dev->battery_min < dev->battery_max &&
buf[1] >= dev->battery_min &&
@@ -1042,9 +1042,14 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
/*
* Ignore out-of-range values as per HID specification,
- * section 5.10 and 6.2.25
+ * section 5.10 and 6.2.25.
+ *
+ * The logical_minimum < logical_maximum check is done so that we
+ * don't unintentionally discard values sent by devices which
+ * don't specify logical min and max.
*/
if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
+ (field->logical_minimum < field->logical_maximum) &&
(value < field->logical_minimum ||
value > field->logical_maximum)) {
dbg_hid("Ignoring out-of-range value %x\n", value);
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index 6af90dbdc3d4..1e2ee2aa84a0 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -314,6 +314,25 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(easypen_m610x_rdesc_fixed);
}
break;
+ case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
+ /*
+ * the fixup that need to be done:
+ * - change Usage Maximum in the Comsumer Control
+ * (report ID 3) to a reasonable value
+ */
+ if (*rsize >= 135 &&
+ /* Usage Page (Consumer Devices) */
+ rdesc[104] == 0x05 && rdesc[105] == 0x0c &&
+ /* Usage (Consumer Control) */
+ rdesc[106] == 0x09 && rdesc[107] == 0x01 &&
+ /* Usage Maximum > 12287 */
+ rdesc[114] == 0x2a && rdesc[116] > 0x2f) {
+ hid_info(hdev,
+ "fixing up Genius Gila Gaming Mouse "
+ "report descriptor\n");
+ rdesc[116] = 0x2f;
+ }
+ break;
}
return rdesc;
}
@@ -407,6 +426,8 @@ static const struct hid_device_id kye_devices[] = {
USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
USB_DEVICE_ID_KYE_EASYPEN_M610X) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
+ USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
{ }
};
MODULE_DEVICE_TABLE(hid, kye_devices);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index d39a5cede0b0..cb0e361d7a4b 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -1111,6 +1111,11 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
+ /* Data Modul easyMaxTouch */
+ { .driver_data = MT_CLS_DEFAULT,
+ MT_USB_DEVICE(USB_VENDOR_ID_DATA_MODUL,
+ USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH) },
+
/* eGalax devices (resistive) */
{ .driver_data = MT_CLS_EGALAX,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
@@ -1120,34 +1125,40 @@ static const struct hid_device_id mt_devices[] = {
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
/* eGalax devices (capacitive) */
- { .driver_data = MT_CLS_EGALAX,
- MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },
- { .driver_data = MT_CLS_EGALAX_SERIAL,
+ { .driver_data = MT_CLS_EGALAX,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },
- { .driver_data = MT_CLS_EGALAX,
+ { .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },
{ .driver_data = MT_CLS_EGALAX,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
+ { .driver_data = MT_CLS_EGALAX,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },
{ .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) },
+ { .driver_data = MT_CLS_EGALAX,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
{ .driver_data = MT_CLS_EGALAX,
@@ -1162,15 +1173,6 @@ static const struct hid_device_id mt_devices[] = {
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) },
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
/* Elo TouchSystems IntelliTouch Plus panel */
{ .driver_data = MT_CLS_DUAL_CONTACT_ID,
diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c
deleted file mode 100644
index f1239d3c5b14..000000000000
--- a/drivers/hid/hid-ps3remote.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * HID driver for Sony PS3 BD Remote Control
- *
- * Copyright (c) 2012 David Dillow <dave@thedillows.org>
- * Based on a blend of the bluez fakehid user-space code by Marcel Holtmann
- * and other kernel HID drivers.
- */
-
-/*
- * 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.
- */
-
-/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
- * a Bluetooth host, the key combination Start+Enter has to be kept pressed
- * for about 7 seconds with the Bluetooth Host Controller in discovering mode.
- *
- * There will be no PIN request from the device.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-
-#include "hid-ids.h"
-
-static __u8 ps3remote_rdesc[] = {
- 0x05, 0x01, /* GUsagePage Generic Desktop */
- 0x09, 0x05, /* LUsage 0x05 [Game Pad] */
- 0xA1, 0x01, /* MCollection Application (mouse, keyboard) */
-
- /* Use collection 1 for joypad buttons */
- 0xA1, 0x02, /* MCollection Logical (interrelated data) */
-
- /* Ignore the 1st byte, maybe it is used for a controller
- * number but it's not needed for correct operation */
- 0x75, 0x08, /* GReportSize 0x08 [8] */
- 0x95, 0x01, /* GReportCount 0x01 [1] */
- 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
-
- /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these
- * buttons multiple keypresses are allowed */
- 0x05, 0x09, /* GUsagePage Button */
- 0x19, 0x01, /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */
- 0x29, 0x18, /* LUsageMaximum 0x18 [Button 24] */
- 0x14, /* GLogicalMinimum [0] */
- 0x25, 0x01, /* GLogicalMaximum 0x01 [1] */
- 0x75, 0x01, /* GReportSize 0x01 [1] */
- 0x95, 0x18, /* GReportCount 0x18 [24] */
- 0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
-
- 0xC0, /* MEndCollection */
-
- /* Use collection 2 for remote control buttons */
- 0xA1, 0x02, /* MCollection Logical (interrelated data) */
-
- /* 5th byte is used for remote control buttons */
- 0x05, 0x09, /* GUsagePage Button */
- 0x18, /* LUsageMinimum [No button pressed] */
- 0x29, 0xFE, /* LUsageMaximum 0xFE [Button 254] */
- 0x14, /* GLogicalMinimum [0] */
- 0x26, 0xFE, 0x00, /* GLogicalMaximum 0x00FE [254] */
- 0x75, 0x08, /* GReportSize 0x08 [8] */
- 0x95, 0x01, /* GReportCount 0x01 [1] */
- 0x80, /* MInput */
-
- /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at
- * 0xff and 11th is for press indication */
- 0x75, 0x08, /* GReportSize 0x08 [8] */
- 0x95, 0x06, /* GReportCount 0x06 [6] */
- 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
-
- /* 12th byte is for battery strength */
- 0x05, 0x06, /* GUsagePage Generic Device Controls */
- 0x09, 0x20, /* LUsage 0x20 [Battery Strength] */
- 0x14, /* GLogicalMinimum [0] */
- 0x25, 0x05, /* GLogicalMaximum 0x05 [5] */
- 0x75, 0x08, /* GReportSize 0x08 [8] */
- 0x95, 0x01, /* GReportCount 0x01 [1] */
- 0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
-
- 0xC0, /* MEndCollection */
-
- 0xC0 /* MEndCollection [Game Pad] */
-};
-
-static const unsigned int ps3remote_keymap_joypad_buttons[] = {
- [0x01] = KEY_SELECT,
- [0x02] = BTN_THUMBL, /* L3 */
- [0x03] = BTN_THUMBR, /* R3 */
- [0x04] = BTN_START,
- [0x05] = KEY_UP,
- [0x06] = KEY_RIGHT,
- [0x07] = KEY_DOWN,
- [0x08] = KEY_LEFT,
- [0x09] = BTN_TL2, /* L2 */
- [0x0a] = BTN_TR2, /* R2 */
- [0x0b] = BTN_TL, /* L1 */
- [0x0c] = BTN_TR, /* R1 */
- [0x0d] = KEY_OPTION, /* options/triangle */
- [0x0e] = KEY_BACK, /* back/circle */
- [0x0f] = BTN_0, /* cross */
- [0x10] = KEY_SCREEN, /* view/square */
- [0x11] = KEY_HOMEPAGE, /* PS button */
- [0x14] = KEY_ENTER,
-};
-static const unsigned int ps3remote_keymap_remote_buttons[] = {
- [0x00] = KEY_1,
- [0x01] = KEY_2,
- [0x02] = KEY_3,
- [0x03] = KEY_4,
- [0x04] = KEY_5,
- [0x05] = KEY_6,
- [0x06] = KEY_7,
- [0x07] = KEY_8,
- [0x08] = KEY_9,
- [0x09] = KEY_0,
- [0x0e] = KEY_ESC, /* return */
- [0x0f] = KEY_CLEAR,
- [0x16] = KEY_EJECTCD,
- [0x1a] = KEY_MENU, /* top menu */
- [0x28] = KEY_TIME,
- [0x30] = KEY_PREVIOUS,
- [0x31] = KEY_NEXT,
- [0x32] = KEY_PLAY,
- [0x33] = KEY_REWIND, /* scan back */
- [0x34] = KEY_FORWARD, /* scan forward */
- [0x38] = KEY_STOP,
- [0x39] = KEY_PAUSE,
- [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */
- [0x60] = KEY_FRAMEBACK, /* slow/step back */
- [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */
- [0x63] = KEY_SUBTITLE,
- [0x64] = KEY_AUDIO,
- [0x65] = KEY_ANGLE,
- [0x70] = KEY_INFO, /* display */
- [0x80] = KEY_BLUE,
- [0x81] = KEY_RED,
- [0x82] = KEY_GREEN,
- [0x83] = KEY_YELLOW,
-};
-
-static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
- unsigned int *rsize)
-{
- *rsize = sizeof(ps3remote_rdesc);
- return ps3remote_rdesc;
-}
-
-static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- unsigned int key = usage->hid & HID_USAGE;
-
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
- return -1;
-
- switch (usage->collection_index) {
- case 1:
- if (key >= ARRAY_SIZE(ps3remote_keymap_joypad_buttons))
- return -1;
-
- key = ps3remote_keymap_joypad_buttons[key];
- if (!key)
- return -1;
- break;
- case 2:
- if (key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
- return -1;
-
- key = ps3remote_keymap_remote_buttons[key];
- if (!key)
- return -1;
- break;
- default:
- return -1;
- }
-
- hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
- return 1;
-}
-
-static const struct hid_device_id ps3remote_devices[] = {
- /* PS3 BD Remote Control */
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
- /* Logitech Harmony Adapter for PS3 */
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, ps3remote_devices);
-
-static struct hid_driver ps3remote_driver = {
- .name = "ps3_remote",
- .id_table = ps3remote_devices,
- .report_fixup = ps3remote_fixup,
- .input_mapping = ps3remote_mapping,
-};
-module_hid_driver(ps3remote_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Dillow <dave@thedillows.org>, Antonio Ospite <ospite@studenti.unina.it>");
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index b59b3df9ca95..65c4ccfcbd29 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -366,7 +366,7 @@ void roccat_disconnect(int minor)
mutex_lock(&devices_lock);
devices[minor] = NULL;
mutex_unlock(&devices_lock);
-
+
if (device->open) {
hid_hw_close(device->hid);
wake_up_interruptible(&device->wait);
@@ -426,13 +426,23 @@ static int __init roccat_init(void)
if (retval < 0) {
pr_warn("can't get major number\n");
- return retval;
+ goto error;
}
cdev_init(&roccat_cdev, &roccat_ops);
- cdev_add(&roccat_cdev, dev_id, ROCCAT_MAX_DEVICES);
+ retval = cdev_add(&roccat_cdev, dev_id, ROCCAT_MAX_DEVICES);
+ if (retval < 0) {
+ pr_warn("cannot add cdev\n");
+ goto cleanup_alloc_chrdev_region;
+ }
return 0;
+
+
+ cleanup_alloc_chrdev_region:
+ unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+ error:
+ return retval;
}
static void __exit roccat_exit(void)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 312098e4af4f..ecbc74923d06 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1,11 +1,13 @@
/*
- * HID driver for some sony "special" devices
+ * HID driver for Sony / PS2 / PS3 BD devices.
*
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2008 Jiri Slaby
- * Copyright (c) 2006-2008 Jiri Kosina
+ * Copyright (c) 2012 David Dillow <dave@thedillows.org>
+ * Copyright (c) 2006-2013 Jiri Kosina
+ * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com>
*/
/*
@@ -15,17 +17,27 @@
* any later version.
*/
+/* NOTE: in order for the Sony PS3 BD Remote Control to be found by
+ * a Bluetooth host, the key combination Start+Enter has to be kept pressed
+ * for about 7 seconds with the Bluetooth Host Controller in discovering mode.
+ *
+ * There will be no PIN request from the device.
+ */
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/leds.h>
#include "hid-ids.h"
#define VAIO_RDESC_CONSTANT (1 << 0)
#define SIXAXIS_CONTROLLER_USB (1 << 1)
#define SIXAXIS_CONTROLLER_BT (1 << 2)
+#define BUZZ_CONTROLLER (1 << 3)
+#define PS3REMOTE (1 << 4)
static const u8 sixaxis_rdesc_fixup[] = {
0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C,
@@ -55,10 +67,214 @@ static const u8 sixaxis_rdesc_fixup2[] = {
0xb1, 0x02, 0xc0, 0xc0,
};
+static __u8 ps3remote_rdesc[] = {
+ 0x05, 0x01, /* GUsagePage Generic Desktop */
+ 0x09, 0x05, /* LUsage 0x05 [Game Pad] */
+ 0xA1, 0x01, /* MCollection Application (mouse, keyboard) */
+
+ /* Use collection 1 for joypad buttons */
+ 0xA1, 0x02, /* MCollection Logical (interrelated data) */
+
+ /* Ignore the 1st byte, maybe it is used for a controller
+ * number but it's not needed for correct operation */
+ 0x75, 0x08, /* GReportSize 0x08 [8] */
+ 0x95, 0x01, /* GReportCount 0x01 [1] */
+ 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
+
+ /* Bytes from 2nd to 4th are a bitmap for joypad buttons, for these
+ * buttons multiple keypresses are allowed */
+ 0x05, 0x09, /* GUsagePage Button */
+ 0x19, 0x01, /* LUsageMinimum 0x01 [Button 1 (primary/trigger)] */
+ 0x29, 0x18, /* LUsageMaximum 0x18 [Button 24] */
+ 0x14, /* GLogicalMinimum [0] */
+ 0x25, 0x01, /* GLogicalMaximum 0x01 [1] */
+ 0x75, 0x01, /* GReportSize 0x01 [1] */
+ 0x95, 0x18, /* GReportCount 0x18 [24] */
+ 0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
+
+ 0xC0, /* MEndCollection */
+
+ /* Use collection 2 for remote control buttons */
+ 0xA1, 0x02, /* MCollection Logical (interrelated data) */
+
+ /* 5th byte is used for remote control buttons */
+ 0x05, 0x09, /* GUsagePage Button */
+ 0x18, /* LUsageMinimum [No button pressed] */
+ 0x29, 0xFE, /* LUsageMaximum 0xFE [Button 254] */
+ 0x14, /* GLogicalMinimum [0] */
+ 0x26, 0xFE, 0x00, /* GLogicalMaximum 0x00FE [254] */
+ 0x75, 0x08, /* GReportSize 0x08 [8] */
+ 0x95, 0x01, /* GReportCount 0x01 [1] */
+ 0x80, /* MInput */
+
+ /* Ignore bytes from 6th to 11th, 6th to 10th are always constant at
+ * 0xff and 11th is for press indication */
+ 0x75, 0x08, /* GReportSize 0x08 [8] */
+ 0x95, 0x06, /* GReportCount 0x06 [6] */
+ 0x81, 0x01, /* MInput 0x01 (Const[0] Arr[1] Abs[2]) */
+
+ /* 12th byte is for battery strength */
+ 0x05, 0x06, /* GUsagePage Generic Device Controls */
+ 0x09, 0x20, /* LUsage 0x20 [Battery Strength] */
+ 0x14, /* GLogicalMinimum [0] */
+ 0x25, 0x05, /* GLogicalMaximum 0x05 [5] */
+ 0x75, 0x08, /* GReportSize 0x08 [8] */
+ 0x95, 0x01, /* GReportCount 0x01 [1] */
+ 0x81, 0x02, /* MInput 0x02 (Data[0] Var[1] Abs[2]) */
+
+ 0xC0, /* MEndCollection */
+
+ 0xC0 /* MEndCollection [Game Pad] */
+};
+
+static const unsigned int ps3remote_keymap_joypad_buttons[] = {
+ [0x01] = KEY_SELECT,
+ [0x02] = BTN_THUMBL, /* L3 */
+ [0x03] = BTN_THUMBR, /* R3 */
+ [0x04] = BTN_START,
+ [0x05] = KEY_UP,
+ [0x06] = KEY_RIGHT,
+ [0x07] = KEY_DOWN,
+ [0x08] = KEY_LEFT,
+ [0x09] = BTN_TL2, /* L2 */
+ [0x0a] = BTN_TR2, /* R2 */
+ [0x0b] = BTN_TL, /* L1 */
+ [0x0c] = BTN_TR, /* R1 */
+ [0x0d] = KEY_OPTION, /* options/triangle */
+ [0x0e] = KEY_BACK, /* back/circle */
+ [0x0f] = BTN_0, /* cross */
+ [0x10] = KEY_SCREEN, /* view/square */
+ [0x11] = KEY_HOMEPAGE, /* PS button */
+ [0x14] = KEY_ENTER,
+};
+static const unsigned int ps3remote_keymap_remote_buttons[] = {
+ [0x00] = KEY_1,
+ [0x01] = KEY_2,
+ [0x02] = KEY_3,
+ [0x03] = KEY_4,
+ [0x04] = KEY_5,
+ [0x05] = KEY_6,
+ [0x06] = KEY_7,
+ [0x07] = KEY_8,
+ [0x08] = KEY_9,
+ [0x09] = KEY_0,
+ [0x0e] = KEY_ESC, /* return */
+ [0x0f] = KEY_CLEAR,
+ [0x16] = KEY_EJECTCD,
+ [0x1a] = KEY_MENU, /* top menu */
+ [0x28] = KEY_TIME,
+ [0x30] = KEY_PREVIOUS,
+ [0x31] = KEY_NEXT,
+ [0x32] = KEY_PLAY,
+ [0x33] = KEY_REWIND, /* scan back */
+ [0x34] = KEY_FORWARD, /* scan forward */
+ [0x38] = KEY_STOP,
+ [0x39] = KEY_PAUSE,
+ [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */
+ [0x60] = KEY_FRAMEBACK, /* slow/step back */
+ [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */
+ [0x63] = KEY_SUBTITLE,
+ [0x64] = KEY_AUDIO,
+ [0x65] = KEY_ANGLE,
+ [0x70] = KEY_INFO, /* display */
+ [0x80] = KEY_BLUE,
+ [0x81] = KEY_RED,
+ [0x82] = KEY_GREEN,
+ [0x83] = KEY_YELLOW,
+};
+
+static const unsigned int buzz_keymap[] = {
+ /* The controller has 4 remote buzzers, each with one LED and 5
+ * buttons.
+ *
+ * We use the mapping chosen by the controller, which is:
+ *
+ * Key Offset
+ * -------------------
+ * Buzz 1
+ * Blue 5
+ * Orange 4
+ * Green 3
+ * Yellow 2
+ *
+ * So, for example, the orange button on the third buzzer is mapped to
+ * BTN_TRIGGER_HAPPY14
+ */
+ [ 1] = BTN_TRIGGER_HAPPY1,
+ [ 2] = BTN_TRIGGER_HAPPY2,
+ [ 3] = BTN_TRIGGER_HAPPY3,
+ [ 4] = BTN_TRIGGER_HAPPY4,
+ [ 5] = BTN_TRIGGER_HAPPY5,
+ [ 6] = BTN_TRIGGER_HAPPY6,
+ [ 7] = BTN_TRIGGER_HAPPY7,
+ [ 8] = BTN_TRIGGER_HAPPY8,
+ [ 9] = BTN_TRIGGER_HAPPY9,
+ [10] = BTN_TRIGGER_HAPPY10,
+ [11] = BTN_TRIGGER_HAPPY11,
+ [12] = BTN_TRIGGER_HAPPY12,
+ [13] = BTN_TRIGGER_HAPPY13,
+ [14] = BTN_TRIGGER_HAPPY14,
+ [15] = BTN_TRIGGER_HAPPY15,
+ [16] = BTN_TRIGGER_HAPPY16,
+ [17] = BTN_TRIGGER_HAPPY17,
+ [18] = BTN_TRIGGER_HAPPY18,
+ [19] = BTN_TRIGGER_HAPPY19,
+ [20] = BTN_TRIGGER_HAPPY20,
+};
+
struct sony_sc {
unsigned long quirks;
+
+ void *extra;
};
+struct buzz_extra {
+ int led_state;
+ struct led_classdev *leds[4];
+};
+
+static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ *rsize = sizeof(ps3remote_rdesc);
+ return ps3remote_rdesc;
+}
+
+static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ unsigned int key = usage->hid & HID_USAGE;
+
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
+ return -1;
+
+ switch (usage->collection_index) {
+ case 1:
+ if (key >= ARRAY_SIZE(ps3remote_keymap_joypad_buttons))
+ return -1;
+
+ key = ps3remote_keymap_joypad_buttons[key];
+ if (!key)
+ return -1;
+ break;
+ case 2:
+ if (key >= ARRAY_SIZE(ps3remote_keymap_remote_buttons))
+ return -1;
+
+ key = ps3remote_keymap_remote_buttons[key];
+ if (!key)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
+ return 1;
+}
+
+
/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
@@ -95,6 +311,10 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(sixaxis_rdesc_fixup2);
memcpy(rdesc, &sixaxis_rdesc_fixup2, *rsize);
}
+
+ if (sc->quirks & PS3REMOTE)
+ return ps3remote_fixup(hdev, rdesc, rsize);
+
return rdesc;
}
@@ -117,6 +337,41 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report,
return 0;
}
+static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+ if (sc->quirks & BUZZ_CONTROLLER) {
+ unsigned int key = usage->hid & HID_USAGE;
+
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
+ return -1;
+
+ switch (usage->collection_index) {
+ case 1:
+ if (key >= ARRAY_SIZE(buzz_keymap))
+ return -1;
+
+ key = buzz_keymap[key];
+ if (!key)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
+ return 1;
+ }
+
+ if (sc->quirks & PS3REMOTE)
+ return ps3remote_mapping(hdev, hi, field, usage, bit, max);
+
+ return -1;
+}
+
/*
* The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
* like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
@@ -192,11 +447,181 @@ static int sixaxis_set_operational_bt(struct hid_device *hdev)
return hdev->hid_output_raw_report(hdev, buf, sizeof(buf), HID_FEATURE_REPORT);
}
+static void buzz_set_leds(struct hid_device *hdev, int leds)
+{
+ struct list_head *report_list =
+ &hdev->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next,
+ struct hid_report, list);
+ __s32 *value = report->field[0]->value;
+
+ value[0] = 0x00;
+ value[1] = (leds & 1) ? 0xff : 0x00;
+ value[2] = (leds & 2) ? 0xff : 0x00;
+ value[3] = (leds & 4) ? 0xff : 0x00;
+ value[4] = (leds & 8) ? 0xff : 0x00;
+ value[5] = 0x00;
+ value[6] = 0x00;
+ hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
+}
+
+static void buzz_led_set_brightness(struct led_classdev *led,
+ enum led_brightness value)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct sony_sc *drv_data;
+ struct buzz_extra *buzz;
+
+ int n;
+
+ drv_data = hid_get_drvdata(hdev);
+ if (!drv_data || !drv_data->extra) {
+ hid_err(hdev, "No device data\n");
+ return;
+ }
+ buzz = drv_data->extra;
+
+ for (n = 0; n < 4; n++) {
+ if (led == buzz->leds[n]) {
+ int on = !! (buzz->led_state & (1 << n));
+ if (value == LED_OFF && on) {
+ buzz->led_state &= ~(1 << n);
+ buzz_set_leds(hdev, buzz->led_state);
+ } else if (value != LED_OFF && !on) {
+ buzz->led_state |= (1 << n);
+ buzz_set_leds(hdev, buzz->led_state);
+ }
+ break;
+ }
+ }
+}
+
+static enum led_brightness buzz_led_get_brightness(struct led_classdev *led)
+{
+ struct device *dev = led->dev->parent;
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct sony_sc *drv_data;
+ struct buzz_extra *buzz;
+
+ int n;
+ int on = 0;
+
+ drv_data = hid_get_drvdata(hdev);
+ if (!drv_data || !drv_data->extra) {
+ hid_err(hdev, "No device data\n");
+ return LED_OFF;
+ }
+ buzz = drv_data->extra;
+
+ for (n = 0; n < 4; n++) {
+ if (led == buzz->leds[n]) {
+ on = !! (buzz->led_state & (1 << n));
+ break;
+ }
+ }
+
+ return on ? LED_FULL : LED_OFF;
+}
+
+static int buzz_init(struct hid_device *hdev)
+{
+ struct sony_sc *drv_data;
+ struct buzz_extra *buzz;
+ int n, ret = 0;
+ struct led_classdev *led;
+ size_t name_sz;
+ char *name;
+
+ drv_data = hid_get_drvdata(hdev);
+ BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
+
+ buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
+ if (!buzz) {
+ hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
+ return -ENOMEM;
+ }
+ drv_data->extra = buzz;
+
+ /* Clear LEDs as we have no way of reading their initial state. This is
+ * only relevant if the driver is loaded after somebody actively set the
+ * LEDs to on */
+ buzz_set_leds(hdev, 0x00);
+
+ name_sz = strlen(dev_name(&hdev->dev)) + strlen("::buzz#") + 1;
+
+ for (n = 0; n < 4; n++) {
+ led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
+ if (!led) {
+ hid_err(hdev, "Couldn't allocate memory for LED %d\n", n);
+ goto error_leds;
+ }
+
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz, "%s::buzz%d", dev_name(&hdev->dev), n + 1);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = buzz_led_get_brightness;
+ led->brightness_set = buzz_led_set_brightness;
+
+ if (led_classdev_register(&hdev->dev, led)) {
+ hid_err(hdev, "Failed to register LED %d\n", n);
+ kfree(led);
+ goto error_leds;
+ }
+
+ buzz->leds[n] = led;
+ }
+
+ return ret;
+
+error_leds:
+ for (n = 0; n < 4; n++) {
+ led = buzz->leds[n];
+ buzz->leds[n] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+
+ kfree(drv_data->extra);
+ drv_data->extra = NULL;
+ return ret;
+}
+
+static void buzz_remove(struct hid_device *hdev)
+{
+ struct sony_sc *drv_data;
+ struct buzz_extra *buzz;
+ struct led_classdev *led;
+ int n;
+
+ drv_data = hid_get_drvdata(hdev);
+ BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
+
+ buzz = drv_data->extra;
+
+ for (n = 0; n < 4; n++) {
+ led = buzz->leds[n];
+ buzz->leds[n] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+
+ kfree(drv_data->extra);
+ drv_data->extra = NULL;
+}
+
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
unsigned long quirks = id->driver_data;
struct sony_sc *sc;
+ unsigned int connect_mask = HID_CONNECT_DEFAULT;
sc = kzalloc(sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
@@ -213,8 +638,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
- HID_CONNECT_HIDDEV_FORCE);
+ if (sc->quirks & VAIO_RDESC_CONSTANT)
+ connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+ else if (sc->quirks & SIXAXIS_CONTROLLER_USB)
+ connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+ else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
+ connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+
+ ret = hid_hw_start(hdev, connect_mask);
if (ret) {
hid_err(hdev, "hw start failed\n");
goto err_free;
@@ -226,6 +657,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
ret = sixaxis_set_operational_bt(hdev);
+ else if (sc->quirks & BUZZ_CONTROLLER)
+ ret = buzz_init(hdev);
else
ret = 0;
@@ -242,8 +675,13 @@ err_free:
static void sony_remove(struct hid_device *hdev)
{
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+ if (sc->quirks & BUZZ_CONTROLLER)
+ buzz_remove(hdev);
+
hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
+ kfree(sc);
}
static const struct hid_device_id sony_devices[] = {
@@ -257,17 +695,30 @@ static const struct hid_device_id sony_devices[] = {
.driver_data = VAIO_RDESC_CONSTANT },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE),
.driver_data = VAIO_RDESC_CONSTANT },
+ /* Wired Buzz Controller. Reported as Sony Hub from its USB ID and as
+ * Logitech joystick from the device descriptor. */
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER),
+ .driver_data = BUZZ_CONTROLLER },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER),
+ .driver_data = BUZZ_CONTROLLER },
+ /* PS3 BD Remote Control */
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE),
+ .driver_data = PS3REMOTE },
+ /* Logitech Harmony Adapter for PS3 */
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3),
+ .driver_data = PS3REMOTE },
{ }
};
MODULE_DEVICE_TABLE(hid, sony_devices);
static struct hid_driver sony_driver = {
- .name = "sony",
- .id_table = sony_devices,
- .probe = sony_probe,
- .remove = sony_remove,
- .report_fixup = sony_report_fixup,
- .raw_event = sony_raw_event
+ .name = "sony",
+ .id_table = sony_devices,
+ .input_mapping = sony_mapping,
+ .probe = sony_probe,
+ .remove = sony_remove,
+ .report_fixup = sony_report_fixup,
+ .raw_event = sony_raw_event
};
module_hid_driver(sony_driver);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index a4a8bb0da688..60c75dcbbdb8 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -46,6 +46,7 @@ struct wacom_data {
__u8 battery_capacity;
__u8 power_raw;
__u8 ps_connected;
+ __u8 bat_charging;
struct power_supply battery;
struct power_supply ac;
__u8 led_selector;
@@ -62,6 +63,7 @@ static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_SCOPE,
+ POWER_SUPPLY_PROP_STATUS,
};
static enum power_supply_property wacom_ac_props[] = {
@@ -287,6 +289,15 @@ static int wacom_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = wdata->battery_capacity;
break;
+ case POWER_SUPPLY_PROP_STATUS:
+ if (wdata->bat_charging)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ if (wdata->battery_capacity == 100 && wdata->ps_connected)
+ val->intval = POWER_SUPPLY_STATUS_FULL;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
default:
ret = -EINVAL;
break;
@@ -727,7 +738,8 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
if (power_raw != wdata->power_raw) {
wdata->power_raw = power_raw;
wdata->battery_capacity = batcap_i4[power_raw & 0x07];
- wdata->ps_connected = power_raw & 0x08;
+ wdata->bat_charging = (power_raw & 0x08) ? 1 : 0;
+ wdata->ps_connected = (power_raw & 0x10) ? 1 : 0;
}
break;
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index e5ee1f20bbd9..0c06054cab8f 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -1,6 +1,6 @@
/*
- * HID driver for Nintendo Wiimote devices
- * Copyright (c) 2011 David Herrmann
+ * HID driver for Nintendo Wii / Wii U peripherals
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
*/
/*
@@ -14,53 +14,19 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
-#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include "hid-ids.h"
#include "hid-wiimote.h"
-enum wiiproto_keys {
- WIIPROTO_KEY_LEFT,
- WIIPROTO_KEY_RIGHT,
- WIIPROTO_KEY_UP,
- WIIPROTO_KEY_DOWN,
- WIIPROTO_KEY_PLUS,
- WIIPROTO_KEY_MINUS,
- WIIPROTO_KEY_ONE,
- WIIPROTO_KEY_TWO,
- WIIPROTO_KEY_A,
- WIIPROTO_KEY_B,
- WIIPROTO_KEY_HOME,
- WIIPROTO_KEY_COUNT
-};
-
-static __u16 wiiproto_keymap[] = {
- KEY_LEFT, /* WIIPROTO_KEY_LEFT */
- KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */
- KEY_UP, /* WIIPROTO_KEY_UP */
- KEY_DOWN, /* WIIPROTO_KEY_DOWN */
- KEY_NEXT, /* WIIPROTO_KEY_PLUS */
- KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */
- BTN_1, /* WIIPROTO_KEY_ONE */
- BTN_2, /* WIIPROTO_KEY_TWO */
- BTN_A, /* WIIPROTO_KEY_A */
- BTN_B, /* WIIPROTO_KEY_B */
- BTN_MODE, /* WIIPROTO_KEY_HOME */
-};
+/* output queue handling */
-static enum power_supply_property wiimote_battery_props[] = {
- POWER_SUPPLY_PROP_CAPACITY,
- POWER_SUPPLY_PROP_SCOPE,
-};
-
-static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
- size_t count)
+static int wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
+ size_t count)
{
__u8 *buf;
- ssize_t ret;
+ int ret;
if (!hdev->hid_output_raw_report)
return -ENODEV;
@@ -75,24 +41,33 @@ static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
return ret;
}
-static void wiimote_worker(struct work_struct *work)
+static void wiimote_queue_worker(struct work_struct *work)
{
- struct wiimote_data *wdata = container_of(work, struct wiimote_data,
- worker);
+ struct wiimote_queue *queue = container_of(work, struct wiimote_queue,
+ worker);
+ struct wiimote_data *wdata = container_of(queue, struct wiimote_data,
+ queue);
unsigned long flags;
+ int ret;
- spin_lock_irqsave(&wdata->qlock, flags);
+ spin_lock_irqsave(&wdata->queue.lock, flags);
- while (wdata->head != wdata->tail) {
- spin_unlock_irqrestore(&wdata->qlock, flags);
- wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data,
- wdata->outq[wdata->tail].size);
- spin_lock_irqsave(&wdata->qlock, flags);
+ while (wdata->queue.head != wdata->queue.tail) {
+ spin_unlock_irqrestore(&wdata->queue.lock, flags);
+ ret = wiimote_hid_send(wdata->hdev,
+ wdata->queue.outq[wdata->queue.tail].data,
+ wdata->queue.outq[wdata->queue.tail].size);
+ if (ret < 0) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_abort(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ }
+ spin_lock_irqsave(&wdata->queue.lock, flags);
- wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE;
+ wdata->queue.tail = (wdata->queue.tail + 1) % WIIMOTE_BUFSIZE;
}
- spin_unlock_irqrestore(&wdata->qlock, flags);
+ spin_unlock_irqrestore(&wdata->queue.lock, flags);
}
static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
@@ -103,7 +78,9 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(wdata->hdev, "Sending too large output report\n");
- return;
+
+ spin_lock_irqsave(&wdata->queue.lock, flags);
+ goto out_error;
}
/*
@@ -116,22 +93,28 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
* will reschedule itself until the queue is empty.
*/
- spin_lock_irqsave(&wdata->qlock, flags);
+ spin_lock_irqsave(&wdata->queue.lock, flags);
- memcpy(wdata->outq[wdata->head].data, buffer, count);
- wdata->outq[wdata->head].size = count;
- newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE;
+ memcpy(wdata->queue.outq[wdata->queue.head].data, buffer, count);
+ wdata->queue.outq[wdata->queue.head].size = count;
+ newhead = (wdata->queue.head + 1) % WIIMOTE_BUFSIZE;
- if (wdata->head == wdata->tail) {
- wdata->head = newhead;
- schedule_work(&wdata->worker);
- } else if (newhead != wdata->tail) {
- wdata->head = newhead;
+ if (wdata->queue.head == wdata->queue.tail) {
+ wdata->queue.head = newhead;
+ schedule_work(&wdata->queue.worker);
+ } else if (newhead != wdata->queue.tail) {
+ wdata->queue.head = newhead;
} else {
hid_warn(wdata->hdev, "Output queue is full");
+ goto out_error;
}
- spin_unlock_irqrestore(&wdata->qlock, flags);
+ goto out_unlock;
+
+out_error:
+ wiimote_cmd_abort(wdata);
+out_unlock:
+ spin_unlock_irqrestore(&wdata->queue.lock, flags);
}
/*
@@ -147,7 +130,7 @@ static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1)
*cmd1 |= 0x01;
}
-static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
+void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
{
__u8 cmd[2];
@@ -167,7 +150,7 @@ static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
wiimote_queue(wdata, cmd, sizeof(cmd));
}
-static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
+void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
{
__u8 cmd[2];
@@ -196,17 +179,46 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
* Check what peripherals of the wiimote are currently
* active and select a proper DRM that supports all of
* the requested data inputs.
+ *
+ * Not all combinations are actually supported. The following
+ * combinations work only with limitations:
+ * - IR cam in extended or full mode disables any data transmission
+ * of extension controllers. There is no DRM mode that supports
+ * extension bytes plus extended/full IR.
+ * - IR cam with accelerometer and extension *_EXT8 is not supported.
+ * However, all extensions that need *_EXT8 are devices that don't
+ * support IR cameras. Hence, this shouldn't happen under normal
+ * operation.
+ * - *_EXT16 is only supported in combination with buttons and
+ * accelerometer. No IR or similar can be active simultaneously. As
+ * above, all modules that require it are mutually exclusive with
+ * IR/etc. so this doesn't matter.
*/
static __u8 select_drm(struct wiimote_data *wdata)
{
__u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR;
- bool ext = wiiext_active(wdata);
+ bool ext;
- if (ir == WIIPROTO_FLAG_IR_BASIC) {
- if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
- return WIIPROTO_REQ_DRM_KAIE;
+ ext = (wdata->state.flags & WIIPROTO_FLAG_EXT_USED) ||
+ (wdata->state.flags & WIIPROTO_FLAG_MP_USED);
+
+ /* some 3rd-party balance-boards are hard-coded to KEE, *sigh* */
+ if (wdata->state.devtype == WIIMOTE_DEV_BALANCE_BOARD) {
+ if (ext)
+ return WIIPROTO_REQ_DRM_KEE;
else
+ return WIIPROTO_REQ_DRM_K;
+ }
+
+ if (ir == WIIPROTO_FLAG_IR_BASIC) {
+ if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) {
+ if (ext)
+ return WIIPROTO_REQ_DRM_KAIE;
+ else
+ return WIIPROTO_REQ_DRM_KAI;
+ } else {
return WIIPROTO_REQ_DRM_KIE;
+ }
} else if (ir == WIIPROTO_FLAG_IR_EXT) {
return WIIPROTO_REQ_DRM_KAI;
} else if (ir == WIIPROTO_FLAG_IR_FULL) {
@@ -219,7 +231,7 @@ static __u8 select_drm(struct wiimote_data *wdata)
return WIIPROTO_REQ_DRM_KA;
} else {
if (ext)
- return WIIPROTO_REQ_DRM_KE;
+ return WIIPROTO_REQ_DRM_KEE;
else
return WIIPROTO_REQ_DRM_K;
}
@@ -230,7 +242,9 @@ void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
{
__u8 cmd[3];
- if (drm == WIIPROTO_REQ_NULL)
+ if (wdata->state.flags & WIIPROTO_FLAG_DRM_LOCKED)
+ drm = wdata->state.drm;
+ else if (drm == WIIPROTO_REQ_NULL)
drm = select_drm(wdata);
cmd[0] = WIIPROTO_REQ_DRM;
@@ -242,7 +256,7 @@ void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
wiimote_queue(wdata, cmd, sizeof(cmd));
}
-static void wiiproto_req_status(struct wiimote_data *wdata)
+void wiiproto_req_status(struct wiimote_data *wdata)
{
__u8 cmd[2];
@@ -253,7 +267,7 @@ static void wiiproto_req_status(struct wiimote_data *wdata)
wiimote_queue(wdata, cmd, sizeof(cmd));
}
-static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
+void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
{
accel = !!accel;
if (accel == !!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
@@ -267,7 +281,7 @@ static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
}
-static void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags)
+void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags)
{
__u8 cmd[2];
@@ -278,7 +292,7 @@ static void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags)
wiimote_queue(wdata, cmd, sizeof(cmd));
}
-static void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags)
+void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags)
{
__u8 cmd[2];
@@ -394,399 +408,998 @@ ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, __u8 *rmem,
return ret;
}
-static int wiimote_battery_get_property(struct power_supply *psy,
- enum power_supply_property psp,
- union power_supply_propval *val)
+/* requires the cmd-mutex to be held */
+static int wiimote_cmd_init_ext(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata = container_of(psy,
- struct wiimote_data, battery);
- int ret = 0, state;
- unsigned long flags;
+ __u8 wmem;
+ int ret;
- if (psp == POWER_SUPPLY_PROP_SCOPE) {
- val->intval = POWER_SUPPLY_SCOPE_DEVICE;
- return 0;
- }
+ /* initialize extension */
+ wmem = 0x55;
+ ret = wiimote_cmd_write(wdata, 0xa400f0, &wmem, sizeof(wmem));
+ if (ret)
+ return ret;
- ret = wiimote_cmd_acquire(wdata);
+ /* disable default encryption */
+ wmem = 0x0;
+ ret = wiimote_cmd_write(wdata, 0xa400fb, &wmem, sizeof(wmem));
if (ret)
return ret;
- spin_lock_irqsave(&wdata->state.lock, flags);
- wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
- wiiproto_req_status(wdata);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
+ return 0;
+}
- ret = wiimote_cmd_wait(wdata);
- state = wdata->state.cmd_battery;
- wiimote_cmd_release(wdata);
+/* requires the cmd-mutex to be held */
+static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
+{
+ int ret;
+
+ /* read extension ID */
+ ret = wiimote_cmd_read(wdata, 0xa400fa, rmem, 6);
+ if (ret != 6)
+ return WIIMOTE_EXT_NONE;
+
+ hid_dbg(wdata->hdev, "extension ID: %02x:%02x %02x:%02x %02x:%02x\n",
+ rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
+ if (rmem[0] == 0xff && rmem[1] == 0xff && rmem[2] == 0xff &&
+ rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
+ return WIIMOTE_EXT_NONE;
+
+ if (rmem[4] == 0x00 && rmem[5] == 0x00)
+ return WIIMOTE_EXT_NUNCHUK;
+ if (rmem[4] == 0x01 && rmem[5] == 0x01)
+ return WIIMOTE_EXT_CLASSIC_CONTROLLER;
+ if (rmem[4] == 0x04 && rmem[5] == 0x02)
+ return WIIMOTE_EXT_BALANCE_BOARD;
+ if (rmem[4] == 0x01 && rmem[5] == 0x20)
+ return WIIMOTE_EXT_PRO_CONTROLLER;
+
+ return WIIMOTE_EXT_UNKNOWN;
+}
+
+/* requires the cmd-mutex to be held */
+static int wiimote_cmd_init_mp(struct wiimote_data *wdata)
+{
+ __u8 wmem;
+ int ret;
+
+ /* initialize MP */
+ wmem = 0x55;
+ ret = wiimote_cmd_write(wdata, 0xa600f0, &wmem, sizeof(wmem));
if (ret)
return ret;
- switch (psp) {
- case POWER_SUPPLY_PROP_CAPACITY:
- val->intval = state * 100 / 255;
- break;
- default:
- ret = -EINVAL;
- break;
+ /* disable default encryption */
+ wmem = 0x0;
+ ret = wiimote_cmd_write(wdata, 0xa600fb, &wmem, sizeof(wmem));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* requires the cmd-mutex to be held */
+static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
+{
+ __u8 wmem;
+
+ /* map MP with correct pass-through mode */
+ switch (exttype) {
+ case WIIMOTE_EXT_CLASSIC_CONTROLLER:
+ wmem = 0x07;
+ break;
+ case WIIMOTE_EXT_NUNCHUK:
+ wmem = 0x05;
+ break;
+ default:
+ wmem = 0x04;
+ break;
}
- return ret;
+ return wiimote_cmd_write(wdata, 0xa600fe, &wmem, sizeof(wmem));
}
-static int wiimote_init_ir(struct wiimote_data *wdata, __u16 mode)
+/* requires the cmd-mutex to be held */
+static bool wiimote_cmd_read_mp(struct wiimote_data *wdata, __u8 *rmem)
{
int ret;
- unsigned long flags;
- __u8 format = 0;
- static const __u8 data_enable[] = { 0x01 };
- static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01,
- 0x00, 0xaa, 0x00, 0x64 };
- static const __u8 data_sens2[] = { 0x63, 0x03 };
- static const __u8 data_fin[] = { 0x08 };
- spin_lock_irqsave(&wdata->state.lock, flags);
+ /* read motion plus ID */
+ ret = wiimote_cmd_read(wdata, 0xa600fa, rmem, 6);
+ if (ret != 6)
+ return false;
- if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) {
- spin_unlock_irqrestore(&wdata->state.lock, flags);
- return 0;
- }
+ hid_dbg(wdata->hdev, "motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
+ rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
- if (mode == 0) {
- wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
- wiiproto_req_ir1(wdata, 0);
- wiiproto_req_ir2(wdata, 0);
- wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
- return 0;
- }
+ if (rmem[5] == 0x05)
+ return true;
- spin_unlock_irqrestore(&wdata->state.lock, flags);
+ hid_info(wdata->hdev, "unknown motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
+ rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
- ret = wiimote_cmd_acquire(wdata);
- if (ret)
- return ret;
+ return false;
+}
- /* send PIXEL CLOCK ENABLE cmd first */
- spin_lock_irqsave(&wdata->state.lock, flags);
- wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0);
- wiiproto_req_ir1(wdata, 0x06);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
+/* requires the cmd-mutex to be held */
+static __u8 wiimote_cmd_read_mp_mapped(struct wiimote_data *wdata)
+{
+ int ret;
+ __u8 rmem[6];
- ret = wiimote_cmd_wait(wdata);
- if (ret)
- goto unlock;
- if (wdata->state.cmd_err) {
- ret = -EIO;
- goto unlock;
+ /* read motion plus ID */
+ ret = wiimote_cmd_read(wdata, 0xa400fa, rmem, 6);
+ if (ret != 6)
+ return WIIMOTE_MP_NONE;
+
+ hid_dbg(wdata->hdev, "mapped motion plus ID: %02x:%02x %02x:%02x %02x:%02x\n",
+ rmem[0], rmem[1], rmem[2], rmem[3], rmem[4], rmem[5]);
+
+ if (rmem[0] == 0xff && rmem[1] == 0xff && rmem[2] == 0xff &&
+ rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
+ return WIIMOTE_MP_NONE;
+
+ if (rmem[4] == 0x04 && rmem[5] == 0x05)
+ return WIIMOTE_MP_SINGLE;
+ else if (rmem[4] == 0x05 && rmem[5] == 0x05)
+ return WIIMOTE_MP_PASSTHROUGH_NUNCHUK;
+ else if (rmem[4] == 0x07 && rmem[5] == 0x05)
+ return WIIMOTE_MP_PASSTHROUGH_CLASSIC;
+
+ return WIIMOTE_MP_UNKNOWN;
+}
+
+/* device module handling */
+
+static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = {
+ [WIIMOTE_DEV_PENDING] = (const __u8[]){
+ WIIMOD_NULL,
+ },
+ [WIIMOTE_DEV_UNKNOWN] = (const __u8[]){
+ WIIMOD_NO_MP,
+ WIIMOD_NULL,
+ },
+ [WIIMOTE_DEV_GENERIC] = (const __u8[]){
+ WIIMOD_KEYS,
+ WIIMOD_RUMBLE,
+ WIIMOD_BATTERY,
+ WIIMOD_LED1,
+ WIIMOD_LED2,
+ WIIMOD_LED3,
+ WIIMOD_LED4,
+ WIIMOD_ACCEL,
+ WIIMOD_IR,
+ WIIMOD_NULL,
+ },
+ [WIIMOTE_DEV_GEN10] = (const __u8[]){
+ WIIMOD_KEYS,
+ WIIMOD_RUMBLE,
+ WIIMOD_BATTERY,
+ WIIMOD_LED1,
+ WIIMOD_LED2,
+ WIIMOD_LED3,
+ WIIMOD_LED4,
+ WIIMOD_ACCEL,
+ WIIMOD_IR,
+ WIIMOD_NULL,
+ },
+ [WIIMOTE_DEV_GEN20] = (const __u8[]){
+ WIIMOD_KEYS,
+ WIIMOD_RUMBLE,
+ WIIMOD_BATTERY,
+ WIIMOD_LED1,
+ WIIMOD_LED2,
+ WIIMOD_LED3,
+ WIIMOD_LED4,
+ WIIMOD_ACCEL,
+ WIIMOD_IR,
+ WIIMOD_BUILTIN_MP,
+ WIIMOD_NULL,
+ },
+ [WIIMOTE_DEV_BALANCE_BOARD] = (const __u8[]) {
+ WIIMOD_BATTERY,
+ WIIMOD_LED1,
+ WIIMOD_NO_MP,
+ WIIMOD_NULL,
+ },
+ [WIIMOTE_DEV_PRO_CONTROLLER] = (const __u8[]) {
+ WIIMOD_BATTERY,
+ WIIMOD_LED1,
+ WIIMOD_LED2,
+ WIIMOD_LED3,
+ WIIMOD_LED4,
+ WIIMOD_NO_MP,
+ WIIMOD_NULL,
+ },
+};
+
+static void wiimote_modules_load(struct wiimote_data *wdata,
+ unsigned int devtype)
+{
+ bool need_input = false;
+ const __u8 *mods, *iter;
+ const struct wiimod_ops *ops;
+ int ret;
+
+ mods = wiimote_devtype_mods[devtype];
+
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+ if (wiimod_table[*iter]->flags & WIIMOD_FLAG_INPUT) {
+ need_input = true;
+ break;
+ }
}
- /* enable IR LOGIC */
- spin_lock_irqsave(&wdata->state.lock, flags);
- wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0);
- wiiproto_req_ir2(wdata, 0x06);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
+ if (need_input) {
+ wdata->input = input_allocate_device();
+ if (!wdata->input)
+ return;
+
+ input_set_drvdata(wdata->input, wdata);
+ wdata->input->dev.parent = &wdata->hdev->dev;
+ wdata->input->id.bustype = wdata->hdev->bus;
+ wdata->input->id.vendor = wdata->hdev->vendor;
+ wdata->input->id.product = wdata->hdev->product;
+ wdata->input->id.version = wdata->hdev->version;
+ wdata->input->name = WIIMOTE_NAME;
+ }
- ret = wiimote_cmd_wait(wdata);
- if (ret)
- goto unlock;
- if (wdata->state.cmd_err) {
- ret = -EIO;
- goto unlock;
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+ ops = wiimod_table[*iter];
+ if (!ops->probe)
+ continue;
+
+ ret = ops->probe(ops, wdata);
+ if (ret)
+ goto error;
}
- /* enable IR cam but do not make it send data, yet */
- ret = wiimote_cmd_write(wdata, 0xb00030, data_enable,
- sizeof(data_enable));
- if (ret)
- goto unlock;
+ if (wdata->input) {
+ ret = input_register_device(wdata->input);
+ if (ret)
+ goto error;
+ }
- /* write first sensitivity block */
- ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1,
- sizeof(data_sens1));
- if (ret)
- goto unlock;
+ spin_lock_irq(&wdata->state.lock);
+ wdata->state.devtype = devtype;
+ spin_unlock_irq(&wdata->state.lock);
+ return;
- /* write second sensitivity block */
- ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2,
- sizeof(data_sens2));
- if (ret)
- goto unlock;
+error:
+ for ( ; iter-- != mods; ) {
+ ops = wiimod_table[*iter];
+ if (ops->remove)
+ ops->remove(ops, wdata);
+ }
- /* put IR cam into desired state */
- switch (mode) {
- case WIIPROTO_FLAG_IR_FULL:
- format = 5;
- break;
- case WIIPROTO_FLAG_IR_EXT:
- format = 3;
- break;
- case WIIPROTO_FLAG_IR_BASIC:
- format = 1;
- break;
+ if (wdata->input) {
+ input_free_device(wdata->input);
+ wdata->input = NULL;
}
- ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format));
- if (ret)
- goto unlock;
+}
- /* make IR cam send data */
- ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin));
- if (ret)
- goto unlock;
+static void wiimote_modules_unload(struct wiimote_data *wdata)
+{
+ const __u8 *mods, *iter;
+ const struct wiimod_ops *ops;
+ unsigned long flags;
+
+ mods = wiimote_devtype_mods[wdata->state.devtype];
- /* request new DRM mode compatible to IR mode */
spin_lock_irqsave(&wdata->state.lock, flags);
- wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
- wdata->state.flags |= mode & WIIPROTO_FLAGS_IR;
- wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ wdata->state.devtype = WIIMOTE_DEV_UNKNOWN;
spin_unlock_irqrestore(&wdata->state.lock, flags);
-unlock:
- wiimote_cmd_release(wdata);
- return ret;
+ /* find end of list */
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter)
+ /* empty */ ;
+
+ if (wdata->input) {
+ input_get_device(wdata->input);
+ input_unregister_device(wdata->input);
+ }
+
+ for ( ; iter-- != mods; ) {
+ ops = wiimod_table[*iter];
+ if (ops->remove)
+ ops->remove(ops, wdata);
+ }
+
+ if (wdata->input) {
+ input_put_device(wdata->input);
+ wdata->input = NULL;
+ }
}
-static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
+/* device extension handling */
+
+static void wiimote_ext_load(struct wiimote_data *wdata, unsigned int ext)
{
- struct wiimote_data *wdata;
- struct device *dev = led_dev->dev->parent;
- int i;
unsigned long flags;
- bool value = false;
+ const struct wiimod_ops *ops;
+ int ret;
- wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+ ops = wiimod_ext_table[ext];
- for (i = 0; i < 4; ++i) {
- if (wdata->leds[i] == led_dev) {
- spin_lock_irqsave(&wdata->state.lock, flags);
- value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
- break;
- }
+ if (ops->probe) {
+ ret = ops->probe(ops, wdata);
+ if (ret)
+ ext = WIIMOTE_EXT_UNKNOWN;
}
- return value ? LED_FULL : LED_OFF;
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.exttype = ext;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
}
-static void wiimote_leds_set(struct led_classdev *led_dev,
- enum led_brightness value)
+static void wiimote_ext_unload(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata;
- struct device *dev = led_dev->dev->parent;
- int i;
unsigned long flags;
- __u8 state, flag;
+ const struct wiimod_ops *ops;
- wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+ ops = wiimod_ext_table[wdata->state.exttype];
- for (i = 0; i < 4; ++i) {
- if (wdata->leds[i] == led_dev) {
- flag = WIIPROTO_FLAG_LED(i + 1);
- spin_lock_irqsave(&wdata->state.lock, flags);
- state = wdata->state.flags;
- if (value == LED_OFF)
- wiiproto_req_leds(wdata, state & ~flag);
- else
- wiiproto_req_leds(wdata, state | flag);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
- break;
- }
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.exttype = WIIMOTE_EXT_UNKNOWN;
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ if (ops->remove)
+ ops->remove(ops, wdata);
+}
+
+static void wiimote_mp_load(struct wiimote_data *wdata)
+{
+ unsigned long flags;
+ const struct wiimod_ops *ops;
+ int ret;
+ __u8 mode = 2;
+
+ ops = &wiimod_mp;
+ if (ops->probe) {
+ ret = ops->probe(ops, wdata);
+ if (ret)
+ mode = 1;
}
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.mp = mode;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
}
-static int wiimote_ff_play(struct input_dev *dev, void *data,
- struct ff_effect *eff)
+static void wiimote_mp_unload(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
- __u8 value;
unsigned long flags;
+ const struct wiimod_ops *ops;
- /*
- * The wiimote supports only a single rumble motor so if any magnitude
- * is set to non-zero then we start the rumble motor. If both are set to
- * zero, we stop the rumble motor.
- */
+ if (wdata->state.mp < 2)
+ return;
- if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
- value = 1;
- else
- value = 0;
+ ops = &wiimod_mp;
spin_lock_irqsave(&wdata->state.lock, flags);
- wiiproto_req_rumble(wdata, value);
+ wdata->state.mp = 0;
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_USED;
spin_unlock_irqrestore(&wdata->state.lock, flags);
- return 0;
+ if (ops->remove)
+ ops->remove(ops, wdata);
}
-static int wiimote_input_open(struct input_dev *dev)
-{
- struct wiimote_data *wdata = input_get_drvdata(dev);
+/* device (re-)initialization and detection */
- return hid_hw_open(wdata->hdev);
-}
+static const char *wiimote_devtype_names[WIIMOTE_DEV_NUM] = {
+ [WIIMOTE_DEV_PENDING] = "Pending",
+ [WIIMOTE_DEV_UNKNOWN] = "Unknown",
+ [WIIMOTE_DEV_GENERIC] = "Generic",
+ [WIIMOTE_DEV_GEN10] = "Nintendo Wii Remote (Gen 1)",
+ [WIIMOTE_DEV_GEN20] = "Nintendo Wii Remote Plus (Gen 2)",
+ [WIIMOTE_DEV_BALANCE_BOARD] = "Nintendo Wii Balance Board",
+ [WIIMOTE_DEV_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
+};
-static void wiimote_input_close(struct input_dev *dev)
+/* Try to guess the device type based on all collected information. We
+ * first try to detect by static extension types, then VID/PID and the
+ * device name. If we cannot detect the device, we use
+ * WIIMOTE_DEV_GENERIC so all modules will get probed on the device. */
+static void wiimote_init_set_type(struct wiimote_data *wdata,
+ __u8 exttype)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 devtype = WIIMOTE_DEV_GENERIC;
+ __u16 vendor, product;
+ const char *name;
+
+ vendor = wdata->hdev->vendor;
+ product = wdata->hdev->product;
+ name = wdata->hdev->name;
+
+ if (exttype == WIIMOTE_EXT_BALANCE_BOARD) {
+ devtype = WIIMOTE_DEV_BALANCE_BOARD;
+ goto done;
+ } else if (exttype == WIIMOTE_EXT_PRO_CONTROLLER) {
+ devtype = WIIMOTE_DEV_PRO_CONTROLLER;
+ goto done;
+ }
- hid_hw_close(wdata->hdev);
+ if (!strcmp(name, "Nintendo RVL-CNT-01")) {
+ devtype = WIIMOTE_DEV_GEN10;
+ goto done;
+ } else if (!strcmp(name, "Nintendo RVL-CNT-01-TR")) {
+ devtype = WIIMOTE_DEV_GEN20;
+ goto done;
+ } else if (!strcmp(name, "Nintendo RVL-WBC-01")) {
+ devtype = WIIMOTE_DEV_BALANCE_BOARD;
+ goto done;
+ } else if (!strcmp(name, "Nintendo RVL-CNT-01-UC")) {
+ devtype = WIIMOTE_DEV_PRO_CONTROLLER;
+ goto done;
+ }
+
+ if (vendor == USB_VENDOR_ID_NINTENDO) {
+ if (product == USB_DEVICE_ID_NINTENDO_WIIMOTE) {
+ devtype = WIIMOTE_DEV_GEN10;
+ goto done;
+ } else if (product == USB_DEVICE_ID_NINTENDO_WIIMOTE2) {
+ devtype = WIIMOTE_DEV_GEN20;
+ goto done;
+ }
+ }
+
+done:
+ if (devtype == WIIMOTE_DEV_GENERIC)
+ hid_info(wdata->hdev, "cannot detect device; NAME: %s VID: %04x PID: %04x EXT: %04x\n",
+ name, vendor, product, exttype);
+ else
+ hid_info(wdata->hdev, "detected device: %s\n",
+ wiimote_devtype_names[devtype]);
+
+ wiimote_modules_load(wdata, devtype);
}
-static int wiimote_accel_open(struct input_dev *dev)
+static void wiimote_init_detect(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 exttype = WIIMOTE_EXT_NONE, extdata[6];
+ bool ext;
int ret;
- unsigned long flags;
- ret = hid_hw_open(wdata->hdev);
+ wiimote_cmd_acquire_noint(wdata);
+
+ spin_lock_irq(&wdata->state.lock);
+ wdata->state.devtype = WIIMOTE_DEV_UNKNOWN;
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
+ wiiproto_req_status(wdata);
+ spin_unlock_irq(&wdata->state.lock);
+
+ ret = wiimote_cmd_wait_noint(wdata);
if (ret)
- return ret;
+ goto out_release;
- spin_lock_irqsave(&wdata->state.lock, flags);
- wiiproto_req_accel(wdata, true);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
+ spin_lock_irq(&wdata->state.lock);
+ ext = wdata->state.flags & WIIPROTO_FLAG_EXT_PLUGGED;
+ spin_unlock_irq(&wdata->state.lock);
- return 0;
+ if (!ext)
+ goto out_release;
+
+ wiimote_cmd_init_ext(wdata);
+ exttype = wiimote_cmd_read_ext(wdata, extdata);
+
+out_release:
+ wiimote_cmd_release(wdata);
+ wiimote_init_set_type(wdata, exttype);
+
+ /* schedule MP timer */
+ spin_lock_irq(&wdata->state.lock);
+ if (!(wdata->state.flags & WIIPROTO_FLAG_BUILTIN_MP) &&
+ !(wdata->state.flags & WIIPROTO_FLAG_NO_MP))
+ mod_timer(&wdata->timer, jiffies + HZ * 4);
+ spin_unlock_irq(&wdata->state.lock);
}
-static void wiimote_accel_close(struct input_dev *dev)
+/*
+ * MP hotplug events are not generated by the wiimote. Therefore, we need
+ * polling to detect it. We use a 4s interval for polling MP registers. This
+ * seems reasonable considering applications can trigger it manually via
+ * sysfs requests.
+ */
+static void wiimote_init_poll_mp(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
- unsigned long flags;
+ bool mp;
+ __u8 mpdata[6];
- spin_lock_irqsave(&wdata->state.lock, flags);
- wiiproto_req_accel(wdata, false);
- spin_unlock_irqrestore(&wdata->state.lock, flags);
+ wiimote_cmd_acquire_noint(wdata);
+ wiimote_cmd_init_mp(wdata);
+ mp = wiimote_cmd_read_mp(wdata, mpdata);
+ wiimote_cmd_release(wdata);
- hid_hw_close(wdata->hdev);
+ /* load/unload MP module if it changed */
+ if (mp) {
+ if (!wdata->state.mp) {
+ hid_info(wdata->hdev, "detected extension: Nintendo Wii Motion Plus\n");
+ wiimote_mp_load(wdata);
+ }
+ } else if (wdata->state.mp) {
+ wiimote_mp_unload(wdata);
+ }
+
+ mod_timer(&wdata->timer, jiffies + HZ * 4);
}
-static int wiimote_ir_open(struct input_dev *dev)
+/*
+ * Check whether the wiimote is in the expected state. The extension registers
+ * may change during hotplug and initialization so we might get hotplug events
+ * that we caused by remapping some memory.
+ * We use some heuristics here to check known states. If the wiimote is in the
+ * expected state, we can ignore the hotplug event.
+ *
+ * Returns "true" if the device is in expected state, "false" if we should
+ * redo hotplug handling and extension initialization.
+ */
+static bool wiimote_init_check(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
- int ret;
+ __u32 flags;
+ __u8 type, data[6];
+ bool ret, poll_mp;
- ret = hid_hw_open(wdata->hdev);
- if (ret)
- return ret;
+ spin_lock_irq(&wdata->state.lock);
+ flags = wdata->state.flags;
+ spin_unlock_irq(&wdata->state.lock);
- ret = wiimote_init_ir(wdata, WIIPROTO_FLAG_IR_BASIC);
- if (ret) {
- hid_hw_close(wdata->hdev);
- return ret;
+ wiimote_cmd_acquire_noint(wdata);
+
+ /* If MP is used and active, but the extension is not, we expect:
+ * read_mp_mapped() == WIIMOTE_MP_SINGLE
+ * state.flags == !EXT_ACTIVE && !MP_PLUGGED && MP_ACTIVE
+ * We do not check EXT_PLUGGED because it might change during
+ * initialization of MP without extensions.
+ * - If MP is unplugged/replugged, read_mp_mapped() fails
+ * - If EXT is plugged, MP_PLUGGED will get set */
+ if (wdata->state.exttype == WIIMOTE_EXT_NONE &&
+ wdata->state.mp > 0 && (flags & WIIPROTO_FLAG_MP_USED)) {
+ type = wiimote_cmd_read_mp_mapped(wdata);
+ ret = type == WIIMOTE_MP_SINGLE;
+
+ spin_lock_irq(&wdata->state.lock);
+ ret = ret && !(wdata->state.flags & WIIPROTO_FLAG_EXT_ACTIVE);
+ ret = ret && !(wdata->state.flags & WIIPROTO_FLAG_MP_PLUGGED);
+ ret = ret && (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE);
+ spin_unlock_irq(&wdata->state.lock);
+
+ if (!ret)
+ hid_dbg(wdata->hdev, "state left: !EXT && MP\n");
+
+ /* while MP is mapped, we get EXT_PLUGGED events */
+ poll_mp = false;
+
+ goto out_release;
}
- return 0;
+ /* If MP is unused, but the extension port is used, we expect:
+ * read_ext == state.exttype
+ * state.flags == !MP_ACTIVE && EXT_ACTIVE
+ * - If MP is plugged/unplugged, our timer detects it
+ * - If EXT is unplugged/replugged, EXT_ACTIVE will become unset */
+ if (!(flags & WIIPROTO_FLAG_MP_USED) &&
+ wdata->state.exttype != WIIMOTE_EXT_NONE) {
+ type = wiimote_cmd_read_ext(wdata, data);
+ ret = type == wdata->state.exttype;
+
+ spin_lock_irq(&wdata->state.lock);
+ ret = ret && !(wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE);
+ ret = ret && (wdata->state.flags & WIIPROTO_FLAG_EXT_ACTIVE);
+ spin_unlock_irq(&wdata->state.lock);
+
+ if (!ret)
+ hid_dbg(wdata->hdev, "state left: EXT && !MP\n");
+
+ /* poll MP for hotplug events */
+ poll_mp = true;
+
+ goto out_release;
+ }
+
+ /* If neither MP nor an extension are used, we expect:
+ * read_ext() == WIIMOTE_EXT_NONE
+ * state.flags == !MP_ACTIVE && !EXT_ACTIVE && !EXT_PLUGGED
+ * No need to perform any action in this case as everything is
+ * disabled already.
+ * - If MP is plugged/unplugged, our timer detects it
+ * - If EXT is plugged, EXT_PLUGGED will be set */
+ if (!(flags & WIIPROTO_FLAG_MP_USED) &&
+ wdata->state.exttype == WIIMOTE_EXT_NONE) {
+ type = wiimote_cmd_read_ext(wdata, data);
+ ret = type == wdata->state.exttype;
+
+ spin_lock_irq(&wdata->state.lock);
+ ret = ret && !(wdata->state.flags & WIIPROTO_FLAG_EXT_ACTIVE);
+ ret = ret && !(wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE);
+ ret = ret && !(wdata->state.flags & WIIPROTO_FLAG_EXT_PLUGGED);
+ spin_unlock_irq(&wdata->state.lock);
+
+ if (!ret)
+ hid_dbg(wdata->hdev, "state left: !EXT && !MP\n");
+
+ /* poll MP for hotplug events */
+ poll_mp = true;
+
+ goto out_release;
+ }
+
+ /* The trickiest part is if both EXT and MP are active. We cannot read
+ * the EXT ID, anymore, because MP is mapped over it. However, we use
+ * a handy trick here:
+ * - EXT_ACTIVE is unset whenever !MP_PLUGGED is sent
+ * MP_PLUGGED might be re-sent again before we are scheduled, but
+ * EXT_ACTIVE will stay unset.
+ * So it is enough to check for mp_mapped() and MP_ACTIVE and
+ * EXT_ACTIVE. EXT_PLUGGED is a sanity check. */
+ if (wdata->state.exttype != WIIMOTE_EXT_NONE &&
+ wdata->state.mp > 0 && (flags & WIIPROTO_FLAG_MP_USED)) {
+ type = wiimote_cmd_read_mp_mapped(wdata);
+ ret = type != WIIMOTE_MP_NONE;
+ ret = ret && type != WIIMOTE_MP_UNKNOWN;
+ ret = ret && type != WIIMOTE_MP_SINGLE;
+
+ spin_lock_irq(&wdata->state.lock);
+ ret = ret && (wdata->state.flags & WIIPROTO_FLAG_EXT_PLUGGED);
+ ret = ret && (wdata->state.flags & WIIPROTO_FLAG_EXT_ACTIVE);
+ ret = ret && (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE);
+ spin_unlock_irq(&wdata->state.lock);
+
+ if (!ret)
+ hid_dbg(wdata->hdev, "state left: EXT && MP\n");
+
+ /* while MP is mapped, we get EXT_PLUGGED events */
+ poll_mp = false;
+
+ goto out_release;
+ }
+
+ /* unknown state */
+ ret = false;
+
+out_release:
+ wiimote_cmd_release(wdata);
+
+ /* only poll for MP if requested and if state didn't change */
+ if (ret && poll_mp && !(flags & WIIPROTO_FLAG_BUILTIN_MP) &&
+ !(flags & WIIPROTO_FLAG_NO_MP))
+ wiimote_init_poll_mp(wdata);
+
+ return ret;
}
-static void wiimote_ir_close(struct input_dev *dev)
+static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
+ [WIIMOTE_EXT_NONE] = "None",
+ [WIIMOTE_EXT_UNKNOWN] = "Unknown",
+ [WIIMOTE_EXT_NUNCHUK] = "Nintendo Wii Nunchuk",
+ [WIIMOTE_EXT_CLASSIC_CONTROLLER] = "Nintendo Wii Classic Controller",
+ [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
+ [WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
+};
+
+/*
+ * Handle hotplug events
+ * If we receive an hotplug event and the device-check failed, we deinitialize
+ * the extension ports, re-read all extension IDs and set the device into
+ * the desired state. This involves mapping MP into the main extension
+ * registers, setting up extension passthrough modes and initializing the
+ * requested extensions.
+ */
+static void wiimote_init_hotplug(struct wiimote_data *wdata)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 exttype, extdata[6], mpdata[6];
+ __u32 flags;
+ bool mp;
- wiimote_init_ir(wdata, 0);
- hid_hw_close(wdata->hdev);
+ hid_dbg(wdata->hdev, "detect extensions..\n");
+
+ wiimote_cmd_acquire_noint(wdata);
+
+ spin_lock_irq(&wdata->state.lock);
+
+ /* get state snapshot that we will then work on */
+ flags = wdata->state.flags;
+
+ /* disable event forwarding temporarily */
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_ACTIVE;
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_ACTIVE;
+
+ spin_unlock_irq(&wdata->state.lock);
+
+ /* init extension and MP (deactivates current extension or MP) */
+ wiimote_cmd_init_ext(wdata);
+ if (flags & WIIPROTO_FLAG_NO_MP) {
+ mp = false;
+ } else {
+ wiimote_cmd_init_mp(wdata);
+ mp = wiimote_cmd_read_mp(wdata, mpdata);
+ }
+ exttype = wiimote_cmd_read_ext(wdata, extdata);
+
+ wiimote_cmd_release(wdata);
+
+ /* load/unload extension module if it changed */
+ if (exttype != wdata->state.exttype) {
+ /* unload previous extension */
+ wiimote_ext_unload(wdata);
+
+ if (exttype == WIIMOTE_EXT_UNKNOWN) {
+ hid_info(wdata->hdev, "cannot detect extension; %02x:%02x %02x:%02x %02x:%02x\n",
+ extdata[0], extdata[1], extdata[2],
+ extdata[3], extdata[4], extdata[5]);
+ } else if (exttype == WIIMOTE_EXT_NONE) {
+ spin_lock_irq(&wdata->state.lock);
+ wdata->state.exttype = WIIMOTE_EXT_NONE;
+ spin_unlock_irq(&wdata->state.lock);
+ } else {
+ hid_info(wdata->hdev, "detected extension: %s\n",
+ wiimote_exttype_names[exttype]);
+ /* try loading new extension */
+ wiimote_ext_load(wdata, exttype);
+ }
+ }
+
+ /* load/unload MP module if it changed */
+ if (mp) {
+ if (!wdata->state.mp) {
+ hid_info(wdata->hdev, "detected extension: Nintendo Wii Motion Plus\n");
+ wiimote_mp_load(wdata);
+ }
+ } else if (wdata->state.mp) {
+ wiimote_mp_unload(wdata);
+ }
+
+ /* if MP is not used, do not map or activate it */
+ if (!(flags & WIIPROTO_FLAG_MP_USED))
+ mp = false;
+
+ /* map MP into main extension registers if used */
+ if (mp) {
+ wiimote_cmd_acquire_noint(wdata);
+ wiimote_cmd_map_mp(wdata, exttype);
+ wiimote_cmd_release(wdata);
+
+ /* delete MP hotplug timer */
+ del_timer_sync(&wdata->timer);
+ } else {
+ /* reschedule MP hotplug timer */
+ if (!(flags & WIIPROTO_FLAG_BUILTIN_MP) &&
+ !(flags & WIIPROTO_FLAG_NO_MP))
+ mod_timer(&wdata->timer, jiffies + HZ * 4);
+ }
+
+ spin_lock_irq(&wdata->state.lock);
+
+ /* enable data forwarding again and set expected hotplug state */
+ if (mp) {
+ wdata->state.flags |= WIIPROTO_FLAG_MP_ACTIVE;
+ if (wdata->state.exttype == WIIMOTE_EXT_NONE) {
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_PLUGGED;
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_PLUGGED;
+ } else {
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_PLUGGED;
+ wdata->state.flags |= WIIPROTO_FLAG_MP_PLUGGED;
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_ACTIVE;
+ }
+ } else if (wdata->state.exttype != WIIMOTE_EXT_NONE) {
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_ACTIVE;
+ }
+
+ /* request status report for hotplug state updates */
+ wiiproto_req_status(wdata);
+
+ spin_unlock_irq(&wdata->state.lock);
+
+ hid_dbg(wdata->hdev, "detected extensions: MP: %d EXT: %d\n",
+ wdata->state.mp, wdata->state.exttype);
}
-static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
+static void wiimote_init_worker(struct work_struct *work)
+{
+ struct wiimote_data *wdata = container_of(work, struct wiimote_data,
+ init_worker);
+ bool changed = false;
+
+ if (wdata->state.devtype == WIIMOTE_DEV_PENDING) {
+ wiimote_init_detect(wdata);
+ changed = true;
+ }
+
+ if (changed || !wiimote_init_check(wdata))
+ wiimote_init_hotplug(wdata);
+
+ if (changed)
+ kobject_uevent(&wdata->hdev->dev.kobj, KOBJ_CHANGE);
+}
+
+void __wiimote_schedule(struct wiimote_data *wdata)
{
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
- !!(payload[0] & 0x01));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT],
- !!(payload[0] & 0x02));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN],
- !!(payload[0] & 0x04));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP],
- !!(payload[0] & 0x08));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS],
- !!(payload[0] & 0x10));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO],
- !!(payload[1] & 0x01));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE],
- !!(payload[1] & 0x02));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B],
- !!(payload[1] & 0x04));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A],
- !!(payload[1] & 0x08));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS],
- !!(payload[1] & 0x10));
- input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME],
- !!(payload[1] & 0x80));
- input_sync(wdata->input);
+ if (!(wdata->state.flags & WIIPROTO_FLAG_EXITING))
+ schedule_work(&wdata->init_worker);
}
-static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
+static void wiimote_schedule(struct wiimote_data *wdata)
{
- __u16 x, y, z;
+ unsigned long flags;
- if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
- return;
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ __wiimote_schedule(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
- /*
- * payload is: BB BB XX YY ZZ
- * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ
- * contain the upper 8 bits of each value. The lower 2 bits are
- * contained in the buttons data BB BB.
- * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the
- * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y
- * accel value and bit 6 is the second bit of the Z value.
- * The first bit of Y and Z values is not available and always set to 0.
- * 0x200 is returned on no movement.
- */
+static void wiimote_init_timeout(unsigned long arg)
+{
+ struct wiimote_data *wdata = (void*)arg;
- x = payload[2] << 2;
- y = payload[3] << 2;
- z = payload[4] << 2;
+ wiimote_schedule(wdata);
+}
+
+/* protocol handlers */
+
+static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
+{
+ const __u8 *iter, *mods;
+ const struct wiimod_ops *ops;
- x |= (payload[0] >> 5) & 0x3;
- y |= (payload[1] >> 4) & 0x2;
- z |= (payload[1] >> 5) & 0x2;
+ ops = wiimod_ext_table[wdata->state.exttype];
+ if (ops->in_keys) {
+ ops->in_keys(wdata, payload);
+ return;
+ }
- input_report_abs(wdata->accel, ABS_RX, x - 0x200);
- input_report_abs(wdata->accel, ABS_RY, y - 0x200);
- input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
- input_sync(wdata->accel);
+ mods = wiimote_devtype_mods[wdata->state.devtype];
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+ ops = wiimod_table[*iter];
+ if (ops->in_keys) {
+ ops->in_keys(wdata, payload);
+ break;
+ }
+ }
}
-#define ir_to_input0(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
- ABS_HAT0X, ABS_HAT0Y)
-#define ir_to_input1(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
- ABS_HAT1X, ABS_HAT1Y)
-#define ir_to_input2(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
- ABS_HAT2X, ABS_HAT2Y)
-#define ir_to_input3(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
- ABS_HAT3X, ABS_HAT3Y)
+static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
+{
+ const __u8 *iter, *mods;
+ const struct wiimod_ops *ops;
+
+ ops = wiimod_ext_table[wdata->state.exttype];
+ if (ops->in_accel) {
+ ops->in_accel(wdata, payload);
+ return;
+ }
-static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
- bool packed, __u8 xid, __u8 yid)
+ mods = wiimote_devtype_mods[wdata->state.devtype];
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+ ops = wiimod_table[*iter];
+ if (ops->in_accel) {
+ ops->in_accel(wdata, payload);
+ break;
+ }
+ }
+}
+
+static bool valid_ext_handler(const struct wiimod_ops *ops, size_t len)
{
- __u16 x, y;
+ if (!ops->in_ext)
+ return false;
+ if ((ops->flags & WIIMOD_FLAG_EXT8) && len < 8)
+ return false;
+ if ((ops->flags & WIIMOD_FLAG_EXT16) && len < 16)
+ return false;
+
+ return true;
+}
- if (!(wdata->state.flags & WIIPROTO_FLAGS_IR))
+static void handler_ext(struct wiimote_data *wdata, const __u8 *payload,
+ size_t len)
+{
+ static const __u8 invalid[21] = { 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0xff };
+ const __u8 *iter, *mods;
+ const struct wiimod_ops *ops;
+ bool is_mp;
+
+ if (len > 21)
+ len = 21;
+ if (len < 6 || !memcmp(payload, invalid, len))
return;
- /*
- * Basic IR data is encoded into 3 bytes. The first two bytes are the
- * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
- * of both.
- * If data is packed, then the 3rd byte is put first and slightly
- * reordered. This allows to interleave packed and non-packed data to
- * have two IR sets in 5 bytes instead of 6.
- * The resulting 10bit X/Y values are passed to the ABS_HATXY input dev.
- */
+ /* if MP is active, track MP slot hotplugging */
+ if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
+ /* this bit is set for invalid events (eg. during hotplug) */
+ if (payload[5] & 0x01)
+ return;
+
+ if (payload[4] & 0x01) {
+ if (!(wdata->state.flags & WIIPROTO_FLAG_MP_PLUGGED)) {
+ hid_dbg(wdata->hdev, "MP hotplug: 1\n");
+ wdata->state.flags |= WIIPROTO_FLAG_MP_PLUGGED;
+ __wiimote_schedule(wdata);
+ }
+ } else {
+ if (wdata->state.flags & WIIPROTO_FLAG_MP_PLUGGED) {
+ hid_dbg(wdata->hdev, "MP hotplug: 0\n");
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_PLUGGED;
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_ACTIVE;
+ __wiimote_schedule(wdata);
+ }
+ }
- if (packed) {
- x = ir[1] | ((ir[0] & 0x03) << 8);
- y = ir[2] | ((ir[0] & 0x0c) << 6);
+ /* detect MP data that is sent interleaved with EXT data */
+ is_mp = payload[5] & 0x02;
} else {
- x = ir[0] | ((ir[2] & 0x30) << 4);
- y = ir[1] | ((ir[2] & 0xc0) << 2);
+ is_mp = false;
+ }
+
+ /* ignore EXT events if no extension is active */
+ if (!(wdata->state.flags & WIIPROTO_FLAG_EXT_ACTIVE) && !is_mp)
+ return;
+
+ /* try forwarding to extension handler, first */
+ ops = wiimod_ext_table[wdata->state.exttype];
+ if (is_mp && ops->in_mp) {
+ ops->in_mp(wdata, payload);
+ return;
+ } else if (!is_mp && valid_ext_handler(ops, len)) {
+ ops->in_ext(wdata, payload);
+ return;
+ }
+
+ /* try forwarding to MP handler */
+ ops = &wiimod_mp;
+ if (is_mp && ops->in_mp) {
+ ops->in_mp(wdata, payload);
+ return;
+ } else if (!is_mp && valid_ext_handler(ops, len)) {
+ ops->in_ext(wdata, payload);
+ return;
}
- input_report_abs(wdata->ir, xid, x);
- input_report_abs(wdata->ir, yid, y);
+ /* try forwarding to loaded modules */
+ mods = wiimote_devtype_mods[wdata->state.devtype];
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+ ops = wiimod_table[*iter];
+ if (is_mp && ops->in_mp) {
+ ops->in_mp(wdata, payload);
+ return;
+ } else if (!is_mp && valid_ext_handler(ops, len)) {
+ ops->in_ext(wdata, payload);
+ return;
+ }
+ }
+}
+
+#define ir_to_input0(wdata, ir, packed) handler_ir((wdata), (ir), (packed), 0)
+#define ir_to_input1(wdata, ir, packed) handler_ir((wdata), (ir), (packed), 1)
+#define ir_to_input2(wdata, ir, packed) handler_ir((wdata), (ir), (packed), 2)
+#define ir_to_input3(wdata, ir, packed) handler_ir((wdata), (ir), (packed), 3)
+
+static void handler_ir(struct wiimote_data *wdata, const __u8 *payload,
+ bool packed, unsigned int id)
+{
+ const __u8 *iter, *mods;
+ const struct wiimod_ops *ops;
+
+ ops = wiimod_ext_table[wdata->state.exttype];
+ if (ops->in_ir) {
+ ops->in_ir(wdata, payload, packed, id);
+ return;
+ }
+
+ mods = wiimote_devtype_mods[wdata->state.devtype];
+ for (iter = mods; *iter != WIIMOD_NULL; ++iter) {
+ ops = wiimod_table[*iter];
+ if (ops->in_ir) {
+ ops->in_ir(wdata, payload, packed, id);
+ break;
+ }
+ }
}
/* reduced status report with "BB BB" key data only */
@@ -804,12 +1417,27 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
{
handler_status_K(wdata, payload);
- wiiext_event(wdata, payload[2] & 0x02);
+ /* update extension status */
+ if (payload[2] & 0x02) {
+ if (!(wdata->state.flags & WIIPROTO_FLAG_EXT_PLUGGED)) {
+ hid_dbg(wdata->hdev, "EXT hotplug: 1\n");
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_PLUGGED;
+ __wiimote_schedule(wdata);
+ }
+ } else {
+ if (wdata->state.flags & WIIPROTO_FLAG_EXT_PLUGGED) {
+ hid_dbg(wdata->hdev, "EXT hotplug: 0\n");
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_PLUGGED;
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_PLUGGED;
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_ACTIVE;
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_ACTIVE;
+ __wiimote_schedule(wdata);
+ }
+ }
- if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) {
- wdata->state.cmd_battery = payload[5];
+ wdata->state.cmd_battery = payload[5];
+ if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0))
wiimote_cmd_complete(wdata);
- }
}
/* reduced generic report with "BB BB" key data only */
@@ -864,7 +1492,7 @@ static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
static void handler_drm_KE(struct wiimote_data *wdata, const __u8 *payload)
{
handler_keys(wdata, payload);
- wiiext_handle(wdata, &payload[2]);
+ handler_ext(wdata, &payload[2], 8);
}
static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
@@ -875,13 +1503,12 @@ static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
ir_to_input1(wdata, &payload[8], false);
ir_to_input2(wdata, &payload[11], false);
ir_to_input3(wdata, &payload[14], false);
- input_sync(wdata->ir);
}
static void handler_drm_KEE(struct wiimote_data *wdata, const __u8 *payload)
{
handler_keys(wdata, payload);
- wiiext_handle(wdata, &payload[2]);
+ handler_ext(wdata, &payload[2], 19);
}
static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
@@ -891,15 +1518,14 @@ static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
ir_to_input1(wdata, &payload[4], true);
ir_to_input2(wdata, &payload[7], false);
ir_to_input3(wdata, &payload[9], true);
- input_sync(wdata->ir);
- wiiext_handle(wdata, &payload[12]);
+ handler_ext(wdata, &payload[12], 9);
}
static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
{
handler_keys(wdata, payload);
handler_accel(wdata, payload);
- wiiext_handle(wdata, &payload[5]);
+ handler_ext(wdata, &payload[5], 16);
}
static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
@@ -910,13 +1536,12 @@ static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
ir_to_input1(wdata, &payload[7], true);
ir_to_input2(wdata, &payload[10], false);
ir_to_input3(wdata, &payload[12], true);
- input_sync(wdata->ir);
- wiiext_handle(wdata, &payload[15]);
+ handler_ext(wdata, &payload[15], 6);
}
static void handler_drm_E(struct wiimote_data *wdata, const __u8 *payload)
{
- wiiext_handle(wdata, payload);
+ handler_ext(wdata, payload, 21);
}
static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
@@ -929,7 +1554,6 @@ static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
ir_to_input0(wdata, &payload[3], false);
ir_to_input1(wdata, &payload[12], false);
- input_sync(wdata->ir);
}
static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
@@ -950,7 +1574,6 @@ static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
ir_to_input2(wdata, &payload[3], false);
ir_to_input3(wdata, &payload[12], false);
- input_sync(wdata->ir);
}
struct wiiproto_handler {
@@ -1017,177 +1640,136 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
return 0;
}
-static void wiimote_leds_destroy(struct wiimote_data *wdata)
+static ssize_t wiimote_ext_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- int i;
- struct led_classdev *led;
-
- for (i = 0; i < 4; ++i) {
- if (wdata->leds[i]) {
- led = wdata->leds[i];
- wdata->leds[i] = NULL;
- led_classdev_unregister(led);
- kfree(led);
- }
+ struct wiimote_data *wdata = dev_to_wii(dev);
+ __u8 type;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ type = wdata->state.exttype;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ switch (type) {
+ case WIIMOTE_EXT_NONE:
+ return sprintf(buf, "none\n");
+ case WIIMOTE_EXT_NUNCHUK:
+ return sprintf(buf, "nunchuk\n");
+ case WIIMOTE_EXT_CLASSIC_CONTROLLER:
+ return sprintf(buf, "classic\n");
+ case WIIMOTE_EXT_BALANCE_BOARD:
+ return sprintf(buf, "balanceboard\n");
+ case WIIMOTE_EXT_PRO_CONTROLLER:
+ return sprintf(buf, "procontroller\n");
+ case WIIMOTE_EXT_UNKNOWN:
+ /* fallthrough */
+ default:
+ return sprintf(buf, "unknown\n");
}
}
-static int wiimote_leds_create(struct wiimote_data *wdata)
+static ssize_t wiimote_ext_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- int i, ret;
- struct device *dev = &wdata->hdev->dev;
- size_t namesz = strlen(dev_name(dev)) + 9;
- struct led_classdev *led;
- char *name;
+ struct wiimote_data *wdata = dev_to_wii(dev);
- for (i = 0; i < 4; ++i) {
- led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
- if (!led) {
- ret = -ENOMEM;
- goto err;
- }
- name = (void*)&led[1];
- snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
- led->name = name;
- led->brightness = 0;
- led->max_brightness = 1;
- led->brightness_get = wiimote_leds_get;
- led->brightness_set = wiimote_leds_set;
-
- ret = led_classdev_register(dev, led);
- if (ret) {
- kfree(led);
- goto err;
- }
- wdata->leds[i] = led;
+ if (!strcmp(buf, "scan")) {
+ wiimote_schedule(wdata);
+ } else {
+ return -EINVAL;
}
- return 0;
+ return strnlen(buf, PAGE_SIZE);
+}
-err:
- wiimote_leds_destroy(wdata);
- return ret;
+static DEVICE_ATTR(extension, S_IRUGO | S_IWUSR | S_IWGRP, wiimote_ext_show,
+ wiimote_ext_store);
+
+static ssize_t wiimote_dev_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct wiimote_data *wdata = dev_to_wii(dev);
+ __u8 type;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ type = wdata->state.devtype;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ switch (type) {
+ case WIIMOTE_DEV_GENERIC:
+ return sprintf(buf, "generic\n");
+ case WIIMOTE_DEV_GEN10:
+ return sprintf(buf, "gen10\n");
+ case WIIMOTE_DEV_GEN20:
+ return sprintf(buf, "gen20\n");
+ case WIIMOTE_DEV_BALANCE_BOARD:
+ return sprintf(buf, "balanceboard\n");
+ case WIIMOTE_DEV_PRO_CONTROLLER:
+ return sprintf(buf, "procontroller\n");
+ case WIIMOTE_DEV_PENDING:
+ return sprintf(buf, "pending\n");
+ case WIIMOTE_DEV_UNKNOWN:
+ /* fallthrough */
+ default:
+ return sprintf(buf, "unknown\n");
+ }
}
+static DEVICE_ATTR(devtype, S_IRUGO, wiimote_dev_show, NULL);
+
static struct wiimote_data *wiimote_create(struct hid_device *hdev)
{
struct wiimote_data *wdata;
- int i;
wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
if (!wdata)
return NULL;
- wdata->input = input_allocate_device();
- if (!wdata->input)
- goto err;
-
wdata->hdev = hdev;
hid_set_drvdata(hdev, wdata);
- input_set_drvdata(wdata->input, wdata);
- wdata->input->open = wiimote_input_open;
- wdata->input->close = wiimote_input_close;
- wdata->input->dev.parent = &wdata->hdev->dev;
- wdata->input->id.bustype = wdata->hdev->bus;
- wdata->input->id.vendor = wdata->hdev->vendor;
- wdata->input->id.product = wdata->hdev->product;
- wdata->input->id.version = wdata->hdev->version;
- wdata->input->name = WIIMOTE_NAME;
-
- set_bit(EV_KEY, wdata->input->evbit);
- for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
- set_bit(wiiproto_keymap[i], wdata->input->keybit);
-
- set_bit(FF_RUMBLE, wdata->input->ffbit);
- if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play))
- goto err_input;
-
- wdata->accel = input_allocate_device();
- if (!wdata->accel)
- goto err_input;
-
- input_set_drvdata(wdata->accel, wdata);
- wdata->accel->open = wiimote_accel_open;
- wdata->accel->close = wiimote_accel_close;
- wdata->accel->dev.parent = &wdata->hdev->dev;
- wdata->accel->id.bustype = wdata->hdev->bus;
- wdata->accel->id.vendor = wdata->hdev->vendor;
- wdata->accel->id.product = wdata->hdev->product;
- wdata->accel->id.version = wdata->hdev->version;
- wdata->accel->name = WIIMOTE_NAME " Accelerometer";
-
- set_bit(EV_ABS, wdata->accel->evbit);
- set_bit(ABS_RX, wdata->accel->absbit);
- set_bit(ABS_RY, wdata->accel->absbit);
- set_bit(ABS_RZ, wdata->accel->absbit);
- input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
- input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
- input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
-
- wdata->ir = input_allocate_device();
- if (!wdata->ir)
- goto err_ir;
-
- input_set_drvdata(wdata->ir, wdata);
- wdata->ir->open = wiimote_ir_open;
- wdata->ir->close = wiimote_ir_close;
- wdata->ir->dev.parent = &wdata->hdev->dev;
- wdata->ir->id.bustype = wdata->hdev->bus;
- wdata->ir->id.vendor = wdata->hdev->vendor;
- wdata->ir->id.product = wdata->hdev->product;
- wdata->ir->id.version = wdata->hdev->version;
- wdata->ir->name = WIIMOTE_NAME " IR";
-
- set_bit(EV_ABS, wdata->ir->evbit);
- set_bit(ABS_HAT0X, wdata->ir->absbit);
- set_bit(ABS_HAT0Y, wdata->ir->absbit);
- set_bit(ABS_HAT1X, wdata->ir->absbit);
- set_bit(ABS_HAT1Y, wdata->ir->absbit);
- set_bit(ABS_HAT2X, wdata->ir->absbit);
- set_bit(ABS_HAT2Y, wdata->ir->absbit);
- set_bit(ABS_HAT3X, wdata->ir->absbit);
- set_bit(ABS_HAT3Y, wdata->ir->absbit);
- input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4);
- input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4);
-
- spin_lock_init(&wdata->qlock);
- INIT_WORK(&wdata->worker, wiimote_worker);
+ spin_lock_init(&wdata->queue.lock);
+ INIT_WORK(&wdata->queue.worker, wiimote_queue_worker);
spin_lock_init(&wdata->state.lock);
init_completion(&wdata->state.ready);
mutex_init(&wdata->state.sync);
wdata->state.drm = WIIPROTO_REQ_DRM_K;
+ wdata->state.cmd_battery = 0xff;
- return wdata;
+ INIT_WORK(&wdata->init_worker, wiimote_init_worker);
+ setup_timer(&wdata->timer, wiimote_init_timeout, (long)wdata);
-err_ir:
- input_free_device(wdata->accel);
-err_input:
- input_free_device(wdata->input);
-err:
- kfree(wdata);
- return NULL;
+ return wdata;
}
static void wiimote_destroy(struct wiimote_data *wdata)
{
+ unsigned long flags;
+
wiidebug_deinit(wdata);
- wiiext_deinit(wdata);
- wiimote_leds_destroy(wdata);
-
- power_supply_unregister(&wdata->battery);
- kfree(wdata->battery.name);
- input_unregister_device(wdata->accel);
- input_unregister_device(wdata->ir);
- input_unregister_device(wdata->input);
- cancel_work_sync(&wdata->worker);
+
+ /* prevent init_worker from being scheduled again */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_EXITING;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ cancel_work_sync(&wdata->init_worker);
+ del_timer_sync(&wdata->timer);
+
+ device_remove_file(&wdata->hdev->dev, &dev_attr_devtype);
+ device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
+
+ wiimote_mp_unload(wdata);
+ wiimote_ext_unload(wdata);
+ wiimote_modules_unload(wdata);
+ cancel_work_sync(&wdata->queue.worker);
+ hid_hw_close(wdata->hdev);
hid_hw_stop(wdata->hdev);
kfree(wdata);
@@ -1219,62 +1801,32 @@ static int wiimote_hid_probe(struct hid_device *hdev,
goto err;
}
- ret = input_register_device(wdata->accel);
+ ret = hid_hw_open(hdev);
if (ret) {
- hid_err(hdev, "Cannot register input device\n");
+ hid_err(hdev, "cannot start hardware I/O\n");
goto err_stop;
}
- ret = input_register_device(wdata->ir);
- if (ret) {
- hid_err(hdev, "Cannot register input device\n");
- goto err_ir;
- }
-
- ret = input_register_device(wdata->input);
+ ret = device_create_file(&hdev->dev, &dev_attr_extension);
if (ret) {
- hid_err(hdev, "Cannot register input device\n");
- goto err_input;
- }
-
- wdata->battery.properties = wiimote_battery_props;
- wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
- wdata->battery.get_property = wiimote_battery_get_property;
- wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
- wdata->battery.use_for_apm = 0;
- wdata->battery.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s",
- wdata->hdev->uniq);
- if (!wdata->battery.name) {
- ret = -ENOMEM;
- goto err_battery_name;
+ hid_err(hdev, "cannot create sysfs attribute\n");
+ goto err_close;
}
- ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
+ ret = device_create_file(&hdev->dev, &dev_attr_devtype);
if (ret) {
- hid_err(hdev, "Cannot register battery device\n");
- goto err_battery;
+ hid_err(hdev, "cannot create sysfs attribute\n");
+ goto err_ext;
}
- power_supply_powers(&wdata->battery, &hdev->dev);
-
- ret = wiimote_leds_create(wdata);
- if (ret)
- goto err_free;
-
- ret = wiiext_init(wdata);
- if (ret)
- goto err_free;
-
ret = wiidebug_init(wdata);
if (ret)
goto err_free;
hid_info(hdev, "New device registered\n");
- /* by default set led1 after device initialization */
- spin_lock_irq(&wdata->state.lock);
- wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
- spin_unlock_irq(&wdata->state.lock);
+ /* schedule device detection */
+ wiimote_schedule(wdata);
return 0;
@@ -1282,23 +1834,15 @@ err_free:
wiimote_destroy(wdata);
return ret;
-err_battery:
- kfree(wdata->battery.name);
-err_battery_name:
- input_unregister_device(wdata->input);
- wdata->input = NULL;
-err_input:
- input_unregister_device(wdata->ir);
- wdata->ir = NULL;
-err_ir:
- input_unregister_device(wdata->accel);
- wdata->accel = NULL;
+err_ext:
+ device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
+err_close:
+ hid_hw_close(hdev);
err_stop:
hid_hw_stop(hdev);
err:
input_free_device(wdata->ir);
input_free_device(wdata->accel);
- input_free_device(wdata->input);
kfree(wdata);
return ret;
}
@@ -1331,4 +1875,4 @@ module_hid_driver(wiimote_hid_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
-MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver");
+MODULE_DESCRIPTION("Driver for Nintendo Wii / Wii U peripherals");
diff --git a/drivers/hid/hid-wiimote-debug.c b/drivers/hid/hid-wiimote-debug.c
index 90124ffaa2a5..c13fb5bd79e8 100644
--- a/drivers/hid/hid-wiimote-debug.c
+++ b/drivers/hid/hid-wiimote-debug.c
@@ -1,6 +1,6 @@
/*
- * Debug support for HID Nintendo Wiimote devices
- * Copyright (c) 2011 David Herrmann
+ * Debug support for HID Nintendo Wii / Wii U peripherals
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
*/
/*
@@ -127,7 +127,8 @@ static int wiidebug_drm_open(struct inode *i, struct file *f)
static ssize_t wiidebug_drm_write(struct file *f, const char __user *u,
size_t s, loff_t *off)
{
- struct wiimote_debug *dbg = f->private_data;
+ struct seq_file *sf = f->private_data;
+ struct wiimote_debug *dbg = sf->private;
unsigned long flags;
char buf[16];
ssize_t len;
@@ -140,7 +141,7 @@ static ssize_t wiidebug_drm_write(struct file *f, const char __user *u,
if (copy_from_user(buf, u, len))
return -EFAULT;
- buf[15] = 0;
+ buf[len] = 0;
for (i = 0; i < WIIPROTO_REQ_MAX; ++i) {
if (!wiidebug_drmmap[i])
@@ -150,10 +151,13 @@ static ssize_t wiidebug_drm_write(struct file *f, const char __user *u,
}
if (i == WIIPROTO_REQ_MAX)
- i = simple_strtoul(buf, NULL, 10);
+ i = simple_strtoul(buf, NULL, 16);
spin_lock_irqsave(&dbg->wdata->state.lock, flags);
+ dbg->wdata->state.flags &= ~WIIPROTO_FLAG_DRM_LOCKED;
wiiproto_req_drm(dbg->wdata, (__u8) i);
+ if (i != WIIPROTO_REQ_NULL)
+ dbg->wdata->state.flags |= WIIPROTO_FLAG_DRM_LOCKED;
spin_unlock_irqrestore(&dbg->wdata->state.lock, flags);
return len;
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
deleted file mode 100644
index 0472191d4a72..000000000000
--- a/drivers/hid/hid-wiimote-ext.c
+++ /dev/null
@@ -1,849 +0,0 @@
-/*
- * HID driver for Nintendo Wiimote extension devices
- * Copyright (c) 2011 David Herrmann
- */
-
-/*
- * 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/atomic.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include "hid-wiimote.h"
-
-struct wiimote_ext {
- struct wiimote_data *wdata;
- struct work_struct worker;
- struct input_dev *input;
- struct input_dev *mp_input;
-
- atomic_t opened;
- atomic_t mp_opened;
- bool plugged;
- bool mp_plugged;
- bool motionp;
- __u8 ext_type;
- __u16 calib[4][3];
-};
-
-enum wiiext_type {
- WIIEXT_NONE, /* placeholder */
- WIIEXT_CLASSIC, /* Nintendo classic controller */
- WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
- WIIEXT_BALANCE_BOARD, /* Nintendo balance board controller */
-};
-
-enum wiiext_keys {
- WIIEXT_KEY_C,
- WIIEXT_KEY_Z,
- WIIEXT_KEY_A,
- WIIEXT_KEY_B,
- WIIEXT_KEY_X,
- WIIEXT_KEY_Y,
- WIIEXT_KEY_ZL,
- WIIEXT_KEY_ZR,
- WIIEXT_KEY_PLUS,
- WIIEXT_KEY_MINUS,
- WIIEXT_KEY_HOME,
- WIIEXT_KEY_LEFT,
- WIIEXT_KEY_RIGHT,
- WIIEXT_KEY_UP,
- WIIEXT_KEY_DOWN,
- WIIEXT_KEY_LT,
- WIIEXT_KEY_RT,
- WIIEXT_KEY_COUNT
-};
-
-static __u16 wiiext_keymap[] = {
- BTN_C, /* WIIEXT_KEY_C */
- BTN_Z, /* WIIEXT_KEY_Z */
- BTN_A, /* WIIEXT_KEY_A */
- BTN_B, /* WIIEXT_KEY_B */
- BTN_X, /* WIIEXT_KEY_X */
- BTN_Y, /* WIIEXT_KEY_Y */
- BTN_TL2, /* WIIEXT_KEY_ZL */
- BTN_TR2, /* WIIEXT_KEY_ZR */
- KEY_NEXT, /* WIIEXT_KEY_PLUS */
- KEY_PREVIOUS, /* WIIEXT_KEY_MINUS */
- BTN_MODE, /* WIIEXT_KEY_HOME */
- KEY_LEFT, /* WIIEXT_KEY_LEFT */
- KEY_RIGHT, /* WIIEXT_KEY_RIGHT */
- KEY_UP, /* WIIEXT_KEY_UP */
- KEY_DOWN, /* WIIEXT_KEY_DOWN */
- BTN_TL, /* WIIEXT_KEY_LT */
- BTN_TR, /* WIIEXT_KEY_RT */
-};
-
-/* disable all extensions */
-static void ext_disable(struct wiimote_ext *ext)
-{
- unsigned long flags;
- __u8 wmem = 0x55;
-
- if (!wiimote_cmd_acquire(ext->wdata)) {
- wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
- wiimote_cmd_release(ext->wdata);
- }
-
- spin_lock_irqsave(&ext->wdata->state.lock, flags);
- ext->motionp = false;
- ext->ext_type = WIIEXT_NONE;
- wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL);
- spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
-}
-
-static bool motionp_read(struct wiimote_ext *ext)
-{
- __u8 rmem[2], wmem;
- ssize_t ret;
- bool avail = false;
-
- if (!atomic_read(&ext->mp_opened))
- return false;
-
- if (wiimote_cmd_acquire(ext->wdata))
- return false;
-
- /* initialize motion plus */
- wmem = 0x55;
- ret = wiimote_cmd_write(ext->wdata, 0xa600f0, &wmem, sizeof(wmem));
- if (ret)
- goto error;
-
- /* read motion plus ID */
- ret = wiimote_cmd_read(ext->wdata, 0xa600fe, rmem, 2);
- if (ret == 2 || rmem[1] == 0x5)
- avail = true;
-
-error:
- wiimote_cmd_release(ext->wdata);
- return avail;
-}
-
-static __u8 ext_read(struct wiimote_ext *ext)
-{
- ssize_t ret;
- __u8 buf[24], i, j, offs = 0;
- __u8 rmem[2], wmem;
- __u8 type = WIIEXT_NONE;
-
- if (!ext->plugged || !atomic_read(&ext->opened))
- return WIIEXT_NONE;
-
- if (wiimote_cmd_acquire(ext->wdata))
- return WIIEXT_NONE;
-
- /* initialize extension */
- wmem = 0x55;
- ret = wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
- if (!ret) {
- /* disable encryption */
- wmem = 0x0;
- wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem));
- }
-
- /* read extension ID */
- ret = wiimote_cmd_read(ext->wdata, 0xa400fe, rmem, 2);
- if (ret == 2) {
- if (rmem[0] == 0 && rmem[1] == 0)
- type = WIIEXT_NUNCHUCK;
- else if (rmem[0] == 0x01 && rmem[1] == 0x01)
- type = WIIEXT_CLASSIC;
- else if (rmem[0] == 0x04 && rmem[1] == 0x02)
- type = WIIEXT_BALANCE_BOARD;
- }
-
- /* get balance board calibration data */
- if (type == WIIEXT_BALANCE_BOARD) {
- ret = wiimote_cmd_read(ext->wdata, 0xa40024, buf, 12);
- ret += wiimote_cmd_read(ext->wdata, 0xa40024 + 12,
- buf + 12, 12);
-
- if (ret != 24) {
- type = WIIEXT_NONE;
- } else {
- for (i = 0; i < 3; i++) {
- for (j = 0; j < 4; j++) {
- ext->calib[j][i] = buf[offs];
- ext->calib[j][i] <<= 8;
- ext->calib[j][i] |= buf[offs + 1];
- offs += 2;
- }
- }
- }
- }
-
- wiimote_cmd_release(ext->wdata);
-
- return type;
-}
-
-static void ext_enable(struct wiimote_ext *ext, bool motionp, __u8 ext_type)
-{
- unsigned long flags;
- __u8 wmem;
- int ret;
-
- if (motionp) {
- if (wiimote_cmd_acquire(ext->wdata))
- return;
-
- if (ext_type == WIIEXT_CLASSIC)
- wmem = 0x07;
- else if (ext_type == WIIEXT_NUNCHUCK)
- wmem = 0x05;
- else
- wmem = 0x04;
-
- ret = wiimote_cmd_write(ext->wdata, 0xa600fe, &wmem, sizeof(wmem));
- wiimote_cmd_release(ext->wdata);
- if (ret)
- return;
- }
-
- spin_lock_irqsave(&ext->wdata->state.lock, flags);
- ext->motionp = motionp;
- ext->ext_type = ext_type;
- wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL);
- spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
-}
-
-static void wiiext_worker(struct work_struct *work)
-{
- struct wiimote_ext *ext = container_of(work, struct wiimote_ext,
- worker);
- bool motionp;
- __u8 ext_type;
-
- ext_disable(ext);
- motionp = motionp_read(ext);
- ext_type = ext_read(ext);
- ext_enable(ext, motionp, ext_type);
-}
-
-/* schedule work only once, otherwise mark for reschedule */
-static void wiiext_schedule(struct wiimote_ext *ext)
-{
- schedule_work(&ext->worker);
-}
-
-/*
- * Reacts on extension port events
- * Whenever the driver gets an event from the wiimote that an extension has been
- * plugged or unplugged, this funtion shall be called. It checks what extensions
- * are connected and initializes and activates them.
- * This can be called in atomic context. The initialization is done in a
- * separate worker thread. The state.lock spinlock must be held by the caller.
- */
-void wiiext_event(struct wiimote_data *wdata, bool plugged)
-{
- if (!wdata->ext)
- return;
-
- if (wdata->ext->plugged == plugged)
- return;
-
- wdata->ext->plugged = plugged;
-
- if (!plugged)
- wdata->ext->mp_plugged = false;
-
- /*
- * We need to call wiiext_schedule(wdata->ext) here, however, the
- * extension initialization logic is not fully understood and so
- * automatic initialization is not supported, yet.
- */
-}
-
-/*
- * Returns true if the current DRM mode should contain extension data and false
- * if there is no interest in extension data.
- * All supported extensions send 6 byte extension data so any DRM that contains
- * extension bytes is fine.
- * The caller must hold the state.lock spinlock.
- */
-bool wiiext_active(struct wiimote_data *wdata)
-{
- if (!wdata->ext)
- return false;
-
- return wdata->ext->motionp || wdata->ext->ext_type;
-}
-
-static void handler_motionp(struct wiimote_ext *ext, const __u8 *payload)
-{
- __s32 x, y, z;
- bool plugged;
-
- /* | 8 7 6 5 4 3 | 2 | 1 |
- * -----+------------------------------+-----+-----+
- * 1 | Yaw Speed <7:0> |
- * 2 | Roll Speed <7:0> |
- * 3 | Pitch Speed <7:0> |
- * -----+------------------------------+-----+-----+
- * 4 | Yaw Speed <13:8> | Yaw |Pitch|
- * -----+------------------------------+-----+-----+
- * 5 | Roll Speed <13:8> |Roll | Ext |
- * -----+------------------------------+-----+-----+
- * 6 | Pitch Speed <13:8> | 1 | 0 |
- * -----+------------------------------+-----+-----+
- * The single bits Yaw, Roll, Pitch in the lower right corner specify
- * whether the wiimote is rotating fast (0) or slow (1). Speed for slow
- * roation is 440 deg/s and for fast rotation 2000 deg/s. To get a
- * linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast
- * and 9 for slow.
- * If the wiimote is not rotating the sensor reports 2^13 = 8192.
- * Ext specifies whether an extension is connected to the motionp.
- */
-
- x = payload[0];
- y = payload[1];
- z = payload[2];
-
- x |= (((__u16)payload[3]) << 6) & 0xff00;
- y |= (((__u16)payload[4]) << 6) & 0xff00;
- z |= (((__u16)payload[5]) << 6) & 0xff00;
-
- x -= 8192;
- y -= 8192;
- z -= 8192;
-
- if (!(payload[3] & 0x02))
- x *= 18;
- else
- x *= 9;
- if (!(payload[4] & 0x02))
- y *= 18;
- else
- y *= 9;
- if (!(payload[3] & 0x01))
- z *= 18;
- else
- z *= 9;
-
- input_report_abs(ext->mp_input, ABS_RX, x);
- input_report_abs(ext->mp_input, ABS_RY, y);
- input_report_abs(ext->mp_input, ABS_RZ, z);
- input_sync(ext->mp_input);
-
- plugged = payload[5] & 0x01;
- if (plugged != ext->mp_plugged)
- ext->mp_plugged = plugged;
-}
-
-static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload)
-{
- __s16 x, y, z, bx, by;
-
- /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 |
- * -----+----------+---------+---------+----+-----+
- * 1 | Button X <7:0> |
- * 2 | Button Y <7:0> |
- * -----+----------+---------+---------+----+-----+
- * 3 | Speed X <9:2> |
- * 4 | Speed Y <9:2> |
- * 5 | Speed Z <9:2> |
- * -----+----------+---------+---------+----+-----+
- * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ |
- * -----+----------+---------+---------+----+-----+
- * Button X/Y is the analog stick. Speed X, Y and Z are the
- * accelerometer data in the same format as the wiimote's accelerometer.
- * The 6th byte contains the LSBs of the accelerometer data.
- * BC and BZ are the C and Z buttons: 0 means pressed
- *
- * If reported interleaved with motionp, then the layout changes. The
- * 5th and 6th byte changes to:
- * -----+-----------------------------------+-----+
- * 5 | Speed Z <9:3> | EXT |
- * -----+--------+-----+-----+----+----+----+-----+
- * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 |
- * -----+--------+-----+-----+----+----+----+-----+
- * All three accelerometer values lose their LSB. The other data is
- * still available but slightly moved.
- *
- * Center data for button values is 128. Center value for accelerometer
- * values it 512 / 0x200
- */
-
- bx = payload[0];
- by = payload[1];
- bx -= 128;
- by -= 128;
-
- x = payload[2] << 2;
- y = payload[3] << 2;
- z = payload[4] << 2;
-
- if (ext->motionp) {
- x |= (payload[5] >> 3) & 0x02;
- y |= (payload[5] >> 4) & 0x02;
- z &= ~0x4;
- z |= (payload[5] >> 5) & 0x06;
- } else {
- x |= (payload[5] >> 2) & 0x03;
- y |= (payload[5] >> 4) & 0x03;
- z |= (payload[5] >> 6) & 0x03;
- }
-
- x -= 0x200;
- y -= 0x200;
- z -= 0x200;
-
- input_report_abs(ext->input, ABS_HAT0X, bx);
- input_report_abs(ext->input, ABS_HAT0Y, by);
-
- input_report_abs(ext->input, ABS_RX, x);
- input_report_abs(ext->input, ABS_RY, y);
- input_report_abs(ext->input, ABS_RZ, z);
-
- if (ext->motionp) {
- input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x04));
- input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x08));
- } else {
- input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_Z], !(payload[5] & 0x01));
- input_report_key(ext->input,
- wiiext_keymap[WIIEXT_KEY_C], !(payload[5] & 0x02));
- }
-
- input_sync(ext->input);
-}
-
-static void handler_classic(struct wiimote_ext *ext, const __u8 *payload)
-{
- __s8 rx, ry, lx, ly, lt, rt;
-
- /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * 1 | RX <5:4> | LX <5:0> |
- * 2 | RX <3:2> | LY <5:0> |
- * -----+-----+-----+-----+-----------------------------+
- * 3 |RX<1>| LT <5:4> | RY <5:1> |
- * -----+-----+-----------+-----------------------------+
- * 4 | LT <3:1> | RT <5:1> |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * 6 | BZL | BB | BY | BA | BX | BZR | BDL | BDU |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * All buttons are 0 if pressed
- * RX and RY are right analog stick
- * LX and LY are left analog stick
- * LT is left trigger, RT is right trigger
- * BLT is 0 if left trigger is fully pressed
- * BRT is 0 if right trigger is fully pressed
- * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons
- * BZL is left Z button and BZR is right Z button
- * B-, BH, B+ are +, HOME and - buttons
- * BB, BY, BA, BX are A, B, X, Y buttons
- * LSB of RX, RY, LT, and RT are not transmitted and always 0.
- *
- * With motionp enabled it changes slightly to this:
- * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * 1 | RX <4:3> | LX <5:1> | BDU |
- * 2 | RX <2:1> | LY <5:1> | BDL |
- * -----+-----+-----+-----+-----------------------+-----+
- * 3 |RX<0>| LT <4:3> | RY <4:0> |
- * -----+-----+-----------+-----------------------------+
- * 4 | LT <2:0> | RT <4:0> |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | EXT |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * 6 | BZL | BB | BY | BA | BX | BZR | 0 | 0 |
- * -----+-----+-----+-----+-----+-----+-----+-----+-----+
- * Only the LSBs of LX and LY are lost. BDU and BDL are moved, the rest
- * is the same as before.
- */
-
- if (ext->motionp) {
- lx = payload[0] & 0x3e;
- ly = payload[0] & 0x3e;
- } else {
- lx = payload[0] & 0x3f;
- ly = payload[0] & 0x3f;
- }
-
- rx = (payload[0] >> 3) & 0x14;
- rx |= (payload[1] >> 5) & 0x06;
- rx |= (payload[2] >> 7) & 0x01;
- ry = payload[2] & 0x1f;
-
- rt = payload[3] & 0x1f;
- lt = (payload[2] >> 2) & 0x18;
- lt |= (payload[3] >> 5) & 0x07;
-
- rx <<= 1;
- ry <<= 1;
- rt <<= 1;
- lt <<= 1;
-
- input_report_abs(ext->input, ABS_HAT1X, lx - 0x20);
- input_report_abs(ext->input, ABS_HAT1Y, ly - 0x20);
- input_report_abs(ext->input, ABS_HAT2X, rx - 0x20);
- input_report_abs(ext->input, ABS_HAT2Y, ry - 0x20);
- input_report_abs(ext->input, ABS_HAT3X, rt - 0x20);
- input_report_abs(ext->input, ABS_HAT3Y, lt - 0x20);
-
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_RIGHT],
- !!(payload[4] & 0x80));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_DOWN],
- !!(payload[4] & 0x40));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LT],
- !!(payload[4] & 0x20));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_MINUS],
- !!(payload[4] & 0x10));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_HOME],
- !!(payload[4] & 0x08));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_PLUS],
- !!(payload[4] & 0x04));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_RT],
- !!(payload[4] & 0x02));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_ZL],
- !!(payload[5] & 0x80));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_B],
- !!(payload[5] & 0x40));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_Y],
- !!(payload[5] & 0x20));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_A],
- !!(payload[5] & 0x10));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_X],
- !!(payload[5] & 0x08));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_ZR],
- !!(payload[5] & 0x04));
-
- if (ext->motionp) {
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_UP],
- !!(payload[0] & 0x01));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LEFT],
- !!(payload[1] & 0x01));
- } else {
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_UP],
- !!(payload[5] & 0x01));
- input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LEFT],
- !!(payload[5] & 0x02));
- }
-
- input_sync(ext->input);
-}
-
-static void handler_balance_board(struct wiimote_ext *ext, const __u8 *payload)
-{
- __s32 val[4], tmp;
- unsigned int i;
-
- /* Byte | 8 7 6 5 4 3 2 1 |
- * -----+--------------------------+
- * 1 | Top Right <15:8> |
- * 2 | Top Right <7:0> |
- * -----+--------------------------+
- * 3 | Bottom Right <15:8> |
- * 4 | Bottom Right <7:0> |
- * -----+--------------------------+
- * 5 | Top Left <15:8> |
- * 6 | Top Left <7:0> |
- * -----+--------------------------+
- * 7 | Bottom Left <15:8> |
- * 8 | Bottom Left <7:0> |
- * -----+--------------------------+
- *
- * These values represent the weight-measurements of the Wii-balance
- * board with 16bit precision.
- *
- * The balance-board is never reported interleaved with motionp.
- */
-
- val[0] = payload[0];
- val[0] <<= 8;
- val[0] |= payload[1];
-
- val[1] = payload[2];
- val[1] <<= 8;
- val[1] |= payload[3];
-
- val[2] = payload[4];
- val[2] <<= 8;
- val[2] |= payload[5];
-
- val[3] = payload[6];
- val[3] <<= 8;
- val[3] |= payload[7];
-
- /* apply calibration data */
- for (i = 0; i < 4; i++) {
- if (val[i] < ext->calib[i][1]) {
- tmp = val[i] - ext->calib[i][0];
- tmp *= 1700;
- tmp /= ext->calib[i][1] - ext->calib[i][0];
- } else {
- tmp = val[i] - ext->calib[i][1];
- tmp *= 1700;
- tmp /= ext->calib[i][2] - ext->calib[i][1];
- tmp += 1700;
- }
- val[i] = tmp;
- }
-
- input_report_abs(ext->input, ABS_HAT0X, val[0]);
- input_report_abs(ext->input, ABS_HAT0Y, val[1]);
- input_report_abs(ext->input, ABS_HAT1X, val[2]);
- input_report_abs(ext->input, ABS_HAT1Y, val[3]);
-
- input_sync(ext->input);
-}
-
-/* call this with state.lock spinlock held */
-void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
-{
- struct wiimote_ext *ext = wdata->ext;
-
- if (!ext)
- return;
-
- if (ext->motionp && (payload[5] & 0x02)) {
- handler_motionp(ext, payload);
- } else if (ext->ext_type == WIIEXT_NUNCHUCK) {
- handler_nunchuck(ext, payload);
- } else if (ext->ext_type == WIIEXT_CLASSIC) {
- handler_classic(ext, payload);
- } else if (ext->ext_type == WIIEXT_BALANCE_BOARD) {
- handler_balance_board(ext, payload);
- }
-}
-
-static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct wiimote_data *wdata = dev_to_wii(dev);
- __u8 type = WIIEXT_NONE;
- bool motionp = false;
- unsigned long flags;
-
- spin_lock_irqsave(&wdata->state.lock, flags);
- if (wdata->ext) {
- motionp = wdata->ext->motionp;
- type = wdata->ext->ext_type;
- }
- spin_unlock_irqrestore(&wdata->state.lock, flags);
-
- if (type == WIIEXT_NUNCHUCK) {
- if (motionp)
- return sprintf(buf, "motionp+nunchuck\n");
- else
- return sprintf(buf, "nunchuck\n");
- } else if (type == WIIEXT_CLASSIC) {
- if (motionp)
- return sprintf(buf, "motionp+classic\n");
- else
- return sprintf(buf, "classic\n");
- } else if (type == WIIEXT_BALANCE_BOARD) {
- if (motionp)
- return sprintf(buf, "motionp+balanceboard\n");
- else
- return sprintf(buf, "balanceboard\n");
- } else {
- if (motionp)
- return sprintf(buf, "motionp\n");
- else
- return sprintf(buf, "none\n");
- }
-}
-
-static DEVICE_ATTR(extension, S_IRUGO, wiiext_show, NULL);
-
-static int wiiext_input_open(struct input_dev *dev)
-{
- struct wiimote_ext *ext = input_get_drvdata(dev);
- int ret;
-
- ret = hid_hw_open(ext->wdata->hdev);
- if (ret)
- return ret;
-
- atomic_inc(&ext->opened);
- wiiext_schedule(ext);
-
- return 0;
-}
-
-static void wiiext_input_close(struct input_dev *dev)
-{
- struct wiimote_ext *ext = input_get_drvdata(dev);
-
- atomic_dec(&ext->opened);
- wiiext_schedule(ext);
- hid_hw_close(ext->wdata->hdev);
-}
-
-static int wiiext_mp_open(struct input_dev *dev)
-{
- struct wiimote_ext *ext = input_get_drvdata(dev);
- int ret;
-
- ret = hid_hw_open(ext->wdata->hdev);
- if (ret)
- return ret;
-
- atomic_inc(&ext->mp_opened);
- wiiext_schedule(ext);
-
- return 0;
-}
-
-static void wiiext_mp_close(struct input_dev *dev)
-{
- struct wiimote_ext *ext = input_get_drvdata(dev);
-
- atomic_dec(&ext->mp_opened);
- wiiext_schedule(ext);
- hid_hw_close(ext->wdata->hdev);
-}
-
-/* Initializes the extension driver of a wiimote */
-int wiiext_init(struct wiimote_data *wdata)
-{
- struct wiimote_ext *ext;
- unsigned long flags;
- int ret, i;
-
- ext = kzalloc(sizeof(*ext), GFP_KERNEL);
- if (!ext)
- return -ENOMEM;
-
- ext->wdata = wdata;
- INIT_WORK(&ext->worker, wiiext_worker);
-
- ext->input = input_allocate_device();
- if (!ext->input) {
- ret = -ENOMEM;
- goto err_input;
- }
-
- input_set_drvdata(ext->input, ext);
- ext->input->open = wiiext_input_open;
- ext->input->close = wiiext_input_close;
- ext->input->dev.parent = &wdata->hdev->dev;
- ext->input->id.bustype = wdata->hdev->bus;
- ext->input->id.vendor = wdata->hdev->vendor;
- ext->input->id.product = wdata->hdev->product;
- ext->input->id.version = wdata->hdev->version;
- ext->input->name = WIIMOTE_NAME " Extension";
-
- set_bit(EV_KEY, ext->input->evbit);
- for (i = 0; i < WIIEXT_KEY_COUNT; ++i)
- set_bit(wiiext_keymap[i], ext->input->keybit);
-
- set_bit(EV_ABS, ext->input->evbit);
- set_bit(ABS_HAT0X, ext->input->absbit);
- set_bit(ABS_HAT0Y, ext->input->absbit);
- set_bit(ABS_HAT1X, ext->input->absbit);
- set_bit(ABS_HAT1Y, ext->input->absbit);
- set_bit(ABS_HAT2X, ext->input->absbit);
- set_bit(ABS_HAT2Y, ext->input->absbit);
- set_bit(ABS_HAT3X, ext->input->absbit);
- set_bit(ABS_HAT3Y, ext->input->absbit);
- input_set_abs_params(ext->input, ABS_HAT0X, -120, 120, 2, 4);
- input_set_abs_params(ext->input, ABS_HAT0Y, -120, 120, 2, 4);
- input_set_abs_params(ext->input, ABS_HAT1X, -30, 30, 1, 1);
- input_set_abs_params(ext->input, ABS_HAT1Y, -30, 30, 1, 1);
- input_set_abs_params(ext->input, ABS_HAT2X, -30, 30, 1, 1);
- input_set_abs_params(ext->input, ABS_HAT2Y, -30, 30, 1, 1);
- input_set_abs_params(ext->input, ABS_HAT3X, -30, 30, 1, 1);
- input_set_abs_params(ext->input, ABS_HAT3Y, -30, 30, 1, 1);
- set_bit(ABS_RX, ext->input->absbit);
- set_bit(ABS_RY, ext->input->absbit);
- set_bit(ABS_RZ, ext->input->absbit);
- input_set_abs_params(ext->input, ABS_RX, -500, 500, 2, 4);
- input_set_abs_params(ext->input, ABS_RY, -500, 500, 2, 4);
- input_set_abs_params(ext->input, ABS_RZ, -500, 500, 2, 4);
-
- ret = input_register_device(ext->input);
- if (ret) {
- input_free_device(ext->input);
- goto err_input;
- }
-
- ext->mp_input = input_allocate_device();
- if (!ext->mp_input) {
- ret = -ENOMEM;
- goto err_mp;
- }
-
- input_set_drvdata(ext->mp_input, ext);
- ext->mp_input->open = wiiext_mp_open;
- ext->mp_input->close = wiiext_mp_close;
- ext->mp_input->dev.parent = &wdata->hdev->dev;
- ext->mp_input->id.bustype = wdata->hdev->bus;
- ext->mp_input->id.vendor = wdata->hdev->vendor;
- ext->mp_input->id.product = wdata->hdev->product;
- ext->mp_input->id.version = wdata->hdev->version;
- ext->mp_input->name = WIIMOTE_NAME " Motion+";
-
- set_bit(EV_ABS, ext->mp_input->evbit);
- set_bit(ABS_RX, ext->mp_input->absbit);
- set_bit(ABS_RY, ext->mp_input->absbit);
- set_bit(ABS_RZ, ext->mp_input->absbit);
- input_set_abs_params(ext->mp_input, ABS_RX, -160000, 160000, 4, 8);
- input_set_abs_params(ext->mp_input, ABS_RY, -160000, 160000, 4, 8);
- input_set_abs_params(ext->mp_input, ABS_RZ, -160000, 160000, 4, 8);
-
- ret = input_register_device(ext->mp_input);
- if (ret) {
- input_free_device(ext->mp_input);
- goto err_mp;
- }
-
- ret = device_create_file(&wdata->hdev->dev, &dev_attr_extension);
- if (ret)
- goto err_dev;
-
- spin_lock_irqsave(&wdata->state.lock, flags);
- wdata->ext = ext;
- spin_unlock_irqrestore(&wdata->state.lock, flags);
-
- return 0;
-
-err_dev:
- input_unregister_device(ext->mp_input);
-err_mp:
- input_unregister_device(ext->input);
-err_input:
- kfree(ext);
- return ret;
-}
-
-/* Deinitializes the extension driver of a wiimote */
-void wiiext_deinit(struct wiimote_data *wdata)
-{
- struct wiimote_ext *ext = wdata->ext;
- unsigned long flags;
-
- if (!ext)
- return;
-
- /*
- * We first unset wdata->ext to avoid further input from the wiimote
- * core. The worker thread does not access this pointer so it is not
- * affected by this.
- * We kill the worker after this so it does not get respawned during
- * deinitialization.
- */
-
- spin_lock_irqsave(&wdata->state.lock, flags);
- wdata->ext = NULL;
- spin_unlock_irqrestore(&wdata->state.lock, flags);
-
- device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
- input_unregister_device(ext->mp_input);
- input_unregister_device(ext->input);
-
- cancel_work_sync(&ext->worker);
- kfree(ext);
-}
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
new file mode 100644
index 000000000000..2e7d644dba18
--- /dev/null
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -0,0 +1,2086 @@
+/*
+ * Device Modules for Nintendo Wii / Wii U HID Driver
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@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.
+ */
+
+/*
+ * Wiimote Modules
+ * Nintendo devices provide different peripherals and many new devices lack
+ * initial features like the IR camera. Therefore, each peripheral device is
+ * implemented as an independent module and we probe on each device only the
+ * modules for the hardware that really is available.
+ *
+ * Module registration is sequential. Unregistration is done in reverse order.
+ * After device detection, the needed modules are loaded. Users can trigger
+ * re-detection which causes all modules to be unloaded and then reload the
+ * modules for the new detected device.
+ *
+ * wdata->input is a shared input device. It is always initialized prior to
+ * module registration. If at least one registered module is marked as
+ * WIIMOD_FLAG_INPUT, then the input device will get registered after all
+ * modules were registered.
+ * Please note that it is unregistered _before_ the "remove" callbacks are
+ * called. This guarantees that no input interaction is done, anymore. However,
+ * the wiimote core keeps a reference to the input device so it is freed only
+ * after all modules were removed. It is safe to send events to unregistered
+ * input devices.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/spinlock.h>
+#include "hid-wiimote.h"
+
+/*
+ * Keys
+ * The initial Wii Remote provided a bunch of buttons that are reported as
+ * part of the core protocol. Many later devices dropped these and report
+ * invalid data in the core button reports. Load this only on devices which
+ * correctly send button reports.
+ * It uses the shared input device.
+ */
+
+static const __u16 wiimod_keys_map[] = {
+ KEY_LEFT, /* WIIPROTO_KEY_LEFT */
+ KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */
+ KEY_UP, /* WIIPROTO_KEY_UP */
+ KEY_DOWN, /* WIIPROTO_KEY_DOWN */
+ KEY_NEXT, /* WIIPROTO_KEY_PLUS */
+ KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */
+ BTN_1, /* WIIPROTO_KEY_ONE */
+ BTN_2, /* WIIPROTO_KEY_TWO */
+ BTN_A, /* WIIPROTO_KEY_A */
+ BTN_B, /* WIIPROTO_KEY_B */
+ BTN_MODE, /* WIIPROTO_KEY_HOME */
+};
+
+static void wiimod_keys_in_keys(struct wiimote_data *wdata, const __u8 *keys)
+{
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_LEFT],
+ !!(keys[0] & 0x01));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_RIGHT],
+ !!(keys[0] & 0x02));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_DOWN],
+ !!(keys[0] & 0x04));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_UP],
+ !!(keys[0] & 0x08));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_PLUS],
+ !!(keys[0] & 0x10));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_TWO],
+ !!(keys[1] & 0x01));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_ONE],
+ !!(keys[1] & 0x02));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_B],
+ !!(keys[1] & 0x04));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_A],
+ !!(keys[1] & 0x08));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_MINUS],
+ !!(keys[1] & 0x10));
+ input_report_key(wdata->input, wiimod_keys_map[WIIPROTO_KEY_HOME],
+ !!(keys[1] & 0x80));
+ input_sync(wdata->input);
+}
+
+static int wiimod_keys_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned int i;
+
+ set_bit(EV_KEY, wdata->input->evbit);
+ for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
+ set_bit(wiimod_keys_map[i], wdata->input->keybit);
+
+ return 0;
+}
+
+static const struct wiimod_ops wiimod_keys = {
+ .flags = WIIMOD_FLAG_INPUT,
+ .arg = 0,
+ .probe = wiimod_keys_probe,
+ .remove = NULL,
+ .in_keys = wiimod_keys_in_keys,
+};
+
+/*
+ * Rumble
+ * Nearly all devices provide a rumble feature. A small motor for
+ * force-feedback effects. We provide an FF_RUMBLE memless ff device on the
+ * shared input device if this module is loaded.
+ * The rumble motor is controlled via a flag on almost every output report so
+ * the wiimote core handles the rumble flag. But if a device doesn't provide
+ * the rumble motor, this flag shouldn't be set.
+ */
+
+static int wiimod_rumble_play(struct input_dev *dev, void *data,
+ struct ff_effect *eff)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 value;
+ unsigned long flags;
+
+ /*
+ * The wiimote supports only a single rumble motor so if any magnitude
+ * is set to non-zero then we start the rumble motor. If both are set to
+ * zero, we stop the rumble motor.
+ */
+
+ if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
+ value = 1;
+ else
+ value = 0;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_rumble(wdata, value);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static int wiimod_rumble_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ set_bit(FF_RUMBLE, wdata->input->ffbit);
+ if (input_ff_create_memless(wdata->input, NULL, wiimod_rumble_play))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void wiimod_rumble_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_rumble(wdata, 0);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static const struct wiimod_ops wiimod_rumble = {
+ .flags = WIIMOD_FLAG_INPUT,
+ .arg = 0,
+ .probe = wiimod_rumble_probe,
+ .remove = wiimod_rumble_remove,
+};
+
+/*
+ * Battery
+ * 1 byte of battery capacity information is sent along every protocol status
+ * report. The wiimote core caches it but we try to update it on every
+ * user-space request.
+ * This is supported by nearly every device so it's almost always enabled.
+ */
+
+static enum power_supply_property wiimod_battery_props[] = {
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_SCOPE,
+};
+
+static int wiimod_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wiimote_data *wdata = container_of(psy, struct wiimote_data,
+ battery);
+ int ret = 0, state;
+ unsigned long flags;
+
+ if (psp == POWER_SUPPLY_PROP_SCOPE) {
+ val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+ return 0;
+ } else if (psp != POWER_SUPPLY_PROP_CAPACITY) {
+ return -EINVAL;
+ }
+
+ ret = wiimote_cmd_acquire(wdata);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
+ wiiproto_req_status(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ wiimote_cmd_wait(wdata);
+ wiimote_cmd_release(wdata);
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ state = wdata->state.cmd_battery;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ val->intval = state * 100 / 255;
+ return ret;
+}
+
+static int wiimod_battery_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret;
+
+ wdata->battery.properties = wiimod_battery_props;
+ wdata->battery.num_properties = ARRAY_SIZE(wiimod_battery_props);
+ wdata->battery.get_property = wiimod_battery_get_property;
+ wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
+ wdata->battery.use_for_apm = 0;
+ wdata->battery.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s",
+ wdata->hdev->uniq);
+ if (!wdata->battery.name)
+ return -ENOMEM;
+
+ ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
+ if (ret) {
+ hid_err(wdata->hdev, "cannot register battery device\n");
+ goto err_free;
+ }
+
+ power_supply_powers(&wdata->battery, &wdata->hdev->dev);
+ return 0;
+
+err_free:
+ kfree(wdata->battery.name);
+ wdata->battery.name = NULL;
+ return ret;
+}
+
+static void wiimod_battery_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->battery.name)
+ return;
+
+ power_supply_unregister(&wdata->battery);
+ kfree(wdata->battery.name);
+ wdata->battery.name = NULL;
+}
+
+static const struct wiimod_ops wiimod_battery = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_battery_probe,
+ .remove = wiimod_battery_remove,
+};
+
+/*
+ * LED
+ * 0 to 4 player LEDs are supported by devices. The "arg" field of the
+ * wiimod_ops structure specifies which LED this module controls. This allows
+ * to register a limited number of LEDs.
+ * State is managed by wiimote core.
+ */
+
+static enum led_brightness wiimod_led_get(struct led_classdev *led_dev)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ bool value = false;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+
+static void wiimod_led_set(struct led_classdev *led_dev,
+ enum led_brightness value)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ __u8 state, flag;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ flag = WIIPROTO_FLAG_LED(i + 1);
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ state = wdata->state.flags;
+ if (value == LED_OFF)
+ wiiproto_req_leds(wdata, state & ~flag);
+ else
+ wiiproto_req_leds(wdata, state | flag);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+}
+
+static int wiimod_led_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ struct device *dev = &wdata->hdev->dev;
+ size_t namesz = strlen(dev_name(dev)) + 9;
+ struct led_classdev *led;
+ unsigned long flags;
+ char *name;
+ int ret;
+
+ led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ name = (void*)&led[1];
+ snprintf(name, namesz, "%s:blue:p%lu", dev_name(dev), ops->arg);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = wiimod_led_get;
+ led->brightness_set = wiimod_led_set;
+
+ wdata->leds[ops->arg] = led;
+ ret = led_classdev_register(dev, led);
+ if (ret)
+ goto err_free;
+
+ /* enable LED1 to stop initial LED-blinking */
+ if (ops->arg == 0) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ }
+
+ return 0;
+
+err_free:
+ wdata->leds[ops->arg] = NULL;
+ kfree(led);
+ return ret;
+}
+
+static void wiimod_led_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->leds[ops->arg])
+ return;
+
+ led_classdev_unregister(wdata->leds[ops->arg]);
+ kfree(wdata->leds[ops->arg]);
+ wdata->leds[ops->arg] = NULL;
+}
+
+static const struct wiimod_ops wiimod_leds[4] = {
+ {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_led_probe,
+ .remove = wiimod_led_remove,
+ },
+ {
+ .flags = 0,
+ .arg = 1,
+ .probe = wiimod_led_probe,
+ .remove = wiimod_led_remove,
+ },
+ {
+ .flags = 0,
+ .arg = 2,
+ .probe = wiimod_led_probe,
+ .remove = wiimod_led_remove,
+ },
+ {
+ .flags = 0,
+ .arg = 3,
+ .probe = wiimod_led_probe,
+ .remove = wiimod_led_remove,
+ },
+};
+
+/*
+ * Accelerometer
+ * 3 axis accelerometer data is part of nearly all DRMs. If not supported by a
+ * device, it's mostly cleared to 0. This module parses this data and provides
+ * it via a separate input device.
+ */
+
+static void wiimod_accel_in_accel(struct wiimote_data *wdata,
+ const __u8 *accel)
+{
+ __u16 x, y, z;
+
+ if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
+ return;
+
+ /*
+ * payload is: BB BB XX YY ZZ
+ * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ
+ * contain the upper 8 bits of each value. The lower 2 bits are
+ * contained in the buttons data BB BB.
+ * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the
+ * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y
+ * accel value and bit 6 is the second bit of the Z value.
+ * The first bit of Y and Z values is not available and always set to 0.
+ * 0x200 is returned on no movement.
+ */
+
+ x = accel[2] << 2;
+ y = accel[3] << 2;
+ z = accel[4] << 2;
+
+ x |= (accel[0] >> 5) & 0x3;
+ y |= (accel[1] >> 4) & 0x2;
+ z |= (accel[1] >> 5) & 0x2;
+
+ input_report_abs(wdata->accel, ABS_RX, x - 0x200);
+ input_report_abs(wdata->accel, ABS_RY, y - 0x200);
+ input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
+ input_sync(wdata->accel);
+}
+
+static int wiimod_accel_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_accel(wdata, true);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_accel_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_accel(wdata, false);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_accel_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret;
+
+ wdata->accel = input_allocate_device();
+ if (!wdata->accel)
+ return -ENOMEM;
+
+ input_set_drvdata(wdata->accel, wdata);
+ wdata->accel->open = wiimod_accel_open;
+ wdata->accel->close = wiimod_accel_close;
+ wdata->accel->dev.parent = &wdata->hdev->dev;
+ wdata->accel->id.bustype = wdata->hdev->bus;
+ wdata->accel->id.vendor = wdata->hdev->vendor;
+ wdata->accel->id.product = wdata->hdev->product;
+ wdata->accel->id.version = wdata->hdev->version;
+ wdata->accel->name = WIIMOTE_NAME " Accelerometer";
+
+ set_bit(EV_ABS, wdata->accel->evbit);
+ set_bit(ABS_RX, wdata->accel->absbit);
+ set_bit(ABS_RY, wdata->accel->absbit);
+ set_bit(ABS_RZ, wdata->accel->absbit);
+ input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
+ input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
+ input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
+
+ ret = input_register_device(wdata->accel);
+ if (ret) {
+ hid_err(wdata->hdev, "cannot register input device\n");
+ goto err_free;
+ }
+
+ return 0;
+
+err_free:
+ input_free_device(wdata->accel);
+ wdata->accel = NULL;
+ return ret;
+}
+
+static void wiimod_accel_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->accel)
+ return;
+
+ input_unregister_device(wdata->accel);
+ wdata->accel = NULL;
+}
+
+static const struct wiimod_ops wiimod_accel = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_accel_probe,
+ .remove = wiimod_accel_remove,
+ .in_accel = wiimod_accel_in_accel,
+};
+
+/*
+ * IR Cam
+ * Up to 4 IR sources can be tracked by a normal Wii Remote. The IR cam needs
+ * to be initialized with a fairly complex procedure and consumes a lot of
+ * power. Therefore, as long as no application uses the IR input device, it is
+ * kept offline.
+ * Nearly no other device than the normal Wii Remotes supports the IR cam so
+ * you can disable this module for these devices.
+ */
+
+static void wiimod_ir_in_ir(struct wiimote_data *wdata, const __u8 *ir,
+ bool packed, unsigned int id)
+{
+ __u16 x, y;
+ __u8 xid, yid;
+ bool sync = false;
+
+ if (!(wdata->state.flags & WIIPROTO_FLAGS_IR))
+ return;
+
+ switch (id) {
+ case 0:
+ xid = ABS_HAT0X;
+ yid = ABS_HAT0Y;
+ break;
+ case 1:
+ xid = ABS_HAT1X;
+ yid = ABS_HAT1Y;
+ break;
+ case 2:
+ xid = ABS_HAT2X;
+ yid = ABS_HAT2Y;
+ break;
+ case 3:
+ xid = ABS_HAT3X;
+ yid = ABS_HAT3Y;
+ sync = true;
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * Basic IR data is encoded into 3 bytes. The first two bytes are the
+ * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
+ * of both.
+ * If data is packed, then the 3rd byte is put first and slightly
+ * reordered. This allows to interleave packed and non-packed data to
+ * have two IR sets in 5 bytes instead of 6.
+ * The resulting 10bit X/Y values are passed to the ABS_HAT? input dev.
+ */
+
+ if (packed) {
+ x = ir[1] | ((ir[0] & 0x03) << 8);
+ y = ir[2] | ((ir[0] & 0x0c) << 6);
+ } else {
+ x = ir[0] | ((ir[2] & 0x30) << 4);
+ y = ir[1] | ((ir[2] & 0xc0) << 2);
+ }
+
+ input_report_abs(wdata->ir, xid, x);
+ input_report_abs(wdata->ir, yid, y);
+
+ if (sync)
+ input_sync(wdata->ir);
+}
+
+static int wiimod_ir_change(struct wiimote_data *wdata, __u16 mode)
+{
+ int ret;
+ unsigned long flags;
+ __u8 format = 0;
+ static const __u8 data_enable[] = { 0x01 };
+ static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01,
+ 0x00, 0xaa, 0x00, 0x64 };
+ static const __u8 data_sens2[] = { 0x63, 0x03 };
+ static const __u8 data_fin[] = { 0x08 };
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+
+ if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) {
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ return 0;
+ }
+
+ if (mode == 0) {
+ wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
+ wiiproto_req_ir1(wdata, 0);
+ wiiproto_req_ir2(wdata, 0);
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ return 0;
+ }
+
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_acquire(wdata);
+ if (ret)
+ return ret;
+
+ /* send PIXEL CLOCK ENABLE cmd first */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0);
+ wiiproto_req_ir1(wdata, 0x06);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_wait(wdata);
+ if (ret)
+ goto unlock;
+ if (wdata->state.cmd_err) {
+ ret = -EIO;
+ goto unlock;
+ }
+
+ /* enable IR LOGIC */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0);
+ wiiproto_req_ir2(wdata, 0x06);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ ret = wiimote_cmd_wait(wdata);
+ if (ret)
+ goto unlock;
+ if (wdata->state.cmd_err) {
+ ret = -EIO;
+ goto unlock;
+ }
+
+ /* enable IR cam but do not make it send data, yet */
+ ret = wiimote_cmd_write(wdata, 0xb00030, data_enable,
+ sizeof(data_enable));
+ if (ret)
+ goto unlock;
+
+ /* write first sensitivity block */
+ ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1,
+ sizeof(data_sens1));
+ if (ret)
+ goto unlock;
+
+ /* write second sensitivity block */
+ ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2,
+ sizeof(data_sens2));
+ if (ret)
+ goto unlock;
+
+ /* put IR cam into desired state */
+ switch (mode) {
+ case WIIPROTO_FLAG_IR_FULL:
+ format = 5;
+ break;
+ case WIIPROTO_FLAG_IR_EXT:
+ format = 3;
+ break;
+ case WIIPROTO_FLAG_IR_BASIC:
+ format = 1;
+ break;
+ }
+ ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format));
+ if (ret)
+ goto unlock;
+
+ /* make IR cam send data */
+ ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin));
+ if (ret)
+ goto unlock;
+
+ /* request new DRM mode compatible to IR mode */
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
+ wdata->state.flags |= mode & WIIPROTO_FLAGS_IR;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+unlock:
+ wiimote_cmd_release(wdata);
+ return ret;
+}
+
+static int wiimod_ir_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ return wiimod_ir_change(wdata, WIIPROTO_FLAG_IR_BASIC);
+}
+
+static void wiimod_ir_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ wiimod_ir_change(wdata, 0);
+}
+
+static int wiimod_ir_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret;
+
+ wdata->ir = input_allocate_device();
+ if (!wdata->ir)
+ return -ENOMEM;
+
+ input_set_drvdata(wdata->ir, wdata);
+ wdata->ir->open = wiimod_ir_open;
+ wdata->ir->close = wiimod_ir_close;
+ wdata->ir->dev.parent = &wdata->hdev->dev;
+ wdata->ir->id.bustype = wdata->hdev->bus;
+ wdata->ir->id.vendor = wdata->hdev->vendor;
+ wdata->ir->id.product = wdata->hdev->product;
+ wdata->ir->id.version = wdata->hdev->version;
+ wdata->ir->name = WIIMOTE_NAME " IR";
+
+ set_bit(EV_ABS, wdata->ir->evbit);
+ set_bit(ABS_HAT0X, wdata->ir->absbit);
+ set_bit(ABS_HAT0Y, wdata->ir->absbit);
+ set_bit(ABS_HAT1X, wdata->ir->absbit);
+ set_bit(ABS_HAT1Y, wdata->ir->absbit);
+ set_bit(ABS_HAT2X, wdata->ir->absbit);
+ set_bit(ABS_HAT2Y, wdata->ir->absbit);
+ set_bit(ABS_HAT3X, wdata->ir->absbit);
+ set_bit(ABS_HAT3Y, wdata->ir->absbit);
+ input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4);
+ input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4);
+
+ ret = input_register_device(wdata->ir);
+ if (ret) {
+ hid_err(wdata->hdev, "cannot register input device\n");
+ goto err_free;
+ }
+
+ return 0;
+
+err_free:
+ input_free_device(wdata->ir);
+ wdata->ir = NULL;
+ return ret;
+}
+
+static void wiimod_ir_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->ir)
+ return;
+
+ input_unregister_device(wdata->ir);
+ wdata->ir = NULL;
+}
+
+static const struct wiimod_ops wiimod_ir = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_ir_probe,
+ .remove = wiimod_ir_remove,
+ .in_ir = wiimod_ir_in_ir,
+};
+
+/*
+ * Nunchuk Extension
+ * The Nintendo Wii Nunchuk was the first official extension published by
+ * Nintendo. It provides two additional keys and a separate accelerometer. It
+ * can be hotplugged to standard Wii Remotes.
+ */
+
+enum wiimod_nunchuk_keys {
+ WIIMOD_NUNCHUK_KEY_C,
+ WIIMOD_NUNCHUK_KEY_Z,
+ WIIMOD_NUNCHUK_KEY_NUM,
+};
+
+static const __u16 wiimod_nunchuk_map[] = {
+ BTN_C, /* WIIMOD_NUNCHUK_KEY_C */
+ BTN_Z, /* WIIMOD_NUNCHUK_KEY_Z */
+};
+
+static void wiimod_nunchuk_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+ __s16 x, y, z, bx, by;
+
+ /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 |
+ * -----+----------+---------+---------+----+-----+
+ * 1 | Button X <7:0> |
+ * 2 | Button Y <7:0> |
+ * -----+----------+---------+---------+----+-----+
+ * 3 | Speed X <9:2> |
+ * 4 | Speed Y <9:2> |
+ * 5 | Speed Z <9:2> |
+ * -----+----------+---------+---------+----+-----+
+ * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ |
+ * -----+----------+---------+---------+----+-----+
+ * Button X/Y is the analog stick. Speed X, Y and Z are the
+ * accelerometer data in the same format as the wiimote's accelerometer.
+ * The 6th byte contains the LSBs of the accelerometer data.
+ * BC and BZ are the C and Z buttons: 0 means pressed
+ *
+ * If reported interleaved with motionp, then the layout changes. The
+ * 5th and 6th byte changes to:
+ * -----+-----------------------------------+-----+
+ * 5 | Speed Z <9:3> | EXT |
+ * -----+--------+-----+-----+----+----+----+-----+
+ * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 |
+ * -----+--------+-----+-----+----+----+----+-----+
+ * All three accelerometer values lose their LSB. The other data is
+ * still available but slightly moved.
+ *
+ * Center data for button values is 128. Center value for accelerometer
+ * values it 512 / 0x200
+ */
+
+ bx = ext[0];
+ by = ext[1];
+ bx -= 128;
+ by -= 128;
+
+ x = ext[2] << 2;
+ y = ext[3] << 2;
+ z = ext[4] << 2;
+
+ if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
+ x |= (ext[5] >> 3) & 0x02;
+ y |= (ext[5] >> 4) & 0x02;
+ z &= ~0x4;
+ z |= (ext[5] >> 5) & 0x06;
+ } else {
+ x |= (ext[5] >> 2) & 0x03;
+ y |= (ext[5] >> 4) & 0x03;
+ z |= (ext[5] >> 6) & 0x03;
+ }
+
+ x -= 0x200;
+ y -= 0x200;
+ z -= 0x200;
+
+ input_report_abs(wdata->extension.input, ABS_HAT0X, bx);
+ input_report_abs(wdata->extension.input, ABS_HAT0Y, by);
+
+ input_report_abs(wdata->extension.input, ABS_RX, x);
+ input_report_abs(wdata->extension.input, ABS_RY, y);
+ input_report_abs(wdata->extension.input, ABS_RZ, z);
+
+ if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
+ input_report_key(wdata->extension.input,
+ wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z],
+ !(ext[5] & 0x04));
+ input_report_key(wdata->extension.input,
+ wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C],
+ !(ext[5] & 0x08));
+ } else {
+ input_report_key(wdata->extension.input,
+ wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z],
+ !(ext[5] & 0x01));
+ input_report_key(wdata->extension.input,
+ wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C],
+ !(ext[5] & 0x02));
+ }
+
+ input_sync(wdata->extension.input);
+}
+
+static int wiimod_nunchuk_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_nunchuk_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_nunchuk_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret, i;
+
+ wdata->extension.input = input_allocate_device();
+ if (!wdata->extension.input)
+ return -ENOMEM;
+
+ input_set_drvdata(wdata->extension.input, wdata);
+ wdata->extension.input->open = wiimod_nunchuk_open;
+ wdata->extension.input->close = wiimod_nunchuk_close;
+ wdata->extension.input->dev.parent = &wdata->hdev->dev;
+ wdata->extension.input->id.bustype = wdata->hdev->bus;
+ wdata->extension.input->id.vendor = wdata->hdev->vendor;
+ wdata->extension.input->id.product = wdata->hdev->product;
+ wdata->extension.input->id.version = wdata->hdev->version;
+ wdata->extension.input->name = WIIMOTE_NAME " Nunchuk";
+
+ set_bit(EV_KEY, wdata->extension.input->evbit);
+ for (i = 0; i < WIIMOD_NUNCHUK_KEY_NUM; ++i)
+ set_bit(wiimod_nunchuk_map[i],
+ wdata->extension.input->keybit);
+
+ set_bit(EV_ABS, wdata->extension.input->evbit);
+ set_bit(ABS_HAT0X, wdata->extension.input->absbit);
+ set_bit(ABS_HAT0Y, wdata->extension.input->absbit);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT0X, -120, 120, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT0Y, -120, 120, 2, 4);
+ set_bit(ABS_RX, wdata->extension.input->absbit);
+ set_bit(ABS_RY, wdata->extension.input->absbit);
+ set_bit(ABS_RZ, wdata->extension.input->absbit);
+ input_set_abs_params(wdata->extension.input,
+ ABS_RX, -500, 500, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_RY, -500, 500, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_RZ, -500, 500, 2, 4);
+
+ ret = input_register_device(wdata->extension.input);
+ if (ret)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ input_free_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+ return ret;
+}
+
+static void wiimod_nunchuk_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->extension.input)
+ return;
+
+ input_unregister_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_nunchuk = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_nunchuk_probe,
+ .remove = wiimod_nunchuk_remove,
+ .in_ext = wiimod_nunchuk_in_ext,
+};
+
+/*
+ * Classic Controller
+ * Another official extension from Nintendo. It provides a classic
+ * gamecube-like controller that can be hotplugged on the Wii Remote.
+ * It has several hardware buttons and switches that are all reported via
+ * a normal extension device.
+ */
+
+enum wiimod_classic_keys {
+ WIIMOD_CLASSIC_KEY_A,
+ WIIMOD_CLASSIC_KEY_B,
+ WIIMOD_CLASSIC_KEY_X,
+ WIIMOD_CLASSIC_KEY_Y,
+ WIIMOD_CLASSIC_KEY_ZL,
+ WIIMOD_CLASSIC_KEY_ZR,
+ WIIMOD_CLASSIC_KEY_PLUS,
+ WIIMOD_CLASSIC_KEY_MINUS,
+ WIIMOD_CLASSIC_KEY_HOME,
+ WIIMOD_CLASSIC_KEY_LEFT,
+ WIIMOD_CLASSIC_KEY_RIGHT,
+ WIIMOD_CLASSIC_KEY_UP,
+ WIIMOD_CLASSIC_KEY_DOWN,
+ WIIMOD_CLASSIC_KEY_LT,
+ WIIMOD_CLASSIC_KEY_RT,
+ WIIMOD_CLASSIC_KEY_NUM,
+};
+
+static const __u16 wiimod_classic_map[] = {
+ BTN_A, /* WIIMOD_CLASSIC_KEY_A */
+ BTN_B, /* WIIMOD_CLASSIC_KEY_B */
+ BTN_X, /* WIIMOD_CLASSIC_KEY_X */
+ BTN_Y, /* WIIMOD_CLASSIC_KEY_Y */
+ BTN_TL2, /* WIIMOD_CLASSIC_KEY_ZL */
+ BTN_TR2, /* WIIMOD_CLASSIC_KEY_ZR */
+ KEY_NEXT, /* WIIMOD_CLASSIC_KEY_PLUS */
+ KEY_PREVIOUS, /* WIIMOD_CLASSIC_KEY_MINUS */
+ BTN_MODE, /* WIIMOD_CLASSIC_KEY_HOME */
+ KEY_LEFT, /* WIIMOD_CLASSIC_KEY_LEFT */
+ KEY_RIGHT, /* WIIMOD_CLASSIC_KEY_RIGHT */
+ KEY_UP, /* WIIMOD_CLASSIC_KEY_UP */
+ KEY_DOWN, /* WIIMOD_CLASSIC_KEY_DOWN */
+ BTN_TL, /* WIIMOD_CLASSIC_KEY_LT */
+ BTN_TR, /* WIIMOD_CLASSIC_KEY_RT */
+};
+
+static void wiimod_classic_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+ __s8 rx, ry, lx, ly, lt, rt;
+
+ /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 1 | RX <5:4> | LX <5:0> |
+ * 2 | RX <3:2> | LY <5:0> |
+ * -----+-----+-----+-----+-----------------------------+
+ * 3 |RX<1>| LT <5:4> | RY <5:1> |
+ * -----+-----+-----------+-----------------------------+
+ * 4 | LT <3:1> | RT <5:1> |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 6 | BZL | BB | BY | BA | BX | BZR | BDL | BDU |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * All buttons are 0 if pressed
+ * RX and RY are right analog stick
+ * LX and LY are left analog stick
+ * LT is left trigger, RT is right trigger
+ * BLT is 0 if left trigger is fully pressed
+ * BRT is 0 if right trigger is fully pressed
+ * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons
+ * BZL is left Z button and BZR is right Z button
+ * B-, BH, B+ are +, HOME and - buttons
+ * BB, BY, BA, BX are A, B, X, Y buttons
+ * LSB of RX, RY, LT, and RT are not transmitted and always 0.
+ *
+ * With motionp enabled it changes slightly to this:
+ * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 1 | RX <5:4> | LX <5:1> | BDU |
+ * 2 | RX <3:2> | LY <5:1> | BDL |
+ * -----+-----+-----+-----+-----------------------+-----+
+ * 3 |RX<1>| LT <5:4> | RY <5:1> |
+ * -----+-----+-----------+-----------------------------+
+ * 4 | LT <3:1> | RT <5:1> |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | EXT |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 6 | BZL | BB | BY | BA | BX | BZR | 0 | 0 |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * Only the LSBs of LX and LY are lost. BDU and BDL are moved, the rest
+ * is the same as before.
+ */
+
+ if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
+ lx = ext[0] & 0x3e;
+ ly = ext[1] & 0x3e;
+ } else {
+ lx = ext[0] & 0x3f;
+ ly = ext[1] & 0x3f;
+ }
+
+ rx = (ext[0] >> 3) & 0x18;
+ rx |= (ext[1] >> 5) & 0x06;
+ rx |= (ext[2] >> 7) & 0x01;
+ ry = ext[2] & 0x1f;
+
+ rt = ext[3] & 0x1f;
+ lt = (ext[2] >> 2) & 0x18;
+ lt |= (ext[3] >> 5) & 0x07;
+
+ rx <<= 1;
+ ry <<= 1;
+ rt <<= 1;
+ lt <<= 1;
+
+ input_report_abs(wdata->extension.input, ABS_HAT1X, lx - 0x20);
+ input_report_abs(wdata->extension.input, ABS_HAT1Y, ly - 0x20);
+ input_report_abs(wdata->extension.input, ABS_HAT2X, rx - 0x20);
+ input_report_abs(wdata->extension.input, ABS_HAT2Y, ry - 0x20);
+ input_report_abs(wdata->extension.input, ABS_HAT3X, rt);
+ input_report_abs(wdata->extension.input, ABS_HAT3Y, lt);
+
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_RIGHT],
+ !(ext[4] & 0x80));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_DOWN],
+ !(ext[4] & 0x40));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_LT],
+ !(ext[4] & 0x20));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_MINUS],
+ !(ext[4] & 0x10));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_HOME],
+ !(ext[4] & 0x08));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_PLUS],
+ !(ext[4] & 0x04));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_RT],
+ !(ext[4] & 0x02));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZL],
+ !(ext[5] & 0x80));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_B],
+ !(ext[5] & 0x40));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_Y],
+ !(ext[5] & 0x20));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_A],
+ !(ext[5] & 0x10));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_X],
+ !(ext[5] & 0x08));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_ZR],
+ !(ext[5] & 0x04));
+
+ if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
+ !(ext[1] & 0x01));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
+ !(ext[0] & 0x01));
+ } else {
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_LEFT],
+ !(ext[5] & 0x02));
+ input_report_key(wdata->extension.input,
+ wiimod_classic_map[WIIMOD_CLASSIC_KEY_UP],
+ !(ext[5] & 0x01));
+ }
+
+ input_sync(wdata->extension.input);
+}
+
+static int wiimod_classic_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_classic_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_classic_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret, i;
+
+ wdata->extension.input = input_allocate_device();
+ if (!wdata->extension.input)
+ return -ENOMEM;
+
+ input_set_drvdata(wdata->extension.input, wdata);
+ wdata->extension.input->open = wiimod_classic_open;
+ wdata->extension.input->close = wiimod_classic_close;
+ wdata->extension.input->dev.parent = &wdata->hdev->dev;
+ wdata->extension.input->id.bustype = wdata->hdev->bus;
+ wdata->extension.input->id.vendor = wdata->hdev->vendor;
+ wdata->extension.input->id.product = wdata->hdev->product;
+ wdata->extension.input->id.version = wdata->hdev->version;
+ wdata->extension.input->name = WIIMOTE_NAME " Classic Controller";
+
+ set_bit(EV_KEY, wdata->extension.input->evbit);
+ for (i = 0; i < WIIMOD_CLASSIC_KEY_NUM; ++i)
+ set_bit(wiimod_classic_map[i],
+ wdata->extension.input->keybit);
+
+ set_bit(EV_ABS, wdata->extension.input->evbit);
+ set_bit(ABS_HAT1X, wdata->extension.input->absbit);
+ set_bit(ABS_HAT1Y, wdata->extension.input->absbit);
+ set_bit(ABS_HAT2X, wdata->extension.input->absbit);
+ set_bit(ABS_HAT2Y, wdata->extension.input->absbit);
+ set_bit(ABS_HAT3X, wdata->extension.input->absbit);
+ set_bit(ABS_HAT3Y, wdata->extension.input->absbit);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT1X, -30, 30, 1, 1);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT1Y, -30, 30, 1, 1);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT2X, -30, 30, 1, 1);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT2Y, -30, 30, 1, 1);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT3X, -30, 30, 1, 1);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT3Y, -30, 30, 1, 1);
+
+ ret = input_register_device(wdata->extension.input);
+ if (ret)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ input_free_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+ return ret;
+}
+
+static void wiimod_classic_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->extension.input)
+ return;
+
+ input_unregister_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_classic = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_classic_probe,
+ .remove = wiimod_classic_remove,
+ .in_ext = wiimod_classic_in_ext,
+};
+
+/*
+ * Balance Board Extension
+ * The Nintendo Wii Balance Board provides four hardware weight sensor plus a
+ * single push button. No other peripherals are available. However, the
+ * balance-board data is sent via a standard Wii Remote extension. All other
+ * data for non-present hardware is zeroed out.
+ * Some 3rd party devices react allergic if we try to access normal Wii Remote
+ * hardware, so this extension module should be the only module that is loaded
+ * on balance boards.
+ * The balance board needs 8 bytes extension data instead of basic 6 bytes so
+ * it needs the WIIMOD_FLAG_EXT8 flag.
+ */
+
+static void wiimod_bboard_in_keys(struct wiimote_data *wdata, const __u8 *keys)
+{
+ input_report_key(wdata->extension.input, BTN_A,
+ !!(keys[1] & 0x08));
+ input_sync(wdata->extension.input);
+}
+
+static void wiimod_bboard_in_ext(struct wiimote_data *wdata,
+ const __u8 *ext)
+{
+ __s32 val[4], tmp, div;
+ unsigned int i;
+ struct wiimote_state *s = &wdata->state;
+
+ /*
+ * Balance board data layout:
+ *
+ * Byte | 8 7 6 5 4 3 2 1 |
+ * -----+--------------------------+
+ * 1 | Top Right <15:8> |
+ * 2 | Top Right <7:0> |
+ * -----+--------------------------+
+ * 3 | Bottom Right <15:8> |
+ * 4 | Bottom Right <7:0> |
+ * -----+--------------------------+
+ * 5 | Top Left <15:8> |
+ * 6 | Top Left <7:0> |
+ * -----+--------------------------+
+ * 7 | Bottom Left <15:8> |
+ * 8 | Bottom Left <7:0> |
+ * -----+--------------------------+
+ *
+ * These values represent the weight-measurements of the Wii-balance
+ * board with 16bit precision.
+ *
+ * The balance-board is never reported interleaved with motionp.
+ */
+
+ val[0] = ext[0];
+ val[0] <<= 8;
+ val[0] |= ext[1];
+
+ val[1] = ext[2];
+ val[1] <<= 8;
+ val[1] |= ext[3];
+
+ val[2] = ext[4];
+ val[2] <<= 8;
+ val[2] |= ext[5];
+
+ val[3] = ext[6];
+ val[3] <<= 8;
+ val[3] |= ext[7];
+
+ /* apply calibration data */
+ for (i = 0; i < 4; i++) {
+ if (val[i] <= s->calib_bboard[i][0]) {
+ tmp = 0;
+ } else if (val[i] < s->calib_bboard[i][1]) {
+ tmp = val[i] - s->calib_bboard[i][0];
+ tmp *= 1700;
+ div = s->calib_bboard[i][1] - s->calib_bboard[i][0];
+ tmp /= div ? div : 1;
+ } else {
+ tmp = val[i] - s->calib_bboard[i][1];
+ tmp *= 1700;
+ div = s->calib_bboard[i][2] - s->calib_bboard[i][1];
+ tmp /= div ? div : 1;
+ tmp += 1700;
+ }
+ val[i] = tmp;
+ }
+
+ input_report_abs(wdata->extension.input, ABS_HAT0X, val[0]);
+ input_report_abs(wdata->extension.input, ABS_HAT0Y, val[1]);
+ input_report_abs(wdata->extension.input, ABS_HAT1X, val[2]);
+ input_report_abs(wdata->extension.input, ABS_HAT1Y, val[3]);
+ input_sync(wdata->extension.input);
+}
+
+static int wiimod_bboard_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_bboard_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static ssize_t wiimod_bboard_calib_show(struct device *dev,
+ struct device_attribute *attr,
+ char *out)
+{
+ struct wiimote_data *wdata = dev_to_wii(dev);
+ int i, j, ret;
+ __u16 val;
+ __u8 buf[24], offs;
+
+ ret = wiimote_cmd_acquire(wdata);
+ if (ret)
+ return ret;
+
+ ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12);
+ if (ret != 12) {
+ wiimote_cmd_release(wdata);
+ return ret < 0 ? ret : -EIO;
+ }
+ ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12);
+ if (ret != 12) {
+ wiimote_cmd_release(wdata);
+ return ret < 0 ? ret : -EIO;
+ }
+
+ wiimote_cmd_release(wdata);
+
+ spin_lock_irq(&wdata->state.lock);
+ offs = 0;
+ for (i = 0; i < 3; ++i) {
+ for (j = 0; j < 4; ++j) {
+ wdata->state.calib_bboard[j][i] = buf[offs];
+ wdata->state.calib_bboard[j][i] <<= 8;
+ wdata->state.calib_bboard[j][i] |= buf[offs + 1];
+ offs += 2;
+ }
+ }
+ spin_unlock_irq(&wdata->state.lock);
+
+ ret = 0;
+ for (i = 0; i < 3; ++i) {
+ for (j = 0; j < 4; ++j) {
+ val = wdata->state.calib_bboard[j][i];
+ if (i == 2 && j == 3)
+ ret += sprintf(&out[ret], "%04x\n", val);
+ else
+ ret += sprintf(&out[ret], "%04x:", val);
+ }
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(bboard_calib, S_IRUGO, wiimod_bboard_calib_show, NULL);
+
+static int wiimod_bboard_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret, i, j;
+ __u8 buf[24], offs;
+
+ wiimote_cmd_acquire_noint(wdata);
+
+ ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12);
+ if (ret != 12) {
+ wiimote_cmd_release(wdata);
+ return ret < 0 ? ret : -EIO;
+ }
+ ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12);
+ if (ret != 12) {
+ wiimote_cmd_release(wdata);
+ return ret < 0 ? ret : -EIO;
+ }
+
+ wiimote_cmd_release(wdata);
+
+ offs = 0;
+ for (i = 0; i < 3; ++i) {
+ for (j = 0; j < 4; ++j) {
+ wdata->state.calib_bboard[j][i] = buf[offs];
+ wdata->state.calib_bboard[j][i] <<= 8;
+ wdata->state.calib_bboard[j][i] |= buf[offs + 1];
+ offs += 2;
+ }
+ }
+
+ wdata->extension.input = input_allocate_device();
+ if (!wdata->extension.input)
+ return -ENOMEM;
+
+ ret = device_create_file(&wdata->hdev->dev,
+ &dev_attr_bboard_calib);
+ if (ret) {
+ hid_err(wdata->hdev, "cannot create sysfs attribute\n");
+ goto err_free;
+ }
+
+ input_set_drvdata(wdata->extension.input, wdata);
+ wdata->extension.input->open = wiimod_bboard_open;
+ wdata->extension.input->close = wiimod_bboard_close;
+ wdata->extension.input->dev.parent = &wdata->hdev->dev;
+ wdata->extension.input->id.bustype = wdata->hdev->bus;
+ wdata->extension.input->id.vendor = wdata->hdev->vendor;
+ wdata->extension.input->id.product = wdata->hdev->product;
+ wdata->extension.input->id.version = wdata->hdev->version;
+ wdata->extension.input->name = WIIMOTE_NAME " Balance Board";
+
+ set_bit(EV_KEY, wdata->extension.input->evbit);
+ set_bit(BTN_A, wdata->extension.input->keybit);
+
+ set_bit(EV_ABS, wdata->extension.input->evbit);
+ set_bit(ABS_HAT0X, wdata->extension.input->absbit);
+ set_bit(ABS_HAT0Y, wdata->extension.input->absbit);
+ set_bit(ABS_HAT1X, wdata->extension.input->absbit);
+ set_bit(ABS_HAT1Y, wdata->extension.input->absbit);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT0X, 0, 65535, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT0Y, 0, 65535, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT1X, 0, 65535, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_HAT1Y, 0, 65535, 2, 4);
+
+ ret = input_register_device(wdata->extension.input);
+ if (ret)
+ goto err_file;
+
+ return 0;
+
+err_file:
+ device_remove_file(&wdata->hdev->dev,
+ &dev_attr_bboard_calib);
+err_free:
+ input_free_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+ return ret;
+}
+
+static void wiimod_bboard_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->extension.input)
+ return;
+
+ input_unregister_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+ device_remove_file(&wdata->hdev->dev,
+ &dev_attr_bboard_calib);
+}
+
+static const struct wiimod_ops wiimod_bboard = {
+ .flags = WIIMOD_FLAG_EXT8,
+ .arg = 0,
+ .probe = wiimod_bboard_probe,
+ .remove = wiimod_bboard_remove,
+ .in_keys = wiimod_bboard_in_keys,
+ .in_ext = wiimod_bboard_in_ext,
+};
+
+/*
+ * Pro Controller
+ * Released with the Wii U was the Nintendo Wii U Pro Controller. It does not
+ * work together with the classic Wii, but only with the new Wii U. However, it
+ * uses the same protocol and provides a builtin "classic controller pro"
+ * extension, few standard buttons, a rumble motor, 4 LEDs and a battery.
+ * We provide all these via a standard extension device as the device doesn't
+ * feature an extension port.
+ */
+
+enum wiimod_pro_keys {
+ WIIMOD_PRO_KEY_A,
+ WIIMOD_PRO_KEY_B,
+ WIIMOD_PRO_KEY_X,
+ WIIMOD_PRO_KEY_Y,
+ WIIMOD_PRO_KEY_PLUS,
+ WIIMOD_PRO_KEY_MINUS,
+ WIIMOD_PRO_KEY_HOME,
+ WIIMOD_PRO_KEY_LEFT,
+ WIIMOD_PRO_KEY_RIGHT,
+ WIIMOD_PRO_KEY_UP,
+ WIIMOD_PRO_KEY_DOWN,
+ WIIMOD_PRO_KEY_TL,
+ WIIMOD_PRO_KEY_TR,
+ WIIMOD_PRO_KEY_ZL,
+ WIIMOD_PRO_KEY_ZR,
+ WIIMOD_PRO_KEY_THUMBL,
+ WIIMOD_PRO_KEY_THUMBR,
+ WIIMOD_PRO_KEY_NUM,
+};
+
+static const __u16 wiimod_pro_map[] = {
+ BTN_EAST, /* WIIMOD_PRO_KEY_A */
+ BTN_SOUTH, /* WIIMOD_PRO_KEY_B */
+ BTN_NORTH, /* WIIMOD_PRO_KEY_X */
+ BTN_WEST, /* WIIMOD_PRO_KEY_Y */
+ BTN_START, /* WIIMOD_PRO_KEY_PLUS */
+ BTN_SELECT, /* WIIMOD_PRO_KEY_MINUS */
+ BTN_MODE, /* WIIMOD_PRO_KEY_HOME */
+ BTN_DPAD_LEFT, /* WIIMOD_PRO_KEY_LEFT */
+ BTN_DPAD_RIGHT, /* WIIMOD_PRO_KEY_RIGHT */
+ BTN_DPAD_UP, /* WIIMOD_PRO_KEY_UP */
+ BTN_DPAD_DOWN, /* WIIMOD_PRO_KEY_DOWN */
+ BTN_TL, /* WIIMOD_PRO_KEY_TL */
+ BTN_TR, /* WIIMOD_PRO_KEY_TR */
+ BTN_TL2, /* WIIMOD_PRO_KEY_ZL */
+ BTN_TR2, /* WIIMOD_PRO_KEY_ZR */
+ BTN_THUMBL, /* WIIMOD_PRO_KEY_THUMBL */
+ BTN_THUMBR, /* WIIMOD_PRO_KEY_THUMBR */
+};
+
+static void wiimod_pro_in_ext(struct wiimote_data *wdata, const __u8 *ext)
+{
+ __s16 rx, ry, lx, ly;
+
+ /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 1 | LX <7:0> |
+ * -----+-----------------------+-----------------------+
+ * 2 | 0 0 0 0 | LX <11:8> |
+ * -----+-----------------------+-----------------------+
+ * 3 | RX <7:0> |
+ * -----+-----------------------+-----------------------+
+ * 4 | 0 0 0 0 | RX <11:8> |
+ * -----+-----------------------+-----------------------+
+ * 5 | LY <7:0> |
+ * -----+-----------------------+-----------------------+
+ * 6 | 0 0 0 0 | LY <11:8> |
+ * -----+-----------------------+-----------------------+
+ * 7 | RY <7:0> |
+ * -----+-----------------------+-----------------------+
+ * 8 | 0 0 0 0 | RY <11:8> |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 9 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 10 | BZL | BB | BY | BA | BX | BZR | BDL | BDU |
+ * -----+-----+-----+-----+-----+-----+-----+-----+-----+
+ * 11 | 1 | BATTERY | USB |CHARG|LTHUM|RTHUM|
+ * -----+-----+-----------------+-----------+-----+-----+
+ * All buttons are low-active (0 if pressed)
+ * RX and RY are right analog stick
+ * LX and LY are left analog stick
+ * BLT is left trigger, BRT is right trigger.
+ * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons
+ * BZL is left Z button and BZR is right Z button
+ * B-, BH, B+ are +, HOME and - buttons
+ * BB, BY, BA, BX are A, B, X, Y buttons
+ *
+ * Bits marked as 0/1 are unknown and never changed during tests.
+ *
+ * Not entirely verified:
+ * CHARG: 1 if uncharging, 0 if charging
+ * USB: 1 if not connected, 0 if connected
+ * BATTERY: battery capacity from 000 (empty) to 100 (full)
+ */
+
+ lx = (ext[0] & 0xff) | ((ext[1] & 0x0f) << 8);
+ rx = (ext[2] & 0xff) | ((ext[3] & 0x0f) << 8);
+ ly = (ext[4] & 0xff) | ((ext[5] & 0x0f) << 8);
+ ry = (ext[6] & 0xff) | ((ext[7] & 0x0f) << 8);
+
+ input_report_abs(wdata->extension.input, ABS_X, lx - 0x800);
+ input_report_abs(wdata->extension.input, ABS_Y, ly - 0x800);
+ input_report_abs(wdata->extension.input, ABS_RX, rx - 0x800);
+ input_report_abs(wdata->extension.input, ABS_RY, ry - 0x800);
+
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_RIGHT],
+ !(ext[8] & 0x80));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_DOWN],
+ !(ext[8] & 0x40));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_TL],
+ !(ext[8] & 0x20));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_MINUS],
+ !(ext[8] & 0x10));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_HOME],
+ !(ext[8] & 0x08));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_PLUS],
+ !(ext[8] & 0x04));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_TR],
+ !(ext[8] & 0x02));
+
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_ZL],
+ !(ext[9] & 0x80));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_B],
+ !(ext[9] & 0x40));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_Y],
+ !(ext[9] & 0x20));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_A],
+ !(ext[9] & 0x10));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_X],
+ !(ext[9] & 0x08));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_ZR],
+ !(ext[9] & 0x04));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_LEFT],
+ !(ext[9] & 0x02));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_UP],
+ !(ext[9] & 0x01));
+
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_THUMBL],
+ !(ext[10] & 0x02));
+ input_report_key(wdata->extension.input,
+ wiimod_pro_map[WIIMOD_PRO_KEY_THUMBR],
+ !(ext[10] & 0x01));
+
+ input_sync(wdata->extension.input);
+}
+
+static int wiimod_pro_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_pro_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_pro_play(struct input_dev *dev, void *data,
+ struct ff_effect *eff)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 value;
+ unsigned long flags;
+
+ /*
+ * The wiimote supports only a single rumble motor so if any magnitude
+ * is set to non-zero then we start the rumble motor. If both are set to
+ * zero, we stop the rumble motor.
+ */
+
+ if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
+ value = 1;
+ else
+ value = 0;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_rumble(wdata, value);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static int wiimod_pro_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret, i;
+
+ wdata->extension.input = input_allocate_device();
+ if (!wdata->extension.input)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, wdata->extension.input->ffbit);
+ input_set_drvdata(wdata->extension.input, wdata);
+
+ if (input_ff_create_memless(wdata->extension.input, NULL,
+ wiimod_pro_play)) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ wdata->extension.input->open = wiimod_pro_open;
+ wdata->extension.input->close = wiimod_pro_close;
+ wdata->extension.input->dev.parent = &wdata->hdev->dev;
+ wdata->extension.input->id.bustype = wdata->hdev->bus;
+ wdata->extension.input->id.vendor = wdata->hdev->vendor;
+ wdata->extension.input->id.product = wdata->hdev->product;
+ wdata->extension.input->id.version = wdata->hdev->version;
+ wdata->extension.input->name = WIIMOTE_NAME " Pro Controller";
+
+ set_bit(EV_KEY, wdata->extension.input->evbit);
+ for (i = 0; i < WIIMOD_PRO_KEY_NUM; ++i)
+ set_bit(wiimod_pro_map[i],
+ wdata->extension.input->keybit);
+
+ set_bit(EV_ABS, wdata->extension.input->evbit);
+ set_bit(ABS_X, wdata->extension.input->absbit);
+ set_bit(ABS_Y, wdata->extension.input->absbit);
+ set_bit(ABS_RX, wdata->extension.input->absbit);
+ set_bit(ABS_RY, wdata->extension.input->absbit);
+ input_set_abs_params(wdata->extension.input,
+ ABS_X, -0x800, 0x800, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_Y, -0x800, 0x800, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_RX, -0x800, 0x800, 2, 4);
+ input_set_abs_params(wdata->extension.input,
+ ABS_RY, -0x800, 0x800, 2, 4);
+
+ ret = input_register_device(wdata->extension.input);
+ if (ret)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ input_free_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+ return ret;
+}
+
+static void wiimod_pro_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned long flags;
+
+ if (!wdata->extension.input)
+ return;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_rumble(wdata, 0);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ input_unregister_device(wdata->extension.input);
+ wdata->extension.input = NULL;
+}
+
+static const struct wiimod_ops wiimod_pro = {
+ .flags = WIIMOD_FLAG_EXT16,
+ .arg = 0,
+ .probe = wiimod_pro_probe,
+ .remove = wiimod_pro_remove,
+ .in_ext = wiimod_pro_in_ext,
+};
+
+/*
+ * Builtin Motion Plus
+ * This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
+ * disables polling for Motion-Plus. This should be set only for devices which
+ * don't allow MP hotplugging.
+ */
+
+static int wiimod_builtin_mp_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_BUILTIN_MP;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_builtin_mp_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_BUILTIN_MP;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static const struct wiimod_ops wiimod_builtin_mp = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_builtin_mp_probe,
+ .remove = wiimod_builtin_mp_remove,
+};
+
+/*
+ * No Motion Plus
+ * This module simply sets the WIIPROTO_FLAG_NO_MP protocol flag which
+ * disables motion-plus. This is needed for devices that advertise this but we
+ * don't know how to use it (or whether it is actually present).
+ */
+
+static int wiimod_no_mp_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_NO_MP;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_no_mp_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_NO_MP;
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static const struct wiimod_ops wiimod_no_mp = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_no_mp_probe,
+ .remove = wiimod_no_mp_remove,
+};
+
+/*
+ * Motion Plus
+ * The Motion Plus extension provides rotation sensors (gyro) as a small
+ * extension device for Wii Remotes. Many devices have them built-in so
+ * you cannot see them from the outside.
+ * Motion Plus extensions are special because they are on a separate extension
+ * port and allow other extensions to be used simultaneously. This is all
+ * handled by the Wiimote Core so we don't have to deal with it.
+ */
+
+static void wiimod_mp_in_mp(struct wiimote_data *wdata, const __u8 *ext)
+{
+ __s32 x, y, z;
+
+ /* | 8 7 6 5 4 3 | 2 | 1 |
+ * -----+------------------------------+-----+-----+
+ * 1 | Yaw Speed <7:0> |
+ * 2 | Roll Speed <7:0> |
+ * 3 | Pitch Speed <7:0> |
+ * -----+------------------------------+-----+-----+
+ * 4 | Yaw Speed <13:8> | Yaw |Pitch|
+ * -----+------------------------------+-----+-----+
+ * 5 | Roll Speed <13:8> |Roll | Ext |
+ * -----+------------------------------+-----+-----+
+ * 6 | Pitch Speed <13:8> | 1 | 0 |
+ * -----+------------------------------+-----+-----+
+ * The single bits Yaw, Roll, Pitch in the lower right corner specify
+ * whether the wiimote is rotating fast (0) or slow (1). Speed for slow
+ * roation is 440 deg/s and for fast rotation 2000 deg/s. To get a
+ * linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast
+ * and 9 for slow.
+ * If the wiimote is not rotating the sensor reports 2^13 = 8192.
+ * Ext specifies whether an extension is connected to the motionp.
+ * which is parsed by wiimote-core.
+ */
+
+ x = ext[0];
+ y = ext[1];
+ z = ext[2];
+
+ x |= (((__u16)ext[3]) << 6) & 0xff00;
+ y |= (((__u16)ext[4]) << 6) & 0xff00;
+ z |= (((__u16)ext[5]) << 6) & 0xff00;
+
+ x -= 8192;
+ y -= 8192;
+ z -= 8192;
+
+ if (!(ext[3] & 0x02))
+ x *= 18;
+ else
+ x *= 9;
+ if (!(ext[4] & 0x02))
+ y *= 18;
+ else
+ y *= 9;
+ if (!(ext[3] & 0x01))
+ z *= 18;
+ else
+ z *= 9;
+
+ input_report_abs(wdata->mp, ABS_RX, x);
+ input_report_abs(wdata->mp, ABS_RY, y);
+ input_report_abs(wdata->mp, ABS_RZ, z);
+ input_sync(wdata->mp);
+}
+
+static int wiimod_mp_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags |= WIIPROTO_FLAG_MP_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ __wiimote_schedule(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
+static void wiimod_mp_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wdata->state.flags &= ~WIIPROTO_FLAG_MP_USED;
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+ __wiimote_schedule(wdata);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+}
+
+static int wiimod_mp_probe(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ int ret;
+
+ wdata->mp = input_allocate_device();
+ if (!wdata->mp)
+ return -ENOMEM;
+
+ input_set_drvdata(wdata->mp, wdata);
+ wdata->mp->open = wiimod_mp_open;
+ wdata->mp->close = wiimod_mp_close;
+ wdata->mp->dev.parent = &wdata->hdev->dev;
+ wdata->mp->id.bustype = wdata->hdev->bus;
+ wdata->mp->id.vendor = wdata->hdev->vendor;
+ wdata->mp->id.product = wdata->hdev->product;
+ wdata->mp->id.version = wdata->hdev->version;
+ wdata->mp->name = WIIMOTE_NAME " Motion Plus";
+
+ set_bit(EV_ABS, wdata->mp->evbit);
+ set_bit(ABS_RX, wdata->mp->absbit);
+ set_bit(ABS_RY, wdata->mp->absbit);
+ set_bit(ABS_RZ, wdata->mp->absbit);
+ input_set_abs_params(wdata->mp,
+ ABS_RX, -16000, 16000, 4, 8);
+ input_set_abs_params(wdata->mp,
+ ABS_RY, -16000, 16000, 4, 8);
+ input_set_abs_params(wdata->mp,
+ ABS_RZ, -16000, 16000, 4, 8);
+
+ ret = input_register_device(wdata->mp);
+ if (ret)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ input_free_device(wdata->mp);
+ wdata->mp = NULL;
+ return ret;
+}
+
+static void wiimod_mp_remove(const struct wiimod_ops *ops,
+ struct wiimote_data *wdata)
+{
+ if (!wdata->mp)
+ return;
+
+ input_unregister_device(wdata->mp);
+ wdata->mp = NULL;
+}
+
+const struct wiimod_ops wiimod_mp = {
+ .flags = 0,
+ .arg = 0,
+ .probe = wiimod_mp_probe,
+ .remove = wiimod_mp_remove,
+ .in_mp = wiimod_mp_in_mp,
+};
+
+/* module table */
+
+static const struct wiimod_ops wiimod_dummy;
+
+const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
+ [WIIMOD_KEYS] = &wiimod_keys,
+ [WIIMOD_RUMBLE] = &wiimod_rumble,
+ [WIIMOD_BATTERY] = &wiimod_battery,
+ [WIIMOD_LED1] = &wiimod_leds[0],
+ [WIIMOD_LED2] = &wiimod_leds[1],
+ [WIIMOD_LED3] = &wiimod_leds[2],
+ [WIIMOD_LED4] = &wiimod_leds[3],
+ [WIIMOD_ACCEL] = &wiimod_accel,
+ [WIIMOD_IR] = &wiimod_ir,
+ [WIIMOD_BUILTIN_MP] = &wiimod_builtin_mp,
+ [WIIMOD_NO_MP] = &wiimod_no_mp,
+};
+
+const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
+ [WIIMOTE_EXT_NONE] = &wiimod_dummy,
+ [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy,
+ [WIIMOTE_EXT_NUNCHUK] = &wiimod_nunchuk,
+ [WIIMOTE_EXT_CLASSIC_CONTROLLER] = &wiimod_classic,
+ [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
+ [WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
+};
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index c81dbeb086c5..f1474f372c0b 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -2,8 +2,8 @@
#define __HID_WIIMOTE_H
/*
- * HID driver for Nintendo Wiimote devices
- * Copyright (c) 2011 David Herrmann
+ * HID driver for Nintendo Wii / Wii U peripherals
+ * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com>
*/
/*
@@ -22,6 +22,7 @@
#include <linux/mutex.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
+#include <linux/timer.h>
#define WIIMOTE_NAME "Nintendo Wii Remote"
#define WIIMOTE_BUFSIZE 32
@@ -35,6 +36,17 @@
#define WIIPROTO_FLAG_IR_BASIC 0x40
#define WIIPROTO_FLAG_IR_EXT 0x80
#define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */
+#define WIIPROTO_FLAG_EXT_PLUGGED 0x0100
+#define WIIPROTO_FLAG_EXT_USED 0x0200
+#define WIIPROTO_FLAG_EXT_ACTIVE 0x0400
+#define WIIPROTO_FLAG_MP_PLUGGED 0x0800
+#define WIIPROTO_FLAG_MP_USED 0x1000
+#define WIIPROTO_FLAG_MP_ACTIVE 0x2000
+#define WIIPROTO_FLAG_EXITING 0x4000
+#define WIIPROTO_FLAG_DRM_LOCKED 0x8000
+#define WIIPROTO_FLAG_BUILTIN_MP 0x010000
+#define WIIPROTO_FLAG_NO_MP 0x020000
+
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
#define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \
@@ -43,16 +55,71 @@
/* return flag for led \num */
#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
+enum wiiproto_keys {
+ WIIPROTO_KEY_LEFT,
+ WIIPROTO_KEY_RIGHT,
+ WIIPROTO_KEY_UP,
+ WIIPROTO_KEY_DOWN,
+ WIIPROTO_KEY_PLUS,
+ WIIPROTO_KEY_MINUS,
+ WIIPROTO_KEY_ONE,
+ WIIPROTO_KEY_TWO,
+ WIIPROTO_KEY_A,
+ WIIPROTO_KEY_B,
+ WIIPROTO_KEY_HOME,
+ WIIPROTO_KEY_COUNT
+};
+
+enum wiimote_devtype {
+ WIIMOTE_DEV_PENDING,
+ WIIMOTE_DEV_UNKNOWN,
+ WIIMOTE_DEV_GENERIC,
+ WIIMOTE_DEV_GEN10,
+ WIIMOTE_DEV_GEN20,
+ WIIMOTE_DEV_BALANCE_BOARD,
+ WIIMOTE_DEV_PRO_CONTROLLER,
+ WIIMOTE_DEV_NUM,
+};
+
+enum wiimote_exttype {
+ WIIMOTE_EXT_NONE,
+ WIIMOTE_EXT_UNKNOWN,
+ WIIMOTE_EXT_NUNCHUK,
+ WIIMOTE_EXT_CLASSIC_CONTROLLER,
+ WIIMOTE_EXT_BALANCE_BOARD,
+ WIIMOTE_EXT_PRO_CONTROLLER,
+ WIIMOTE_EXT_NUM,
+};
+
+enum wiimote_mptype {
+ WIIMOTE_MP_NONE,
+ WIIMOTE_MP_UNKNOWN,
+ WIIMOTE_MP_SINGLE,
+ WIIMOTE_MP_PASSTHROUGH_NUNCHUK,
+ WIIMOTE_MP_PASSTHROUGH_CLASSIC,
+};
+
struct wiimote_buf {
__u8 data[HID_MAX_BUFFER_SIZE];
size_t size;
};
+struct wiimote_queue {
+ spinlock_t lock;
+ struct work_struct worker;
+ __u8 head;
+ __u8 tail;
+ struct wiimote_buf outq[WIIMOTE_BUFSIZE];
+};
+
struct wiimote_state {
spinlock_t lock;
- __u8 flags;
+ __u32 flags;
__u8 accel_split[2];
__u8 drm;
+ __u8 devtype;
+ __u8 exttype;
+ __u8 mp;
/* synchronous cmd requests */
struct mutex sync;
@@ -65,6 +132,9 @@ struct wiimote_state {
__u8 cmd_err;
__u8 *cmd_read_buf;
__u8 cmd_read_size;
+
+ /* calibration data */
+ __u16 calib_bboard[4][3];
};
struct wiimote_data {
@@ -74,18 +144,63 @@ struct wiimote_data {
struct input_dev *accel;
struct input_dev *ir;
struct power_supply battery;
- struct wiimote_ext *ext;
+ struct input_dev *mp;
+ struct timer_list timer;
struct wiimote_debug *debug;
- spinlock_t qlock;
- __u8 head;
- __u8 tail;
- struct wiimote_buf outq[WIIMOTE_BUFSIZE];
- struct work_struct worker;
+ union {
+ struct input_dev *input;
+ } extension;
+ struct wiimote_queue queue;
struct wiimote_state state;
+ struct work_struct init_worker;
+};
+
+/* wiimote modules */
+
+enum wiimod_module {
+ WIIMOD_KEYS,
+ WIIMOD_RUMBLE,
+ WIIMOD_BATTERY,
+ WIIMOD_LED1,
+ WIIMOD_LED2,
+ WIIMOD_LED3,
+ WIIMOD_LED4,
+ WIIMOD_ACCEL,
+ WIIMOD_IR,
+ WIIMOD_BUILTIN_MP,
+ WIIMOD_NO_MP,
+ WIIMOD_NUM,
+ WIIMOD_NULL = WIIMOD_NUM,
+};
+
+#define WIIMOD_FLAG_INPUT 0x0001
+#define WIIMOD_FLAG_EXT8 0x0002
+#define WIIMOD_FLAG_EXT16 0x0004
+
+struct wiimod_ops {
+ __u16 flags;
+ unsigned long arg;
+ int (*probe) (const struct wiimod_ops *ops,
+ struct wiimote_data *wdata);
+ void (*remove) (const struct wiimod_ops *ops,
+ struct wiimote_data *wdata);
+
+ void (*in_keys) (struct wiimote_data *wdata, const __u8 *keys);
+ void (*in_accel) (struct wiimote_data *wdata, const __u8 *accel);
+ void (*in_ir) (struct wiimote_data *wdata, const __u8 *ir, bool packed,
+ unsigned int id);
+ void (*in_mp) (struct wiimote_data *wdata, const __u8 *mp);
+ void (*in_ext) (struct wiimote_data *wdata, const __u8 *ext);
};
+extern const struct wiimod_ops *wiimod_table[WIIMOD_NUM];
+extern const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM];
+extern const struct wiimod_ops wiimod_mp;
+
+/* wiimote requests */
+
enum wiiproto_reqs {
WIIPROTO_REQ_NULL = 0x0,
WIIPROTO_REQ_RUMBLE = 0x10,
@@ -99,24 +214,55 @@ enum wiiproto_reqs {
WIIPROTO_REQ_STATUS = 0x20,
WIIPROTO_REQ_DATA = 0x21,
WIIPROTO_REQ_RETURN = 0x22,
+
+ /* DRM_K: BB*2 */
WIIPROTO_REQ_DRM_K = 0x30,
+
+ /* DRM_KA: BB*2 AA*3 */
WIIPROTO_REQ_DRM_KA = 0x31,
+
+ /* DRM_KE: BB*2 EE*8 */
WIIPROTO_REQ_DRM_KE = 0x32,
+
+ /* DRM_KAI: BB*2 AA*3 II*12 */
WIIPROTO_REQ_DRM_KAI = 0x33,
+
+ /* DRM_KEE: BB*2 EE*19 */
WIIPROTO_REQ_DRM_KEE = 0x34,
+
+ /* DRM_KAE: BB*2 AA*3 EE*16 */
WIIPROTO_REQ_DRM_KAE = 0x35,
+
+ /* DRM_KIE: BB*2 II*10 EE*9 */
WIIPROTO_REQ_DRM_KIE = 0x36,
+
+ /* DRM_KAIE: BB*2 AA*3 II*10 EE*6 */
WIIPROTO_REQ_DRM_KAIE = 0x37,
+
+ /* DRM_E: EE*21 */
WIIPROTO_REQ_DRM_E = 0x3d,
+
+ /* DRM_SKAI1: BB*2 AA*1 II*18 */
WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
+
+ /* DRM_SKAI2: BB*2 AA*1 II*18 */
WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
+
WIIPROTO_REQ_MAX
};
#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
dev))
+void __wiimote_schedule(struct wiimote_data *wdata);
+
extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm);
+extern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble);
+extern void wiiproto_req_leds(struct wiimote_data *wdata, int leds);
+extern void wiiproto_req_status(struct wiimote_data *wdata);
+extern void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel);
+extern void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags);
+extern void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags);
extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
const __u8 *wmem, __u8 size);
extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset,
@@ -129,24 +275,6 @@ extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset,
extern void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom,
__u32 offset, __u16 size);
-#ifdef CONFIG_HID_WIIMOTE_EXT
-
-extern int wiiext_init(struct wiimote_data *wdata);
-extern void wiiext_deinit(struct wiimote_data *wdata);
-extern void wiiext_event(struct wiimote_data *wdata, bool plugged);
-extern bool wiiext_active(struct wiimote_data *wdata);
-extern void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload);
-
-#else
-
-static inline int wiiext_init(void *u) { return 0; }
-static inline void wiiext_deinit(void *u) { }
-static inline void wiiext_event(void *u, bool p) { }
-static inline bool wiiext_active(void *u) { return false; }
-static inline void wiiext_handle(void *u, const __u8 *p) { }
-
-#endif
-
#ifdef CONFIG_DEBUG_FS
extern int wiidebug_init(struct wiimote_data *wdata);
@@ -173,11 +301,26 @@ static inline void wiimote_cmd_complete(struct wiimote_data *wdata)
complete(&wdata->state.ready);
}
+/* requires the state.lock spinlock to be held */
+static inline void wiimote_cmd_abort(struct wiimote_data *wdata)
+{
+ /* Abort synchronous request by waking up the sleeping caller. But
+ * reset the state.cmd field to an invalid value so no further event
+ * handlers will work with it. */
+ wdata->state.cmd = WIIPROTO_REQ_MAX;
+ complete(&wdata->state.ready);
+}
+
static inline int wiimote_cmd_acquire(struct wiimote_data *wdata)
{
return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0;
}
+static inline void wiimote_cmd_acquire_noint(struct wiimote_data *wdata)
+{
+ mutex_lock(&wdata->state.sync);
+}
+
/* requires the state.lock spinlock to be held */
static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd,
__u32 opt)
@@ -196,11 +339,31 @@ static inline int wiimote_cmd_wait(struct wiimote_data *wdata)
{
int ret;
+ /* The completion acts as implicit memory barrier so we can safely
+ * assume that state.cmd is set on success/failure and isn't accessed
+ * by any other thread, anymore. */
+
ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ);
if (ret < 0)
return -ERESTARTSYS;
else if (ret == 0)
return -EIO;
+ else if (wdata->state.cmd != WIIPROTO_REQ_NULL)
+ return -EIO;
+ else
+ return 0;
+}
+
+static inline int wiimote_cmd_wait_noint(struct wiimote_data *wdata)
+{
+ unsigned long ret;
+
+ /* no locking needed; see wiimote_cmd_wait() */
+ ret = wait_for_completion_timeout(&wdata->state.ready, HZ);
+ if (!ret)
+ return -EIO;
+ else if (wdata->state.cmd != WIIPROTO_REQ_NULL)
+ return -EIO;
else
return 0;
}
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 2b1799a3b212..879b0ed701a3 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -108,6 +108,7 @@ static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01),
static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) };
static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) };
static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) };
+static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 };
/*
* These definitions are not used here, but are defined by the spec.
@@ -259,8 +260,11 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *args = ihid->argsbuf;
+ const struct i2c_hid_cmd * hidcmd = &hid_set_report_cmd;
int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
+ u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
+ u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
/* hidraw already checked that data_len < HID_MAX_BUFFER_SIZE */
u16 size = 2 /* size */ +
@@ -278,8 +282,18 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
reportID = 0x0F;
}
- args[index++] = dataRegister & 0xFF;
- args[index++] = dataRegister >> 8;
+ /*
+ * use the data register for feature reports or if the device does not
+ * support the output register
+ */
+ if (reportType == 0x03 || maxOutputLength == 0) {
+ args[index++] = dataRegister & 0xFF;
+ args[index++] = dataRegister >> 8;
+ } else {
+ args[index++] = outputRegister & 0xFF;
+ args[index++] = outputRegister >> 8;
+ hidcmd = &hid_no_cmd;
+ }
args[index++] = size & 0xFF;
args[index++] = size >> 8;
@@ -289,7 +303,7 @@ static int i2c_hid_set_report(struct i2c_client *client, u8 reportType,
memcpy(&args[index], buf, data_len);
- ret = __i2c_hid_command(client, &hid_set_report_cmd, reportID,
+ ret = __i2c_hid_command(client, hidcmd, reportID,
reportType, args, args_len, NULL, 0);
if (ret) {
dev_err(&client->dev, "failed to set a report to device.\n");
diff --git a/drivers/hsi/hsi.c b/drivers/hsi/hsi.c
index 833dd1afbf46..66d44581e1b1 100644
--- a/drivers/hsi/hsi.c
+++ b/drivers/hsi/hsi.c
@@ -75,7 +75,7 @@ static void hsi_new_client(struct hsi_port *port, struct hsi_board_info *info)
cl->device.bus = &hsi_bus_type;
cl->device.parent = &port->device;
cl->device.release = hsi_client_release;
- dev_set_name(&cl->device, info->name);
+ dev_set_name(&cl->device, "%s", info->name);
cl->device.platform_data = info->platform_data;
if (info->archdata)
cl->device.archdata = *info->archdata;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 0428e8a74b19..e989f7fd645b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -348,11 +348,16 @@ config SENSORS_DS620
will be called ds620.
config SENSORS_DS1621
- tristate "Dallas Semiconductor DS1621 and DS1625"
+ tristate "Dallas Semiconductor DS1621 and compatibles"
depends on I2C
help
- If you say yes here you get support for Dallas Semiconductor
- DS1621 and DS1625 sensor chips.
+ If you say yes here you get support for Dallas Semiconductor/Maxim
+ Integrated DS1621 sensor chips and compatible models including:
+
+ - Dallas Semiconductor DS1625
+ - Maxim Integrated DS1631
+ - Maxim Integrated DS1721
+ - Maxim Integrated DS1731
This driver can also be built as a module. If so, the module
will be called ds1621.
@@ -456,6 +461,16 @@ config SENSORS_G760A
This driver can also be built as a module. If so, the module
will be called g760a.
+config SENSORS_G762
+ tristate "GMT G762 and G763"
+ depends on I2C
+ help
+ If you say yes here you get support for Global Mixed-mode
+ Technology Inc G762 and G763 fan speed PWM controller chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called g762.
+
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index d17d3e64f9f4..4f0fb5235f42 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -60,6 +60,7 @@ obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_G760A) += g760a.o
+obj-$(CONFIG_SENSORS_G762) += g762.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index 1d2da31c27c6..0cac8c0b001a 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -1079,7 +1079,6 @@ static int abituguru3_remove(struct platform_device *pdev)
int i;
struct abituguru3_data *data = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->hwmon_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index f920619cd6da..29dd9f746dfa 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -284,15 +284,11 @@ static DEVICE_ATTR(low_power, S_IWUSR | S_IRUGO, show_low_power, set_low_power);
static struct attribute *adm1021_attributes[] = {
&sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_low_power.attr,
@@ -303,6 +299,18 @@ static const struct attribute_group adm1021_group = {
.attrs = adm1021_attributes,
};
+static struct attribute *adm1021_min_attributes[] = {
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group adm1021_min_group = {
+ .attrs = adm1021_min_attributes,
+};
+
/* Return 0 if detection is successful, -ENODEV otherwise */
static int adm1021_detect(struct i2c_client *client,
struct i2c_board_info *info)
@@ -425,6 +433,12 @@ static int adm1021_probe(struct i2c_client *client,
if (err)
return err;
+ if (data->type != lm84) {
+ err = sysfs_create_group(&client->dev.kobj, &adm1021_min_group);
+ if (err)
+ goto error;
+ }
+
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
@@ -434,6 +448,7 @@ static int adm1021_probe(struct i2c_client *client,
return 0;
error:
+ sysfs_remove_group(&client->dev.kobj, &adm1021_min_group);
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
return err;
}
@@ -452,6 +467,7 @@ static int adm1021_remove(struct i2c_client *client)
struct adm1021_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1021_min_group);
sysfs_remove_group(&client->dev.kobj, &adm1021_group);
return 0;
@@ -477,9 +493,11 @@ static struct adm1021_data *adm1021_update_device(struct device *dev)
data->temp_max[i] = 1000 *
(s8) i2c_smbus_read_byte_data(
client, ADM1021_REG_TOS_R(i));
- data->temp_min[i] = 1000 *
- (s8) i2c_smbus_read_byte_data(
- client, ADM1021_REG_THYST_R(i));
+ if (data->type != lm84) {
+ data->temp_min[i] = 1000 *
+ (s8) i2c_smbus_read_byte_data(client,
+ ADM1021_REG_THYST_R(i));
+ }
}
data->alarms = i2c_smbus_read_byte_data(client,
ADM1021_REG_STATUS) & 0x7c;
diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index b83bf4bb95eb..0f34bca9f5e5 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -1285,7 +1285,7 @@ static int adt7470_probe(struct i2c_client *client,
}
init_completion(&data->auto_update_stop);
- data->auto_update = kthread_run(adt7470_update_thread, client,
+ data->auto_update = kthread_run(adt7470_update_thread, client, "%s",
dev_name(data->hwmon_dev));
if (IS_ERR(data->auto_update)) {
err = PTR_ERR(data->auto_update);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 658ce3a8717f..ade35cf3f488 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -578,7 +578,6 @@ static int coretemp_probe(struct platform_device *pdev)
exit_name:
device_remove_file(&pdev->dev, &pdata->name_attr);
- platform_set_drvdata(pdev, NULL);
exit_free:
kfree(pdata);
return err;
@@ -595,7 +594,6 @@ static int coretemp_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev, &pdata->name_attr);
hwmon_device_unregister(pdata->hwmon_dev);
- platform_set_drvdata(pdev, NULL);
kfree(pdata);
return 0;
}
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 1c568736baff..a26ba7a17c2b 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -6,6 +6,19 @@
* Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
* the help of Jean Delvare <khali@linux-fr.org>
*
+ * The DS1621 device is a digital temperature/thermometer with 9-bit
+ * resolution, a thermal alarm output (Tout), and user-defined minimum
+ * and maximum temperature thresholds (TH and TL).
+ *
+ * The DS1625, DS1631, DS1721, and DS1731 are pin compatible with the DS1621
+ * and similar in operation, with slight variations as noted in the device
+ * datasheets (please refer to www.maximintegrated.com for specific
+ * device information).
+ *
+ * Since the DS1621 was the first chipset supported by this driver,
+ * most comments will refer to this chipset, but are actually general
+ * and concern all supported chipsets, unless mentioned otherwise.
+ *
* 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
@@ -31,27 +44,62 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
-#include "lm75.h"
+#include <linux/kernel.h>
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
- 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+/* Supported devices */
+enum chips { ds1621, ds1625, ds1631, ds1721, ds1731 };
/* Insmod parameters */
static int polarity = -1;
module_param(polarity, int, 0);
MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
-/* Many DS1621 constants specified below */
-/* Config register used for detection */
-/* 7 6 5 4 3 2 1 0 */
-/* |Done|THF |TLF |NVB | X | X |POL |1SHOT| */
+/*
+ * The Configuration/Status register
+ *
+ * - DS1621:
+ * 7 6 5 4 3 2 1 0
+ * |Done|THF |TLF |NVB | X | X |POL |1SHOT|
+ *
+ * - DS1625:
+ * 7 6 5 4 3 2 1 0
+ * |Done|THF |TLF |NVB | 1 | 0 |POL |1SHOT|
+ *
+ * - DS1631, DS1731:
+ * 7 6 5 4 3 2 1 0
+ * |Done|THF |TLF |NVB | R1 | R0 |POL |1SHOT|
+ *
+ * - DS1721:
+ * 7 6 5 4 3 2 1 0
+ * |Done| X | X | U | R1 | R0 |POL |1SHOT|
+ *
+ * Where:
+ * - 'X' is Reserved
+ * - 'U' is Undefined
+ */
#define DS1621_REG_CONFIG_NVB 0x10
+#define DS1621_REG_CONFIG_RESOL 0x0C
#define DS1621_REG_CONFIG_POLARITY 0x02
#define DS1621_REG_CONFIG_1SHOT 0x01
#define DS1621_REG_CONFIG_DONE 0x80
-/* The DS1621 registers */
+#define DS1621_REG_CONFIG_RESOL_SHIFT 2
+
+/* ds1721 conversion rates: {C/LSB, time(ms), resolution bit setting} */
+static const unsigned short ds1721_convrates[] = {
+ 94, /* 9-bits (0.5, 93.75, RES[0..1] = 0 */
+ 188, /* 10-bits (0.25, 187.5, RES[0..1] = 1 */
+ 375, /* 11-bits (0.125, 375, RES[0..1] = 2 */
+ 750, /* 12-bits (0.0625, 750, RES[0..1] = 3 */
+};
+
+#define DS1621_CONVERSION_MAX 750
+#define DS1625_CONVERSION_MAX 500
+
+#define DS1621_TEMP_MAX 125000
+#define DS1621_TEMP_MIN (-55000)
+
+/* The DS1621 temperature registers */
static const u8 DS1621_REG_TEMP[3] = {
0xAA, /* input, word, RO */
0xA2, /* min, word, RW */
@@ -59,6 +107,7 @@ static const u8 DS1621_REG_TEMP[3] = {
};
#define DS1621_REG_CONF 0xAC /* byte, RW */
#define DS1621_COM_START 0xEE /* no data */
+#define DS1721_COM_START 0x51 /* no data */
#define DS1621_COM_STOP 0x22 /* no data */
/* The DS1621 configuration register */
@@ -75,14 +124,37 @@ struct ds1621_data {
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
+ enum chips kind; /* device type */
u16 temp[3]; /* Register values, word */
u8 conf; /* Register encoding, combined */
+ u8 zbits; /* Resolution encoded as number of
+ * zero bits */
+ u16 update_interval; /* Conversion rate in milliseconds */
};
+static inline int DS1621_TEMP_FROM_REG(u16 reg)
+{
+ return DIV_ROUND_CLOSEST(((s16)reg / 16) * 625, 10);
+}
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG:
+ * - 1621, 1625: 0.5C/bit, 7 zero-bits
+ * - 1631, 1721, 1731: 0.0625C/bit, 4 zero-bits
+ */
+static inline u16 DS1621_TEMP_TO_REG(long temp, u8 zbits)
+{
+ temp = clamp_val(temp, DS1621_TEMP_MIN, DS1621_TEMP_MAX);
+ temp = DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits;
+ return temp;
+}
+
static void ds1621_init_client(struct i2c_client *client)
{
- u8 conf, new_conf;
+ u8 conf, new_conf, sreg, resol;
+ struct ds1621_data *data = i2c_get_clientdata(client);
new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
/* switch to continuous conversion mode */
@@ -97,8 +169,30 @@ static void ds1621_init_client(struct i2c_client *client)
if (conf != new_conf)
i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf);
+ switch (data->kind) {
+ case ds1625:
+ data->update_interval = DS1625_CONVERSION_MAX;
+ data->zbits = 7;
+ sreg = DS1621_COM_START;
+ break;
+ case ds1631:
+ case ds1721:
+ case ds1731:
+ resol = (new_conf & DS1621_REG_CONFIG_RESOL) >>
+ DS1621_REG_CONFIG_RESOL_SHIFT;
+ data->update_interval = ds1721_convrates[resol];
+ data->zbits = 7 - resol;
+ sreg = DS1721_COM_START;
+ break;
+ default:
+ data->update_interval = DS1621_CONVERSION_MAX;
+ data->zbits = 7;
+ sreg = DS1621_COM_START;
+ break;
+ }
+
/* start conversion */
- i2c_smbus_write_byte(client, DS1621_COM_START);
+ i2c_smbus_write_byte(client, sreg);
}
static struct ds1621_data *ds1621_update_client(struct device *dev)
@@ -109,8 +203,8 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
+ if (time_after(jiffies, data->last_updated + data->update_interval) ||
+ !data->valid) {
int i;
dev_dbg(&client->dev, "Starting ds1621 update\n");
@@ -146,7 +240,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *da,
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ds1621_data *data = ds1621_update_client(dev);
return sprintf(buf, "%d\n",
- LM75_TEMP_FROM_REG(data->temp[attr->index]));
+ DS1621_TEMP_FROM_REG(data->temp[attr->index]));
}
static ssize_t set_temp(struct device *dev, struct device_attribute *da,
@@ -163,7 +257,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da,
return err;
mutex_lock(&data->update_lock);
- data->temp[attr->index] = LM75_TEMP_TO_REG(val);
+ data->temp[attr->index] = DS1621_TEMP_TO_REG(val, data->zbits);
i2c_smbus_write_word_swapped(client, DS1621_REG_TEMP[attr->index],
data->temp[attr->index]);
mutex_unlock(&data->update_lock);
@@ -185,7 +279,47 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
return sprintf(buf, "%d\n", !!(data->conf & attr->index));
}
+static ssize_t show_convrate(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1621_data *data = i2c_get_clientdata(client);
+ return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval);
+}
+
+static ssize_t set_convrate(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1621_data *data = i2c_get_clientdata(client);
+ unsigned long convrate;
+ s32 err;
+ int resol = 0;
+
+ err = kstrtoul(buf, 10, &convrate);
+ if (err)
+ return err;
+
+ /* Convert rate into resolution bits */
+ while (resol < (ARRAY_SIZE(ds1721_convrates) - 1) &&
+ convrate > ds1721_convrates[resol])
+ resol++;
+
+ mutex_lock(&data->update_lock);
+ data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
+ data->conf &= ~DS1621_REG_CONFIG_RESOL;
+ data->conf |= (resol << DS1621_REG_CONFIG_RESOL_SHIFT);
+ i2c_smbus_write_byte_data(client, DS1621_REG_CONF, data->conf);
+ data->update_interval = ds1721_convrates[resol];
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_convrate,
+ set_convrate);
+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
@@ -201,48 +335,29 @@ static struct attribute *ds1621_attributes[] = {
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_update_interval.attr,
NULL
};
-static const struct attribute_group ds1621_group = {
- .attrs = ds1621_attributes,
-};
-
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int ds1621_detect(struct i2c_client *client,
- struct i2c_board_info *info)
+static umode_t ds1621_attribute_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
{
- struct i2c_adapter *adapter = client->adapter;
- int conf, temp;
- int i;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_WORD_DATA
- | I2C_FUNC_SMBUS_WRITE_BYTE))
- return -ENODEV;
-
- /*
- * Now, we do the remaining detection. It is lousy.
- *
- * The NVB bit should be low if no EEPROM write has been requested
- * during the latest 10ms, which is highly improbable in our case.
- */
- conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF);
- if (conf < 0 || conf & DS1621_REG_CONFIG_NVB)
- return -ENODEV;
- /* The 7 lowest bits of a temperature should always be 0. */
- for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) {
- temp = i2c_smbus_read_word_data(client, DS1621_REG_TEMP[i]);
- if (temp < 0 || (temp & 0x7f00))
- return -ENODEV;
- }
-
- strlcpy(info->type, "ds1621", I2C_NAME_SIZE);
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1621_data *data = i2c_get_clientdata(client);
- return 0;
+ if (attr == &dev_attr_update_interval.attr)
+ if (data->kind == ds1621 || data->kind == ds1625)
+ /* shhh, we're hiding update_interval */
+ return 0;
+ return attr->mode;
}
+static const struct attribute_group ds1621_group = {
+ .attrs = ds1621_attributes,
+ .is_visible = ds1621_attribute_visible
+};
+
static int ds1621_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -257,6 +372,8 @@ static int ds1621_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
+ data->kind = id->driver_data;
+
/* Initialize the DS1621 chip */
ds1621_init_client(client);
@@ -289,8 +406,11 @@ static int ds1621_remove(struct i2c_client *client)
}
static const struct i2c_device_id ds1621_id[] = {
- { "ds1621", 0 },
- { "ds1625", 0 },
+ { "ds1621", ds1621 },
+ { "ds1625", ds1625 },
+ { "ds1631", ds1631 },
+ { "ds1721", ds1721 },
+ { "ds1731", ds1731 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds1621_id);
@@ -304,8 +424,6 @@ static struct i2c_driver ds1621_driver = {
.probe = ds1621_probe,
.remove = ds1621_remove,
.id_table = ds1621_id,
- .detect = ds1621_detect,
- .address_list = normal_i2c,
};
module_i2c_driver(ds1621_driver);
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c
new file mode 100644
index 000000000000..73adf01b0ef2
--- /dev/null
+++ b/drivers/hwmon/g762.c
@@ -0,0 +1,1149 @@
+/*
+ * g762 - Driver for the Global Mixed-mode Technology Inc. fan speed
+ * PWM controller chips from G762 family, i.e. G762 and G763
+ *
+ * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * This work is based on a basic version for 2.6.31 kernel developed
+ * by Olivier Mouchet for LaCie. Updates and correction have been
+ * performed to run on recent kernels. Additional features, like the
+ * ability to configure various characteristics via .dts file or
+ * board init file have been added. Detailed datasheet on which this
+ * development is based is available here:
+ *
+ * http://natisbad.org/NAS/refs/GMT_EDS-762_763-080710-0.2.pdf
+ *
+ * Headers from previous developments have been kept below:
+ *
+ * Copyright (c) 2009 LaCie
+ *
+ * Author: Olivier Mouchet <olivier.mouchet@gmail.com>
+ *
+ * based on g760a code written by Herbert Valerio Riedel <hvr@gnu.org>
+ * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
+ *
+ * g762: minimal datasheet available at:
+ * http://www.gmt.com.tw/product/datasheet/EDS-762_3.pdf
+ *
+ * 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.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/g762.h>
+
+#define DRVNAME "g762"
+
+static const struct i2c_device_id g762_id[] = {
+ { "g762", 0 },
+ { "g763", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, g762_id);
+
+enum g762_regs {
+ G762_REG_SET_CNT = 0x00,
+ G762_REG_ACT_CNT = 0x01,
+ G762_REG_FAN_STA = 0x02,
+ G762_REG_SET_OUT = 0x03,
+ G762_REG_FAN_CMD1 = 0x04,
+ G762_REG_FAN_CMD2 = 0x05,
+};
+
+/* Config register bits */
+#define G762_REG_FAN_CMD1_DET_FAN_FAIL 0x80 /* enable fan_fail signal */
+#define G762_REG_FAN_CMD1_DET_FAN_OOC 0x40 /* enable fan_out_of_control */
+#define G762_REG_FAN_CMD1_OUT_MODE 0x20 /* out mode: PWM or DC */
+#define G762_REG_FAN_CMD1_FAN_MODE 0x10 /* fan mode: closed/open-loop */
+#define G762_REG_FAN_CMD1_CLK_DIV_ID1 0x08 /* clock divisor value */
+#define G762_REG_FAN_CMD1_CLK_DIV_ID0 0x04
+#define G762_REG_FAN_CMD1_PWM_POLARITY 0x02 /* PWM polarity */
+#define G762_REG_FAN_CMD1_PULSE_PER_REV 0x01 /* pulse per fan revolution */
+
+#define G762_REG_FAN_CMD2_GEAR_MODE_1 0x08 /* fan gear mode */
+#define G762_REG_FAN_CMD2_GEAR_MODE_0 0x04
+#define G762_REG_FAN_CMD2_FAN_STARTV_1 0x02 /* fan startup voltage */
+#define G762_REG_FAN_CMD2_FAN_STARTV_0 0x01
+
+#define G762_REG_FAN_STA_FAIL 0x02 /* fan fail */
+#define G762_REG_FAN_STA_OOC 0x01 /* fan out of control */
+
+/* Config register values */
+#define G762_OUT_MODE_PWM 1
+#define G762_OUT_MODE_DC 0
+
+#define G762_FAN_MODE_CLOSED_LOOP 2
+#define G762_FAN_MODE_OPEN_LOOP 1
+
+#define G762_PWM_POLARITY_NEGATIVE 1
+#define G762_PWM_POLARITY_POSITIVE 0
+
+/* Register data is read (and cached) at most once per second. */
+#define G762_UPDATE_INTERVAL HZ
+
+/*
+ * Extract pulse count per fan revolution value (2 or 4) from given
+ * FAN_CMD1 register value.
+ */
+#define G762_PULSE_FROM_REG(reg) \
+ ((((reg) & G762_REG_FAN_CMD1_PULSE_PER_REV) + 1) << 1)
+
+/*
+ * Extract fan clock divisor (1, 2, 4 or 8) from given FAN_CMD1
+ * register value.
+ */
+#define G762_CLKDIV_FROM_REG(reg) \
+ (1 << (((reg) & (G762_REG_FAN_CMD1_CLK_DIV_ID0 | \
+ G762_REG_FAN_CMD1_CLK_DIV_ID1)) >> 2))
+
+/*
+ * Extract fan gear mode multiplier value (0, 2 or 4) from given
+ * FAN_CMD2 register value.
+ */
+#define G762_GEARMULT_FROM_REG(reg) \
+ (1 << (((reg) & (G762_REG_FAN_CMD2_GEAR_MODE_0 | \
+ G762_REG_FAN_CMD2_GEAR_MODE_1)) >> 2))
+
+struct g762_data {
+ struct i2c_client *client;
+ struct device *hwmon_dev;
+ struct clk *clk;
+
+ /* update mutex */
+ struct mutex update_lock;
+
+ /* board specific parameters. */
+ u32 clk_freq;
+
+ /* g762 register cache */
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+
+ u8 set_cnt; /* controls fan rotation speed in closed-loop mode */
+ u8 act_cnt; /* provides access to current fan RPM value */
+ u8 fan_sta; /* bit 0: set when actual fan speed is more than
+ * 25% outside requested fan speed
+ * bit 1: set when no transition occurs on fan
+ * pin for 0.7s
+ */
+ u8 set_out; /* controls fan rotation speed in open-loop mode */
+ u8 fan_cmd1; /* 0: FG_PLS_ID0 FG pulses count per revolution
+ * 0: 2 counts per revolution
+ * 1: 4 counts per revolution
+ * 1: PWM_POLARITY 1: negative_duty
+ * 0: positive_duty
+ * 2,3: [FG_CLOCK_ID0, FG_CLK_ID1]
+ * 00: Divide fan clock by 1
+ * 01: Divide fan clock by 2
+ * 10: Divide fan clock by 4
+ * 11: Divide fan clock by 8
+ * 4: FAN_MODE 1:closed-loop, 0:open-loop
+ * 5: OUT_MODE 1:PWM, 0:DC
+ * 6: DET_FAN_OOC enable "fan ooc" status
+ * 7: DET_FAN_FAIL enable "fan fail" status
+ */
+ u8 fan_cmd2; /* 0,1: FAN_STARTV 0,1,2,3 -> 0,32,64,96 dac_code
+ * 2,3: FG_GEAR_MODE
+ * 00: multiplier = 1
+ * 01: multiplier = 2
+ * 10: multiplier = 4
+ * 4: Mask ALERT# (g763 only)
+ */
+};
+
+/*
+ * Convert count value from fan controller register (FAN_SET_CNT) into fan
+ * speed RPM value. Note that the datasheet documents a basic formula;
+ * influence of additional parameters (fan clock divisor, fan gear mode)
+ * have been infered from examples in the datasheet and tests.
+ */
+static inline unsigned int rpm_from_cnt(u8 cnt, u32 clk_freq, u16 p,
+ u8 clk_div, u8 gear_mult)
+{
+ if (cnt == 0xff) /* setting cnt to 255 stops the fan */
+ return 0;
+
+ return (clk_freq * 30 * gear_mult) / ((cnt ? cnt : 1) * p * clk_div);
+}
+
+/*
+ * Convert fan RPM value from sysfs into count value for fan controller
+ * register (FAN_SET_CNT).
+ */
+static inline unsigned char cnt_from_rpm(u32 rpm, u32 clk_freq, u16 p,
+ u8 clk_div, u8 gear_mult)
+{
+ if (!rpm) /* to stop the fan, set cnt to 255 */
+ return 0xff;
+
+ return clamp_val(((clk_freq * 30 * gear_mult) / (rpm * p * clk_div)),
+ 0, 255);
+}
+
+/* helper to grab and cache data, at most one time per second */
+static struct g762_data *g762_update_client(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = i2c_get_clientdata(client);
+ int ret = 0;
+
+ mutex_lock(&data->update_lock);
+ if (time_before(jiffies, data->last_updated + G762_UPDATE_INTERVAL) &&
+ likely(data->valid))
+ goto out;
+
+ ret = i2c_smbus_read_byte_data(client, G762_REG_SET_CNT);
+ if (ret < 0)
+ goto out;
+ data->set_cnt = ret;
+
+ ret = i2c_smbus_read_byte_data(client, G762_REG_ACT_CNT);
+ if (ret < 0)
+ goto out;
+ data->act_cnt = ret;
+
+ ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_STA);
+ if (ret < 0)
+ goto out;
+ data->fan_sta = ret;
+
+ ret = i2c_smbus_read_byte_data(client, G762_REG_SET_OUT);
+ if (ret < 0)
+ goto out;
+ data->set_out = ret;
+
+ ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_CMD1);
+ if (ret < 0)
+ goto out;
+ data->fan_cmd1 = ret;
+
+ ret = i2c_smbus_read_byte_data(client, G762_REG_FAN_CMD2);
+ if (ret < 0)
+ goto out;
+ data->fan_cmd2 = ret;
+
+ data->last_updated = jiffies;
+ data->valid = true;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ if (ret < 0) /* upon error, encode it in return value */
+ data = ERR_PTR(ret);
+
+ return data;
+}
+
+/* helpers for writing hardware parameters */
+
+/*
+ * Set input clock frequency received on CLK pin of the chip. Accepted values
+ * are between 0 and 0xffffff. If zero is given, then default frequency
+ * (32,768Hz) is used. Note that clock frequency is a characteristic of the
+ * system but an internal parameter, i.e. value is not passed to the device.
+ */
+static int do_set_clk_freq(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = i2c_get_clientdata(client);
+
+ if (val > 0xffffff)
+ return -EINVAL;
+ if (!val)
+ val = 32768;
+
+ data->clk_freq = val;
+
+ return 0;
+}
+
+/* Set pwm mode. Accepts either 0 (PWM mode) or 1 (DC mode) */
+static int do_set_pwm_mode(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case G762_OUT_MODE_PWM:
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_OUT_MODE;
+ break;
+ case G762_OUT_MODE_DC:
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_OUT_MODE;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+ data->fan_cmd1);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/* Set fan clock divisor. Accepts either 1, 2, 4 or 8. */
+static int do_set_fan_div(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case 1:
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID0;
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID1;
+ break;
+ case 2:
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_CLK_DIV_ID0;
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID1;
+ break;
+ case 4:
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_CLK_DIV_ID0;
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_CLK_DIV_ID1;
+ break;
+ case 8:
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_CLK_DIV_ID0;
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_CLK_DIV_ID1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+ data->fan_cmd1);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/* Set fan gear mode. Accepts either 0, 1 or 2. */
+static int do_set_fan_gear_mode(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case 0:
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_0;
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_1;
+ break;
+ case 1:
+ data->fan_cmd2 |= G762_REG_FAN_CMD2_GEAR_MODE_0;
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_1;
+ break;
+ case 2:
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_GEAR_MODE_0;
+ data->fan_cmd2 |= G762_REG_FAN_CMD2_GEAR_MODE_1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD2,
+ data->fan_cmd2);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/* Set number of fan pulses per revolution. Accepts either 2 or 4. */
+static int do_set_fan_pulses(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case 2:
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_PULSE_PER_REV;
+ break;
+ case 4:
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_PULSE_PER_REV;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+ data->fan_cmd1);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/* Set fan mode. Accepts either 1 (open-loop) or 2 (closed-loop). */
+static int do_set_pwm_enable(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case G762_FAN_MODE_CLOSED_LOOP:
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_FAN_MODE;
+ break;
+ case G762_FAN_MODE_OPEN_LOOP:
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_FAN_MODE;
+ /*
+ * BUG FIX: if SET_CNT register value is 255 then, for some
+ * unknown reason, fan will not rotate as expected, no matter
+ * the value of SET_OUT (to be specific, this seems to happen
+ * only in PWM mode). To workaround this bug, we give SET_CNT
+ * value of 254 if it is 255 when switching to open-loop.
+ */
+ if (data->set_cnt == 0xff)
+ i2c_smbus_write_byte_data(client, G762_REG_SET_CNT,
+ 254);
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+ data->fan_cmd1);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/* Set PWM polarity. Accepts either 0 (positive duty) or 1 (negative duty) */
+static int do_set_pwm_polarity(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case G762_PWM_POLARITY_POSITIVE:
+ data->fan_cmd1 &= ~G762_REG_FAN_CMD1_PWM_POLARITY;
+ break;
+ case G762_PWM_POLARITY_NEGATIVE:
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_PWM_POLARITY;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+ data->fan_cmd1);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/*
+ * Set pwm value. Accepts values between 0 (stops the fan) and
+ * 255 (full speed). This only makes sense in open-loop mode.
+ */
+static int do_set_pwm(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ if (val > 255)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = i2c_smbus_write_byte_data(client, G762_REG_SET_OUT, val);
+ data->valid = false;
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/*
+ * Set fan RPM value. Can be called both in closed and open-loop mode
+ * but effect will only be seen after closed-loop mode is configured.
+ */
+static int do_set_fan_target(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ data->set_cnt = cnt_from_rpm(val, data->clk_freq,
+ G762_PULSE_FROM_REG(data->fan_cmd1),
+ G762_CLKDIV_FROM_REG(data->fan_cmd1),
+ G762_GEARMULT_FROM_REG(data->fan_cmd2));
+ ret = i2c_smbus_write_byte_data(client, G762_REG_SET_CNT,
+ data->set_cnt);
+ data->valid = false;
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/* Set fan startup voltage. Accepted values are either 0, 1, 2 or 3. */
+static int do_set_fan_startv(struct device *dev, unsigned long val)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+ int ret;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ switch (val) {
+ case 0:
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_0;
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_1;
+ break;
+ case 1:
+ data->fan_cmd2 |= G762_REG_FAN_CMD2_FAN_STARTV_0;
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_1;
+ break;
+ case 2:
+ data->fan_cmd2 &= ~G762_REG_FAN_CMD2_FAN_STARTV_0;
+ data->fan_cmd2 |= G762_REG_FAN_CMD2_FAN_STARTV_1;
+ break;
+ case 3:
+ data->fan_cmd2 |= G762_REG_FAN_CMD2_FAN_STARTV_0;
+ data->fan_cmd2 |= G762_REG_FAN_CMD2_FAN_STARTV_1;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD2,
+ data->fan_cmd2);
+ data->valid = false;
+ out:
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+/*
+ * Helper to import hardware characteristics from .dts file and push
+ * those to the chip.
+ */
+
+#ifdef CONFIG_OF
+static struct of_device_id g762_dt_match[] = {
+ { .compatible = "gmt,g762" },
+ { .compatible = "gmt,g763" },
+ { },
+};
+
+/*
+ * Grab clock (a required property), enable it, get (fixed) clock frequency
+ * and store it. Note: upon success, clock has been prepared and enabled; it
+ * must later be unprepared and disabled (e.g. during module unloading) by a
+ * call to g762_of_clock_disable(). Note that a reference to clock is kept
+ * in our private data structure to be used in this function.
+ */
+static int g762_of_clock_enable(struct i2c_client *client)
+{
+ struct g762_data *data;
+ unsigned long clk_freq;
+ struct clk *clk;
+ int ret;
+
+ if (!client->dev.of_node)
+ return 0;
+
+ clk = of_clk_get(client->dev.of_node, 0);
+ if (IS_ERR(clk)) {
+ dev_err(&client->dev, "failed to get clock\n");
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_prepare_enable(clk);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable clock\n");
+ goto clk_put;
+ }
+
+ clk_freq = clk_get_rate(clk);
+ ret = do_set_clk_freq(&client->dev, clk_freq);
+ if (ret) {
+ dev_err(&client->dev, "invalid clock freq %lu\n", clk_freq);
+ goto clk_unprep;
+ }
+
+ data = i2c_get_clientdata(client);
+ data->clk = clk;
+
+ return 0;
+
+ clk_unprep:
+ clk_disable_unprepare(clk);
+
+ clk_put:
+ clk_put(clk);
+
+ return ret;
+}
+
+static void g762_of_clock_disable(struct i2c_client *client)
+{
+ struct g762_data *data = i2c_get_clientdata(client);
+
+ if (!data->clk)
+ return;
+
+ clk_disable_unprepare(data->clk);
+ clk_put(data->clk);
+}
+
+static int g762_of_prop_import_one(struct i2c_client *client,
+ const char *pname,
+ int (*psetter)(struct device *dev,
+ unsigned long val))
+{
+ const __be32 *prop;
+ int len, ret;
+ u32 pval;
+
+ prop = of_get_property(client->dev.of_node, pname, &len);
+ if (!prop || len != sizeof(u32))
+ return 0;
+
+ pval = be32_to_cpu(prop[0]);
+ dev_dbg(&client->dev, "found %s (%d)\n", pname, pval);
+ ret = (*psetter)(&client->dev, pval);
+ if (ret)
+ dev_err(&client->dev, "unable to set %s (%d)\n", pname, pval);
+
+ return ret;
+}
+
+static int g762_of_prop_import(struct i2c_client *client)
+{
+ int ret;
+
+ if (!client->dev.of_node)
+ return 0;
+
+ ret = g762_of_prop_import_one(client, "fan_gear_mode",
+ do_set_fan_gear_mode);
+ if (ret)
+ return ret;
+
+ ret = g762_of_prop_import_one(client, "pwm_polarity",
+ do_set_pwm_polarity);
+ if (ret)
+ return ret;
+
+ return g762_of_prop_import_one(client, "fan_startv",
+ do_set_fan_startv);
+}
+
+#else
+static int g762_of_prop_import(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int g762_of_clock_enable(struct i2c_client *client)
+{
+ return 0;
+}
+
+static void g762_of_clock_disable(struct i2c_client *client) { }
+#endif
+
+/*
+ * Helper to import hardware characteristics from .dts file and push
+ * those to the chip.
+ */
+
+static int g762_pdata_prop_import(struct i2c_client *client)
+{
+ struct g762_platform_data *pdata = client->dev.platform_data;
+ int ret;
+
+ if (!pdata)
+ return 0;
+
+ ret = do_set_fan_gear_mode(&client->dev, pdata->fan_gear_mode);
+ if (ret)
+ return ret;
+
+ ret = do_set_pwm_polarity(&client->dev, pdata->pwm_polarity);
+ if (ret)
+ return ret;
+
+ ret = do_set_fan_startv(&client->dev, pdata->fan_startv);
+ if (ret)
+ return ret;
+
+ return do_set_clk_freq(&client->dev, pdata->clk_freq);
+}
+
+/*
+ * sysfs attributes
+ */
+
+/*
+ * Read function for fan1_input sysfs file. Return current fan RPM value, or
+ * 0 if fan is out of control.
+ */
+static ssize_t get_fan_rpm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+ unsigned int rpm = 0;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ /* reverse logic: fan out of control reporting is enabled low */
+ if (data->fan_sta & G762_REG_FAN_STA_OOC) {
+ rpm = rpm_from_cnt(data->act_cnt, data->clk_freq,
+ G762_PULSE_FROM_REG(data->fan_cmd1),
+ G762_CLKDIV_FROM_REG(data->fan_cmd1),
+ G762_GEARMULT_FROM_REG(data->fan_cmd2));
+ }
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n", rpm);
+}
+
+/*
+ * Read and write functions for pwm1_mode sysfs file. Get and set fan speed
+ * control mode i.e. PWM (1) or DC (0).
+ */
+static ssize_t get_pwm_mode(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n",
+ !!(data->fan_cmd1 & G762_REG_FAN_CMD1_OUT_MODE));
+}
+
+static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ ret = do_set_pwm_mode(dev, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+/*
+ * Read and write functions for fan1_div sysfs file. Get and set fan
+ * controller prescaler value
+ */
+static ssize_t get_fan_div(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", G762_CLKDIV_FROM_REG(data->fan_cmd1));
+}
+
+static ssize_t set_fan_div(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ ret = do_set_fan_div(dev, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+/*
+ * Read and write functions for fan1_pulses sysfs file. Get and set number
+ * of tachometer pulses per fan revolution.
+ */
+static ssize_t get_fan_pulses(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", G762_PULSE_FROM_REG(data->fan_cmd1));
+}
+
+static ssize_t set_fan_pulses(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ ret = do_set_fan_pulses(dev, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+/*
+ * Read and write functions for pwm1_enable. Get and set fan speed control mode
+ * (i.e. closed or open-loop).
+ *
+ * Following documentation about hwmon's sysfs interface, a pwm1_enable node
+ * should accept followings:
+ *
+ * 0 : no fan speed control (i.e. fan at full speed)
+ * 1 : manual fan speed control enabled (use pwm[1-*]) (open-loop)
+ * 2+: automatic fan speed control enabled (use fan[1-*]_target) (closed-loop)
+ *
+ * but we do not accept 0 as this mode is not natively supported by the chip
+ * and it is not emulated by g762 driver. -EINVAL is returned in this case.
+ */
+static ssize_t get_pwm_enable(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n",
+ (!!(data->fan_cmd1 & G762_REG_FAN_CMD1_FAN_MODE)) + 1);
+}
+
+static ssize_t set_pwm_enable(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ ret = do_set_pwm_enable(dev, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+/*
+ * Read and write functions for pwm1 sysfs file. Get and set pwm value
+ * (which affects fan speed) in open-loop mode. 0 stops the fan and 255
+ * makes it run at full speed.
+ */
+static ssize_t get_pwm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", data->set_out);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ ret = do_set_pwm(dev, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+/*
+ * Read and write function for fan1_target sysfs file. Get/set the fan speed in
+ * closed-loop mode. Speed is given as a RPM value; then the chip will regulate
+ * the fan speed using pulses from fan tachometer.
+ *
+ * Refer to rpm_from_cnt() implementation above to get info about count number
+ * calculation.
+ *
+ * Also note that due to rounding errors it is possible that you don't read
+ * back exactly the value you have set.
+ */
+static ssize_t get_fan_target(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+ unsigned int rpm;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ mutex_lock(&data->update_lock);
+ rpm = rpm_from_cnt(data->set_cnt, data->clk_freq,
+ G762_PULSE_FROM_REG(data->fan_cmd1),
+ G762_CLKDIV_FROM_REG(data->fan_cmd1),
+ G762_GEARMULT_FROM_REG(data->fan_cmd2));
+ mutex_unlock(&data->update_lock);
+
+ return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(buf, 10, &val))
+ return -EINVAL;
+
+ ret = do_set_fan_target(dev, val);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+/* read function for fan1_fault sysfs file. */
+static ssize_t get_fan_failure(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%u\n", !!(data->fan_sta & G762_REG_FAN_STA_FAIL));
+}
+
+/*
+ * read function for fan1_alarm sysfs file. Note that OOC condition is
+ * enabled low
+ */
+static ssize_t get_fan_ooc(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%u\n", !(data->fan_sta & G762_REG_FAN_STA_OOC));
+}
+
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, get_pwm_mode, set_pwm_mode);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ get_pwm_enable, set_pwm_enable);
+static DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL);
+static DEVICE_ATTR(fan1_alarm, S_IRUGO, get_fan_ooc, NULL);
+static DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_failure, NULL);
+static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO,
+ get_fan_target, set_fan_target);
+static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_fan_div, set_fan_div);
+static DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO,
+ get_fan_pulses, set_fan_pulses);
+
+/* Driver data */
+static struct attribute *g762_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_alarm.attr,
+ &dev_attr_fan1_fault.attr,
+ &dev_attr_fan1_target.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_pulses.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_mode.attr,
+ &dev_attr_pwm1_enable.attr,
+ NULL
+};
+
+static const struct attribute_group g762_group = {
+ .attrs = g762_attributes,
+};
+
+/*
+ * Enable both fan failure detection and fan out of control protection. The
+ * function does not protect change/access to data structure; it must thus
+ * only be called during initialization.
+ */
+static inline int g762_fan_init(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct g762_data *data = g762_update_client(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_FAIL;
+ data->fan_cmd1 |= G762_REG_FAN_CMD1_DET_FAN_OOC;
+ data->valid = false;
+
+ return i2c_smbus_write_byte_data(client, G762_REG_FAN_CMD1,
+ data->fan_cmd1);
+}
+
+static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct g762_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(&client->dev, sizeof(struct g762_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+ mutex_init(&data->update_lock);
+
+ /* Enable fan failure detection and fan out of control protection */
+ ret = g762_fan_init(&client->dev);
+ if (ret)
+ return ret;
+
+ /* Get configuration via DT ... */
+ ret = g762_of_clock_enable(client);
+ if (ret)
+ return ret;
+ ret = g762_of_prop_import(client);
+ if (ret)
+ goto clock_dis;
+ /* ... or platform_data */
+ ret = g762_pdata_prop_import(client);
+ if (ret)
+ goto clock_dis;
+
+ /* Register sysfs hooks */
+ ret = sysfs_create_group(&client->dev.kobj, &g762_group);
+ if (ret)
+ goto clock_dis;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto sysfs_rem;
+ }
+
+ return 0;
+
+ sysfs_rem:
+ sysfs_remove_group(&client->dev.kobj, &g762_group);
+
+ clock_dis:
+ g762_of_clock_disable(client);
+
+ return ret;
+}
+
+static int g762_remove(struct i2c_client *client)
+{
+ struct g762_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &g762_group);
+ g762_of_clock_disable(client);
+
+ return 0;
+}
+
+static struct i2c_driver g762_driver = {
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(g762_dt_match),
+ },
+ .probe = g762_probe,
+ .remove = g762_remove,
+ .id_table = g762_id,
+};
+
+module_i2c_driver(g762_driver);
+
+MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>");
+MODULE_DESCRIPTION("GMT G762/G763 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index b87c2ccee06b..de058c278aa9 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -556,7 +556,6 @@ static int i5k_amb_probe(struct platform_device *pdev)
err_init_failed:
iounmap(data->amb_mmio);
- platform_set_drvdata(pdev, NULL);
err_map_failed:
release_mem_region(data->amb_base, data->amb_len);
err:
@@ -576,7 +575,6 @@ static int i5k_amb_remove(struct platform_device *pdev)
kfree(data->attrs);
iounmap(data->amb_mmio);
release_mem_region(data->amb_base, data->amb_len);
- platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 52b77afebde1..708081b68c6f 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -180,6 +180,7 @@ static struct of_device_id iio_hwmon_of_match[] = {
{ .compatible = "iio-hwmon", },
{ }
};
+MODULE_DEVICE_TABLE(of, iio_hwmon_of_match);
static struct platform_driver __refdata iio_hwmon_driver = {
.driver = {
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 4958b2f89dce..d917a2d8c30f 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -34,6 +34,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
+#include <linux/of.h>
#include <linux/platform_data/ina2xx.h>
@@ -221,6 +222,7 @@ static int ina2xx_probe(struct i2c_client *client,
struct ina2xx_data *data;
struct ina2xx_platform_data *pdata;
int ret;
+ u32 val;
long shunt = 10000; /* default shunt value 10mOhms */
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
@@ -234,6 +236,9 @@ static int ina2xx_probe(struct i2c_client *client,
pdata =
(struct ina2xx_platform_data *)client->dev.platform_data;
shunt = pdata->shunt_uohms;
+ } else if (!of_property_read_u32(client->dev.of_node,
+ "shunt-resistor", &val)) {
+ shunt = val;
}
if (shunt <= 0)
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index f644a2e57599..d0def50ea860 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -247,9 +247,8 @@ static struct lm63_data *lm63_update_device(struct device *dev)
mutex_lock(&data->update_lock);
- next_update = data->last_updated
- + msecs_to_jiffies(data->update_interval) + 1;
-
+ next_update = data->last_updated +
+ msecs_to_jiffies(data->update_interval);
if (time_after(jiffies, next_update) || !data->valid) {
if (data->config & 0x04) { /* tachometer enabled */
/* order matters for fan1_input */
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 8eeb141c85ac..cdff74282955 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -470,8 +470,8 @@ static struct lm90_data *lm90_update_device(struct device *dev)
mutex_lock(&data->update_lock);
- next_update = data->last_updated
- + msecs_to_jiffies(data->update_interval) + 1;
+ next_update = data->last_updated +
+ msecs_to_jiffies(data->update_interval);
if (time_after(jiffies, next_update) || !data->valid) {
u8 h, l;
u8 alarms;
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 04638aee9039..99cec1825420 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -199,7 +199,7 @@ static const s8 NCT6775_ALARM_BITS[] = {
0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */
17, -1, -1, -1, -1, -1, -1, /* in8..in14 */
-1, /* unused */
- 6, 7, 11, 10, 23, /* fan1..fan5 */
+ 6, 7, 11, -1, -1, /* fan1..fan5 */
-1, -1, -1, /* unused */
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, -1 }; /* intrusion0, intrusion1 */
@@ -625,6 +625,7 @@ struct nct6775_data {
u8 has_fan_min; /* some fans don't have min register */
bool has_fan_div;
+ u8 num_temp_alarms; /* 2 or 3 */
u8 temp_fixed_num; /* 3 or 6 */
u8 temp_type[NUM_TEMP_FIXED];
s8 temp_offset[NUM_TEMP_FIXED];
@@ -1193,6 +1194,42 @@ show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
(unsigned int)((data->alarms >> nr) & 0x01));
}
+static int find_temp_source(struct nct6775_data *data, int index, int count)
+{
+ int source = data->temp_src[index];
+ int nr;
+
+ for (nr = 0; nr < count; nr++) {
+ int src;
+
+ src = nct6775_read_value(data,
+ data->REG_TEMP_SOURCE[nr]) & 0x1f;
+ if (src == source)
+ return nr;
+ }
+ return -1;
+}
+
+static ssize_t
+show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct6775_data *data = nct6775_update_device(dev);
+ unsigned int alarm = 0;
+ int nr;
+
+ /*
+ * For temperatures, there is no fixed mapping from registers to alarm
+ * bits. Alarm bits are determined by the temperature source mapping.
+ */
+ nr = find_temp_source(data, sattr->index, data->num_temp_alarms);
+ if (nr >= 0) {
+ int bit = data->ALARM_BITS[nr + TEMP_ALARM_BASE];
+ alarm = (data->alarms >> bit) & 0x01;
+ }
+ return sprintf(buf, "%u\n", alarm);
+}
+
static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0);
static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0);
static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0);
@@ -1874,22 +1911,18 @@ static struct sensor_device_attribute sda_temp_type[] = {
};
static struct sensor_device_attribute sda_temp_alarm[] = {
- SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL,
- TEMP_ALARM_BASE),
- SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL,
- TEMP_ALARM_BASE + 1),
- SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL,
- TEMP_ALARM_BASE + 2),
- SENSOR_ATTR(temp4_alarm, S_IRUGO, show_alarm, NULL,
- TEMP_ALARM_BASE + 3),
- SENSOR_ATTR(temp5_alarm, S_IRUGO, show_alarm, NULL,
- TEMP_ALARM_BASE + 4),
- SENSOR_ATTR(temp6_alarm, S_IRUGO, show_alarm, NULL,
- TEMP_ALARM_BASE + 5),
+ SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
+ SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
+ SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
+ SENSOR_ATTR(temp4_alarm, S_IRUGO, show_temp_alarm, NULL, 3),
+ SENSOR_ATTR(temp5_alarm, S_IRUGO, show_temp_alarm, NULL, 4),
+ SENSOR_ATTR(temp6_alarm, S_IRUGO, show_temp_alarm, NULL, 5),
+ SENSOR_ATTR(temp7_alarm, S_IRUGO, show_temp_alarm, NULL, 6),
+ SENSOR_ATTR(temp8_alarm, S_IRUGO, show_temp_alarm, NULL, 7),
+ SENSOR_ATTR(temp9_alarm, S_IRUGO, show_temp_alarm, NULL, 8),
+ SENSOR_ATTR(temp10_alarm, S_IRUGO, show_temp_alarm, NULL, 9),
};
-#define NUM_TEMP_ALARM ARRAY_SIZE(sda_temp_alarm)
-
static ssize_t
show_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -3215,13 +3248,11 @@ static void nct6775_device_remove_files(struct device *dev)
device_remove_file(dev, &sda_temp_max[i].dev_attr);
device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
device_remove_file(dev, &sda_temp_crit[i].dev_attr);
+ device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
if (!(data->have_temp_fixed & (1 << i)))
continue;
device_remove_file(dev, &sda_temp_type[i].dev_attr);
device_remove_file(dev, &sda_temp_offset[i].dev_attr);
- if (i >= NUM_TEMP_ALARM)
- continue;
- device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
}
device_remove_file(dev, &sda_caseopen[0].dev_attr);
@@ -3419,6 +3450,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->auto_pwm_num = 6;
data->has_fan_div = true;
data->temp_fixed_num = 3;
+ data->num_temp_alarms = 3;
data->ALARM_BITS = NCT6775_ALARM_BITS;
@@ -3483,6 +3515,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->auto_pwm_num = 4;
data->has_fan_div = false;
data->temp_fixed_num = 3;
+ data->num_temp_alarms = 3;
data->ALARM_BITS = NCT6776_ALARM_BITS;
@@ -3547,6 +3580,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->auto_pwm_num = 4;
data->has_fan_div = false;
data->temp_fixed_num = 6;
+ data->num_temp_alarms = 2;
data->ALARM_BITS = NCT6779_ALARM_BITS;
@@ -3843,10 +3877,12 @@ static int nct6775_probe(struct platform_device *pdev)
&sda_fan_input[i].dev_attr);
if (err)
goto exit_remove;
- err = device_create_file(dev,
- &sda_fan_alarm[i].dev_attr);
- if (err)
- goto exit_remove;
+ if (data->ALARM_BITS[FAN_ALARM_BASE + i] >= 0) {
+ err = device_create_file(dev,
+ &sda_fan_alarm[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
if (data->kind != nct6776 &&
data->kind != nct6779) {
err = device_create_file(dev,
@@ -3897,6 +3933,12 @@ static int nct6775_probe(struct platform_device *pdev)
if (err)
goto exit_remove;
}
+ if (find_temp_source(data, i, data->num_temp_alarms) >= 0) {
+ err = device_create_file(dev,
+ &sda_temp_alarm[i].dev_attr);
+ if (err)
+ goto exit_remove;
+ }
if (!(data->have_temp_fixed & (1 << i)))
continue;
err = device_create_file(dev, &sda_temp_type[i].dev_attr);
@@ -3905,12 +3947,6 @@ static int nct6775_probe(struct platform_device *pdev)
err = device_create_file(dev, &sda_temp_offset[i].dev_attr);
if (err)
goto exit_remove;
- if (i >= NUM_TEMP_ALARM ||
- data->ALARM_BITS[TEMP_ALARM_BASE + i] < 0)
- continue;
- err = device_create_file(dev, &sda_temp_alarm[i].dev_attr);
- if (err)
- goto exit_remove;
}
for (i = 0; i < ARRAY_SIZE(sda_caseopen); i++) {
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index d6d640a733d5..830a842d796a 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -514,7 +514,6 @@ static int ntc_thermistor_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
ntc_iio_channel_release(pdata);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 016027229e81..004801e6fbb9 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -2598,7 +2598,6 @@ static int w83627ehf_probe(struct platform_device *pdev)
exit_remove:
w83627ehf_device_remove_files(dev);
exit_release:
- platform_set_drvdata(pdev, NULL);
release_region(res->start, IOREGION_LENGTH);
exit:
return err;
@@ -2611,7 +2610,6 @@ static int w83627ehf_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
w83627ehf_device_remove_files(&pdev->dev);
release_region(data->addr, IOREGION_LENGTH);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 73e2e7db2b64..fdc2ab4af315 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -108,6 +108,7 @@ config I2C_I801
Lynx Point-LP (PCH)
Avoton (SOC)
Wellsburg (PCH)
+ Coleto Creek (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -150,6 +151,7 @@ config I2C_PIIX4
ATI SB700/SP5100
ATI SB800
AMD Hudson-2
+ AMD CZ
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -474,16 +476,6 @@ config I2C_IMX
This driver can also be built as a module. If so, the module
will be called i2c-imx.
-config I2C_INTEL_MID
- tristate "Intel Moorestown/Medfield Platform I2C controller"
- depends on PCI
- help
- Say Y here if you have an Intel Moorestown/Medfield platform I2C
- controller.
-
- This support is also available as a module. If so, the module
- will be called i2c-intel-mid.
-
config I2C_IOP3XX
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
@@ -494,6 +486,16 @@ config I2C_IOP3XX
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
+config I2C_KEMPLD
+ tristate "Kontron COM I2C Controller"
+ depends on MFD_KEMPLD
+ help
+ This enables support for the I2C bus interface on some Kontron ETX
+ and COMexpress (ETXexpress) modules.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-kempld.
+
config I2C_MPC
tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx"
depends on PPC
@@ -507,10 +509,11 @@ config I2C_MPC
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
- depends on (MV64X60 || PLAT_ORION)
+ depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI)
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges.
+ This driver is also used for Allwinner SoCs I2C controllers.
This driver can also be built as a module. If so, the module
will be called i2c-mv64xxx.
@@ -724,6 +727,16 @@ config I2C_VERSATILE
This driver can also be built as a module. If so, the module
will be called i2c-versatile.
+config I2C_WMT
+ tristate "Wondermedia WM8xxx SoC I2C bus support"
+ depends on ARCH_VT8500
+ help
+ Say yes if you want to support the I2C bus on Wondermedia 8xxx-series
+ SoCs.
+
+ This driver can also be built as a module. If so, the module will be
+ called i2c-wmt.
+
config I2C_OCTEON
tristate "Cavium OCTEON I2C bus support"
depends on CPU_CAVIUM_OCTEON
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 8f4fc23b85b1..d00997f3eb3b 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -46,8 +46,8 @@ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
-obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
+obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_MXS) += i2c-mxs.o
@@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
+obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o
obj-$(CONFIG_I2C_XLR) += i2c-xlr.o
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
index 05080c449c6b..13ea1c29873d 100644
--- a/drivers/i2c/busses/i2c-bfin-twi.c
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -39,33 +39,40 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
unsigned short mast_stat = read_MASTER_STAT(iface);
if (twi_int_status & XMTSERV) {
+ if (iface->writeNum <= 0) {
+ /* start receive immediately after complete sending in
+ * combine mode.
+ */
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | MDIR);
+ else if (iface->manual_stop)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) | STOP);
+ else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
+ iface->cur_msg + 1 < iface->msg_num) {
+ if (iface->pmsg[iface->cur_msg + 1].flags &
+ I2C_M_RD)
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) |
+ MDIR);
+ else
+ write_MASTER_CTL(iface,
+ read_MASTER_CTL(iface) &
+ ~MDIR);
+ }
+ }
/* Transmit next data */
- if (iface->writeNum > 0) {
+ while (iface->writeNum > 0 &&
+ (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) {
SSYNC();
write_XMT_DATA8(iface, *(iface->transPtr++));
iface->writeNum--;
}
- /* start receive immediately after complete sending in
- * combine mode.
- */
- else if (iface->cur_mode == TWI_I2C_MODE_COMBINED)
- write_MASTER_CTL(iface,
- read_MASTER_CTL(iface) | MDIR);
- else if (iface->manual_stop)
- write_MASTER_CTL(iface,
- read_MASTER_CTL(iface) | STOP);
- else if (iface->cur_mode == TWI_I2C_MODE_REPEAT &&
- iface->cur_msg + 1 < iface->msg_num) {
- if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD)
- write_MASTER_CTL(iface,
- read_MASTER_CTL(iface) | MDIR);
- else
- write_MASTER_CTL(iface,
- read_MASTER_CTL(iface) & ~MDIR);
- }
}
if (twi_int_status & RCVSERV) {
- if (iface->readNum > 0) {
+ while (iface->readNum > 0 &&
+ (read_FIFO_STAT(iface) & RCVSTAT)) {
/* Receive next data */
*(iface->transPtr) = read_RCV_DATA8(iface);
if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 3823623baa48..2e1f7eb55bf4 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -338,6 +338,14 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
tptr = 0;
rptr = 0;
+ /*
+ * If there was a collision in the last i2c transaction,
+ * Set I2COM_MASTER as it was cleared during collision.
+ */
+ if (in_be16(&tbdf->cbd_sc) & BD_SC_CL) {
+ out_8(&cpm->i2c_reg->i2com, I2COM_MASTER);
+ }
+
while (tptr < num) {
pmsg = &msgs[tptr];
dev_dbg(&adap->dev, "R: %d T: %d\n", rptr, tptr);
@@ -646,7 +654,7 @@ static int cpm_i2c_probe(struct platform_device *ofdev)
cpm->ofdev = ofdev;
- dev_set_drvdata(&ofdev->dev, cpm);
+ platform_set_drvdata(ofdev, cpm);
cpm->adap = cpm_ops;
i2c_set_adapdata(&cpm->adap, cpm);
@@ -689,7 +697,7 @@ out_free:
static int cpm_i2c_remove(struct platform_device *ofdev)
{
- struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev);
+ struct cpm_i2c *cpm = platform_get_drvdata(ofdev);
i2c_del_adapter(&cpm->adap);
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index cf20e06a88e1..fa556057d224 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -646,13 +646,6 @@ static int davinci_i2c_probe(struct platform_device *pdev)
struct resource *mem, *irq;
int r;
- /* NOTE: driver uses the static register mapping */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
-
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq) {
dev_err(&pdev->dev, "no irq resource?\n");
@@ -697,6 +690,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
return -ENODEV;
clk_prepare_enable(dev->clk);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base)) {
r = PTR_ERR(dev->base);
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index c41ca6354fc5..ad46616de29e 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -67,9 +67,12 @@
#define DW_IC_STATUS 0x70
#define DW_IC_TXFLR 0x74
#define DW_IC_RXFLR 0x78
+#define DW_IC_SDA_HOLD 0x7c
#define DW_IC_TX_ABRT_SOURCE 0x80
#define DW_IC_ENABLE_STATUS 0x9c
#define DW_IC_COMP_PARAM_1 0xf4
+#define DW_IC_COMP_VERSION 0xf8
+#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A
#define DW_IC_COMP_TYPE 0xfc
#define DW_IC_COMP_TYPE_VALUE 0x44570140
@@ -332,6 +335,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
+ /* Configure SDA Hold Time if required */
+ if (dev->sda_hold_time) {
+ reg = dw_readl(dev, DW_IC_COMP_VERSION);
+ if (reg >= DW_IC_SDA_HOLD_MIN_VERS)
+ dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD);
+ else
+ dev_warn(dev->dev,
+ "Hardware too old to adjust SDA hold time.");
+ }
+
/* Configure Tx/Rx FIFO threshold levels */
dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL);
dw_writel(dev, 0, DW_IC_RX_TL);
@@ -580,14 +593,23 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
i2c_dw_xfer_init(dev);
/* wait for tx to complete */
- ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
+ ret = wait_for_completion_timeout(&dev->cmd_complete, HZ);
if (ret == 0) {
dev_err(dev->dev, "controller timed out\n");
+ /* i2c_dw_init implicitly disables the adapter */
i2c_dw_init(dev);
ret = -ETIMEDOUT;
goto done;
- } else if (ret < 0)
- goto done;
+ }
+
+ /*
+ * We must disable the adapter before unlocking the &dev->lock mutex
+ * below. Otherwise the hardware might continue generating interrupts
+ * which in turn causes a race condition with the following transfer.
+ * Needs some more investigation if the additional interrupts are
+ * a hardware bug or this driver doesn't handle them correctly yet.
+ */
+ __i2c_dw_enable(dev, false);
if (dev->msg_err) {
ret = dev->msg_err;
@@ -596,8 +618,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
/* no error */
if (likely(!dev->cmd_err)) {
- /* Disable the adapter */
- __i2c_dw_enable(dev, false);
ret = num;
goto done;
}
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index e761ad18dd61..912aa2262866 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -90,6 +90,7 @@ struct dw_i2c_dev {
unsigned int tx_fifo_depth;
unsigned int rx_fifo_depth;
int rx_outstanding;
+ u32 sda_hold_time;
};
#define ACCESS_SWAP 0x00000001
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 35b70a1edf57..4c5fadabe49d 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -34,6 +34,7 @@
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -87,13 +88,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
struct resource *mem;
int irq, r;
- /* NOTE: driver uses the static register mapping */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -EINVAL;
- }
-
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no irq resource?\n");
@@ -104,6 +98,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
@@ -121,6 +116,16 @@ static int dw_i2c_probe(struct platform_device *pdev)
return PTR_ERR(dev->clk);
clk_prepare_enable(dev->clk);
+ if (pdev->dev.of_node) {
+ u32 ht = 0;
+ u32 ic_clk = dev->get_clk_rate_khz(dev);
+
+ of_property_read_u32(pdev->dev.of_node,
+ "i2c-sda-hold-time-ns", &ht);
+ dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
+ 1000000);
+ }
+
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 3a6903f63913..4ebceed6bc66 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -58,6 +58,7 @@
Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes
Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes
Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes
+ Coleto Creek (PCH) 0x23b0 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -169,6 +170,7 @@
#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
#define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
+#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
#define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22
@@ -817,6 +819,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 405a2e240454..973f51688276 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -705,7 +705,7 @@ static int iic_probe(struct platform_device *ofdev)
return -ENOMEM;
}
- dev_set_drvdata(&ofdev->dev, dev);
+ platform_set_drvdata(ofdev, dev);
dev->vaddr = of_iomap(np, 0);
if (dev->vaddr == NULL) {
@@ -782,7 +782,7 @@ error_cleanup:
*/
static int iic_remove(struct platform_device *ofdev)
{
- struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev);
+ struct ibm_iic_private *dev = platform_get_drvdata(ofdev);
i2c_del_adapter(&dev->adap);
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 82f20c60bb7b..e24279725d36 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -51,7 +51,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
/** Defines ********************************************************************
@@ -148,6 +147,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
{
@@ -493,24 +493,19 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
struct imx_i2c_struct *i2c_imx;
struct resource *res;
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
- struct pinctrl *pinctrl;
void __iomem *base;
int irq, ret;
u32 bitrate;
dev_dbg(&pdev->dev, "<%s>\n", __func__);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "can't get device resources\n");
- return -ENOENT;
- }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "can't get irq number\n");
return -ENOENT;
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
@@ -535,12 +530,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->base = base;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl)) {
- dev_err(&pdev->dev, "can't get/select pinctrl\n");
- return PTR_ERR(pinctrl);
- }
-
/* Get I2C clock */
i2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_imx->clk)) {
diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c
deleted file mode 100644
index 0fb659726ffc..000000000000
--- a/drivers/i2c/busses/i2c-intel-mid.c
+++ /dev/null
@@ -1,1121 +0,0 @@
-/*
- * Support for Moorestown/Medfield I2C chip
- *
- * Copyright (c) 2009 Intel Corporation.
- * Copyright (c) 2009 Synopsys. Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License, version
- * 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc., 51
- * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/pm_runtime.h>
-#include <linux/io.h>
-
-#define DRIVER_NAME "i2c-intel-mid"
-#define VERSION "Version 0.5ac2"
-#define PLATFORM "Moorestown/Medfield"
-
-/* Tables use: 0 Moorestown, 1 Medfield */
-#define NUM_PLATFORMS 2
-enum platform_enum {
- MOORESTOWN = 0,
- MEDFIELD = 1,
-};
-
-enum mid_i2c_status {
- STATUS_IDLE = 0,
- STATUS_READ_START,
- STATUS_READ_IN_PROGRESS,
- STATUS_READ_SUCCESS,
- STATUS_WRITE_START,
- STATUS_WRITE_SUCCESS,
- STATUS_XFER_ABORT,
- STATUS_STANDBY
-};
-
-/**
- * struct intel_mid_i2c_private - per device I²C context
- * @adap: core i2c layer adapter information
- * @dev: device reference for power management
- * @base: register base
- * @speed: speed mode for this port
- * @complete: completion object for transaction wait
- * @abort: reason for last abort
- * @rx_buf: pointer into working receive buffer
- * @rx_buf_len: receive buffer length
- * @status: adapter state machine
- * @msg: the message we are currently processing
- * @platform: the MID device type we are part of
- * @lock: transaction serialization
- *
- * We allocate one of these per device we discover, it holds the core
- * i2c layer objects and the data we need to track privately.
- */
-struct intel_mid_i2c_private {
- struct i2c_adapter adap;
- struct device *dev;
- void __iomem *base;
- int speed;
- struct completion complete;
- int abort;
- u8 *rx_buf;
- int rx_buf_len;
- enum mid_i2c_status status;
- struct i2c_msg *msg;
- enum platform_enum platform;
- struct mutex lock;
-};
-
-#define NUM_SPEEDS 3
-
-#define ACTIVE 0
-#define STANDBY 1
-
-
-/* Control register */
-#define IC_CON 0x00
-#define SLV_DIS (1 << 6) /* Disable slave mode */
-#define RESTART (1 << 5) /* Send a Restart condition */
-#define ADDR_10BIT (1 << 4) /* 10-bit addressing */
-#define STANDARD_MODE (1 << 1) /* standard mode */
-#define FAST_MODE (2 << 1) /* fast mode */
-#define HIGH_MODE (3 << 1) /* high speed mode */
-#define MASTER_EN (1 << 0) /* Master mode */
-
-/* Target address register */
-#define IC_TAR 0x04
-#define IC_TAR_10BIT_ADDR (1 << 12) /* 10-bit addressing */
-#define IC_TAR_SPECIAL (1 << 11) /* Perform special I2C cmd */
-#define IC_TAR_GC_OR_START (1 << 10) /* 0: Gerneral Call Address */
- /* 1: START BYTE */
-/* Slave Address Register */
-#define IC_SAR 0x08 /* Not used in Master mode */
-
-/* High Speed Master Mode Code Address Register */
-#define IC_HS_MADDR 0x0c
-
-/* Rx/Tx Data Buffer and Command Register */
-#define IC_DATA_CMD 0x10
-#define IC_RD (1 << 8) /* 1: Read 0: Write */
-
-/* Standard Speed Clock SCL High Count Register */
-#define IC_SS_SCL_HCNT 0x14
-
-/* Standard Speed Clock SCL Low Count Register */
-#define IC_SS_SCL_LCNT 0x18
-
-/* Fast Speed Clock SCL High Count Register */
-#define IC_FS_SCL_HCNT 0x1c
-
-/* Fast Spedd Clock SCL Low Count Register */
-#define IC_FS_SCL_LCNT 0x20
-
-/* High Speed Clock SCL High Count Register */
-#define IC_HS_SCL_HCNT 0x24
-
-/* High Speed Clock SCL Low Count Register */
-#define IC_HS_SCL_LCNT 0x28
-
-/* Interrupt Status Register */
-#define IC_INTR_STAT 0x2c /* Read only */
-#define R_GEN_CALL (1 << 11)
-#define R_START_DET (1 << 10)
-#define R_STOP_DET (1 << 9)
-#define R_ACTIVITY (1 << 8)
-#define R_RX_DONE (1 << 7)
-#define R_TX_ABRT (1 << 6)
-#define R_RD_REQ (1 << 5)
-#define R_TX_EMPTY (1 << 4)
-#define R_TX_OVER (1 << 3)
-#define R_RX_FULL (1 << 2)
-#define R_RX_OVER (1 << 1)
-#define R_RX_UNDER (1 << 0)
-
-/* Interrupt Mask Register */
-#define IC_INTR_MASK 0x30 /* Read and Write */
-#define M_GEN_CALL (1 << 11)
-#define M_START_DET (1 << 10)
-#define M_STOP_DET (1 << 9)
-#define M_ACTIVITY (1 << 8)
-#define M_RX_DONE (1 << 7)
-#define M_TX_ABRT (1 << 6)
-#define M_RD_REQ (1 << 5)
-#define M_TX_EMPTY (1 << 4)
-#define M_TX_OVER (1 << 3)
-#define M_RX_FULL (1 << 2)
-#define M_RX_OVER (1 << 1)
-#define M_RX_UNDER (1 << 0)
-
-/* Raw Interrupt Status Register */
-#define IC_RAW_INTR_STAT 0x34 /* Read Only */
-#define GEN_CALL (1 << 11) /* General call */
-#define START_DET (1 << 10) /* (RE)START occurred */
-#define STOP_DET (1 << 9) /* STOP occurred */
-#define ACTIVITY (1 << 8) /* Bus busy */
-#define RX_DONE (1 << 7) /* Not used in Master mode */
-#define TX_ABRT (1 << 6) /* Transmit Abort */
-#define RD_REQ (1 << 5) /* Not used in Master mode */
-#define TX_EMPTY (1 << 4) /* TX FIFO <= threshold */
-#define TX_OVER (1 << 3) /* TX FIFO overflow */
-#define RX_FULL (1 << 2) /* RX FIFO >= threshold */
-#define RX_OVER (1 << 1) /* RX FIFO overflow */
-#define RX_UNDER (1 << 0) /* RX FIFO empty */
-
-/* Receive FIFO Threshold Register */
-#define IC_RX_TL 0x38
-
-/* Transmit FIFO Treshold Register */
-#define IC_TX_TL 0x3c
-
-/* Clear Combined and Individual Interrupt Register */
-#define IC_CLR_INTR 0x40
-#define CLR_INTR (1 << 0)
-
-/* Clear RX_UNDER Interrupt Register */
-#define IC_CLR_RX_UNDER 0x44
-#define CLR_RX_UNDER (1 << 0)
-
-/* Clear RX_OVER Interrupt Register */
-#define IC_CLR_RX_OVER 0x48
-#define CLR_RX_OVER (1 << 0)
-
-/* Clear TX_OVER Interrupt Register */
-#define IC_CLR_TX_OVER 0x4c
-#define CLR_TX_OVER (1 << 0)
-
-#define IC_CLR_RD_REQ 0x50
-
-/* Clear TX_ABRT Interrupt Register */
-#define IC_CLR_TX_ABRT 0x54
-#define CLR_TX_ABRT (1 << 0)
-#define IC_CLR_RX_DONE 0x58
-
-/* Clear ACTIVITY Interrupt Register */
-#define IC_CLR_ACTIVITY 0x5c
-#define CLR_ACTIVITY (1 << 0)
-
-/* Clear STOP_DET Interrupt Register */
-#define IC_CLR_STOP_DET 0x60
-#define CLR_STOP_DET (1 << 0)
-
-/* Clear START_DET Interrupt Register */
-#define IC_CLR_START_DET 0x64
-#define CLR_START_DET (1 << 0)
-
-/* Clear GEN_CALL Interrupt Register */
-#define IC_CLR_GEN_CALL 0x68
-#define CLR_GEN_CALL (1 << 0)
-
-/* Enable Register */
-#define IC_ENABLE 0x6c
-#define ENABLE (1 << 0)
-
-/* Status Register */
-#define IC_STATUS 0x70 /* Read Only */
-#define STAT_SLV_ACTIVITY (1 << 6) /* Slave not in idle */
-#define STAT_MST_ACTIVITY (1 << 5) /* Master not in idle */
-#define STAT_RFF (1 << 4) /* RX FIFO Full */
-#define STAT_RFNE (1 << 3) /* RX FIFO Not Empty */
-#define STAT_TFE (1 << 2) /* TX FIFO Empty */
-#define STAT_TFNF (1 << 1) /* TX FIFO Not Full */
-#define STAT_ACTIVITY (1 << 0) /* Activity Status */
-
-/* Transmit FIFO Level Register */
-#define IC_TXFLR 0x74 /* Read Only */
-#define TXFLR (1 << 0) /* TX FIFO level */
-
-/* Receive FIFO Level Register */
-#define IC_RXFLR 0x78 /* Read Only */
-#define RXFLR (1 << 0) /* RX FIFO level */
-
-/* Transmit Abort Source Register */
-#define IC_TX_ABRT_SOURCE 0x80
-#define ABRT_SLVRD_INTX (1 << 15)
-#define ABRT_SLV_ARBLOST (1 << 14)
-#define ABRT_SLVFLUSH_TXFIFO (1 << 13)
-#define ARB_LOST (1 << 12)
-#define ABRT_MASTER_DIS (1 << 11)
-#define ABRT_10B_RD_NORSTRT (1 << 10)
-#define ABRT_SBYTE_NORSTRT (1 << 9)
-#define ABRT_HS_NORSTRT (1 << 8)
-#define ABRT_SBYTE_ACKDET (1 << 7)
-#define ABRT_HS_ACKDET (1 << 6)
-#define ABRT_GCALL_READ (1 << 5)
-#define ABRT_GCALL_NOACK (1 << 4)
-#define ABRT_TXDATA_NOACK (1 << 3)
-#define ABRT_10ADDR2_NOACK (1 << 2)
-#define ABRT_10ADDR1_NOACK (1 << 1)
-#define ABRT_7B_ADDR_NOACK (1 << 0)
-
-/* Enable Status Register */
-#define IC_ENABLE_STATUS 0x9c
-#define IC_EN (1 << 0) /* I2C in an enabled state */
-
-/* Component Parameter Register 1*/
-#define IC_COMP_PARAM_1 0xf4
-#define APB_DATA_WIDTH (0x3 << 0)
-
-/* added by xiaolin --begin */
-#define SS_MIN_SCL_HIGH 4000
-#define SS_MIN_SCL_LOW 4700
-#define FS_MIN_SCL_HIGH 600
-#define FS_MIN_SCL_LOW 1300
-#define HS_MIN_SCL_HIGH_100PF 60
-#define HS_MIN_SCL_LOW_100PF 120
-
-#define STANDARD 0
-#define FAST 1
-#define HIGH 2
-
-#define NUM_SPEEDS 3
-
-static int speed_mode[6] = {
- FAST,
- FAST,
- FAST,
- STANDARD,
- FAST,
- FAST
-};
-
-static int ctl_num = 6;
-module_param_array(speed_mode, int, &ctl_num, S_IRUGO);
-MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)");
-
-/**
- * intel_mid_i2c_disable - Disable I2C controller
- * @adap: struct pointer to i2c_adapter
- *
- * Return Value:
- * 0 success
- * -EBUSY if device is busy
- * -ETIMEDOUT if i2c cannot be disabled within the given time
- *
- * I2C bus state should be checked prior to disabling the hardware. If bus is
- * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable
- * I2C controller.
- */
-static int intel_mid_i2c_disable(struct i2c_adapter *adap)
-{
- struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
- int err = 0;
- int count = 0;
- int ret1, ret2;
- static const u16 delay[NUM_SPEEDS] = {100, 25, 3};
-
- /* Set IC_ENABLE to 0 */
- writel(0, i2c->base + IC_ENABLE);
-
- /* Check if device is busy */
- dev_dbg(&adap->dev, "mrst i2c disable\n");
- while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1)
- || (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) {
- udelay(delay[i2c->speed]);
- writel(0, i2c->base + IC_ENABLE);
- dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n",
- count, i2c->speed);
- if (count++ > 10) {
- err = -ETIMEDOUT;
- break;
- }
- }
-
- /* Clear all interrupts */
- readl(i2c->base + IC_CLR_INTR);
- readl(i2c->base + IC_CLR_STOP_DET);
- readl(i2c->base + IC_CLR_START_DET);
- readl(i2c->base + IC_CLR_ACTIVITY);
- readl(i2c->base + IC_CLR_TX_ABRT);
- readl(i2c->base + IC_CLR_RX_OVER);
- readl(i2c->base + IC_CLR_RX_UNDER);
- readl(i2c->base + IC_CLR_TX_OVER);
- readl(i2c->base + IC_CLR_RX_DONE);
- readl(i2c->base + IC_CLR_GEN_CALL);
-
- /* Disable all interupts */
- writel(0x0000, i2c->base + IC_INTR_MASK);
-
- return err;
-}
-
-/**
- * intel_mid_i2c_hwinit - Initialize the I2C hardware registers
- * @dev: pci device struct pointer
- *
- * This function will be called in intel_mid_i2c_probe() before device
- * registration.
- *
- * Return Values:
- * 0 success
- * -EBUSY i2c cannot be disabled
- * -ETIMEDOUT i2c cannot be disabled
- * -EFAULT If APB data width is not 32-bit wide
- *
- * I2C should be disabled prior to other register operation. If failed, an
- * errno is returned. Mask and Clear all interrpts, this should be done at
- * first. Set common registers which will not be modified during normal
- * transfers, including: control register, FIFO threshold and clock freq.
- * Check APB data width at last.
- */
-static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c)
-{
- int err;
-
- static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
- { 0x75, 0x15, 0x07 },
- { 0x04c, 0x10, 0x06 }
- };
- static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = {
- { 0x7C, 0x21, 0x0E },
- { 0x053, 0x19, 0x0F }
- };
-
- /* Disable i2c first */
- err = intel_mid_i2c_disable(&i2c->adap);
- if (err)
- return err;
-
- /*
- * Setup clock frequency and speed mode
- * Enable restart condition,
- * enable master FSM, disable slave FSM,
- * use target address when initiating transfer
- */
-
- writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN,
- i2c->base + IC_CON);
- writel(hcnt[i2c->platform][i2c->speed],
- i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3)));
- writel(lcnt[i2c->platform][i2c->speed],
- i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3)));
-
- /* Set tranmit & receive FIFO threshold to zero */
- writel(0x0, i2c->base + IC_RX_TL);
- writel(0x0, i2c->base + IC_TX_TL);
-
- return 0;
-}
-
-/**
- * intel_mid_i2c_func - Return the supported three I2C operations.
- * @adapter: i2c_adapter struct pointer
- */
-static u32 intel_mid_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
-}
-
-/**
- * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages
- * are equal.
- * @p1: first i2c_msg
- * @p2: second i2c_msg
- *
- * Return Values:
- * 0 if addresses are equal
- * 1 if not equal
- *
- * Within a single transfer, the I2C client may need to send its address more
- * than once. So a check if the addresses match is needed.
- */
-static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1,
- const struct i2c_msg *p2)
-{
- if (p1->addr != p2->addr)
- return 1;
- if ((p1->flags ^ p2->flags) & I2C_M_TEN)
- return 1;
- return 0;
-}
-
-/**
- * intel_mid_i2c_abort - To handle transfer abortions and print error messages.
- * @adap: i2c_adapter struct pointer
- *
- * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be
- * distingushed. At present, no circumstances have been found out that
- * multiple errors would be occurred simutaneously, so we simply use the
- * register value directly.
- *
- * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need
- * a few extra steps)
- */
-static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c)
-{
- /* Read about source register */
- int abort = i2c->abort;
- struct i2c_adapter *adap = &i2c->adap;
-
- /* Single transfer error check:
- * According to databook, TX/RX FIFOs would be flushed when
- * the abort interrupt occurred.
- */
- if (abort & ABRT_MASTER_DIS)
- dev_err(&adap->dev,
- "initiate master operation with master mode disabled.\n");
- if (abort & ABRT_10B_RD_NORSTRT)
- dev_err(&adap->dev,
- "RESTART disabled and master sent READ cmd in 10-bit addressing.\n");
-
- if (abort & ABRT_SBYTE_NORSTRT) {
- dev_err(&adap->dev,
- "RESTART disabled and user is trying to send START byte.\n");
- writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE);
- writel(RESTART, i2c->base + IC_CON);
- writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR);
- }
-
- if (abort & ABRT_SBYTE_ACKDET)
- dev_err(&adap->dev,
- "START byte was not acknowledged.\n");
- if (abort & ABRT_TXDATA_NOACK)
- dev_dbg(&adap->dev,
- "No acknowledgement received from slave.\n");
- if (abort & ABRT_10ADDR2_NOACK)
- dev_dbg(&adap->dev,
- "The 2nd address byte of the 10-bit address was not acknowledged.\n");
- if (abort & ABRT_10ADDR1_NOACK)
- dev_dbg(&adap->dev,
- "The 1st address byte of 10-bit address was not acknowledged.\n");
- if (abort & ABRT_7B_ADDR_NOACK)
- dev_dbg(&adap->dev,
- "I2C slave device not acknowledged.\n");
-
- /* Clear TX_ABRT bit */
- readl(i2c->base + IC_CLR_TX_ABRT);
- i2c->status = STATUS_XFER_ABORT;
-}
-
-/**
- * xfer_read - Internal function to implement master read transfer.
- * @adap: i2c_adapter struct pointer
- * @buf: buffer in i2c_msg
- * @length: number of bytes to be read
- *
- * Return Values:
- * 0 if the read transfer succeeds
- * -ETIMEDOUT if cannot read the "raw" interrupt register
- * -EINVAL if a transfer abort occurred
- *
- * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to
- * data transfer. The actual "read" operation will be performed if an RX_FULL
- * interrupt occurred.
- *
- * Note there may be two interrupt signals captured, one should read
- * IC_RAW_INTR_STAT to separate between errors and actual data.
- */
-static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length)
-{
- struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
- int i = length;
- int err;
-
- if (length >= 256) {
- dev_err(&adap->dev,
- "I2C FIFO cannot support larger than 256 bytes\n");
- return -EMSGSIZE;
- }
-
- INIT_COMPLETION(i2c->complete);
-
- readl(i2c->base + IC_CLR_INTR);
- writel(0x0044, i2c->base + IC_INTR_MASK);
-
- i2c->status = STATUS_READ_START;
-
- while (i--)
- writel(IC_RD, i2c->base + IC_DATA_CMD);
-
- i2c->status = STATUS_READ_START;
- err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
- if (!err) {
- dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
- intel_mid_i2c_hwinit(i2c);
- return -ETIMEDOUT;
- }
- if (i2c->status == STATUS_READ_SUCCESS)
- return 0;
- else
- return -EIO;
-}
-
-/**
- * xfer_write - Internal function to implement master write transfer.
- * @adap: i2c_adapter struct pointer
- * @buf: buffer in i2c_msg
- * @length: number of bytes to be read
- *
- * Return Values:
- * 0 if the read transfer succeeds
- * -ETIMEDOUT if we cannot read the "raw" interrupt register
- * -EINVAL if a transfer abort occurred
- *
- * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to
- * data transfer. The actual "write" operation will be performed when the
- * RX_FULL interrupt signal occurs.
- *
- * Note there may be two interrupt signals captured, one should read
- * IC_RAW_INTR_STAT to separate between errors and actual data.
- */
-static int xfer_write(struct i2c_adapter *adap,
- unsigned char *buf, int length)
-{
- struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
- int i, err;
-
- if (length >= 256) {
- dev_err(&adap->dev,
- "I2C FIFO cannot support larger than 256 bytes\n");
- return -EMSGSIZE;
- }
-
- INIT_COMPLETION(i2c->complete);
-
- readl(i2c->base + IC_CLR_INTR);
- writel(0x0050, i2c->base + IC_INTR_MASK);
-
- i2c->status = STATUS_WRITE_START;
- for (i = 0; i < length; i++)
- writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD);
-
- i2c->status = STATUS_WRITE_START;
- err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ);
- if (!err) {
- dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n");
- intel_mid_i2c_hwinit(i2c);
- return -ETIMEDOUT;
- } else {
- if (i2c->status == STATUS_WRITE_SUCCESS)
- return 0;
- else
- return -EIO;
- }
-}
-
-static int intel_mid_i2c_setup(struct i2c_adapter *adap, struct i2c_msg *pmsg)
-{
- struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
- int err;
- u32 reg;
- u32 bit_mask;
- u32 mode;
-
- /* Disable device first */
- err = intel_mid_i2c_disable(adap);
- if (err) {
- dev_err(&adap->dev,
- "Cannot disable i2c controller, timeout\n");
- return err;
- }
-
- mode = (1 + i2c->speed) << 1;
- /* set the speed mode */
- reg = readl(i2c->base + IC_CON);
- if ((reg & 0x06) != mode) {
- dev_dbg(&adap->dev, "set mode %d\n", i2c->speed);
- writel((reg & ~0x6) | mode, i2c->base + IC_CON);
- }
-
- reg = readl(i2c->base + IC_CON);
- /* use 7-bit addressing */
- if (pmsg->flags & I2C_M_TEN) {
- if ((reg & ADDR_10BIT) != ADDR_10BIT) {
- dev_dbg(&adap->dev, "set i2c 10 bit address mode\n");
- writel(reg | ADDR_10BIT, i2c->base + IC_CON);
- }
- } else {
- if ((reg & ADDR_10BIT) != 0x0) {
- dev_dbg(&adap->dev, "set i2c 7 bit address mode\n");
- writel(reg & ~ADDR_10BIT, i2c->base + IC_CON);
- }
- }
- /* enable restart conditions */
- reg = readl(i2c->base + IC_CON);
- if ((reg & RESTART) != RESTART) {
- dev_dbg(&adap->dev, "enable restart conditions\n");
- writel(reg | RESTART, i2c->base + IC_CON);
- }
-
- /* enable master FSM */
- reg = readl(i2c->base + IC_CON);
- dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
- writel(reg | MASTER_EN, i2c->base + IC_CON);
- if ((reg & SLV_DIS) != SLV_DIS) {
- dev_dbg(&adap->dev, "enable master FSM\n");
- writel(reg | SLV_DIS, i2c->base + IC_CON);
- dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg);
- }
-
- /* use target address when initiating transfer */
- reg = readl(i2c->base + IC_TAR);
- bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START;
-
- if ((reg & bit_mask) != 0x0) {
- dev_dbg(&adap->dev,
- "WR: use target address when intiating transfer, i2c_tx_target\n");
- writel(reg & ~bit_mask, i2c->base + IC_TAR);
- }
-
- /* set target address to the I2C slave address */
- dev_dbg(&adap->dev,
- "set target address to the I2C slave address, addr is %x\n",
- pmsg->addr);
- writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0),
- i2c->base + IC_TAR);
-
- /* Enable I2C controller */
- writel(ENABLE, i2c->base + IC_ENABLE);
-
- return 0;
-}
-
-/**
- * intel_mid_i2c_xfer - Main master transfer routine.
- * @adap: i2c_adapter struct pointer
- * @pmsg: i2c_msg struct pointer
- * @num: number of i2c_msg
- *
- * Return Values:
- * + number of messages transferred
- * -ETIMEDOUT If cannot disable I2C controller or read IC_STATUS
- * -EINVAL If the address in i2c_msg is invalid
- *
- * This function will be registered in i2c-core and exposed to external
- * I2C clients.
- * 1. Disable I2C controller
- * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT
- * 3. Check if address in i2c_msg is valid
- * 4. Enable I2C controller
- * 5. Perform real transfer (call xfer_read or xfer_write)
- * 6. Wait until the current transfer is finished (check bus state)
- * 7. Mask and clear all interrupts
- */
-static int intel_mid_i2c_xfer(struct i2c_adapter *adap,
- struct i2c_msg *pmsg,
- int num)
-{
- struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap);
- int i, err = 0;
-
- /* if number of messages equal 0*/
- if (num == 0)
- return 0;
-
- pm_runtime_get(i2c->dev);
-
- mutex_lock(&i2c->lock);
- dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num);
- dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr);
-
-
- if (i2c->status != STATUS_IDLE) {
- dev_err(&adap->dev, "Adapter %d in transfer/standby\n",
- adap->nr);
- mutex_unlock(&i2c->lock);
- pm_runtime_put(i2c->dev);
- return -1;
- }
-
-
- for (i = 1; i < num; i++) {
- /* Message address equal? */
- if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) {
- dev_err(&adap->dev, "Invalid address in msg[%d]\n", i);
- mutex_unlock(&i2c->lock);
- pm_runtime_put(i2c->dev);
- return -EINVAL;
- }
- }
-
- if (intel_mid_i2c_setup(adap, pmsg)) {
- mutex_unlock(&i2c->lock);
- pm_runtime_put(i2c->dev);
- return -EINVAL;
- }
-
- for (i = 0; i < num; i++) {
- i2c->msg = pmsg;
- i2c->status = STATUS_IDLE;
- /* Read or Write */
- if (pmsg->flags & I2C_M_RD) {
- dev_dbg(&adap->dev, "I2C_M_RD\n");
- err = xfer_read(adap, pmsg->buf, pmsg->len);
- } else {
- dev_dbg(&adap->dev, "I2C_M_WR\n");
- err = xfer_write(adap, pmsg->buf, pmsg->len);
- }
- if (err < 0)
- break;
- dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i);
- pmsg++; /* next message */
- }
-
- /* Mask interrupts */
- writel(0x0000, i2c->base + IC_INTR_MASK);
- /* Clear all interrupts */
- readl(i2c->base + IC_CLR_INTR);
-
- i2c->status = STATUS_IDLE;
- mutex_unlock(&i2c->lock);
- pm_runtime_put(i2c->dev);
-
- return err;
-}
-
-static int intel_mid_i2c_runtime_suspend(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
- struct i2c_adapter *adap = to_i2c_adapter(dev);
- int err;
-
- if (i2c->status != STATUS_IDLE)
- return -1;
-
- intel_mid_i2c_disable(adap);
-
- err = pci_save_state(pdev);
- if (err) {
- dev_err(dev, "pci_save_state failed\n");
- return err;
- }
-
- err = pci_set_power_state(pdev, PCI_D3hot);
- if (err) {
- dev_err(dev, "pci_set_power_state failed\n");
- return err;
- }
- i2c->status = STATUS_STANDBY;
-
- return 0;
-}
-
-static int intel_mid_i2c_runtime_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev);
- int err;
-
- if (i2c->status != STATUS_STANDBY)
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(dev, "pci_enable_device failed\n");
- return err;
- }
-
- i2c->status = STATUS_IDLE;
-
- intel_mid_i2c_hwinit(i2c);
- return err;
-}
-
-static void i2c_isr_read(struct intel_mid_i2c_private *i2c)
-{
- struct i2c_msg *msg = i2c->msg;
- int rx_num;
- u32 len;
- u8 *buf;
-
- if (!(msg->flags & I2C_M_RD))
- return;
-
- if (i2c->status != STATUS_READ_IN_PROGRESS) {
- len = msg->len;
- buf = msg->buf;
- } else {
- len = i2c->rx_buf_len;
- buf = i2c->rx_buf;
- }
-
- rx_num = readl(i2c->base + IC_RXFLR);
-
- for (; len > 0 && rx_num > 0; len--, rx_num--)
- *buf++ = readl(i2c->base + IC_DATA_CMD);
-
- if (len > 0) {
- i2c->status = STATUS_READ_IN_PROGRESS;
- i2c->rx_buf_len = len;
- i2c->rx_buf = buf;
- } else
- i2c->status = STATUS_READ_SUCCESS;
-
- return;
-}
-
-static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev)
-{
- struct intel_mid_i2c_private *i2c = dev;
- u32 stat = readl(i2c->base + IC_INTR_STAT);
-
- if (!stat)
- return IRQ_NONE;
-
- dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat);
- stat &= 0x54;
-
- if (i2c->status != STATUS_WRITE_START &&
- i2c->status != STATUS_READ_START &&
- i2c->status != STATUS_READ_IN_PROGRESS)
- goto err;
-
- if (stat & TX_ABRT)
- i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE);
-
- readl(i2c->base + IC_CLR_INTR);
-
- if (stat & TX_ABRT) {
- intel_mid_i2c_abort(i2c);
- goto exit;
- }
-
- if (stat & RX_FULL) {
- i2c_isr_read(i2c);
- goto exit;
- }
-
- if (stat & TX_EMPTY) {
- if (readl(i2c->base + IC_STATUS) & 0x4)
- i2c->status = STATUS_WRITE_SUCCESS;
- }
-
-exit:
- if (i2c->status == STATUS_READ_SUCCESS ||
- i2c->status == STATUS_WRITE_SUCCESS ||
- i2c->status == STATUS_XFER_ABORT) {
- /* Clear all interrupts */
- readl(i2c->base + IC_CLR_INTR);
- /* Mask interrupts */
- writel(0, i2c->base + IC_INTR_MASK);
- complete(&i2c->complete);
- }
-err:
- return IRQ_HANDLED;
-}
-
-static struct i2c_algorithm intel_mid_i2c_algorithm = {
- .master_xfer = intel_mid_i2c_xfer,
- .functionality = intel_mid_i2c_func,
-};
-
-
-static const struct dev_pm_ops intel_mid_i2c_pm_ops = {
- .runtime_suspend = intel_mid_i2c_runtime_suspend,
- .runtime_resume = intel_mid_i2c_runtime_resume,
-};
-
-/**
- * intel_mid_i2c_probe - I2C controller initialization routine
- * @dev: pci device
- * @id: device id
- *
- * Return Values:
- * 0 success
- * -ENODEV If cannot allocate pci resource
- * -ENOMEM If the register base remapping failed, or
- * if kzalloc failed
- *
- * Initialization steps:
- * 1. Request for PCI resource
- * 2. Remap the start address of PCI resource to register base
- * 3. Request for device memory region
- * 4. Fill in the struct members of intel_mid_i2c_private
- * 5. Call intel_mid_i2c_hwinit() for hardware initialization
- * 6. Register I2C adapter in i2c-core
- */
-static int intel_mid_i2c_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- struct intel_mid_i2c_private *mrst;
- unsigned long start, len;
- int err, busnum;
- void __iomem *base = NULL;
-
- dev_dbg(&dev->dev, "Get into probe function for I2C\n");
- err = pci_enable_device(dev);
- if (err) {
- dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n",
- err);
- goto exit;
- }
-
- /* Determine the address of the I2C area */
- start = pci_resource_start(dev, 0);
- len = pci_resource_len(dev, 0);
- if (!start || len == 0) {
- dev_err(&dev->dev, "base address not set\n");
- err = -ENODEV;
- goto exit;
- }
- dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n",
- PLATFORM, start, len);
-
- err = pci_request_region(dev, 0, DRIVER_NAME);
- if (err) {
- dev_err(&dev->dev, "failed to request I2C region "
- "0x%lx-0x%lx\n", start,
- (unsigned long)pci_resource_end(dev, 0));
- goto exit;
- }
-
- base = ioremap_nocache(start, len);
- if (!base) {
- dev_err(&dev->dev, "I/O memory remapping failed\n");
- err = -ENOMEM;
- goto fail0;
- }
-
- /* Allocate the per-device data structure, intel_mid_i2c_private */
- mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL);
- if (mrst == NULL) {
- dev_err(&dev->dev, "can't allocate interface\n");
- err = -ENOMEM;
- goto fail1;
- }
-
- /* Initialize struct members */
- snprintf(mrst->adap.name, sizeof(mrst->adap.name),
- "Intel MID I2C at %lx", start);
- mrst->adap.owner = THIS_MODULE;
- mrst->adap.algo = &intel_mid_i2c_algorithm;
- mrst->adap.dev.parent = &dev->dev;
- mrst->dev = &dev->dev;
- mrst->base = base;
- mrst->speed = STANDARD;
- mrst->abort = 0;
- mrst->rx_buf_len = 0;
- mrst->status = STATUS_IDLE;
-
- pci_set_drvdata(dev, mrst);
- i2c_set_adapdata(&mrst->adap, mrst);
-
- mrst->adap.nr = busnum = id->driver_data;
- if (dev->device <= 0x0804)
- mrst->platform = MOORESTOWN;
- else
- mrst->platform = MEDFIELD;
-
- dev_dbg(&dev->dev, "I2C%d\n", busnum);
-
- if (ctl_num > busnum) {
- if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS)
- dev_warn(&dev->dev, "invalid speed %d ignored.\n",
- speed_mode[busnum]);
- else
- mrst->speed = speed_mode[busnum];
- }
-
- /* Initialize i2c controller */
- err = intel_mid_i2c_hwinit(mrst);
- if (err < 0) {
- dev_err(&dev->dev, "I2C interface initialization failed\n");
- goto fail2;
- }
-
- mutex_init(&mrst->lock);
- init_completion(&mrst->complete);
-
- /* Clear all interrupts */
- readl(mrst->base + IC_CLR_INTR);
- writel(0x0000, mrst->base + IC_INTR_MASK);
-
- err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED,
- mrst->adap.name, mrst);
- if (err) {
- dev_err(&dev->dev, "Failed to request IRQ for I2C controller: "
- "%s", mrst->adap.name);
- goto fail2;
- }
-
- /* Adapter registration */
- err = i2c_add_numbered_adapter(&mrst->adap);
- if (err) {
- dev_err(&dev->dev, "Adapter %s registration failed\n",
- mrst->adap.name);
- goto fail3;
- }
-
- dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n",
- (mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield",
- busnum);
-
- pm_runtime_enable(&dev->dev);
- return 0;
-
-fail3:
- free_irq(dev->irq, mrst);
-fail2:
- kfree(mrst);
-fail1:
- iounmap(base);
-fail0:
- pci_release_region(dev, 0);
-exit:
- return err;
-}
-
-static void intel_mid_i2c_remove(struct pci_dev *dev)
-{
- struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev);
- intel_mid_i2c_disable(&mrst->adap);
- i2c_del_adapter(&mrst->adap);
-
- free_irq(dev->irq, mrst);
- iounmap(mrst->base);
- kfree(mrst);
- pci_release_region(dev, 0);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = {
- /* Moorestown */
- { PCI_VDEVICE(INTEL, 0x0802), 0 },
- { PCI_VDEVICE(INTEL, 0x0803), 1 },
- { PCI_VDEVICE(INTEL, 0x0804), 2 },
- /* Medfield */
- { PCI_VDEVICE(INTEL, 0x0817), 3,},
- { PCI_VDEVICE(INTEL, 0x0818), 4 },
- { PCI_VDEVICE(INTEL, 0x0819), 5 },
- { PCI_VDEVICE(INTEL, 0x082C), 0 },
- { PCI_VDEVICE(INTEL, 0x082D), 1 },
- { PCI_VDEVICE(INTEL, 0x082E), 2 },
- { 0,}
-};
-MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids);
-
-static struct pci_driver intel_mid_i2c_driver = {
- .name = DRIVER_NAME,
- .id_table = intel_mid_i2c_ids,
- .probe = intel_mid_i2c_probe,
- .remove = intel_mid_i2c_remove,
-};
-
-module_pci_driver(intel_mid_i2c_driver);
-
-MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>");
-MODULE_DESCRIPTION("I2C driver for Moorestown Platform");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(VERSION);
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index bc993331c695..dd24aa0424a9 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -176,7 +176,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
interrupted = wait_event_interruptible_timeout (
iop3xx_adap->waitq,
(done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )),
- 1 * HZ;
+ 1 * HZ
);
if ((rc = iop3xx_i2c_error(sr)) < 0) {
*status = sr;
diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c
new file mode 100644
index 000000000000..ccec916bc3eb
--- /dev/null
+++ b/drivers/i2c/busses/i2c-kempld.c
@@ -0,0 +1,410 @@
+/*
+ * I2C bus driver for Kontron COM modules
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * The driver is based on the i2c-ocores driver by Peter Korsgaard.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/mfd/kempld.h>
+
+#define KEMPLD_I2C_PRELOW 0x0b
+#define KEMPLD_I2C_PREHIGH 0x0c
+#define KEMPLD_I2C_DATA 0x0e
+
+#define KEMPLD_I2C_CTRL 0x0d
+#define I2C_CTRL_IEN 0x40
+#define I2C_CTRL_EN 0x80
+
+#define KEMPLD_I2C_STAT 0x0f
+#define I2C_STAT_IF 0x01
+#define I2C_STAT_TIP 0x02
+#define I2C_STAT_ARBLOST 0x20
+#define I2C_STAT_BUSY 0x40
+#define I2C_STAT_NACK 0x80
+
+#define KEMPLD_I2C_CMD 0x0f
+#define I2C_CMD_START 0x91
+#define I2C_CMD_STOP 0x41
+#define I2C_CMD_READ 0x21
+#define I2C_CMD_WRITE 0x11
+#define I2C_CMD_READ_ACK 0x21
+#define I2C_CMD_READ_NACK 0x29
+#define I2C_CMD_IACK 0x01
+
+#define KEMPLD_I2C_FREQ_MAX 2700 /* 2.7 mHz */
+#define KEMPLD_I2C_FREQ_STD 100 /* 100 kHz */
+
+enum {
+ STATE_DONE = 0,
+ STATE_INIT,
+ STATE_ADDR,
+ STATE_ADDR10,
+ STATE_START,
+ STATE_WRITE,
+ STATE_READ,
+ STATE_ERROR,
+};
+
+struct kempld_i2c_data {
+ struct device *dev;
+ struct kempld_device_data *pld;
+ struct i2c_adapter adap;
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ int state;
+ bool was_active;
+};
+
+static unsigned int bus_frequency = KEMPLD_I2C_FREQ_STD;
+module_param(bus_frequency, uint, 0);
+MODULE_PARM_DESC(bus_frequency, "Set I2C bus frequency in kHz (default="
+ __MODULE_STRING(KEMPLD_I2C_FREQ_STD)")");
+
+static int i2c_bus = -1;
+module_param(i2c_bus, int, 0);
+MODULE_PARM_DESC(i2c_bus, "Set I2C bus number (default=-1 for dynamic assignment)");
+
+static bool i2c_gpio_mux;
+module_param(i2c_gpio_mux, bool, 0);
+MODULE_PARM_DESC(i2c_gpio_mux, "Enable I2C port on GPIO out (default=false)");
+
+/*
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static int kempld_i2c_process(struct kempld_i2c_data *i2c)
+{
+ struct kempld_device_data *pld = i2c->pld;
+ u8 stat = kempld_read8(pld, KEMPLD_I2C_STAT);
+ struct i2c_msg *msg = i2c->msg;
+ u8 addr;
+
+ /* Ready? */
+ if (stat & I2C_STAT_TIP)
+ return -EBUSY;
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
+ /* Stop has been sent */
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
+ if (i2c->state == STATE_ERROR)
+ return -EIO;
+ return 0;
+ }
+
+ /* Error? */
+ if (stat & I2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return -EAGAIN;
+ }
+
+ if (i2c->state == STATE_INIT) {
+ if (stat & I2C_STAT_BUSY)
+ return -EBUSY;
+
+ i2c->state = STATE_ADDR;
+ }
+
+ if (i2c->state == STATE_ADDR) {
+ /* 10 bit address? */
+ if (i2c->msg->flags & I2C_M_TEN) {
+ addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6);
+ i2c->state = STATE_ADDR10;
+ } else {
+ addr = (i2c->msg->addr << 1);
+ i2c->state = STATE_START;
+ }
+
+ /* Set read bit if necessary */
+ addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
+
+ kempld_write8(pld, KEMPLD_I2C_DATA, addr);
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START);
+
+ return 0;
+ }
+
+ /* Second part of 10 bit addressing */
+ if (i2c->state == STATE_ADDR10) {
+ kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff);
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
+
+ i2c->state = STATE_START;
+ return 0;
+ }
+
+ if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
+ i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & I2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return -ENXIO;
+ }
+ } else {
+ msg->buf[i2c->pos++] = kempld_read8(pld, KEMPLD_I2C_DATA);
+ }
+
+ if (i2c->pos >= msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) {
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ i2c->state = STATE_ADDR;
+ return 0;
+ } else {
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ }
+ } else {
+ i2c->state = STATE_DONE;
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return 0;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ kempld_write8(pld, KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
+ I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
+ } else {
+ kempld_write8(pld, KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE);
+ }
+
+ return 0;
+}
+
+static int kempld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct kempld_i2c_data *i2c = i2c_get_adapdata(adap);
+ struct kempld_device_data *pld = i2c->pld;
+ unsigned long timeout = jiffies + HZ;
+ int ret;
+
+ i2c->msg = msgs;
+ i2c->pos = 0;
+ i2c->nmsgs = num;
+ i2c->state = STATE_INIT;
+
+ /* Handle the transfer */
+ while (time_before(jiffies, timeout)) {
+ kempld_get_mutex(pld);
+ ret = kempld_i2c_process(i2c);
+ kempld_release_mutex(pld);
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR)
+ return (i2c->state == STATE_DONE) ? num : ret;
+
+ if (ret == 0)
+ timeout = jiffies + HZ;
+
+ usleep_range(5, 15);
+ }
+
+ i2c->state = STATE_ERROR;
+
+ return -ETIMEDOUT;
+}
+
+/*
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
+{
+ struct kempld_device_data *pld = i2c->pld;
+ u16 prescale_corr;
+ long prescale;
+ u8 ctrl;
+ u8 stat;
+ u8 cfg;
+
+ /* Make sure the device is disabled */
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+ ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+
+ if (bus_frequency > KEMPLD_I2C_FREQ_MAX)
+ bus_frequency = KEMPLD_I2C_FREQ_MAX;
+
+ if (pld->info.spec_major == 1)
+ prescale = pld->pld_clock / bus_frequency * 5 - 1000;
+ else
+ prescale = pld->pld_clock / bus_frequency * 4 - 3000;
+
+ if (prescale < 0)
+ prescale = 0;
+
+ /* Round to the best matching value */
+ prescale_corr = prescale / 1000;
+ if (prescale % 1000 >= 500)
+ prescale_corr++;
+
+ kempld_write8(pld, KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
+ kempld_write8(pld, KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
+
+ /* Activate I2C bus output on GPIO pins */
+ cfg = kempld_read8(pld, KEMPLD_CFG);
+ if (i2c_gpio_mux)
+ cfg |= KEMPLD_CFG_GPIO_I2C_MUX;
+ else
+ cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
+ kempld_write8(pld, KEMPLD_CFG, cfg);
+
+ /* Enable the device */
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK);
+ ctrl |= I2C_CTRL_EN;
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+
+ stat = kempld_read8(pld, KEMPLD_I2C_STAT);
+ if (stat & I2C_STAT_BUSY)
+ kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP);
+}
+
+static u32 kempld_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm kempld_i2c_algorithm = {
+ .master_xfer = kempld_i2c_xfer,
+ .functionality = kempld_i2c_func,
+};
+
+static struct i2c_adapter kempld_i2c_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-kempld",
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &kempld_i2c_algorithm,
+};
+
+static int kempld_i2c_probe(struct platform_device *pdev)
+{
+ struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent);
+ struct kempld_i2c_data *i2c;
+ int ret;
+ u8 ctrl;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->pld = pld;
+ i2c->dev = &pdev->dev;
+ i2c->adap = kempld_i2c_adapter;
+ i2c->adap.dev.parent = i2c->dev;
+ i2c_set_adapdata(&i2c->adap, i2c);
+ platform_set_drvdata(pdev, i2c);
+
+ kempld_get_mutex(pld);
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+
+ if (ctrl & I2C_CTRL_EN)
+ i2c->was_active = true;
+
+ kempld_i2c_device_init(i2c);
+ kempld_release_mutex(pld);
+
+ /* Add I2C adapter to I2C tree */
+ if (i2c_bus >= -1)
+ i2c->adap.nr = i2c_bus;
+ ret = i2c_add_numbered_adapter(&i2c->adap);
+ if (ret)
+ return ret;
+
+ dev_info(i2c->dev, "I2C bus initialized at %dkHz\n",
+ bus_frequency);
+
+ return 0;
+}
+
+static int kempld_i2c_remove(struct platform_device *pdev)
+{
+ struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
+ struct kempld_device_data *pld = i2c->pld;
+ u8 ctrl;
+
+ kempld_get_mutex(pld);
+ /*
+ * Disable I2C logic if it was not activated before the
+ * driver loaded
+ */
+ if (!i2c->was_active) {
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+ ctrl &= ~I2C_CTRL_EN;
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+ }
+ kempld_release_mutex(pld);
+
+ i2c_del_adapter(&i2c->adap);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
+ struct kempld_device_data *pld = i2c->pld;
+ u8 ctrl;
+
+ kempld_get_mutex(pld);
+ ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL);
+ ctrl &= ~I2C_CTRL_EN;
+ kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl);
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+
+static int kempld_i2c_resume(struct platform_device *pdev)
+{
+ struct kempld_i2c_data *i2c = platform_get_drvdata(pdev);
+ struct kempld_device_data *pld = i2c->pld;
+
+ kempld_get_mutex(pld);
+ kempld_i2c_device_init(i2c);
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+#else
+#define kempld_i2c_suspend NULL
+#define kempld_i2c_resume NULL
+#endif
+
+static struct platform_driver kempld_i2c_driver = {
+ .driver = {
+ .name = "kempld-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = kempld_i2c_probe,
+ .remove = kempld_i2c_remove,
+ .suspend = kempld_i2c_suspend,
+ .resume = kempld_i2c_resume,
+};
+
+module_platform_driver(kempld_i2c_driver);
+
+MODULE_DESCRIPTION("KEM PLD I2C Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld_i2c");
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 5e705ee02f4a..7607dc061918 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -679,7 +679,7 @@ static int fsl_i2c_probe(struct platform_device *op)
}
dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ);
- dev_set_drvdata(&op->dev, i2c);
+ platform_set_drvdata(op, i2c);
i2c->adap = mpc_ops;
i2c_set_adapdata(&i2c->adap, i2c);
@@ -707,7 +707,7 @@ static int fsl_i2c_probe(struct platform_device *op)
static int fsl_i2c_remove(struct platform_device *op)
{
- struct mpc_i2c *i2c = dev_get_drvdata(&op->dev);
+ struct mpc_i2c *i2c = platform_get_drvdata(op);
i2c_del_adapter(&i2c->adap);
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 1a3abd6a0bfc..b1f42bf40963 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -19,19 +19,15 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_i2c.h>
#include <linux/clk.h>
#include <linux/err.h>
-/* Register defines */
-#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00
-#define MV64XXX_I2C_REG_DATA 0x04
-#define MV64XXX_I2C_REG_CONTROL 0x08
-#define MV64XXX_I2C_REG_STATUS 0x0c
-#define MV64XXX_I2C_REG_BAUD 0x0c
-#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10
-#define MV64XXX_I2C_REG_SOFT_RESET 0x1c
+#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1)
+#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7)
+#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3)
#define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004
#define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008
@@ -85,15 +81,26 @@ enum {
MV64XXX_I2C_ACTION_SEND_STOP,
};
+struct mv64xxx_i2c_regs {
+ u8 addr;
+ u8 ext_addr;
+ u8 data;
+ u8 control;
+ u8 status;
+ u8 clock;
+ u8 soft_reset;
+};
+
struct mv64xxx_i2c_data {
+ struct i2c_msg *msgs;
+ int num_msgs;
int irq;
u32 state;
u32 action;
u32 aborting;
u32 cntl_bits;
void __iomem *reg_base;
- u32 reg_base_p;
- u32 reg_size;
+ struct mv64xxx_i2c_regs reg_offsets;
u32 addr1;
u32 addr2;
u32 bytes_left;
@@ -112,6 +119,52 @@ struct mv64xxx_i2c_data {
struct i2c_adapter adapter;
};
+static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
+ .addr = 0x00,
+ .ext_addr = 0x10,
+ .data = 0x04,
+ .control = 0x08,
+ .status = 0x0c,
+ .clock = 0x0c,
+ .soft_reset = 0x1c,
+};
+
+static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_sun4i = {
+ .addr = 0x00,
+ .ext_addr = 0x04,
+ .data = 0x08,
+ .control = 0x0c,
+ .status = 0x10,
+ .clock = 0x14,
+ .soft_reset = 0x18,
+};
+
+static void
+mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
+ struct i2c_msg *msg)
+{
+ u32 dir = 0;
+
+ drv_data->msg = msg;
+ drv_data->byte_posn = 0;
+ drv_data->bytes_left = msg->len;
+ drv_data->aborting = 0;
+ drv_data->rc = 0;
+ drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
+ MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
+
+ if (msg->flags & I2C_M_RD)
+ dir = 1;
+
+ if (msg->flags & I2C_M_TEN) {
+ drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
+ drv_data->addr2 = (u32)msg->addr & 0xff;
+ } else {
+ drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir;
+ drv_data->addr2 = 0;
+ }
+}
+
/*
*****************************************************************************
*
@@ -124,13 +177,13 @@ struct mv64xxx_i2c_data {
static void
mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
{
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
- writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
- drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
- writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+ writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset);
+ writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n),
+ drv_data->reg_base + drv_data->reg_offsets.clock);
+ writel(0, drv_data->reg_base + drv_data->reg_offsets.addr);
+ writel(0, drv_data->reg_base + drv_data->reg_offsets.ext_addr);
writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->state = MV64XXX_I2C_STATE_IDLE;
}
@@ -170,7 +223,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
if ((drv_data->bytes_left == 0)
|| (drv_data->aborting
&& (drv_data->byte_posn != 0))) {
- if (drv_data->send_stop) {
+ if (drv_data->send_stop || drv_data->aborting) {
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
drv_data->state = MV64XXX_I2C_STATE_IDLE;
} else {
@@ -227,7 +280,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
/* Doesn't seem to be a device at other end */
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
drv_data->state = MV64XXX_I2C_STATE_IDLE;
- drv_data->rc = -ENODEV;
+ drv_data->rc = -ENXIO;
break;
default:
@@ -247,58 +300,71 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
{
switch(drv_data->action) {
case MV64XXX_I2C_ACTION_SEND_RESTART:
+ /* We should only get here if we have further messages */
+ BUG_ON(drv_data->num_msgs == 0);
+
drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
- drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
- drv_data->block = 0;
- wake_up(&drv_data->waitq);
+ drv_data->reg_base + drv_data->reg_offsets.control);
+
+ drv_data->msgs++;
+ drv_data->num_msgs--;
+
+ /* Setup for the next message */
+ mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+
+ /*
+ * We're never at the start of the message here, and by this
+ * time it's already too late to do any protocol mangling.
+ * Thankfully, do not advertise support for that feature.
+ */
+ drv_data->send_stop = drv_data->num_msgs == 1;
break;
case MV64XXX_I2C_ACTION_CONTINUE:
writel(drv_data->cntl_bits,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_START:
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_ADDR_1:
writel(drv_data->addr1,
- drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_ADDR_2:
writel(drv_data->addr2,
- drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_SEND_DATA:
writel(drv_data->msg->buf[drv_data->byte_posn++],
- drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_RCV_DATA:
drv_data->msg->buf[drv_data->byte_posn++] =
- readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ readl(drv_data->reg_base + drv_data->reg_offsets.data);
writel(drv_data->cntl_bits,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
break;
case MV64XXX_I2C_ACTION_RCV_DATA_STOP:
drv_data->msg->buf[drv_data->byte_posn++] =
- readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA);
+ readl(drv_data->reg_base + drv_data->reg_offsets.data);
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
wake_up(&drv_data->waitq);
break;
@@ -313,7 +379,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
case MV64XXX_I2C_ACTION_SEND_STOP:
drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN;
writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP,
- drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+ drv_data->reg_base + drv_data->reg_offsets.control);
drv_data->block = 0;
wake_up(&drv_data->waitq);
break;
@@ -329,9 +395,9 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
irqreturn_t rc = IRQ_NONE;
spin_lock_irqsave(&drv_data->lock, flags);
- while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) &
+ while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
MV64XXX_I2C_REG_CONTROL_IFLG) {
- status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS);
+ status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
mv64xxx_i2c_fsm(drv_data, status);
mv64xxx_i2c_do_action(drv_data);
rc = IRQ_HANDLED;
@@ -349,32 +415,6 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
*****************************************************************************
*/
static void
-mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
- struct i2c_msg *msg)
-{
- u32 dir = 0;
-
- drv_data->msg = msg;
- drv_data->byte_posn = 0;
- drv_data->bytes_left = msg->len;
- drv_data->aborting = 0;
- drv_data->rc = 0;
- drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
- MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
-
- if (msg->flags & I2C_M_RD)
- dir = 1;
-
- if (msg->flags & I2C_M_TEN) {
- drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir;
- drv_data->addr2 = (u32)msg->addr & 0xff;
- } else {
- drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir;
- drv_data->addr2 = 0;
- }
-}
-
-static void
mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
{
long time_left;
@@ -414,36 +454,15 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
static int
mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
- int is_first, int is_last)
+ int is_last)
{
unsigned long flags;
spin_lock_irqsave(&drv_data->lock, flags);
mv64xxx_i2c_prepare_for_io(drv_data, msg);
- if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */
- if (drv_data->msg->flags & I2C_M_RD) {
- /* No action to do, wait for slave to send a byte */
- drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
- drv_data->state =
- MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
- } else {
- drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
- drv_data->state =
- MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
- drv_data->bytes_left--;
- }
- } else {
- if (is_first) {
- drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
- drv_data->state =
- MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
- } else {
- drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
- drv_data->state =
- MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
- }
- }
+ drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
+ drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
drv_data->send_stop = is_last;
drv_data->block = 1;
@@ -471,16 +490,20 @@ static int
mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap);
- int i, rc;
+ int rc, ret = num;
- for (i = 0; i < num; i++) {
- rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i],
- i == 0, i + 1 == num);
- if (rc < 0)
- return rc;
- }
+ BUG_ON(drv_data->msgs != NULL);
+ drv_data->msgs = msgs;
+ drv_data->num_msgs = num;
+
+ rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1);
+ if (rc < 0)
+ ret = rc;
+
+ drv_data->num_msgs = 0;
+ drv_data->msgs = NULL;
- return num;
+ return ret;
}
static const struct i2c_algorithm mv64xxx_i2c_algo = {
@@ -495,39 +518,12 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
*
*****************************************************************************
*/
-static int
-mv64xxx_i2c_map_regs(struct platform_device *pd,
- struct mv64xxx_i2c_data *drv_data)
-{
- int size;
- struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0);
-
- if (!r)
- return -ENODEV;
-
- size = resource_size(r);
-
- if (!request_mem_region(r->start, size, drv_data->adapter.name))
- return -EBUSY;
-
- drv_data->reg_base = ioremap(r->start, size);
- drv_data->reg_base_p = r->start;
- drv_data->reg_size = size;
-
- return 0;
-}
-
-static void
-mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
-{
- if (drv_data->reg_base) {
- iounmap(drv_data->reg_base);
- release_mem_region(drv_data->reg_base_p, drv_data->reg_size);
- }
-
- drv_data->reg_base = NULL;
- drv_data->reg_base_p = 0;
-}
+static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
+ { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
+ { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
+ {}
+};
+MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
#ifdef CONFIG_OF
static int
@@ -562,8 +558,10 @@ mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
- struct device_node *np)
+ struct device *dev)
{
+ const struct of_device_id *device;
+ struct device_node *np = dev->of_node;
u32 bus_freq, tclk;
int rc = 0;
@@ -580,7 +578,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
goto out;
}
tclk = clk_get_rate(drv_data->clk);
- of_property_read_u32(np, "clock-frequency", &bus_freq);
+
+ rc = of_property_read_u32(np, "clock-frequency", &bus_freq);
+ if (rc)
+ bus_freq = 100000; /* 100kHz by default */
+
if (!mv64xxx_find_baud_factors(bus_freq, tclk,
&drv_data->freq_n, &drv_data->freq_m)) {
rc = -EINVAL;
@@ -592,6 +594,13 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
* So hard code the value to 1 second.
*/
drv_data->adapter.timeout = HZ;
+
+ device = of_match_device(mv64xxx_i2c_of_match_table, dev);
+ if (!device)
+ return -ENODEV;
+
+ memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets));
+
out:
return rc;
#endif
@@ -599,7 +608,7 @@ out:
#else /* CONFIG_OF */
static int
mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
- struct device_node *np)
+ struct device *dev)
{
return -ENODEV;
}
@@ -610,19 +619,21 @@ mv64xxx_i2c_probe(struct platform_device *pd)
{
struct mv64xxx_i2c_data *drv_data;
struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data;
+ struct resource *r;
int rc;
if ((!pdata && !pd->dev.of_node))
return -ENODEV;
- drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL);
+ drv_data = devm_kzalloc(&pd->dev, sizeof(struct mv64xxx_i2c_data),
+ GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
- if (mv64xxx_i2c_map_regs(pd, drv_data)) {
- rc = -ENODEV;
- goto exit_kfree;
- }
+ r = platform_get_resource(pd, IORESOURCE_MEM, 0);
+ drv_data->reg_base = devm_ioremap_resource(&pd->dev, r);
+ if (IS_ERR(drv_data->reg_base))
+ return PTR_ERR(drv_data->reg_base);
strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
sizeof(drv_data->adapter.name));
@@ -632,7 +643,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
- drv_data->clk = clk_get(&pd->dev, NULL);
+ drv_data->clk = devm_clk_get(&pd->dev, NULL);
if (!IS_ERR(drv_data->clk)) {
clk_prepare(drv_data->clk);
clk_enable(drv_data->clk);
@@ -643,14 +654,15 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->freq_n = pdata->freq_n;
drv_data->irq = platform_get_irq(pd, 0);
drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout);
+ memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets));
} else if (pd->dev.of_node) {
- rc = mv64xxx_of_config(drv_data, pd->dev.of_node);
+ rc = mv64xxx_of_config(drv_data, &pd->dev);
if (rc)
- goto exit_unmap_regs;
+ goto exit_clk;
}
if (drv_data->irq < 0) {
rc = -ENXIO;
- goto exit_unmap_regs;
+ goto exit_clk;
}
drv_data->adapter.dev.parent = &pd->dev;
@@ -664,13 +676,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
mv64xxx_i2c_hw_init(drv_data);
- if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
- MV64XXX_I2C_CTLR_NAME, drv_data)) {
+ rc = request_irq(drv_data->irq, mv64xxx_i2c_intr, 0,
+ MV64XXX_I2C_CTLR_NAME, drv_data);
+ if (rc) {
dev_err(&drv_data->adapter.dev,
- "mv64xxx: Can't register intr handler irq: %d\n",
- drv_data->irq);
- rc = -EINVAL;
- goto exit_unmap_regs;
+ "mv64xxx: Can't register intr handler irq%d: %d\n",
+ drv_data->irq, rc);
+ goto exit_clk;
} else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
@@ -681,9 +693,9 @@ mv64xxx_i2c_probe(struct platform_device *pd)
return 0;
- exit_free_irq:
- free_irq(drv_data->irq, drv_data);
- exit_unmap_regs:
+exit_free_irq:
+ free_irq(drv_data->irq, drv_data);
+exit_clk:
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
@@ -691,9 +703,6 @@ mv64xxx_i2c_probe(struct platform_device *pd)
clk_unprepare(drv_data->clk);
}
#endif
- mv64xxx_i2c_unmap_regs(drv_data);
- exit_kfree:
- kfree(drv_data);
return rc;
}
@@ -704,7 +713,6 @@ mv64xxx_i2c_remove(struct platform_device *dev)
i2c_del_adapter(&drv_data->adapter);
free_irq(drv_data->irq, drv_data);
- mv64xxx_i2c_unmap_regs(drv_data);
#if defined(CONFIG_HAVE_CLK)
/* Not all platforms have a clk */
if (!IS_ERR(drv_data->clk)) {
@@ -712,17 +720,10 @@ mv64xxx_i2c_remove(struct platform_device *dev)
clk_unprepare(drv_data->clk);
}
#endif
- kfree(drv_data);
return 0;
}
-static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
- { .compatible = "marvell,mv64xxx-i2c", },
- {}
-};
-MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
-
static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe,
.remove = mv64xxx_i2c_remove,
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 2039f230482d..df8ff5aea5b5 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -24,7 +24,6 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/io.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/stmp_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
@@ -638,15 +637,10 @@ static int mxs_i2c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
- struct pinctrl *pinctrl;
struct resource *res;
resource_size_t res_size;
int err, irq;
- pinctrl = devm_pinctrl_get_select_default(dev);
- if (IS_ERR(pinctrl))
- return PTR_ERR(pinctrl);
-
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 650293ff4d62..512dfe609706 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/amba/bus.h>
-#include <linux/atomic.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
@@ -106,6 +105,16 @@
/* maximum threshold value */
#define MAX_I2C_FIFO_THRESHOLD 15
+/**
+ * struct i2c_vendor_data - per-vendor variations
+ * @has_mtdws: variant has the MTDWS bit
+ * @fifodepth: variant FIFO depth
+ */
+struct i2c_vendor_data {
+ bool has_mtdws;
+ u32 fifodepth;
+};
+
enum i2c_status {
I2C_NOP,
I2C_ON_GOING,
@@ -138,6 +147,7 @@ struct i2c_nmk_client {
/**
* struct nmk_i2c_dev - private data structure of the controller.
+ * @vendor: vendor data for this variant.
* @adev: parent amba device.
* @adap: corresponding I2C adapter.
* @irq: interrupt line for the controller.
@@ -148,13 +158,10 @@ struct i2c_nmk_client {
* @stop: stop condition.
* @xfer_complete: acknowledge completion for a I2C message.
* @result: controller propogated result.
- * @pinctrl: pinctrl handle.
- * @pins_default: default state for the pins.
- * @pins_idle: idle state for the pins.
- * @pins_sleep: sleep state for the pins.
* @busy: Busy doing transfer.
*/
struct nmk_i2c_dev {
+ struct i2c_vendor_data *vendor;
struct amba_device *adev;
struct i2c_adapter adap;
int irq;
@@ -165,11 +172,6 @@ struct nmk_i2c_dev {
int stop;
struct completion xfer_complete;
int result;
- /* Three pin states - default, idle & sleep */
- struct pinctrl *pinctrl;
- struct pinctrl_state *pins_default;
- struct pinctrl_state *pins_idle;
- struct pinctrl_state *pins_sleep;
bool busy;
};
@@ -431,7 +433,7 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
I2C_IT_MAL | I2C_IT_BERR);
- if (dev->stop)
+ if (dev->stop || !dev->vendor->has_mtdws)
irq_mask |= I2C_IT_MTD;
else
irq_mask |= I2C_IT_MTDWS;
@@ -511,7 +513,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
* set the MTDWS bit (Master Transaction Done Without Stop)
* to start repeated start operation
*/
- if (dev->stop)
+ if (dev->stop || !dev->vendor->has_mtdws)
irq_mask |= I2C_IT_MTD;
else
irq_mask |= I2C_IT_MTDWS;
@@ -645,13 +647,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
}
/* Optionaly enable pins to be muxed in and configured */
- if (!IS_ERR(dev->pins_default)) {
- status = pinctrl_select_state(dev->pinctrl,
- dev->pins_default);
- if (status)
- dev_err(&dev->adev->dev,
- "could not set default pins\n");
- }
+ pinctrl_pm_select_default_state(&dev->adev->dev);
status = init_hw(dev);
if (status)
@@ -681,13 +677,7 @@ out:
clk_disable_unprepare(dev->clk);
out_clk:
/* Optionally let pins go into idle state */
- if (!IS_ERR(dev->pins_idle)) {
- status = pinctrl_select_state(dev->pinctrl,
- dev->pins_idle);
- if (status)
- dev_err(&dev->adev->dev,
- "could not set pins to idle state\n");
- }
+ pinctrl_pm_select_idle_state(&dev->adev->dev);
pm_runtime_put_sync(&dev->adev->dev);
@@ -882,41 +872,22 @@ static int nmk_i2c_suspend(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
- int ret;
if (nmk_i2c->busy)
return -EBUSY;
- if (!IS_ERR(nmk_i2c->pins_sleep)) {
- ret = pinctrl_select_state(nmk_i2c->pinctrl,
- nmk_i2c->pins_sleep);
- if (ret)
- dev_err(dev, "could not set pins to sleep state\n");
- }
+ pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int nmk_i2c_resume(struct device *dev)
{
- struct amba_device *adev = to_amba_device(dev);
- struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
- int ret;
-
/* First go to the default state */
- if (!IS_ERR(nmk_i2c->pins_default)) {
- ret = pinctrl_select_state(nmk_i2c->pinctrl,
- nmk_i2c->pins_default);
- if (ret)
- dev_err(dev, "could not set pins to default state\n");
- }
+ pinctrl_pm_select_default_state(dev);
/* Then let's idle the pins until the next transfer happens */
- if (!IS_ERR(nmk_i2c->pins_idle)) {
- ret = pinctrl_select_state(nmk_i2c->pinctrl,
- nmk_i2c->pins_idle);
- if (ret)
- dev_err(dev, "could not set pins to idle state\n");
- }
+ pinctrl_pm_select_idle_state(dev);
+
return 0;
}
#else
@@ -969,8 +940,6 @@ static void nmk_i2c_of_probe(struct device_node *np,
pdata->sm = I2C_FREQ_MODE_FAST;
}
-static atomic_t adapter_id = ATOMIC_INIT(0);
-
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
{
int ret = 0;
@@ -978,6 +947,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
struct device_node *np = adev->dev.of_node;
struct nmk_i2c_dev *dev;
struct i2c_adapter *adap;
+ struct i2c_vendor_data *vendor = id->data;
+ u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
if (!pdata) {
if (np) {
@@ -994,49 +965,33 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
pdata = &u8500_i2c;
}
+ if (pdata->tft > max_fifo_threshold) {
+ dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
+ pdata->tft, max_fifo_threshold);
+ pdata->tft = max_fifo_threshold;
+ }
+
+ if (pdata->rft > max_fifo_threshold) {
+ dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
+ pdata->rft, max_fifo_threshold);
+ pdata->rft = max_fifo_threshold;
+ }
+
dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
if (!dev) {
dev_err(&adev->dev, "cannot allocate memory\n");
ret = -ENOMEM;
goto err_no_mem;
}
+ dev->vendor = vendor;
dev->busy = false;
dev->adev = adev;
amba_set_drvdata(adev, dev);
- dev->pinctrl = devm_pinctrl_get(&adev->dev);
- if (IS_ERR(dev->pinctrl)) {
- ret = PTR_ERR(dev->pinctrl);
- goto err_pinctrl;
- }
-
- dev->pins_default = pinctrl_lookup_state(dev->pinctrl,
- PINCTRL_STATE_DEFAULT);
- if (IS_ERR(dev->pins_default)) {
- dev_err(&adev->dev, "could not get default pinstate\n");
- } else {
- ret = pinctrl_select_state(dev->pinctrl,
- dev->pins_default);
- if (ret)
- dev_dbg(&adev->dev, "could not set default pinstate\n");
- }
-
- dev->pins_idle = pinctrl_lookup_state(dev->pinctrl,
- PINCTRL_STATE_IDLE);
- if (IS_ERR(dev->pins_idle)) {
- dev_dbg(&adev->dev, "could not get idle pinstate\n");
- } else {
- /* If possible, let's go to idle until the first transfer */
- ret = pinctrl_select_state(dev->pinctrl,
- dev->pins_idle);
- if (ret)
- dev_dbg(&adev->dev, "could not set idle pinstate\n");
- }
-
- dev->pins_sleep = pinctrl_lookup_state(dev->pinctrl,
- PINCTRL_STATE_SLEEP);
- if (IS_ERR(dev->pins_sleep))
- dev_dbg(&adev->dev, "could not get sleep pinstate\n");
+ /* Select default pin state */
+ pinctrl_pm_select_default_state(&adev->dev);
+ /* If possible, let's go to idle until the first transfer */
+ pinctrl_pm_select_idle_state(&adev->dev);
dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
if (!dev->virtbase) {
@@ -1068,10 +1023,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->algo = &nmk_i2c_algo;
adap->timeout = msecs_to_jiffies(pdata->timeout);
- adap->nr = atomic_read(&adapter_id);
snprintf(adap->name, sizeof(adap->name),
- "Nomadik I2C%d at %pR", adap->nr, &adev->res);
- atomic_inc(&adapter_id);
+ "Nomadik I2C at %pR", &adev->res);
/* fetch the controller configuration from machine */
dev->cfg.clk_freq = pdata->clk_freq;
@@ -1086,7 +1039,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
"initialize %s on virtual base %p\n",
adap->name, dev->virtbase);
- ret = i2c_add_numbered_adapter(adap);
+ ret = i2c_add_adapter(adap);
if (ret) {
dev_err(&adev->dev, "failed to add adapter\n");
goto err_add_adap;
@@ -1106,7 +1059,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
iounmap(dev->virtbase);
err_no_ioremap:
kfree(dev);
- err_pinctrl:
err_no_mem:
return ret;
@@ -1134,14 +1086,26 @@ static int nmk_i2c_remove(struct amba_device *adev)
return 0;
}
+static struct i2c_vendor_data vendor_stn8815 = {
+ .has_mtdws = false,
+ .fifodepth = 16, /* Guessed from TFTR/RFTR = 7 */
+};
+
+static struct i2c_vendor_data vendor_db8500 = {
+ .has_mtdws = true,
+ .fifodepth = 32, /* Guessed from TFTR/RFTR = 15 */
+};
+
static struct amba_id nmk_i2c_ids[] = {
{
.id = 0x00180024,
.mask = 0x00ffffff,
+ .data = &vendor_stn8815,
},
{
.id = 0x00380024,
.mask = 0x00ffffff,
+ .data = &vendor_db8500,
},
{},
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index e02f9e36a7b2..142b694d1c60 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -180,6 +180,8 @@ enum {
#define I2C_OMAP_ERRATA_I207 (1 << 0)
#define I2C_OMAP_ERRATA_I462 (1 << 1)
+#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF
+
struct omap_i2c_dev {
spinlock_t lock; /* IRQ synchronization */
struct device *dev;
@@ -193,6 +195,7 @@ struct omap_i2c_dev {
long latency);
u32 speed; /* Speed of bus in kHz */
u32 flags;
+ u16 scheme;
u16 cmd_err;
u8 *buf;
u8 *regs;
@@ -1082,14 +1085,7 @@ omap_i2c_probe(struct platform_device *pdev)
int irq;
int r;
u32 rev;
- u16 minor, major, scheme;
-
- /* NOTE: driver uses the static register mapping */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "no mem resource?\n");
- return -ENODEV;
- }
+ u16 minor, major;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -1103,6 +1099,7 @@ omap_i2c_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->base = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
@@ -1159,8 +1156,8 @@ omap_i2c_probe(struct platform_device *pdev)
*/
rev = __raw_readw(dev->base + 0x04);
- scheme = OMAP_I2C_SCHEME(rev);
- switch (scheme) {
+ dev->scheme = OMAP_I2C_SCHEME(rev);
+ switch (dev->scheme) {
case OMAP_I2C_SCHEME_0:
dev->regs = (u8 *)reg_map_ip_v1;
dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG);
@@ -1289,7 +1286,11 @@ static int omap_i2c_runtime_suspend(struct device *dev)
_dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG);
- omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
+ if (_dev->scheme == OMAP_I2C_SCHEME_0)
+ omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0);
+ else
+ omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR,
+ OMAP_I2C_IP_V2_INTERRUPTS_MASK);
if (_dev->rev < OMAP_I2C_OMAP1_REV_2) {
omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 39ab78c1a02c..d05ad590af29 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -22,7 +22,7 @@
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
- AMD Hudson-2
+ AMD Hudson-2, CZ
SMSC Victory66
Note: we assume there can only be one device, with one or more
@@ -522,6 +522,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x790b) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4) },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS,
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index ea6d45d1dcd6..fbafed29fb81 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1160,7 +1160,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.class = plat->class;
}
- clk_enable(i2c->clk);
+ clk_prepare_enable(i2c->clk);
if (i2c->use_pio) {
i2c->adap.algo = &i2c_pxa_pio_algorithm;
@@ -1202,7 +1202,7 @@ eadapt:
if (!i2c->use_pio)
free_irq(irq, i2c);
ereqirq:
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
iounmap(i2c->reg_base);
eremap:
clk_put(i2c->clk);
@@ -1221,7 +1221,7 @@ static int i2c_pxa_remove(struct platform_device *dev)
if (!i2c->use_pio)
free_irq(i2c->irq, i2c);
- clk_disable(i2c->clk);
+ clk_disable_unprepare(i2c->clk);
clk_put(i2c->clk);
iounmap(i2c->reg_base);
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 4ba4a95b6b26..0fc585861610 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -623,12 +623,6 @@ static int rcar_i2c_probe(struct platform_device *pdev)
u32 bus_speed;
int ret;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no mmio resources\n");
- return -ENODEV;
- }
-
priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
if (!priv) {
dev_err(dev, "no mem for private data\n");
@@ -642,6 +636,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->io))
return PTR_ERR(priv->io);
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
new file mode 100644
index 000000000000..baaa7d15b73e
--- /dev/null
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -0,0 +1,479 @@
+/*
+ * Wondermedia I2C Master Mode Driver
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * Derived from GPLv2+ licensed source:
+ * - Copyright (C) 2008 WonderMedia Technologies, 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, or
+ * (at your option) any later version. as published by the Free Software
+ * Foundation
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_i2c.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define REG_CR 0x00
+#define REG_TCR 0x02
+#define REG_CSR 0x04
+#define REG_ISR 0x06
+#define REG_IMR 0x08
+#define REG_CDR 0x0A
+#define REG_TR 0x0C
+#define REG_MCR 0x0E
+#define REG_SLAVE_CR 0x10
+#define REG_SLAVE_SR 0x12
+#define REG_SLAVE_ISR 0x14
+#define REG_SLAVE_IMR 0x16
+#define REG_SLAVE_DR 0x18
+#define REG_SLAVE_TR 0x1A
+
+/* REG_CR Bit fields */
+#define CR_TX_NEXT_ACK 0x0000
+#define CR_ENABLE 0x0001
+#define CR_TX_NEXT_NO_ACK 0x0002
+#define CR_TX_END 0x0004
+#define CR_CPU_RDY 0x0008
+#define SLAV_MODE_SEL 0x8000
+
+/* REG_TCR Bit fields */
+#define TCR_STANDARD_MODE 0x0000
+#define TCR_MASTER_WRITE 0x0000
+#define TCR_HS_MODE 0x2000
+#define TCR_MASTER_READ 0x4000
+#define TCR_FAST_MODE 0x8000
+#define TCR_SLAVE_ADDR_MASK 0x007F
+
+/* REG_ISR Bit fields */
+#define ISR_NACK_ADDR 0x0001
+#define ISR_BYTE_END 0x0002
+#define ISR_SCL_TIMEOUT 0x0004
+#define ISR_WRITE_ALL 0x0007
+
+/* REG_IMR Bit fields */
+#define IMR_ENABLE_ALL 0x0007
+
+/* REG_CSR Bit fields */
+#define CSR_RCV_NOT_ACK 0x0001
+#define CSR_RCV_ACK_MASK 0x0001
+#define CSR_READY_MASK 0x0002
+
+/* REG_TR */
+#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8)
+#define TR_STD 0x0064
+#define TR_HS 0x0019
+
+/* REG_MCR */
+#define MCR_APB_96M 7
+#define MCR_APB_166M 12
+
+#define I2C_MODE_STANDARD 0
+#define I2C_MODE_FAST 1
+
+#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+struct wmt_i2c_dev {
+ struct i2c_adapter adapter;
+ struct completion complete;
+ struct device *dev;
+ void __iomem *base;
+ struct clk *clk;
+ int mode;
+ int irq;
+ u16 cmd_status;
+};
+
+static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + WMT_I2C_TIMEOUT;
+ while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n");
+ return -EBUSY;
+ }
+ msleep(20);
+ }
+
+ return 0;
+}
+
+static int wmt_check_status(struct wmt_i2c_dev *i2c_dev)
+{
+ int ret = 0;
+
+ if (i2c_dev->cmd_status & ISR_NACK_ADDR)
+ ret = -EIO;
+
+ if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT)
+ ret = -ETIMEDOUT;
+
+ return ret;
+}
+
+static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+ int last)
+{
+ struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ u16 val, tcr_val;
+ int ret, wait_result;
+ int xfer_len = 0;
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (pmsg->len == 0) {
+ /*
+ * We still need to run through the while (..) once, so
+ * start at -1 and break out early from the loop
+ */
+ xfer_len = -1;
+ writew(0, i2c_dev->base + REG_CDR);
+ } else {
+ writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR);
+ }
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ val = readw(i2c_dev->base + REG_CR);
+ val &= ~CR_TX_END;
+ writew(val, i2c_dev->base + REG_CR);
+
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ INIT_COMPLETION(i2c_dev->complete);
+
+ if (i2c_dev->mode == I2C_MODE_STANDARD)
+ tcr_val = TCR_STANDARD_MODE;
+ else
+ tcr_val = TCR_FAST_MODE;
+
+ tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK));
+
+ writew(tcr_val, i2c_dev->base + REG_TCR);
+
+ if (pmsg->flags & I2C_M_NOSTART) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ while (xfer_len < pmsg->len) {
+ wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+ 500 * HZ / 1000);
+
+ if (wait_result == 0)
+ return -ETIMEDOUT;
+
+ ret = wmt_check_status(i2c_dev);
+ if (ret)
+ return ret;
+
+ xfer_len++;
+
+ val = readw(i2c_dev->base + REG_CSR);
+ if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) {
+ dev_dbg(i2c_dev->dev, "write RCV NACK error\n");
+ return -EIO;
+ }
+
+ if (pmsg->len == 0) {
+ val = CR_TX_END | CR_CPU_RDY | CR_ENABLE;
+ writew(val, i2c_dev->base + REG_CR);
+ break;
+ }
+
+ if (xfer_len == pmsg->len) {
+ if (last != 1)
+ writew(CR_ENABLE, i2c_dev->base + REG_CR);
+ } else {
+ writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base +
+ REG_CDR);
+ writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR);
+ }
+ }
+
+ return 0;
+}
+
+static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
+ int last)
+{
+ struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
+ u16 val, tcr_val;
+ int ret, wait_result;
+ u32 xfer_len = 0;
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ ret = wmt_i2c_wait_bus_not_busy(i2c_dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ val = readw(i2c_dev->base + REG_CR);
+ val &= ~CR_TX_END;
+ writew(val, i2c_dev->base + REG_CR);
+
+ val = readw(i2c_dev->base + REG_CR);
+ val &= ~CR_TX_NEXT_NO_ACK;
+ writew(val, i2c_dev->base + REG_CR);
+
+ if (!(pmsg->flags & I2C_M_NOSTART)) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ if (pmsg->len == 1) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_TX_NEXT_NO_ACK;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ INIT_COMPLETION(i2c_dev->complete);
+
+ if (i2c_dev->mode == I2C_MODE_STANDARD)
+ tcr_val = TCR_STANDARD_MODE;
+ else
+ tcr_val = TCR_FAST_MODE;
+
+ tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK);
+
+ writew(tcr_val, i2c_dev->base + REG_TCR);
+
+ if (pmsg->flags & I2C_M_NOSTART) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+
+ while (xfer_len < pmsg->len) {
+ wait_result = wait_for_completion_timeout(&i2c_dev->complete,
+ 500 * HZ / 1000);
+
+ if (!wait_result)
+ return -ETIMEDOUT;
+
+ ret = wmt_check_status(i2c_dev);
+ if (ret)
+ return ret;
+
+ pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8;
+ xfer_len++;
+
+ if (xfer_len == pmsg->len - 1) {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY);
+ writew(val, i2c_dev->base + REG_CR);
+ } else {
+ val = readw(i2c_dev->base + REG_CR);
+ val |= CR_CPU_RDY;
+ writew(val, i2c_dev->base + REG_CR);
+ }
+ }
+
+ return 0;
+}
+
+static int wmt_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct i2c_msg *pmsg;
+ int i, is_last;
+ int ret = 0;
+
+ for (i = 0; ret >= 0 && i < num; i++) {
+ is_last = ((i + 1) == num);
+
+ pmsg = &msgs[i];
+ if (pmsg->flags & I2C_M_RD)
+ ret = wmt_i2c_read(adap, pmsg, is_last);
+ else
+ ret = wmt_i2c_write(adap, pmsg, is_last);
+ }
+
+ return (ret < 0) ? ret : i;
+}
+
+static u32 wmt_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm wmt_i2c_algo = {
+ .master_xfer = wmt_i2c_xfer,
+ .functionality = wmt_i2c_func,
+};
+
+static irqreturn_t wmt_i2c_isr(int irq, void *data)
+{
+ struct wmt_i2c_dev *i2c_dev = data;
+
+ /* save the status and write-clear it */
+ i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR);
+ writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR);
+
+ complete(&i2c_dev->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev)
+{
+ int err;
+
+ err = clk_prepare_enable(i2c_dev->clk);
+ if (err) {
+ dev_err(i2c_dev->dev, "failed to enable clock\n");
+ return err;
+ }
+
+ err = clk_set_rate(i2c_dev->clk, 20000000);
+ if (err) {
+ dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n");
+ return err;
+ }
+
+ writew(0, i2c_dev->base + REG_CR);
+ writew(MCR_APB_166M, i2c_dev->base + REG_MCR);
+ writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+ writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR);
+ writew(CR_ENABLE, i2c_dev->base + REG_CR);
+ readw(i2c_dev->base + REG_CSR); /* read clear */
+ writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR);
+
+ if (i2c_dev->mode == I2C_MODE_STANDARD)
+ writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR);
+ else
+ writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR);
+
+ return 0;
+}
+
+static int wmt_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct wmt_i2c_dev *i2c_dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int err;
+ u32 clk_rate;
+
+ i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
+ if (!i2c_dev) {
+ dev_err(&pdev->dev, "device memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(i2c_dev->base))
+ return PTR_ERR(i2c_dev->base);
+
+ i2c_dev->irq = irq_of_parse_and_map(np, 0);
+ if (!i2c_dev->irq) {
+ dev_err(&pdev->dev, "irq missing or invalid\n");
+ return -EINVAL;
+ }
+
+ i2c_dev->clk = of_clk_get(np, 0);
+ if (IS_ERR(i2c_dev->clk)) {
+ dev_err(&pdev->dev, "unable to request clock\n");
+ return PTR_ERR(i2c_dev->clk);
+ }
+
+ i2c_dev->mode = I2C_MODE_STANDARD;
+ err = of_property_read_u32(np, "clock-frequency", &clk_rate);
+ if ((!err) && (clk_rate == 400000))
+ i2c_dev->mode = I2C_MODE_FAST;
+
+ i2c_dev->dev = &pdev->dev;
+
+ err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0,
+ "i2c", i2c_dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq);
+ return err;
+ }
+
+ adap = &i2c_dev->adapter;
+ i2c_set_adapdata(adap, i2c_dev);
+ strlcpy(adap->name, "WMT I2C adapter", sizeof(adap->name));
+ adap->owner = THIS_MODULE;
+ adap->algo = &wmt_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ init_completion(&i2c_dev->complete);
+
+ err = wmt_i2c_reset_hardware(i2c_dev);
+ if (err) {
+ dev_err(&pdev->dev, "error initializing hardware\n");
+ return err;
+ }
+
+ err = i2c_add_adapter(adap);
+ if (err) {
+ dev_err(&pdev->dev, "failed to add adapter\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, i2c_dev);
+
+ of_i2c_register_devices(adap);
+
+ return 0;
+}
+
+static int wmt_i2c_remove(struct platform_device *pdev)
+{
+ struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+
+ /* Disable interrupts, clock and delete adapter */
+ writew(0, i2c_dev->base + REG_IMR);
+ clk_disable_unprepare(i2c_dev->clk);
+ i2c_del_adapter(&i2c_dev->adapter);
+
+ return 0;
+}
+
+static struct of_device_id wmt_i2c_dt_ids[] = {
+ { .compatible = "wm,wm8505-i2c" },
+ { /* Sentinel */ },
+};
+
+static struct platform_driver wmt_i2c_driver = {
+ .probe = wmt_i2c_probe,
+ .remove = wmt_i2c_remove,
+ .driver = {
+ .name = "wmt-i2c",
+ .owner = THIS_MODULE,
+ .of_match_table = wmt_i2c_dt_ids,
+ },
+};
+
+module_platform_driver(wmt_i2c_driver);
+
+MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 48e31ed69dbf..f32ca293ae0e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -435,7 +435,7 @@ static const struct dev_pm_ops i2c_device_pm_ops = {
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
- pm_generic_runtime_idle
+ NULL
)
};
diff --git a/drivers/ide/delkin_cb.c b/drivers/ide/delkin_cb.c
index 7e27d3295e55..300daabaa575 100644
--- a/drivers/ide/delkin_cb.c
+++ b/drivers/ide/delkin_cb.c
@@ -173,18 +173,7 @@ static struct pci_driver delkin_cb_pci_driver = {
.resume = delkin_cb_resume,
};
-static int __init delkin_cb_init(void)
-{
- return pci_register_driver(&delkin_cb_pci_driver);
-}
-
-static void __exit delkin_cb_exit(void)
-{
- pci_unregister_driver(&delkin_cb_pci_driver);
-}
-
-module_init(delkin_cb_init);
-module_exit(delkin_cb_exit);
+module_pci_driver(delkin_cb_pci_driver);
MODULE_AUTHOR("Mark Lord");
MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c
index 51beb85250d4..0a8440ae0565 100644
--- a/drivers/ide/gayle.c
+++ b/drivers/ide/gayle.c
@@ -183,20 +183,7 @@ static struct platform_driver amiga_gayle_ide_driver = {
},
};
-static int __init amiga_gayle_ide_init(void)
-{
- return platform_driver_probe(&amiga_gayle_ide_driver,
- amiga_gayle_ide_probe);
-}
-
-module_init(amiga_gayle_ide_init);
-
-static void __exit amiga_gayle_ide_exit(void)
-{
- platform_driver_unregister(&amiga_gayle_ide_driver);
-}
-
-module_exit(amiga_gayle_ide_exit);
+module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:amiga-gayle-ide");
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 2ff620444930..0b510bafd90e 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1756,7 +1756,7 @@ static int ide_cd_probe(ide_drive_t *drive)
info->dev.parent = &drive->gendev;
info->dev.release = ide_cd_release;
- dev_set_name(&info->dev, dev_name(&drive->gendev));
+ dev_set_name(&info->dev, "%s", dev_name(&drive->gendev));
if (device_register(&info->dev))
goto out_free_disk;
diff --git a/drivers/ide/ide-gd.c b/drivers/ide/ide-gd.c
index de86631e767d..838996a0039e 100644
--- a/drivers/ide/ide-gd.c
+++ b/drivers/ide/ide-gd.c
@@ -392,7 +392,7 @@ static int ide_gd_probe(ide_drive_t *drive)
idkp->dev.parent = &drive->gendev;
idkp->dev.release = ide_disk_release;
- dev_set_name(&idkp->dev, dev_name(&drive->gendev));
+ dev_set_name(&idkp->dev, "%s", dev_name(&drive->gendev));
if (device_register(&idkp->dev))
goto out_free_disk;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 068cef0a987a..2a744a91370e 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -545,7 +545,7 @@ static int ide_register_port(ide_hwif_t *hwif)
int ret;
/* register with global device tree */
- dev_set_name(&hwif->gendev, hwif->name);
+ dev_set_name(&hwif->gendev, "%s", hwif->name);
dev_set_drvdata(&hwif->gendev, hwif);
if (hwif->gendev.parent == NULL)
hwif->gendev.parent = hwif->dev;
@@ -559,7 +559,7 @@ static int ide_register_port(ide_hwif_t *hwif)
}
hwif->portdev = device_create(ide_port_class, &hwif->gendev,
- MKDEV(0, 0), hwif, hwif->name);
+ MKDEV(0, 0), hwif, "%s", hwif->name);
if (IS_ERR(hwif->portdev)) {
ret = PTR_ERR(hwif->portdev);
device_unregister(&hwif->gendev);
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index c6c574bd5f59..1793aea4a7d2 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1985,7 +1985,7 @@ static int ide_tape_probe(ide_drive_t *drive)
tape->dev.parent = &drive->gendev;
tape->dev.release = ide_tape_release;
- dev_set_name(&tape->dev, dev_name(&drive->gendev));
+ dev_set_name(&tape->dev, "%s", dev_name(&drive->gendev));
if (device_register(&tape->dev))
goto out_free_disk;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 729428edeba2..dabb88b1cbec 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -239,9 +239,6 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
int page_is_high;
- if (nr_bytes > PAGE_SIZE)
- nr_bytes = PAGE_SIZE;
-
page = sg_page(cursg);
offset = cursg->offset + cmd->cursg_ofs;
@@ -249,6 +246,8 @@ void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
page = nth_page(page, (offset >> PAGE_SHIFT));
offset %= PAGE_SIZE;
+ nr_bytes = min_t(unsigned, nr_bytes, (PAGE_SIZE - offset));
+
page_is_high = PageHighMem(page);
if (page_is_high)
local_irq_save(flags);
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index 91d49dd957ef..ede8575ac7d5 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -203,18 +203,7 @@ static struct platform_driver tx4938ide_driver = {
.remove = __exit_p(tx4938ide_remove),
};
-static int __init tx4938ide_init(void)
-{
- return platform_driver_probe(&tx4938ide_driver, tx4938ide_probe);
-}
-
-static void __exit tx4938ide_exit(void)
-{
- platform_driver_unregister(&tx4938ide_driver);
-}
-
-module_init(tx4938ide_init);
-module_exit(tx4938ide_exit);
+module_platform_driver_probe(tx4938ide_driver, tx4938ide_probe);
MODULE_DESCRIPTION("TX4938 internal IDE driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
index c0ab800b7bb3..4ecdee5eca83 100644
--- a/drivers/ide/tx4939ide.c
+++ b/drivers/ide/tx4939ide.c
@@ -624,18 +624,7 @@ static struct platform_driver tx4939ide_driver = {
.resume = tx4939ide_resume,
};
-static int __init tx4939ide_init(void)
-{
- return platform_driver_probe(&tx4939ide_driver, tx4939ide_probe);
-}
-
-static void __exit tx4939ide_exit(void)
-{
- platform_driver_unregister(&tx4939ide_driver);
-}
-
-module_init(tx4939ide_init);
-module_exit(tx4939ide_exit);
+module_platform_driver_probe(tx4939ide_driver, tx4939ide_probe);
MODULE_DESCRIPTION("TX4939 internal IDE driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index 5f9a7e7d3135..4427e8e46a7f 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -22,13 +22,18 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/iio/iio.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
#include <linux/mfd/ti_am335x_tscadc.h>
-#include <linux/platform_data/ti_am335x_adc.h>
struct tiadc_device {
struct ti_tscadc_dev *mfd_tscadc;
int channels;
+ u8 channel_line[8];
+ u8 channel_step[8];
};
static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg)
@@ -42,10 +47,20 @@ static void tiadc_writel(struct tiadc_device *adc, unsigned int reg,
writel(val, adc->mfd_tscadc->tscadc_base + reg);
}
+static u32 get_adc_step_mask(struct tiadc_device *adc_dev)
+{
+ u32 step_en;
+
+ step_en = ((1 << adc_dev->channels) - 1);
+ step_en <<= TOTAL_STEPS - adc_dev->channels + 1;
+ return step_en;
+}
+
static void tiadc_step_config(struct tiadc_device *adc_dev)
{
unsigned int stepconfig;
- int i, channels = 0, steps;
+ int i, steps;
+ u32 step_en;
/*
* There are 16 configurable steps and 8 analog input
@@ -58,43 +73,63 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
*/
steps = TOTAL_STEPS - adc_dev->channels;
- channels = TOTAL_CHANNELS - adc_dev->channels;
-
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1;
- for (i = (steps + 1); i <= TOTAL_STEPS; i++) {
- tiadc_writel(adc_dev, REG_STEPCONFIG(i),
- stepconfig | STEPCONFIG_INP(channels));
- tiadc_writel(adc_dev, REG_STEPDELAY(i),
+ for (i = 0; i < adc_dev->channels; i++) {
+ int chan;
+
+ chan = adc_dev->channel_line[i];
+ tiadc_writel(adc_dev, REG_STEPCONFIG(steps),
+ stepconfig | STEPCONFIG_INP(chan));
+ tiadc_writel(adc_dev, REG_STEPDELAY(steps),
STEPCONFIG_OPENDLY);
- channels++;
+ adc_dev->channel_step[i] = steps;
+ steps++;
}
- tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
+ step_en = get_adc_step_mask(adc_dev);
+ am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
}
+static const char * const chan_name_ain[] = {
+ "AIN0",
+ "AIN1",
+ "AIN2",
+ "AIN3",
+ "AIN4",
+ "AIN5",
+ "AIN6",
+ "AIN7",
+};
+
static int tiadc_channel_init(struct iio_dev *indio_dev, int channels)
{
+ struct tiadc_device *adc_dev = iio_priv(indio_dev);
struct iio_chan_spec *chan_array;
+ struct iio_chan_spec *chan;
int i;
indio_dev->num_channels = channels;
- chan_array = kcalloc(indio_dev->num_channels,
+ chan_array = kcalloc(channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
-
if (chan_array == NULL)
return -ENOMEM;
- for (i = 0; i < (indio_dev->num_channels); i++) {
- struct iio_chan_spec *chan = chan_array + i;
+ chan = chan_array;
+ for (i = 0; i < channels; i++, chan++) {
+
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
- chan->channel = i;
+ chan->channel = adc_dev->channel_line[i];
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ chan->datasheet_name = chan_name_ain[chan->channel];
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 12;
+ chan->scan_type.storagebits = 32;
}
indio_dev->channels = chan_array;
- return indio_dev->num_channels;
+ return 0;
}
static void tiadc_channels_remove(struct iio_dev *indio_dev)
@@ -108,7 +143,9 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
int i;
- unsigned int fifo1count, readx1;
+ unsigned int fifo1count, read;
+ u32 step = UINT_MAX;
+ bool found = false;
/*
* When the sub-system is first enabled,
@@ -121,14 +158,26 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
* Hence we need to flush out this data.
*/
+ for (i = 0; i < ARRAY_SIZE(adc_dev->channel_step); i++) {
+ if (chan->channel == adc_dev->channel_line[i]) {
+ step = adc_dev->channel_step[i];
+ break;
+ }
+ }
+ if (WARN_ON_ONCE(step == UINT_MAX))
+ return -EINVAL;
+
fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
for (i = 0; i < fifo1count; i++) {
- readx1 = tiadc_readl(adc_dev, REG_FIFO1);
- if (i == chan->channel)
- *val = readx1 & 0xfff;
+ read = tiadc_readl(adc_dev, REG_FIFO1);
+ if (read >> 16 == step) {
+ *val = read & 0xfff;
+ found = true;
+ }
}
- tiadc_writel(adc_dev, REG_SE, STPENB_STEPENB);
-
+ am335x_tsc_se_update(adc_dev->mfd_tscadc);
+ if (found == false)
+ return -EBUSY;
return IIO_VAL_INT;
}
@@ -140,13 +189,15 @@ static int tiadc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
struct tiadc_device *adc_dev;
- struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
- struct mfd_tscadc_board *pdata;
+ struct device_node *node = pdev->dev.of_node;
+ struct property *prop;
+ const __be32 *cur;
int err;
+ u32 val;
+ int channels = 0;
- pdata = tscadc_dev->dev->platform_data;
- if (!pdata || !pdata->adc_init) {
- dev_err(&pdev->dev, "Could not find platform data\n");
+ if (!node) {
+ dev_err(&pdev->dev, "Could not find valid DT data.\n");
return -EINVAL;
}
@@ -158,8 +209,13 @@ static int tiadc_probe(struct platform_device *pdev)
}
adc_dev = iio_priv(indio_dev);
- adc_dev->mfd_tscadc = tscadc_dev;
- adc_dev->channels = pdata->adc_init->adc_channels;
+ adc_dev->mfd_tscadc = ti_tscadc_dev_get(pdev);
+
+ of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
+ adc_dev->channel_line[channels] = val;
+ channels++;
+ }
+ adc_dev->channels = channels;
indio_dev->dev.parent = &pdev->dev;
indio_dev->name = dev_name(&pdev->dev);
@@ -191,10 +247,15 @@ err_ret:
static int tiadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct tiadc_device *adc_dev = iio_priv(indio_dev);
+ u32 step_en;
iio_device_unregister(indio_dev);
tiadc_channels_remove(indio_dev);
+ step_en = get_adc_step_mask(adc_dev);
+ am335x_tsc_se_clr(adc_dev->mfd_tscadc, step_en);
+
iio_device_free(indio_dev);
return 0;
@@ -205,9 +266,10 @@ static int tiadc_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct tiadc_device *adc_dev = iio_priv(indio_dev);
- struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
+ struct ti_tscadc_dev *tscadc_dev;
unsigned int idle;
+ tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
if (!device_may_wakeup(tscadc_dev->dev)) {
idle = tiadc_readl(adc_dev, REG_CTRL);
idle &= ~(CNTRLREG_TSCSSENB);
@@ -243,16 +305,22 @@ static const struct dev_pm_ops tiadc_pm_ops = {
#define TIADC_PM_OPS NULL
#endif
+static const struct of_device_id ti_adc_dt_ids[] = {
+ { .compatible = "ti,am3359-adc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_adc_dt_ids);
+
static struct platform_driver tiadc_driver = {
.driver = {
- .name = "tiadc",
+ .name = "TI-am335x-adc",
.owner = THIS_MODULE,
.pm = TIADC_PM_OPS,
+ .of_match_table = of_match_ptr(ti_adc_dt_ids),
},
.probe = tiadc_probe,
.remove = tiadc_remove,
};
-
module_platform_driver(tiadc_driver);
MODULE_DESCRIPTION("TI ADC controller driver");
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 71c2c7116802..34fbc2f60a09 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -3269,9 +3269,9 @@ static int cma_netdev_change(struct net_device *ndev, struct rdma_id_private *id
}
static int cma_netdev_callback(struct notifier_block *self, unsigned long event,
- void *ctx)
+ void *ptr)
{
- struct net_device *ndev = (struct net_device *)ctx;
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
struct cma_device *cma_dev;
struct rdma_id_private *id_priv;
int ret = NOTIFY_DONE;
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 246fdc151652..99904f7d59e3 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -813,7 +813,7 @@ int ib_device_register_sysfs(struct ib_device *device,
class_dev->class = &ib_class;
class_dev->parent = device->dma_device;
- dev_set_name(class_dev, device->name);
+ dev_set_name(class_dev, "%s", device->name);
dev_set_drvdata(class_dev, device);
INIT_LIST_HEAD(&device->port_list);
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index f8a62918a88d..982e3efd98d3 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -713,8 +713,7 @@ static struct attribute_group ehca_dev_attr_grp = {
.attrs = ehca_dev_attrs
};
-static int ehca_probe(struct platform_device *dev,
- const struct of_device_id *id)
+static int ehca_probe(struct platform_device *dev)
{
struct ehca_shca *shca;
const u64 *handle;
@@ -937,7 +936,7 @@ static struct of_device_id ehca_device_table[] =
};
MODULE_DEVICE_TABLE(of, ehca_device_table);
-static struct of_platform_driver ehca_driver = {
+static struct platform_driver ehca_driver = {
.probe = ehca_probe,
.remove = ehca_remove,
.driver = {
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 23d734349d8e..a188d3178559 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -1161,7 +1161,7 @@ static void netdev_removed(struct mlx4_ib_dev *dev, int port)
static int mlx4_ib_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct mlx4_ib_dev *ibdev;
struct net_device *oldnd;
struct mlx4_ib_iboe *iboe;
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index b56c9428f3c5..9dd0bc89c3aa 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -2208,7 +2208,7 @@ int qib_cdev_init(int minor, const char *name,
goto err_cdev;
}
- device = device_create(qib_class, NULL, dev, NULL, name);
+ device = device_create(qib_class, NULL, dev, NULL, "%s", name);
if (!IS_ERR(device))
goto done;
ret = PTR_ERR(device);
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index 41712f096515..3f62041222f2 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -388,6 +388,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
init_waitqueue_head(&isert_conn->conn_wait_comp_err);
kref_init(&isert_conn->conn_kref);
kref_get(&isert_conn->conn_kref);
+ mutex_init(&isert_conn->conn_mutex);
cma_id->context = isert_conn;
isert_conn->conn_cm_id = cma_id;
@@ -540,15 +541,32 @@ isert_disconnect_work(struct work_struct *work)
struct isert_conn, conn_logout_work);
pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
-
+ mutex_lock(&isert_conn->conn_mutex);
isert_conn->state = ISER_CONN_DOWN;
if (isert_conn->post_recv_buf_count == 0 &&
atomic_read(&isert_conn->post_send_buf_count) == 0) {
pr_debug("Calling wake_up(&isert_conn->conn_wait);\n");
- wake_up(&isert_conn->conn_wait);
+ mutex_unlock(&isert_conn->conn_mutex);
+ goto wake_up;
+ }
+ if (!isert_conn->conn_cm_id) {
+ mutex_unlock(&isert_conn->conn_mutex);
+ isert_put_conn(isert_conn);
+ return;
}
+ if (!isert_conn->logout_posted) {
+ pr_debug("Calling rdma_disconnect for !logout_posted from"
+ " isert_disconnect_work\n");
+ rdma_disconnect(isert_conn->conn_cm_id);
+ mutex_unlock(&isert_conn->conn_mutex);
+ iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+ goto wake_up;
+ }
+ mutex_unlock(&isert_conn->conn_mutex);
+wake_up:
+ wake_up(&isert_conn->conn_wait);
isert_put_conn(isert_conn);
}
@@ -934,16 +952,11 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn,
}
sequence_cmd:
- rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn);
+ rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn);
if (!rc && dump_payload == false && unsol_data)
iscsit_set_unsoliticed_dataout(cmd);
- if (rc == CMDSN_ERROR_CANNOT_RECOVER)
- return iscsit_add_reject_from_cmd(
- ISCSI_REASON_PROTOCOL_ERROR,
- 1, 0, (unsigned char *)hdr, cmd);
-
return 0;
}
@@ -1001,17 +1014,71 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
}
static int
+isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+ struct iser_rx_desc *rx_desc, unsigned char *buf)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
+ int rc;
+
+ rc = iscsit_setup_nop_out(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+ /*
+ * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload
+ */
+
+ return iscsit_process_nop_out(conn, cmd, hdr);
+}
+
+static int
+isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
+ struct iser_rx_desc *rx_desc, struct iscsi_text *hdr)
+{
+ struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+ struct iscsi_conn *conn = isert_conn->conn;
+ u32 payload_length = ntoh24(hdr->dlength);
+ int rc;
+ unsigned char *text_in;
+
+ rc = iscsit_setup_text_cmd(conn, cmd, hdr);
+ if (rc < 0)
+ return rc;
+
+ text_in = kzalloc(payload_length, GFP_KERNEL);
+ if (!text_in) {
+ pr_err("Unable to allocate text_in of payload_length: %u\n",
+ payload_length);
+ return -ENOMEM;
+ }
+ cmd->text_in_ptr = text_in;
+
+ memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length);
+
+ return iscsit_process_text_cmd(conn, cmd, hdr);
+}
+
+static int
isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
uint32_t read_stag, uint64_t read_va,
uint32_t write_stag, uint64_t write_va)
{
struct iscsi_hdr *hdr = &rx_desc->iscsi_header;
struct iscsi_conn *conn = isert_conn->conn;
+ struct iscsi_session *sess = conn->sess;
struct iscsi_cmd *cmd;
struct isert_cmd *isert_cmd;
int ret = -EINVAL;
u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK);
+ if (sess->sess_ops->SessionType &&
+ (!(opcode & ISCSI_OP_TEXT) || !(opcode & ISCSI_OP_LOGOUT))) {
+ pr_err("Got illegal opcode: 0x%02x in SessionType=Discovery,"
+ " ignoring\n", opcode);
+ return 0;
+ }
+
switch (opcode) {
case ISCSI_OP_SCSI_CMD:
cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
@@ -1032,7 +1099,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
if (!cmd)
break;
- ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr);
+ isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+ ret = isert_handle_nop_out(isert_conn, isert_cmd,
+ rx_desc, (unsigned char *)hdr);
break;
case ISCSI_OP_SCSI_DATA_OUT:
ret = isert_handle_iscsi_dataout(isert_conn, rx_desc,
@@ -1057,6 +1126,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
SECONDS_FOR_LOGOUT_COMP *
HZ);
break;
+ case ISCSI_OP_TEXT:
+ cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+ if (!cmd)
+ break;
+
+ isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+ ret = isert_handle_text_cmd(isert_conn, isert_cmd,
+ rx_desc, (struct iscsi_text *)hdr);
+ break;
default:
pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode);
dump_stack();
@@ -1184,14 +1262,12 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
{
struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
struct isert_conn *isert_conn = isert_cmd->conn;
- struct iscsi_conn *conn;
+ struct iscsi_conn *conn = isert_conn->conn;
pr_debug("Entering isert_put_cmd: %p\n", isert_cmd);
switch (cmd->iscsi_opcode) {
case ISCSI_OP_SCSI_CMD:
- conn = isert_conn->conn;
-
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
list_del(&cmd->i_conn_node);
@@ -1201,16 +1277,19 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
iscsit_stop_dataout_timer(cmd);
isert_unmap_cmd(isert_cmd, isert_conn);
- /*
- * Fall-through
- */
+ transport_generic_free_cmd(&cmd->se_cmd, 0);
+ break;
case ISCSI_OP_SCSI_TMFUNC:
+ spin_lock_bh(&conn->cmd_lock);
+ if (!list_empty(&cmd->i_conn_node))
+ list_del(&cmd->i_conn_node);
+ spin_unlock_bh(&conn->cmd_lock);
+
transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
case ISCSI_OP_REJECT:
case ISCSI_OP_NOOP_OUT:
- conn = isert_conn->conn;
-
+ case ISCSI_OP_TEXT:
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
list_del(&cmd->i_conn_node);
@@ -1222,6 +1301,9 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
* associated cmd->se_cmd needs to be released.
*/
if (cmd->se_cmd.se_tfo != NULL) {
+ pr_debug("Calling transport_generic_free_cmd from"
+ " isert_put_cmd for 0x%02x\n",
+ cmd->iscsi_opcode);
transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
}
@@ -1249,11 +1331,11 @@ static void
isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd,
struct ib_device *ib_dev)
{
- if (isert_cmd->sense_buf_dma != 0) {
- pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n");
- ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma,
- isert_cmd->sense_buf_len, DMA_TO_DEVICE);
- isert_cmd->sense_buf_dma = 0;
+ if (isert_cmd->pdu_buf_dma != 0) {
+ pr_debug("Calling ib_dma_unmap_single for isert_cmd->pdu_buf_dma\n");
+ ib_dma_unmap_single(ib_dev, isert_cmd->pdu_buf_dma,
+ isert_cmd->pdu_buf_len, DMA_TO_DEVICE);
+ isert_cmd->pdu_buf_dma = 0;
}
isert_unmap_tx_desc(tx_desc, ib_dev);
@@ -1318,8 +1400,8 @@ isert_do_control_comp(struct work_struct *work)
atomic_dec(&isert_conn->post_send_buf_count);
cmd->i_state = ISTATE_SENT_STATUS;
- complete(&cmd->reject_comp);
isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+ break;
case ISTATE_SEND_LOGOUTRSP:
pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n");
/*
@@ -1329,6 +1411,11 @@ isert_do_control_comp(struct work_struct *work)
isert_conn->logout_posted = true;
iscsit_logout_post_handler(cmd, cmd->conn);
break;
+ case ISTATE_SEND_TEXTRSP:
+ atomic_dec(&isert_conn->post_send_buf_count);
+ cmd->i_state = ISTATE_SENT_STATUS;
+ isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev);
+ break;
default:
pr_err("Unknown do_control_comp i_state %d\n", cmd->i_state);
dump_stack();
@@ -1345,7 +1432,9 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
- cmd->i_state == ISTATE_SEND_LOGOUTRSP) {
+ cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
+ cmd->i_state == ISTATE_SEND_REJECT ||
+ cmd->i_state == ISTATE_SEND_TEXTRSP) {
isert_unmap_tx_desc(tx_desc, ib_dev);
INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp);
@@ -1419,7 +1508,11 @@ isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn)
pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
pr_debug("Calling wake_up from isert_cq_comp_err\n");
- isert_conn->state = ISER_CONN_TERMINATING;
+ mutex_lock(&isert_conn->conn_mutex);
+ if (isert_conn->state != ISER_CONN_DOWN)
+ isert_conn->state = ISER_CONN_TERMINATING;
+ mutex_unlock(&isert_conn->conn_mutex);
+
wake_up(&isert_conn->conn_wait_comp_err);
}
}
@@ -1445,6 +1538,7 @@ isert_cq_tx_work(struct work_struct *work)
} else {
pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
pr_debug("TX wc.status: 0x%08x\n", wc.status);
+ pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err);
atomic_dec(&isert_conn->post_send_buf_count);
isert_cq_comp_err(tx_desc, isert_conn);
}
@@ -1484,9 +1578,11 @@ isert_cq_rx_work(struct work_struct *work)
isert_rx_completion(rx_desc, isert_conn, xfer_len);
} else {
pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n");
- if (wc.status != IB_WC_WR_FLUSH_ERR)
+ if (wc.status != IB_WC_WR_FLUSH_ERR) {
pr_debug("RX wc.status: 0x%08x\n", wc.status);
-
+ pr_debug("RX wc.vendor_err: 0x%08x\n",
+ wc.vendor_err);
+ }
isert_conn->post_recv_buf_count--;
isert_cq_comp_err(NULL, isert_conn);
}
@@ -1543,7 +1639,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
(cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) {
struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
- u32 padding, sense_len;
+ u32 padding, pdu_len;
put_unaligned_be16(cmd->se_cmd.scsi_sense_length,
cmd->sense_buffer);
@@ -1551,15 +1647,15 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
padding = -(cmd->se_cmd.scsi_sense_length) & 3;
hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length);
- sense_len = cmd->se_cmd.scsi_sense_length + padding;
+ pdu_len = cmd->se_cmd.scsi_sense_length + padding;
- isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev,
- (void *)cmd->sense_buffer, sense_len,
+ isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+ (void *)cmd->sense_buffer, pdu_len,
DMA_TO_DEVICE);
- isert_cmd->sense_buf_len = sense_len;
- tx_dsg->addr = isert_cmd->sense_buf_dma;
- tx_dsg->length = sense_len;
+ isert_cmd->pdu_buf_len = pdu_len;
+ tx_dsg->addr = isert_cmd->pdu_buf_dma;
+ tx_dsg->length = pdu_len;
tx_dsg->lkey = isert_conn->conn_mr->lkey;
isert_cmd->tx_desc.num_sge = 2;
}
@@ -1587,7 +1683,7 @@ isert_put_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
isert_init_send_wr(isert_cmd, send_wr);
- pr_debug("Posting NOPIN Reponse IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+ pr_debug("Posting NOPIN Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
return isert_post_response(isert_conn, isert_cmd);
}
@@ -1637,11 +1733,25 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
struct isert_cmd, iscsi_cmd);
struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+ struct iscsi_reject *hdr =
+ (struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header;
isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
- iscsit_build_reject(cmd, conn, (struct iscsi_reject *)
- &isert_cmd->tx_desc.iscsi_header);
+ iscsit_build_reject(cmd, conn, hdr);
isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ hton24(hdr->dlength, ISCSI_HDR_LEN);
+ isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+ (void *)cmd->buf_ptr, ISCSI_HDR_LEN,
+ DMA_TO_DEVICE);
+ isert_cmd->pdu_buf_len = ISCSI_HDR_LEN;
+ tx_dsg->addr = isert_cmd->pdu_buf_dma;
+ tx_dsg->length = ISCSI_HDR_LEN;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ isert_cmd->tx_desc.num_sge = 2;
+
isert_init_send_wr(isert_cmd, send_wr);
pr_debug("Posting Reject IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
@@ -1650,6 +1760,47 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
}
static int
+isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
+{
+ struct isert_cmd *isert_cmd = container_of(cmd,
+ struct isert_cmd, iscsi_cmd);
+ struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+ struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
+ struct iscsi_text_rsp *hdr =
+ (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header;
+ u32 txt_rsp_len;
+ int rc;
+
+ isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+ rc = iscsit_build_text_rsp(cmd, conn, hdr);
+ if (rc < 0)
+ return rc;
+
+ txt_rsp_len = rc;
+ isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+
+ if (txt_rsp_len) {
+ struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+ struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1];
+ void *txt_rsp_buf = cmd->buf_ptr;
+
+ isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev,
+ txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE);
+
+ isert_cmd->pdu_buf_len = txt_rsp_len;
+ tx_dsg->addr = isert_cmd->pdu_buf_dma;
+ tx_dsg->length = txt_rsp_len;
+ tx_dsg->lkey = isert_conn->conn_mr->lkey;
+ isert_cmd->tx_desc.num_sge = 2;
+ }
+ isert_init_send_wr(isert_cmd, send_wr);
+
+ pr_debug("Posting Text Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n");
+
+ return isert_post_response(isert_conn, isert_cmd);
+}
+
+static int
isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
struct ib_sge *ib_sge, struct ib_send_wr *send_wr,
u32 data_left, u32 offset)
@@ -1947,6 +2098,9 @@ isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state)
case ISTATE_SEND_REJECT:
ret = isert_put_reject(cmd, conn);
break;
+ case ISTATE_SEND_TEXTRSP:
+ ret = isert_put_text_rsp(cmd, conn);
+ break;
case ISTATE_SEND_STATUS:
/*
* Special case for sending non GOOD SCSI status from TX thread
@@ -2175,6 +2329,17 @@ isert_free_np(struct iscsi_np *np)
kfree(isert_np);
}
+static int isert_check_state(struct isert_conn *isert_conn, int state)
+{
+ int ret;
+
+ mutex_lock(&isert_conn->conn_mutex);
+ ret = (isert_conn->state == state);
+ mutex_unlock(&isert_conn->conn_mutex);
+
+ return ret;
+}
+
static void isert_free_conn(struct iscsi_conn *conn)
{
struct isert_conn *isert_conn = conn->context;
@@ -2184,26 +2349,43 @@ static void isert_free_conn(struct iscsi_conn *conn)
* Decrement post_send_buf_count for special case when called
* from isert_do_control_comp() -> iscsit_logout_post_handler()
*/
+ mutex_lock(&isert_conn->conn_mutex);
if (isert_conn->logout_posted)
atomic_dec(&isert_conn->post_send_buf_count);
- if (isert_conn->conn_cm_id)
+ if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) {
+ pr_debug("Calling rdma_disconnect from isert_free_conn\n");
rdma_disconnect(isert_conn->conn_cm_id);
+ }
/*
* Only wait for conn_wait_comp_err if the isert_conn made it
* into full feature phase..
*/
- if (isert_conn->state > ISER_CONN_INIT) {
+ if (isert_conn->state == ISER_CONN_UP) {
pr_debug("isert_free_conn: Before wait_event comp_err %d\n",
isert_conn->state);
+ mutex_unlock(&isert_conn->conn_mutex);
+
wait_event(isert_conn->conn_wait_comp_err,
- isert_conn->state == ISER_CONN_TERMINATING);
- pr_debug("isert_free_conn: After wait_event #1 >>>>>>>>>>>>\n");
+ (isert_check_state(isert_conn, ISER_CONN_TERMINATING)));
+
+ wait_event(isert_conn->conn_wait,
+ (isert_check_state(isert_conn, ISER_CONN_DOWN)));
+
+ isert_put_conn(isert_conn);
+ return;
+ }
+ if (isert_conn->state == ISER_CONN_INIT) {
+ mutex_unlock(&isert_conn->conn_mutex);
+ isert_put_conn(isert_conn);
+ return;
}
+ pr_debug("isert_free_conn: wait_event conn_wait %d\n",
+ isert_conn->state);
+ mutex_unlock(&isert_conn->conn_mutex);
- pr_debug("isert_free_conn: wait_event conn_wait %d\n", isert_conn->state);
- wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN);
- pr_debug("isert_free_conn: After wait_event #2 >>>>>>>>>>>>>>>>>>>>\n");
+ wait_event(isert_conn->conn_wait,
+ (isert_check_state(isert_conn, ISER_CONN_DOWN)));
isert_put_conn(isert_conn);
}
diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h
index b104f4c2cd38..191117b5b508 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.h
+++ b/drivers/infiniband/ulp/isert/ib_isert.h
@@ -61,8 +61,8 @@ struct isert_cmd {
uint32_t write_stag;
uint64_t read_va;
uint64_t write_va;
- u64 sense_buf_dma;
- u32 sense_buf_len;
+ u64 pdu_buf_dma;
+ u32 pdu_buf_len;
u32 read_va_off;
u32 write_va_off;
u32 rdma_wr_num;
@@ -102,6 +102,7 @@ struct isert_conn {
struct ib_qp *conn_qp;
struct isert_device *conn_device;
struct work_struct conn_logout_work;
+ struct mutex conn_mutex;
wait_queue_head_t conn_wait;
wait_queue_head_t conn_wait_comp_err;
struct kref conn_kref;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 3f3f0416fbdd..653ac6bfc57a 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3011,7 +3011,7 @@ static u8 tcm_to_srp_tsk_mgmt_status(const int tcm_mgmt_status)
* Callback function called by the TCM core. Must not block since it can be
* invoked on the context of the IB completion handler.
*/
-static int srpt_queue_response(struct se_cmd *cmd)
+static void srpt_queue_response(struct se_cmd *cmd)
{
struct srpt_rdma_ch *ch;
struct srpt_send_ioctx *ioctx;
@@ -3022,8 +3022,6 @@ static int srpt_queue_response(struct se_cmd *cmd)
int resp_len;
u8 srp_tm_status;
- ret = 0;
-
ioctx = container_of(cmd, struct srpt_send_ioctx, cmd);
ch = ioctx->ch;
BUG_ON(!ch);
@@ -3049,7 +3047,7 @@ static int srpt_queue_response(struct se_cmd *cmd)
|| WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
atomic_inc(&ch->req_lim_delta);
srpt_abort_cmd(ioctx);
- goto out;
+ return;
}
dir = ioctx->cmd.data_direction;
@@ -3061,7 +3059,7 @@ static int srpt_queue_response(struct se_cmd *cmd)
if (ret) {
printk(KERN_ERR "xfer_data failed for tag %llu\n",
ioctx->tag);
- goto out;
+ return;
}
}
@@ -3082,9 +3080,17 @@ static int srpt_queue_response(struct se_cmd *cmd)
srpt_set_cmd_state(ioctx, SRPT_STATE_DONE);
target_put_sess_cmd(ioctx->ch->sess, &ioctx->cmd);
}
+}
-out:
- return ret;
+static int srpt_queue_data_in(struct se_cmd *cmd)
+{
+ srpt_queue_response(cmd);
+ return 0;
+}
+
+static void srpt_queue_tm_rsp(struct se_cmd *cmd)
+{
+ srpt_queue_response(cmd);
}
static int srpt_queue_status(struct se_cmd *cmd)
@@ -3097,7 +3103,8 @@ static int srpt_queue_status(struct se_cmd *cmd)
(SCF_TRANSPORT_TASK_SENSE | SCF_EMULATED_TASK_SENSE))
WARN_ON(cmd->scsi_status != SAM_STAT_CHECK_CONDITION);
ioctx->queue_status_only = true;
- return srpt_queue_response(cmd);
+ srpt_queue_response(cmd);
+ return 0;
}
static void srpt_refresh_port_work(struct work_struct *work)
@@ -3930,9 +3937,9 @@ static struct target_core_fabric_ops srpt_template = {
.set_default_node_attributes = srpt_set_default_node_attrs,
.get_task_tag = srpt_get_task_tag,
.get_cmd_state = srpt_get_tcm_cmd_state,
- .queue_data_in = srpt_queue_response,
+ .queue_data_in = srpt_queue_data_in,
.queue_status = srpt_queue_status,
- .queue_tm_rsp = srpt_queue_response,
+ .queue_tm_rsp = srpt_queue_tm_rsp,
/*
* Setup function pointers for generic logic in
* target_core_fabric_configfs.c
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index f0f8928b3c8a..d2b34fbbc42e 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -52,6 +52,82 @@ struct evdev_client {
struct input_event buffer[];
};
+/* flush queued events of type @type, caller must hold client->buffer_lock */
+static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
+{
+ unsigned int i, head, num;
+ unsigned int mask = client->bufsize - 1;
+ bool is_report;
+ struct input_event *ev;
+
+ BUG_ON(type == EV_SYN);
+
+ head = client->tail;
+ client->packet_head = client->tail;
+
+ /* init to 1 so a leading SYN_REPORT will not be dropped */
+ num = 1;
+
+ for (i = client->tail; i != client->head; i = (i + 1) & mask) {
+ ev = &client->buffer[i];
+ is_report = ev->type == EV_SYN && ev->code == SYN_REPORT;
+
+ if (ev->type == type) {
+ /* drop matched entry */
+ continue;
+ } else if (is_report && !num) {
+ /* drop empty SYN_REPORT groups */
+ continue;
+ } else if (head != i) {
+ /* move entry to fill the gap */
+ client->buffer[head].time = ev->time;
+ client->buffer[head].type = ev->type;
+ client->buffer[head].code = ev->code;
+ client->buffer[head].value = ev->value;
+ }
+
+ num++;
+ head = (head + 1) & mask;
+
+ if (is_report) {
+ num = 0;
+ client->packet_head = head;
+ }
+ }
+
+ client->head = head;
+}
+
+/* queue SYN_DROPPED event */
+static void evdev_queue_syn_dropped(struct evdev_client *client)
+{
+ unsigned long flags;
+ struct input_event ev;
+ ktime_t time;
+
+ time = ktime_get();
+ if (client->clkid != CLOCK_MONOTONIC)
+ time = ktime_sub(time, ktime_get_monotonic_offset());
+
+ ev.time = ktime_to_timeval(time);
+ ev.type = EV_SYN;
+ ev.code = SYN_DROPPED;
+ ev.value = 0;
+
+ spin_lock_irqsave(&client->buffer_lock, flags);
+
+ client->buffer[client->head++] = ev;
+ client->head &= client->bufsize - 1;
+
+ if (unlikely(client->head == client->tail)) {
+ /* drop queue but keep our SYN_DROPPED event */
+ client->tail = (client->head - 1) & (client->bufsize - 1);
+ client->packet_head = client->tail;
+ }
+
+ spin_unlock_irqrestore(&client->buffer_lock, flags);
+}
+
static void __pass_event(struct evdev_client *client,
const struct input_event *event)
{
@@ -650,6 +726,51 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p)
return input_set_keycode(dev, &ke);
}
+/*
+ * If we transfer state to the user, we should flush all pending events
+ * of the same type from the client's queue. Otherwise, they might end up
+ * with duplicate events, which can screw up client's state tracking.
+ * If bits_to_user fails after flushing the queue, we queue a SYN_DROPPED
+ * event so user-space will notice missing events.
+ *
+ * LOCKING:
+ * We need to take event_lock before buffer_lock to avoid dead-locks. But we
+ * need the even_lock only to guarantee consistent state. We can safely release
+ * it while flushing the queue. This allows input-core to handle filters while
+ * we flush the queue.
+ */
+static int evdev_handle_get_val(struct evdev_client *client,
+ struct input_dev *dev, unsigned int type,
+ unsigned long *bits, unsigned int max,
+ unsigned int size, void __user *p, int compat)
+{
+ int ret;
+ unsigned long *mem;
+
+ mem = kmalloc(sizeof(unsigned long) * max, GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ spin_lock_irq(&dev->event_lock);
+ spin_lock(&client->buffer_lock);
+
+ memcpy(mem, bits, sizeof(unsigned long) * max);
+
+ spin_unlock(&dev->event_lock);
+
+ __evdev_flush_queue(client, type);
+
+ spin_unlock_irq(&client->buffer_lock);
+
+ ret = bits_to_user(mem, max, size, p, compat);
+ if (ret < 0)
+ evdev_queue_syn_dropped(client);
+
+ kfree(mem);
+
+ return ret;
+}
+
static int evdev_handle_mt_request(struct input_dev *dev,
unsigned int size,
int __user *ip)
@@ -771,16 +892,20 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
return evdev_handle_mt_request(dev, size, ip);
case EVIOCGKEY(0):
- return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode);
+ return evdev_handle_get_val(client, dev, EV_KEY, dev->key,
+ KEY_MAX, size, p, compat_mode);
case EVIOCGLED(0):
- return bits_to_user(dev->led, LED_MAX, size, p, compat_mode);
+ return evdev_handle_get_val(client, dev, EV_LED, dev->led,
+ LED_MAX, size, p, compat_mode);
case EVIOCGSND(0):
- return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode);
+ return evdev_handle_get_val(client, dev, EV_SND, dev->snd,
+ SND_MAX, size, p, compat_mode);
case EVIOCGSW(0):
- return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode);
+ return evdev_handle_get_val(client, dev, EV_SW, dev->sw,
+ SW_MAX, size, p, compat_mode);
case EVIOCGNAME(0):
return str_to_user(dev->name, size, p);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 7ac9c9818d55..269d4c3658cb 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -418,6 +418,16 @@ config KEYBOARD_NOMADIK
To compile this driver as a module, choose M here: the
module will be called nmk-ske-keypad.
+config KEYBOARD_NSPIRE
+ tristate "TI-NSPIRE built-in keyboard"
+ depends on ARCH_NSPIRE && OF
+ select INPUT_MATRIXKMAP
+ help
+ Say Y here if you want to use the built-in keypad on TI-NSPIRE.
+
+ To compile this driver as a module, choose M here: the
+ module will be called nspire-keypad.
+
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
depends on ARCH_TEGRA && OF
@@ -442,6 +452,7 @@ config KEYBOARD_OPENCORES
config KEYBOARD_PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx || ARCH_MMP
+ select INPUT_MATRIXKMAP
help
Enable support for PXA27x/PXA3xx keypad controller.
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 0c43e8cf8d0e..a699b6172303 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
+obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index ba0b36f7daea..096d6067ae1f 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -246,7 +246,6 @@ static int __exit amikbd_remove(struct platform_device *pdev)
{
struct input_dev *dev = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
free_irq(IRQ_AMIGA_CIAA_SP, dev);
input_unregister_device(dev);
return 0;
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index 20b9fa91fb9e..fc88fb48d70d 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -326,7 +326,6 @@ out0:
kfree(bf54x_kpad->keycode);
out:
kfree(bf54x_kpad);
- platform_set_drvdata(pdev, NULL);
return error;
}
@@ -346,7 +345,6 @@ static int bfin_kpad_remove(struct platform_device *pdev)
kfree(bf54x_kpad->keycode);
kfree(bf54x_kpad);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 49557f27bfa6..7e8b0a52af25 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -206,33 +206,6 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
return NOTIFY_DONE;
}
-/* Clear any keys in the buffer */
-static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
-{
- uint8_t old_state[ckdev->cols];
- uint8_t new_state[ckdev->cols];
- unsigned long duration;
- int i, ret;
-
- /*
- * Keep reading until we see that the scan state does not change.
- * That indicates that we are done.
- *
- * Assume that the EC keyscan buffer is at most 32 deep.
- */
- duration = jiffies;
- ret = cros_ec_keyb_get_state(ckdev, new_state);
- for (i = 1; !ret && i < 32; i++) {
- memcpy(old_state, new_state, sizeof(old_state));
- ret = cros_ec_keyb_get_state(ckdev, new_state);
- if (0 == memcmp(old_state, new_state, sizeof(old_state)))
- break;
- }
- duration = jiffies - duration;
- dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
- jiffies_to_usecs(duration));
-}
-
static int cros_ec_keyb_probe(struct platform_device *pdev)
{
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@@ -299,6 +272,33 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+/* Clear any keys in the buffer */
+static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
+{
+ uint8_t old_state[ckdev->cols];
+ uint8_t new_state[ckdev->cols];
+ unsigned long duration;
+ int i, ret;
+
+ /*
+ * Keep reading until we see that the scan state does not change.
+ * That indicates that we are done.
+ *
+ * Assume that the EC keyscan buffer is at most 32 deep.
+ */
+ duration = jiffies;
+ ret = cros_ec_keyb_get_state(ckdev, new_state);
+ for (i = 1; !ret && i < 32; i++) {
+ memcpy(old_state, new_state, sizeof(old_state));
+ ret = cros_ec_keyb_get_state(ckdev, new_state);
+ if (0 == memcmp(old_state, new_state, sizeof(old_state)))
+ break;
+ }
+ duration = jiffies - duration;
+ dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
+ jiffies_to_usecs(duration));
+}
+
static int cros_ec_keyb_resume(struct device *dev)
{
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
diff --git a/drivers/input/keyboard/davinci_keyscan.c b/drivers/input/keyboard/davinci_keyscan.c
index 829753702b62..d15977a8361e 100644
--- a/drivers/input/keyboard/davinci_keyscan.c
+++ b/drivers/input/keyboard/davinci_keyscan.c
@@ -314,8 +314,6 @@ static int davinci_ks_remove(struct platform_device *pdev)
iounmap(davinci_ks->base);
release_mem_region(davinci_ks->pbase, davinci_ks->base_size);
- platform_set_drvdata(pdev, NULL);
-
kfree(davinci_ks);
return 0;
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 9857e8fd0987..47206bdba411 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -329,8 +329,7 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
- free_irq(keypad->irq, pdev);
- platform_set_drvdata(pdev, NULL);
+ free_irq(keypad->irq, keypad);
failed_free_dev:
input_free_device(input_dev);
failed_put_clk:
@@ -351,9 +350,7 @@ static int ep93xx_keypad_remove(struct platform_device *pdev)
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
- free_irq(keypad->irq, pdev);
-
- platform_set_drvdata(pdev, NULL);
+ free_irq(keypad->irq, keypad);
if (keypad->enabled)
clk_disable(keypad->clk);
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index b29ca651a395..440ce32462ba 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -767,7 +767,6 @@ static int gpio_keys_probe(struct platform_device *pdev)
while (--i >= 0)
gpio_remove_key(&ddata->data[i]);
- platform_set_drvdata(pdev, NULL);
fail1:
input_free_device(input);
kfree(ddata);
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 21147164874d..cd5ed9e22168 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -324,7 +324,6 @@ err_free_gpio:
err_free_bdev:
kfree(bdev);
- platform_set_drvdata(pdev, NULL);
err_free_pdata:
/* If we have no platform_data, we allocated pdata dynamically. */
@@ -355,7 +354,6 @@ static int gpio_keys_polled_remove(struct platform_device *pdev)
kfree(pdata);
kfree(bdev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c
index 74e75a6e8deb..a2a034c25f0b 100644
--- a/drivers/input/keyboard/jornada680_kbd.c
+++ b/drivers/input/keyboard/jornada680_kbd.c
@@ -233,7 +233,6 @@ static int jornada680kbd_probe(struct platform_device *pdev)
failed:
printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n",
error);
- platform_set_drvdata(pdev, NULL);
input_free_polled_device(poll_dev);
kfree(jornadakbd);
return error;
@@ -244,7 +243,6 @@ static int jornada680kbd_remove(struct platform_device *pdev)
{
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_polled_device(jornadakbd->poll_dev);
input_free_polled_device(jornadakbd->poll_dev);
kfree(jornadakbd);
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c
index 5ceef636df2f..b0ad457ca9d8 100644
--- a/drivers/input/keyboard/jornada720_kbd.c
+++ b/drivers/input/keyboard/jornada720_kbd.c
@@ -146,7 +146,6 @@ static int jornada720_kbd_probe(struct platform_device *pdev)
fail2: /* IRQ, DEVICE, MEMORY */
free_irq(IRQ_GPIO0, pdev);
fail1: /* DEVICE, MEMORY */
- platform_set_drvdata(pdev, NULL);
input_free_device(input_dev);
kfree(jornadakbd);
return err;
@@ -157,7 +156,6 @@ static int jornada720_kbd_remove(struct platform_device *pdev)
struct jornadakbd *jornadakbd = platform_get_drvdata(pdev);
free_irq(IRQ_GPIO0, pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(jornadakbd->input);
kfree(jornadakbd);
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 71d77192ac1e..90ff73ace424 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -549,8 +549,6 @@ static int matrix_keypad_remove(struct platform_device *pdev)
input_unregister_device(keypad->input_dev);
kfree(keypad);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c
new file mode 100644
index 000000000000..e0a1339e40e6
--- /dev/null
+++ b/drivers/input/keyboard/nspire-keypad.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
+ *
+ * This program is free software; you can 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/input/matrix_keypad.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#define KEYPAD_SCAN_MODE 0x00
+#define KEYPAD_CNTL 0x04
+#define KEYPAD_INT 0x08
+#define KEYPAD_INTMSK 0x0C
+
+#define KEYPAD_DATA 0x10
+#define KEYPAD_GPIO 0x30
+
+#define KEYPAD_UNKNOWN_INT 0x40
+#define KEYPAD_UNKNOWN_INT_STS 0x44
+
+#define KEYPAD_BITMASK_COLS 11
+#define KEYPAD_BITMASK_ROWS 8
+
+struct nspire_keypad {
+ void __iomem *reg_base;
+ u32 int_mask;
+
+ struct input_dev *input;
+ struct clk *clk;
+
+ struct matrix_keymap_data *keymap;
+ int row_shift;
+
+ /* Maximum delay estimated assuming 33MHz APB */
+ u32 scan_interval; /* In microseconds (~2000us max) */
+ u32 row_delay; /* In microseconds (~500us max) */
+
+ u16 state[KEYPAD_BITMASK_ROWS];
+
+ bool active_low;
+};
+
+static irqreturn_t nspire_keypad_irq(int irq, void *dev_id)
+{
+ struct nspire_keypad *keypad = dev_id;
+ struct input_dev *input = keypad->input;
+ unsigned short *keymap = input->keycode;
+ unsigned int code;
+ int row, col;
+ u32 int_sts;
+ u16 state[8];
+ u16 bits, changed;
+
+ int_sts = readl(keypad->reg_base + KEYPAD_INT) & keypad->int_mask;
+ if (!int_sts)
+ return IRQ_NONE;
+
+ memcpy_fromio(state, keypad->reg_base + KEYPAD_DATA, sizeof(state));
+
+ for (row = 0; row < KEYPAD_BITMASK_ROWS; row++) {
+ bits = state[row];
+ if (keypad->active_low)
+ bits = ~bits;
+
+ changed = bits ^ keypad->state[row];
+ if (!changed)
+ continue;
+
+ keypad->state[row] = bits;
+
+ for (col = 0; col < KEYPAD_BITMASK_COLS; col++) {
+ if (!(changed & (1U << col)))
+ continue;
+
+ code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, keymap[code],
+ bits & (1U << col));
+ }
+ }
+
+ input_sync(input);
+
+ writel(0x3, keypad->reg_base + KEYPAD_INT);
+
+ return IRQ_HANDLED;
+}
+
+static int nspire_keypad_chip_init(struct nspire_keypad *keypad)
+{
+ unsigned long val = 0, cycles_per_us, delay_cycles, row_delay_cycles;
+
+ cycles_per_us = (clk_get_rate(keypad->clk) / 1000000);
+ if (cycles_per_us == 0)
+ cycles_per_us = 1;
+
+ delay_cycles = cycles_per_us * keypad->scan_interval;
+ WARN_ON(delay_cycles >= (1 << 16)); /* Overflow */
+ delay_cycles &= 0xffff;
+
+ row_delay_cycles = cycles_per_us * keypad->row_delay;
+ WARN_ON(row_delay_cycles >= (1 << 14)); /* Overflow */
+ row_delay_cycles &= 0x3fff;
+
+ val |= 3 << 0; /* Set scan mode to 3 (continuous scan) */
+ val |= row_delay_cycles << 2; /* Delay between scanning each row */
+ val |= delay_cycles << 16; /* Delay between scans */
+ writel(val, keypad->reg_base + KEYPAD_SCAN_MODE);
+
+ val = (KEYPAD_BITMASK_ROWS & 0xff) | (KEYPAD_BITMASK_COLS & 0xff)<<8;
+ writel(val, keypad->reg_base + KEYPAD_CNTL);
+
+ /* Enable interrupts */
+ keypad->int_mask = 1 << 1;
+ writel(keypad->int_mask, keypad->reg_base + 0xc);
+
+ /* Disable GPIO interrupts to prevent hanging on touchpad */
+ /* Possibly used to detect touchpad events */
+ writel(0, keypad->reg_base + KEYPAD_UNKNOWN_INT);
+ /* Acknowledge existing interrupts */
+ writel(~0, keypad->reg_base + KEYPAD_UNKNOWN_INT_STS);
+
+ return 0;
+}
+
+static int nspire_keypad_open(struct input_dev *input)
+{
+ struct nspire_keypad *keypad = input_get_drvdata(input);
+ int error;
+
+ error = clk_prepare_enable(keypad->clk);
+ if (error)
+ return error;
+
+ error = nspire_keypad_chip_init(keypad);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void nspire_keypad_close(struct input_dev *input)
+{
+ struct nspire_keypad *keypad = input_get_drvdata(input);
+
+ clk_disable_unprepare(keypad->clk);
+}
+
+static int nspire_keypad_probe(struct platform_device *pdev)
+{
+ const struct device_node *of_node = pdev->dev.of_node;
+ struct nspire_keypad *keypad;
+ struct input_dev *input;
+ struct resource *res;
+ int irq;
+ int error;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get keypad irq\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing platform resources\n");
+ return -EINVAL;
+ }
+
+ keypad = devm_kzalloc(&pdev->dev, sizeof(struct nspire_keypad),
+ GFP_KERNEL);
+ if (!keypad) {
+ dev_err(&pdev->dev, "failed to allocate keypad memory\n");
+ return -ENOMEM;
+ }
+
+ keypad->row_shift = get_count_order(KEYPAD_BITMASK_COLS);
+
+ error = of_property_read_u32(of_node, "scan-interval",
+ &keypad->scan_interval);
+ if (error) {
+ dev_err(&pdev->dev, "failed to get scan-interval\n");
+ return error;
+ }
+
+ error = of_property_read_u32(of_node, "row-delay",
+ &keypad->row_delay);
+ if (error) {
+ dev_err(&pdev->dev, "failed to get row-delay\n");
+ return error;
+ }
+
+ keypad->active_low = of_property_read_bool(of_node, "active-low");
+
+ keypad->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(keypad->clk)) {
+ dev_err(&pdev->dev, "unable to get clock\n");
+ return PTR_ERR(keypad->clk);
+ }
+
+ keypad->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(keypad->reg_base))
+ return PTR_ERR(keypad->reg_base);
+
+ keypad->input = input = devm_input_allocate_device(&pdev->dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ input_set_drvdata(input, keypad);
+
+ input->id.bustype = BUS_HOST;
+ input->name = "nspire-keypad";
+ input->open = nspire_keypad_open;
+ input->close = nspire_keypad_close;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_REP, input->evbit);
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ error = matrix_keypad_build_keymap(NULL, NULL,
+ KEYPAD_BITMASK_ROWS,
+ KEYPAD_BITMASK_COLS,
+ NULL, input);
+ if (error) {
+ dev_err(&pdev->dev, "building keymap failed\n");
+ return error;
+ }
+
+ error = devm_request_irq(&pdev->dev, irq, nspire_keypad_irq, 0,
+ "nspire_keypad", keypad);
+ if (error) {
+ dev_err(&pdev->dev, "allocate irq %d failed\n", irq);
+ return error;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to register input device: %d\n", error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, keypad);
+
+ dev_dbg(&pdev->dev,
+ "TI-NSPIRE keypad at %pR (scan_interval=%uus, row_delay=%uus%s)\n",
+ res, keypad->row_delay, keypad->scan_interval,
+ keypad->active_low ? ", active_low" : "");
+
+ return 0;
+}
+
+static const struct of_device_id nspire_keypad_dt_match[] = {
+ { .compatible = "ti,nspire-keypad" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, nspire_keypad_dt_match);
+
+static struct platform_driver nspire_keypad_driver = {
+ .driver = {
+ .name = "nspire-keypad",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(nspire_keypad_dt_match),
+ },
+ .probe = nspire_keypad_probe,
+};
+
+module_platform_driver(nspire_keypad_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TI-NSPIRE Keypad Driver");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index 1b289092f4e3..f4aa53a1fd69 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -419,8 +419,6 @@ static int omap4_keypad_remove(struct platform_device *pdev)
kfree(keypad_data->keymap);
kfree(keypad_data);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c
index 7ac5f174c6f7..7b9b44158ad1 100644
--- a/drivers/input/keyboard/opencores-kbd.c
+++ b/drivers/input/keyboard/opencores-kbd.c
@@ -151,8 +151,6 @@ static int opencores_kbd_remove(struct platform_device *pdev)
input_unregister_device(opencores_kbd->input);
kfree(opencores_kbd);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 74339e139d43..2c9f19ac35ea 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -707,7 +707,6 @@ err_gpio_config:
err_get_irq:
input_free_device(kp->input);
err_alloc_device:
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return rc;
}
@@ -722,7 +721,6 @@ static int pmic8xxx_kp_remove(struct platform_device *pdev)
input_unregister_device(kp->input);
kfree(kp);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 5330d8fbf6c0..134c3b404a54 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -100,7 +100,7 @@
#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
struct pxa27x_keypad {
- struct pxa27x_keypad_platform_data *pdata;
+ const struct pxa27x_keypad_platform_data *pdata;
struct clk *clk;
struct input_dev *input_dev;
@@ -118,25 +118,254 @@ struct pxa27x_keypad {
unsigned int direct_key_mask;
};
-static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
+#ifdef CONFIG_OF
+static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
+ struct pxa27x_keypad_platform_data *pdata)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
- unsigned short keycode;
+ struct device *dev = input_dev->dev.parent;
+ u32 rows, cols;
+ int error;
+
+ error = matrix_keypad_parse_of_params(dev, &rows, &cols);
+ if (error)
+ return error;
+
+ if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) {
+ dev_err(dev, "rows or cols exceeds maximum value\n");
+ return -EINVAL;
+ }
+
+ pdata->matrix_key_rows = rows;
+ pdata->matrix_key_cols = cols;
+
+ error = matrix_keypad_build_keymap(NULL, NULL,
+ pdata->matrix_key_rows,
+ pdata->matrix_key_cols,
+ keypad->keycodes, input_dev);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
+ struct pxa27x_keypad_platform_data *pdata)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+ const __be16 *prop;
+ unsigned short code;
+ unsigned int proplen, size;
int i;
+ int error;
- for (i = 0; i < pdata->matrix_key_map_size; i++) {
- unsigned int key = pdata->matrix_key_map[i];
- unsigned int row = KEY_ROW(key);
- unsigned int col = KEY_COL(key);
- unsigned int scancode = MATRIX_SCAN_CODE(row, col,
- MATRIX_ROW_SHIFT);
+ error = of_property_read_u32(np, "marvell,direct-key-count",
+ &pdata->direct_key_num);
+ if (error) {
+ /*
+ * If do not have marvel,direct-key-count defined,
+ * it means direct key is not supported.
+ */
+ return error == -EINVAL ? 0 : error;
+ }
- keycode = KEY_VAL(key);
- keypad->keycodes[scancode] = keycode;
- __set_bit(keycode, input_dev->keybit);
+ error = of_property_read_u32(np, "marvell,direct-key-mask",
+ &pdata->direct_key_mask);
+ if (error) {
+ if (error != -EINVAL)
+ return error;
+
+ /*
+ * If marvell,direct-key-mask is not defined, driver will use
+ * default value. Default value is set when configure the keypad.
+ */
+ pdata->direct_key_mask = 0;
+ }
+
+ pdata->direct_key_low_active = of_property_read_bool(np,
+ "marvell,direct-key-low-active");
+
+ prop = of_get_property(np, "marvell,direct-key-map", &proplen);
+ if (!prop)
+ return -EINVAL;
+
+ if (proplen % sizeof(u16))
+ return -EINVAL;
+
+ size = proplen / sizeof(u16);
+
+ /* Only MAX_DIRECT_KEY_NUM is accepted.*/
+ if (size > MAX_DIRECT_KEY_NUM)
+ return -EINVAL;
+
+ for (i = 0; i < size; i++) {
+ code = be16_to_cpup(prop + i);
+ keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code;
+ __set_bit(code, input_dev->keybit);
+ }
+
+ return 0;
+}
+
+static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad,
+ struct pxa27x_keypad_platform_data *pdata)
+{
+ const __be32 *prop;
+ int i, relkey_ret;
+ unsigned int code, proplen;
+ const char *rotaryname[2] = {
+ "marvell,rotary0", "marvell,rotary1"};
+ const char relkeyname[] = {"marvell,rotary-rel-key"};
+ struct input_dev *input_dev = keypad->input_dev;
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+
+ relkey_ret = of_property_read_u32(np, relkeyname, &code);
+ /* if can read correct rotary key-code, we do not need this. */
+ if (relkey_ret == 0) {
+ unsigned short relcode;
+
+ /* rotary0 taks lower half, rotary1 taks upper half. */
+ relcode = code & 0xffff;
+ pdata->rotary0_rel_code = (code & 0xffff);
+ __set_bit(relcode, input_dev->relbit);
+
+ relcode = code >> 16;
+ pdata->rotary1_rel_code = relcode;
+ __set_bit(relcode, input_dev->relbit);
+ }
+
+ for (i = 0; i < 2; i++) {
+ prop = of_get_property(np, rotaryname[i], &proplen);
+ /*
+ * If the prop is not set, it means keypad does not need
+ * initialize the rotaryX.
+ */
+ if (!prop)
+ continue;
+
+ code = be32_to_cpup(prop);
+ /*
+ * Not all up/down key code are valid.
+ * Now we depends on direct-rel-code.
+ */
+ if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) {
+ return relkey_ret;
+ } else {
+ unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1);
+ unsigned short keycode;
+
+ keycode = code & 0xffff;
+ keypad->keycodes[n] = keycode;
+ __set_bit(keycode, input_dev->keybit);
+
+ keycode = code >> 16;
+ keypad->keycodes[n + 1] = keycode;
+ __set_bit(keycode, input_dev->keybit);
+
+ if (i == 0)
+ pdata->rotary0_rel_code = -1;
+ else
+ pdata->rotary1_rel_code = -1;
+ }
+ if (i == 0)
+ pdata->enable_rotary0 = 1;
+ else
+ pdata->enable_rotary1 = 1;
+ }
+
+ keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
+ keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
+
+ return 0;
+}
+
+static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
+{
+ struct input_dev *input_dev = keypad->input_dev;
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+ struct pxa27x_keypad_platform_data *pdata;
+ int error;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "failed to allocate memory for pdata\n");
+ return -ENOMEM;
+ }
+
+ error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata);
+ if (error) {
+ dev_err(dev, "failed to parse matrix key\n");
+ return error;
+ }
+
+ error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata);
+ if (error) {
+ dev_err(dev, "failed to parse direct key\n");
+ return error;
+ }
+
+ error = pxa27x_keypad_rotary_parse_dt(keypad, pdata);
+ if (error) {
+ dev_err(dev, "failed to parse rotary key\n");
+ return error;
+ }
+
+ error = of_property_read_u32(np, "marvell,debounce-interval",
+ &pdata->debounce_interval);
+ if (error) {
+ dev_err(dev, "failed to parse debpunce-interval\n");
+ return error;
}
+ /*
+ * The keycodes may not only includes matrix key but also the direct
+ * key or rotary key.
+ */
+ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+ keypad->pdata = pdata;
+ return 0;
+}
+
+#else
+
+static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
+{
+ dev_info(keypad->input_dev->dev.parent, "missing platform data\n");
+
+ return -EINVAL;
+}
+
+#endif
+
+static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
+{
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ struct input_dev *input_dev = keypad->input_dev;
+ const struct matrix_keymap_data *keymap_data =
+ pdata ? pdata->matrix_keymap_data : NULL;
+ unsigned short keycode;
+ int i;
+ int error;
+
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ pdata->matrix_key_rows,
+ pdata->matrix_key_cols,
+ keypad->keycodes, input_dev);
+ if (error)
+ return error;
+
+ /*
+ * The keycodes may not only include matrix keys but also the direct
+ * or rotary keys.
+ */
+ input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
+
+ /* For direct keys. */
for (i = 0; i < pdata->direct_key_num; i++) {
keycode = pdata->direct_key_map[i];
keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
@@ -178,11 +407,13 @@ static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ return 0;
}
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
int row, col, num_keys_pressed = 0;
uint32_t new_state[MAX_MATRIX_KEY_COLS];
@@ -284,7 +515,7 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
uint32_t kprec;
/* read and reset to default count value */
@@ -300,7 +531,7 @@ static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
unsigned int new_state;
uint32_t kpdk, bits_changed;
@@ -340,7 +571,7 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
static void clear_wakeup_event(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
if (pdata->clear_wakeup_event)
(pdata->clear_wakeup_event)();
@@ -364,7 +595,7 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
{
- struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+ const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
unsigned int mask = 0, direct_key_num = 0;
unsigned long kpc = 0;
@@ -431,7 +662,7 @@ static void pxa27x_keypad_close(struct input_dev *dev)
clk_disable_unprepare(keypad->clk);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int pxa27x_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -475,25 +706,25 @@ static int pxa27x_keypad_resume(struct device *dev)
return 0;
}
-
-static const struct dev_pm_ops pxa27x_keypad_pm_ops = {
- .suspend = pxa27x_keypad_suspend,
- .resume = pxa27x_keypad_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops,
+ pxa27x_keypad_suspend, pxa27x_keypad_resume);
+
+
static int pxa27x_keypad_probe(struct platform_device *pdev)
{
- struct pxa27x_keypad_platform_data *pdata = pdev->dev.platform_data;
+ const struct pxa27x_keypad_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
struct pxa27x_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
int irq, error;
- if (pdata == NULL) {
- dev_err(&pdev->dev, "no platform data defined\n");
+ /* Driver need build keycode from device tree or pdata */
+ if (!np && !pdata)
return -EINVAL;
- }
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -555,7 +786,14 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- pxa27x_keypad_build_keycode(keypad);
+ if (pdata)
+ error = pxa27x_keypad_build_keycode(keypad);
+ else
+ error = pxa27x_keypad_build_keycode_from_dt(keypad);
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keycode\n");
+ goto failed_put_clk;
+ }
if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
(pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
@@ -582,7 +820,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
- free_irq(irq, pdev);
+ free_irq(irq, keypad);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
@@ -600,7 +838,7 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
- free_irq(keypad->irq, pdev);
+ free_irq(keypad->irq, keypad);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
@@ -609,7 +847,6 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;
@@ -618,15 +855,22 @@ static int pxa27x_keypad_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:pxa27x-keypad");
+#ifdef CONFIG_OF
+static const struct of_device_id pxa27x_keypad_dt_match[] = {
+ { .compatible = "marvell,pxa27x-keypad" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pxa27x_keypad_dt_match);
+#endif
+
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = pxa27x_keypad_remove,
.driver = {
.name = "pxa27x-keypad",
+ .of_match_table = of_match_ptr(pxa27x_keypad_dt_match),
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &pxa27x_keypad_pm_ops,
-#endif
},
};
module_platform_driver(pxa27x_keypad_driver);
diff --git a/drivers/input/keyboard/pxa930_rotary.c b/drivers/input/keyboard/pxa930_rotary.c
index bcad95be73aa..248cdcf95296 100644
--- a/drivers/input/keyboard/pxa930_rotary.c
+++ b/drivers/input/keyboard/pxa930_rotary.c
@@ -181,7 +181,6 @@ static int pxa930_rotary_remove(struct platform_device *pdev)
free_irq(platform_get_irq(pdev, 0), r);
input_unregister_device(r->input_dev);
iounmap(r->mmio_base);
- platform_set_drvdata(pdev, NULL);
kfree(r);
return 0;
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 22e357b51024..ac43a486c775 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -24,7 +24,6 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/sched.h>
#include <linux/input/samsung-keypad.h>
@@ -79,10 +78,6 @@ struct samsung_keypad {
unsigned int rows;
unsigned int cols;
unsigned int row_state[SAMSUNG_MAX_COLS];
-#ifdef CONFIG_OF
- int row_gpios[SAMSUNG_MAX_ROWS];
- int col_gpios[SAMSUNG_MAX_COLS];
-#endif
unsigned short keycodes[];
};
@@ -304,45 +299,6 @@ static struct samsung_keypad_platdata *samsung_keypad_parse_dt(
return pdata;
}
-
-static void samsung_keypad_parse_dt_gpio(struct device *dev,
- struct samsung_keypad *keypad)
-{
- struct device_node *np = dev->of_node;
- int gpio, error, row, col;
-
- for (row = 0; row < keypad->rows; row++) {
- gpio = of_get_named_gpio(np, "row-gpios", row);
- keypad->row_gpios[row] = gpio;
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "keypad row[%d]: invalid gpio %d\n",
- row, gpio);
- continue;
- }
-
- error = devm_gpio_request(dev, gpio, "keypad-row");
- if (error)
- dev_err(dev,
- "keypad row[%d] gpio request failed: %d\n",
- row, error);
- }
-
- for (col = 0; col < keypad->cols; col++) {
- gpio = of_get_named_gpio(np, "col-gpios", col);
- keypad->col_gpios[col] = gpio;
- if (!gpio_is_valid(gpio)) {
- dev_err(dev, "keypad column[%d]: invalid gpio %d\n",
- col, gpio);
- continue;
- }
-
- error = devm_gpio_request(dev, gpio, "keypad-col");
- if (error)
- dev_err(dev,
- "keypad column[%d] gpio request failed: %d\n",
- col, error);
- }
-}
#else
static
struct samsung_keypad_platdata *samsung_keypad_parse_dt(struct device *dev)
@@ -424,15 +380,11 @@ static int samsung_keypad_probe(struct platform_device *pdev)
keypad->stopped = true;
init_waitqueue_head(&keypad->wait);
- if (pdev->dev.of_node) {
-#ifdef CONFIG_OF
- samsung_keypad_parse_dt_gpio(&pdev->dev, keypad);
+ if (pdev->dev.of_node)
keypad->type = of_device_is_compatible(pdev->dev.of_node,
"samsung,s5pv210-keypad");
-#endif
- } else {
+ else
keypad->type = platform_get_device_id(pdev)->driver_data;
- }
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
@@ -487,7 +439,6 @@ static int samsung_keypad_probe(struct platform_device *pdev)
err_disable_runtime_pm:
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
err_unprepare_clk:
clk_unprepare(keypad->clk);
return error;
@@ -499,7 +450,6 @@ static int samsung_keypad_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(keypad->input_dev);
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index fdb9eb2df380..fe0e498d2479 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -266,7 +266,6 @@ static int sh_keysc_probe(struct platform_device *pdev)
err2:
iounmap(priv->iomem_base);
err1:
- platform_set_drvdata(pdev, NULL);
kfree(priv);
err0:
return error;
@@ -285,7 +284,6 @@ static int sh_keysc_remove(struct platform_device *pdev)
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- platform_set_drvdata(pdev, NULL);
kfree(priv);
return 0;
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index cb1e8f614631..7111124b5362 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -290,7 +290,6 @@ static int spear_kbd_remove(struct platform_device *pdev)
clk_unprepare(kbd->clk);
device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
index ee1635011292..5f7b427dd7ed 100644
--- a/drivers/input/keyboard/tnetv107x-keypad.c
+++ b/drivers/input/keyboard/tnetv107x-keypad.c
@@ -296,7 +296,6 @@ error_clk:
error_map:
release_mem_region(kp->res->start, resource_size(kp->res));
error_res:
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return error;
}
@@ -311,7 +310,6 @@ static int keypad_remove(struct platform_device *pdev)
clk_put(kp->clk);
iounmap(kp->regs);
release_mem_region(kp->res->start, resource_size(kp->res));
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 04f84fd57173..d2d178c84ea7 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -422,7 +422,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
err3:
/* mask all events - we don't care about the result */
(void) twl4030_kpwrite_u8(kp, 0xff, KEYP_IMR1);
- free_irq(kp->irq, NULL);
+ free_irq(kp->irq, kp);
err2:
input_unregister_device(input);
input = NULL;
@@ -438,7 +438,6 @@ static int twl4030_kp_remove(struct platform_device *pdev)
free_irq(kp->irq, kp);
input_unregister_device(kp->input);
- platform_set_drvdata(pdev, NULL);
kfree(kp);
return 0;
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
index ee163bee8cce..7b039162a3f8 100644
--- a/drivers/input/keyboard/w90p910_keypad.c
+++ b/drivers/input/keyboard/w90p910_keypad.c
@@ -221,7 +221,7 @@ static int w90p910_keypad_probe(struct platform_device *pdev)
return 0;
failed_free_irq:
- free_irq(irq, pdev);
+ free_irq(irq, keypad);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
@@ -239,7 +239,7 @@ static int w90p910_keypad_remove(struct platform_device *pdev)
struct w90p910_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
- free_irq(keypad->irq, pdev);
+ free_irq(keypad->irq, keypad);
clk_put(keypad->clk);
@@ -249,7 +249,6 @@ static int w90p910_keypad_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index bb698e1f9e42..0b541cdf9b8e 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -637,4 +637,14 @@ config INPUT_XEN_KBDDEV_FRONTEND
To compile this driver as a module, choose M here: the
module will be called xen-kbdfront.
+config INPUT_SIRFSOC_ONKEY
+ bool "CSR SiRFSoC power on/off/suspend key support"
+ depends on ARCH_SIRF && OF
+ default y
+ help
+ Say Y here if you want to support for the SiRFSoC power on/off/suspend key
+ in Linux, after you press the onkey, system will suspend.
+
+ If unsure, say N.
+
endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index d7fc17f11d77..829de43a2427 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
+obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c
index 2f090b46e716..f2fbdd88ed20 100644
--- a/drivers/input/misc/ab8500-ponkey.c
+++ b/drivers/input/misc/ab8500-ponkey.c
@@ -127,8 +127,6 @@ static int ab8500_ponkey_remove(struct platform_device *pdev)
input_unregister_device(ponkey->idev);
kfree(ponkey);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c
index a6666e142a91..cd139cb17e32 100644
--- a/drivers/input/misc/bfin_rotary.c
+++ b/drivers/input/misc/bfin_rotary.c
@@ -208,7 +208,6 @@ static int bfin_rotary_remove(struct platform_device *pdev)
peripheral_free_list(per_cnt);
kfree(rotary);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c
index ee6ae3a00174..a0af8b2506ce 100644
--- a/drivers/input/misc/da9055_onkey.c
+++ b/drivers/input/misc/da9055_onkey.c
@@ -36,7 +36,7 @@ static void da9055_onkey_query(struct da9055_onkey *onkey)
} else {
key_stat &= DA9055_NOKEY_STS;
/*
- * Onkey status bit is cleared when onkey button is relased.
+ * Onkey status bit is cleared when onkey button is released.
*/
if (!key_stat) {
input_report_key(onkey->input, KEY_POWER, 0);
diff --git a/drivers/input/misc/gpio_tilt_polled.c b/drivers/input/misc/gpio_tilt_polled.c
index da05cca8b562..714c68369134 100644
--- a/drivers/input/misc/gpio_tilt_polled.c
+++ b/drivers/input/misc/gpio_tilt_polled.c
@@ -184,8 +184,6 @@ static int gpio_tilt_polled_remove(struct platform_device *pdev)
struct gpio_tilt_polled_dev *tdev = platform_get_drvdata(pdev);
const struct gpio_tilt_platform_data *pdata = tdev->pdata;
- platform_set_drvdata(pdev, NULL);
-
input_unregister_polled_device(tdev->poll_dev);
input_free_polled_device(tdev->poll_dev);
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 6ab3decc86e6..f34beb228d36 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -125,7 +125,7 @@ static int ixp4xx_spkr_probe(struct platform_device *dev)
return 0;
err_free_irq:
- free_irq(IRQ_IXP4XX_TIMER2, dev);
+ free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
err_free_device:
input_free_device(input_dev);
@@ -138,13 +138,12 @@ static int ixp4xx_spkr_remove(struct platform_device *dev)
unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
input_unregister_device(input_dev);
- platform_set_drvdata(dev, NULL);
/* turn the speaker off */
disable_irq(IRQ_IXP4XX_TIMER2);
ixp4xx_spkr_control(pin, 0);
- free_irq(IRQ_IXP4XX_TIMER2, dev);
+ free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
return 0;
}
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index b40ee4b47f4f..def21dc84522 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -85,7 +85,6 @@ static int m68kspkr_remove(struct platform_device *dev)
struct input_dev *input_dev = platform_get_drvdata(dev);
input_unregister_device(input_dev);
- platform_set_drvdata(dev, NULL);
/* turn off the speaker */
m68kspkr_event(NULL, EV_SND, SND_BELL, 0);
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index f9179b2585a9..eef41cfc054d 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -148,8 +148,6 @@ static int max8925_onkey_remove(struct platform_device *pdev)
input_unregister_device(info->idev);
kfree(info);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index 0906ca593d5f..d0277a7b1579 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -250,7 +250,6 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev)
input_unregister_device(priv->pwr);
kfree(priv);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 199db78acc4f..7288b267613d 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -100,7 +100,6 @@ static int pcspkr_remove(struct platform_device *dev)
struct input_dev *pcspkr_dev = platform_get_drvdata(dev);
input_unregister_device(pcspkr_dev);
- platform_set_drvdata(dev, NULL);
/* turn off the speaker */
pcspkr_event(NULL, EV_SND, SND_BELL, 0);
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index a9da65e41c5b..ec086f6f3cc3 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -249,8 +249,6 @@ static int pm8xxx_vib_remove(struct platform_device *pdev)
input_unregister_device(vib->vib_input_dev);
kfree(vib);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 4b811be73974..b49b738aa9c6 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -175,9 +175,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev)
return 0;
free_press_irq:
- free_irq(key_press_irq, NULL);
+ free_irq(key_press_irq, pwrkey);
unreg_input_dev:
- platform_set_drvdata(pdev, NULL);
input_unregister_device(pwr);
pwr = NULL;
free_input_dev:
@@ -198,7 +197,6 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev)
free_irq(key_press_irq, pwrkey);
free_irq(key_release_irq, pwrkey);
input_unregister_device(pwrkey->pwr);
- platform_set_drvdata(pdev, NULL);
kfree(pwrkey);
return 0;
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 0808868461de..a37f0c909aba 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -133,7 +133,6 @@ static int pwm_beeper_remove(struct platform_device *pdev)
{
struct pwm_beeper *beeper = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(beeper->input);
pwm_disable(beeper->pwm);
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index aff47b2c38ff..5b1aff825138 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -317,8 +317,6 @@ static int rotary_encoder_remove(struct platform_device *pdev)
if (!dev_get_platdata(&pdev->dev))
kfree(pdata);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c
index ad6415ceaf5f..95cf299ef9a3 100644
--- a/drivers/input/misc/sgi_btns.c
+++ b/drivers/input/misc/sgi_btns.c
@@ -128,7 +128,7 @@ static int sgi_buttons_probe(struct platform_device *pdev)
__clear_bit(KEY_RESERVED, input->keybit);
bdev->poll_dev = poll_dev;
- dev_set_drvdata(&pdev->dev, bdev);
+ platform_set_drvdata(pdev, bdev);
error = input_register_polled_device(poll_dev);
if (error)
@@ -139,19 +139,16 @@ static int sgi_buttons_probe(struct platform_device *pdev)
err_free_mem:
input_free_polled_device(poll_dev);
kfree(bdev);
- dev_set_drvdata(&pdev->dev, NULL);
return error;
}
static int sgi_buttons_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct buttons_dev *bdev = dev_get_drvdata(dev);
+ struct buttons_dev *bdev = platform_get_drvdata(pdev);
input_unregister_polled_device(bdev->poll_dev);
input_free_polled_device(bdev->poll_dev);
kfree(bdev);
- dev_set_drvdata(dev, NULL);
return 0;
}
diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
new file mode 100644
index 000000000000..0621c367049a
--- /dev/null
+++ b/drivers/input/misc/sirfsoc-onkey.c
@@ -0,0 +1,165 @@
+/*
+ * Power key driver for SiRF PrimaII
+ *
+ * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/rtc/sirfsoc_rtciobrg.h>
+#include <linux/of.h>
+
+struct sirfsoc_pwrc_drvdata {
+ u32 pwrc_base;
+ struct input_dev *input;
+};
+
+#define PWRC_ON_KEY_BIT (1 << 0)
+
+#define PWRC_INT_STATUS 0xc
+#define PWRC_INT_MASK 0x10
+
+static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
+{
+ struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
+ u32 int_status;
+
+ int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
+ PWRC_INT_STATUS);
+ sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
+ pwrcdrv->pwrc_base + PWRC_INT_STATUS);
+
+ /*
+ * For a typical Linux system, we report KEY_SUSPEND to trigger apm-power.c
+ * to queue a SUSPEND APM event
+ */
+ input_event(pwrcdrv->input, EV_PWR, KEY_SUSPEND, 1);
+ input_sync(pwrcdrv->input);
+
+ /*
+ * Todo: report KEY_POWER event for Android platforms, Android PowerManager
+ * will handle the suspend and powerdown/hibernation
+ */
+
+ return IRQ_HANDLED;
+}
+
+static const struct of_device_id sirfsoc_pwrc_of_match[] = {
+ { .compatible = "sirf,prima2-pwrc" },
+ {},
+}
+MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
+
+static int sirfsoc_pwrc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sirfsoc_pwrc_drvdata *pwrcdrv;
+ int irq;
+ int error;
+
+ pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
+ GFP_KERNEL);
+ if (!pwrcdrv) {
+ dev_info(&pdev->dev, "Not enough memory for the device data\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * we can't use of_iomap because pwrc is not mapped in memory,
+ * the so-called base address is only offset in rtciobrg
+ */
+ error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to find base address of pwrc node in dtb\n");
+ return error;
+ }
+
+ pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
+ if (!pwrcdrv->input)
+ return -ENOMEM;
+
+ pwrcdrv->input->name = "sirfsoc pwrckey";
+ pwrcdrv->input->phys = "pwrc/input0";
+ pwrcdrv->input->evbit[0] = BIT_MASK(EV_PWR);
+
+ irq = platform_get_irq(pdev, 0);
+ error = devm_request_irq(&pdev->dev, irq,
+ sirfsoc_pwrc_isr, IRQF_SHARED,
+ "sirfsoc_pwrc_int", pwrcdrv);
+ if (error) {
+ dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
+ irq, error);
+ return error;
+ }
+
+ sirfsoc_rtc_iobrg_writel(
+ sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK) |
+ PWRC_ON_KEY_BIT,
+ pwrcdrv->pwrc_base + PWRC_INT_MASK);
+
+ error = input_register_device(pwrcdrv->input);
+ if (error) {
+ dev_err(&pdev->dev,
+ "unable to register input device, error: %d\n",
+ error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, pwrcdrv);
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+}
+
+static int sirfsoc_pwrc_remove(struct platform_device *pdev)
+{
+ device_init_wakeup(&pdev->dev, 0);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pwrc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sirfsoc_pwrc_drvdata *pwrcdrv = platform_get_drvdata(pdev);
+
+ /*
+ * Do not mask pwrc interrupt as we want pwrc work as a wakeup source
+ * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
+ */
+ sirfsoc_rtc_iobrg_writel(
+ sirfsoc_rtc_iobrg_readl(
+ pwrcdrv->pwrc_base + PWRC_INT_MASK) | PWRC_ON_KEY_BIT,
+ pwrcdrv->pwrc_base + PWRC_INT_MASK);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, pwrc_resume);
+
+static struct platform_driver sirfsoc_pwrc_driver = {
+ .probe = sirfsoc_pwrc_probe,
+ .remove = sirfsoc_pwrc_remove,
+ .driver = {
+ .name = "sirfsoc-pwrc",
+ .owner = THIS_MODULE,
+ .pm = &sirfsoc_pwrc_pm_ops,
+ .of_match_table = of_match_ptr(sirfsoc_pwrc_of_match),
+ }
+};
+
+module_platform_driver(sirfsoc_pwrc_driver);
+
+MODULE_LICENSE("GPLv2");
+MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
+MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
+MODULE_ALIAS("platform:sirfsoc-pwrc");
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index a53586a7fbdb..65fd3150919b 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -175,7 +175,7 @@ static int sparcspkr_probe(struct device *dev)
static void sparcspkr_shutdown(struct platform_device *dev)
{
- struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
+ struct sparcspkr_state *state = platform_get_drvdata(dev);
struct input_dev *input_dev = state->input_dev;
/* turn off the speaker */
@@ -211,7 +211,7 @@ static int bbc_beep_probe(struct platform_device *op)
if (!info->regs)
goto out_free;
- dev_set_drvdata(&op->dev, state);
+ platform_set_drvdata(op, state);
err = sparcspkr_probe(&op->dev);
if (err)
@@ -220,7 +220,6 @@ static int bbc_beep_probe(struct platform_device *op)
return 0;
out_clear_drvdata:
- dev_set_drvdata(&op->dev, NULL);
of_iounmap(&op->resource[0], info->regs, 6);
out_free:
@@ -231,7 +230,7 @@ out_err:
static int bbc_remove(struct platform_device *op)
{
- struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
+ struct sparcspkr_state *state = platform_get_drvdata(op);
struct input_dev *input_dev = state->input_dev;
struct bbc_beep_info *info = &state->u.bbc;
@@ -242,7 +241,6 @@ static int bbc_remove(struct platform_device *op)
of_iounmap(&op->resource[0], info->regs, 6);
- dev_set_drvdata(&op->dev, NULL);
kfree(state);
return 0;
@@ -290,7 +288,7 @@ static int grover_beep_probe(struct platform_device *op)
if (!info->enable_reg)
goto out_unmap_freq_regs;
- dev_set_drvdata(&op->dev, state);
+ platform_set_drvdata(op, state);
err = sparcspkr_probe(&op->dev);
if (err)
@@ -299,7 +297,6 @@ static int grover_beep_probe(struct platform_device *op)
return 0;
out_clear_drvdata:
- dev_set_drvdata(&op->dev, NULL);
of_iounmap(&op->resource[3], info->enable_reg, 1);
out_unmap_freq_regs:
@@ -312,7 +309,7 @@ out_err:
static int grover_remove(struct platform_device *op)
{
- struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
+ struct sparcspkr_state *state = platform_get_drvdata(op);
struct grover_beep_info *info = &state->u.grover;
struct input_dev *input_dev = state->input_dev;
@@ -324,7 +321,6 @@ static int grover_remove(struct platform_device *op)
of_iounmap(&op->resource[3], info->enable_reg, 1);
of_iounmap(&op->resource[2], info->freq_regs, 2);
- dev_set_drvdata(&op->dev, NULL);
kfree(state);
return 0;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index b55d5af217a7..62ec52b2e347 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -133,7 +133,6 @@ static int __exit amimouse_remove(struct platform_device *pdev)
{
struct input_dev *dev = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(dev);
return 0;
}
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 2baff1b79a55..4ef4d5e198ae 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -88,6 +88,10 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259
#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a
#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b
+/* MacbookAir6,2 (unibody, June 2013) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0291
+#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0292
+#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0293
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -145,6 +149,10 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
+ /* MacbookAir6,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING8_JIS),
/* Terminating entry */
{}
};
@@ -172,15 +180,18 @@ struct bt_data {
/* trackpad header types */
enum tp_type {
TYPE1, /* plain trackpad */
- TYPE2 /* button integrated in trackpad */
+ TYPE2, /* button integrated in trackpad */
+ TYPE3 /* additional header fields since June 2013 */
};
/* trackpad finger data offsets, le16-aligned */
#define FINGER_TYPE1 (13 * sizeof(__le16))
#define FINGER_TYPE2 (15 * sizeof(__le16))
+#define FINGER_TYPE3 (19 * sizeof(__le16))
/* trackpad button data offsets */
#define BUTTON_TYPE2 15
+#define BUTTON_TYPE3 23
/* list of device capability bits */
#define HAS_INTEGRATED_BUTTON 1
@@ -400,6 +411,19 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ SN_COORD, -150, 6730 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING8_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING8_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0, sizeof(struct bt_data),
+ 0x83, TYPE3, FINGER_TYPE3, FINGER_TYPE3 + SIZEOF_ALL_FINGERS,
+ { SN_PRESSURE, 0, 300 },
+ { SN_WIDTH, 0, 2048 },
+ { SN_COORD, -4620, 5140 },
+ { SN_COORD, -150, 6600 },
+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+ },
{}
};
@@ -557,6 +581,9 @@ static int report_tp_state(struct bcm5974 *dev, int size)
input_report_key(input, BTN_LEFT, ibt);
}
+ if (c->tp_type == TYPE3)
+ input_report_key(input, BTN_LEFT, dev->tp_data[BUTTON_TYPE3]);
+
input_sync(input);
return 0;
@@ -572,9 +599,14 @@ static int report_tp_state(struct bcm5974 *dev, int size)
static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
{
- char *data = kmalloc(8, GFP_KERNEL);
int retval = 0, size;
+ char *data;
+
+ /* Type 3 does not require a mode switch */
+ if (dev->cfg.tp_type == TYPE3)
+ return 0;
+ data = kmalloc(8, GFP_KERNEL);
if (!data) {
dev_err(&dev->intf->dev, "out of memory\n");
retval = -ENOMEM;
diff --git a/drivers/input/mouse/gpio_mouse.c b/drivers/input/mouse/gpio_mouse.c
index 532eaca4cc56..6b44413f54e3 100644
--- a/drivers/input/mouse/gpio_mouse.c
+++ b/drivers/input/mouse/gpio_mouse.c
@@ -138,7 +138,6 @@ static int gpio_mouse_probe(struct platform_device *pdev)
out_free_polldev:
input_free_polled_device(input_poll);
- platform_set_drvdata(pdev, NULL);
out_free_gpios:
while (--i >= 0) {
@@ -165,8 +164,6 @@ static int gpio_mouse_remove(struct platform_device *pdev)
gpio_free(pin);
}
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index 8e1b98ea5648..0b8d33591dee 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -287,7 +287,7 @@ static int navpoint_probe(struct platform_device *pdev)
return 0;
err_free_irq:
- free_irq(ssp->irq, &pdev->dev);
+ free_irq(ssp->irq, navpoint);
err_free_mem:
input_free_device(input);
kfree(navpoint);
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 1bda828f4b55..94c17c28d268 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -256,4 +256,14 @@ config SERIO_APBPS2
To compile this driver as a module, choose M here: the module will
be called apbps2.
+config SERIO_OLPC_APSP
+ tristate "OLPC AP-SP input support"
+ depends on OF
+ help
+ Say Y here if you want support for the keyboard and touchpad included
+ in the OLPC XO-1.75 and XO-4 laptops.
+
+ To compile this driver as a module, choose M here: the module will
+ be called olpc_apsp.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 8edb36c2cdb4..12298b1c0e71 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -27,3 +27,4 @@ obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
+obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
index 479ce5fe8955..a0a2657e31ff 100644
--- a/drivers/input/serio/altera_ps2.c
+++ b/drivers/input/serio/altera_ps2.c
@@ -163,7 +163,6 @@ static int altera_ps2_remove(struct platform_device *pdev)
{
struct ps2if *ps2if = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
serio_unregister_port(ps2if->io);
free_irq(ps2if->irq, ps2if);
iounmap(ps2if->base);
diff --git a/drivers/input/serio/at32psif.c b/drivers/input/serio/at32psif.c
index 190ce35af7df..3290b287ac4b 100644
--- a/drivers/input/serio/at32psif.c
+++ b/drivers/input/serio/at32psif.c
@@ -314,8 +314,6 @@ static int __exit psif_remove(struct platform_device *pdev)
clk_put(psif->pclk);
kfree(psif);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c
new file mode 100644
index 000000000000..818aa466b5d2
--- /dev/null
+++ b/drivers/input/serio/olpc_apsp.c
@@ -0,0 +1,287 @@
+/*
+ * OLPC serio driver for multiplexed input from Marvell MMP security processor
+ *
+ * Copyright (C) 2011-2013 One Laptop Per Child
+ *
+ * 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/interrupt.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+/*
+ * The OLPC XO-1.75 and XO-4 laptops do not have a hardware PS/2 controller.
+ * Instead, the OLPC firmware runs a bit-banging PS/2 implementation on an
+ * otherwise-unused slow processor which is included in the Marvell MMP2/MMP3
+ * SoC, known as the "Security Processor" (SP) or "Wireless Trusted Module"
+ * (WTM). This firmware then reports its results via the WTM registers,
+ * which we read from the Application Processor (AP, i.e. main CPU) in this
+ * driver.
+ *
+ * On the hardware side we have a PS/2 mouse and an AT keyboard, the data
+ * is multiplexed through this system. We create a serio port for each one,
+ * and demultiplex the data accordingly.
+ */
+
+/* WTM register offsets */
+#define SECURE_PROCESSOR_COMMAND 0x40
+#define COMMAND_RETURN_STATUS 0x80
+#define COMMAND_FIFO_STATUS 0xc4
+#define PJ_RST_INTERRUPT 0xc8
+#define PJ_INTERRUPT_MASK 0xcc
+
+/*
+ * The upper byte of SECURE_PROCESSOR_COMMAND and COMMAND_RETURN_STATUS is
+ * used to identify which port (device) is being talked to. The lower byte
+ * is the data being sent/received.
+ */
+#define PORT_MASK 0xff00
+#define DATA_MASK 0x00ff
+#define PORT_SHIFT 8
+#define KEYBOARD_PORT 0
+#define TOUCHPAD_PORT 1
+
+/* COMMAND_FIFO_STATUS */
+#define CMD_CNTR_MASK 0x7 /* Number of pending/unprocessed commands */
+#define MAX_PENDING_CMDS 4 /* from device specs */
+
+/* PJ_RST_INTERRUPT */
+#define SP_COMMAND_COMPLETE_RESET 0x1
+
+/* PJ_INTERRUPT_MASK */
+#define INT_0 (1 << 0)
+
+/* COMMAND_FIFO_STATUS */
+#define CMD_STS_MASK 0x100
+
+struct olpc_apsp {
+ struct device *dev;
+ struct serio *kbio;
+ struct serio *padio;
+ void __iomem *base;
+ int open_count;
+ int irq;
+};
+
+static int olpc_apsp_write(struct serio *port, unsigned char val)
+{
+ struct olpc_apsp *priv = port->port_data;
+ unsigned int i;
+ u32 which = 0;
+
+ if (port == priv->padio)
+ which = TOUCHPAD_PORT << PORT_SHIFT;
+ else
+ which = KEYBOARD_PORT << PORT_SHIFT;
+
+ dev_dbg(priv->dev, "olpc_apsp_write which=%x val=%x\n", which, val);
+ for (i = 0; i < 50; i++) {
+ u32 sts = readl(priv->base + COMMAND_FIFO_STATUS);
+ if ((sts & CMD_CNTR_MASK) < MAX_PENDING_CMDS) {
+ writel(which | val,
+ priv->base + SECURE_PROCESSOR_COMMAND);
+ return 0;
+ }
+ /* SP busy. This has not been seen in practice. */
+ mdelay(1);
+ }
+
+ dev_dbg(priv->dev, "olpc_apsp_write timeout, status=%x\n",
+ readl(priv->base + COMMAND_FIFO_STATUS));
+
+ return -ETIMEDOUT;
+}
+
+static irqreturn_t olpc_apsp_rx(int irq, void *dev_id)
+{
+ struct olpc_apsp *priv = dev_id;
+ unsigned int w, tmp;
+ struct serio *serio;
+
+ /*
+ * Write 1 to PJ_RST_INTERRUPT to acknowledge and clear the interrupt
+ * Write 0xff00 to SECURE_PROCESSOR_COMMAND.
+ */
+ tmp = readl(priv->base + PJ_RST_INTERRUPT);
+ if (!(tmp & SP_COMMAND_COMPLETE_RESET)) {
+ dev_warn(priv->dev, "spurious interrupt?\n");
+ return IRQ_NONE;
+ }
+
+ w = readl(priv->base + COMMAND_RETURN_STATUS);
+ dev_dbg(priv->dev, "olpc_apsp_rx %x\n", w);
+
+ if (w >> PORT_SHIFT == KEYBOARD_PORT)
+ serio = priv->kbio;
+ else
+ serio = priv->padio;
+
+ serio_interrupt(serio, w & DATA_MASK, 0);
+
+ /* Ack and clear interrupt */
+ writel(tmp | SP_COMMAND_COMPLETE_RESET, priv->base + PJ_RST_INTERRUPT);
+ writel(PORT_MASK, priv->base + SECURE_PROCESSOR_COMMAND);
+
+ pm_wakeup_event(priv->dev, 1000);
+ return IRQ_HANDLED;
+}
+
+static int olpc_apsp_open(struct serio *port)
+{
+ struct olpc_apsp *priv = port->port_data;
+ unsigned int tmp;
+
+ if (priv->open_count++ == 0) {
+ /* Enable interrupt 0 by clearing its bit */
+ tmp = readl(priv->base + PJ_INTERRUPT_MASK);
+ writel(tmp & ~INT_0, priv->base + PJ_INTERRUPT_MASK);
+ }
+
+ return 0;
+}
+
+static void olpc_apsp_close(struct serio *port)
+{
+ struct olpc_apsp *priv = port->port_data;
+ unsigned int tmp;
+
+ if (--priv->open_count == 0) {
+ /* Disable interrupt 0 */
+ tmp = readl(priv->base + PJ_INTERRUPT_MASK);
+ writel(tmp | INT_0, priv->base + PJ_INTERRUPT_MASK);
+ }
+}
+
+static int olpc_apsp_probe(struct platform_device *pdev)
+{
+ struct serio *kb_serio, *pad_serio;
+ struct olpc_apsp *priv;
+ struct resource *res;
+ struct device_node *np;
+ unsigned long l;
+ int error;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct olpc_apsp), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ np = pdev->dev.of_node;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base)) {
+ dev_err(&pdev->dev, "Failed to map WTM registers\n");
+ return PTR_ERR(priv->base);
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0)
+ return priv->irq;
+
+ l = readl(priv->base + COMMAND_FIFO_STATUS);
+ if (!(l & CMD_STS_MASK)) {
+ dev_err(&pdev->dev, "SP cannot accept commands.\n");
+ return -EIO;
+ }
+
+ /* KEYBOARD */
+ kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!kb_serio)
+ return -ENOMEM;
+ kb_serio->id.type = SERIO_8042_XL;
+ kb_serio->write = olpc_apsp_write;
+ kb_serio->open = olpc_apsp_open;
+ kb_serio->close = olpc_apsp_close;
+ kb_serio->port_data = priv;
+ kb_serio->dev.parent = &pdev->dev;
+ strlcpy(kb_serio->name, "sp keyboard", sizeof(kb_serio->name));
+ strlcpy(kb_serio->phys, "sp/serio0", sizeof(kb_serio->phys));
+ priv->kbio = kb_serio;
+ serio_register_port(kb_serio);
+
+ /* TOUCHPAD */
+ pad_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!pad_serio) {
+ error = -ENOMEM;
+ goto err_pad;
+ }
+ pad_serio->id.type = SERIO_8042;
+ pad_serio->write = olpc_apsp_write;
+ pad_serio->open = olpc_apsp_open;
+ pad_serio->close = olpc_apsp_close;
+ pad_serio->port_data = priv;
+ pad_serio->dev.parent = &pdev->dev;
+ strlcpy(pad_serio->name, "sp touchpad", sizeof(pad_serio->name));
+ strlcpy(pad_serio->phys, "sp/serio1", sizeof(pad_serio->phys));
+ priv->padio = pad_serio;
+ serio_register_port(pad_serio);
+
+ error = request_irq(priv->irq, olpc_apsp_rx, 0, "olpc-apsp", priv);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to request IRQ\n");
+ goto err_irq;
+ }
+
+ priv->dev = &pdev->dev;
+ device_init_wakeup(priv->dev, 1);
+ platform_set_drvdata(pdev, priv);
+
+ dev_dbg(&pdev->dev, "probed successfully.\n");
+ return 0;
+
+err_irq:
+ serio_unregister_port(pad_serio);
+err_pad:
+ serio_unregister_port(kb_serio);
+ return error;
+}
+
+static int olpc_apsp_remove(struct platform_device *pdev)
+{
+ struct olpc_apsp *priv = platform_get_drvdata(pdev);
+
+ free_irq(priv->irq, priv);
+
+ serio_unregister_port(priv->kbio);
+ serio_unregister_port(priv->padio);
+
+ return 0;
+}
+
+static struct of_device_id olpc_apsp_dt_ids[] = {
+ { .compatible = "olpc,ap-sp", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids);
+
+static struct platform_driver olpc_apsp_driver = {
+ .probe = olpc_apsp_probe,
+ .remove = olpc_apsp_remove,
+ .driver = {
+ .name = "olpc-apsp",
+ .owner = THIS_MODULE,
+ .of_match_table = olpc_apsp_dt_ids,
+ },
+};
+
+MODULE_DESCRIPTION("OLPC AP-SP serio driver");
+MODULE_LICENSE("GPL");
+module_platform_driver(olpc_apsp_driver);
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index 436a3433f8e5..7a65a1bc5226 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -181,7 +181,6 @@ static int q40kbd_remove(struct platform_device *pdev)
free_irq(Q40_IRQ_KEYBOARD, q40kbd);
kfree(q40kbd);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index 17be85948ffd..4b7662a17ae9 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -349,8 +349,6 @@ static int xps2_of_remove(struct platform_device *of_dev)
kfree(drvdata);
- platform_set_drvdata(of_dev, NULL);
-
return 0;
}
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index c7068942ebe8..f7de14a268bf 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -237,7 +237,7 @@ static int pm860x_touch_probe(struct platform_device *pdev)
touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL);
if (touch == NULL)
return -ENOMEM;
- dev_set_drvdata(&pdev->dev, touch);
+ platform_set_drvdata(pdev, touch);
touch->idev = input_allocate_device();
if (touch->idev == NULL) {
@@ -299,7 +299,6 @@ static int pm860x_touch_remove(struct platform_device *pdev)
input_unregister_device(touch->idev);
free_irq(touch->irq, touch);
- platform_set_drvdata(pdev, NULL);
kfree(touch);
return 0;
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index f9a5fd89bc02..3b9758b5f4d7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -167,6 +167,36 @@ config TOUCHSCREEN_CYTTSP_SPI
To compile this driver as a module, choose M here: the
module will be called cyttsp_spi.
+config TOUCHSCREEN_CYTTSP4_CORE
+ tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
+ help
+ Core driver for Cypress TrueTouch(tm) Standard Product
+ Generation4 touchscreen controllers.
+
+ Say Y here if you have a Cypress Gen4 touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here.
+
+config TOUCHSCREEN_CYTTSP4_I2C
+ tristate "support I2C bus connection"
+ depends on TOUCHSCREEN_CYTTSP4_CORE && I2C
+ help
+ Say Y here if the touchscreen is connected via I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cyttsp4_i2c.
+
+config TOUCHSCREEN_CYTTSP4_SPI
+ tristate "support SPI bus connection"
+ depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER
+ help
+ Say Y here if the touchscreen is connected via SPI bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cyttsp4_spi.
+
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
@@ -879,6 +909,7 @@ config TOUCHSCREEN_STMPE
config TOUCHSCREEN_TPS6507X
tristate "TPS6507x based touchscreens"
depends on I2C
+ select INPUT_POLLDEV
help
Say Y here if you have a TPS6507x based touchscreen
controller.
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 6bfbeab67c9f..f5216c1bf53e 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -18,8 +18,11 @@ obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c
index 2c1e46b7e45b..268a35e55d7f 100644
--- a/drivers/input/touchscreen/atmel-wm97xx.c
+++ b/drivers/input/touchscreen/atmel-wm97xx.c
@@ -372,7 +372,6 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev)
err_irq:
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
err:
- platform_set_drvdata(pdev, NULL);
kfree(atmel_wm97xx);
return ret;
}
@@ -386,7 +385,6 @@ static int __exit atmel_wm97xx_remove(struct platform_device *pdev)
free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx);
del_timer_sync(&atmel_wm97xx->pen_timer);
wm97xx_unregister_mach_ops(wm);
- platform_set_drvdata(pdev, NULL);
kfree(atmel_wm97xx);
return 0;
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
index 95f6785a94b0..bddabc595077 100644
--- a/drivers/input/touchscreen/atmel_tsadcc.c
+++ b/drivers/input/touchscreen/atmel_tsadcc.c
@@ -183,10 +183,13 @@ static int atmel_tsadcc_probe(struct platform_device *pdev)
struct input_dev *input_dev;
struct resource *res;
struct at91_tsadcc_data *pdata = pdev->dev.platform_data;
- int err = 0;
+ int err;
unsigned int prsc;
unsigned int reg;
+ if (!pdata)
+ return -EINVAL;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no mmio resource defined.\n");
@@ -265,9 +268,6 @@ static int atmel_tsadcc_probe(struct platform_device *pdev)
prsc = clk_get_rate(ts_dev->clk);
dev_info(&pdev->dev, "Master clock is set at: %d Hz\n", prsc);
- if (!pdata)
- goto err_fail;
-
if (!pdata->adc_clock)
pdata->adc_clock = ADC_DEFAULT_CLOCK;
@@ -325,7 +325,7 @@ err_free_mem:
static int atmel_tsadcc_remove(struct platform_device *pdev)
{
- struct atmel_tsadcc *ts_dev = dev_get_drvdata(&pdev->dev);
+ struct atmel_tsadcc *ts_dev = platform_get_drvdata(pdev);
struct resource *res;
free_irq(ts_dev->irq, ts_dev);
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
new file mode 100644
index 000000000000..edcf7993034b
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -0,0 +1,2166 @@
+/*
+ * cyttsp4_core.c
+ * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
+ *
+ */
+
+#include "cyttsp4_core.h"
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+/* Timeout in ms. */
+#define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT 500
+#define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT 5000
+#define CY_CORE_MODE_CHANGE_TIMEOUT 1000
+#define CY_CORE_RESET_AND_WAIT_TIMEOUT 500
+#define CY_CORE_WAKEUP_TIMEOUT 500
+
+#define CY_CORE_STARTUP_RETRY_COUNT 3
+
+static const u8 ldr_exit[] = {
+ 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
+};
+
+static const u8 ldr_err_app[] = {
+ 0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17
+};
+
+static inline size_t merge_bytes(u8 high, u8 low)
+{
+ return (high << 8) + low;
+}
+
+#ifdef VERBOSE_DEBUG
+static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size,
+ const char *data_name)
+{
+ int i, k;
+ const char fmt[] = "%02X ";
+ int max;
+
+ if (!size)
+ return;
+
+ max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
+
+ pr_buf[0] = 0;
+ for (i = k = 0; i < size && k < max; i++, k += 3)
+ scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]);
+
+ dev_vdbg(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name, size - 1,
+ pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
+}
+#else
+#define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0)
+#endif
+
+static int cyttsp4_load_status_regs(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ struct device *dev = cd->dev;
+ int rc;
+
+ rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size,
+ si->xy_mode);
+ if (rc < 0)
+ dev_err(dev, "%s: fail read mode regs r=%d\n",
+ __func__, rc);
+ else
+ cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode,
+ si->si_ofs.mode_size, "xy_mode");
+
+ return rc;
+}
+
+static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode)
+{
+ u8 cmd = mode ^ CY_HST_TOGGLE;
+ int rc;
+
+ /*
+ * Mode change issued, handshaking now will cause endless mode change
+ * requests, for sync mode modechange will do same with handshake
+ * */
+ if (mode & CY_HST_MODE_CHANGE)
+ return 0;
+
+ rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
+ if (rc < 0)
+ dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd)
+{
+ u8 cmd = CY_HST_RESET;
+ int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n",
+ __func__);
+ return rc;
+ }
+ return 0;
+}
+
+static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd)
+{
+ if (cd->cpdata->xres) {
+ cd->cpdata->xres(cd->cpdata, cd->dev);
+ dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__);
+ return 0;
+ }
+ dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__);
+ return -ENOSYS;
+}
+
+static int cyttsp4_hw_reset(struct cyttsp4 *cd)
+{
+ int rc = cyttsp4_hw_hard_reset(cd);
+ if (rc == -ENOSYS)
+ rc = cyttsp4_hw_soft_reset(cd);
+ return rc;
+}
+
+/*
+ * Gets number of bits for a touch filed as parameter,
+ * sets maximum value for field which is used as bit mask
+ * and returns number of bytes required for that field
+ */
+static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max)
+{
+ *max = 1UL << nbits;
+ return (nbits + 7) / 8;
+}
+
+static int cyttsp4_si_data_offsets(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data),
+ &si->si_data);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Print sysinfo data offsets */
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data,
+ sizeof(si->si_data), "sysinfo_data_offsets");
+
+ /* convert sysinfo data offset bytes into integers */
+
+ si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
+ si->si_data.map_szl);
+ si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
+ si->si_data.map_szl);
+ si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh,
+ si->si_data.cydata_ofsl);
+ si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh,
+ si->si_data.test_ofsl);
+ si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh,
+ si->si_data.pcfg_ofsl);
+ si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh,
+ si->si_data.opcfg_ofsl);
+ si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh,
+ si->si_data.ddata_ofsl);
+ si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh,
+ si->si_data.mdata_ofsl);
+ return rc;
+}
+
+static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ int read_offset;
+ int mfgid_sz, calc_mfgid_sz;
+ void *p;
+ int rc;
+
+ si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
+ dev_dbg(cd->dev, "%s: cydata size: %Zd\n", __func__,
+ si->si_ofs.cydata_size);
+
+ p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
+ if (p == NULL) {
+ dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__);
+ return -ENOMEM;
+ }
+ si->si_ptrs.cydata = p;
+
+ read_offset = si->si_ofs.cydata_ofs;
+
+ /* Read the CYDA registers up to MFGID field */
+ rc = cyttsp4_adap_read(cd, read_offset,
+ offsetof(struct cyttsp4_cydata, mfgid_sz)
+ + sizeof(si->si_ptrs.cydata->mfgid_sz),
+ si->si_ptrs.cydata);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read cydata r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ /* Check MFGID size */
+ mfgid_sz = si->si_ptrs.cydata->mfgid_sz;
+ calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata);
+ if (mfgid_sz != calc_mfgid_sz) {
+ dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n",
+ __func__, mfgid_sz, calc_mfgid_sz);
+ return -EINVAL;
+ }
+
+ read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz)
+ + sizeof(si->si_ptrs.cydata->mfgid_sz);
+
+ /* Read the CYDA registers for MFGID field */
+ rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz,
+ si->si_ptrs.cydata->mfg_id);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read cydata r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ read_offset += si->si_ptrs.cydata->mfgid_sz;
+
+ /* Read the rest of the CYDA registers */
+ rc = cyttsp4_adap_read(cd, read_offset,
+ sizeof(struct cyttsp4_cydata)
+ - offsetof(struct cyttsp4_cydata, cyito_idh),
+ &si->si_ptrs.cydata->cyito_idh);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read cydata r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata,
+ si->si_ofs.cydata_size, "sysinfo_cydata");
+ return rc;
+}
+
+static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ void *p;
+ int rc;
+
+ si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
+
+ p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
+ if (p == NULL) {
+ dev_err(cd->dev, "%s: fail alloc test memory\n", __func__);
+ return -ENOMEM;
+ }
+ si->si_ptrs.test = p;
+
+ rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size,
+ si->si_ptrs.test);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read test data r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf,
+ (u8 *)si->si_ptrs.test, si->si_ofs.test_size,
+ "sysinfo_test_data");
+ if (si->si_ptrs.test->post_codel &
+ CY_POST_CODEL_WDG_RST)
+ dev_info(cd->dev, "%s: %s codel=%02X\n",
+ __func__, "Reset was a WATCHDOG RESET",
+ si->si_ptrs.test->post_codel);
+
+ if (!(si->si_ptrs.test->post_codel &
+ CY_POST_CODEL_CFG_DATA_CRC_FAIL))
+ dev_info(cd->dev, "%s: %s codel=%02X\n", __func__,
+ "Config Data CRC FAIL",
+ si->si_ptrs.test->post_codel);
+
+ if (!(si->si_ptrs.test->post_codel &
+ CY_POST_CODEL_PANEL_TEST_FAIL))
+ dev_info(cd->dev, "%s: %s codel=%02X\n",
+ __func__, "PANEL TEST FAIL",
+ si->si_ptrs.test->post_codel);
+
+ dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n",
+ __func__, si->si_ptrs.test->post_codel & 0x08 ?
+ "ENABLED" : "DISABLED",
+ si->si_ptrs.test->post_codel);
+ return rc;
+}
+
+static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ void *p;
+ int rc;
+
+ si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
+
+ p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
+ if (p == NULL) {
+ rc = -ENOMEM;
+ dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+ si->si_ptrs.pcfg = p;
+
+ rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size,
+ si->si_ptrs.pcfg);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read pcfg data r=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh
+ & CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl);
+ si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh
+ & CY_PCFG_ORIGIN_X_MASK);
+ si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh
+ & CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl);
+ si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh
+ & CY_PCFG_ORIGIN_Y_MASK);
+ si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh,
+ si->si_ptrs.pcfg->max_zl);
+
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf,
+ (u8 *)si->si_ptrs.pcfg,
+ si->si_ofs.pcfg_size, "sysinfo_pcfg_data");
+ return rc;
+}
+
+static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ struct cyttsp4_tch_abs_params *tch;
+ struct cyttsp4_tch_rec_params *tch_old, *tch_new;
+ enum cyttsp4_tch_abs abs;
+ int i;
+ void *p;
+ int rc;
+
+ si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
+
+ p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
+ if (p == NULL) {
+ dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__);
+ rc = -ENOMEM;
+ goto cyttsp4_si_get_opcfg_data_exit;
+ }
+ si->si_ptrs.opcfg = p;
+
+ rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size,
+ si->si_ptrs.opcfg);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
+ __func__, rc);
+ goto cyttsp4_si_get_opcfg_data_exit;
+ }
+ si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
+ si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
+ si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) +
+ si->si_ptrs.opcfg->rep_szl;
+ si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns;
+ si->si_ofs.num_btn_regs = (si->si_ofs.num_btns +
+ CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG;
+ si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs;
+ si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0;
+ si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs &
+ CY_BYTE_OFS_MASK;
+ si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size &
+ CY_BYTE_OFS_MASK;
+
+ /* Get the old touch fields */
+ for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) {
+ tch = &si->si_ofs.tch_abs[abs];
+ tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs];
+
+ tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK;
+ tch->size = cyttsp4_bits_2_bytes(tch_old->size,
+ &tch->max);
+ tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
+ }
+
+ /* button fields */
+ si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size;
+ si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs;
+ si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size;
+
+ if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
+ /* Get the extended touch fields */
+ for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) {
+ tch = &si->si_ofs.tch_abs[abs];
+ tch_new = &si->si_ptrs.opcfg->tch_rec_new[i];
+
+ tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK;
+ tch->size = cyttsp4_bits_2_bytes(tch_new->size,
+ &tch->max);
+ tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
+ }
+ }
+
+ for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) {
+ dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__,
+ cyttsp4_tch_abs_string[abs]);
+ dev_dbg(cd->dev, "%s: ofs =%2Zd\n", __func__,
+ si->si_ofs.tch_abs[abs].ofs);
+ dev_dbg(cd->dev, "%s: siz =%2Zd\n", __func__,
+ si->si_ofs.tch_abs[abs].size);
+ dev_dbg(cd->dev, "%s: max =%2Zd\n", __func__,
+ si->si_ofs.tch_abs[abs].max);
+ dev_dbg(cd->dev, "%s: bofs=%2Zd\n", __func__,
+ si->si_ofs.tch_abs[abs].bofs);
+ }
+
+ si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1;
+ si->si_ofs.data_size = si->si_ofs.max_tchs *
+ si->si_ptrs.opcfg->tch_rec_size;
+
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
+ si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
+
+cyttsp4_si_get_opcfg_data_exit:
+ return rc;
+}
+
+static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ void *p;
+ int rc;
+
+ si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs;
+
+ p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL);
+ if (p == NULL) {
+ dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__);
+ return -ENOMEM;
+ }
+ si->si_ptrs.ddata = p;
+
+ rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size,
+ si->si_ptrs.ddata);
+ if (rc < 0)
+ dev_err(cd->dev, "%s: fail read ddata data r=%d\n",
+ __func__, rc);
+ else
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf,
+ (u8 *)si->si_ptrs.ddata,
+ si->si_ofs.ddata_size, "sysinfo_ddata");
+ return rc;
+}
+
+static int cyttsp4_si_get_mdata(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ void *p;
+ int rc;
+
+ si->si_ofs.mdata_size = si->si_ofs.map_sz - si->si_ofs.mdata_ofs;
+
+ p = krealloc(si->si_ptrs.mdata, si->si_ofs.mdata_size, GFP_KERNEL);
+ if (p == NULL) {
+ dev_err(cd->dev, "%s: fail alloc mdata memory\n", __func__);
+ return -ENOMEM;
+ }
+ si->si_ptrs.mdata = p;
+
+ rc = cyttsp4_adap_read(cd, si->si_ofs.mdata_ofs, si->si_ofs.mdata_size,
+ si->si_ptrs.mdata);
+ if (rc < 0)
+ dev_err(cd->dev, "%s: fail read mdata data r=%d\n",
+ __func__, rc);
+ else
+ cyttsp4_pr_buf(cd->dev, cd->pr_buf,
+ (u8 *)si->si_ptrs.mdata,
+ si->si_ofs.mdata_size, "sysinfo_mdata");
+ return rc;
+}
+
+static int cyttsp4_si_get_btn_data(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ int btn;
+ int num_defined_keys;
+ u16 *key_table;
+ void *p;
+ int rc = 0;
+
+ if (si->si_ofs.num_btns) {
+ si->si_ofs.btn_keys_size = si->si_ofs.num_btns *
+ sizeof(struct cyttsp4_btn);
+
+ p = krealloc(si->btn, si->si_ofs.btn_keys_size,
+ GFP_KERNEL|__GFP_ZERO);
+ if (p == NULL) {
+ dev_err(cd->dev, "%s: %s\n", __func__,
+ "fail alloc btn_keys memory");
+ return -ENOMEM;
+ }
+ si->btn = p;
+
+ if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL)
+ num_defined_keys = 0;
+ else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL)
+ num_defined_keys = 0;
+ else
+ num_defined_keys = cd->cpdata->sett
+ [CY_IC_GRPNUM_BTN_KEYS]->size;
+
+ for (btn = 0; btn < si->si_ofs.num_btns &&
+ btn < num_defined_keys; btn++) {
+ key_table = (u16 *)cd->cpdata->sett
+ [CY_IC_GRPNUM_BTN_KEYS]->data;
+ si->btn[btn].key_code = key_table[btn];
+ si->btn[btn].state = CY_BTN_RELEASED;
+ si->btn[btn].enabled = true;
+ }
+ for (; btn < si->si_ofs.num_btns; btn++) {
+ si->btn[btn].key_code = KEY_RESERVED;
+ si->btn[btn].state = CY_BTN_RELEASED;
+ si->btn[btn].enabled = true;
+ }
+
+ return rc;
+ }
+
+ si->si_ofs.btn_keys_size = 0;
+ kfree(si->btn);
+ si->btn = NULL;
+ return rc;
+}
+
+static int cyttsp4_si_get_op_data_ptrs(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ void *p;
+
+ p = krealloc(si->xy_mode, si->si_ofs.mode_size, GFP_KERNEL|__GFP_ZERO);
+ if (p == NULL)
+ return -ENOMEM;
+ si->xy_mode = p;
+
+ p = krealloc(si->xy_data, si->si_ofs.data_size, GFP_KERNEL|__GFP_ZERO);
+ if (p == NULL)
+ return -ENOMEM;
+ si->xy_data = p;
+
+ p = krealloc(si->btn_rec_data,
+ si->si_ofs.btn_rec_size * si->si_ofs.num_btns,
+ GFP_KERNEL|__GFP_ZERO);
+ if (p == NULL)
+ return -ENOMEM;
+ si->btn_rec_data = p;
+
+ return 0;
+}
+
+static void cyttsp4_si_put_log_data(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ dev_dbg(cd->dev, "%s: cydata_ofs =%4Zd siz=%4Zd\n", __func__,
+ si->si_ofs.cydata_ofs, si->si_ofs.cydata_size);
+ dev_dbg(cd->dev, "%s: test_ofs =%4Zd siz=%4Zd\n", __func__,
+ si->si_ofs.test_ofs, si->si_ofs.test_size);
+ dev_dbg(cd->dev, "%s: pcfg_ofs =%4Zd siz=%4Zd\n", __func__,
+ si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size);
+ dev_dbg(cd->dev, "%s: opcfg_ofs =%4Zd siz=%4Zd\n", __func__,
+ si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size);
+ dev_dbg(cd->dev, "%s: ddata_ofs =%4Zd siz=%4Zd\n", __func__,
+ si->si_ofs.ddata_ofs, si->si_ofs.ddata_size);
+ dev_dbg(cd->dev, "%s: mdata_ofs =%4Zd siz=%4Zd\n", __func__,
+ si->si_ofs.mdata_ofs, si->si_ofs.mdata_size);
+
+ dev_dbg(cd->dev, "%s: cmd_ofs =%4Zd\n", __func__,
+ si->si_ofs.cmd_ofs);
+ dev_dbg(cd->dev, "%s: rep_ofs =%4Zd\n", __func__,
+ si->si_ofs.rep_ofs);
+ dev_dbg(cd->dev, "%s: rep_sz =%4Zd\n", __func__,
+ si->si_ofs.rep_sz);
+ dev_dbg(cd->dev, "%s: num_btns =%4Zd\n", __func__,
+ si->si_ofs.num_btns);
+ dev_dbg(cd->dev, "%s: num_btn_regs =%4Zd\n", __func__,
+ si->si_ofs.num_btn_regs);
+ dev_dbg(cd->dev, "%s: tt_stat_ofs =%4Zd\n", __func__,
+ si->si_ofs.tt_stat_ofs);
+ dev_dbg(cd->dev, "%s: tch_rec_size =%4Zd\n", __func__,
+ si->si_ofs.tch_rec_size);
+ dev_dbg(cd->dev, "%s: max_tchs =%4Zd\n", __func__,
+ si->si_ofs.max_tchs);
+ dev_dbg(cd->dev, "%s: mode_size =%4Zd\n", __func__,
+ si->si_ofs.mode_size);
+ dev_dbg(cd->dev, "%s: data_size =%4Zd\n", __func__,
+ si->si_ofs.data_size);
+ dev_dbg(cd->dev, "%s: map_sz =%4Zd\n", __func__,
+ si->si_ofs.map_sz);
+
+ dev_dbg(cd->dev, "%s: btn_rec_size =%2Zd\n", __func__,
+ si->si_ofs.btn_rec_size);
+ dev_dbg(cd->dev, "%s: btn_diff_ofs =%2Zd\n", __func__,
+ si->si_ofs.btn_diff_ofs);
+ dev_dbg(cd->dev, "%s: btn_diff_size =%2Zd\n", __func__,
+ si->si_ofs.btn_diff_size);
+
+ dev_dbg(cd->dev, "%s: max_x = 0x%04ZX (%Zd)\n", __func__,
+ si->si_ofs.max_x, si->si_ofs.max_x);
+ dev_dbg(cd->dev, "%s: x_origin = %Zd (%s)\n", __func__,
+ si->si_ofs.x_origin,
+ si->si_ofs.x_origin == CY_NORMAL_ORIGIN ?
+ "left corner" : "right corner");
+ dev_dbg(cd->dev, "%s: max_y = 0x%04ZX (%Zd)\n", __func__,
+ si->si_ofs.max_y, si->si_ofs.max_y);
+ dev_dbg(cd->dev, "%s: y_origin = %Zd (%s)\n", __func__,
+ si->si_ofs.y_origin,
+ si->si_ofs.y_origin == CY_NORMAL_ORIGIN ?
+ "upper corner" : "lower corner");
+ dev_dbg(cd->dev, "%s: max_p = 0x%04ZX (%Zd)\n", __func__,
+ si->si_ofs.max_p, si->si_ofs.max_p);
+
+ dev_dbg(cd->dev, "%s: xy_mode=%p xy_data=%p\n", __func__,
+ si->xy_mode, si->xy_data);
+}
+
+static int cyttsp4_get_sysinfo_regs(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+ int rc;
+
+ rc = cyttsp4_si_data_offsets(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_cydata(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_test_data(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_pcfg_data(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_opcfg_data(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_ddata(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_mdata(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_btn_data(cd);
+ if (rc < 0)
+ return rc;
+
+ rc = cyttsp4_si_get_op_data_ptrs(cd);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: failed to get_op_data\n",
+ __func__);
+ return rc;
+ }
+
+ cyttsp4_si_put_log_data(cd);
+
+ /* provide flow control handshake */
+ rc = cyttsp4_handshake(cd, si->si_data.hst_mode);
+ if (rc < 0)
+ dev_err(cd->dev, "%s: handshake fail on sysinfo reg\n",
+ __func__);
+
+ si->ready = true;
+ return rc;
+}
+
+static void cyttsp4_queue_startup_(struct cyttsp4 *cd)
+{
+ if (cd->startup_state == STARTUP_NONE) {
+ cd->startup_state = STARTUP_QUEUED;
+ schedule_work(&cd->startup_work);
+ dev_dbg(cd->dev, "%s: cyttsp4_startup queued\n", __func__);
+ } else {
+ dev_dbg(cd->dev, "%s: startup_state = %d\n", __func__,
+ cd->startup_state);
+ }
+}
+
+static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md,
+ int max_slots)
+{
+ int t;
+
+ if (md->num_prv_tch == 0)
+ return;
+
+ for (t = 0; t < max_slots; t++) {
+ input_mt_slot(md->input, t);
+ input_mt_report_slot_state(md->input,
+ MT_TOOL_FINGER, false);
+ }
+}
+
+static void cyttsp4_lift_all(struct cyttsp4_mt_data *md)
+{
+ if (!md->si)
+ return;
+
+ if (md->num_prv_tch != 0) {
+ cyttsp4_report_slot_liftoff(md,
+ md->si->si_ofs.tch_abs[CY_TCH_T].max);
+ input_sync(md->input);
+ md->num_prv_tch = 0;
+ }
+}
+
+static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md,
+ int *axis, int size, int max, u8 *xy_data, int bofs)
+{
+ int nbyte;
+ int next;
+
+ for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
+ dev_vdbg(&md->input->dev,
+ "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
+ " xy_data[%d]=%02X(%d) bofs=%d\n",
+ __func__, *axis, *axis, size, max, xy_data, next,
+ xy_data[next], xy_data[next], bofs);
+ *axis = (*axis * 256) + (xy_data[next] >> bofs);
+ next++;
+ }
+
+ *axis &= max - 1;
+
+ dev_vdbg(&md->input->dev,
+ "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
+ " xy_data[%d]=%02X(%d)\n",
+ __func__, *axis, *axis, size, max, xy_data, next,
+ xy_data[next], xy_data[next]);
+}
+
+static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
+ struct cyttsp4_touch *touch, u8 *xy_data)
+{
+ struct device *dev = &md->input->dev;
+ struct cyttsp4_sysinfo *si = md->si;
+ enum cyttsp4_tch_abs abs;
+ int tmp;
+ bool flipped;
+
+ for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
+ cyttsp4_get_touch_axis(md, &touch->abs[abs],
+ si->si_ofs.tch_abs[abs].size,
+ si->si_ofs.tch_abs[abs].max,
+ xy_data + si->si_ofs.tch_abs[abs].ofs,
+ si->si_ofs.tch_abs[abs].bofs);
+ dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
+ cyttsp4_tch_abs_string[abs],
+ touch->abs[abs], touch->abs[abs]);
+ }
+
+ if (md->pdata->flags & CY_FLAG_FLIP) {
+ tmp = touch->abs[CY_TCH_X];
+ touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
+ touch->abs[CY_TCH_Y] = tmp;
+ flipped = true;
+ } else
+ flipped = false;
+
+ if (md->pdata->flags & CY_FLAG_INV_X) {
+ if (flipped)
+ touch->abs[CY_TCH_X] = md->si->si_ofs.max_y -
+ touch->abs[CY_TCH_X];
+ else
+ touch->abs[CY_TCH_X] = md->si->si_ofs.max_x -
+ touch->abs[CY_TCH_X];
+ }
+ if (md->pdata->flags & CY_FLAG_INV_Y) {
+ if (flipped)
+ touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x -
+ touch->abs[CY_TCH_Y];
+ else
+ touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y -
+ touch->abs[CY_TCH_Y];
+ }
+
+ dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
+ __func__, flipped ? "true" : "false",
+ md->pdata->flags & CY_FLAG_INV_X ? "true" : "false",
+ md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false",
+ touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
+ touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
+}
+
+static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids)
+{
+ int t;
+
+ for (t = 0; t < max_slots; t++) {
+ if (ids[t])
+ continue;
+ input_mt_slot(input, t);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+ }
+
+ input_sync(input);
+}
+
+static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch)
+{
+ struct device *dev = &md->input->dev;
+ struct cyttsp4_sysinfo *si = md->si;
+ struct cyttsp4_touch tch;
+ int sig;
+ int i, j, t = 0;
+ int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)];
+
+ memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int));
+ for (i = 0; i < num_cur_tch; i++) {
+ cyttsp4_get_touch(md, &tch, si->xy_data +
+ (i * si->si_ofs.tch_rec_size));
+ if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs
+ [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) ||
+ (tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs
+ [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) {
+ dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
+ __func__, i, tch.abs[CY_TCH_T],
+ md->pdata->frmwrk->abs[(CY_ABS_ID_OST *
+ CY_NUM_ABS_SET) + CY_MAX_OST]);
+ continue;
+ }
+
+ /* use 0 based track id's */
+ sig = md->pdata->frmwrk->abs
+ [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0];
+ if (sig != CY_IGNORE_VALUE) {
+ t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs
+ [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST];
+ if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) {
+ dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
+ __func__, t, tch.abs[CY_TCH_E]);
+ goto cyttsp4_get_mt_touches_pr_tch;
+ }
+ input_mt_slot(md->input, t);
+ input_mt_report_slot_state(md->input, MT_TOOL_FINGER,
+ true);
+ ids[t] = true;
+ }
+
+ /* all devices: position and pressure fields */
+ for (j = 0; j <= CY_ABS_W_OST; j++) {
+ sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) *
+ CY_NUM_ABS_SET) + 0];
+ if (sig != CY_IGNORE_VALUE)
+ input_report_abs(md->input, sig,
+ tch.abs[CY_TCH_X + j]);
+ }
+ if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
+ /*
+ * TMA400 size and orientation fields:
+ * if pressure is non-zero and major touch
+ * signal is zero, then set major and minor touch
+ * signals to minimum non-zero value
+ */
+ if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0)
+ tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1;
+
+ /* Get the extended touch fields */
+ for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
+ sig = md->pdata->frmwrk->abs
+ [((CY_ABS_MAJ_OST + j) *
+ CY_NUM_ABS_SET) + 0];
+ if (sig != CY_IGNORE_VALUE)
+ input_report_abs(md->input, sig,
+ tch.abs[CY_TCH_MAJ + j]);
+ }
+ }
+
+cyttsp4_get_mt_touches_pr_tch:
+ if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE)
+ dev_dbg(dev,
+ "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n",
+ __func__, t,
+ tch.abs[CY_TCH_X],
+ tch.abs[CY_TCH_Y],
+ tch.abs[CY_TCH_P],
+ tch.abs[CY_TCH_MAJ],
+ tch.abs[CY_TCH_MIN],
+ tch.abs[CY_TCH_OR],
+ tch.abs[CY_TCH_E]);
+ else
+ dev_dbg(dev,
+ "%s: t=%d x=%d y=%d z=%d e=%d\n", __func__,
+ t,
+ tch.abs[CY_TCH_X],
+ tch.abs[CY_TCH_Y],
+ tch.abs[CY_TCH_P],
+ tch.abs[CY_TCH_E]);
+ }
+
+ cyttsp4_final_sync(md->input, si->si_ofs.tch_abs[CY_TCH_T].max, ids);
+
+ md->num_prv_tch = num_cur_tch;
+
+ return;
+}
+
+/* read xy_data for all current touches */
+static int cyttsp4_xy_worker(struct cyttsp4 *cd)
+{
+ struct cyttsp4_mt_data *md = &cd->md;
+ struct device *dev = &md->input->dev;
+ struct cyttsp4_sysinfo *si = md->si;
+ u8 num_cur_tch;
+ u8 hst_mode;
+ u8 rep_len;
+ u8 rep_stat;
+ u8 tt_stat;
+ int rc = 0;
+
+ /*
+ * Get event data from cyttsp4 device.
+ * The event data includes all data
+ * for all active touches.
+ * Event data also includes button data
+ */
+ /*
+ * Use 2 reads:
+ * 1st read to get mode + button bytes + touch count (core)
+ * 2nd read (optional) to get touch 1 - touch n data
+ */
+ hst_mode = si->xy_mode[CY_REG_BASE];
+ rep_len = si->xy_mode[si->si_ofs.rep_ofs];
+ rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1];
+ tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs];
+ dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__,
+ "hst_mode=", hst_mode, "rep_len=", rep_len,
+ "rep_stat=", rep_stat, "tt_stat=", tt_stat);
+
+ num_cur_tch = GET_NUM_TOUCHES(tt_stat);
+ dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch);
+
+ if (rep_len == 0 && num_cur_tch > 0) {
+ dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n",
+ __func__, rep_len, num_cur_tch);
+ goto cyttsp4_xy_worker_exit;
+ }
+
+ /* read touches */
+ if (num_cur_tch > 0) {
+ rc = cyttsp4_adap_read(cd, si->si_ofs.tt_stat_ofs + 1,
+ num_cur_tch * si->si_ofs.tch_rec_size,
+ si->xy_data);
+ if (rc < 0) {
+ dev_err(dev, "%s: read fail on touch regs r=%d\n",
+ __func__, rc);
+ goto cyttsp4_xy_worker_exit;
+ }
+ }
+
+ /* print xy data */
+ cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_data, num_cur_tch *
+ si->si_ofs.tch_rec_size, "xy_data");
+
+ /* check any error conditions */
+ if (IS_BAD_PKT(rep_stat)) {
+ dev_dbg(dev, "%s: Invalid buffer detected\n", __func__);
+ rc = 0;
+ goto cyttsp4_xy_worker_exit;
+ }
+
+ if (IS_LARGE_AREA(tt_stat))
+ dev_dbg(dev, "%s: Large area detected\n", __func__);
+
+ if (num_cur_tch > si->si_ofs.max_tchs) {
+ dev_err(dev, "%s: too many tch; set to max tch (n=%d c=%Zd)\n",
+ __func__, num_cur_tch, si->si_ofs.max_tchs);
+ num_cur_tch = si->si_ofs.max_tchs;
+ }
+
+ /* extract xy_data for all currently reported touches */
+ dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
+ num_cur_tch);
+ if (num_cur_tch)
+ cyttsp4_get_mt_touches(md, num_cur_tch);
+ else
+ cyttsp4_lift_all(md);
+
+ rc = 0;
+
+cyttsp4_xy_worker_exit:
+ return rc;
+}
+
+static int cyttsp4_mt_attention(struct cyttsp4 *cd)
+{
+ struct device *dev = cd->dev;
+ struct cyttsp4_mt_data *md = &cd->md;
+ int rc = 0;
+
+ if (!md->si)
+ return 0;
+
+ mutex_lock(&md->report_lock);
+ if (!md->is_suspended) {
+ /* core handles handshake */
+ rc = cyttsp4_xy_worker(cd);
+ } else {
+ dev_vdbg(dev, "%s: Ignoring report while suspended\n",
+ __func__);
+ }
+ mutex_unlock(&md->report_lock);
+ if (rc < 0)
+ dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
+
+ return rc;
+}
+
+static irqreturn_t cyttsp4_irq(int irq, void *handle)
+{
+ struct cyttsp4 *cd = handle;
+ struct device *dev = cd->dev;
+ enum cyttsp4_mode cur_mode;
+ u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs;
+ u8 mode[3];
+ int rc;
+
+ /*
+ * Check whether this IRQ should be ignored (external)
+ * This should be the very first thing to check since
+ * ignore_irq may be set for a very short period of time
+ */
+ if (atomic_read(&cd->ignore_irq)) {
+ dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
+ return IRQ_HANDLED;
+ }
+
+ dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status);
+
+ mutex_lock(&cd->system_lock);
+
+ /* Just to debug */
+ if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING)
+ dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__);
+
+ rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode);
+ if (rc) {
+ dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
+ goto cyttsp4_irq_exit;
+ }
+ dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__,
+ mode[0], mode[1], mode[2]);
+
+ if (IS_BOOTLOADER(mode[0], mode[1])) {
+ cur_mode = CY_MODE_BOOTLOADER;
+ dev_vdbg(dev, "%s: bl running\n", __func__);
+ if (cd->mode == CY_MODE_BOOTLOADER) {
+ /* Signal bootloader heartbeat heard */
+ wake_up(&cd->wait_q);
+ goto cyttsp4_irq_exit;
+ }
+
+ /* switch to bootloader */
+ dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n",
+ __func__, cd->mode, cur_mode);
+
+ /* catch operation->bl glitch */
+ if (cd->mode != CY_MODE_UNKNOWN) {
+ /* Incase startup_state do not let startup_() */
+ cd->mode = CY_MODE_UNKNOWN;
+ cyttsp4_queue_startup_(cd);
+ goto cyttsp4_irq_exit;
+ }
+
+ /*
+ * do not wake thread on this switch since
+ * it is possible to get an early heartbeat
+ * prior to performing the reset
+ */
+ cd->mode = cur_mode;
+
+ goto cyttsp4_irq_exit;
+ }
+
+ switch (mode[0] & CY_HST_MODE) {
+ case CY_HST_OPERATE:
+ cur_mode = CY_MODE_OPERATIONAL;
+ dev_vdbg(dev, "%s: operational\n", __func__);
+ break;
+ case CY_HST_CAT:
+ cur_mode = CY_MODE_CAT;
+ dev_vdbg(dev, "%s: CaT\n", __func__);
+ break;
+ case CY_HST_SYSINFO:
+ cur_mode = CY_MODE_SYSINFO;
+ dev_vdbg(dev, "%s: sysinfo\n", __func__);
+ break;
+ default:
+ cur_mode = CY_MODE_UNKNOWN;
+ dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__,
+ mode[0]);
+ break;
+ }
+
+ /* Check whether this IRQ should be ignored (internal) */
+ if (cd->int_status & CY_INT_IGNORE) {
+ dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
+ goto cyttsp4_irq_exit;
+ }
+
+ /* Check for wake up interrupt */
+ if (cd->int_status & CY_INT_AWAKE) {
+ cd->int_status &= ~CY_INT_AWAKE;
+ wake_up(&cd->wait_q);
+ dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__);
+ goto cyttsp4_irq_handshake;
+ }
+
+ /* Expecting mode change interrupt */
+ if ((cd->int_status & CY_INT_MODE_CHANGE)
+ && (mode[0] & CY_HST_MODE_CHANGE) == 0) {
+ cd->int_status &= ~CY_INT_MODE_CHANGE;
+ dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n",
+ __func__, cd->mode, cur_mode);
+ cd->mode = cur_mode;
+ wake_up(&cd->wait_q);
+ goto cyttsp4_irq_handshake;
+ }
+
+ /* compare current core mode to current device mode */
+ dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n",
+ __func__, cd->mode, cur_mode);
+ if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) {
+ /* Unexpected mode change occurred */
+ dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode,
+ cur_mode, cd->int_status);
+ dev_dbg(dev, "%s: Unexpected mode change, startup\n",
+ __func__);
+ cyttsp4_queue_startup_(cd);
+ goto cyttsp4_irq_exit;
+ }
+
+ /* Expecting command complete interrupt */
+ dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]);
+ if ((cd->int_status & CY_INT_EXEC_CMD)
+ && mode[cmd_ofs] & CY_CMD_COMPLETE) {
+ cd->int_status &= ~CY_INT_EXEC_CMD;
+ dev_vdbg(dev, "%s: Received command complete interrupt\n",
+ __func__);
+ wake_up(&cd->wait_q);
+ /*
+ * It is possible to receive a single interrupt for
+ * command complete and touch/button status report.
+ * Continue processing for a possible status report.
+ */
+ }
+
+ /* This should be status report, read status regs */
+ if (cd->mode == CY_MODE_OPERATIONAL) {
+ dev_vdbg(dev, "%s: Read status registers\n", __func__);
+ rc = cyttsp4_load_status_regs(cd);
+ if (rc < 0)
+ dev_err(dev, "%s: fail read mode regs r=%d\n",
+ __func__, rc);
+ }
+
+ cyttsp4_mt_attention(cd);
+
+cyttsp4_irq_handshake:
+ /* handshake the event */
+ dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n",
+ __func__, mode[0], rc);
+ rc = cyttsp4_handshake(cd, mode[0]);
+ if (rc < 0)
+ dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n",
+ __func__, mode[0], rc);
+
+ /*
+ * a non-zero udelay period is required for using
+ * IRQF_TRIGGER_LOW in order to delay until the
+ * device completes isr deassert
+ */
+ udelay(cd->cpdata->level_irq_udelay);
+
+cyttsp4_irq_exit:
+ mutex_unlock(&cd->system_lock);
+ return IRQ_HANDLED;
+}
+
+static void cyttsp4_start_wd_timer(struct cyttsp4 *cd)
+{
+ if (!CY_WATCHDOG_TIMEOUT)
+ return;
+
+ mod_timer(&cd->watchdog_timer, jiffies +
+ msecs_to_jiffies(CY_WATCHDOG_TIMEOUT));
+}
+
+static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
+{
+ if (!CY_WATCHDOG_TIMEOUT)
+ return;
+
+ /*
+ * Ensure we wait until the watchdog timer
+ * running on a different CPU finishes
+ */
+ del_timer_sync(&cd->watchdog_timer);
+ cancel_work_sync(&cd->watchdog_work);
+ del_timer_sync(&cd->watchdog_timer);
+}
+
+static void cyttsp4_watchdog_timer(unsigned long handle)
+{
+ struct cyttsp4 *cd = (struct cyttsp4 *)handle;
+
+ dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
+
+ if (!cd)
+ return;
+
+ if (!work_pending(&cd->watchdog_work))
+ schedule_work(&cd->watchdog_work);
+
+ return;
+}
+
+static int cyttsp4_request_exclusive(struct cyttsp4 *cd, void *ownptr,
+ int timeout_ms)
+{
+ int t = msecs_to_jiffies(timeout_ms);
+ bool with_timeout = (timeout_ms != 0);
+
+ mutex_lock(&cd->system_lock);
+ if (!cd->exclusive_dev && cd->exclusive_waits == 0) {
+ cd->exclusive_dev = ownptr;
+ goto exit;
+ }
+
+ cd->exclusive_waits++;
+wait:
+ mutex_unlock(&cd->system_lock);
+ if (with_timeout) {
+ t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t);
+ if (IS_TMO(t)) {
+ dev_err(cd->dev, "%s: tmo waiting exclusive access\n",
+ __func__);
+ mutex_lock(&cd->system_lock);
+ cd->exclusive_waits--;
+ mutex_unlock(&cd->system_lock);
+ return -ETIME;
+ }
+ } else {
+ wait_event(cd->wait_q, !cd->exclusive_dev);
+ }
+ mutex_lock(&cd->system_lock);
+ if (cd->exclusive_dev)
+ goto wait;
+ cd->exclusive_dev = ownptr;
+ cd->exclusive_waits--;
+exit:
+ mutex_unlock(&cd->system_lock);
+
+ return 0;
+}
+
+/*
+ * returns error if was not owned
+ */
+static int cyttsp4_release_exclusive(struct cyttsp4 *cd, void *ownptr)
+{
+ mutex_lock(&cd->system_lock);
+ if (cd->exclusive_dev != ownptr) {
+ mutex_unlock(&cd->system_lock);
+ return -EINVAL;
+ }
+
+ dev_vdbg(cd->dev, "%s: exclusive_dev %p freed\n",
+ __func__, cd->exclusive_dev);
+ cd->exclusive_dev = NULL;
+ wake_up(&cd->wait_q);
+ mutex_unlock(&cd->system_lock);
+ return 0;
+}
+
+static int cyttsp4_wait_bl_heartbeat(struct cyttsp4 *cd)
+{
+ long t;
+ int rc = 0;
+
+ /* wait heartbeat */
+ dev_vdbg(cd->dev, "%s: wait heartbeat...\n", __func__);
+ t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_BOOTLOADER,
+ msecs_to_jiffies(CY_CORE_RESET_AND_WAIT_TIMEOUT));
+ if (IS_TMO(t)) {
+ dev_err(cd->dev, "%s: tmo waiting bl heartbeat cd->mode=%d\n",
+ __func__, cd->mode);
+ rc = -ETIME;
+ }
+
+ return rc;
+}
+
+static int cyttsp4_wait_sysinfo_mode(struct cyttsp4 *cd)
+{
+ long t;
+
+ dev_vdbg(cd->dev, "%s: wait sysinfo...\n", __func__);
+
+ t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_SYSINFO,
+ msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
+ if (IS_TMO(t)) {
+ dev_err(cd->dev, "%s: tmo waiting exit bl cd->mode=%d\n",
+ __func__, cd->mode);
+ mutex_lock(&cd->system_lock);
+ cd->int_status &= ~CY_INT_MODE_CHANGE;
+ mutex_unlock(&cd->system_lock);
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+static int cyttsp4_reset_and_wait(struct cyttsp4 *cd)
+{
+ int rc;
+
+ /* reset hardware */
+ mutex_lock(&cd->system_lock);
+ dev_dbg(cd->dev, "%s: reset hw...\n", __func__);
+ rc = cyttsp4_hw_reset(cd);
+ cd->mode = CY_MODE_UNKNOWN;
+ mutex_unlock(&cd->system_lock);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s:Fail hw reset r=%d\n", __func__, rc);
+ return rc;
+ }
+
+ return cyttsp4_wait_bl_heartbeat(cd);
+}
+
+/*
+ * returns err if refused or timeout; block until mode change complete
+ * bit is set (mode change interrupt)
+ */
+static int cyttsp4_set_mode(struct cyttsp4 *cd, int new_mode)
+{
+ u8 new_dev_mode;
+ u8 mode;
+ long t;
+ int rc;
+
+ switch (new_mode) {
+ case CY_MODE_OPERATIONAL:
+ new_dev_mode = CY_HST_OPERATE;
+ break;
+ case CY_MODE_SYSINFO:
+ new_dev_mode = CY_HST_SYSINFO;
+ break;
+ case CY_MODE_CAT:
+ new_dev_mode = CY_HST_CAT;
+ break;
+ default:
+ dev_err(cd->dev, "%s: invalid mode: %02X(%d)\n",
+ __func__, new_mode, new_mode);
+ return -EINVAL;
+ }
+
+ /* change mode */
+ dev_dbg(cd->dev, "%s: %s=%p new_dev_mode=%02X new_mode=%d\n",
+ __func__, "have exclusive", cd->exclusive_dev,
+ new_dev_mode, new_mode);
+
+ mutex_lock(&cd->system_lock);
+ rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
+ if (rc < 0) {
+ mutex_unlock(&cd->system_lock);
+ dev_err(cd->dev, "%s: Fail read mode r=%d\n",
+ __func__, rc);
+ goto exit;
+ }
+
+ /* Clear device mode bits and set to new mode */
+ mode &= ~CY_HST_MODE;
+ mode |= new_dev_mode | CY_HST_MODE_CHANGE;
+
+ cd->int_status |= CY_INT_MODE_CHANGE;
+ rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode), &mode);
+ mutex_unlock(&cd->system_lock);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: Fail write mode change r=%d\n",
+ __func__, rc);
+ goto exit;
+ }
+
+ /* wait for mode change done interrupt */
+ t = wait_event_timeout(cd->wait_q,
+ (cd->int_status & CY_INT_MODE_CHANGE) == 0,
+ msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
+ dev_dbg(cd->dev, "%s: back from wait t=%ld cd->mode=%d\n",
+ __func__, t, cd->mode);
+
+ if (IS_TMO(t)) {
+ dev_err(cd->dev, "%s: %s\n", __func__,
+ "tmo waiting mode change");
+ mutex_lock(&cd->system_lock);
+ cd->int_status &= ~CY_INT_MODE_CHANGE;
+ mutex_unlock(&cd->system_lock);
+ rc = -EINVAL;
+ }
+
+exit:
+ return rc;
+}
+
+static void cyttsp4_watchdog_work(struct work_struct *work)
+{
+ struct cyttsp4 *cd =
+ container_of(work, struct cyttsp4, watchdog_work);
+ u8 *mode;
+ int retval;
+
+ mutex_lock(&cd->system_lock);
+ retval = cyttsp4_load_status_regs(cd);
+ if (retval < 0) {
+ dev_err(cd->dev,
+ "%s: failed to access device in watchdog timer r=%d\n",
+ __func__, retval);
+ cyttsp4_queue_startup_(cd);
+ goto cyttsp4_timer_watchdog_exit_error;
+ }
+ mode = &cd->sysinfo.xy_mode[CY_REG_BASE];
+ if (IS_BOOTLOADER(mode[0], mode[1])) {
+ dev_err(cd->dev,
+ "%s: device found in bootloader mode when operational mode\n",
+ __func__);
+ cyttsp4_queue_startup_(cd);
+ goto cyttsp4_timer_watchdog_exit_error;
+ }
+
+ cyttsp4_start_wd_timer(cd);
+cyttsp4_timer_watchdog_exit_error:
+ mutex_unlock(&cd->system_lock);
+ return;
+}
+
+static int cyttsp4_core_sleep_(struct cyttsp4 *cd)
+{
+ enum cyttsp4_sleep_state ss = SS_SLEEP_ON;
+ enum cyttsp4_int_state int_status = CY_INT_IGNORE;
+ int rc = 0;
+ u8 mode[2];
+
+ /* Already in sleep mode? */
+ mutex_lock(&cd->system_lock);
+ if (cd->sleep_state == SS_SLEEP_ON) {
+ mutex_unlock(&cd->system_lock);
+ return 0;
+ }
+ cd->sleep_state = SS_SLEEPING;
+ mutex_unlock(&cd->system_lock);
+
+ cyttsp4_stop_wd_timer(cd);
+
+ /* Wait until currently running IRQ handler exits and disable IRQ */
+ disable_irq(cd->irq);
+
+ dev_vdbg(cd->dev, "%s: write DEEP SLEEP...\n", __func__);
+ mutex_lock(&cd->system_lock);
+ rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
+ if (rc) {
+ mutex_unlock(&cd->system_lock);
+ dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
+ goto error;
+ }
+
+ if (IS_BOOTLOADER(mode[0], mode[1])) {
+ mutex_unlock(&cd->system_lock);
+ dev_err(cd->dev, "%s: Device in BOOTLADER mode.\n", __func__);
+ rc = -EINVAL;
+ goto error;
+ }
+
+ mode[0] |= CY_HST_SLEEP;
+ rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode[0]), &mode[0]);
+ mutex_unlock(&cd->system_lock);
+ if (rc) {
+ dev_err(cd->dev, "%s: Fail write adapter r=%d\n", __func__, rc);
+ goto error;
+ }
+ dev_vdbg(cd->dev, "%s: write DEEP SLEEP succeeded\n", __func__);
+
+ if (cd->cpdata->power) {
+ dev_dbg(cd->dev, "%s: Power down HW\n", __func__);
+ rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, &cd->ignore_irq);
+ } else {
+ dev_dbg(cd->dev, "%s: No power function\n", __func__);
+ rc = 0;
+ }
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: HW Power down fails r=%d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ /* Give time to FW to sleep */
+ msleep(50);
+
+ goto exit;
+
+error:
+ ss = SS_SLEEP_OFF;
+ int_status = CY_INT_NONE;
+ cyttsp4_start_wd_timer(cd);
+
+exit:
+ mutex_lock(&cd->system_lock);
+ cd->sleep_state = ss;
+ cd->int_status |= int_status;
+ mutex_unlock(&cd->system_lock);
+ enable_irq(cd->irq);
+ return rc;
+}
+
+static int cyttsp4_core_sleep(struct cyttsp4 *cd)
+{
+ int rc;
+
+ rc = cyttsp4_request_exclusive(cd, cd->dev,
+ CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+ __func__, cd->exclusive_dev, cd->dev);
+ return 0;
+ }
+
+ rc = cyttsp4_core_sleep_(cd);
+
+ if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
+ dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+ else
+ dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
+
+ return rc;
+}
+
+static int cyttsp4_core_wake_(struct cyttsp4 *cd)
+{
+ struct device *dev = cd->dev;
+ int rc;
+ u8 mode;
+ int t;
+
+ /* Already woken? */
+ mutex_lock(&cd->system_lock);
+ if (cd->sleep_state == SS_SLEEP_OFF) {
+ mutex_unlock(&cd->system_lock);
+ return 0;
+ }
+ cd->int_status &= ~CY_INT_IGNORE;
+ cd->int_status |= CY_INT_AWAKE;
+ cd->sleep_state = SS_WAKING;
+
+ if (cd->cpdata->power) {
+ dev_dbg(dev, "%s: Power up HW\n", __func__);
+ rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq);
+ } else {
+ dev_dbg(dev, "%s: No power function\n", __func__);
+ rc = -ENOSYS;
+ }
+ if (rc < 0) {
+ dev_err(dev, "%s: HW Power up fails r=%d\n",
+ __func__, rc);
+
+ /* Initiate a read transaction to wake up */
+ cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
+ } else
+ dev_vdbg(cd->dev, "%s: HW power up succeeds\n",
+ __func__);
+ mutex_unlock(&cd->system_lock);
+
+ t = wait_event_timeout(cd->wait_q,
+ (cd->int_status & CY_INT_AWAKE) == 0,
+ msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT));
+ if (IS_TMO(t)) {
+ dev_err(dev, "%s: TMO waiting for wakeup\n", __func__);
+ mutex_lock(&cd->system_lock);
+ cd->int_status &= ~CY_INT_AWAKE;
+ /* Try starting up */
+ cyttsp4_queue_startup_(cd);
+ mutex_unlock(&cd->system_lock);
+ }
+
+ mutex_lock(&cd->system_lock);
+ cd->sleep_state = SS_SLEEP_OFF;
+ mutex_unlock(&cd->system_lock);
+
+ cyttsp4_start_wd_timer(cd);
+
+ return 0;
+}
+
+static int cyttsp4_core_wake(struct cyttsp4 *cd)
+{
+ int rc;
+
+ rc = cyttsp4_request_exclusive(cd, cd->dev,
+ CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+ __func__, cd->exclusive_dev, cd->dev);
+ return 0;
+ }
+
+ rc = cyttsp4_core_wake_(cd);
+
+ if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
+ dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+ else
+ dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
+
+ return rc;
+}
+
+static int cyttsp4_startup_(struct cyttsp4 *cd)
+{
+ int retry = CY_CORE_STARTUP_RETRY_COUNT;
+ int rc;
+
+ cyttsp4_stop_wd_timer(cd);
+
+reset:
+ if (retry != CY_CORE_STARTUP_RETRY_COUNT)
+ dev_dbg(cd->dev, "%s: Retry %d\n", __func__,
+ CY_CORE_STARTUP_RETRY_COUNT - retry);
+
+ /* reset hardware and wait for heartbeat */
+ rc = cyttsp4_reset_and_wait(cd);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: Error on h/w reset r=%d\n", __func__, rc);
+ if (retry--)
+ goto reset;
+ goto exit;
+ }
+
+ /* exit bl into sysinfo mode */
+ dev_vdbg(cd->dev, "%s: write exit ldr...\n", __func__);
+ mutex_lock(&cd->system_lock);
+ cd->int_status &= ~CY_INT_IGNORE;
+ cd->int_status |= CY_INT_MODE_CHANGE;
+
+ rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(ldr_exit),
+ (u8 *)ldr_exit);
+ mutex_unlock(&cd->system_lock);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: Fail write r=%d\n", __func__, rc);
+ if (retry--)
+ goto reset;
+ goto exit;
+ }
+
+ rc = cyttsp4_wait_sysinfo_mode(cd);
+ if (rc < 0) {
+ u8 buf[sizeof(ldr_err_app)];
+ int rc1;
+
+ /* Check for invalid/corrupted touch application */
+ rc1 = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(ldr_err_app),
+ buf);
+ if (rc1) {
+ dev_err(cd->dev, "%s: Fail read r=%d\n", __func__, rc1);
+ } else if (!memcmp(buf, ldr_err_app, sizeof(ldr_err_app))) {
+ dev_err(cd->dev, "%s: Error launching touch application\n",
+ __func__);
+ mutex_lock(&cd->system_lock);
+ cd->invalid_touch_app = true;
+ mutex_unlock(&cd->system_lock);
+ goto exit_no_wd;
+ }
+
+ if (retry--)
+ goto reset;
+ goto exit;
+ }
+
+ mutex_lock(&cd->system_lock);
+ cd->invalid_touch_app = false;
+ mutex_unlock(&cd->system_lock);
+
+ /* read sysinfo data */
+ dev_vdbg(cd->dev, "%s: get sysinfo regs..\n", __func__);
+ rc = cyttsp4_get_sysinfo_regs(cd);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: failed to get sysinfo regs rc=%d\n",
+ __func__, rc);
+ if (retry--)
+ goto reset;
+ goto exit;
+ }
+
+ rc = cyttsp4_set_mode(cd, CY_MODE_OPERATIONAL);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: failed to set mode to operational rc=%d\n",
+ __func__, rc);
+ if (retry--)
+ goto reset;
+ goto exit;
+ }
+
+ cyttsp4_lift_all(&cd->md);
+
+ /* restore to sleep if was suspended */
+ mutex_lock(&cd->system_lock);
+ if (cd->sleep_state == SS_SLEEP_ON) {
+ cd->sleep_state = SS_SLEEP_OFF;
+ mutex_unlock(&cd->system_lock);
+ cyttsp4_core_sleep_(cd);
+ goto exit_no_wd;
+ }
+ mutex_unlock(&cd->system_lock);
+
+exit:
+ cyttsp4_start_wd_timer(cd);
+exit_no_wd:
+ return rc;
+}
+
+static int cyttsp4_startup(struct cyttsp4 *cd)
+{
+ int rc;
+
+ mutex_lock(&cd->system_lock);
+ cd->startup_state = STARTUP_RUNNING;
+ mutex_unlock(&cd->system_lock);
+
+ rc = cyttsp4_request_exclusive(cd, cd->dev,
+ CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
+ if (rc < 0) {
+ dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
+ __func__, cd->exclusive_dev, cd->dev);
+ goto exit;
+ }
+
+ rc = cyttsp4_startup_(cd);
+
+ if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
+ /* Don't return fail code, mode is already changed. */
+ dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
+ else
+ dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
+
+exit:
+ mutex_lock(&cd->system_lock);
+ cd->startup_state = STARTUP_NONE;
+ mutex_unlock(&cd->system_lock);
+
+ /* Wake the waiters for end of startup */
+ wake_up(&cd->wait_q);
+
+ return rc;
+}
+
+static void cyttsp4_startup_work_function(struct work_struct *work)
+{
+ struct cyttsp4 *cd = container_of(work, struct cyttsp4, startup_work);
+ int rc;
+
+ rc = cyttsp4_startup(cd);
+ if (rc < 0)
+ dev_err(cd->dev, "%s: Fail queued startup r=%d\n",
+ __func__, rc);
+}
+
+static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
+{
+ struct cyttsp4_sysinfo *si = &cd->sysinfo;
+
+ if (!si)
+ return;
+
+ kfree(si->si_ptrs.cydata);
+ kfree(si->si_ptrs.test);
+ kfree(si->si_ptrs.pcfg);
+ kfree(si->si_ptrs.opcfg);
+ kfree(si->si_ptrs.ddata);
+ kfree(si->si_ptrs.mdata);
+ kfree(si->btn);
+ kfree(si->xy_mode);
+ kfree(si->xy_data);
+ kfree(si->btn_rec_data);
+}
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+static int cyttsp4_core_suspend(struct device *dev)
+{
+ struct cyttsp4 *cd = dev_get_drvdata(dev);
+ struct cyttsp4_mt_data *md = &cd->md;
+ int rc;
+
+ md->is_suspended = true;
+
+ rc = cyttsp4_core_sleep(cd);
+ if (rc < 0) {
+ dev_err(dev, "%s: Error on sleep\n", __func__);
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int cyttsp4_core_resume(struct device *dev)
+{
+ struct cyttsp4 *cd = dev_get_drvdata(dev);
+ struct cyttsp4_mt_data *md = &cd->md;
+ int rc;
+
+ md->is_suspended = false;
+
+ rc = cyttsp4_core_wake(cd);
+ if (rc < 0) {
+ dev_err(dev, "%s: Error on wake\n", __func__);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+#endif
+
+const struct dev_pm_ops cyttsp4_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume)
+ SET_RUNTIME_PM_OPS(cyttsp4_core_suspend, cyttsp4_core_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(cyttsp4_pm_ops);
+
+static int cyttsp4_mt_open(struct input_dev *input)
+{
+ pm_runtime_get(input->dev.parent);
+ return 0;
+}
+
+static void cyttsp4_mt_close(struct input_dev *input)
+{
+ struct cyttsp4_mt_data *md = input_get_drvdata(input);
+ mutex_lock(&md->report_lock);
+ if (!md->is_suspended)
+ pm_runtime_put(input->dev.parent);
+ mutex_unlock(&md->report_lock);
+}
+
+
+static int cyttsp4_setup_input_device(struct cyttsp4 *cd)
+{
+ struct device *dev = cd->dev;
+ struct cyttsp4_mt_data *md = &cd->md;
+ int signal = CY_IGNORE_VALUE;
+ int max_x, max_y, max_p, min, max;
+ int max_x_tmp, max_y_tmp;
+ int i;
+ int rc;
+
+ dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
+ __set_bit(EV_ABS, md->input->evbit);
+ __set_bit(EV_REL, md->input->evbit);
+ __set_bit(EV_KEY, md->input->evbit);
+
+ max_x_tmp = md->si->si_ofs.max_x;
+ max_y_tmp = md->si->si_ofs.max_y;
+
+ /* get maximum values from the sysinfo data */
+ if (md->pdata->flags & CY_FLAG_FLIP) {
+ max_x = max_y_tmp - 1;
+ max_y = max_x_tmp - 1;
+ } else {
+ max_x = max_x_tmp - 1;
+ max_y = max_y_tmp - 1;
+ }
+ max_p = md->si->si_ofs.max_p;
+
+ /* set event signal capabilities */
+ for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) {
+ signal = md->pdata->frmwrk->abs
+ [(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST];
+ if (signal != CY_IGNORE_VALUE) {
+ __set_bit(signal, md->input->absbit);
+ min = md->pdata->frmwrk->abs
+ [(i * CY_NUM_ABS_SET) + CY_MIN_OST];
+ max = md->pdata->frmwrk->abs
+ [(i * CY_NUM_ABS_SET) + CY_MAX_OST];
+ if (i == CY_ABS_ID_OST) {
+ /* shift track ids down to start at 0 */
+ max = max - min;
+ min = min - min;
+ } else if (i == CY_ABS_X_OST)
+ max = max_x;
+ else if (i == CY_ABS_Y_OST)
+ max = max_y;
+ else if (i == CY_ABS_P_OST)
+ max = max_p;
+ input_set_abs_params(md->input, signal, min, max,
+ md->pdata->frmwrk->abs
+ [(i * CY_NUM_ABS_SET) + CY_FUZZ_OST],
+ md->pdata->frmwrk->abs
+ [(i * CY_NUM_ABS_SET) + CY_FLAT_OST]);
+ dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
+ __func__, signal, min, max);
+ if ((i == CY_ABS_ID_OST) &&
+ (md->si->si_ofs.tch_rec_size <
+ CY_TMA4XX_TCH_REC_SIZE))
+ break;
+ }
+ }
+
+ input_mt_init_slots(md->input, md->si->si_ofs.tch_abs[CY_TCH_T].max,
+ INPUT_MT_DIRECT);
+ rc = input_register_device(md->input);
+ if (rc < 0)
+ dev_err(dev, "%s: Error, failed register input device r=%d\n",
+ __func__, rc);
+ return rc;
+}
+
+static int cyttsp4_mt_probe(struct cyttsp4 *cd)
+{
+ struct device *dev = cd->dev;
+ struct cyttsp4_mt_data *md = &cd->md;
+ struct cyttsp4_mt_platform_data *pdata = cd->pdata->mt_pdata;
+ int rc = 0;
+
+ mutex_init(&md->report_lock);
+ md->pdata = pdata;
+ /* Create the input device and register it. */
+ dev_vdbg(dev, "%s: Create the input device and register it\n",
+ __func__);
+ md->input = input_allocate_device();
+ if (md->input == NULL) {
+ dev_err(dev, "%s: Error, failed to allocate input device\n",
+ __func__);
+ rc = -ENOSYS;
+ goto error_alloc_failed;
+ }
+
+ md->input->name = pdata->inp_dev_name;
+ scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev));
+ md->input->phys = md->phys;
+ md->input->id.bustype = cd->bus_ops->bustype;
+ md->input->dev.parent = dev;
+ md->input->open = cyttsp4_mt_open;
+ md->input->close = cyttsp4_mt_close;
+ input_set_drvdata(md->input, md);
+
+ /* get sysinfo */
+ md->si = &cd->sysinfo;
+ if (!md->si) {
+ dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
+ __func__, md->si);
+ goto error_get_sysinfo;
+ }
+
+ rc = cyttsp4_setup_input_device(cd);
+ if (rc)
+ goto error_init_input;
+
+ return 0;
+
+error_init_input:
+ input_free_device(md->input);
+error_get_sysinfo:
+ input_set_drvdata(md->input, NULL);
+error_alloc_failed:
+ dev_err(dev, "%s failed.\n", __func__);
+ return rc;
+}
+
+struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
+ struct device *dev, u16 irq, size_t xfer_buf_size)
+{
+ struct cyttsp4 *cd;
+ struct cyttsp4_platform_data *pdata = dev_get_platdata(dev);
+ unsigned long irq_flags;
+ int rc = 0;
+
+ if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) {
+ dev_err(dev, "%s: Missing platform data\n", __func__);
+ rc = -ENODEV;
+ goto error_no_pdata;
+ }
+
+ cd = kzalloc(sizeof(*cd), GFP_KERNEL);
+ if (!cd) {
+ dev_err(dev, "%s: Error, kzalloc\n", __func__);
+ rc = -ENOMEM;
+ goto error_alloc_data;
+ }
+
+ cd->xfer_buf = kzalloc(xfer_buf_size, GFP_KERNEL);
+ if (!cd->xfer_buf) {
+ dev_err(dev, "%s: Error, kzalloc\n", __func__);
+ rc = -ENOMEM;
+ goto error_free_cd;
+ }
+
+ /* Initialize device info */
+ cd->dev = dev;
+ cd->pdata = pdata;
+ cd->cpdata = pdata->core_pdata;
+ cd->bus_ops = ops;
+
+ /* Initialize mutexes and spinlocks */
+ mutex_init(&cd->system_lock);
+ mutex_init(&cd->adap_lock);
+
+ /* Initialize wait queue */
+ init_waitqueue_head(&cd->wait_q);
+
+ /* Initialize works */
+ INIT_WORK(&cd->startup_work, cyttsp4_startup_work_function);
+ INIT_WORK(&cd->watchdog_work, cyttsp4_watchdog_work);
+
+ /* Initialize IRQ */
+ cd->irq = gpio_to_irq(cd->cpdata->irq_gpio);
+ if (cd->irq < 0) {
+ rc = -EINVAL;
+ goto error_free_xfer;
+ }
+
+ dev_set_drvdata(dev, cd);
+
+ /* Call platform init function */
+ if (cd->cpdata->init) {
+ dev_dbg(cd->dev, "%s: Init HW\n", __func__);
+ rc = cd->cpdata->init(cd->cpdata, 1, cd->dev);
+ } else {
+ dev_dbg(cd->dev, "%s: No HW INIT function\n", __func__);
+ rc = 0;
+ }
+ if (rc < 0)
+ dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc);
+
+ dev_dbg(dev, "%s: initialize threaded irq=%d\n", __func__, cd->irq);
+ if (cd->cpdata->level_irq_udelay > 0)
+ /* use level triggered interrupts */
+ irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
+ else
+ /* use edge triggered interrupts */
+ irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+
+ rc = request_threaded_irq(cd->irq, NULL, cyttsp4_irq, irq_flags,
+ dev_name(dev), cd);
+ if (rc < 0) {
+ dev_err(dev, "%s: Error, could not request irq\n", __func__);
+ goto error_request_irq;
+ }
+
+ /* Setup watchdog timer */
+ setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer,
+ (unsigned long)cd);
+
+ /*
+ * call startup directly to ensure that the device
+ * is tested before leaving the probe
+ */
+ rc = cyttsp4_startup(cd);
+
+ /* Do not fail probe if startup fails but the device is detected */
+ if (rc < 0 && cd->mode == CY_MODE_UNKNOWN) {
+ dev_err(cd->dev, "%s: Fail initial startup r=%d\n",
+ __func__, rc);
+ goto error_startup;
+ }
+
+ rc = cyttsp4_mt_probe(cd);
+ if (rc < 0) {
+ dev_err(dev, "%s: Error, fail mt probe\n", __func__);
+ goto error_startup;
+ }
+
+ pm_runtime_enable(dev);
+
+ return cd;
+
+error_startup:
+ cancel_work_sync(&cd->startup_work);
+ cyttsp4_stop_wd_timer(cd);
+ pm_runtime_disable(dev);
+ cyttsp4_free_si_ptrs(cd);
+ free_irq(cd->irq, cd);
+error_request_irq:
+ if (cd->cpdata->init)
+ cd->cpdata->init(cd->cpdata, 0, dev);
+ dev_set_drvdata(dev, NULL);
+error_free_xfer:
+ kfree(cd->xfer_buf);
+error_free_cd:
+ kfree(cd);
+error_alloc_data:
+error_no_pdata:
+ dev_err(dev, "%s failed.\n", __func__);
+ return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(cyttsp4_probe);
+
+static void cyttsp4_mt_release(struct cyttsp4_mt_data *md)
+{
+ input_unregister_device(md->input);
+ input_set_drvdata(md->input, NULL);
+}
+
+int cyttsp4_remove(struct cyttsp4 *cd)
+{
+ struct device *dev = cd->dev;
+
+ cyttsp4_mt_release(&cd->md);
+
+ /*
+ * Suspend the device before freeing the startup_work and stopping
+ * the watchdog since sleep function restarts watchdog on failure
+ */
+ pm_runtime_suspend(dev);
+ pm_runtime_disable(dev);
+
+ cancel_work_sync(&cd->startup_work);
+
+ cyttsp4_stop_wd_timer(cd);
+
+ free_irq(cd->irq, cd);
+ if (cd->cpdata->init)
+ cd->cpdata->init(cd->cpdata, 0, dev);
+ dev_set_drvdata(dev, NULL);
+ cyttsp4_free_si_ptrs(cd);
+ kfree(cd);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cyttsp4_remove);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen core driver");
+MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h
new file mode 100644
index 000000000000..86a254354136
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_core.h
@@ -0,0 +1,472 @@
+/*
+ * cyttsp4_core.h
+ * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
+ *
+ */
+
+#ifndef _LINUX_CYTTSP4_CORE_H
+#define _LINUX_CYTTSP4_CORE_H
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/platform_data/cyttsp4.h>
+
+#define CY_REG_BASE 0x00
+
+#define CY_POST_CODEL_WDG_RST 0x01
+#define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02
+#define CY_POST_CODEL_PANEL_TEST_FAIL 0x04
+
+#define CY_NUM_BTN_PER_REG 4
+
+/* touch record system information offset masks and shifts */
+#define CY_BYTE_OFS_MASK 0x1F
+#define CY_BOFS_MASK 0xE0
+#define CY_BOFS_SHIFT 5
+
+#define CY_TMA1036_TCH_REC_SIZE 6
+#define CY_TMA4XX_TCH_REC_SIZE 9
+#define CY_TMA1036_MAX_TCH 0x0E
+#define CY_TMA4XX_MAX_TCH 0x1E
+
+#define CY_NORMAL_ORIGIN 0 /* upper, left corner */
+#define CY_INVERT_ORIGIN 1 /* lower, right corner */
+
+/* helpers */
+#define GET_NUM_TOUCHES(x) ((x) & 0x1F)
+#define IS_LARGE_AREA(x) ((x) & 0x20)
+#define IS_BAD_PKT(x) ((x) & 0x20)
+#define IS_BOOTLOADER(hst_mode, reset_detect) \
+ ((hst_mode) & 0x01 || (reset_detect) != 0)
+#define IS_TMO(t) ((t) == 0)
+
+
+enum cyttsp_cmd_bits {
+ CY_CMD_COMPLETE = (1 << 6),
+};
+
+/* Timeout in ms. */
+#define CY_WATCHDOG_TIMEOUT 1000
+
+#define CY_MAX_PRINT_SIZE 512
+#ifdef VERBOSE_DEBUG
+#define CY_MAX_PRBUF_SIZE PIPE_BUF
+#define CY_PR_TRUNCATED " truncated..."
+#endif
+
+enum cyttsp4_ic_grpnum {
+ CY_IC_GRPNUM_RESERVED,
+ CY_IC_GRPNUM_CMD_REGS,
+ CY_IC_GRPNUM_TCH_REP,
+ CY_IC_GRPNUM_DATA_REC,
+ CY_IC_GRPNUM_TEST_REC,
+ CY_IC_GRPNUM_PCFG_REC,
+ CY_IC_GRPNUM_TCH_PARM_VAL,
+ CY_IC_GRPNUM_TCH_PARM_SIZE,
+ CY_IC_GRPNUM_RESERVED1,
+ CY_IC_GRPNUM_RESERVED2,
+ CY_IC_GRPNUM_OPCFG_REC,
+ CY_IC_GRPNUM_DDATA_REC,
+ CY_IC_GRPNUM_MDATA_REC,
+ CY_IC_GRPNUM_TEST_REGS,
+ CY_IC_GRPNUM_BTN_KEYS,
+ CY_IC_GRPNUM_TTHE_REGS,
+ CY_IC_GRPNUM_NUM
+};
+
+enum cyttsp4_int_state {
+ CY_INT_NONE,
+ CY_INT_IGNORE = (1 << 0),
+ CY_INT_MODE_CHANGE = (1 << 1),
+ CY_INT_EXEC_CMD = (1 << 2),
+ CY_INT_AWAKE = (1 << 3),
+};
+
+enum cyttsp4_mode {
+ CY_MODE_UNKNOWN,
+ CY_MODE_BOOTLOADER = (1 << 1),
+ CY_MODE_OPERATIONAL = (1 << 2),
+ CY_MODE_SYSINFO = (1 << 3),
+ CY_MODE_CAT = (1 << 4),
+ CY_MODE_STARTUP = (1 << 5),
+ CY_MODE_LOADER = (1 << 6),
+ CY_MODE_CHANGE_MODE = (1 << 7),
+ CY_MODE_CHANGED = (1 << 8),
+ CY_MODE_CMD_COMPLETE = (1 << 9),
+};
+
+enum cyttsp4_sleep_state {
+ SS_SLEEP_OFF,
+ SS_SLEEP_ON,
+ SS_SLEEPING,
+ SS_WAKING,
+};
+
+enum cyttsp4_startup_state {
+ STARTUP_NONE,
+ STARTUP_QUEUED,
+ STARTUP_RUNNING,
+};
+
+#define CY_NUM_REVCTRL 8
+struct cyttsp4_cydata {
+ u8 ttpidh;
+ u8 ttpidl;
+ u8 fw_ver_major;
+ u8 fw_ver_minor;
+ u8 revctrl[CY_NUM_REVCTRL];
+ u8 blver_major;
+ u8 blver_minor;
+ u8 jtag_si_id3;
+ u8 jtag_si_id2;
+ u8 jtag_si_id1;
+ u8 jtag_si_id0;
+ u8 mfgid_sz;
+ u8 cyito_idh;
+ u8 cyito_idl;
+ u8 cyito_verh;
+ u8 cyito_verl;
+ u8 ttsp_ver_major;
+ u8 ttsp_ver_minor;
+ u8 device_info;
+ u8 mfg_id[];
+} __packed;
+
+struct cyttsp4_test {
+ u8 post_codeh;
+ u8 post_codel;
+} __packed;
+
+struct cyttsp4_pcfg {
+ u8 electrodes_x;
+ u8 electrodes_y;
+ u8 len_xh;
+ u8 len_xl;
+ u8 len_yh;
+ u8 len_yl;
+ u8 res_xh;
+ u8 res_xl;
+ u8 res_yh;
+ u8 res_yl;
+ u8 max_zh;
+ u8 max_zl;
+ u8 panel_info0;
+} __packed;
+
+struct cyttsp4_tch_rec_params {
+ u8 loc;
+ u8 size;
+} __packed;
+
+#define CY_NUM_TCH_FIELDS 7
+#define CY_NUM_EXT_TCH_FIELDS 3
+struct cyttsp4_opcfg {
+ u8 cmd_ofs;
+ u8 rep_ofs;
+ u8 rep_szh;
+ u8 rep_szl;
+ u8 num_btns;
+ u8 tt_stat_ofs;
+ u8 obj_cfg0;
+ u8 max_tchs;
+ u8 tch_rec_size;
+ struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS];
+ u8 btn_rec_size; /* btn record size (in bytes) */
+ u8 btn_diff_ofs; /* btn data loc, diff counts */
+ u8 btn_diff_size; /* btn size of diff counts (in bits) */
+ struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS];
+} __packed;
+
+struct cyttsp4_sysinfo_ptr {
+ struct cyttsp4_cydata *cydata;
+ struct cyttsp4_test *test;
+ struct cyttsp4_pcfg *pcfg;
+ struct cyttsp4_opcfg *opcfg;
+ struct cyttsp4_ddata *ddata;
+ struct cyttsp4_mdata *mdata;
+} __packed;
+
+struct cyttsp4_sysinfo_data {
+ u8 hst_mode;
+ u8 reserved;
+ u8 map_szh;
+ u8 map_szl;
+ u8 cydata_ofsh;
+ u8 cydata_ofsl;
+ u8 test_ofsh;
+ u8 test_ofsl;
+ u8 pcfg_ofsh;
+ u8 pcfg_ofsl;
+ u8 opcfg_ofsh;
+ u8 opcfg_ofsl;
+ u8 ddata_ofsh;
+ u8 ddata_ofsl;
+ u8 mdata_ofsh;
+ u8 mdata_ofsl;
+} __packed;
+
+enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */
+ CY_TCH_X, /* X */
+ CY_TCH_Y, /* Y */
+ CY_TCH_P, /* P (Z) */
+ CY_TCH_T, /* TOUCH ID */
+ CY_TCH_E, /* EVENT ID */
+ CY_TCH_O, /* OBJECT ID */
+ CY_TCH_W, /* SIZE */
+ CY_TCH_MAJ, /* TOUCH_MAJOR */
+ CY_TCH_MIN, /* TOUCH_MINOR */
+ CY_TCH_OR, /* ORIENTATION */
+ CY_TCH_NUM_ABS
+};
+
+static const char * const cyttsp4_tch_abs_string[] = {
+ [CY_TCH_X] = "X",
+ [CY_TCH_Y] = "Y",
+ [CY_TCH_P] = "P",
+ [CY_TCH_T] = "T",
+ [CY_TCH_E] = "E",
+ [CY_TCH_O] = "O",
+ [CY_TCH_W] = "W",
+ [CY_TCH_MAJ] = "MAJ",
+ [CY_TCH_MIN] = "MIN",
+ [CY_TCH_OR] = "OR",
+ [CY_TCH_NUM_ABS] = "INVALID"
+};
+
+struct cyttsp4_touch {
+ int abs[CY_TCH_NUM_ABS];
+};
+
+struct cyttsp4_tch_abs_params {
+ size_t ofs; /* abs byte offset */
+ size_t size; /* size in bits */
+ size_t max; /* max value */
+ size_t bofs; /* bit offset */
+};
+
+struct cyttsp4_sysinfo_ofs {
+ size_t chip_type;
+ size_t cmd_ofs;
+ size_t rep_ofs;
+ size_t rep_sz;
+ size_t num_btns;
+ size_t num_btn_regs; /* ceil(num_btns/4) */
+ size_t tt_stat_ofs;
+ size_t tch_rec_size;
+ size_t obj_cfg0;
+ size_t max_tchs;
+ size_t mode_size;
+ size_t data_size;
+ size_t map_sz;
+ size_t max_x;
+ size_t x_origin; /* left or right corner */
+ size_t max_y;
+ size_t y_origin; /* upper or lower corner */
+ size_t max_p;
+ size_t cydata_ofs;
+ size_t test_ofs;
+ size_t pcfg_ofs;
+ size_t opcfg_ofs;
+ size_t ddata_ofs;
+ size_t mdata_ofs;
+ size_t cydata_size;
+ size_t test_size;
+ size_t pcfg_size;
+ size_t opcfg_size;
+ size_t ddata_size;
+ size_t mdata_size;
+ size_t btn_keys_size;
+ struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS];
+ size_t btn_rec_size; /* btn record size (in bytes) */
+ size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */
+ size_t btn_diff_size;/* btn size of diff counts (in bits) */
+};
+
+enum cyttsp4_btn_state {
+ CY_BTN_RELEASED,
+ CY_BTN_PRESSED,
+ CY_BTN_NUM_STATE
+};
+
+struct cyttsp4_btn {
+ bool enabled;
+ int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */
+ int key_code;
+};
+
+struct cyttsp4_sysinfo {
+ bool ready;
+ struct cyttsp4_sysinfo_data si_data;
+ struct cyttsp4_sysinfo_ptr si_ptrs;
+ struct cyttsp4_sysinfo_ofs si_ofs;
+ struct cyttsp4_btn *btn; /* button states */
+ u8 *btn_rec_data; /* button diff count data */
+ u8 *xy_mode; /* operational mode and status regs */
+ u8 *xy_data; /* operational touch regs */
+};
+
+struct cyttsp4_mt_data {
+ struct cyttsp4_mt_platform_data *pdata;
+ struct cyttsp4_sysinfo *si;
+ struct input_dev *input;
+ struct mutex report_lock;
+ bool is_suspended;
+ char phys[NAME_MAX];
+ int num_prv_tch;
+};
+
+struct cyttsp4 {
+ struct device *dev;
+ struct mutex system_lock;
+ struct mutex adap_lock;
+ enum cyttsp4_mode mode;
+ enum cyttsp4_sleep_state sleep_state;
+ enum cyttsp4_startup_state startup_state;
+ int int_status;
+ wait_queue_head_t wait_q;
+ int irq;
+ struct work_struct startup_work;
+ struct work_struct watchdog_work;
+ struct timer_list watchdog_timer;
+ struct cyttsp4_sysinfo sysinfo;
+ void *exclusive_dev;
+ int exclusive_waits;
+ atomic_t ignore_irq;
+ bool invalid_touch_app;
+ struct cyttsp4_mt_data md;
+ struct cyttsp4_platform_data *pdata;
+ struct cyttsp4_core_platform_data *cpdata;
+ const struct cyttsp4_bus_ops *bus_ops;
+ u8 *xfer_buf;
+#ifdef VERBOSE_DEBUG
+ u8 pr_buf[CY_MAX_PRBUF_SIZE];
+#endif
+};
+
+struct cyttsp4_bus_ops {
+ u16 bustype;
+ int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+ const void *values);
+ int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+ void *values);
+};
+
+enum cyttsp4_hst_mode_bits {
+ CY_HST_TOGGLE = (1 << 7),
+ CY_HST_MODE_CHANGE = (1 << 3),
+ CY_HST_MODE = (7 << 4),
+ CY_HST_OPERATE = (0 << 4),
+ CY_HST_SYSINFO = (1 << 4),
+ CY_HST_CAT = (2 << 4),
+ CY_HST_LOWPOW = (1 << 2),
+ CY_HST_SLEEP = (1 << 1),
+ CY_HST_RESET = (1 << 0),
+};
+
+/* abs settings */
+#define CY_IGNORE_VALUE 0xFFFF
+
+/* abs signal capabilities offsets in the frameworks array */
+enum cyttsp4_sig_caps {
+ CY_SIGNAL_OST,
+ CY_MIN_OST,
+ CY_MAX_OST,
+ CY_FUZZ_OST,
+ CY_FLAT_OST,
+ CY_NUM_ABS_SET /* number of signal capability fields */
+};
+
+/* abs axis signal offsets in the framworks array */
+enum cyttsp4_sig_ost {
+ CY_ABS_X_OST,
+ CY_ABS_Y_OST,
+ CY_ABS_P_OST,
+ CY_ABS_W_OST,
+ CY_ABS_ID_OST,
+ CY_ABS_MAJ_OST,
+ CY_ABS_MIN_OST,
+ CY_ABS_OR_OST,
+ CY_NUM_ABS_OST /* number of abs signals */
+};
+
+enum cyttsp4_flags {
+ CY_FLAG_NONE = 0x00,
+ CY_FLAG_HOVER = 0x04,
+ CY_FLAG_FLIP = 0x08,
+ CY_FLAG_INV_X = 0x10,
+ CY_FLAG_INV_Y = 0x20,
+ CY_FLAG_VKEYS = 0x40,
+};
+
+enum cyttsp4_object_id {
+ CY_OBJ_STANDARD_FINGER,
+ CY_OBJ_LARGE_OBJECT,
+ CY_OBJ_STYLUS,
+ CY_OBJ_HOVER,
+};
+
+enum cyttsp4_event_id {
+ CY_EV_NO_EVENT,
+ CY_EV_TOUCHDOWN,
+ CY_EV_MOVE, /* significant displacement (> act dist) */
+ CY_EV_LIFTOFF, /* record reports last position */
+};
+
+/* x-axis resolution of panel in pixels */
+#define CY_PCFG_RESOLUTION_X_MASK 0x7F
+
+/* y-axis resolution of panel in pixels */
+#define CY_PCFG_RESOLUTION_Y_MASK 0x7F
+
+/* x-axis, 0:origin is on left side of panel, 1: right */
+#define CY_PCFG_ORIGIN_X_MASK 0x80
+
+/* y-axis, 0:origin is on top side of panel, 1: bottom */
+#define CY_PCFG_ORIGIN_Y_MASK 0x80
+
+static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u8 addr, int size,
+ void *buf)
+{
+ return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf);
+}
+
+static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u8 addr, int size,
+ const void *buf)
+{
+ return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf);
+}
+
+extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
+ struct device *dev, u16 irq, size_t xfer_buf_size);
+extern int cyttsp4_remove(struct cyttsp4 *ts);
+int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+ u8 length, const void *values);
+int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+ u8 length, void *values);
+extern const struct dev_pm_ops cyttsp4_pm_ops;
+
+#endif /* _LINUX_CYTTSP4_CORE_H */
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c
new file mode 100644
index 000000000000..8e2012c79058
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_i2c.c
@@ -0,0 +1,90 @@
+/*
+ * cyttsp_i2c.c
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ * Copyright (C) 2013 Cypress Semiconductor
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
+ *
+ */
+
+#include "cyttsp4_core.h"
+
+#include <linux/i2c.h>
+#include <linux/input.h>
+
+#define CYTTSP4_I2C_DATA_SIZE (3 * 256)
+
+static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = {
+ .bustype = BUS_I2C,
+ .write = cyttsp_i2c_write_block_data,
+ .read = cyttsp_i2c_read_block_data,
+};
+
+static int cyttsp4_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cyttsp4 *ts;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "I2C functionality not Supported\n");
+ return -EIO;
+ }
+
+ ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
+ CYTTSP4_I2C_DATA_SIZE);
+
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+
+ return 0;
+}
+
+static int cyttsp4_i2c_remove(struct i2c_client *client)
+{
+ struct cyttsp4 *ts = i2c_get_clientdata(client);
+
+ cyttsp4_remove(ts);
+
+ return 0;
+}
+
+static const struct i2c_device_id cyttsp4_i2c_id[] = {
+ { CYTTSP4_I2C_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
+
+static struct i2c_driver cyttsp4_i2c_driver = {
+ .driver = {
+ .name = CYTTSP4_I2C_NAME,
+ .owner = THIS_MODULE,
+ .pm = &cyttsp4_pm_ops,
+ },
+ .probe = cyttsp4_i2c_probe,
+ .remove = cyttsp4_i2c_remove,
+ .id_table = cyttsp4_i2c_id,
+};
+
+module_i2c_driver(cyttsp4_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("i2c:cyttsp4");
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c
new file mode 100644
index 000000000000..f8f891bead34
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_spi.c
@@ -0,0 +1,205 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ * Copyright (C) 2013 Cypress Semiconductor
+ *
+ * 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
+ *
+ */
+
+#include "cyttsp4_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+
+#define CY_SPI_WR_OP 0x00 /* r/~w */
+#define CY_SPI_RD_OP 0x01
+#define CY_SPI_BITS_PER_WORD 8
+#define CY_SPI_A8_BIT 0x02
+#define CY_SPI_WR_HEADER_BYTES 2
+#define CY_SPI_RD_HEADER_BYTES 1
+#define CY_SPI_CMD_BYTES 2
+#define CY_SPI_SYNC_BYTE 0
+#define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */
+#define CY_SPI_DATA_SIZE (2 * 256)
+
+#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+
+static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
+ u8 op, u8 reg, u8 *buf, int length)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct spi_message msg;
+ struct spi_transfer xfer[2];
+ u8 *wr_buf = &xfer_buf[0];
+ u8 rd_buf[CY_SPI_CMD_BYTES];
+ int retval;
+ int i;
+
+ if (length > CY_SPI_DATA_SIZE) {
+ dev_err(dev, "%s: length %d is too big.\n",
+ __func__, length);
+ return -EINVAL;
+ }
+
+ memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+ memset(rd_buf, 0, CY_SPI_CMD_BYTES);
+
+ if (reg > 255)
+ wr_buf[0] = op + CY_SPI_A8_BIT;
+ else
+ wr_buf[0] = op;
+ if (op == CY_SPI_WR_OP)
+ wr_buf[1] = reg % 256;
+ if (op == CY_SPI_WR_OP && length > 0)
+ memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+ memset(xfer, 0, sizeof(xfer));
+ spi_message_init(&msg);
+
+ /*
+ We set both TX and RX buffers because Cypress TTSP
+ requires full duplex operation.
+ */
+ xfer[0].tx_buf = wr_buf;
+ xfer[0].rx_buf = rd_buf;
+ switch (op) {
+ case CY_SPI_WR_OP:
+ xfer[0].len = length + CY_SPI_CMD_BYTES;
+ spi_message_add_tail(&xfer[0], &msg);
+ break;
+
+ case CY_SPI_RD_OP:
+ xfer[0].len = CY_SPI_RD_HEADER_BYTES;
+ spi_message_add_tail(&xfer[0], &msg);
+
+ xfer[1].rx_buf = buf;
+ xfer[1].len = length;
+ spi_message_add_tail(&xfer[1], &msg);
+ break;
+
+ default:
+ dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
+ return -EINVAL;
+ }
+
+ retval = spi_sync(spi, &msg);
+ if (retval < 0) {
+ dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
+ __func__, retval, xfer[1].len, op);
+
+ /*
+ * do not return here since was a bad ACK sequence
+ * let the following ACK check handle any errors and
+ * allow silent retries
+ */
+ }
+
+ if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
+ dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
+
+ for (i = 0; i < CY_SPI_CMD_BYTES; i++)
+ dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
+ __func__, i, rd_buf[i]);
+ for (i = 0; i < length; i++)
+ dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
+ __func__, i, buf[i]);
+
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
+ u8 addr, u8 length, void *data)
+{
+ int rc;
+
+ rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
+ if (rc)
+ return rc;
+ else
+ return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
+ length);
+}
+
+static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
+ u8 addr, u8 length, const void *data)
+{
+ return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
+ length);
+}
+
+static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
+ .bustype = BUS_SPI,
+ .write = cyttsp_spi_write_block_data,
+ .read = cyttsp_spi_read_block_data,
+};
+
+static int cyttsp4_spi_probe(struct spi_device *spi)
+{
+ struct cyttsp4 *ts;
+ int error;
+
+ /* Set up SPI*/
+ spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+ spi->mode = SPI_MODE_0;
+ error = spi_setup(spi);
+ if (error < 0) {
+ dev_err(&spi->dev, "%s: SPI setup error %d\n",
+ __func__, error);
+ return error;
+ }
+
+ ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
+ CY_SPI_DATA_BUF_SIZE);
+
+ if (IS_ERR(ts))
+ return PTR_ERR(ts);
+
+ return 0;
+}
+
+static int cyttsp4_spi_remove(struct spi_device *spi)
+{
+ struct cyttsp4 *ts = spi_get_drvdata(spi);
+ cyttsp4_remove(ts);
+
+ return 0;
+}
+
+static struct spi_driver cyttsp4_spi_driver = {
+ .driver = {
+ .name = CYTTSP4_SPI_NAME,
+ .owner = THIS_MODULE,
+ .pm = &cyttsp4_pm_ops,
+ },
+ .probe = cyttsp4_spi_probe,
+ .remove = cyttsp4_spi_remove,
+};
+
+module_spi_driver(cyttsp4_spi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+MODULE_ALIAS("spi:cyttsp4");
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index ae89d2609ab0..d53e0b72a407 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -84,7 +84,8 @@ static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
int tries;
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
- error = ts->bus_ops->read(ts, command, length, buf);
+ error = ts->bus_ops->read(ts->dev, ts->xfer_buf, command,
+ length, buf);
if (!error)
return 0;
@@ -101,7 +102,8 @@ static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
int tries;
for (tries = 0; tries < CY_NUM_RETRY; tries++) {
- error = ts->bus_ops->write(ts, command, length, buf);
+ error = ts->bus_ops->write(ts->dev, ts->xfer_buf, command,
+ length, buf);
if (!error)
return 0;
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
index f1ebde369f86..0cf564a79fb5 100644
--- a/drivers/input/touchscreen/cyttsp_core.h
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -112,9 +112,10 @@ struct cyttsp;
struct cyttsp_bus_ops {
u16 bustype;
- int (*write)(struct cyttsp *ts,
- u8 addr, u8 length, const void *values);
- int (*read)(struct cyttsp *ts, u8 addr, u8 length, void *values);
+ int (*write)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+ const void *values);
+ int (*read)(struct device *dev, u8 *xfer_buf, u8 addr, u8 length,
+ void *values);
};
enum cyttsp_state {
@@ -144,6 +145,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size);
void cyttsp_remove(struct cyttsp *ts);
+int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+ u8 length, const void *values);
+int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u8 addr,
+ u8 length, void *values);
extern const struct dev_pm_ops cyttsp_pm_ops;
#endif /* __CYTTSP_CORE_H__ */
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
index 4dbdf44b8fc5..63104a86a9bd 100644
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -1,5 +1,5 @@
/*
- * Source for:
+ * cyttsp_i2c.c
* Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
* For use with Cypress Txx3xx parts.
* Supported parts include:
@@ -19,11 +19,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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.
- *
- * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
@@ -34,47 +30,6 @@
#define CY_I2C_DATA_SIZE 128
-static int cyttsp_i2c_read_block_data(struct cyttsp *ts,
- u8 addr, u8 length, void *values)
-{
- struct i2c_client *client = to_i2c_client(ts->dev);
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = &addr,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = values,
- },
- };
- int retval;
-
- retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (retval < 0)
- return retval;
-
- return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
-}
-
-static int cyttsp_i2c_write_block_data(struct cyttsp *ts,
- u8 addr, u8 length, const void *values)
-{
- struct i2c_client *client = to_i2c_client(ts->dev);
- int retval;
-
- ts->xfer_buf[0] = addr;
- memcpy(&ts->xfer_buf[1], values, length);
-
- retval = i2c_master_send(client, ts->xfer_buf, length + 1);
-
- return retval < 0 ? retval : 0;
-}
-
static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
@@ -98,7 +53,6 @@ static int cyttsp_i2c_probe(struct i2c_client *client,
return PTR_ERR(ts);
i2c_set_clientdata(client, ts);
-
return 0;
}
diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c
new file mode 100644
index 000000000000..07c553fbcef2
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c_common.c
@@ -0,0 +1,79 @@
+/*
+ * cyttsp_i2c_common.c
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx and Txx4xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.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, 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.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
+ u8 addr, u8 length, void *values)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = values,
+ },
+ };
+ int retval;
+
+ retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (retval < 0)
+ return retval;
+
+ return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data);
+
+int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
+ u8 addr, u8 length, const void *values)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int retval;
+
+ xfer_buf[0] = addr;
+ memcpy(&xfer_buf[1], values, length);
+
+ retval = i2c_master_send(client, xfer_buf, length + 1);
+
+ return retval < 0 ? retval : 0;
+}
+EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 861b7f77605b..1df625337b84 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -8,6 +8,7 @@
*
* Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
* Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
+ * Copyright (C) 2013 Cypress Semiconductor
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,11 +20,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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.
- *
- * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
*
*/
@@ -43,19 +40,19 @@
#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
#define CY_SPI_BITS_PER_WORD 8
-static int cyttsp_spi_xfer(struct cyttsp *ts,
+static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
u8 op, u8 reg, u8 *buf, int length)
{
- struct spi_device *spi = to_spi_device(ts->dev);
+ struct spi_device *spi = to_spi_device(dev);
struct spi_message msg;
struct spi_transfer xfer[2];
- u8 *wr_buf = &ts->xfer_buf[0];
- u8 *rd_buf = &ts->xfer_buf[CY_SPI_DATA_BUF_SIZE];
+ u8 *wr_buf = &xfer_buf[0];
+ u8 *rd_buf = &xfer_buf[CY_SPI_DATA_BUF_SIZE];
int retval;
int i;
if (length > CY_SPI_DATA_SIZE) {
- dev_err(ts->dev, "%s: length %d is too big.\n",
+ dev_err(dev, "%s: length %d is too big.\n",
__func__, length);
return -EINVAL;
}
@@ -95,13 +92,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts,
break;
default:
- dev_err(ts->dev, "%s: bad operation code=%d\n", __func__, op);
+ dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
return -EINVAL;
}
retval = spi_sync(spi, &msg);
if (retval < 0) {
- dev_dbg(ts->dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
+ dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
__func__, retval, xfer[1].len, op);
/*
@@ -113,14 +110,13 @@ static int cyttsp_spi_xfer(struct cyttsp *ts,
if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK1 ||
rd_buf[CY_SPI_SYNC_BYTE + 1] != CY_SPI_SYNC_ACK2) {
-
- dev_dbg(ts->dev, "%s: operation %d failed\n", __func__, op);
+ dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
for (i = 0; i < CY_SPI_CMD_BYTES; i++)
- dev_dbg(ts->dev, "%s: test rd_buf[%d]:0x%02x\n",
+ dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
__func__, i, rd_buf[i]);
for (i = 0; i < length; i++)
- dev_dbg(ts->dev, "%s: test buf[%d]:0x%02x\n",
+ dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
__func__, i, buf[i]);
return -EIO;
@@ -129,16 +125,18 @@ static int cyttsp_spi_xfer(struct cyttsp *ts,
return 0;
}
-static int cyttsp_spi_read_block_data(struct cyttsp *ts,
+static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, void *data)
{
- return cyttsp_spi_xfer(ts, CY_SPI_RD_OP, addr, data, length);
+ return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
+ length);
}
-static int cyttsp_spi_write_block_data(struct cyttsp *ts,
+static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
u8 addr, u8 length, const void *data)
{
- return cyttsp_spi_xfer(ts, CY_SPI_WR_OP, addr, (void *)data, length);
+ return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
+ length);
}
static const struct cyttsp_bus_ops cyttsp_spi_bus_ops = {
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
index 8f561e22bdd4..ab64d58c3ac0 100644
--- a/drivers/input/touchscreen/da9052_tsi.c
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -329,8 +329,6 @@ static int da9052_ts_remove(struct platform_device *pdev)
input_unregister_device(tsi->dev);
kfree(tsi);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index 39f3df8670c3..ef5fcb0945e9 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -166,24 +166,22 @@ static int egalax_firmware_version(struct i2c_client *client)
}
static int egalax_ts_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct egalax_ts *ts;
struct input_dev *input_dev;
- int ret;
int error;
- ts = kzalloc(sizeof(struct egalax_ts), GFP_KERNEL);
+ ts = devm_kzalloc(&client->dev, sizeof(struct egalax_ts), GFP_KERNEL);
if (!ts) {
dev_err(&client->dev, "Failed to allocate memory\n");
return -ENOMEM;
}
- input_dev = input_allocate_device();
+ input_dev = devm_input_allocate_device(&client->dev);
if (!input_dev) {
dev_err(&client->dev, "Failed to allocate memory\n");
- error = -ENOMEM;
- goto err_free_ts;
+ return -ENOMEM;
}
ts->client = client;
@@ -193,19 +191,17 @@ static int egalax_ts_probe(struct i2c_client *client,
error = egalax_wake_up_device(client);
if (error) {
dev_err(&client->dev, "Failed to wake up the controller\n");
- goto err_free_dev;
+ return error;
}
- ret = egalax_firmware_version(client);
- if (ret < 0) {
+ error = egalax_firmware_version(client);
+ if (error < 0) {
dev_err(&client->dev, "Failed to read firmware version\n");
- error = -EIO;
- goto err_free_dev;
+ return error;
}
input_dev->name = "EETI eGalax Touch Screen";
input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = &client->dev;
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
@@ -221,41 +217,21 @@ static int egalax_ts_probe(struct i2c_client *client,
input_set_drvdata(input_dev, ts);
- error = request_threaded_irq(client->irq, NULL, egalax_ts_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "egalax_ts", ts);
+ error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ egalax_ts_interrupt,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "egalax_ts", ts);
if (error < 0) {
dev_err(&client->dev, "Failed to register interrupt\n");
- goto err_free_dev;
+ return error;
}
error = input_register_device(ts->input_dev);
if (error)
- goto err_free_irq;
+ return error;
i2c_set_clientdata(client, ts);
return 0;
-
-err_free_irq:
- free_irq(client->irq, ts);
-err_free_dev:
- input_free_device(input_dev);
-err_free_ts:
- kfree(ts);
-
- return error;
-}
-
-static int egalax_ts_remove(struct i2c_client *client)
-{
- struct egalax_ts *ts = i2c_get_clientdata(client);
-
- free_irq(client->irq, ts);
-
- input_unregister_device(ts->input_dev);
- kfree(ts);
-
- return 0;
}
static const struct i2c_device_id egalax_ts_id[] = {
@@ -301,7 +277,6 @@ static struct i2c_driver egalax_ts_driver = {
},
.id_table = egalax_ts_id,
.probe = egalax_ts_probe,
- .remove = egalax_ts_remove,
};
module_i2c_driver(egalax_ts_driver);
diff --git a/drivers/input/touchscreen/intel-mid-touch.c b/drivers/input/touchscreen/intel-mid-touch.c
index 465db5dba8b4..e30d837dae2f 100644
--- a/drivers/input/touchscreen/intel-mid-touch.c
+++ b/drivers/input/touchscreen/intel-mid-touch.c
@@ -651,8 +651,6 @@ static int mrstouch_remove(struct platform_device *pdev)
input_unregister_device(tsdev->input);
kfree(tsdev);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c
index 282d7c7ad2fc..e463a79ffecc 100644
--- a/drivers/input/touchscreen/jornada720_ts.c
+++ b/drivers/input/touchscreen/jornada720_ts.c
@@ -145,7 +145,6 @@ static int jornada720_ts_probe(struct platform_device *pdev)
fail2:
free_irq(IRQ_GPIO9, pdev);
fail1:
- platform_set_drvdata(pdev, NULL);
input_free_device(input_dev);
kfree(jornada_ts);
return error;
@@ -156,7 +155,6 @@ static int jornada720_ts_remove(struct platform_device *pdev)
struct jornada_ts *jornada_ts = platform_get_drvdata(pdev);
free_irq(IRQ_GPIO9, pdev);
- platform_set_drvdata(pdev, NULL);
input_unregister_device(jornada_ts->dev);
kfree(jornada_ts);
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index 89308fe38752..d6f099c47f84 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -233,8 +233,6 @@ static int mc13783_ts_remove(struct platform_device *pdev)
{
struct mc13783_ts_priv *priv = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
destroy_workqueue(priv->workq);
input_unregister_device(priv->idev);
kfree(priv);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 51e7b87827a4..e1c5300cacfc 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -24,8 +24,9 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/io.h>
-#include <linux/input/ti_am335x_tsc.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mfd/ti_am335x_tscadc.h>
@@ -33,6 +34,13 @@
#define SEQ_SETTLE 275
#define MAX_12BIT ((1 << 12) - 1)
+static const int config_pins[] = {
+ STEPCONFIG_XPP,
+ STEPCONFIG_XNN,
+ STEPCONFIG_YPP,
+ STEPCONFIG_YNN,
+};
+
struct titsc {
struct input_dev *input;
struct ti_tscadc_dev *mfd_tscadc;
@@ -40,7 +48,10 @@ struct titsc {
unsigned int wires;
unsigned int x_plate_resistance;
bool pen_down;
- int steps_to_configure;
+ int coordinate_readouts;
+ u32 config_inp[4];
+ u32 bit_xp, bit_xn, bit_yp, bit_yn;
+ u32 inp_xp, inp_xn, inp_yp, inp_yn;
};
static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
@@ -54,92 +65,153 @@ static void titsc_writel(struct titsc *tsc, unsigned int reg,
writel(val, tsc->mfd_tscadc->tscadc_base + reg);
}
+static int titsc_config_wires(struct titsc *ts_dev)
+{
+ u32 analog_line[4];
+ u32 wire_order[4];
+ int i, bit_cfg;
+
+ for (i = 0; i < 4; i++) {
+ /*
+ * Get the order in which TSC wires are attached
+ * w.r.t. each of the analog input lines on the EVM.
+ */
+ analog_line[i] = (ts_dev->config_inp[i] & 0xF0) >> 4;
+ wire_order[i] = ts_dev->config_inp[i] & 0x0F;
+ if (WARN_ON(analog_line[i] > 7))
+ return -EINVAL;
+ if (WARN_ON(wire_order[i] > ARRAY_SIZE(config_pins)))
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 4; i++) {
+ int an_line;
+ int wi_order;
+
+ an_line = analog_line[i];
+ wi_order = wire_order[i];
+ bit_cfg = config_pins[wi_order];
+ if (bit_cfg == 0)
+ return -EINVAL;
+ switch (wi_order) {
+ case 0:
+ ts_dev->bit_xp = bit_cfg;
+ ts_dev->inp_xp = an_line;
+ break;
+
+ case 1:
+ ts_dev->bit_xn = bit_cfg;
+ ts_dev->inp_xn = an_line;
+ break;
+
+ case 2:
+ ts_dev->bit_yp = bit_cfg;
+ ts_dev->inp_yp = an_line;
+ break;
+ case 3:
+ ts_dev->bit_yn = bit_cfg;
+ ts_dev->inp_yn = an_line;
+ break;
+ }
+ }
+ return 0;
+}
+
static void titsc_step_config(struct titsc *ts_dev)
{
unsigned int config;
- int i, total_steps;
-
- /* Configure the Step registers */
- total_steps = 2 * ts_dev->steps_to_configure;
+ int i;
+ int end_step;
+ u32 stepenable;
config = STEPCONFIG_MODE_HWSYNC |
- STEPCONFIG_AVG_16 | STEPCONFIG_XPP;
+ STEPCONFIG_AVG_16 | ts_dev->bit_xp;
switch (ts_dev->wires) {
case 4:
- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN;
+ config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
break;
case 5:
- config |= STEPCONFIG_YNN |
- STEPCONFIG_INP_AN4 | STEPCONFIG_XNN |
- STEPCONFIG_YPP;
+ config |= ts_dev->bit_yn |
+ STEPCONFIG_INP_AN4 | ts_dev->bit_xn |
+ ts_dev->bit_yp;
break;
case 8:
- config |= STEPCONFIG_INP_AN2 | STEPCONFIG_XNN;
+ config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn;
break;
}
- for (i = 1; i <= ts_dev->steps_to_configure; i++) {
+ /* 1 … coordinate_readouts is for X */
+ end_step = ts_dev->coordinate_readouts;
+ for (i = 0; i < end_step; i++) {
titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
}
config = 0;
config = STEPCONFIG_MODE_HWSYNC |
- STEPCONFIG_AVG_16 | STEPCONFIG_YNN |
- STEPCONFIG_INM_ADCREFM | STEPCONFIG_FIFO1;
+ STEPCONFIG_AVG_16 | ts_dev->bit_yn |
+ STEPCONFIG_INM_ADCREFM;
switch (ts_dev->wires) {
case 4:
- config |= STEPCONFIG_YPP;
+ config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
break;
case 5:
- config |= STEPCONFIG_XPP | STEPCONFIG_INP_AN4 |
- STEPCONFIG_XNP | STEPCONFIG_YPN;
+ config |= ts_dev->bit_xp | STEPCONFIG_INP_AN4 |
+ ts_dev->bit_xn | ts_dev->bit_yp;
break;
case 8:
- config |= STEPCONFIG_YPP;
+ config |= ts_dev->bit_yp | STEPCONFIG_INP(ts_dev->inp_xp);
break;
}
- for (i = (ts_dev->steps_to_configure + 1); i <= total_steps; i++) {
+ /* coordinate_readouts … coordinate_readouts * 2 is for Y */
+ end_step = ts_dev->coordinate_readouts * 2;
+ for (i = ts_dev->coordinate_readouts; i < end_step; i++) {
titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
}
- config = 0;
/* Charge step configuration */
- config = STEPCONFIG_XPP | STEPCONFIG_YNN |
+ config = ts_dev->bit_xp | ts_dev->bit_yn |
STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
- STEPCHARGE_INM_AN1 | STEPCHARGE_INP_AN1;
+ STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp);
titsc_writel(ts_dev, REG_CHARGECONFIG, config);
titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
- config = 0;
- /* Configure to calculate pressure */
+ /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
config = STEPCONFIG_MODE_HWSYNC |
- STEPCONFIG_AVG_16 | STEPCONFIG_YPP |
- STEPCONFIG_XNN | STEPCONFIG_INM_ADCREFM;
- titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 1), config);
- titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 1),
+ STEPCONFIG_AVG_16 | ts_dev->bit_yp |
+ ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
+ STEPCONFIG_INP(ts_dev->inp_xp);
+ titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+ titsc_writel(ts_dev, REG_STEPDELAY(end_step),
STEPCONFIG_OPENDLY);
- config |= STEPCONFIG_INP_AN3 | STEPCONFIG_FIFO1;
- titsc_writel(ts_dev, REG_STEPCONFIG(total_steps + 2), config);
- titsc_writel(ts_dev, REG_STEPDELAY(total_steps + 2),
+ end_step++;
+ config |= STEPCONFIG_INP(ts_dev->inp_yn);
+ titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config);
+ titsc_writel(ts_dev, REG_STEPDELAY(end_step),
STEPCONFIG_OPENDLY);
- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC);
+ /* The steps1 … end and bit 0 for TS_Charge */
+ stepenable = (1 << (end_step + 2)) - 1;
+ am335x_tsc_se_set(ts_dev->mfd_tscadc, stepenable);
}
static void titsc_read_coordinates(struct titsc *ts_dev,
- unsigned int *x, unsigned int *y)
+ u32 *x, u32 *y, u32 *z1, u32 *z2)
{
unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
unsigned int prev_val_x = ~0, prev_val_y = ~0;
unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
unsigned int read, diff;
unsigned int i, channel;
+ unsigned int creads = ts_dev->coordinate_readouts;
+ *z1 = *z2 = 0;
+ if (fifocount % (creads * 2 + 2))
+ fifocount -= fifocount % (creads * 2 + 2);
/*
* Delta filter is used to remove large variations in sampled
* values from ADC. The filter tries to predict where the next
@@ -148,32 +220,32 @@ static void titsc_read_coordinates(struct titsc *ts_dev,
* algorithm compares the difference with that of a present value,
* if true the value is reported to the sub system.
*/
- for (i = 0; i < fifocount - 1; i++) {
+ for (i = 0; i < fifocount; i++) {
read = titsc_readl(ts_dev, REG_FIFO0);
- channel = read & 0xf0000;
- channel = channel >> 0x10;
- if ((channel >= 0) && (channel < ts_dev->steps_to_configure)) {
- read &= 0xfff;
+
+ channel = (read & 0xf0000) >> 16;
+ read &= 0xfff;
+ if (channel < creads) {
diff = abs(read - prev_val_x);
if (diff < prev_diff_x) {
prev_diff_x = diff;
*x = read;
}
prev_val_x = read;
- }
- read = titsc_readl(ts_dev, REG_FIFO1);
- channel = read & 0xf0000;
- channel = channel >> 0x10;
- if ((channel >= ts_dev->steps_to_configure) &&
- (channel < (2 * ts_dev->steps_to_configure - 1))) {
- read &= 0xfff;
+ } else if (channel < creads * 2) {
diff = abs(read - prev_val_y);
if (diff < prev_diff_y) {
prev_diff_y = diff;
*y = read;
}
prev_val_y = read;
+
+ } else if (channel < creads * 2 + 1) {
+ *z1 = read;
+
+ } else if (channel < creads * 2 + 2) {
+ *z2 = read;
}
}
}
@@ -186,23 +258,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
unsigned int x = 0, y = 0;
unsigned int z1, z2, z;
unsigned int fsm;
- unsigned int fifo1count, fifo0count;
- int i;
status = titsc_readl(ts_dev, REG_IRQSTATUS);
if (status & IRQENB_FIFO0THRES) {
- titsc_read_coordinates(ts_dev, &x, &y);
- z1 = titsc_readl(ts_dev, REG_FIFO0) & 0xfff;
- z2 = titsc_readl(ts_dev, REG_FIFO1) & 0xfff;
-
- fifo1count = titsc_readl(ts_dev, REG_FIFO1CNT);
- for (i = 0; i < fifo1count; i++)
- titsc_readl(ts_dev, REG_FIFO1);
-
- fifo0count = titsc_readl(ts_dev, REG_FIFO0CNT);
- for (i = 0; i < fifo0count; i++)
- titsc_readl(ts_dev, REG_FIFO0);
+ titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
/*
@@ -210,10 +270,10 @@ static irqreturn_t titsc_irq(int irq, void *dev)
* Resistance(touch) = x plate resistance *
* x postion/4096 * ((z2 / z1) - 1)
*/
- z = z2 - z1;
+ z = z1 - z2;
z *= x;
z *= ts_dev->x_plate_resistance;
- z /= z1;
+ z /= z2;
z = (z + 2047) >> 12;
if (z <= MAX_12BIT) {
@@ -248,10 +308,53 @@ static irqreturn_t titsc_irq(int irq, void *dev)
irqclr |= IRQENB_PENUP;
}
- titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+ if (status & IRQENB_HW_PEN) {
+
+ titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
+ titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
+ }
- titsc_writel(ts_dev, REG_SE, STPENB_STEPENB_TC);
- return IRQ_HANDLED;
+ if (irqclr) {
+ titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
+ am335x_tsc_se_update(ts_dev->mfd_tscadc);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int titsc_parse_dt(struct platform_device *pdev,
+ struct titsc *ts_dev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ int err;
+
+ if (!node)
+ return -EINVAL;
+
+ err = of_property_read_u32(node, "ti,wires", &ts_dev->wires);
+ if (err < 0)
+ return err;
+ switch (ts_dev->wires) {
+ case 4:
+ case 5:
+ case 8:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = of_property_read_u32(node, "ti,x-plate-resistance",
+ &ts_dev->x_plate_resistance);
+ if (err < 0)
+ return err;
+
+ err = of_property_read_u32(node, "ti,coordiante-readouts",
+ &ts_dev->coordinate_readouts);
+ if (err < 0)
+ return err;
+
+ return of_property_read_u32_array(node, "ti,wire-config",
+ ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
}
/*
@@ -262,17 +365,9 @@ static int titsc_probe(struct platform_device *pdev)
{
struct titsc *ts_dev;
struct input_dev *input_dev;
- struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
- struct mfd_tscadc_board *pdata;
+ struct ti_tscadc_dev *tscadc_dev = ti_tscadc_dev_get(pdev);
int err;
- pdata = tscadc_dev->dev->platform_data;
-
- if (!pdata) {
- dev_err(&pdev->dev, "Could not find platform data\n");
- return -EINVAL;
- }
-
/* Allocate memory for device */
ts_dev = kzalloc(sizeof(struct titsc), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -286,9 +381,12 @@ static int titsc_probe(struct platform_device *pdev)
ts_dev->mfd_tscadc = tscadc_dev;
ts_dev->input = input_dev;
ts_dev->irq = tscadc_dev->irq;
- ts_dev->wires = pdata->tsc_init->wires;
- ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance;
- ts_dev->steps_to_configure = pdata->tsc_init->steps_to_configure;
+
+ err = titsc_parse_dt(pdev, ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "Could not find valid DT data.\n");
+ goto err_free_mem;
+ }
err = request_irq(ts_dev->irq, titsc_irq,
0, pdev->dev.driver->name, ts_dev);
@@ -298,8 +396,14 @@ static int titsc_probe(struct platform_device *pdev)
}
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
+ err = titsc_config_wires(ts_dev);
+ if (err) {
+ dev_err(&pdev->dev, "wrong i/p wire configuration\n");
+ goto err_free_irq;
+ }
titsc_step_config(ts_dev);
- titsc_writel(ts_dev, REG_FIFO0THR, ts_dev->steps_to_configure);
+ titsc_writel(ts_dev, REG_FIFO0THR,
+ ts_dev->coordinate_readouts * 2 + 2 - 1);
input_dev->name = "ti-tsc";
input_dev->dev.parent = &pdev->dev;
@@ -329,14 +433,18 @@ err_free_mem:
static int titsc_remove(struct platform_device *pdev)
{
- struct ti_tscadc_dev *tscadc_dev = pdev->dev.platform_data;
- struct titsc *ts_dev = tscadc_dev->tsc;
+ struct titsc *ts_dev = platform_get_drvdata(pdev);
+ u32 steps;
free_irq(ts_dev->irq, ts_dev);
+ /* total steps followed by the enable mask */
+ steps = 2 * ts_dev->coordinate_readouts + 2;
+ steps = (1 << steps) - 1;
+ am335x_tsc_se_clr(ts_dev->mfd_tscadc, steps);
+
input_unregister_device(ts_dev->input);
- platform_set_drvdata(pdev, NULL);
kfree(ts_dev);
return 0;
}
@@ -344,10 +452,11 @@ static int titsc_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int titsc_suspend(struct device *dev)
{
- struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
- struct titsc *ts_dev = tscadc_dev->tsc;
+ struct titsc *ts_dev = dev_get_drvdata(dev);
+ struct ti_tscadc_dev *tscadc_dev;
unsigned int idle;
+ tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
if (device_may_wakeup(tscadc_dev->dev)) {
idle = titsc_readl(ts_dev, REG_IRQENABLE);
titsc_writel(ts_dev, REG_IRQENABLE,
@@ -359,9 +468,10 @@ static int titsc_suspend(struct device *dev)
static int titsc_resume(struct device *dev)
{
- struct ti_tscadc_dev *tscadc_dev = dev->platform_data;
- struct titsc *ts_dev = tscadc_dev->tsc;
+ struct titsc *ts_dev = dev_get_drvdata(dev);
+ struct ti_tscadc_dev *tscadc_dev;
+ tscadc_dev = ti_tscadc_dev_get(to_platform_device(dev));
if (device_may_wakeup(tscadc_dev->dev)) {
titsc_writel(ts_dev, REG_IRQWAKEUP,
0x00);
@@ -369,7 +479,7 @@ static int titsc_resume(struct device *dev)
}
titsc_step_config(ts_dev);
titsc_writel(ts_dev, REG_FIFO0THR,
- ts_dev->steps_to_configure);
+ ts_dev->coordinate_readouts * 2 + 2 - 1);
return 0;
}
@@ -382,13 +492,20 @@ static const struct dev_pm_ops titsc_pm_ops = {
#define TITSC_PM_OPS NULL
#endif
+static const struct of_device_id ti_tsc_dt_ids[] = {
+ { .compatible = "ti,am3359-tsc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids);
+
static struct platform_driver ti_tsc_driver = {
.probe = titsc_probe,
.remove = titsc_remove,
.driver = {
- .name = "tsc",
+ .name = "TI-am335x-tsc",
.owner = THIS_MODULE,
.pm = TITSC_PM_OPS,
+ .of_match_table = of_match_ptr(ti_tsc_dt_ids),
},
};
module_platform_driver(ti_tsc_driver);
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
index acfb87607b87..c47827a26e3c 100644
--- a/drivers/input/touchscreen/tnetv107x-ts.c
+++ b/drivers/input/touchscreen/tnetv107x-ts.c
@@ -351,7 +351,6 @@ error_clk:
error_map:
release_mem_region(ts->res->start, resource_size(ts->res));
error_res:
- platform_set_drvdata(pdev, NULL);
kfree(ts);
return error;
@@ -366,7 +365,6 @@ static int tsc_remove(struct platform_device *pdev)
clk_put(ts->clk);
iounmap(ts->regs);
release_mem_region(ts->res->start, resource_size(ts->res));
- platform_set_drvdata(pdev, NULL);
kfree(ts);
return 0;
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index 820a066c3b8a..94cde2cb1491 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -17,6 +17,7 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps6507x.h>
#include <linux/input/tps6507x-ts.h>
@@ -38,20 +39,13 @@ struct ts_event {
};
struct tps6507x_ts {
- struct input_dev *input_dev;
struct device *dev;
+ struct input_polled_dev *poll_dev;
+ struct tps6507x_dev *mfd;
char phys[32];
- struct delayed_work work;
- unsigned polling; /* polling is active */
struct ts_event tc;
- struct tps6507x_dev *mfd;
- u16 model;
- unsigned pendown;
- int irq;
- void (*clear_penirq)(void);
- unsigned long poll_period; /* ms */
u16 min_pressure;
- int vref; /* non-zero to leave vref on */
+ bool pendown;
};
static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
@@ -161,18 +155,15 @@ static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
return ret;
}
-static void tps6507x_ts_handler(struct work_struct *work)
+static void tps6507x_ts_poll(struct input_polled_dev *poll_dev)
{
- struct tps6507x_ts *tsc = container_of(work,
- struct tps6507x_ts, work.work);
- struct input_dev *input_dev = tsc->input_dev;
- int pendown;
- int schd;
- int poll = 0;
+ struct tps6507x_ts *tsc = poll_dev->private;
+ struct input_dev *input_dev = poll_dev->input;
+ bool pendown;
s32 ret;
- ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
- &tsc->tc.pressure);
+ ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
+ &tsc->tc.pressure);
if (ret)
goto done;
@@ -183,7 +174,7 @@ static void tps6507x_ts_handler(struct work_struct *work)
input_report_key(input_dev, BTN_TOUCH, 0);
input_report_abs(input_dev, ABS_PRESSURE, 0);
input_sync(input_dev);
- tsc->pendown = 0;
+ tsc->pendown = false;
}
if (pendown) {
@@ -208,76 +199,69 @@ static void tps6507x_ts_handler(struct work_struct *work)
input_report_abs(input_dev, ABS_Y, tsc->tc.y);
input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
input_sync(input_dev);
- tsc->pendown = 1;
- poll = 1;
+ tsc->pendown = true;
}
done:
- /* always poll if not using interrupts */
- poll = 1;
-
- if (poll) {
- schd = schedule_delayed_work(&tsc->work,
- msecs_to_jiffies(tsc->poll_period));
- if (schd)
- tsc->polling = 1;
- else {
- tsc->polling = 0;
- dev_err(tsc->dev, "re-schedule failed");
- }
- } else
- tsc->polling = 0;
-
- ret = tps6507x_adc_standby(tsc);
+ tps6507x_adc_standby(tsc);
}
static int tps6507x_ts_probe(struct platform_device *pdev)
{
- int error;
- struct tps6507x_ts *tsc;
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
- struct touchscreen_init_data *init_data;
+ const struct tps6507x_board *tps_board;
+ const struct touchscreen_init_data *init_data;
+ struct tps6507x_ts *tsc;
+ struct input_polled_dev *poll_dev;
struct input_dev *input_dev;
- struct tps6507x_board *tps_board;
- int schd;
+ int error;
- /**
+ /*
* tps_board points to pmic related constants
* coming from the board-evm file.
*/
-
- tps_board = (struct tps6507x_board *)tps6507x_dev->dev->platform_data;
-
+ tps_board = dev_get_platdata(tps6507x_dev->dev);
if (!tps_board) {
dev_err(tps6507x_dev->dev,
"Could not find tps6507x platform data\n");
- return -EIO;
+ return -ENODEV;
}
- /**
+ /*
* init_data points to array of regulator_init structures
* coming from the board-evm file.
*/
-
init_data = tps_board->tps6507x_ts_init_data;
tsc = kzalloc(sizeof(struct tps6507x_ts), GFP_KERNEL);
if (!tsc) {
dev_err(tps6507x_dev->dev, "failed to allocate driver data\n");
- error = -ENOMEM;
- goto err0;
+ return -ENOMEM;
}
- tps6507x_dev->ts = tsc;
tsc->mfd = tps6507x_dev;
tsc->dev = tps6507x_dev->dev;
- input_dev = input_allocate_device();
- if (!input_dev) {
- dev_err(tsc->dev, "Failed to allocate input device.\n");
+ tsc->min_pressure = init_data ?
+ init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE;
+
+ snprintf(tsc->phys, sizeof(tsc->phys),
+ "%s/input0", dev_name(tsc->dev));
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev) {
+ dev_err(tsc->dev, "Failed to allocate polled input device.\n");
error = -ENOMEM;
- goto err1;
+ goto err_free_mem;
}
+ tsc->poll_dev = poll_dev;
+
+ poll_dev->private = tsc;
+ poll_dev->poll = tps6507x_ts_poll;
+ poll_dev->poll_interval = init_data ?
+ init_data->poll_period : TSC_DEFAULT_POLL_PERIOD;
+
+ input_dev = poll_dev->input;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
@@ -286,76 +270,42 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
input_dev->name = "TPS6507x Touchscreen";
- input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = tsc->dev;
-
- snprintf(tsc->phys, sizeof(tsc->phys),
- "%s/input0", dev_name(tsc->dev));
input_dev->phys = tsc->phys;
-
- dev_dbg(tsc->dev, "device: %s\n", input_dev->phys);
-
- input_set_drvdata(input_dev, tsc);
-
- tsc->input_dev = input_dev;
-
- INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
-
+ input_dev->dev.parent = tsc->dev;
+ input_dev->id.bustype = BUS_I2C;
if (init_data) {
- tsc->poll_period = init_data->poll_period;
- tsc->vref = init_data->vref;
- tsc->min_pressure = init_data->min_pressure;
input_dev->id.vendor = init_data->vendor;
input_dev->id.product = init_data->product;
input_dev->id.version = init_data->version;
- } else {
- tsc->poll_period = TSC_DEFAULT_POLL_PERIOD;
- tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE;
}
error = tps6507x_adc_standby(tsc);
if (error)
- goto err2;
+ goto err_free_polled_dev;
- error = input_register_device(input_dev);
+ error = input_register_polled_device(poll_dev);
if (error)
- goto err2;
+ goto err_free_polled_dev;
- schd = schedule_delayed_work(&tsc->work,
- msecs_to_jiffies(tsc->poll_period));
-
- if (schd)
- tsc->polling = 1;
- else {
- tsc->polling = 0;
- dev_err(tsc->dev, "schedule failed");
- goto err2;
- }
- platform_set_drvdata(pdev, tps6507x_dev);
+ platform_set_drvdata(pdev, tsc);
return 0;
-err2:
- cancel_delayed_work_sync(&tsc->work);
- input_free_device(input_dev);
-err1:
+err_free_polled_dev:
+ input_free_polled_device(poll_dev);
+err_free_mem:
kfree(tsc);
- tps6507x_dev->ts = NULL;
-err0:
return error;
}
static int tps6507x_ts_remove(struct platform_device *pdev)
{
- struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
- struct tps6507x_ts *tsc = tps6507x_dev->ts;
- struct input_dev *input_dev = tsc->input_dev;
-
- cancel_delayed_work_sync(&tsc->work);
+ struct tps6507x_ts *tsc = platform_get_drvdata(pdev);
+ struct input_polled_dev *poll_dev = tsc->poll_dev;
- input_unregister_device(input_dev);
+ input_unregister_polled_device(poll_dev);
+ input_free_polled_device(poll_dev);
- tps6507x_dev->ts = NULL;
kfree(tsc);
return 0;
diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c
index d2ef8f05c66e..003d0c3b5d08 100644
--- a/drivers/input/touchscreen/w90p910_ts.c
+++ b/drivers/input/touchscreen/w90p910_ts.c
@@ -318,8 +318,6 @@ static int w90x900ts_remove(struct platform_device *pdev)
input_unregister_device(w90p910_ts->input);
kfree(w90p910_ts);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index bf0d07620bac..7ccaa1b12b05 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -1,7 +1,7 @@
/*
* Wacom Penabled Driver for I2C
*
- * Copyright (c) 2011 Tatsunosuke Tobita, Wacom.
+ * Copyright (c) 2011 - 2013 Tatsunosuke Tobita, Wacom.
* <tobita.tatsunosuke@wacom.co.jp>
*
* This program is free software; you can redistribute it
@@ -27,7 +27,6 @@
#define WACOM_CMD_THROW0 0x05
#define WACOM_CMD_THROW1 0x00
#define WACOM_QUERY_SIZE 19
-#define WACOM_RETRY_CNT 100
struct wacom_features {
int x_max;
@@ -40,6 +39,8 @@ struct wacom_i2c {
struct i2c_client *client;
struct input_dev *input;
u8 data[WACOM_QUERY_SIZE];
+ bool prox;
+ int tool;
};
static int wacom_query_device(struct i2c_client *client,
@@ -112,9 +113,14 @@ static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
y = le16_to_cpup((__le16 *)&data[6]);
pressure = le16_to_cpup((__le16 *)&data[8]);
+ if (!wac_i2c->prox)
+ wac_i2c->tool = (data[3] & 0x0c) ?
+ BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+
+ wac_i2c->prox = data[3] & 0x20;
+
input_report_key(input, BTN_TOUCH, tsw || ers);
- input_report_key(input, BTN_TOOL_PEN, tsw);
- input_report_key(input, BTN_TOOL_RUBBER, ers);
+ input_report_key(input, wac_i2c->tool, wac_i2c->prox);
input_report_key(input, BTN_STYLUS, f1);
input_report_key(input, BTN_STYLUS2, f2);
input_report_abs(input, ABS_X, x);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index c332fb98480d..820d85c4a4a0 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -261,4 +261,25 @@ config SHMOBILE_IOMMU_L1SIZE
default 256 if SHMOBILE_IOMMU_ADDRSIZE_64MB
default 128 if SHMOBILE_IOMMU_ADDRSIZE_32MB
+config SPAPR_TCE_IOMMU
+ bool "sPAPR TCE IOMMU Support"
+ depends on PPC_POWERNV || PPC_PSERIES
+ select IOMMU_API
+ help
+ Enables bits of IOMMU API required by VFIO. The iommu_ops
+ is not implemented as it is not necessary for VFIO.
+
+config ARM_SMMU
+ bool "ARM Ltd. System MMU (SMMU) Support"
+ depends on ARM64 || (ARM_LPAE && OF)
+ select IOMMU_API
+ select ARM_DMA_USE_IOMMU if ARM
+ help
+ Support for implementations of the ARM System MMU architecture
+ versions 1 and 2. The driver supports both v7l and v8l table
+ formats with 4k and 64k page sizes.
+
+ Say Y here if your SoC includes an IOMMU device implementing
+ the ARM SMMU architecture.
+
endif # IOMMU_SUPPORT
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index ef0e5207ad69..bbe7041212dd 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_OF_IOMMU) += of_iommu.o
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
+obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 21d02b0d907c..6dc659426a51 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -287,14 +287,27 @@ static struct pci_dev *get_isolation_root(struct pci_dev *pdev)
/*
* If it's a multifunction device that does not support our
- * required ACS flags, add to the same group as function 0.
+ * required ACS flags, add to the same group as lowest numbered
+ * function that also does not suport the required ACS flags.
*/
if (dma_pdev->multifunction &&
- !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
- swap_pci_ref(&dma_pdev,
- pci_get_slot(dma_pdev->bus,
- PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
- 0)));
+ !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+ u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+ for (i = 0; i < 8; i++) {
+ struct pci_dev *tmp;
+
+ tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+ if (!tmp)
+ continue;
+
+ if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+ swap_pci_ref(&dma_pdev, tmp);
+ break;
+ }
+ pci_dev_put(tmp);
+ }
+ }
/*
* Devices on the root bus go through the iommu. If that's not us,
@@ -1484,6 +1497,10 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
/* Large PTE found which maps this address */
unmap_size = PTE_PAGE_SIZE(*pte);
+
+ /* Only unmap from the first pte in the page */
+ if ((unmap_size - 1) & bus_addr)
+ break;
count = PAGE_SIZE_PTE_COUNT(unmap_size);
for (i = 0; i < count; i++)
pte[i] = 0ULL;
@@ -1493,7 +1510,7 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom,
unmapped += unmap_size;
}
- BUG_ON(!is_power_of_2(unmapped));
+ BUG_ON(unmapped && !is_power_of_2(unmapped));
return unmapped;
}
@@ -1893,34 +1910,59 @@ static void domain_id_free(int id)
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
}
+#define DEFINE_FREE_PT_FN(LVL, FN) \
+static void free_pt_##LVL (unsigned long __pt) \
+{ \
+ unsigned long p; \
+ u64 *pt; \
+ int i; \
+ \
+ pt = (u64 *)__pt; \
+ \
+ for (i = 0; i < 512; ++i) { \
+ if (!IOMMU_PTE_PRESENT(pt[i])) \
+ continue; \
+ \
+ p = (unsigned long)IOMMU_PTE_PAGE(pt[i]); \
+ FN(p); \
+ } \
+ free_page((unsigned long)pt); \
+}
+
+DEFINE_FREE_PT_FN(l2, free_page)
+DEFINE_FREE_PT_FN(l3, free_pt_l2)
+DEFINE_FREE_PT_FN(l4, free_pt_l3)
+DEFINE_FREE_PT_FN(l5, free_pt_l4)
+DEFINE_FREE_PT_FN(l6, free_pt_l5)
+
static void free_pagetable(struct protection_domain *domain)
{
- int i, j;
- u64 *p1, *p2, *p3;
-
- p1 = domain->pt_root;
-
- if (!p1)
- return;
-
- for (i = 0; i < 512; ++i) {
- if (!IOMMU_PTE_PRESENT(p1[i]))
- continue;
-
- p2 = IOMMU_PTE_PAGE(p1[i]);
- for (j = 0; j < 512; ++j) {
- if (!IOMMU_PTE_PRESENT(p2[j]))
- continue;
- p3 = IOMMU_PTE_PAGE(p2[j]);
- free_page((unsigned long)p3);
- }
+ unsigned long root = (unsigned long)domain->pt_root;
- free_page((unsigned long)p2);
+ switch (domain->mode) {
+ case PAGE_MODE_NONE:
+ break;
+ case PAGE_MODE_1_LEVEL:
+ free_page(root);
+ break;
+ case PAGE_MODE_2_LEVEL:
+ free_pt_l2(root);
+ break;
+ case PAGE_MODE_3_LEVEL:
+ free_pt_l3(root);
+ break;
+ case PAGE_MODE_4_LEVEL:
+ free_pt_l4(root);
+ break;
+ case PAGE_MODE_5_LEVEL:
+ free_pt_l5(root);
+ break;
+ case PAGE_MODE_6_LEVEL:
+ free_pt_l6(root);
+ break;
+ default:
+ BUG();
}
-
- free_page((unsigned long)p1);
-
- domain->pt_root = NULL;
}
static void free_gcr3_tbl_level1(u64 *tbl)
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
new file mode 100644
index 000000000000..ebd0a4cff049
--- /dev/null
+++ b/drivers/iommu/arm-smmu.c
@@ -0,0 +1,1969 @@
+/*
+ * IOMMU API for ARM architected SMMU implementations.
+ *
+ * This program is free software; you can 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) 2013 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ *
+ * This driver currently supports:
+ * - SMMUv1 and v2 implementations
+ * - Stream-matching and stream-indexing
+ * - v7/v8 long-descriptor format
+ * - Non-secure access to the SMMU
+ * - 4k and 64k pages, with contiguous pte hints.
+ * - Up to 39-bit addressing
+ * - Context fault reporting
+ */
+
+#define pr_fmt(fmt) "arm-smmu: " fmt
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iommu.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/pgalloc.h>
+
+/* Maximum number of stream IDs assigned to a single device */
+#define MAX_MASTER_STREAMIDS 8
+
+/* Maximum number of context banks per SMMU */
+#define ARM_SMMU_MAX_CBS 128
+
+/* Maximum number of mapping groups per SMMU */
+#define ARM_SMMU_MAX_SMRS 128
+
+/* Number of VMIDs per SMMU */
+#define ARM_SMMU_NUM_VMIDS 256
+
+/* SMMU global address space */
+#define ARM_SMMU_GR0(smmu) ((smmu)->base)
+#define ARM_SMMU_GR1(smmu) ((smmu)->base + (smmu)->pagesize)
+
+/* Page table bits */
+#define ARM_SMMU_PTE_PAGE (((pteval_t)3) << 0)
+#define ARM_SMMU_PTE_CONT (((pteval_t)1) << 52)
+#define ARM_SMMU_PTE_AF (((pteval_t)1) << 10)
+#define ARM_SMMU_PTE_SH_NS (((pteval_t)0) << 8)
+#define ARM_SMMU_PTE_SH_OS (((pteval_t)2) << 8)
+#define ARM_SMMU_PTE_SH_IS (((pteval_t)3) << 8)
+
+#if PAGE_SIZE == SZ_4K
+#define ARM_SMMU_PTE_CONT_ENTRIES 16
+#elif PAGE_SIZE == SZ_64K
+#define ARM_SMMU_PTE_CONT_ENTRIES 32
+#else
+#define ARM_SMMU_PTE_CONT_ENTRIES 1
+#endif
+
+#define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
+#define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1))
+#define ARM_SMMU_PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t))
+
+/* Stage-1 PTE */
+#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
+#define ARM_SMMU_PTE_AP_RDONLY (((pteval_t)2) << 6)
+#define ARM_SMMU_PTE_ATTRINDX_SHIFT 2
+
+/* Stage-2 PTE */
+#define ARM_SMMU_PTE_HAP_FAULT (((pteval_t)0) << 6)
+#define ARM_SMMU_PTE_HAP_READ (((pteval_t)1) << 6)
+#define ARM_SMMU_PTE_HAP_WRITE (((pteval_t)2) << 6)
+#define ARM_SMMU_PTE_MEMATTR_OIWB (((pteval_t)0xf) << 2)
+#define ARM_SMMU_PTE_MEMATTR_NC (((pteval_t)0x5) << 2)
+#define ARM_SMMU_PTE_MEMATTR_DEV (((pteval_t)0x1) << 2)
+
+/* Configuration registers */
+#define ARM_SMMU_GR0_sCR0 0x0
+#define sCR0_CLIENTPD (1 << 0)
+#define sCR0_GFRE (1 << 1)
+#define sCR0_GFIE (1 << 2)
+#define sCR0_GCFGFRE (1 << 4)
+#define sCR0_GCFGFIE (1 << 5)
+#define sCR0_USFCFG (1 << 10)
+#define sCR0_VMIDPNE (1 << 11)
+#define sCR0_PTM (1 << 12)
+#define sCR0_FB (1 << 13)
+#define sCR0_BSU_SHIFT 14
+#define sCR0_BSU_MASK 0x3
+
+/* Identification registers */
+#define ARM_SMMU_GR0_ID0 0x20
+#define ARM_SMMU_GR0_ID1 0x24
+#define ARM_SMMU_GR0_ID2 0x28
+#define ARM_SMMU_GR0_ID3 0x2c
+#define ARM_SMMU_GR0_ID4 0x30
+#define ARM_SMMU_GR0_ID5 0x34
+#define ARM_SMMU_GR0_ID6 0x38
+#define ARM_SMMU_GR0_ID7 0x3c
+#define ARM_SMMU_GR0_sGFSR 0x48
+#define ARM_SMMU_GR0_sGFSYNR0 0x50
+#define ARM_SMMU_GR0_sGFSYNR1 0x54
+#define ARM_SMMU_GR0_sGFSYNR2 0x58
+#define ARM_SMMU_GR0_PIDR0 0xfe0
+#define ARM_SMMU_GR0_PIDR1 0xfe4
+#define ARM_SMMU_GR0_PIDR2 0xfe8
+
+#define ID0_S1TS (1 << 30)
+#define ID0_S2TS (1 << 29)
+#define ID0_NTS (1 << 28)
+#define ID0_SMS (1 << 27)
+#define ID0_PTFS_SHIFT 24
+#define ID0_PTFS_MASK 0x2
+#define ID0_PTFS_V8_ONLY 0x2
+#define ID0_CTTW (1 << 14)
+#define ID0_NUMIRPT_SHIFT 16
+#define ID0_NUMIRPT_MASK 0xff
+#define ID0_NUMSMRG_SHIFT 0
+#define ID0_NUMSMRG_MASK 0xff
+
+#define ID1_PAGESIZE (1 << 31)
+#define ID1_NUMPAGENDXB_SHIFT 28
+#define ID1_NUMPAGENDXB_MASK 7
+#define ID1_NUMS2CB_SHIFT 16
+#define ID1_NUMS2CB_MASK 0xff
+#define ID1_NUMCB_SHIFT 0
+#define ID1_NUMCB_MASK 0xff
+
+#define ID2_OAS_SHIFT 4
+#define ID2_OAS_MASK 0xf
+#define ID2_IAS_SHIFT 0
+#define ID2_IAS_MASK 0xf
+#define ID2_UBS_SHIFT 8
+#define ID2_UBS_MASK 0xf
+#define ID2_PTFS_4K (1 << 12)
+#define ID2_PTFS_16K (1 << 13)
+#define ID2_PTFS_64K (1 << 14)
+
+#define PIDR2_ARCH_SHIFT 4
+#define PIDR2_ARCH_MASK 0xf
+
+/* Global TLB invalidation */
+#define ARM_SMMU_GR0_STLBIALL 0x60
+#define ARM_SMMU_GR0_TLBIVMID 0x64
+#define ARM_SMMU_GR0_TLBIALLNSNH 0x68
+#define ARM_SMMU_GR0_TLBIALLH 0x6c
+#define ARM_SMMU_GR0_sTLBGSYNC 0x70
+#define ARM_SMMU_GR0_sTLBGSTATUS 0x74
+#define sTLBGSTATUS_GSACTIVE (1 << 0)
+#define TLB_LOOP_TIMEOUT 1000000 /* 1s! */
+
+/* Stream mapping registers */
+#define ARM_SMMU_GR0_SMR(n) (0x800 + ((n) << 2))
+#define SMR_VALID (1 << 31)
+#define SMR_MASK_SHIFT 16
+#define SMR_MASK_MASK 0x7fff
+#define SMR_ID_SHIFT 0
+#define SMR_ID_MASK 0x7fff
+
+#define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2))
+#define S2CR_CBNDX_SHIFT 0
+#define S2CR_CBNDX_MASK 0xff
+#define S2CR_TYPE_SHIFT 16
+#define S2CR_TYPE_MASK 0x3
+#define S2CR_TYPE_TRANS (0 << S2CR_TYPE_SHIFT)
+#define S2CR_TYPE_BYPASS (1 << S2CR_TYPE_SHIFT)
+#define S2CR_TYPE_FAULT (2 << S2CR_TYPE_SHIFT)
+
+/* Context bank attribute registers */
+#define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2))
+#define CBAR_VMID_SHIFT 0
+#define CBAR_VMID_MASK 0xff
+#define CBAR_S1_MEMATTR_SHIFT 12
+#define CBAR_S1_MEMATTR_MASK 0xf
+#define CBAR_S1_MEMATTR_WB 0xf
+#define CBAR_TYPE_SHIFT 16
+#define CBAR_TYPE_MASK 0x3
+#define CBAR_TYPE_S2_TRANS (0 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_BYPASS (1 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_FAULT (2 << CBAR_TYPE_SHIFT)
+#define CBAR_TYPE_S1_TRANS_S2_TRANS (3 << CBAR_TYPE_SHIFT)
+#define CBAR_IRPTNDX_SHIFT 24
+#define CBAR_IRPTNDX_MASK 0xff
+
+#define ARM_SMMU_GR1_CBA2R(n) (0x800 + ((n) << 2))
+#define CBA2R_RW64_32BIT (0 << 0)
+#define CBA2R_RW64_64BIT (1 << 0)
+
+/* Translation context bank */
+#define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1))
+#define ARM_SMMU_CB(smmu, n) ((n) * (smmu)->pagesize)
+
+#define ARM_SMMU_CB_SCTLR 0x0
+#define ARM_SMMU_CB_RESUME 0x8
+#define ARM_SMMU_CB_TTBCR2 0x10
+#define ARM_SMMU_CB_TTBR0_LO 0x20
+#define ARM_SMMU_CB_TTBR0_HI 0x24
+#define ARM_SMMU_CB_TTBCR 0x30
+#define ARM_SMMU_CB_S1_MAIR0 0x38
+#define ARM_SMMU_CB_FSR 0x58
+#define ARM_SMMU_CB_FAR_LO 0x60
+#define ARM_SMMU_CB_FAR_HI 0x64
+#define ARM_SMMU_CB_FSYNR0 0x68
+
+#define SCTLR_S1_ASIDPNE (1 << 12)
+#define SCTLR_CFCFG (1 << 7)
+#define SCTLR_CFIE (1 << 6)
+#define SCTLR_CFRE (1 << 5)
+#define SCTLR_E (1 << 4)
+#define SCTLR_AFE (1 << 2)
+#define SCTLR_TRE (1 << 1)
+#define SCTLR_M (1 << 0)
+#define SCTLR_EAE_SBOP (SCTLR_AFE | SCTLR_TRE)
+
+#define RESUME_RETRY (0 << 0)
+#define RESUME_TERMINATE (1 << 0)
+
+#define TTBCR_EAE (1 << 31)
+
+#define TTBCR_PASIZE_SHIFT 16
+#define TTBCR_PASIZE_MASK 0x7
+
+#define TTBCR_TG0_4K (0 << 14)
+#define TTBCR_TG0_64K (1 << 14)
+
+#define TTBCR_SH0_SHIFT 12
+#define TTBCR_SH0_MASK 0x3
+#define TTBCR_SH_NS 0
+#define TTBCR_SH_OS 2
+#define TTBCR_SH_IS 3
+
+#define TTBCR_ORGN0_SHIFT 10
+#define TTBCR_IRGN0_SHIFT 8
+#define TTBCR_RGN_MASK 0x3
+#define TTBCR_RGN_NC 0
+#define TTBCR_RGN_WBWA 1
+#define TTBCR_RGN_WT 2
+#define TTBCR_RGN_WB 3
+
+#define TTBCR_SL0_SHIFT 6
+#define TTBCR_SL0_MASK 0x3
+#define TTBCR_SL0_LVL_2 0
+#define TTBCR_SL0_LVL_1 1
+
+#define TTBCR_T1SZ_SHIFT 16
+#define TTBCR_T0SZ_SHIFT 0
+#define TTBCR_SZ_MASK 0xf
+
+#define TTBCR2_SEP_SHIFT 15
+#define TTBCR2_SEP_MASK 0x7
+
+#define TTBCR2_PASIZE_SHIFT 0
+#define TTBCR2_PASIZE_MASK 0x7
+
+/* Common definitions for PASize and SEP fields */
+#define TTBCR2_ADDR_32 0
+#define TTBCR2_ADDR_36 1
+#define TTBCR2_ADDR_40 2
+#define TTBCR2_ADDR_42 3
+#define TTBCR2_ADDR_44 4
+#define TTBCR2_ADDR_48 5
+
+#define MAIR_ATTR_SHIFT(n) ((n) << 3)
+#define MAIR_ATTR_MASK 0xff
+#define MAIR_ATTR_DEVICE 0x04
+#define MAIR_ATTR_NC 0x44
+#define MAIR_ATTR_WBRWA 0xff
+#define MAIR_ATTR_IDX_NC 0
+#define MAIR_ATTR_IDX_CACHE 1
+#define MAIR_ATTR_IDX_DEV 2
+
+#define FSR_MULTI (1 << 31)
+#define FSR_SS (1 << 30)
+#define FSR_UUT (1 << 8)
+#define FSR_ASF (1 << 7)
+#define FSR_TLBLKF (1 << 6)
+#define FSR_TLBMCF (1 << 5)
+#define FSR_EF (1 << 4)
+#define FSR_PF (1 << 3)
+#define FSR_AFF (1 << 2)
+#define FSR_TF (1 << 1)
+
+#define FSR_IGN (FSR_AFF | FSR_ASF | FSR_TLBMCF | \
+ FSR_TLBLKF)
+#define FSR_FAULT (FSR_MULTI | FSR_SS | FSR_UUT | \
+ FSR_EF | FSR_PF | FSR_TF)
+
+#define FSYNR0_WNR (1 << 4)
+
+struct arm_smmu_smr {
+ u8 idx;
+ u16 mask;
+ u16 id;
+};
+
+struct arm_smmu_master {
+ struct device_node *of_node;
+
+ /*
+ * The following is specific to the master's position in the
+ * SMMU chain.
+ */
+ struct rb_node node;
+ int num_streamids;
+ u16 streamids[MAX_MASTER_STREAMIDS];
+
+ /*
+ * We only need to allocate these on the root SMMU, as we
+ * configure unmatched streams to bypass translation.
+ */
+ struct arm_smmu_smr *smrs;
+};
+
+struct arm_smmu_device {
+ struct device *dev;
+ struct device_node *parent_of_node;
+
+ void __iomem *base;
+ unsigned long size;
+ unsigned long pagesize;
+
+#define ARM_SMMU_FEAT_COHERENT_WALK (1 << 0)
+#define ARM_SMMU_FEAT_STREAM_MATCH (1 << 1)
+#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2)
+#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3)
+#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4)
+ u32 features;
+ int version;
+
+ u32 num_context_banks;
+ u32 num_s2_context_banks;
+ DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
+ atomic_t irptndx;
+
+ u32 num_mapping_groups;
+ DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
+
+ unsigned long input_size;
+ unsigned long s1_output_size;
+ unsigned long s2_output_size;
+
+ u32 num_global_irqs;
+ u32 num_context_irqs;
+ unsigned int *irqs;
+
+ DECLARE_BITMAP(vmid_map, ARM_SMMU_NUM_VMIDS);
+
+ struct list_head list;
+ struct rb_root masters;
+};
+
+struct arm_smmu_cfg {
+ struct arm_smmu_device *smmu;
+ u8 vmid;
+ u8 cbndx;
+ u8 irptndx;
+ u32 cbar;
+ pgd_t *pgd;
+};
+
+struct arm_smmu_domain {
+ /*
+ * A domain can span across multiple, chained SMMUs and requires
+ * all devices within the domain to follow the same translation
+ * path.
+ */
+ struct arm_smmu_device *leaf_smmu;
+ struct arm_smmu_cfg root_cfg;
+ phys_addr_t output_mask;
+
+ spinlock_t lock;
+};
+
+static DEFINE_SPINLOCK(arm_smmu_devices_lock);
+static LIST_HEAD(arm_smmu_devices);
+
+static struct arm_smmu_master *find_smmu_master(struct arm_smmu_device *smmu,
+ struct device_node *dev_node)
+{
+ struct rb_node *node = smmu->masters.rb_node;
+
+ while (node) {
+ struct arm_smmu_master *master;
+ master = container_of(node, struct arm_smmu_master, node);
+
+ if (dev_node < master->of_node)
+ node = node->rb_left;
+ else if (dev_node > master->of_node)
+ node = node->rb_right;
+ else
+ return master;
+ }
+
+ return NULL;
+}
+
+static int insert_smmu_master(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ struct rb_node **new, *parent;
+
+ new = &smmu->masters.rb_node;
+ parent = NULL;
+ while (*new) {
+ struct arm_smmu_master *this;
+ this = container_of(*new, struct arm_smmu_master, node);
+
+ parent = *new;
+ if (master->of_node < this->of_node)
+ new = &((*new)->rb_left);
+ else if (master->of_node > this->of_node)
+ new = &((*new)->rb_right);
+ else
+ return -EEXIST;
+ }
+
+ rb_link_node(&master->node, parent, new);
+ rb_insert_color(&master->node, &smmu->masters);
+ return 0;
+}
+
+static int register_smmu_master(struct arm_smmu_device *smmu,
+ struct device *dev,
+ struct of_phandle_args *masterspec)
+{
+ int i;
+ struct arm_smmu_master *master;
+
+ master = find_smmu_master(smmu, masterspec->np);
+ if (master) {
+ dev_err(dev,
+ "rejecting multiple registrations for master device %s\n",
+ masterspec->np->name);
+ return -EBUSY;
+ }
+
+ if (masterspec->args_count > MAX_MASTER_STREAMIDS) {
+ dev_err(dev,
+ "reached maximum number (%d) of stream IDs for master device %s\n",
+ MAX_MASTER_STREAMIDS, masterspec->np->name);
+ return -ENOSPC;
+ }
+
+ master = devm_kzalloc(dev, sizeof(*master), GFP_KERNEL);
+ if (!master)
+ return -ENOMEM;
+
+ master->of_node = masterspec->np;
+ master->num_streamids = masterspec->args_count;
+
+ for (i = 0; i < master->num_streamids; ++i)
+ master->streamids[i] = masterspec->args[i];
+
+ return insert_smmu_master(smmu, master);
+}
+
+static struct arm_smmu_device *find_parent_smmu(struct arm_smmu_device *smmu)
+{
+ struct arm_smmu_device *parent;
+
+ if (!smmu->parent_of_node)
+ return NULL;
+
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(parent, &arm_smmu_devices, list)
+ if (parent->dev->of_node == smmu->parent_of_node)
+ goto out_unlock;
+
+ parent = NULL;
+ dev_warn(smmu->dev,
+ "Failed to find SMMU parent despite parent in DT\n");
+out_unlock:
+ spin_unlock(&arm_smmu_devices_lock);
+ return parent;
+}
+
+static int __arm_smmu_alloc_bitmap(unsigned long *map, int start, int end)
+{
+ int idx;
+
+ do {
+ idx = find_next_zero_bit(map, end, start);
+ if (idx == end)
+ return -ENOSPC;
+ } while (test_and_set_bit(idx, map));
+
+ return idx;
+}
+
+static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
+{
+ clear_bit(idx, map);
+}
+
+/* Wait for any pending TLB invalidations to complete */
+static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
+{
+ int count = 0;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_sTLBGSYNC);
+ while (readl_relaxed(gr0_base + ARM_SMMU_GR0_sTLBGSTATUS)
+ & sTLBGSTATUS_GSACTIVE) {
+ cpu_relax();
+ if (++count == TLB_LOOP_TIMEOUT) {
+ dev_err_ratelimited(smmu->dev,
+ "TLB sync timed out -- SMMU may be deadlocked\n");
+ return;
+ }
+ udelay(1);
+ }
+}
+
+static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
+{
+ int flags, ret;
+ u32 fsr, far, fsynr, resume;
+ unsigned long iova;
+ struct iommu_domain *domain = dev;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ void __iomem *cb_base;
+
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+ fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+
+ if (!(fsr & FSR_FAULT))
+ return IRQ_NONE;
+
+ if (fsr & FSR_IGN)
+ dev_err_ratelimited(smmu->dev,
+ "Unexpected context fault (fsr 0x%u)\n",
+ fsr);
+
+ fsynr = readl_relaxed(cb_base + ARM_SMMU_CB_FSYNR0);
+ flags = fsynr & FSYNR0_WNR ? IOMMU_FAULT_WRITE : IOMMU_FAULT_READ;
+
+ far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_LO);
+ iova = far;
+#ifdef CONFIG_64BIT
+ far = readl_relaxed(cb_base + ARM_SMMU_CB_FAR_HI);
+ iova |= ((unsigned long)far << 32);
+#endif
+
+ if (!report_iommu_fault(domain, smmu->dev, iova, flags)) {
+ ret = IRQ_HANDLED;
+ resume = RESUME_RETRY;
+ } else {
+ ret = IRQ_NONE;
+ resume = RESUME_TERMINATE;
+ }
+
+ /* Clear the faulting FSR */
+ writel(fsr, cb_base + ARM_SMMU_CB_FSR);
+
+ /* Retry or terminate any stalled transactions */
+ if (fsr & FSR_SS)
+ writel_relaxed(resume, cb_base + ARM_SMMU_CB_RESUME);
+
+ return ret;
+}
+
+static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
+{
+ u32 gfsr, gfsynr0, gfsynr1, gfsynr2;
+ struct arm_smmu_device *smmu = dev;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
+ gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
+ gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
+ gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
+
+ dev_err_ratelimited(smmu->dev,
+ "Unexpected global fault, this could be serious\n");
+ dev_err_ratelimited(smmu->dev,
+ "\tGFSR 0x%08x, GFSYNR0 0x%08x, GFSYNR1 0x%08x, GFSYNR2 0x%08x\n",
+ gfsr, gfsynr0, gfsynr1, gfsynr2);
+
+ writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
+ return IRQ_NONE;
+}
+
+static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
+{
+ u32 reg;
+ bool stage1;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ void __iomem *cb_base, *gr0_base, *gr1_base;
+
+ gr0_base = ARM_SMMU_GR0(smmu);
+ gr1_base = ARM_SMMU_GR1(smmu);
+ stage1 = root_cfg->cbar != CBAR_TYPE_S2_TRANS;
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+
+ /* CBAR */
+ reg = root_cfg->cbar |
+ (root_cfg->vmid << CBAR_VMID_SHIFT);
+ if (smmu->version == 1)
+ reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
+
+ /* Use the weakest memory type, so it is overridden by the pte */
+ if (stage1)
+ reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+ writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
+
+ if (smmu->version > 1) {
+ /* CBA2R */
+#ifdef CONFIG_64BIT
+ reg = CBA2R_RW64_64BIT;
+#else
+ reg = CBA2R_RW64_32BIT;
+#endif
+ writel_relaxed(reg,
+ gr1_base + ARM_SMMU_GR1_CBA2R(root_cfg->cbndx));
+
+ /* TTBCR2 */
+ switch (smmu->input_size) {
+ case 32:
+ reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
+ break;
+ case 36:
+ reg = (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT);
+ break;
+ case 39:
+ reg = (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT);
+ break;
+ case 42:
+ reg = (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT);
+ break;
+ case 44:
+ reg = (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT);
+ break;
+ case 48:
+ reg = (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT);
+ break;
+ }
+
+ switch (smmu->s1_output_size) {
+ case 32:
+ reg |= (TTBCR2_ADDR_32 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 36:
+ reg |= (TTBCR2_ADDR_36 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 39:
+ reg |= (TTBCR2_ADDR_40 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 42:
+ reg |= (TTBCR2_ADDR_42 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 44:
+ reg |= (TTBCR2_ADDR_44 << TTBCR2_PASIZE_SHIFT);
+ break;
+ case 48:
+ reg |= (TTBCR2_ADDR_48 << TTBCR2_PASIZE_SHIFT);
+ break;
+ }
+
+ if (stage1)
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
+ }
+
+ /* TTBR0 */
+ reg = __pa(root_cfg->pgd);
+#ifndef __BIG_ENDIAN
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+ reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+#else
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+ reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+#endif
+
+ /*
+ * TTBCR
+ * We use long descriptor, with inner-shareable WBWA tables in TTBR0.
+ */
+ if (smmu->version > 1) {
+ if (PAGE_SIZE == SZ_4K)
+ reg = TTBCR_TG0_4K;
+ else
+ reg = TTBCR_TG0_64K;
+
+ if (!stage1) {
+ switch (smmu->s2_output_size) {
+ case 32:
+ reg |= (TTBCR2_ADDR_32 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 36:
+ reg |= (TTBCR2_ADDR_36 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 40:
+ reg |= (TTBCR2_ADDR_40 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 42:
+ reg |= (TTBCR2_ADDR_42 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 44:
+ reg |= (TTBCR2_ADDR_44 << TTBCR_PASIZE_SHIFT);
+ break;
+ case 48:
+ reg |= (TTBCR2_ADDR_48 << TTBCR_PASIZE_SHIFT);
+ break;
+ }
+ } else {
+ reg |= (64 - smmu->s1_output_size) << TTBCR_T0SZ_SHIFT;
+ }
+ } else {
+ reg = 0;
+ }
+
+ reg |= TTBCR_EAE |
+ (TTBCR_SH_IS << TTBCR_SH0_SHIFT) |
+ (TTBCR_RGN_WBWA << TTBCR_ORGN0_SHIFT) |
+ (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT) |
+ (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT);
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
+
+ /* MAIR0 (stage-1 only) */
+ if (stage1) {
+ reg = (MAIR_ATTR_NC << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_NC)) |
+ (MAIR_ATTR_WBRWA << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_CACHE)) |
+ (MAIR_ATTR_DEVICE << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_DEV));
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
+ }
+
+ /* Nuke the TLB */
+ writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
+ arm_smmu_tlb_sync(smmu);
+
+ /* SCTLR */
+ reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
+ if (stage1)
+ reg |= SCTLR_S1_ASIDPNE;
+#ifdef __BIG_ENDIAN
+ reg |= SCTLR_E;
+#endif
+ writel(reg, cb_base + ARM_SMMU_CB_SCTLR);
+}
+
+static int arm_smmu_init_domain_context(struct iommu_domain *domain,
+ struct device *dev)
+{
+ int irq, ret, start;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu, *parent;
+
+ /*
+ * Walk the SMMU chain to find the root device for this chain.
+ * We assume that no masters have translations which terminate
+ * early, and therefore check that the root SMMU does indeed have
+ * a StreamID for the master in question.
+ */
+ parent = dev->archdata.iommu;
+ smmu_domain->output_mask = -1;
+ do {
+ smmu = parent;
+ smmu_domain->output_mask &= (1ULL << smmu->s2_output_size) - 1;
+ } while ((parent = find_parent_smmu(smmu)));
+
+ if (!find_smmu_master(smmu, dev->of_node)) {
+ dev_err(dev, "unable to find root SMMU for device\n");
+ return -ENODEV;
+ }
+
+ ret = __arm_smmu_alloc_bitmap(smmu->vmid_map, 0, ARM_SMMU_NUM_VMIDS);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+
+ root_cfg->vmid = ret;
+ if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
+ /*
+ * We will likely want to change this if/when KVM gets
+ * involved.
+ */
+ root_cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
+ start = smmu->num_s2_context_banks;
+ } else if (smmu->features & ARM_SMMU_FEAT_TRANS_S2) {
+ root_cfg->cbar = CBAR_TYPE_S2_TRANS;
+ start = 0;
+ } else {
+ root_cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
+ start = smmu->num_s2_context_banks;
+ }
+
+ ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
+ smmu->num_context_banks);
+ if (IS_ERR_VALUE(ret))
+ goto out_free_vmid;
+
+ root_cfg->cbndx = ret;
+
+ if (smmu->version == 1) {
+ root_cfg->irptndx = atomic_inc_return(&smmu->irptndx);
+ root_cfg->irptndx %= smmu->num_context_irqs;
+ } else {
+ root_cfg->irptndx = root_cfg->cbndx;
+ }
+
+ irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
+ ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
+ "arm-smmu-context-fault", domain);
+ if (IS_ERR_VALUE(ret)) {
+ dev_err(smmu->dev, "failed to request context IRQ %d (%u)\n",
+ root_cfg->irptndx, irq);
+ root_cfg->irptndx = -1;
+ goto out_free_context;
+ }
+
+ root_cfg->smmu = smmu;
+ arm_smmu_init_context_bank(smmu_domain);
+ return ret;
+
+out_free_context:
+ __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
+out_free_vmid:
+ __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
+ return ret;
+}
+
+static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ int irq;
+
+ if (!smmu)
+ return;
+
+ if (root_cfg->irptndx != -1) {
+ irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
+ free_irq(irq, domain);
+ }
+
+ __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
+ __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
+}
+
+static int arm_smmu_domain_init(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain;
+ pgd_t *pgd;
+
+ /*
+ * Allocate the domain and initialise some of its data structures.
+ * We can't really do anything meaningful until we've added a
+ * master.
+ */
+ smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
+ if (!smmu_domain)
+ return -ENOMEM;
+
+ pgd = kzalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
+ if (!pgd)
+ goto out_free_domain;
+ smmu_domain->root_cfg.pgd = pgd;
+
+ spin_lock_init(&smmu_domain->lock);
+ domain->priv = smmu_domain;
+ return 0;
+
+out_free_domain:
+ kfree(smmu_domain);
+ return -ENOMEM;
+}
+
+static void arm_smmu_free_ptes(pmd_t *pmd)
+{
+ pgtable_t table = pmd_pgtable(*pmd);
+ pgtable_page_dtor(table);
+ __free_page(table);
+}
+
+static void arm_smmu_free_pmds(pud_t *pud)
+{
+ int i;
+ pmd_t *pmd, *pmd_base = pmd_offset(pud, 0);
+
+ pmd = pmd_base;
+ for (i = 0; i < PTRS_PER_PMD; ++i) {
+ if (pmd_none(*pmd))
+ continue;
+
+ arm_smmu_free_ptes(pmd);
+ pmd++;
+ }
+
+ pmd_free(NULL, pmd_base);
+}
+
+static void arm_smmu_free_puds(pgd_t *pgd)
+{
+ int i;
+ pud_t *pud, *pud_base = pud_offset(pgd, 0);
+
+ pud = pud_base;
+ for (i = 0; i < PTRS_PER_PUD; ++i) {
+ if (pud_none(*pud))
+ continue;
+
+ arm_smmu_free_pmds(pud);
+ pud++;
+ }
+
+ pud_free(NULL, pud_base);
+}
+
+static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain)
+{
+ int i;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ pgd_t *pgd, *pgd_base = root_cfg->pgd;
+
+ /*
+ * Recursively free the page tables for this domain. We don't
+ * care about speculative TLB filling, because the TLB will be
+ * nuked next time this context bank is re-allocated and no devices
+ * currently map to these tables.
+ */
+ pgd = pgd_base;
+ for (i = 0; i < PTRS_PER_PGD; ++i) {
+ if (pgd_none(*pgd))
+ continue;
+ arm_smmu_free_puds(pgd);
+ pgd++;
+ }
+
+ kfree(pgd_base);
+}
+
+static void arm_smmu_domain_destroy(struct iommu_domain *domain)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ arm_smmu_destroy_domain_context(domain);
+ arm_smmu_free_pgtables(smmu_domain);
+ kfree(smmu_domain);
+}
+
+static int arm_smmu_master_configure_smrs(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ int i;
+ struct arm_smmu_smr *smrs;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ if (!(smmu->features & ARM_SMMU_FEAT_STREAM_MATCH))
+ return 0;
+
+ if (master->smrs)
+ return -EEXIST;
+
+ smrs = kmalloc(sizeof(*smrs) * master->num_streamids, GFP_KERNEL);
+ if (!smrs) {
+ dev_err(smmu->dev, "failed to allocate %d SMRs for master %s\n",
+ master->num_streamids, master->of_node->name);
+ return -ENOMEM;
+ }
+
+ /* Allocate the SMRs on the root SMMU */
+ for (i = 0; i < master->num_streamids; ++i) {
+ int idx = __arm_smmu_alloc_bitmap(smmu->smr_map, 0,
+ smmu->num_mapping_groups);
+ if (IS_ERR_VALUE(idx)) {
+ dev_err(smmu->dev, "failed to allocate free SMR\n");
+ goto err_free_smrs;
+ }
+
+ smrs[i] = (struct arm_smmu_smr) {
+ .idx = idx,
+ .mask = 0, /* We don't currently share SMRs */
+ .id = master->streamids[i],
+ };
+ }
+
+ /* It worked! Now, poke the actual hardware */
+ for (i = 0; i < master->num_streamids; ++i) {
+ u32 reg = SMR_VALID | smrs[i].id << SMR_ID_SHIFT |
+ smrs[i].mask << SMR_MASK_SHIFT;
+ writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_SMR(smrs[i].idx));
+ }
+
+ master->smrs = smrs;
+ return 0;
+
+err_free_smrs:
+ while (--i >= 0)
+ __arm_smmu_free_bitmap(smmu->smr_map, smrs[i].idx);
+ kfree(smrs);
+ return -ENOSPC;
+}
+
+static void arm_smmu_master_free_smrs(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ int i;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+ struct arm_smmu_smr *smrs = master->smrs;
+
+ /* Invalidate the SMRs before freeing back to the allocator */
+ for (i = 0; i < master->num_streamids; ++i) {
+ u8 idx = smrs[i].idx;
+ writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(idx));
+ __arm_smmu_free_bitmap(smmu->smr_map, idx);
+ }
+
+ master->smrs = NULL;
+ kfree(smrs);
+}
+
+static void arm_smmu_bypass_stream_mapping(struct arm_smmu_device *smmu,
+ struct arm_smmu_master *master)
+{
+ int i;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ for (i = 0; i < master->num_streamids; ++i) {
+ u16 sid = master->streamids[i];
+ writel_relaxed(S2CR_TYPE_BYPASS,
+ gr0_base + ARM_SMMU_GR0_S2CR(sid));
+ }
+}
+
+static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_master *master)
+{
+ int i, ret;
+ struct arm_smmu_device *parent, *smmu = smmu_domain->root_cfg.smmu;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ ret = arm_smmu_master_configure_smrs(smmu, master);
+ if (ret)
+ return ret;
+
+ /* Bypass the leaves */
+ smmu = smmu_domain->leaf_smmu;
+ while ((parent = find_parent_smmu(smmu))) {
+ /*
+ * We won't have a StreamID match for anything but the root
+ * smmu, so we only need to worry about StreamID indexing,
+ * where we must install bypass entries in the S2CRs.
+ */
+ if (smmu->features & ARM_SMMU_FEAT_STREAM_MATCH)
+ continue;
+
+ arm_smmu_bypass_stream_mapping(smmu, master);
+ smmu = parent;
+ }
+
+ /* Now we're at the root, time to point at our context bank */
+ for (i = 0; i < master->num_streamids; ++i) {
+ u32 idx, s2cr;
+ idx = master->smrs ? master->smrs[i].idx : master->streamids[i];
+ s2cr = (S2CR_TYPE_TRANS << S2CR_TYPE_SHIFT) |
+ (smmu_domain->root_cfg.cbndx << S2CR_CBNDX_SHIFT);
+ writel_relaxed(s2cr, gr0_base + ARM_SMMU_GR0_S2CR(idx));
+ }
+
+ return 0;
+}
+
+static void arm_smmu_domain_remove_master(struct arm_smmu_domain *smmu_domain,
+ struct arm_smmu_master *master)
+{
+ struct arm_smmu_device *smmu = smmu_domain->root_cfg.smmu;
+
+ /*
+ * We *must* clear the S2CR first, because freeing the SMR means
+ * that it can be re-allocated immediately.
+ */
+ arm_smmu_bypass_stream_mapping(smmu, master);
+ arm_smmu_master_free_smrs(smmu, master);
+}
+
+static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+ int ret = -EINVAL;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_device *device_smmu = dev->archdata.iommu;
+ struct arm_smmu_master *master;
+
+ if (!device_smmu) {
+ dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n");
+ return -ENXIO;
+ }
+
+ /*
+ * Sanity check the domain. We don't currently support domains
+ * that cross between different SMMU chains.
+ */
+ spin_lock(&smmu_domain->lock);
+ if (!smmu_domain->leaf_smmu) {
+ /* Now that we have a master, we can finalise the domain */
+ ret = arm_smmu_init_domain_context(domain, dev);
+ if (IS_ERR_VALUE(ret))
+ goto err_unlock;
+
+ smmu_domain->leaf_smmu = device_smmu;
+ } else if (smmu_domain->leaf_smmu != device_smmu) {
+ dev_err(dev,
+ "cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
+ dev_name(smmu_domain->leaf_smmu->dev),
+ dev_name(device_smmu->dev));
+ goto err_unlock;
+ }
+ spin_unlock(&smmu_domain->lock);
+
+ /* Looks ok, so add the device to the domain */
+ master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
+ if (!master)
+ return -ENODEV;
+
+ return arm_smmu_domain_add_master(smmu_domain, master);
+
+err_unlock:
+ spin_unlock(&smmu_domain->lock);
+ return ret;
+}
+
+static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_master *master;
+
+ master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node);
+ if (master)
+ arm_smmu_domain_remove_master(smmu_domain, master);
+}
+
+static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
+ size_t size)
+{
+ unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+ /*
+ * If the SMMU can't walk tables in the CPU caches, treat them
+ * like non-coherent DMA since we need to flush the new entries
+ * all the way out to memory. There's no possibility of recursion
+ * here as the SMMU table walker will not be wired through another
+ * SMMU.
+ */
+ if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK))
+ dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+ DMA_TO_DEVICE);
+}
+
+static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
+ unsigned long end)
+{
+ return !(addr & ~ARM_SMMU_PTE_CONT_MASK) &&
+ (addr + ARM_SMMU_PTE_CONT_SIZE <= end);
+}
+
+static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ unsigned long pfn, int flags, int stage)
+{
+ pte_t *pte, *start;
+ pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF;
+
+ if (pmd_none(*pmd)) {
+ /* Allocate a new set of tables */
+ pgtable_t table = alloc_page(PGALLOC_GFP);
+ if (!table)
+ return -ENOMEM;
+
+ arm_smmu_flush_pgtable(smmu, page_address(table),
+ ARM_SMMU_PTE_HWTABLE_SIZE);
+ pgtable_page_ctor(table);
+ pmd_populate(NULL, pmd, table);
+ arm_smmu_flush_pgtable(smmu, pmd, sizeof(*pmd));
+ }
+
+ if (stage == 1) {
+ pteval |= ARM_SMMU_PTE_AP_UNPRIV;
+ if (!(flags & IOMMU_WRITE) && (flags & IOMMU_READ))
+ pteval |= ARM_SMMU_PTE_AP_RDONLY;
+
+ if (flags & IOMMU_CACHE)
+ pteval |= (MAIR_ATTR_IDX_CACHE <<
+ ARM_SMMU_PTE_ATTRINDX_SHIFT);
+ } else {
+ pteval |= ARM_SMMU_PTE_HAP_FAULT;
+ if (flags & IOMMU_READ)
+ pteval |= ARM_SMMU_PTE_HAP_READ;
+ if (flags & IOMMU_WRITE)
+ pteval |= ARM_SMMU_PTE_HAP_WRITE;
+ if (flags & IOMMU_CACHE)
+ pteval |= ARM_SMMU_PTE_MEMATTR_OIWB;
+ else
+ pteval |= ARM_SMMU_PTE_MEMATTR_NC;
+ }
+
+ /* If no access, create a faulting entry to avoid TLB fills */
+ if (!(flags & (IOMMU_READ | IOMMU_WRITE)))
+ pteval &= ~ARM_SMMU_PTE_PAGE;
+
+ pteval |= ARM_SMMU_PTE_SH_IS;
+ start = pmd_page_vaddr(*pmd) + pte_index(addr);
+ pte = start;
+
+ /*
+ * Install the page table entries. This is fairly complicated
+ * since we attempt to make use of the contiguous hint in the
+ * ptes where possible. The contiguous hint indicates a series
+ * of ARM_SMMU_PTE_CONT_ENTRIES ptes mapping a physically
+ * contiguous region with the following constraints:
+ *
+ * - The region start is aligned to ARM_SMMU_PTE_CONT_SIZE
+ * - Each pte in the region has the contiguous hint bit set
+ *
+ * This complicates unmapping (also handled by this code, when
+ * neither IOMMU_READ or IOMMU_WRITE are set) because it is
+ * possible, yet highly unlikely, that a client may unmap only
+ * part of a contiguous range. This requires clearing of the
+ * contiguous hint bits in the range before installing the new
+ * faulting entries.
+ *
+ * Note that re-mapping an address range without first unmapping
+ * it is not supported, so TLB invalidation is not required here
+ * and is instead performed at unmap and domain-init time.
+ */
+ do {
+ int i = 1;
+ pteval &= ~ARM_SMMU_PTE_CONT;
+
+ if (arm_smmu_pte_is_contiguous_range(addr, end)) {
+ i = ARM_SMMU_PTE_CONT_ENTRIES;
+ pteval |= ARM_SMMU_PTE_CONT;
+ } else if (pte_val(*pte) &
+ (ARM_SMMU_PTE_CONT | ARM_SMMU_PTE_PAGE)) {
+ int j;
+ pte_t *cont_start;
+ unsigned long idx = pte_index(addr);
+
+ idx &= ~(ARM_SMMU_PTE_CONT_ENTRIES - 1);
+ cont_start = pmd_page_vaddr(*pmd) + idx;
+ for (j = 0; j < ARM_SMMU_PTE_CONT_ENTRIES; ++j)
+ pte_val(*(cont_start + j)) &= ~ARM_SMMU_PTE_CONT;
+
+ arm_smmu_flush_pgtable(smmu, cont_start,
+ sizeof(*pte) *
+ ARM_SMMU_PTE_CONT_ENTRIES);
+ }
+
+ do {
+ *pte = pfn_pte(pfn, __pgprot(pteval));
+ } while (pte++, pfn++, addr += PAGE_SIZE, --i);
+ } while (addr != end);
+
+ arm_smmu_flush_pgtable(smmu, start, sizeof(*pte) * (pte - start));
+ return 0;
+}
+
+static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
+ unsigned long addr, unsigned long end,
+ phys_addr_t phys, int flags, int stage)
+{
+ int ret;
+ pmd_t *pmd;
+ unsigned long next, pfn = __phys_to_pfn(phys);
+
+#ifndef __PAGETABLE_PMD_FOLDED
+ if (pud_none(*pud)) {
+ pmd = pmd_alloc_one(NULL, addr);
+ if (!pmd)
+ return -ENOMEM;
+ } else
+#endif
+ pmd = pmd_offset(pud, addr);
+
+ do {
+ next = pmd_addr_end(addr, end);
+ ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn,
+ flags, stage);
+ pud_populate(NULL, pud, pmd);
+ arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
+ phys += next - addr;
+ } while (pmd++, addr = next, addr < end);
+
+ return ret;
+}
+
+static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
+ unsigned long addr, unsigned long end,
+ phys_addr_t phys, int flags, int stage)
+{
+ int ret = 0;
+ pud_t *pud;
+ unsigned long next;
+
+#ifndef __PAGETABLE_PUD_FOLDED
+ if (pgd_none(*pgd)) {
+ pud = pud_alloc_one(NULL, addr);
+ if (!pud)
+ return -ENOMEM;
+ } else
+#endif
+ pud = pud_offset(pgd, addr);
+
+ do {
+ next = pud_addr_end(addr, end);
+ ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
+ flags, stage);
+ pgd_populate(NULL, pud, pgd);
+ arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
+ phys += next - addr;
+ } while (pud++, addr = next, addr < end);
+
+ return ret;
+}
+
+static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
+ unsigned long iova, phys_addr_t paddr,
+ size_t size, int flags)
+{
+ int ret, stage;
+ unsigned long end;
+ phys_addr_t input_mask, output_mask;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ pgd_t *pgd = root_cfg->pgd;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+
+ if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) {
+ stage = 2;
+ output_mask = (1ULL << smmu->s2_output_size) - 1;
+ } else {
+ stage = 1;
+ output_mask = (1ULL << smmu->s1_output_size) - 1;
+ }
+
+ if (!pgd)
+ return -EINVAL;
+
+ if (size & ~PAGE_MASK)
+ return -EINVAL;
+
+ input_mask = (1ULL << smmu->input_size) - 1;
+ if ((phys_addr_t)iova & ~input_mask)
+ return -ERANGE;
+
+ if (paddr & ~output_mask)
+ return -ERANGE;
+
+ spin_lock(&smmu_domain->lock);
+ pgd += pgd_index(iova);
+ end = iova + size;
+ do {
+ unsigned long next = pgd_addr_end(iova, end);
+
+ ret = arm_smmu_alloc_init_pud(smmu, pgd, iova, next, paddr,
+ flags, stage);
+ if (ret)
+ goto out_unlock;
+
+ paddr += next - iova;
+ iova = next;
+ } while (pgd++, iova != end);
+
+out_unlock:
+ spin_unlock(&smmu_domain->lock);
+
+ /* Ensure new page tables are visible to the hardware walker */
+ if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+ dsb();
+
+ return ret;
+}
+
+static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int flags)
+{
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_device *smmu = smmu_domain->leaf_smmu;
+
+ if (!smmu_domain || !smmu)
+ return -ENODEV;
+
+ /* Check for silent address truncation up the SMMU chain. */
+ if ((phys_addr_t)iova & ~smmu_domain->output_mask)
+ return -ERANGE;
+
+ return arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, flags);
+}
+
+static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size)
+{
+ int ret;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+
+ ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
+ writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
+ arm_smmu_tlb_sync(smmu);
+ return ret ? ret : size;
+}
+
+static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
+ dma_addr_t iova)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
+ struct arm_smmu_device *smmu = root_cfg->smmu;
+
+ spin_lock(&smmu_domain->lock);
+ pgd = root_cfg->pgd;
+ if (!pgd)
+ goto err_unlock;
+
+ pgd += pgd_index(iova);
+ if (pgd_none_or_clear_bad(pgd))
+ goto err_unlock;
+
+ pud = pud_offset(pgd, iova);
+ if (pud_none_or_clear_bad(pud))
+ goto err_unlock;
+
+ pmd = pmd_offset(pud, iova);
+ if (pmd_none_or_clear_bad(pmd))
+ goto err_unlock;
+
+ pte = pmd_page_vaddr(*pmd) + pte_index(iova);
+ if (pte_none(pte))
+ goto err_unlock;
+
+ spin_unlock(&smmu_domain->lock);
+ return __pfn_to_phys(pte_pfn(*pte)) | (iova & ~PAGE_MASK);
+
+err_unlock:
+ spin_unlock(&smmu_domain->lock);
+ dev_warn(smmu->dev,
+ "invalid (corrupt?) page tables detected for iova 0x%llx\n",
+ (unsigned long long)iova);
+ return -EINVAL;
+}
+
+static int arm_smmu_domain_has_cap(struct iommu_domain *domain,
+ unsigned long cap)
+{
+ unsigned long caps = 0;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+
+ if (smmu_domain->root_cfg.smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)
+ caps |= IOMMU_CAP_CACHE_COHERENCY;
+
+ return !!(cap & caps);
+}
+
+static int arm_smmu_add_device(struct device *dev)
+{
+ struct arm_smmu_device *child, *parent, *smmu;
+ struct arm_smmu_master *master = NULL;
+
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(parent, &arm_smmu_devices, list) {
+ smmu = parent;
+
+ /* Try to find a child of the current SMMU. */
+ list_for_each_entry(child, &arm_smmu_devices, list) {
+ if (child->parent_of_node == parent->dev->of_node) {
+ /* Does the child sit above our master? */
+ master = find_smmu_master(child, dev->of_node);
+ if (master) {
+ smmu = NULL;
+ break;
+ }
+ }
+ }
+
+ /* We found some children, so keep searching. */
+ if (!smmu) {
+ master = NULL;
+ continue;
+ }
+
+ master = find_smmu_master(smmu, dev->of_node);
+ if (master)
+ break;
+ }
+ spin_unlock(&arm_smmu_devices_lock);
+
+ if (!master)
+ return -ENODEV;
+
+ dev->archdata.iommu = smmu;
+ return 0;
+}
+
+static void arm_smmu_remove_device(struct device *dev)
+{
+ dev->archdata.iommu = NULL;
+}
+
+static struct iommu_ops arm_smmu_ops = {
+ .domain_init = arm_smmu_domain_init,
+ .domain_destroy = arm_smmu_domain_destroy,
+ .attach_dev = arm_smmu_attach_dev,
+ .detach_dev = arm_smmu_detach_dev,
+ .map = arm_smmu_map,
+ .unmap = arm_smmu_unmap,
+ .iova_to_phys = arm_smmu_iova_to_phys,
+ .domain_has_cap = arm_smmu_domain_has_cap,
+ .add_device = arm_smmu_add_device,
+ .remove_device = arm_smmu_remove_device,
+ .pgsize_bitmap = (SECTION_SIZE |
+ ARM_SMMU_PTE_CONT_SIZE |
+ PAGE_SIZE),
+};
+
+static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
+{
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+ int i = 0;
+ u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
+
+ /* Mark all SMRn as invalid and all S2CRn as bypass */
+ for (i = 0; i < smmu->num_mapping_groups; ++i) {
+ writel_relaxed(~SMR_VALID, gr0_base + ARM_SMMU_GR0_SMR(i));
+ writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i));
+ }
+
+ /* Invalidate the TLB, just in case */
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
+ writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
+
+ /* Enable fault reporting */
+ scr0 |= (sCR0_GFRE | sCR0_GFIE | sCR0_GCFGFRE | sCR0_GCFGFIE);
+
+ /* Disable TLB broadcasting. */
+ scr0 |= (sCR0_VMIDPNE | sCR0_PTM);
+
+ /* Enable client access, but bypass when no mapping is found */
+ scr0 &= ~(sCR0_CLIENTPD | sCR0_USFCFG);
+
+ /* Disable forced broadcasting */
+ scr0 &= ~sCR0_FB;
+
+ /* Don't upgrade barriers */
+ scr0 &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT);
+
+ /* Push the button */
+ arm_smmu_tlb_sync(smmu);
+ writel(scr0, gr0_base + ARM_SMMU_GR0_sCR0);
+}
+
+static int arm_smmu_id_size_to_bits(int size)
+{
+ switch (size) {
+ case 0:
+ return 32;
+ case 1:
+ return 36;
+ case 2:
+ return 40;
+ case 3:
+ return 42;
+ case 4:
+ return 44;
+ case 5:
+ default:
+ return 48;
+ }
+}
+
+static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
+{
+ unsigned long size;
+ void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+ u32 id;
+
+ dev_notice(smmu->dev, "probing hardware configuration...\n");
+
+ /* Primecell ID */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_PIDR2);
+ smmu->version = ((id >> PIDR2_ARCH_SHIFT) & PIDR2_ARCH_MASK) + 1;
+ dev_notice(smmu->dev, "SMMUv%d with:\n", smmu->version);
+
+ /* ID0 */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0);
+#ifndef CONFIG_64BIT
+ if (((id >> ID0_PTFS_SHIFT) & ID0_PTFS_MASK) == ID0_PTFS_V8_ONLY) {
+ dev_err(smmu->dev, "\tno v7 descriptor support!\n");
+ return -ENODEV;
+ }
+#endif
+ if (id & ID0_S1TS) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_S1;
+ dev_notice(smmu->dev, "\tstage 1 translation\n");
+ }
+
+ if (id & ID0_S2TS) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_S2;
+ dev_notice(smmu->dev, "\tstage 2 translation\n");
+ }
+
+ if (id & ID0_NTS) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_NESTED;
+ dev_notice(smmu->dev, "\tnested translation\n");
+ }
+
+ if (!(smmu->features &
+ (ARM_SMMU_FEAT_TRANS_S1 | ARM_SMMU_FEAT_TRANS_S2 |
+ ARM_SMMU_FEAT_TRANS_NESTED))) {
+ dev_err(smmu->dev, "\tno translation support!\n");
+ return -ENODEV;
+ }
+
+ if (id & ID0_CTTW) {
+ smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
+ dev_notice(smmu->dev, "\tcoherent table walk\n");
+ }
+
+ if (id & ID0_SMS) {
+ u32 smr, sid, mask;
+
+ smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH;
+ smmu->num_mapping_groups = (id >> ID0_NUMSMRG_SHIFT) &
+ ID0_NUMSMRG_MASK;
+ if (smmu->num_mapping_groups == 0) {
+ dev_err(smmu->dev,
+ "stream-matching supported, but no SMRs present!\n");
+ return -ENODEV;
+ }
+
+ smr = SMR_MASK_MASK << SMR_MASK_SHIFT;
+ smr |= (SMR_ID_MASK << SMR_ID_SHIFT);
+ writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0));
+ smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0));
+
+ mask = (smr >> SMR_MASK_SHIFT) & SMR_MASK_MASK;
+ sid = (smr >> SMR_ID_SHIFT) & SMR_ID_MASK;
+ if ((mask & sid) != sid) {
+ dev_err(smmu->dev,
+ "SMR mask bits (0x%x) insufficient for ID field (0x%x)\n",
+ mask, sid);
+ return -ENODEV;
+ }
+
+ dev_notice(smmu->dev,
+ "\tstream matching with %u register groups, mask 0x%x",
+ smmu->num_mapping_groups, mask);
+ }
+
+ /* ID1 */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID1);
+ smmu->pagesize = (id & ID1_PAGESIZE) ? SZ_64K : SZ_4K;
+
+ /* Check that we ioremapped enough */
+ size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1);
+ size *= (smmu->pagesize << 1);
+ if (smmu->size < size)
+ dev_warn(smmu->dev,
+ "device is 0x%lx bytes but only mapped 0x%lx!\n",
+ size, smmu->size);
+
+ smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) &
+ ID1_NUMS2CB_MASK;
+ smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK;
+ if (smmu->num_s2_context_banks > smmu->num_context_banks) {
+ dev_err(smmu->dev, "impossible number of S2 context banks!\n");
+ return -ENODEV;
+ }
+ dev_notice(smmu->dev, "\t%u context banks (%u stage-2 only)\n",
+ smmu->num_context_banks, smmu->num_s2_context_banks);
+
+ /* ID2 */
+ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
+ size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
+
+ /*
+ * Stage-1 output limited by stage-2 input size due to pgd
+ * allocation (PTRS_PER_PGD).
+ */
+#ifdef CONFIG_64BIT
+ /* Current maximum output size of 39 bits */
+ smmu->s1_output_size = min(39UL, size);
+#else
+ smmu->s1_output_size = min(32UL, size);
+#endif
+
+ /* The stage-2 output mask is also applied for bypass */
+ size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
+ smmu->s2_output_size = min((unsigned long)PHYS_MASK_SHIFT, size);
+
+ if (smmu->version == 1) {
+ smmu->input_size = 32;
+ } else {
+#ifdef CONFIG_64BIT
+ size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
+ size = min(39, arm_smmu_id_size_to_bits(size));
+#else
+ size = 32;
+#endif
+ smmu->input_size = size;
+
+ if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
+ (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
+ (PAGE_SIZE != SZ_4K && PAGE_SIZE != SZ_64K)) {
+ dev_err(smmu->dev, "CPU page size 0x%lx unsupported\n",
+ PAGE_SIZE);
+ return -ENODEV;
+ }
+ }
+
+ dev_notice(smmu->dev,
+ "\t%lu-bit VA, %lu-bit IPA, %lu-bit PA\n",
+ smmu->input_size, smmu->s1_output_size, smmu->s2_output_size);
+ return 0;
+}
+
+static int arm_smmu_device_dt_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct arm_smmu_device *smmu;
+ struct device_node *dev_node;
+ struct device *dev = &pdev->dev;
+ struct rb_node *node;
+ struct of_phandle_args masterspec;
+ int num_irqs, i, err;
+
+ smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+ if (!smmu) {
+ dev_err(dev, "failed to allocate arm_smmu_device\n");
+ return -ENOMEM;
+ }
+ smmu->dev = dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing base address/size\n");
+ return -ENODEV;
+ }
+
+ smmu->size = resource_size(res);
+ smmu->base = devm_request_and_ioremap(dev, res);
+ if (!smmu->base)
+ return -EADDRNOTAVAIL;
+
+ if (of_property_read_u32(dev->of_node, "#global-interrupts",
+ &smmu->num_global_irqs)) {
+ dev_err(dev, "missing #global-interrupts property\n");
+ return -ENODEV;
+ }
+
+ num_irqs = 0;
+ while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) {
+ num_irqs++;
+ if (num_irqs > smmu->num_global_irqs)
+ smmu->num_context_irqs++;
+ }
+
+ if (num_irqs < smmu->num_global_irqs) {
+ dev_warn(dev, "found %d interrupts but expected at least %d\n",
+ num_irqs, smmu->num_global_irqs);
+ smmu->num_global_irqs = num_irqs;
+ }
+ smmu->num_context_irqs = num_irqs - smmu->num_global_irqs;
+
+ smmu->irqs = devm_kzalloc(dev, sizeof(*smmu->irqs) * num_irqs,
+ GFP_KERNEL);
+ if (!smmu->irqs) {
+ dev_err(dev, "failed to allocate %d irqs\n", num_irqs);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num_irqs; ++i) {
+ int irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ dev_err(dev, "failed to get irq index %d\n", i);
+ return -ENODEV;
+ }
+ smmu->irqs[i] = irq;
+ }
+
+ i = 0;
+ smmu->masters = RB_ROOT;
+ while (!of_parse_phandle_with_args(dev->of_node, "mmu-masters",
+ "#stream-id-cells", i,
+ &masterspec)) {
+ err = register_smmu_master(smmu, dev, &masterspec);
+ if (err) {
+ dev_err(dev, "failed to add master %s\n",
+ masterspec.np->name);
+ goto out_put_masters;
+ }
+
+ i++;
+ }
+ dev_notice(dev, "registered %d master devices\n", i);
+
+ if ((dev_node = of_parse_phandle(dev->of_node, "smmu-parent", 0)))
+ smmu->parent_of_node = dev_node;
+
+ err = arm_smmu_device_cfg_probe(smmu);
+ if (err)
+ goto out_put_parent;
+
+ if (smmu->version > 1 &&
+ smmu->num_context_banks != smmu->num_context_irqs) {
+ dev_err(dev,
+ "found only %d context interrupt(s) but %d required\n",
+ smmu->num_context_irqs, smmu->num_context_banks);
+ goto out_put_parent;
+ }
+
+ arm_smmu_device_reset(smmu);
+
+ for (i = 0; i < smmu->num_global_irqs; ++i) {
+ err = request_irq(smmu->irqs[i],
+ arm_smmu_global_fault,
+ IRQF_SHARED,
+ "arm-smmu global fault",
+ smmu);
+ if (err) {
+ dev_err(dev, "failed to request global IRQ %d (%u)\n",
+ i, smmu->irqs[i]);
+ goto out_free_irqs;
+ }
+ }
+
+ INIT_LIST_HEAD(&smmu->list);
+ spin_lock(&arm_smmu_devices_lock);
+ list_add(&smmu->list, &arm_smmu_devices);
+ spin_unlock(&arm_smmu_devices_lock);
+ return 0;
+
+out_free_irqs:
+ while (i--)
+ free_irq(smmu->irqs[i], smmu);
+
+out_put_parent:
+ if (smmu->parent_of_node)
+ of_node_put(smmu->parent_of_node);
+
+out_put_masters:
+ for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
+ struct arm_smmu_master *master;
+ master = container_of(node, struct arm_smmu_master, node);
+ of_node_put(master->of_node);
+ }
+
+ return err;
+}
+
+static int arm_smmu_device_remove(struct platform_device *pdev)
+{
+ int i;
+ struct device *dev = &pdev->dev;
+ struct arm_smmu_device *curr, *smmu = NULL;
+ struct rb_node *node;
+
+ spin_lock(&arm_smmu_devices_lock);
+ list_for_each_entry(curr, &arm_smmu_devices, list) {
+ if (curr->dev == dev) {
+ smmu = curr;
+ list_del(&smmu->list);
+ break;
+ }
+ }
+ spin_unlock(&arm_smmu_devices_lock);
+
+ if (!smmu)
+ return -ENODEV;
+
+ if (smmu->parent_of_node)
+ of_node_put(smmu->parent_of_node);
+
+ for (node = rb_first(&smmu->masters); node; node = rb_next(node)) {
+ struct arm_smmu_master *master;
+ master = container_of(node, struct arm_smmu_master, node);
+ of_node_put(master->of_node);
+ }
+
+ if (!bitmap_empty(smmu->vmid_map, ARM_SMMU_NUM_VMIDS))
+ dev_err(dev, "removing device with active domains!\n");
+
+ for (i = 0; i < smmu->num_global_irqs; ++i)
+ free_irq(smmu->irqs[i], smmu);
+
+ /* Turn the thing off */
+ writel(sCR0_CLIENTPD, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_sCR0);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id arm_smmu_of_match[] = {
+ { .compatible = "arm,smmu-v1", },
+ { .compatible = "arm,smmu-v2", },
+ { .compatible = "arm,mmu-400", },
+ { .compatible = "arm,mmu-500", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+#endif
+
+static struct platform_driver arm_smmu_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "arm-smmu",
+ .of_match_table = of_match_ptr(arm_smmu_of_match),
+ },
+ .probe = arm_smmu_device_dt_probe,
+ .remove = arm_smmu_device_remove,
+};
+
+static int __init arm_smmu_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&arm_smmu_driver);
+ if (ret)
+ return ret;
+
+ /* Oh, for a proper bus abstraction */
+ if (!iommu_present(&platform_bus_type));
+ bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
+
+ if (!iommu_present(&amba_bustype));
+ bus_set_iommu(&amba_bustype, &arm_smmu_ops);
+
+ return 0;
+}
+
+static void __exit arm_smmu_exit(void)
+{
+ return platform_driver_unregister(&arm_smmu_driver);
+}
+
+module_init(arm_smmu_init);
+module_exit(arm_smmu_exit);
+
+MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
+MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c
index a7967ceb79e6..785675a56a10 100644
--- a/drivers/iommu/dmar.c
+++ b/drivers/iommu/dmar.c
@@ -309,6 +309,7 @@ parse_dmar_table(void)
struct acpi_table_dmar *dmar;
struct acpi_dmar_header *entry_header;
int ret = 0;
+ int drhd_count = 0;
/*
* Do it again, earlier dmar_tbl mapping could be mapped with
@@ -347,6 +348,7 @@ parse_dmar_table(void)
switch (entry_header->type) {
case ACPI_DMAR_TYPE_HARDWARE_UNIT:
+ drhd_count++;
ret = dmar_parse_one_drhd(entry_header);
break;
case ACPI_DMAR_TYPE_RESERVED_MEMORY:
@@ -371,6 +373,8 @@ parse_dmar_table(void)
entry_header = ((void *)entry_header + entry_header->length);
}
+ if (drhd_count == 0)
+ pr_warn(FW_BUG "No DRHD structure found in DMAR table\n");
return ret;
}
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index b4f0e28dfa41..eec0d3e04bf5 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4182,14 +4182,27 @@ static int intel_iommu_add_device(struct device *dev)
/*
* If it's a multifunction device that does not support our
- * required ACS flags, add to the same group as function 0.
+ * required ACS flags, add to the same group as lowest numbered
+ * function that also does not suport the required ACS flags.
*/
if (dma_pdev->multifunction &&
- !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
- swap_pci_ref(&dma_pdev,
- pci_get_slot(dma_pdev->bus,
- PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
- 0)));
+ !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+ u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+ for (i = 0; i < 8; i++) {
+ struct pci_dev *tmp;
+
+ tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+ if (!tmp)
+ continue;
+
+ if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+ swap_pci_ref(&dma_pdev, tmp);
+ break;
+ }
+ pci_dev_put(tmp);
+ }
+ }
/*
* Devices on the root bus go through the iommu. If that's not us,
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 5b19b2d6ec2d..f71673dbb23d 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -664,8 +664,7 @@ error:
*/
if (x2apic_present)
- WARN(1, KERN_WARNING
- "Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
+ pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
return -1;
}
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index d8f98b14e2fe..fbe9ca734f8f 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -754,6 +754,38 @@ int iommu_domain_has_cap(struct iommu_domain *domain,
}
EXPORT_SYMBOL_GPL(iommu_domain_has_cap);
+static size_t iommu_pgsize(struct iommu_domain *domain,
+ unsigned long addr_merge, size_t size)
+{
+ unsigned int pgsize_idx;
+ size_t pgsize;
+
+ /* Max page size that still fits into 'size' */
+ pgsize_idx = __fls(size);
+
+ /* need to consider alignment requirements ? */
+ if (likely(addr_merge)) {
+ /* Max page size allowed by address */
+ unsigned int align_pgsize_idx = __ffs(addr_merge);
+ pgsize_idx = min(pgsize_idx, align_pgsize_idx);
+ }
+
+ /* build a mask of acceptable page sizes */
+ pgsize = (1UL << (pgsize_idx + 1)) - 1;
+
+ /* throw away page sizes not supported by the hardware */
+ pgsize &= domain->ops->pgsize_bitmap;
+
+ /* make sure we're still sane */
+ BUG_ON(!pgsize);
+
+ /* pick the biggest page */
+ pgsize_idx = __fls(pgsize);
+ pgsize = 1UL << pgsize_idx;
+
+ return pgsize;
+}
+
int iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
@@ -775,45 +807,18 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
* size of the smallest page supported by the hardware
*/
if (!IS_ALIGNED(iova | paddr | size, min_pagesz)) {
- pr_err("unaligned: iova 0x%lx pa 0x%lx size 0x%lx min_pagesz "
- "0x%x\n", iova, (unsigned long)paddr,
- (unsigned long)size, min_pagesz);
+ pr_err("unaligned: iova 0x%lx pa 0x%pa size 0x%zx min_pagesz 0x%x\n",
+ iova, &paddr, size, min_pagesz);
return -EINVAL;
}
- pr_debug("map: iova 0x%lx pa 0x%lx size 0x%lx\n", iova,
- (unsigned long)paddr, (unsigned long)size);
+ pr_debug("map: iova 0x%lx pa 0x%pa size 0x%zx\n", iova, &paddr, size);
while (size) {
- unsigned long pgsize, addr_merge = iova | paddr;
- unsigned int pgsize_idx;
-
- /* Max page size that still fits into 'size' */
- pgsize_idx = __fls(size);
-
- /* need to consider alignment requirements ? */
- if (likely(addr_merge)) {
- /* Max page size allowed by both iova and paddr */
- unsigned int align_pgsize_idx = __ffs(addr_merge);
-
- pgsize_idx = min(pgsize_idx, align_pgsize_idx);
- }
-
- /* build a mask of acceptable page sizes */
- pgsize = (1UL << (pgsize_idx + 1)) - 1;
-
- /* throw away page sizes not supported by the hardware */
- pgsize &= domain->ops->pgsize_bitmap;
-
- /* make sure we're still sane */
- BUG_ON(!pgsize);
-
- /* pick the biggest page */
- pgsize_idx = __fls(pgsize);
- pgsize = 1UL << pgsize_idx;
+ size_t pgsize = iommu_pgsize(domain, iova | paddr, size);
- pr_debug("mapping: iova 0x%lx pa 0x%lx pgsize %lu\n", iova,
- (unsigned long)paddr, pgsize);
+ pr_debug("mapping: iova 0x%lx pa 0x%pa pgsize 0x%zx\n",
+ iova, &paddr, pgsize);
ret = domain->ops->map(domain, iova, paddr, pgsize, prot);
if (ret)
@@ -850,27 +855,26 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
* by the hardware
*/
if (!IS_ALIGNED(iova | size, min_pagesz)) {
- pr_err("unaligned: iova 0x%lx size 0x%lx min_pagesz 0x%x\n",
- iova, (unsigned long)size, min_pagesz);
+ pr_err("unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
+ iova, size, min_pagesz);
return -EINVAL;
}
- pr_debug("unmap this: iova 0x%lx size 0x%lx\n", iova,
- (unsigned long)size);
+ pr_debug("unmap this: iova 0x%lx size 0x%zx\n", iova, size);
/*
* Keep iterating until we either unmap 'size' bytes (or more)
* or we hit an area that isn't mapped.
*/
while (unmapped < size) {
- size_t left = size - unmapped;
+ size_t pgsize = iommu_pgsize(domain, iova, size - unmapped);
- unmapped_page = domain->ops->unmap(domain, iova, left);
+ unmapped_page = domain->ops->unmap(domain, iova, pgsize);
if (!unmapped_page)
break;
- pr_debug("unmapped: iova 0x%lx size %lx\n", iova,
- (unsigned long)unmapped_page);
+ pr_debug("unmapped: iova 0x%lx size 0x%zx\n",
+ iova, unmapped_page);
iova += unmapped_page;
unmapped += unmapped_page;
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index dcfea4e39be7..39f81aeefcd6 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -51,26 +51,27 @@ static void irq_remapping_disable_io_apic(void)
static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
{
- int node, ret, sub_handle, index = 0;
+ int node, ret, sub_handle, nvec_pow2, index = 0;
unsigned int irq;
struct msi_desc *msidesc;
- nvec = __roundup_pow_of_two(nvec);
-
WARN_ON(!list_is_singular(&dev->msi_list));
msidesc = list_entry(dev->msi_list.next, struct msi_desc, list);
WARN_ON(msidesc->irq);
WARN_ON(msidesc->msi_attrib.multiple);
+ WARN_ON(msidesc->nvec_used);
node = dev_to_node(&dev->dev);
irq = __create_irqs(get_nr_irqs_gsi(), nvec, node);
if (irq == 0)
return -ENOSPC;
- msidesc->msi_attrib.multiple = ilog2(nvec);
+ nvec_pow2 = __roundup_pow_of_two(nvec);
+ msidesc->nvec_used = nvec;
+ msidesc->msi_attrib.multiple = ilog2(nvec_pow2);
for (sub_handle = 0; sub_handle < nvec; sub_handle++) {
if (!sub_handle) {
- index = msi_alloc_remapped_irq(dev, irq, nvec);
+ index = msi_alloc_remapped_irq(dev, irq, nvec_pow2);
if (index < 0) {
ret = index;
goto error;
@@ -95,6 +96,7 @@ error:
* IRQs from tearing down again in default_teardown_msi_irqs()
*/
msidesc->irq = 0;
+ msidesc->nvec_used = 0;
msidesc->msi_attrib.multiple = 0;
return ret;
diff --git a/drivers/iommu/msm_iommu_dev.c b/drivers/iommu/msm_iommu_dev.c
index 9144a6beed92..6ba351477132 100644
--- a/drivers/iommu/msm_iommu_dev.c
+++ b/drivers/iommu/msm_iommu_dev.c
@@ -291,25 +291,20 @@ static int msm_iommu_ctx_probe(struct platform_device *pdev)
{
struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
struct msm_iommu_drvdata *drvdata;
- struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
+ struct msm_iommu_ctx_drvdata *ctx_drvdata;
int i, ret;
- if (!c || !pdev->dev.parent) {
- ret = -EINVAL;
- goto fail;
- }
- drvdata = dev_get_drvdata(pdev->dev.parent);
+ if (!c || !pdev->dev.parent)
+ return -EINVAL;
- if (!drvdata) {
- ret = -ENODEV;
- goto fail;
- }
+ drvdata = dev_get_drvdata(pdev->dev.parent);
+ if (!drvdata)
+ return -ENODEV;
ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
- if (!ctx_drvdata) {
- ret = -ENOMEM;
- goto fail;
- }
+ if (!ctx_drvdata)
+ return -ENOMEM;
+
ctx_drvdata->num = c->num;
ctx_drvdata->pdev = pdev;
@@ -403,6 +398,7 @@ static int __init msm_iommu_driver_init(void)
ret = platform_driver_register(&msm_iommu_ctx_driver);
if (ret != 0) {
+ platform_driver_unregister(&msm_iommu_driver);
pr_err("Failed to register IOMMU context driver\n");
goto error;
}
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index e02e5d71745b..0ba3766240d5 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -833,16 +833,15 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
iopgd = iopgd_offset(obj, da);
if (!iopgd_is_table(*iopgd)) {
- dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
- "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
+ dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:px%08x\n",
+ obj->name, errs, da, iopgd, *iopgd);
return IRQ_NONE;
}
iopte = iopte_offset(iopgd, da);
- dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
- "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
- iopte, *iopte);
+ dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x pte:0x%p *pte:0x%08x\n",
+ obj->name, errs, da, iopgd, *iopgd, iopte, *iopte);
return IRQ_NONE;
}
@@ -1235,14 +1234,16 @@ static phys_addr_t omap_iommu_iova_to_phys(struct iommu_domain *domain,
else if (iopte_is_large(*pte))
ret = omap_iommu_translate(*pte, da, IOLARGE_MASK);
else
- dev_err(dev, "bogus pte 0x%x, da 0x%lx", *pte, da);
+ dev_err(dev, "bogus pte 0x%x, da 0x%llx", *pte,
+ (unsigned long long)da);
} else {
if (iopgd_is_section(*pgd))
ret = omap_iommu_translate(*pgd, da, IOSECTION_MASK);
else if (iopgd_is_super(*pgd))
ret = omap_iommu_translate(*pgd, da, IOSUPER_MASK);
else
- dev_err(dev, "bogus pgd 0x%x, da 0x%lx", *pgd, da);
+ dev_err(dev, "bogus pgd 0x%x, da 0x%llx", *pgd,
+ (unsigned long long)da);
}
return ret;
diff --git a/drivers/iommu/omap-iopgtable.h b/drivers/iommu/omap-iopgtable.h
index cd4ae9e5b0c6..f4003d568a92 100644
--- a/drivers/iommu/omap-iopgtable.h
+++ b/drivers/iommu/omap-iopgtable.h
@@ -95,4 +95,4 @@ static inline phys_addr_t omap_iommu_translate(u32 d, u32 va, u32 mask)
#define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da))
#define to_iommu(dev) \
- (struct omap_iommu *)platform_get_drvdata(to_platform_device(dev))
+ ((struct omap_iommu *)platform_get_drvdata(to_platform_device(dev)))
diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c
index 46d875690739..d14725984153 100644
--- a/drivers/iommu/omap-iovmm.c
+++ b/drivers/iommu/omap-iovmm.c
@@ -102,8 +102,8 @@ static size_t sgtable_len(const struct sg_table *sgt)
}
if (i && sg->offset) {
- pr_err("%s: sg[%d] offset not allowed in internal "
- "entries\n", __func__, i);
+ pr_err("%s: sg[%d] offset not allowed in internal entries\n",
+ __func__, i);
return 0;
}
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 88d657dff474..8b98d53d9976 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -885,7 +885,7 @@ isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp)
addinfo[0] = '\0';
/* This check stolen from 2.1.72 dev_queue_xmit_nit() */
- if (p < skb->data || skb->network_header >= skb->tail) {
+ if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) {
/* fall back to old isdn_net_log_packet method() */
char *buf = skb->data;
diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c
index 88305c9cbff5..8b1a66c6ca8a 100644
--- a/drivers/isdn/mISDN/dsp_pipeline.c
+++ b/drivers/isdn/mISDN/dsp_pipeline.c
@@ -102,7 +102,7 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
entry->dev.class = elements_class;
entry->dev.release = mISDN_dsp_dev_release;
dev_set_drvdata(&entry->dev, elem);
- dev_set_name(&entry->dev, elem->name);
+ dev_set_name(&entry->dev, "%s", elem->name);
ret = device_register(&entry->dev);
if (ret) {
printk(KERN_ERR "%s: failed to register %s\n",
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ef992293598a..e43402dd1dea 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -388,12 +388,12 @@ config LEDS_DELL_NETBOOKS
notebooks that have an external LED.
config LEDS_MC13783
- tristate "LED Support for MC13783 PMIC"
+ tristate "LED Support for MC13XXX PMIC"
depends on LEDS_CLASS
- depends on MFD_MC13783
+ depends on MFD_MC13XXX
help
This option enable support for on-chip LED drivers found
- on Freescale Semiconductor MC13783 PMIC.
+ on Freescale Semiconductor MC13783/MC13892 PMIC.
config LEDS_NS2
tristate "LED support for Network Space v2 GPIO LEDs"
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index a20752f562bc..4336e37a97f4 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -156,7 +156,7 @@ void led_classdev_resume(struct led_classdev *led_cdev)
}
EXPORT_SYMBOL_GPL(led_classdev_resume);
-static int led_suspend(struct device *dev, pm_message_t state)
+static int led_suspend(struct device *dev)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
@@ -176,6 +176,11 @@ static int led_resume(struct device *dev)
return 0;
}
+static const struct dev_pm_ops leds_class_dev_pm_ops = {
+ .suspend = led_suspend,
+ .resume = led_resume,
+};
+
/**
* led_classdev_register - register a new object of led_classdev class.
* @parent: The device to register.
@@ -252,8 +257,7 @@ static int __init leds_init(void)
leds_class = class_create(THIS_MODULE, "leds");
if (IS_ERR(leds_class))
return PTR_ERR(leds_class);
- leds_class->suspend = led_suspend;
- leds_class->resume = led_resume;
+ leds_class->pm = &leds_class_dev_pm_ops;
leds_class->dev_attrs = led_class_attrs;
return 0;
}
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index f5b9ea315790..232b3ce902e5 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -204,7 +204,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
sprintf(data->name, "led1-blue");
break;
}
- dev_set_drvdata(&pdev->dev, data);
+ platform_set_drvdata(pdev, data);
data->chip = chip;
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
data->port = pdev->id;
diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c
index 8a39c5b20f76..90518f84b9c0 100644
--- a/drivers/leds/leds-atmel-pwm.c
+++ b/drivers/leds/leds-atmel-pwm.c
@@ -129,7 +129,6 @@ static int pwmled_remove(struct platform_device *pdev)
pwm_channel_free(&led->pwmc);
}
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b02b679abf31..84d74c373cae 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/err.h>
struct gpio_led_data {
@@ -236,13 +235,8 @@ static int gpio_led_probe(struct platform_device *pdev)
{
struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
struct gpio_leds_priv *priv;
- struct pinctrl *pinctrl;
int i, ret = 0;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&pdev->dev,
- "pins are not configured from the driver\n");
if (pdata && pdata->num_leds) {
priv = devm_kzalloc(&pdev->dev,
@@ -282,8 +276,6 @@ static int gpio_led_remove(struct platform_device *pdev)
for (i = 0; i < priv->num_leds; i++)
delete_gpio_led(&priv->leds[i]);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 19752c928aa2..1392feb1bcf7 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -31,6 +31,7 @@
#include <linux/mutex.h>
#include <linux/platform_data/leds-lp55xx.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include "leds-lp55xx-common.h"
@@ -416,12 +417,20 @@ static int lp5521_probe(struct i2c_client *client,
int ret;
struct lp55xx_chip *chip;
struct lp55xx_led *led;
- struct lp55xx_platform_data *pdata = client->dev.platform_data;
-
- if (!pdata) {
- dev_err(&client->dev, "no platform data\n");
- return -EINVAL;
+ struct lp55xx_platform_data *pdata;
+ struct device_node *np = client->dev.of_node;
+
+ if (!client->dev.platform_data) {
+ if (np) {
+ ret = lp55xx_of_populate_pdata(&client->dev, np);
+ if (ret < 0)
+ return ret;
+ } else {
+ dev_err(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
}
+ pdata = client->dev.platform_data;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -485,9 +494,18 @@ static const struct i2c_device_id lp5521_id[] = {
};
MODULE_DEVICE_TABLE(i2c, lp5521_id);
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp5521_leds_match[] = {
+ { .compatible = "national,lp5521", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp5521_leds_match);
+#endif
static struct i2c_driver lp5521_driver = {
.driver = {
.name = "lp5521",
+ .of_match_table = of_match_ptr(of_lp5521_leds_match),
},
.probe = lp5521_probe,
.remove = lp5521_remove,
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 229f734040af..3979428f3100 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -429,12 +429,20 @@ static int lp5523_probe(struct i2c_client *client,
int ret;
struct lp55xx_chip *chip;
struct lp55xx_led *led;
- struct lp55xx_platform_data *pdata = client->dev.platform_data;
-
- if (!pdata) {
- dev_err(&client->dev, "no platform data\n");
- return -EINVAL;
+ struct lp55xx_platform_data *pdata;
+ struct device_node *np = client->dev.of_node;
+
+ if (!client->dev.platform_data) {
+ if (np) {
+ ret = lp55xx_of_populate_pdata(&client->dev, np);
+ if (ret < 0)
+ return ret;
+ } else {
+ dev_err(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
}
+ pdata = client->dev.platform_data;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -500,9 +508,19 @@ static const struct i2c_device_id lp5523_id[] = {
MODULE_DEVICE_TABLE(i2c, lp5523_id);
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp5523_leds_match[] = {
+ { .compatible = "national,lp5523", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp5523_leds_match);
+#endif
+
static struct i2c_driver lp5523_driver = {
.driver = {
.name = "lp5523x",
+ .of_match_table = of_match_ptr(of_lp5523_leds_match),
},
.probe = lp5523_probe,
.remove = lp5523_remove,
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 513f2390ca2d..cbd856dac150 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -515,12 +515,20 @@ static int lp5562_probe(struct i2c_client *client,
int ret;
struct lp55xx_chip *chip;
struct lp55xx_led *led;
- struct lp55xx_platform_data *pdata = client->dev.platform_data;
-
- if (!pdata) {
- dev_err(&client->dev, "no platform data\n");
- return -EINVAL;
+ struct lp55xx_platform_data *pdata;
+ struct device_node *np = client->dev.of_node;
+
+ if (!client->dev.platform_data) {
+ if (np) {
+ ret = lp55xx_of_populate_pdata(&client->dev, np);
+ if (ret < 0)
+ return ret;
+ } else {
+ dev_err(&client->dev, "no platform data\n");
+ return -EINVAL;
+ }
}
+ pdata = client->dev.platform_data;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -583,9 +591,19 @@ static const struct i2c_device_id lp5562_id[] = {
};
MODULE_DEVICE_TABLE(i2c, lp5562_id);
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp5562_leds_match[] = {
+ { .compatible = "ti,lp5562", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp5562_leds_match);
+#endif
+
static struct i2c_driver lp5562_driver = {
.driver = {
.name = "lp5562",
+ .of_match_table = of_match_ptr(of_lp5562_leds_match),
},
.probe = lp5562_probe,
.remove = lp5562_remove,
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
index ba34199dc3d9..c2fecd4d391c 100644
--- a/drivers/leds/leds-lp55xx-common.c
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -19,6 +19,7 @@
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/platform_data/leds-lp55xx.h>
+#include <linux/slab.h>
#include "leds-lp55xx-common.h"
@@ -554,6 +555,50 @@ void lp55xx_unregister_sysfs(struct lp55xx_chip *chip)
}
EXPORT_SYMBOL_GPL(lp55xx_unregister_sysfs);
+int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np)
+{
+ struct device_node *child;
+ struct lp55xx_platform_data *pdata;
+ struct lp55xx_led_config *cfg;
+ int num_channels;
+ int i = 0;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ num_channels = of_get_child_count(np);
+ if (num_channels == 0) {
+ dev_err(dev, "no LED channels\n");
+ return -EINVAL;
+ }
+
+ cfg = devm_kzalloc(dev, sizeof(*cfg) * num_channels, GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ pdata->led_config = &cfg[0];
+ pdata->num_channels = num_channels;
+
+ for_each_child_of_node(np, child) {
+ cfg[i].chan_nr = i;
+
+ of_property_read_string(child, "chan-name", &cfg[i].name);
+ of_property_read_u8(child, "led-cur", &cfg[i].led_current);
+ of_property_read_u8(child, "max-cur", &cfg[i].max_current);
+
+ i++;
+ }
+
+ of_property_read_string(np, "label", &pdata->label);
+ of_property_read_u8(np, "clock-mode", &pdata->clock_mode);
+
+ dev->platform_data = pdata;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(lp55xx_of_populate_pdata);
+
MODULE_AUTHOR("Milo Kim <milo.kim@ti.com>");
MODULE_DESCRIPTION("LP55xx Common Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h
index fa6a078bf547..dbbf86df0f1f 100644
--- a/drivers/leds/leds-lp55xx-common.h
+++ b/drivers/leds/leds-lp55xx-common.h
@@ -135,4 +135,8 @@ extern void lp55xx_unregister_leds(struct lp55xx_led *led,
extern int lp55xx_register_sysfs(struct lp55xx_chip *chip);
extern void lp55xx_unregister_sysfs(struct lp55xx_chip *chip);
+/* common device tree population function */
+extern int lp55xx_of_populate_pdata(struct device *dev,
+ struct device_node *np);
+
#endif /* _LEDS_LP55XX_COMMON_H */
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index e942adaa7504..fa9b439323bd 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -1,5 +1,5 @@
/*
- * LEDs driver for Freescale MC13783
+ * LEDs driver for Freescale MC13783/MC13892
*
* Copyright (C) 2010 Philippe Rétornaz
*
@@ -22,9 +22,16 @@
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/mfd/mc13xxx.h>
-#include <linux/slab.h>
-struct mc13783_led {
+#define MC13XXX_REG_LED_CONTROL(x) (51 + (x))
+
+struct mc13xxx_led_devtype {
+ int led_min;
+ int led_max;
+ int num_regs;
+};
+
+struct mc13xxx_led {
struct led_classdev cdev;
struct work_struct work;
struct mc13xxx *master;
@@ -32,66 +39,35 @@ struct mc13783_led {
int id;
};
-#define MC13783_REG_LED_CONTROL_0 51
-#define MC13783_LED_C0_ENABLE_BIT (1 << 0)
-#define MC13783_LED_C0_TRIODE_MD_BIT (1 << 7)
-#define MC13783_LED_C0_TRIODE_AD_BIT (1 << 8)
-#define MC13783_LED_C0_TRIODE_KP_BIT (1 << 9)
-#define MC13783_LED_C0_BOOST_BIT (1 << 10)
-#define MC13783_LED_C0_ABMODE_MASK 0x7
-#define MC13783_LED_C0_ABMODE 11
-#define MC13783_LED_C0_ABREF_MASK 0x3
-#define MC13783_LED_C0_ABREF 14
-
-#define MC13783_REG_LED_CONTROL_1 52
-#define MC13783_LED_C1_TC1HALF_BIT (1 << 18)
-
-#define MC13783_REG_LED_CONTROL_2 53
-#define MC13783_LED_C2_BL_P_MASK 0xf
-#define MC13783_LED_C2_MD_P 9
-#define MC13783_LED_C2_AD_P 13
-#define MC13783_LED_C2_KP_P 17
-#define MC13783_LED_C2_BL_C_MASK 0x7
-#define MC13783_LED_C2_MD_C 0
-#define MC13783_LED_C2_AD_C 3
-#define MC13783_LED_C2_KP_C 6
-
-#define MC13783_REG_LED_CONTROL_3 54
-#define MC13783_LED_C3_TC_P 6
-#define MC13783_LED_C3_TC_P_MASK 0x1f
-
-#define MC13783_REG_LED_CONTROL_4 55
-#define MC13783_REG_LED_CONTROL_5 56
-
-#define MC13783_LED_Cx_PERIOD 21
-#define MC13783_LED_Cx_PERIOD_MASK 0x3
-#define MC13783_LED_Cx_SLEWLIM_BIT (1 << 23)
-#define MC13783_LED_Cx_TRIODE_TC_BIT (1 << 23)
-#define MC13783_LED_Cx_TC_C_MASK 0x3
-
-static void mc13783_led_work(struct work_struct *work)
+struct mc13xxx_leds {
+ struct mc13xxx_led_devtype *devtype;
+ int num_leds;
+ struct mc13xxx_led led[0];
+};
+
+static void mc13xxx_led_work(struct work_struct *work)
{
- struct mc13783_led *led = container_of(work, struct mc13783_led, work);
- int reg = 0;
- int mask = 0;
- int value = 0;
- int bank, off, shift;
+ struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
+ int reg, mask, value, bank, off, shift;
switch (led->id) {
case MC13783_LED_MD:
- reg = MC13783_REG_LED_CONTROL_2;
- mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_MD_P;
- value = (led->new_brightness >> 4) << MC13783_LED_C2_MD_P;
+ reg = MC13XXX_REG_LED_CONTROL(2);
+ shift = 9;
+ mask = 0x0f;
+ value = led->new_brightness >> 4;
break;
case MC13783_LED_AD:
- reg = MC13783_REG_LED_CONTROL_2;
- mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_AD_P;
- value = (led->new_brightness >> 4) << MC13783_LED_C2_AD_P;
+ reg = MC13XXX_REG_LED_CONTROL(2);
+ shift = 13;
+ mask = 0x0f;
+ value = led->new_brightness >> 4;
break;
case MC13783_LED_KP:
- reg = MC13783_REG_LED_CONTROL_2;
- mask = MC13783_LED_C2_BL_P_MASK << MC13783_LED_C2_KP_P;
- value = (led->new_brightness >> 4) << MC13783_LED_C2_KP_P;
+ reg = MC13XXX_REG_LED_CONTROL(2);
+ shift = 17;
+ mask = 0x0f;
+ value = led->new_brightness >> 4;
break;
case MC13783_LED_R1:
case MC13783_LED_G1:
@@ -103,57 +79,78 @@ static void mc13783_led_work(struct work_struct *work)
case MC13783_LED_G3:
case MC13783_LED_B3:
off = led->id - MC13783_LED_R1;
- bank = off/3;
- reg = MC13783_REG_LED_CONTROL_3 + off/3;
- shift = (off - bank * 3) * 5 + MC13783_LED_C3_TC_P;
- value = (led->new_brightness >> 3) << shift;
- mask = MC13783_LED_C3_TC_P_MASK << shift;
+ bank = off / 3;
+ reg = MC13XXX_REG_LED_CONTROL(3) + bank;
+ shift = (off - bank * 3) * 5 + 6;
+ value = led->new_brightness >> 3;
+ mask = 0x1f;
+ break;
+ case MC13892_LED_MD:
+ reg = MC13XXX_REG_LED_CONTROL(0);
+ shift = 3;
+ mask = 0x3f;
+ value = led->new_brightness >> 2;
+ break;
+ case MC13892_LED_AD:
+ reg = MC13XXX_REG_LED_CONTROL(0);
+ shift = 15;
+ mask = 0x3f;
+ value = led->new_brightness >> 2;
+ break;
+ case MC13892_LED_KP:
+ reg = MC13XXX_REG_LED_CONTROL(1);
+ shift = 3;
+ mask = 0x3f;
+ value = led->new_brightness >> 2;
break;
+ case MC13892_LED_R:
+ case MC13892_LED_G:
+ case MC13892_LED_B:
+ off = led->id - MC13892_LED_R;
+ bank = off / 2;
+ reg = MC13XXX_REG_LED_CONTROL(2) + bank;
+ shift = (off - bank * 2) * 12 + 3;
+ value = led->new_brightness >> 2;
+ mask = 0x3f;
+ break;
+ default:
+ BUG();
}
mc13xxx_lock(led->master);
-
- mc13xxx_reg_rmw(led->master, reg, mask, value);
-
+ mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift);
mc13xxx_unlock(led->master);
}
-static void mc13783_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static void mc13xxx_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- struct mc13783_led *led;
+ struct mc13xxx_led *led =
+ container_of(led_cdev, struct mc13xxx_led, cdev);
- led = container_of(led_cdev, struct mc13783_led, cdev);
led->new_brightness = value;
schedule_work(&led->work);
}
-static int mc13783_led_setup(struct mc13783_led *led, int max_current)
+static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current)
{
- int shift = 0;
- int mask = 0;
- int value = 0;
- int reg = 0;
- int ret, bank;
+ int shift, mask, reg, ret, bank;
switch (led->id) {
case MC13783_LED_MD:
- shift = MC13783_LED_C2_MD_C;
- mask = MC13783_LED_C2_BL_C_MASK;
- value = max_current & MC13783_LED_C2_BL_C_MASK;
- reg = MC13783_REG_LED_CONTROL_2;
+ reg = MC13XXX_REG_LED_CONTROL(2);
+ shift = 0;
+ mask = 0x07;
break;
case MC13783_LED_AD:
- shift = MC13783_LED_C2_AD_C;
- mask = MC13783_LED_C2_BL_C_MASK;
- value = max_current & MC13783_LED_C2_BL_C_MASK;
- reg = MC13783_REG_LED_CONTROL_2;
+ reg = MC13XXX_REG_LED_CONTROL(2);
+ shift = 3;
+ mask = 0x07;
break;
case MC13783_LED_KP:
- shift = MC13783_LED_C2_KP_C;
- mask = MC13783_LED_C2_BL_C_MASK;
- value = max_current & MC13783_LED_C2_BL_C_MASK;
- reg = MC13783_REG_LED_CONTROL_2;
+ reg = MC13XXX_REG_LED_CONTROL(2);
+ shift = 6;
+ mask = 0x07;
break;
case MC13783_LED_R1:
case MC13783_LED_G1:
@@ -164,229 +161,195 @@ static int mc13783_led_setup(struct mc13783_led *led, int max_current)
case MC13783_LED_R3:
case MC13783_LED_G3:
case MC13783_LED_B3:
- bank = (led->id - MC13783_LED_R1)/3;
- reg = MC13783_REG_LED_CONTROL_3 + bank;
+ bank = (led->id - MC13783_LED_R1) / 3;
+ reg = MC13XXX_REG_LED_CONTROL(3) + bank;
shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2;
- mask = MC13783_LED_Cx_TC_C_MASK;
- value = max_current & MC13783_LED_Cx_TC_C_MASK;
+ mask = 0x03;
+ break;
+ case MC13892_LED_MD:
+ reg = MC13XXX_REG_LED_CONTROL(0);
+ shift = 9;
+ mask = 0x07;
break;
+ case MC13892_LED_AD:
+ reg = MC13XXX_REG_LED_CONTROL(0);
+ shift = 21;
+ mask = 0x07;
+ break;
+ case MC13892_LED_KP:
+ reg = MC13XXX_REG_LED_CONTROL(1);
+ shift = 9;
+ mask = 0x07;
+ break;
+ case MC13892_LED_R:
+ case MC13892_LED_G:
+ case MC13892_LED_B:
+ bank = (led->id - MC13892_LED_R) / 2;
+ reg = MC13XXX_REG_LED_CONTROL(2) + bank;
+ shift = ((led->id - MC13892_LED_R) - bank * 2) * 12 + 9;
+ mask = 0x07;
+ break;
+ default:
+ BUG();
}
mc13xxx_lock(led->master);
-
ret = mc13xxx_reg_rmw(led->master, reg, mask << shift,
- value << shift);
-
+ max_current << shift);
mc13xxx_unlock(led->master);
- return ret;
-}
-
-static int mc13783_leds_prepare(struct platform_device *pdev)
-{
- struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent);
- int ret = 0;
- int reg = 0;
-
- mc13xxx_lock(dev);
-
- if (pdata->flags & MC13783_LED_TC1HALF)
- reg |= MC13783_LED_C1_TC1HALF_BIT;
-
- if (pdata->flags & MC13783_LED_SLEWLIMTC)
- reg |= MC13783_LED_Cx_SLEWLIM_BIT;
-
- ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, reg);
- if (ret)
- goto out;
-
- reg = (pdata->bl_period & MC13783_LED_Cx_PERIOD_MASK) <<
- MC13783_LED_Cx_PERIOD;
-
- if (pdata->flags & MC13783_LED_SLEWLIMBL)
- reg |= MC13783_LED_Cx_SLEWLIM_BIT;
-
- ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, reg);
- if (ret)
- goto out;
-
- reg = (pdata->tc1_period & MC13783_LED_Cx_PERIOD_MASK) <<
- MC13783_LED_Cx_PERIOD;
- if (pdata->flags & MC13783_LED_TRIODE_TC1)
- reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
-
- ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, reg);
- if (ret)
- goto out;
-
- reg = (pdata->tc2_period & MC13783_LED_Cx_PERIOD_MASK) <<
- MC13783_LED_Cx_PERIOD;
-
- if (pdata->flags & MC13783_LED_TRIODE_TC2)
- reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
-
- ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, reg);
- if (ret)
- goto out;
-
- reg = (pdata->tc3_period & MC13783_LED_Cx_PERIOD_MASK) <<
- MC13783_LED_Cx_PERIOD;
-
- if (pdata->flags & MC13783_LED_TRIODE_TC3)
- reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
-
- ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg);
- if (ret)
- goto out;
-
- reg = MC13783_LED_C0_ENABLE_BIT;
- if (pdata->flags & MC13783_LED_TRIODE_MD)
- reg |= MC13783_LED_C0_TRIODE_MD_BIT;
- if (pdata->flags & MC13783_LED_TRIODE_AD)
- reg |= MC13783_LED_C0_TRIODE_AD_BIT;
- if (pdata->flags & MC13783_LED_TRIODE_KP)
- reg |= MC13783_LED_C0_TRIODE_KP_BIT;
- if (pdata->flags & MC13783_LED_BOOST_EN)
- reg |= MC13783_LED_C0_BOOST_BIT;
-
- reg |= (pdata->abmode & MC13783_LED_C0_ABMODE_MASK) <<
- MC13783_LED_C0_ABMODE;
- reg |= (pdata->abref & MC13783_LED_C0_ABREF_MASK) <<
- MC13783_LED_C0_ABREF;
-
- ret = mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, reg);
-
-out:
- mc13xxx_unlock(dev);
return ret;
}
-static int mc13783_led_probe(struct platform_device *pdev)
+static int __init mc13xxx_led_probe(struct platform_device *pdev)
{
struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct mc13xxx_led_platform_data *led_cur;
- struct mc13783_led *led, *led_dat;
- int ret, i;
- int init_led = 0;
-
- if (pdata == NULL) {
- dev_err(&pdev->dev, "missing platform data\n");
+ struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx_led_devtype *devtype =
+ (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data;
+ struct mc13xxx_leds *leds;
+ int i, id, num_leds, ret = -ENODATA;
+ u32 reg, init_led = 0;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "Missing platform data\n");
return -ENODEV;
}
- if (pdata->num_leds < 1 || pdata->num_leds > (MC13783_LED_MAX + 1)) {
- dev_err(&pdev->dev, "Invalid led count %d\n", pdata->num_leds);
+ num_leds = pdata->num_leds;
+
+ if ((num_leds < 1) ||
+ (num_leds > (devtype->led_max - devtype->led_min + 1))) {
+ dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds);
return -EINVAL;
}
- led = devm_kzalloc(&pdev->dev, pdata->num_leds * sizeof(*led),
- GFP_KERNEL);
- if (led == NULL) {
- dev_err(&pdev->dev, "failed to alloc memory\n");
+ leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) +
+ sizeof(struct mc13xxx_leds), GFP_KERNEL);
+ if (!leds)
return -ENOMEM;
+
+ leds->devtype = devtype;
+ leds->num_leds = num_leds;
+ platform_set_drvdata(pdev, leds);
+
+ mc13xxx_lock(mcdev);
+ for (i = 0; i < devtype->num_regs; i++) {
+ reg = pdata->led_control[i];
+ WARN_ON(reg >= (1 << 24));
+ ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
+ if (ret)
+ break;
}
+ mc13xxx_unlock(mcdev);
- ret = mc13783_leds_prepare(pdev);
if (ret) {
- dev_err(&pdev->dev, "unable to init led driver\n");
+ dev_err(&pdev->dev, "Unable to init LED driver\n");
return ret;
}
- for (i = 0; i < pdata->num_leds; i++) {
- led_dat = &led[i];
- led_cur = &pdata->led[i];
+ for (i = 0; i < num_leds; i++) {
+ const char *name, *trig;
+ char max_current;
+
+ ret = -EINVAL;
- if (led_cur->id > MC13783_LED_MAX || led_cur->id < 0) {
- dev_err(&pdev->dev, "invalid id %d\n", led_cur->id);
- ret = -EINVAL;
- goto err_register;
+ id = pdata->led[i].id;
+ name = pdata->led[i].name;
+ trig = pdata->led[i].default_trigger;
+ max_current = pdata->led[i].max_current;
+
+ if ((id > devtype->led_max) || (id < devtype->led_min)) {
+ dev_err(&pdev->dev, "Invalid ID %i\n", id);
+ break;
}
- if (init_led & (1 << led_cur->id)) {
- dev_err(&pdev->dev, "led %d already initialized\n",
- led_cur->id);
- ret = -EINVAL;
- goto err_register;
+ if (init_led & (1 << id)) {
+ dev_warn(&pdev->dev,
+ "LED %i already initialized\n", id);
+ break;
}
- init_led |= 1 << led_cur->id;
- led_dat->cdev.name = led_cur->name;
- led_dat->cdev.default_trigger = led_cur->default_trigger;
- led_dat->cdev.brightness_set = mc13783_led_set;
- led_dat->cdev.brightness = LED_OFF;
- led_dat->id = led_cur->id;
- led_dat->master = dev_get_drvdata(pdev->dev.parent);
+ init_led |= 1 << id;
+ leds->led[i].id = id;
+ leds->led[i].master = mcdev;
+ leds->led[i].cdev.name = name;
+ leds->led[i].cdev.default_trigger = trig;
+ leds->led[i].cdev.brightness_set = mc13xxx_led_set;
+ leds->led[i].cdev.brightness = LED_OFF;
- INIT_WORK(&led_dat->work, mc13783_led_work);
+ INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
- ret = led_classdev_register(pdev->dev.parent, &led_dat->cdev);
+ ret = mc13xxx_led_setup(&leds->led[i], max_current);
if (ret) {
- dev_err(&pdev->dev, "failed to register led %d\n",
- led_dat->id);
- goto err_register;
+ dev_err(&pdev->dev, "Unable to setup LED %i\n", id);
+ break;
}
-
- ret = mc13783_led_setup(led_dat, led_cur->max_current);
+ ret = led_classdev_register(pdev->dev.parent,
+ &leds->led[i].cdev);
if (ret) {
- dev_err(&pdev->dev, "unable to init led %d\n",
- led_dat->id);
- i++;
- goto err_register;
+ dev_err(&pdev->dev, "Failed to register LED %i\n", id);
+ break;
}
}
- platform_set_drvdata(pdev, led);
- return 0;
-
-err_register:
- for (i = i - 1; i >= 0; i--) {
- led_classdev_unregister(&led[i].cdev);
- cancel_work_sync(&led[i].work);
- }
+ if (ret)
+ while (--i >= 0) {
+ led_classdev_unregister(&leds->led[i].cdev);
+ cancel_work_sync(&leds->led[i].work);
+ }
return ret;
}
-static int mc13783_led_remove(struct platform_device *pdev)
+static int mc13xxx_led_remove(struct platform_device *pdev)
{
- struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct mc13783_led *led = platform_get_drvdata(pdev);
- struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
+ struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < pdata->num_leds; i++) {
- led_classdev_unregister(&led[i].cdev);
- cancel_work_sync(&led[i].work);
+ for (i = 0; i < leds->num_leds; i++) {
+ led_classdev_unregister(&leds->led[i].cdev);
+ cancel_work_sync(&leds->led[i].work);
}
- mc13xxx_lock(dev);
-
- mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_0, 0);
- mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_1, 0);
- mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_2, 0);
- mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_3, 0);
- mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_4, 0);
- mc13xxx_reg_write(dev, MC13783_REG_LED_CONTROL_5, 0);
-
- mc13xxx_unlock(dev);
+ mc13xxx_lock(mcdev);
+ for (i = 0; i < leds->devtype->num_regs; i++)
+ mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
+ mc13xxx_unlock(mcdev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
-static struct platform_driver mc13783_led_driver = {
+static const struct mc13xxx_led_devtype mc13783_led_devtype = {
+ .led_min = MC13783_LED_MD,
+ .led_max = MC13783_LED_B3,
+ .num_regs = 6,
+};
+
+static const struct mc13xxx_led_devtype mc13892_led_devtype = {
+ .led_min = MC13892_LED_MD,
+ .led_max = MC13892_LED_B,
+ .num_regs = 4,
+};
+
+static const struct platform_device_id mc13xxx_led_id_table[] = {
+ { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, },
+ { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table);
+
+static struct platform_driver mc13xxx_led_driver = {
.driver = {
- .name = "mc13783-led",
+ .name = "mc13xxx-led",
.owner = THIS_MODULE,
},
- .probe = mc13783_led_probe,
- .remove = mc13783_led_remove,
+ .remove = mc13xxx_led_remove,
+ .id_table = mc13xxx_led_id_table,
};
+module_platform_driver_probe(mc13xxx_led_driver, mc13xxx_led_probe);
-module_platform_driver(mc13783_led_driver);
-
-MODULE_DESCRIPTION("LEDs driver for Freescale MC13783 PMIC");
+MODULE_DESCRIPTION("LEDs driver for Freescale MC13XXX PMIC");
MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mc13783-led");
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index 70137b1eecf5..e7df9875c400 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -374,8 +374,6 @@ static int ns2_led_remove(struct platform_device *pdev)
for (i = 0; i < priv->num_leds; i++)
delete_ns2_led(&priv->leds_data[i]);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c
index 9483f1c1078d..adebf4931e1e 100644
--- a/drivers/leds/leds-renesas-tpu.c
+++ b/drivers/leds/leds-renesas-tpu.c
@@ -63,7 +63,7 @@ static DEFINE_SPINLOCK(r_tpu_lock);
#define TGRC 8 /* Timer general register C (+0x20) */
#define TGRD 9 /* Timer general register D (+0x24) */
-static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
+static inline u16 r_tpu_read(struct r_tpu_priv *p, int reg_nr)
{
struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
void __iomem *base = p->mapbase;
@@ -75,8 +75,7 @@ static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
return ioread16(base + offs);
}
-static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
- unsigned short value)
+static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr, u16 value)
{
struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
void __iomem *base = p->mapbase;
@@ -93,7 +92,8 @@ static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
{
struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
- unsigned long flags, value;
+ unsigned long flags;
+ u16 value;
/* start stop register shared by multiple timer channels */
spin_lock_irqsave(&r_tpu_lock, flags);
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
index 89792990088d..388632d23d44 100644
--- a/drivers/leds/leds-sunfire.c
+++ b/drivers/leds/leds-sunfire.c
@@ -159,14 +159,14 @@ static int sunfire_led_generic_probe(struct platform_device *pdev,
}
}
- dev_set_drvdata(&pdev->dev, p);
+ platform_set_drvdata(pdev, p);
return 0;
}
static int sunfire_led_generic_remove(struct platform_device *pdev)
{
- struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
+ struct sunfire_drvdata *p = platform_get_drvdata(pdev);
int i;
for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index 6bd5c679d877..120815a42701 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -241,7 +241,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
- dev_set_drvdata(&pdev->dev, drvdata);
+ platform_set_drvdata(pdev, drvdata);
drvdata->wm831x = wm831x;
drvdata->reg = res->start;
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index 5b9ac32801c7..a35d8d100165 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -70,7 +70,7 @@
/*H:320
* The page table code is curly enough to need helper functions to keep it
* clear and clean. The kernel itself provides many of them; one advantage
- * of insisting that the Guest and Host use the same CONFIG_PAE setting.
+ * of insisting that the Guest and Host use the same CONFIG_X86_PAE setting.
*
* There are two functions which return pointers to the shadow (aka "real")
* page tables.
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index b026896206ca..04a50498f257 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -697,7 +697,7 @@ static ssize_t adb_read(struct file *file, char __user *buf,
int ret = 0;
struct adbdev_state *state = file->private_data;
struct adb_request *req;
- wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait,current);
+ DECLARE_WAITQUEUE(wait,current);
unsigned long flags;
if (count < 2)
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 6a82388505f0..80d30e8e3389 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -181,7 +181,7 @@ static void mac_hid_stop_emulation(void)
mac_hid_destroy_emumouse();
}
-static int mac_hid_toggle_emumouse(ctl_table *table, int write,
+static int mac_hid_toggle_emumouse(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
@@ -214,7 +214,7 @@ static int mac_hid_toggle_emumouse(ctl_table *table, int write,
}
/* file(s) in /proc/sys/dev/mac_hid */
-static ctl_table mac_hid_files[] = {
+static struct ctl_table mac_hid_files[] = {
{
.procname = "mouse_button_emulation",
.data = &mouse_emulate_buttons,
@@ -240,7 +240,7 @@ static ctl_table mac_hid_files[] = {
};
/* dir in /proc/sys/dev */
-static ctl_table mac_hid_dir[] = {
+static struct ctl_table mac_hid_dir[] = {
{
.procname = "mac_hid",
.maxlen = 0,
@@ -251,7 +251,7 @@ static ctl_table mac_hid_dir[] = {
};
/* /proc/sys/dev itself, in case that is not there yet */
-static ctl_table mac_hid_root_dir[] = {
+static struct ctl_table mac_hid_root_dir[] = {
{
.procname = "dev",
.maxlen = 0,
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 86511c570dd8..d61f271d2207 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -259,7 +259,7 @@ cuda_probe(void)
} while (0)
static int
-cuda_init_via(void)
+__init cuda_init_via(void)
{
out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */
out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */
diff --git a/drivers/macintosh/windfarm_pm121.c b/drivers/macintosh/windfarm_pm121.c
index af605e915d41..7fe58b0ae8b4 100644
--- a/drivers/macintosh/windfarm_pm121.c
+++ b/drivers/macintosh/windfarm_pm121.c
@@ -276,6 +276,7 @@ static const char *loop_names[N_LOOPS] = {
static unsigned int pm121_failure_state;
static int pm121_readjust, pm121_skipping;
+static bool pm121_overtemp;
static s32 average_power;
struct pm121_correction {
@@ -847,6 +848,7 @@ static void pm121_tick(void)
if (new_failure & FAILURE_OVERTEMP) {
wf_set_overtemp();
pm121_skipping = 2;
+ pm121_overtemp = true;
}
/* We only clear the overtemp condition if overtemp is cleared
@@ -855,8 +857,10 @@ static void pm121_tick(void)
* the control loop levels, but we don't want to keep it clear
* here in this case
*/
- if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+ if (!pm121_failure_state && pm121_overtemp) {
wf_clear_overtemp();
+ pm121_overtemp = false;
+ }
}
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index f84933ff3298..2a5e1b15b1d2 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -149,6 +149,7 @@ static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started;
static unsigned int wf_smu_failure_state;
static int wf_smu_readjust, wf_smu_skipping;
+static bool wf_smu_overtemp;
/*
* ****** System Fans Control Loop ******
@@ -593,6 +594,7 @@ static void wf_smu_tick(void)
if (new_failure & FAILURE_OVERTEMP) {
wf_set_overtemp();
wf_smu_skipping = 2;
+ wf_smu_overtemp = true;
}
/* We only clear the overtemp condition if overtemp is cleared
@@ -601,8 +603,10 @@ static void wf_smu_tick(void)
* the control loop levels, but we don't want to keep it clear
* here in this case
*/
- if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+ if (!wf_smu_failure_state && wf_smu_overtemp) {
wf_clear_overtemp();
+ wf_smu_overtemp = false;
+ }
}
static void wf_smu_new_control(struct wf_control *ct)
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 2eb484f213c8..a8ac66cd3b13 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -76,6 +76,7 @@ static struct wf_control *cpufreq_clamp;
/* Set to kick the control loop into life */
static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started;
+static bool wf_smu_overtemp;
/* Failure handling.. could be nicer */
#define FAILURE_FAN 0x01
@@ -517,6 +518,7 @@ static void wf_smu_tick(void)
if (new_failure & FAILURE_OVERTEMP) {
wf_set_overtemp();
wf_smu_skipping = 2;
+ wf_smu_overtemp = true;
}
/* We only clear the overtemp condition if overtemp is cleared
@@ -525,8 +527,10 @@ static void wf_smu_tick(void)
* the control loop levels, but we don't want to keep it clear
* here in this case
*/
- if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
+ if (!wf_smu_failure_state && wf_smu_overtemp) {
wf_clear_overtemp();
+ wf_smu_overtemp = false;
+ }
}
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index d87f5ee04ca9..ad6223e88340 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -343,7 +343,6 @@ static int wf_sat_remove(struct i2c_client *client)
wf_unregister_sensor(&sens->sens);
}
sat->i2c = NULL;
- i2c_set_clientdata(client, NULL);
kref_put(&sat->ref, wf_sat_release);
return 0;
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 3bfc8f1da9fe..30b426ed744b 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -412,4 +412,18 @@ config DM_VERITY
If unsure, say N.
+config DM_SWITCH
+ tristate "Switch target support (EXPERIMENTAL)"
+ depends on BLK_DEV_DM
+ ---help---
+ This device-mapper target creates a device that supports an arbitrary
+ mapping of fixed-size regions of I/O across a fixed set of paths.
+ The path used for any specific region can be switched dynamically
+ by sending the target a message.
+
+ To compile this code as a module, choose M here: the module will
+ be called dm-switch.
+
+ If unsure, say N.
+
endif # MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 1439fd4ad9b1..5ef78efc27f2 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_MULTIPATH_QL) += dm-queue-length.o
obj-$(CONFIG_DM_MULTIPATH_ST) += dm-service-time.o
+obj-$(CONFIG_DM_SWITCH) += dm-switch.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
obj-$(CONFIG_DM_PERSISTENT_DATA) += persistent-data/
obj-$(CONFIG_DM_MIRROR) += dm-mirror.o dm-log.o dm-region-hash.o
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index cb4578a327b9..1d27d3af3251 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -395,7 +395,7 @@ void inorder_test(void)
#endif
/*
- * Cacheline/offset <-> bkey pointer arithmatic:
+ * Cacheline/offset <-> bkey pointer arithmetic:
*
* t->tree is a binary search tree in an array; each node corresponds to a key
* in one cacheline in t->set (BSET_CACHELINE bytes).
@@ -404,7 +404,7 @@ void inorder_test(void)
* the binary tree points to; to_inorder() gives us the cacheline, and then
* bkey_float->m gives us the offset within that cacheline, in units of 8 bytes.
*
- * cacheline_to_bkey() and friends abstract out all the pointer arithmatic to
+ * cacheline_to_bkey() and friends abstract out all the pointer arithmetic to
* make this work.
*
* To construct the bfloat for an arbitrary key we need to know what the key
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 5a2c75499824..a7fd82133b12 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -2002,9 +2002,9 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
} else {
int rv;
if (buf[0] == '+')
- rv = strict_strtoll(buf+1, 10, &offset);
+ rv = kstrtoll(buf+1, 10, &offset);
else
- rv = strict_strtoll(buf, 10, &offset);
+ rv = kstrtoll(buf, 10, &offset);
if (rv)
return rv;
if (offset == 0)
@@ -2139,7 +2139,7 @@ static ssize_t
backlog_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long backlog;
- int rv = strict_strtoul(buf, 10, &backlog);
+ int rv = kstrtoul(buf, 10, &backlog);
if (rv)
return rv;
if (backlog > COUNTER_MAX)
@@ -2165,7 +2165,7 @@ chunksize_store(struct mddev *mddev, const char *buf, size_t len)
unsigned long csize;
if (mddev->bitmap)
return -EBUSY;
- rv = strict_strtoul(buf, 10, &csize);
+ rv = kstrtoul(buf, 10, &csize);
if (rv)
return rv;
if (csize < 512 ||
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 0387e05cdb98..5227e079a6e3 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -145,6 +145,7 @@ struct dm_buffer {
unsigned long state;
unsigned long last_accessed;
struct dm_bufio_client *c;
+ struct list_head write_list;
struct bio bio;
struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS];
};
@@ -349,7 +350,7 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
if (gfp_mask & __GFP_NORETRY)
noio_flag = memalloc_noio_save();
- ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
+ ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL);
if (gfp_mask & __GFP_NORETRY)
memalloc_noio_restore(noio_flag);
@@ -630,7 +631,8 @@ static int do_io_schedule(void *word)
* - Submit our write and don't wait on it. We set B_WRITING indicating
* that there is a write in progress.
*/
-static void __write_dirty_buffer(struct dm_buffer *b)
+static void __write_dirty_buffer(struct dm_buffer *b,
+ struct list_head *write_list)
{
if (!test_bit(B_DIRTY, &b->state))
return;
@@ -639,7 +641,24 @@ static void __write_dirty_buffer(struct dm_buffer *b)
wait_on_bit_lock(&b->state, B_WRITING,
do_io_schedule, TASK_UNINTERRUPTIBLE);
- submit_io(b, WRITE, b->block, write_endio);
+ if (!write_list)
+ submit_io(b, WRITE, b->block, write_endio);
+ else
+ list_add_tail(&b->write_list, write_list);
+}
+
+static void __flush_write_list(struct list_head *write_list)
+{
+ struct blk_plug plug;
+ blk_start_plug(&plug);
+ while (!list_empty(write_list)) {
+ struct dm_buffer *b =
+ list_entry(write_list->next, struct dm_buffer, write_list);
+ list_del(&b->write_list);
+ submit_io(b, WRITE, b->block, write_endio);
+ dm_bufio_cond_resched();
+ }
+ blk_finish_plug(&plug);
}
/*
@@ -655,7 +674,7 @@ static void __make_buffer_clean(struct dm_buffer *b)
return;
wait_on_bit(&b->state, B_READING, do_io_schedule, TASK_UNINTERRUPTIBLE);
- __write_dirty_buffer(b);
+ __write_dirty_buffer(b, NULL);
wait_on_bit(&b->state, B_WRITING, do_io_schedule, TASK_UNINTERRUPTIBLE);
}
@@ -802,7 +821,8 @@ static void __free_buffer_wake(struct dm_buffer *b)
wake_up(&c->free_buffer_wait);
}
-static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait)
+static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait,
+ struct list_head *write_list)
{
struct dm_buffer *b, *tmp;
@@ -818,7 +838,7 @@ static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait)
if (no_wait && test_bit(B_WRITING, &b->state))
return;
- __write_dirty_buffer(b);
+ __write_dirty_buffer(b, write_list);
dm_bufio_cond_resched();
}
}
@@ -853,7 +873,8 @@ static void __get_memory_limit(struct dm_bufio_client *c,
* If we are over threshold_buffers, start freeing buffers.
* If we're over "limit_buffers", block until we get under the limit.
*/
-static void __check_watermark(struct dm_bufio_client *c)
+static void __check_watermark(struct dm_bufio_client *c,
+ struct list_head *write_list)
{
unsigned long threshold_buffers, limit_buffers;
@@ -872,7 +893,7 @@ static void __check_watermark(struct dm_bufio_client *c)
}
if (c->n_buffers[LIST_DIRTY] > threshold_buffers)
- __write_dirty_buffers_async(c, 1);
+ __write_dirty_buffers_async(c, 1, write_list);
}
/*
@@ -897,7 +918,8 @@ static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
*--------------------------------------------------------------*/
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
- enum new_flag nf, int *need_submit)
+ enum new_flag nf, int *need_submit,
+ struct list_head *write_list)
{
struct dm_buffer *b, *new_b = NULL;
@@ -924,7 +946,7 @@ static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
goto found_buffer;
}
- __check_watermark(c);
+ __check_watermark(c, write_list);
b = new_b;
b->hold_count = 1;
@@ -992,10 +1014,14 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
int need_submit;
struct dm_buffer *b;
+ LIST_HEAD(write_list);
+
dm_bufio_lock(c);
- b = __bufio_new(c, block, nf, &need_submit);
+ b = __bufio_new(c, block, nf, &need_submit, &write_list);
dm_bufio_unlock(c);
+ __flush_write_list(&write_list);
+
if (!b)
return b;
@@ -1047,6 +1073,8 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
{
struct blk_plug plug;
+ LIST_HEAD(write_list);
+
BUG_ON(dm_bufio_in_request());
blk_start_plug(&plug);
@@ -1055,7 +1083,15 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
for (; n_blocks--; block++) {
int need_submit;
struct dm_buffer *b;
- b = __bufio_new(c, block, NF_PREFETCH, &need_submit);
+ b = __bufio_new(c, block, NF_PREFETCH, &need_submit,
+ &write_list);
+ if (unlikely(!list_empty(&write_list))) {
+ dm_bufio_unlock(c);
+ blk_finish_plug(&plug);
+ __flush_write_list(&write_list);
+ blk_start_plug(&plug);
+ dm_bufio_lock(c);
+ }
if (unlikely(b != NULL)) {
dm_bufio_unlock(c);
@@ -1069,7 +1105,6 @@ void dm_bufio_prefetch(struct dm_bufio_client *c,
goto flush_plug;
dm_bufio_lock(c);
}
-
}
dm_bufio_unlock(c);
@@ -1126,11 +1161,14 @@ EXPORT_SYMBOL_GPL(dm_bufio_mark_buffer_dirty);
void dm_bufio_write_dirty_buffers_async(struct dm_bufio_client *c)
{
+ LIST_HEAD(write_list);
+
BUG_ON(dm_bufio_in_request());
dm_bufio_lock(c);
- __write_dirty_buffers_async(c, 0);
+ __write_dirty_buffers_async(c, 0, &write_list);
dm_bufio_unlock(c);
+ __flush_write_list(&write_list);
}
EXPORT_SYMBOL_GPL(dm_bufio_write_dirty_buffers_async);
@@ -1147,8 +1185,13 @@ int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c)
unsigned long buffers_processed = 0;
struct dm_buffer *b, *tmp;
+ LIST_HEAD(write_list);
+
+ dm_bufio_lock(c);
+ __write_dirty_buffers_async(c, 0, &write_list);
+ dm_bufio_unlock(c);
+ __flush_write_list(&write_list);
dm_bufio_lock(c);
- __write_dirty_buffers_async(c, 0);
again:
list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_DIRTY], lru_list) {
@@ -1274,7 +1317,7 @@ retry:
BUG_ON(!b->hold_count);
BUG_ON(test_bit(B_READING, &b->state));
- __write_dirty_buffer(b);
+ __write_dirty_buffer(b, NULL);
if (b->hold_count == 1) {
wait_on_bit(&b->state, B_WRITING,
do_io_schedule, TASK_UNINTERRUPTIBLE);
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index df44b60e66f2..0df3ec085ebb 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -425,6 +425,10 @@ static bool block_size_is_power_of_two(struct cache *cache)
return cache->sectors_per_block_shift >= 0;
}
+/* gcc on ARM generates spurious references to __udivdi3 and __umoddi3 */
+#if defined(CONFIG_ARM) && __GNUC__ == 4 && __GNUC_MINOR__ <= 6
+__always_inline
+#endif
static dm_block_t block_div(dm_block_t b, uint32_t n)
{
do_div(b, n);
diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c
index 7fcf21cb4ff8..c80a0ec5f126 100644
--- a/drivers/md/dm-flakey.c
+++ b/drivers/md/dm-flakey.c
@@ -176,7 +176,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv)
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (!fc) {
- ti->error = "Cannot allocate linear context";
+ ti->error = "Cannot allocate context";
return -ENOMEM;
}
fc->start_time = jiffies;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index aa04f0224642..f1b758675ec7 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -36,6 +36,14 @@ struct hash_cell {
struct dm_table *new_map;
};
+/*
+ * A dummy definition to make RCU happy.
+ * struct dm_table should never be dereferenced in this file.
+ */
+struct dm_table {
+ int undefined__;
+};
+
struct vers_iter {
size_t param_size;
struct dm_target_versions *vers, *old_vers;
@@ -242,9 +250,10 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
return -EBUSY;
}
-static void __hash_remove(struct hash_cell *hc)
+static struct dm_table *__hash_remove(struct hash_cell *hc)
{
struct dm_table *table;
+ int srcu_idx;
/* remove from the dev hash */
list_del(&hc->uuid_list);
@@ -253,16 +262,18 @@ static void __hash_remove(struct hash_cell *hc)
dm_set_mdptr(hc->md, NULL);
mutex_unlock(&dm_hash_cells_mutex);
- table = dm_get_live_table(hc->md);
- if (table) {
+ table = dm_get_live_table(hc->md, &srcu_idx);
+ if (table)
dm_table_event(table);
- dm_table_put(table);
- }
+ dm_put_live_table(hc->md, srcu_idx);
+ table = NULL;
if (hc->new_map)
- dm_table_destroy(hc->new_map);
+ table = hc->new_map;
dm_put(hc->md);
free_cell(hc);
+
+ return table;
}
static void dm_hash_remove_all(int keep_open_devices)
@@ -270,6 +281,7 @@ static void dm_hash_remove_all(int keep_open_devices)
int i, dev_skipped;
struct hash_cell *hc;
struct mapped_device *md;
+ struct dm_table *t;
retry:
dev_skipped = 0;
@@ -287,10 +299,14 @@ retry:
continue;
}
- __hash_remove(hc);
+ t = __hash_remove(hc);
up_write(&_hash_lock);
+ if (t) {
+ dm_sync_table(md);
+ dm_table_destroy(t);
+ }
dm_put(md);
if (likely(keep_open_devices))
dm_destroy(md);
@@ -356,6 +372,7 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
struct dm_table *table;
struct mapped_device *md;
unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
+ int srcu_idx;
/*
* duplicate new.
@@ -418,11 +435,10 @@ static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
/*
* Wake up any dm event waiters.
*/
- table = dm_get_live_table(hc->md);
- if (table) {
+ table = dm_get_live_table(hc->md, &srcu_idx);
+ if (table)
dm_table_event(table);
- dm_table_put(table);
- }
+ dm_put_live_table(hc->md, srcu_idx);
if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
param->flags |= DM_UEVENT_GENERATED_FLAG;
@@ -620,11 +636,14 @@ static int check_name(const char *name)
* _hash_lock without first calling dm_table_put, because dm_table_destroy
* waits for this dm_table_put and could be called under this lock.
*/
-static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
+static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx)
{
struct hash_cell *hc;
struct dm_table *table = NULL;
+ /* increment rcu count, we don't care about the table pointer */
+ dm_get_live_table(md, srcu_idx);
+
down_read(&_hash_lock);
hc = dm_get_mdptr(md);
if (!hc || hc->md != md) {
@@ -633,8 +652,6 @@ static struct dm_table *dm_get_inactive_table(struct mapped_device *md)
}
table = hc->new_map;
- if (table)
- dm_table_get(table);
out:
up_read(&_hash_lock);
@@ -643,10 +660,11 @@ out:
}
static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
- struct dm_ioctl *param)
+ struct dm_ioctl *param,
+ int *srcu_idx)
{
return (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) ?
- dm_get_inactive_table(md) : dm_get_live_table(md);
+ dm_get_inactive_table(md, srcu_idx) : dm_get_live_table(md, srcu_idx);
}
/*
@@ -657,6 +675,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
{
struct gendisk *disk = dm_disk(md);
struct dm_table *table;
+ int srcu_idx;
param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
DM_ACTIVE_PRESENT_FLAG);
@@ -676,26 +695,27 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
param->event_nr = dm_get_event_nr(md);
param->target_count = 0;
- table = dm_get_live_table(md);
+ table = dm_get_live_table(md, &srcu_idx);
if (table) {
if (!(param->flags & DM_QUERY_INACTIVE_TABLE_FLAG)) {
if (get_disk_ro(disk))
param->flags |= DM_READONLY_FLAG;
param->target_count = dm_table_get_num_targets(table);
}
- dm_table_put(table);
param->flags |= DM_ACTIVE_PRESENT_FLAG;
}
+ dm_put_live_table(md, srcu_idx);
if (param->flags & DM_QUERY_INACTIVE_TABLE_FLAG) {
- table = dm_get_inactive_table(md);
+ int srcu_idx;
+ table = dm_get_inactive_table(md, &srcu_idx);
if (table) {
if (!(dm_table_get_mode(table) & FMODE_WRITE))
param->flags |= DM_READONLY_FLAG;
param->target_count = dm_table_get_num_targets(table);
- dm_table_put(table);
}
+ dm_put_live_table(md, srcu_idx);
}
}
@@ -796,6 +816,7 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
struct hash_cell *hc;
struct mapped_device *md;
int r;
+ struct dm_table *t;
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
@@ -819,9 +840,14 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
return r;
}
- __hash_remove(hc);
+ t = __hash_remove(hc);
up_write(&_hash_lock);
+ if (t) {
+ dm_sync_table(md);
+ dm_table_destroy(t);
+ }
+
if (!dm_kobject_uevent(md, KOBJ_REMOVE, param->event_nr))
param->flags |= DM_UEVENT_GENERATED_FLAG;
@@ -986,6 +1012,7 @@ static int do_resume(struct dm_ioctl *param)
old_map = dm_swap_table(md, new_map);
if (IS_ERR(old_map)) {
+ dm_sync_table(md);
dm_table_destroy(new_map);
dm_put(md);
return PTR_ERR(old_map);
@@ -1003,6 +1030,10 @@ static int do_resume(struct dm_ioctl *param)
param->flags |= DM_UEVENT_GENERATED_FLAG;
}
+ /*
+ * Since dm_swap_table synchronizes RCU, nobody should be in
+ * read-side critical section already.
+ */
if (old_map)
dm_table_destroy(old_map);
@@ -1125,6 +1156,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
int r = 0;
struct mapped_device *md;
struct dm_table *table;
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1145,11 +1177,10 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
*/
__dev_status(md, param);
- table = dm_get_live_or_inactive_table(md, param);
- if (table) {
+ table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+ if (table)
retrieve_status(table, param, param_size);
- dm_table_put(table);
- }
+ dm_put_live_table(md, srcu_idx);
out:
dm_put(md);
@@ -1221,7 +1252,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
{
int r;
struct hash_cell *hc;
- struct dm_table *t;
+ struct dm_table *t, *old_map = NULL;
struct mapped_device *md;
struct target_type *immutable_target_type;
@@ -1277,14 +1308,14 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
hc = dm_get_mdptr(md);
if (!hc || hc->md != md) {
DMWARN("device has been removed from the dev hash table.");
- dm_table_destroy(t);
up_write(&_hash_lock);
+ dm_table_destroy(t);
r = -ENXIO;
goto out;
}
if (hc->new_map)
- dm_table_destroy(hc->new_map);
+ old_map = hc->new_map;
hc->new_map = t;
up_write(&_hash_lock);
@@ -1292,6 +1323,11 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
__dev_status(md, param);
out:
+ if (old_map) {
+ dm_sync_table(md);
+ dm_table_destroy(old_map);
+ }
+
dm_put(md);
return r;
@@ -1301,6 +1337,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
{
struct hash_cell *hc;
struct mapped_device *md;
+ struct dm_table *old_map = NULL;
down_write(&_hash_lock);
@@ -1312,7 +1349,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
}
if (hc->new_map) {
- dm_table_destroy(hc->new_map);
+ old_map = hc->new_map;
hc->new_map = NULL;
}
@@ -1321,6 +1358,10 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
__dev_status(hc->md, param);
md = hc->md;
up_write(&_hash_lock);
+ if (old_map) {
+ dm_sync_table(md);
+ dm_table_destroy(old_map);
+ }
dm_put(md);
return 0;
@@ -1370,6 +1411,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;
struct dm_table *table;
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1377,11 +1419,10 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
__dev_status(md, param);
- table = dm_get_live_or_inactive_table(md, param);
- if (table) {
+ table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+ if (table)
retrieve_deps(table, param, param_size);
- dm_table_put(table);
- }
+ dm_put_live_table(md, srcu_idx);
dm_put(md);
@@ -1396,6 +1437,7 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
{
struct mapped_device *md;
struct dm_table *table;
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1403,11 +1445,10 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
__dev_status(md, param);
- table = dm_get_live_or_inactive_table(md, param);
- if (table) {
+ table = dm_get_live_or_inactive_table(md, param, &srcu_idx);
+ if (table)
retrieve_status(table, param, param_size);
- dm_table_put(table);
- }
+ dm_put_live_table(md, srcu_idx);
dm_put(md);
@@ -1443,6 +1484,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
struct dm_target_msg *tmsg = (void *) param + param->data_start;
size_t maxlen;
char *result = get_result_buffer(param, param_size, &maxlen);
+ int srcu_idx;
md = find_device(param);
if (!md)
@@ -1470,9 +1512,9 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
if (r <= 1)
goto out_argv;
- table = dm_get_live_table(md);
+ table = dm_get_live_table(md, &srcu_idx);
if (!table)
- goto out_argv;
+ goto out_table;
if (dm_deleting_md(md)) {
r = -ENXIO;
@@ -1491,7 +1533,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
}
out_table:
- dm_table_put(table);
+ dm_put_live_table(md, srcu_idx);
out_argv:
kfree(argv);
out:
@@ -1644,7 +1686,10 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
}
if (!dmi) {
- dmi = __vmalloc(param_kernel->data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
+ unsigned noio_flag;
+ noio_flag = memalloc_noio_save();
+ dmi = __vmalloc(param_kernel->data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH | __GFP_HIGHMEM, PAGE_KERNEL);
+ memalloc_noio_restore(noio_flag);
if (dmi)
*param_flags |= DM_PARAMS_VMALLOC;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index bdf26f5bd326..5adede17ddf6 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1561,7 +1561,6 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd,
unsigned long flags;
int r;
-again:
bdev = NULL;
mode = 0;
r = 0;
@@ -1579,7 +1578,7 @@ again:
}
if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
- r = -EAGAIN;
+ r = -ENOTCONN;
else if (!bdev)
r = -EIO;
@@ -1591,11 +1590,8 @@ again:
if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
r = scsi_verify_blk_ioctl(NULL, cmd);
- if (r == -EAGAIN && !fatal_signal_pending(current)) {
+ if (r == -ENOTCONN && !fatal_signal_pending(current))
queue_work(kmultipathd, &m->process_queued_ios);
- msleep(10);
- goto again;
- }
return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
}
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 1d3fe1a40a9b..4880b69e2e9e 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -380,7 +380,7 @@ static int validate_region_size(struct raid_set *rs, unsigned long region_size)
static int validate_raid_redundancy(struct raid_set *rs)
{
unsigned i, rebuild_cnt = 0;
- unsigned rebuilds_per_group, copies, d;
+ unsigned rebuilds_per_group = 0, copies, d;
unsigned group_size, last_group_start;
for (i = 0; i < rs->md.raid_disks; i++)
@@ -504,7 +504,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
* First, parse the in-order required arguments
* "chunk_size" is the only argument of this type.
*/
- if ((strict_strtoul(argv[0], 10, &value) < 0)) {
+ if ((kstrtoul(argv[0], 10, &value) < 0)) {
rs->ti->error = "Bad chunk size";
return -EINVAL;
} else if (rs->raid_type->level == 1) {
@@ -585,7 +585,7 @@ static int parse_raid_params(struct raid_set *rs, char **argv,
continue;
}
- if (strict_strtoul(argv[i], 10, &value) < 0) {
+ if (kstrtoul(argv[i], 10, &value) < 0) {
rs->ti->error = "Bad numerical argument given in raid params";
return -EINVAL;
}
@@ -1181,7 +1181,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
argv++;
/* number of RAID parameters */
- if (strict_strtoul(argv[0], 10, &num_raid_params) < 0) {
+ if (kstrtoul(argv[0], 10, &num_raid_params) < 0) {
ti->error = "Cannot understand number of RAID parameters";
return -EINVAL;
}
@@ -1194,7 +1194,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
return -EINVAL;
}
- if ((strict_strtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
+ if ((kstrtoul(argv[num_raid_params], 10, &num_raid_devs) < 0) ||
(num_raid_devs >= INT_MAX)) {
ti->error = "Cannot understand number of raid devices";
return -EINVAL;
@@ -1388,6 +1388,7 @@ static void raid_status(struct dm_target *ti, status_type_t type,
* performing a "check" of the array.
*/
DMEMIT(" %llu",
+ (strcmp(rs->md.last_sync_action, "check")) ? 0 :
(unsigned long long)
atomic64_read(&rs->md.resync_mismatches));
break;
@@ -1572,6 +1573,62 @@ static void raid_postsuspend(struct dm_target *ti)
mddev_suspend(&rs->md);
}
+static void attempt_restore_of_faulty_devices(struct raid_set *rs)
+{
+ int i;
+ uint64_t failed_devices, cleared_failed_devices = 0;
+ unsigned long flags;
+ struct dm_raid_superblock *sb;
+ struct md_rdev *r;
+
+ for (i = 0; i < rs->md.raid_disks; i++) {
+ r = &rs->dev[i].rdev;
+ if (test_bit(Faulty, &r->flags) && r->sb_page &&
+ sync_page_io(r, 0, r->sb_size, r->sb_page, READ, 1)) {
+ DMINFO("Faulty %s device #%d has readable super block."
+ " Attempting to revive it.",
+ rs->raid_type->name, i);
+
+ /*
+ * Faulty bit may be set, but sometimes the array can
+ * be suspended before the personalities can respond
+ * by removing the device from the array (i.e. calling
+ * 'hot_remove_disk'). If they haven't yet removed
+ * the failed device, its 'raid_disk' number will be
+ * '>= 0' - meaning we must call this function
+ * ourselves.
+ */
+ if ((r->raid_disk >= 0) &&
+ (r->mddev->pers->hot_remove_disk(r->mddev, r) != 0))
+ /* Failed to revive this device, try next */
+ continue;
+
+ r->raid_disk = i;
+ r->saved_raid_disk = i;
+ flags = r->flags;
+ clear_bit(Faulty, &r->flags);
+ clear_bit(WriteErrorSeen, &r->flags);
+ clear_bit(In_sync, &r->flags);
+ if (r->mddev->pers->hot_add_disk(r->mddev, r)) {
+ r->raid_disk = -1;
+ r->saved_raid_disk = -1;
+ r->flags = flags;
+ } else {
+ r->recovery_offset = 0;
+ cleared_failed_devices |= 1 << i;
+ }
+ }
+ }
+ if (cleared_failed_devices) {
+ rdev_for_each(r, &rs->md) {
+ sb = page_address(r->sb_page);
+ failed_devices = le64_to_cpu(sb->failed_devices);
+ failed_devices &= ~cleared_failed_devices;
+ sb->failed_devices = cpu_to_le64(failed_devices);
+ }
+ }
+}
+
static void raid_resume(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
@@ -1580,6 +1637,13 @@ static void raid_resume(struct dm_target *ti)
if (!rs->bitmap_loaded) {
bitmap_load(&rs->md);
rs->bitmap_loaded = 1;
+ } else {
+ /*
+ * A secondary resume while the device is active.
+ * Take this opportunity to check whether any failed
+ * devices are reachable again.
+ */
+ attempt_restore_of_faulty_devices(rs);
}
clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
@@ -1588,7 +1652,7 @@ static void raid_resume(struct dm_target *ti)
static struct target_type raid_target = {
.name = "raid",
- .version = {1, 5, 0},
+ .version = {1, 5, 2},
.module = THIS_MODULE,
.ctr = raid_ctr,
.dtr = raid_dtr,
diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c
new file mode 100644
index 000000000000..ff9ac4be4721
--- /dev/null
+++ b/drivers/md/dm-switch.c
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2010-2012 by Dell Inc. All rights reserved.
+ * Copyright (C) 2011-2013 Red Hat, Inc.
+ *
+ * This file is released under the GPL.
+ *
+ * dm-switch is a device-mapper target that maps IO to underlying block
+ * devices efficiently when there are a large number of fixed-sized
+ * address regions but there is no simple pattern to allow for a compact
+ * mapping representation such as dm-stripe.
+ */
+
+#include <linux/device-mapper.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#define DM_MSG_PREFIX "switch"
+
+/*
+ * One region_table_slot_t holds <region_entries_per_slot> region table
+ * entries each of which is <region_table_entry_bits> in size.
+ */
+typedef unsigned long region_table_slot_t;
+
+/*
+ * A device with the offset to its start sector.
+ */
+struct switch_path {
+ struct dm_dev *dmdev;
+ sector_t start;
+};
+
+/*
+ * Context block for a dm switch device.
+ */
+struct switch_ctx {
+ struct dm_target *ti;
+
+ unsigned nr_paths; /* Number of paths in path_list. */
+
+ unsigned region_size; /* Region size in 512-byte sectors */
+ unsigned long nr_regions; /* Number of regions making up the device */
+ signed char region_size_bits; /* log2 of region_size or -1 */
+
+ unsigned char region_table_entry_bits; /* Number of bits in one region table entry */
+ unsigned char region_entries_per_slot; /* Number of entries in one region table slot */
+ signed char region_entries_per_slot_bits; /* log2 of region_entries_per_slot or -1 */
+
+ region_table_slot_t *region_table; /* Region table */
+
+ /*
+ * Array of dm devices to switch between.
+ */
+ struct switch_path path_list[0];
+};
+
+static struct switch_ctx *alloc_switch_ctx(struct dm_target *ti, unsigned nr_paths,
+ unsigned region_size)
+{
+ struct switch_ctx *sctx;
+
+ sctx = kzalloc(sizeof(struct switch_ctx) + nr_paths * sizeof(struct switch_path),
+ GFP_KERNEL);
+ if (!sctx)
+ return NULL;
+
+ sctx->ti = ti;
+ sctx->region_size = region_size;
+
+ ti->private = sctx;
+
+ return sctx;
+}
+
+static int alloc_region_table(struct dm_target *ti, unsigned nr_paths)
+{
+ struct switch_ctx *sctx = ti->private;
+ sector_t nr_regions = ti->len;
+ sector_t nr_slots;
+
+ if (!(sctx->region_size & (sctx->region_size - 1)))
+ sctx->region_size_bits = __ffs(sctx->region_size);
+ else
+ sctx->region_size_bits = -1;
+
+ sctx->region_table_entry_bits = 1;
+ while (sctx->region_table_entry_bits < sizeof(region_table_slot_t) * 8 &&
+ (region_table_slot_t)1 << sctx->region_table_entry_bits < nr_paths)
+ sctx->region_table_entry_bits++;
+
+ sctx->region_entries_per_slot = (sizeof(region_table_slot_t) * 8) / sctx->region_table_entry_bits;
+ if (!(sctx->region_entries_per_slot & (sctx->region_entries_per_slot - 1)))
+ sctx->region_entries_per_slot_bits = __ffs(sctx->region_entries_per_slot);
+ else
+ sctx->region_entries_per_slot_bits = -1;
+
+ if (sector_div(nr_regions, sctx->region_size))
+ nr_regions++;
+
+ sctx->nr_regions = nr_regions;
+ if (sctx->nr_regions != nr_regions || sctx->nr_regions >= ULONG_MAX) {
+ ti->error = "Region table too large";
+ return -EINVAL;
+ }
+
+ nr_slots = nr_regions;
+ if (sector_div(nr_slots, sctx->region_entries_per_slot))
+ nr_slots++;
+
+ if (nr_slots > ULONG_MAX / sizeof(region_table_slot_t)) {
+ ti->error = "Region table too large";
+ return -EINVAL;
+ }
+
+ sctx->region_table = vmalloc(nr_slots * sizeof(region_table_slot_t));
+ if (!sctx->region_table) {
+ ti->error = "Cannot allocate region table";
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void switch_get_position(struct switch_ctx *sctx, unsigned long region_nr,
+ unsigned long *region_index, unsigned *bit)
+{
+ if (sctx->region_entries_per_slot_bits >= 0) {
+ *region_index = region_nr >> sctx->region_entries_per_slot_bits;
+ *bit = region_nr & (sctx->region_entries_per_slot - 1);
+ } else {
+ *region_index = region_nr / sctx->region_entries_per_slot;
+ *bit = region_nr % sctx->region_entries_per_slot;
+ }
+
+ *bit *= sctx->region_table_entry_bits;
+}
+
+/*
+ * Find which path to use at given offset.
+ */
+static unsigned switch_get_path_nr(struct switch_ctx *sctx, sector_t offset)
+{
+ unsigned long region_index;
+ unsigned bit, path_nr;
+ sector_t p;
+
+ p = offset;
+ if (sctx->region_size_bits >= 0)
+ p >>= sctx->region_size_bits;
+ else
+ sector_div(p, sctx->region_size);
+
+ switch_get_position(sctx, p, &region_index, &bit);
+ path_nr = (ACCESS_ONCE(sctx->region_table[region_index]) >> bit) &
+ ((1 << sctx->region_table_entry_bits) - 1);
+
+ /* This can only happen if the processor uses non-atomic stores. */
+ if (unlikely(path_nr >= sctx->nr_paths))
+ path_nr = 0;
+
+ return path_nr;
+}
+
+static void switch_region_table_write(struct switch_ctx *sctx, unsigned long region_nr,
+ unsigned value)
+{
+ unsigned long region_index;
+ unsigned bit;
+ region_table_slot_t pte;
+
+ switch_get_position(sctx, region_nr, &region_index, &bit);
+
+ pte = sctx->region_table[region_index];
+ pte &= ~((((region_table_slot_t)1 << sctx->region_table_entry_bits) - 1) << bit);
+ pte |= (region_table_slot_t)value << bit;
+ sctx->region_table[region_index] = pte;
+}
+
+/*
+ * Fill the region table with an initial round robin pattern.
+ */
+static void initialise_region_table(struct switch_ctx *sctx)
+{
+ unsigned path_nr = 0;
+ unsigned long region_nr;
+
+ for (region_nr = 0; region_nr < sctx->nr_regions; region_nr++) {
+ switch_region_table_write(sctx, region_nr, path_nr);
+ if (++path_nr >= sctx->nr_paths)
+ path_nr = 0;
+ }
+}
+
+static int parse_path(struct dm_arg_set *as, struct dm_target *ti)
+{
+ struct switch_ctx *sctx = ti->private;
+ unsigned long long start;
+ int r;
+
+ r = dm_get_device(ti, dm_shift_arg(as), dm_table_get_mode(ti->table),
+ &sctx->path_list[sctx->nr_paths].dmdev);
+ if (r) {
+ ti->error = "Device lookup failed";
+ return r;
+ }
+
+ if (kstrtoull(dm_shift_arg(as), 10, &start) || start != (sector_t)start) {
+ ti->error = "Invalid device starting offset";
+ dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
+ return -EINVAL;
+ }
+
+ sctx->path_list[sctx->nr_paths].start = start;
+
+ sctx->nr_paths++;
+
+ return 0;
+}
+
+/*
+ * Destructor: Don't free the dm_target, just the ti->private data (if any).
+ */
+static void switch_dtr(struct dm_target *ti)
+{
+ struct switch_ctx *sctx = ti->private;
+
+ while (sctx->nr_paths--)
+ dm_put_device(ti, sctx->path_list[sctx->nr_paths].dmdev);
+
+ vfree(sctx->region_table);
+ kfree(sctx);
+}
+
+/*
+ * Constructor arguments:
+ * <num_paths> <region_size> <num_optional_args> [<optional_args>...]
+ * [<dev_path> <offset>]+
+ *
+ * Optional args are to allow for future extension: currently this
+ * parameter must be 0.
+ */
+static int switch_ctr(struct dm_target *ti, unsigned argc, char **argv)
+{
+ static struct dm_arg _args[] = {
+ {1, (KMALLOC_MAX_SIZE - sizeof(struct switch_ctx)) / sizeof(struct switch_path), "Invalid number of paths"},
+ {1, UINT_MAX, "Invalid region size"},
+ {0, 0, "Invalid number of optional args"},
+ };
+
+ struct switch_ctx *sctx;
+ struct dm_arg_set as;
+ unsigned nr_paths, region_size, nr_optional_args;
+ int r;
+
+ as.argc = argc;
+ as.argv = argv;
+
+ r = dm_read_arg(_args, &as, &nr_paths, &ti->error);
+ if (r)
+ return -EINVAL;
+
+ r = dm_read_arg(_args + 1, &as, &region_size, &ti->error);
+ if (r)
+ return r;
+
+ r = dm_read_arg_group(_args + 2, &as, &nr_optional_args, &ti->error);
+ if (r)
+ return r;
+ /* parse optional arguments here, if we add any */
+
+ if (as.argc != nr_paths * 2) {
+ ti->error = "Incorrect number of path arguments";
+ return -EINVAL;
+ }
+
+ sctx = alloc_switch_ctx(ti, nr_paths, region_size);
+ if (!sctx) {
+ ti->error = "Cannot allocate redirection context";
+ return -ENOMEM;
+ }
+
+ r = dm_set_target_max_io_len(ti, region_size);
+ if (r)
+ goto error;
+
+ while (as.argc) {
+ r = parse_path(&as, ti);
+ if (r)
+ goto error;
+ }
+
+ r = alloc_region_table(ti, nr_paths);
+ if (r)
+ goto error;
+
+ initialise_region_table(sctx);
+
+ /* For UNMAP, sending the request down any path is sufficient */
+ ti->num_discard_bios = 1;
+
+ return 0;
+
+error:
+ switch_dtr(ti);
+
+ return r;
+}
+
+static int switch_map(struct dm_target *ti, struct bio *bio)
+{
+ struct switch_ctx *sctx = ti->private;
+ sector_t offset = dm_target_offset(ti, bio->bi_sector);
+ unsigned path_nr = switch_get_path_nr(sctx, offset);
+
+ bio->bi_bdev = sctx->path_list[path_nr].dmdev->bdev;
+ bio->bi_sector = sctx->path_list[path_nr].start + offset;
+
+ return DM_MAPIO_REMAPPED;
+}
+
+/*
+ * We need to parse hex numbers in the message as quickly as possible.
+ *
+ * This table-based hex parser improves performance.
+ * It improves a time to load 1000000 entries compared to the condition-based
+ * parser.
+ * table-based parser condition-based parser
+ * PA-RISC 0.29s 0.31s
+ * Opteron 0.0495s 0.0498s
+ */
+static const unsigned char hex_table[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
+255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+};
+
+static __always_inline unsigned long parse_hex(const char **string)
+{
+ unsigned char d;
+ unsigned long r = 0;
+
+ while ((d = hex_table[(unsigned char)**string]) < 16) {
+ r = (r << 4) | d;
+ (*string)++;
+ }
+
+ return r;
+}
+
+static int process_set_region_mappings(struct switch_ctx *sctx,
+ unsigned argc, char **argv)
+{
+ unsigned i;
+ unsigned long region_index = 0;
+
+ for (i = 1; i < argc; i++) {
+ unsigned long path_nr;
+ const char *string = argv[i];
+
+ if (*string == ':')
+ region_index++;
+ else {
+ region_index = parse_hex(&string);
+ if (unlikely(*string != ':')) {
+ DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+ return -EINVAL;
+ }
+ }
+
+ string++;
+ if (unlikely(!*string)) {
+ DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+ return -EINVAL;
+ }
+
+ path_nr = parse_hex(&string);
+ if (unlikely(*string)) {
+ DMWARN("invalid set_region_mappings argument: '%s'", argv[i]);
+ return -EINVAL;
+ }
+ if (unlikely(region_index >= sctx->nr_regions)) {
+ DMWARN("invalid set_region_mappings region number: %lu >= %lu", region_index, sctx->nr_regions);
+ return -EINVAL;
+ }
+ if (unlikely(path_nr >= sctx->nr_paths)) {
+ DMWARN("invalid set_region_mappings device: %lu >= %u", path_nr, sctx->nr_paths);
+ return -EINVAL;
+ }
+
+ switch_region_table_write(sctx, region_index, path_nr);
+ }
+
+ return 0;
+}
+
+/*
+ * Messages are processed one-at-a-time.
+ *
+ * Only set_region_mappings is supported.
+ */
+static int switch_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+ static DEFINE_MUTEX(message_mutex);
+
+ struct switch_ctx *sctx = ti->private;
+ int r = -EINVAL;
+
+ mutex_lock(&message_mutex);
+
+ if (!strcasecmp(argv[0], "set_region_mappings"))
+ r = process_set_region_mappings(sctx, argc, argv);
+ else
+ DMWARN("Unrecognised message received.");
+
+ mutex_unlock(&message_mutex);
+
+ return r;
+}
+
+static void switch_status(struct dm_target *ti, status_type_t type,
+ unsigned status_flags, char *result, unsigned maxlen)
+{
+ struct switch_ctx *sctx = ti->private;
+ unsigned sz = 0;
+ int path_nr;
+
+ switch (type) {
+ case STATUSTYPE_INFO:
+ result[0] = '\0';
+ break;
+
+ case STATUSTYPE_TABLE:
+ DMEMIT("%u %u 0", sctx->nr_paths, sctx->region_size);
+ for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++)
+ DMEMIT(" %s %llu", sctx->path_list[path_nr].dmdev->name,
+ (unsigned long long)sctx->path_list[path_nr].start);
+ break;
+ }
+}
+
+/*
+ * Switch ioctl:
+ *
+ * Passthrough all ioctls to the path for sector 0
+ */
+static int switch_ioctl(struct dm_target *ti, unsigned cmd,
+ unsigned long arg)
+{
+ struct switch_ctx *sctx = ti->private;
+ struct block_device *bdev;
+ fmode_t mode;
+ unsigned path_nr;
+ int r = 0;
+
+ path_nr = switch_get_path_nr(sctx, 0);
+
+ bdev = sctx->path_list[path_nr].dmdev->bdev;
+ mode = sctx->path_list[path_nr].dmdev->mode;
+
+ /*
+ * Only pass ioctls through if the device sizes match exactly.
+ */
+ if (ti->len + sctx->path_list[path_nr].start != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT)
+ r = scsi_verify_blk_ioctl(NULL, cmd);
+
+ return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+}
+
+static int switch_iterate_devices(struct dm_target *ti,
+ iterate_devices_callout_fn fn, void *data)
+{
+ struct switch_ctx *sctx = ti->private;
+ int path_nr;
+ int r;
+
+ for (path_nr = 0; path_nr < sctx->nr_paths; path_nr++) {
+ r = fn(ti, sctx->path_list[path_nr].dmdev,
+ sctx->path_list[path_nr].start, ti->len, data);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+static struct target_type switch_target = {
+ .name = "switch",
+ .version = {1, 0, 0},
+ .module = THIS_MODULE,
+ .ctr = switch_ctr,
+ .dtr = switch_dtr,
+ .map = switch_map,
+ .message = switch_message,
+ .status = switch_status,
+ .ioctl = switch_ioctl,
+ .iterate_devices = switch_iterate_devices,
+};
+
+static int __init dm_switch_init(void)
+{
+ int r;
+
+ r = dm_register_target(&switch_target);
+ if (r < 0)
+ DMERR("dm_register_target() failed %d", r);
+
+ return r;
+}
+
+static void __exit dm_switch_exit(void)
+{
+ dm_unregister_target(&switch_target);
+}
+
+module_init(dm_switch_init);
+module_exit(dm_switch_exit);
+
+MODULE_DESCRIPTION(DM_NAME " dynamic path switching target");
+MODULE_AUTHOR("Kevin D. O'Kelley <Kevin_OKelley@dell.com>");
+MODULE_AUTHOR("Narendran Ganapathy <Narendran_Ganapathy@dell.com>");
+MODULE_AUTHOR("Jim Ramsay <Jim_Ramsay@dell.com>");
+MODULE_AUTHOR("Mikulas Patocka <mpatocka@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 1ff252ab7d46..f221812b7dbc 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -26,22 +26,8 @@
#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
-/*
- * The table has always exactly one reference from either mapped_device->map
- * or hash_cell->new_map. This reference is not counted in table->holders.
- * A pair of dm_create_table/dm_destroy_table functions is used for table
- * creation/destruction.
- *
- * Temporary references from the other code increase table->holders. A pair
- * of dm_table_get/dm_table_put functions is used to manipulate it.
- *
- * When the table is about to be destroyed, we wait for table->holders to
- * drop to zero.
- */
-
struct dm_table {
struct mapped_device *md;
- atomic_t holders;
unsigned type;
/* btree table */
@@ -208,7 +194,6 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
INIT_LIST_HEAD(&t->devices);
INIT_LIST_HEAD(&t->target_callbacks);
- atomic_set(&t->holders, 0);
if (!num_targets)
num_targets = KEYS_PER_NODE;
@@ -246,10 +231,6 @@ void dm_table_destroy(struct dm_table *t)
if (!t)
return;
- while (atomic_read(&t->holders))
- msleep(1);
- smp_mb();
-
/* free the indexes */
if (t->depth >= 2)
vfree(t->index[t->depth - 2]);
@@ -274,22 +255,6 @@ void dm_table_destroy(struct dm_table *t)
kfree(t);
}
-void dm_table_get(struct dm_table *t)
-{
- atomic_inc(&t->holders);
-}
-EXPORT_SYMBOL(dm_table_get);
-
-void dm_table_put(struct dm_table *t)
-{
- if (!t)
- return;
-
- smp_mb__before_atomic_dec();
- atomic_dec(&t->holders);
-}
-EXPORT_SYMBOL(dm_table_put);
-
/*
* Checks to see if we need to extend highs or targets.
*/
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c
index b948fd864d45..4b7941db3aff 100644
--- a/drivers/md/dm-verity.c
+++ b/drivers/md/dm-verity.c
@@ -451,7 +451,7 @@ static void verity_prefetch_io(struct work_struct *work)
goto no_prefetch_cluster;
if (unlikely(cluster & (cluster - 1)))
- cluster = 1 << (fls(cluster) - 1);
+ cluster = 1 << __fls(cluster);
hash_block_start &= ~(sector_t)(cluster - 1);
hash_block_end |= cluster - 1;
@@ -695,8 +695,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
- if (sscanf(argv[0], "%d%c", &num, &dummy) != 1 ||
- num < 0 || num > 1) {
+ if (sscanf(argv[0], "%u%c", &num, &dummy) != 1 ||
+ num > 1) {
ti->error = "Invalid version";
r = -EINVAL;
goto bad;
@@ -723,7 +723,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -EINVAL;
goto bad;
}
- v->data_dev_block_bits = ffs(num) - 1;
+ v->data_dev_block_bits = __ffs(num);
if (sscanf(argv[4], "%u%c", &num, &dummy) != 1 ||
!num || (num & (num - 1)) ||
@@ -733,7 +733,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -EINVAL;
goto bad;
}
- v->hash_dev_block_bits = ffs(num) - 1;
+ v->hash_dev_block_bits = __ffs(num);
if (sscanf(argv[5], "%llu%c", &num_ll, &dummy) != 1 ||
(sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
@@ -812,7 +812,7 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
}
v->hash_per_block_bits =
- fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
+ __fls((1 << v->hash_dev_block_bits) / v->digest_size);
v->levels = 0;
if (v->data_blocks)
@@ -831,9 +831,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
for (i = v->levels - 1; i >= 0; i--) {
sector_t s;
v->hash_level_block[i] = hash_position;
- s = verity_position_at_level(v, v->data_blocks, i);
- s = (s >> v->hash_per_block_bits) +
- !!(s & ((1 << v->hash_per_block_bits) - 1));
+ s = (v->data_blocks + ((sector_t)1 << ((i + 1) * v->hash_per_block_bits)) - 1)
+ >> ((i + 1) * v->hash_per_block_bits);
if (hash_position + s < hash_position) {
ti->error = "Hash device offset overflow";
r = -E2BIG;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index d5370a94b2c1..9e39d2b64bf8 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -117,15 +117,29 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
#define DMF_MERGE_IS_OPTIONAL 6
/*
+ * A dummy definition to make RCU happy.
+ * struct dm_table should never be dereferenced in this file.
+ */
+struct dm_table {
+ int undefined__;
+};
+
+/*
* Work processed by per-device workqueue.
*/
struct mapped_device {
- struct rw_semaphore io_lock;
+ struct srcu_struct io_barrier;
struct mutex suspend_lock;
- rwlock_t map_lock;
atomic_t holders;
atomic_t open_count;
+ /*
+ * The current mapping.
+ * Use dm_get_live_table{_fast} or take suspend_lock for
+ * dereference.
+ */
+ struct dm_table *map;
+
unsigned long flags;
struct request_queue *queue;
@@ -155,11 +169,6 @@ struct mapped_device {
struct workqueue_struct *wq;
/*
- * The current mapping.
- */
- struct dm_table *map;
-
- /*
* io objects are allocated from here.
*/
mempool_t *io_pool;
@@ -386,10 +395,14 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
struct mapped_device *md = bdev->bd_disk->private_data;
- struct dm_table *map = dm_get_live_table(md);
+ int srcu_idx;
+ struct dm_table *map;
struct dm_target *tgt;
int r = -ENOTTY;
+retry:
+ map = dm_get_live_table(md, &srcu_idx);
+
if (!map || !dm_table_get_size(map))
goto out;
@@ -408,7 +421,12 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
r = tgt->type->ioctl(tgt, cmd, arg);
out:
- dm_table_put(map);
+ dm_put_live_table(md, srcu_idx);
+
+ if (r == -ENOTCONN) {
+ msleep(10);
+ goto retry;
+ }
return r;
}
@@ -502,20 +520,39 @@ static void queue_io(struct mapped_device *md, struct bio *bio)
/*
* Everyone (including functions in this file), should use this
* function to access the md->map field, and make sure they call
- * dm_table_put() when finished.
+ * dm_put_live_table() when finished.
*/
-struct dm_table *dm_get_live_table(struct mapped_device *md)
+struct dm_table *dm_get_live_table(struct mapped_device *md, int *srcu_idx) __acquires(md->io_barrier)
{
- struct dm_table *t;
- unsigned long flags;
+ *srcu_idx = srcu_read_lock(&md->io_barrier);
+
+ return srcu_dereference(md->map, &md->io_barrier);
+}
- read_lock_irqsave(&md->map_lock, flags);
- t = md->map;
- if (t)
- dm_table_get(t);
- read_unlock_irqrestore(&md->map_lock, flags);
+void dm_put_live_table(struct mapped_device *md, int srcu_idx) __releases(md->io_barrier)
+{
+ srcu_read_unlock(&md->io_barrier, srcu_idx);
+}
- return t;
+void dm_sync_table(struct mapped_device *md)
+{
+ synchronize_srcu(&md->io_barrier);
+ synchronize_rcu_expedited();
+}
+
+/*
+ * A fast alternative to dm_get_live_table/dm_put_live_table.
+ * The caller must not block between these two functions.
+ */
+static struct dm_table *dm_get_live_table_fast(struct mapped_device *md) __acquires(RCU)
+{
+ rcu_read_lock();
+ return rcu_dereference(md->map);
+}
+
+static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
+{
+ rcu_read_unlock();
}
/*
@@ -1349,17 +1386,18 @@ static int __split_and_process_non_flush(struct clone_info *ci)
/*
* Entry point to split a bio into clones and submit them to the targets.
*/
-static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
+static void __split_and_process_bio(struct mapped_device *md,
+ struct dm_table *map, struct bio *bio)
{
struct clone_info ci;
int error = 0;
- ci.map = dm_get_live_table(md);
- if (unlikely(!ci.map)) {
+ if (unlikely(!map)) {
bio_io_error(bio);
return;
}
+ ci.map = map;
ci.md = md;
ci.io = alloc_io(md);
ci.io->error = 0;
@@ -1386,7 +1424,6 @@ static void __split_and_process_bio(struct mapped_device *md, struct bio *bio)
/* drop the extra reference count */
dec_pending(ci.io, error);
- dm_table_put(ci.map);
}
/*-----------------------------------------------------------------
* CRUD END
@@ -1397,7 +1434,7 @@ static int dm_merge_bvec(struct request_queue *q,
struct bio_vec *biovec)
{
struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_live_table(md);
+ struct dm_table *map = dm_get_live_table_fast(md);
struct dm_target *ti;
sector_t max_sectors;
int max_size = 0;
@@ -1407,7 +1444,7 @@ static int dm_merge_bvec(struct request_queue *q,
ti = dm_table_find_target(map, bvm->bi_sector);
if (!dm_target_is_valid(ti))
- goto out_table;
+ goto out;
/*
* Find maximum amount of I/O that won't need splitting
@@ -1436,10 +1473,8 @@ static int dm_merge_bvec(struct request_queue *q,
max_size = 0;
-out_table:
- dm_table_put(map);
-
out:
+ dm_put_live_table_fast(md);
/*
* Always allow an entire first page
*/
@@ -1458,8 +1493,10 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
int rw = bio_data_dir(bio);
struct mapped_device *md = q->queuedata;
int cpu;
+ int srcu_idx;
+ struct dm_table *map;
- down_read(&md->io_lock);
+ map = dm_get_live_table(md, &srcu_idx);
cpu = part_stat_lock();
part_stat_inc(cpu, &dm_disk(md)->part0, ios[rw]);
@@ -1468,7 +1505,7 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
/* if we're suspended, we have to queue this io for later */
if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))) {
- up_read(&md->io_lock);
+ dm_put_live_table(md, srcu_idx);
if (bio_rw(bio) != READA)
queue_io(md, bio);
@@ -1477,8 +1514,8 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
return;
}
- __split_and_process_bio(md, bio);
- up_read(&md->io_lock);
+ __split_and_process_bio(md, map, bio);
+ dm_put_live_table(md, srcu_idx);
return;
}
@@ -1664,7 +1701,8 @@ static struct request *dm_start_request(struct mapped_device *md, struct request
static void dm_request_fn(struct request_queue *q)
{
struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_live_table(md);
+ int srcu_idx;
+ struct dm_table *map = dm_get_live_table(md, &srcu_idx);
struct dm_target *ti;
struct request *rq, *clone;
sector_t pos;
@@ -1719,7 +1757,7 @@ requeued:
delay_and_out:
blk_delay_queue(q, HZ / 10);
out:
- dm_table_put(map);
+ dm_put_live_table(md, srcu_idx);
}
int dm_underlying_device_busy(struct request_queue *q)
@@ -1732,14 +1770,14 @@ static int dm_lld_busy(struct request_queue *q)
{
int r;
struct mapped_device *md = q->queuedata;
- struct dm_table *map = dm_get_live_table(md);
+ struct dm_table *map = dm_get_live_table_fast(md);
if (!map || test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags))
r = 1;
else
r = dm_table_any_busy_target(map);
- dm_table_put(map);
+ dm_put_live_table_fast(md);
return r;
}
@@ -1751,7 +1789,7 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
struct dm_table *map;
if (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
- map = dm_get_live_table(md);
+ map = dm_get_live_table_fast(md);
if (map) {
/*
* Request-based dm cares about only own queue for
@@ -1762,9 +1800,8 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
bdi_bits;
else
r = dm_table_any_congested(map, bdi_bits);
-
- dm_table_put(map);
}
+ dm_put_live_table_fast(md);
}
return r;
@@ -1869,12 +1906,14 @@ static struct mapped_device *alloc_dev(int minor)
if (r < 0)
goto bad_minor;
+ r = init_srcu_struct(&md->io_barrier);
+ if (r < 0)
+ goto bad_io_barrier;
+
md->type = DM_TYPE_NONE;
- init_rwsem(&md->io_lock);
mutex_init(&md->suspend_lock);
mutex_init(&md->type_lock);
spin_lock_init(&md->deferred_lock);
- rwlock_init(&md->map_lock);
atomic_set(&md->holders, 1);
atomic_set(&md->open_count, 0);
atomic_set(&md->event_nr, 0);
@@ -1937,6 +1976,8 @@ bad_thread:
bad_disk:
blk_cleanup_queue(md->queue);
bad_queue:
+ cleanup_srcu_struct(&md->io_barrier);
+bad_io_barrier:
free_minor(minor);
bad_minor:
module_put(THIS_MODULE);
@@ -1960,6 +2001,7 @@ static void free_dev(struct mapped_device *md)
bioset_free(md->bs);
blk_integrity_unregister(md->disk);
del_gendisk(md->disk);
+ cleanup_srcu_struct(&md->io_barrier);
free_minor(minor);
spin_lock(&_minor_lock);
@@ -2102,7 +2144,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
struct dm_table *old_map;
struct request_queue *q = md->queue;
sector_t size;
- unsigned long flags;
int merge_is_optional;
size = dm_table_get_size(t);
@@ -2131,9 +2172,8 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
merge_is_optional = dm_table_merge_is_optional(t);
- write_lock_irqsave(&md->map_lock, flags);
old_map = md->map;
- md->map = t;
+ rcu_assign_pointer(md->map, t);
md->immutable_target_type = dm_table_get_immutable_target_type(t);
dm_table_set_restrictions(t, q, limits);
@@ -2141,7 +2181,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
set_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
else
clear_bit(DMF_MERGE_IS_OPTIONAL, &md->flags);
- write_unlock_irqrestore(&md->map_lock, flags);
+ dm_sync_table(md);
return old_map;
}
@@ -2152,15 +2192,13 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
static struct dm_table *__unbind(struct mapped_device *md)
{
struct dm_table *map = md->map;
- unsigned long flags;
if (!map)
return NULL;
dm_table_event_callback(map, NULL, NULL);
- write_lock_irqsave(&md->map_lock, flags);
- md->map = NULL;
- write_unlock_irqrestore(&md->map_lock, flags);
+ rcu_assign_pointer(md->map, NULL);
+ dm_sync_table(md);
return map;
}
@@ -2312,11 +2350,12 @@ EXPORT_SYMBOL_GPL(dm_device_name);
static void __dm_destroy(struct mapped_device *md, bool wait)
{
struct dm_table *map;
+ int srcu_idx;
might_sleep();
spin_lock(&_minor_lock);
- map = dm_get_live_table(md);
+ map = dm_get_live_table(md, &srcu_idx);
idr_replace(&_minor_idr, MINOR_ALLOCED, MINOR(disk_devt(dm_disk(md))));
set_bit(DMF_FREEING, &md->flags);
spin_unlock(&_minor_lock);
@@ -2326,6 +2365,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
dm_table_postsuspend_targets(map);
}
+ /* dm_put_live_table must be before msleep, otherwise deadlock is possible */
+ dm_put_live_table(md, srcu_idx);
+
/*
* Rare, but there may be I/O requests still going to complete,
* for example. Wait for all references to disappear.
@@ -2340,7 +2382,6 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
dm_device_name(md), atomic_read(&md->holders));
dm_sysfs_exit(md);
- dm_table_put(map);
dm_table_destroy(__unbind(md));
free_dev(md);
}
@@ -2397,8 +2438,10 @@ static void dm_wq_work(struct work_struct *work)
struct mapped_device *md = container_of(work, struct mapped_device,
work);
struct bio *c;
+ int srcu_idx;
+ struct dm_table *map;
- down_read(&md->io_lock);
+ map = dm_get_live_table(md, &srcu_idx);
while (!test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) {
spin_lock_irq(&md->deferred_lock);
@@ -2408,17 +2451,13 @@ static void dm_wq_work(struct work_struct *work)
if (!c)
break;
- up_read(&md->io_lock);
-
if (dm_request_based(md))
generic_make_request(c);
else
- __split_and_process_bio(md, c);
-
- down_read(&md->io_lock);
+ __split_and_process_bio(md, map, c);
}
- up_read(&md->io_lock);
+ dm_put_live_table(md, srcu_idx);
}
static void dm_queue_flush(struct mapped_device *md)
@@ -2450,10 +2489,10 @@ struct dm_table *dm_swap_table(struct mapped_device *md, struct dm_table *table)
* reappear.
*/
if (dm_table_has_no_data_devices(table)) {
- live_map = dm_get_live_table(md);
+ live_map = dm_get_live_table_fast(md);
if (live_map)
limits = md->queue->limits;
- dm_table_put(live_map);
+ dm_put_live_table_fast(md);
}
if (!live_map) {
@@ -2533,7 +2572,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
goto out_unlock;
}
- map = dm_get_live_table(md);
+ map = md->map;
/*
* DMF_NOFLUSH_SUSPENDING must be set before presuspend.
@@ -2554,7 +2593,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
if (!noflush && do_lockfs) {
r = lock_fs(md);
if (r)
- goto out;
+ goto out_unlock;
}
/*
@@ -2569,9 +2608,8 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
* (dm_wq_work), we set BMF_BLOCK_IO_FOR_SUSPEND and call
* flush_workqueue(md->wq).
*/
- down_write(&md->io_lock);
set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
- up_write(&md->io_lock);
+ synchronize_srcu(&md->io_barrier);
/*
* Stop md->queue before flushing md->wq in case request-based
@@ -2589,10 +2627,9 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
*/
r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE);
- down_write(&md->io_lock);
if (noflush)
clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
- up_write(&md->io_lock);
+ synchronize_srcu(&md->io_barrier);
/* were we interrupted ? */
if (r < 0) {
@@ -2602,7 +2639,7 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
start_queue(md->queue);
unlock_fs(md);
- goto out; /* pushback list is already flushed, so skip flush */
+ goto out_unlock; /* pushback list is already flushed, so skip flush */
}
/*
@@ -2615,9 +2652,6 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
dm_table_postsuspend_targets(map);
-out:
- dm_table_put(map);
-
out_unlock:
mutex_unlock(&md->suspend_lock);
return r;
@@ -2632,7 +2666,7 @@ int dm_resume(struct mapped_device *md)
if (!dm_suspended_md(md))
goto out;
- map = dm_get_live_table(md);
+ map = md->map;
if (!map || !dm_table_get_size(map))
goto out;
@@ -2656,7 +2690,6 @@ int dm_resume(struct mapped_device *md)
r = 0;
out:
- dm_table_put(map);
mutex_unlock(&md->suspend_lock);
return r;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9b82377a833b..dddc87bcf64a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -521,6 +521,7 @@ void mddev_init(struct mddev *mddev)
init_waitqueue_head(&mddev->recovery_wait);
mddev->reshape_position = MaxSector;
mddev->reshape_backwards = 0;
+ mddev->last_sync_action = "none";
mddev->resync_min = 0;
mddev->resync_max = MaxSector;
mddev->level = LEVEL_NONE;
@@ -2867,7 +2868,7 @@ static ssize_t
offset_store(struct md_rdev *rdev, const char *buf, size_t len)
{
unsigned long long offset;
- if (strict_strtoull(buf, 10, &offset) < 0)
+ if (kstrtoull(buf, 10, &offset) < 0)
return -EINVAL;
if (rdev->mddev->pers && rdev->raid_disk >= 0)
return -EBUSY;
@@ -2895,7 +2896,7 @@ static ssize_t new_offset_store(struct md_rdev *rdev,
unsigned long long new_offset;
struct mddev *mddev = rdev->mddev;
- if (strict_strtoull(buf, 10, &new_offset) < 0)
+ if (kstrtoull(buf, 10, &new_offset) < 0)
return -EINVAL;
if (mddev->sync_thread)
@@ -2961,7 +2962,7 @@ static int strict_blocks_to_sectors(const char *buf, sector_t *sectors)
unsigned long long blocks;
sector_t new;
- if (strict_strtoull(buf, 10, &blocks) < 0)
+ if (kstrtoull(buf, 10, &blocks) < 0)
return -EINVAL;
if (blocks & 1ULL << (8 * sizeof(blocks) - 1))
@@ -3069,7 +3070,7 @@ static ssize_t recovery_start_store(struct md_rdev *rdev, const char *buf, size_
if (cmd_match(buf, "none"))
recovery_start = MaxSector;
- else if (strict_strtoull(buf, 10, &recovery_start))
+ else if (kstrtoull(buf, 10, &recovery_start))
return -EINVAL;
if (rdev->mddev->pers &&
@@ -3497,7 +3498,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
if (clevel[len-1] == '\n')
len--;
clevel[len] = 0;
- if (strict_strtol(clevel, 10, &level))
+ if (kstrtol(clevel, 10, &level))
level = LEVEL_NONE;
if (request_module("md-%s", clevel) != 0)
@@ -4272,6 +4273,17 @@ action_store(struct mddev *mddev, const char *page, size_t len)
return len;
}
+static struct md_sysfs_entry md_scan_mode =
+__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
+
+static ssize_t
+last_sync_action_show(struct mddev *mddev, char *page)
+{
+ return sprintf(page, "%s\n", mddev->last_sync_action);
+}
+
+static struct md_sysfs_entry md_last_scan_mode = __ATTR_RO(last_sync_action);
+
static ssize_t
mismatch_cnt_show(struct mddev *mddev, char *page)
{
@@ -4280,10 +4292,6 @@ mismatch_cnt_show(struct mddev *mddev, char *page)
atomic64_read(&mddev->resync_mismatches));
}
-static struct md_sysfs_entry md_scan_mode =
-__ATTR(sync_action, S_IRUGO|S_IWUSR, action_show, action_store);
-
-
static struct md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);
static ssize_t
@@ -4356,7 +4364,7 @@ sync_force_parallel_store(struct mddev *mddev, const char *buf, size_t len)
{
long n;
- if (strict_strtol(buf, 10, &n))
+ if (kstrtol(buf, 10, &n))
return -EINVAL;
if (n != 0 && n != 1)
@@ -4424,7 +4432,7 @@ static ssize_t
min_sync_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long long min;
- if (strict_strtoull(buf, 10, &min))
+ if (kstrtoull(buf, 10, &min))
return -EINVAL;
if (min > mddev->resync_max)
return -EINVAL;
@@ -4461,7 +4469,7 @@ max_sync_store(struct mddev *mddev, const char *buf, size_t len)
mddev->resync_max = MaxSector;
else {
unsigned long long max;
- if (strict_strtoull(buf, 10, &max))
+ if (kstrtoull(buf, 10, &max))
return -EINVAL;
if (max < mddev->resync_min)
return -EINVAL;
@@ -4686,6 +4694,7 @@ static struct attribute *md_default_attrs[] = {
static struct attribute *md_redundancy_attrs[] = {
&md_scan_mode.attr,
+ &md_last_scan_mode.attr,
&md_mismatches.attr,
&md_sync_min.attr,
&md_sync_max.attr,
@@ -6405,6 +6414,12 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
/* need to ensure md_delayed_delete() has completed */
flush_workqueue(md_misc_wq);
+ if (cmd == HOT_REMOVE_DISK)
+ /* need to ensure recovery thread has run */
+ wait_event_interruptible_timeout(mddev->sb_wait,
+ !test_bit(MD_RECOVERY_NEEDED,
+ &mddev->flags),
+ msecs_to_jiffies(5000));
err = mddev_lock(mddev);
if (err) {
printk(KERN_INFO
@@ -7323,7 +7338,7 @@ void md_do_sync(struct md_thread *thread)
sector_t last_check;
int skipped = 0;
struct md_rdev *rdev;
- char *desc;
+ char *desc, *action = NULL;
struct blk_plug plug;
/* just incase thread restarts... */
@@ -7333,17 +7348,21 @@ void md_do_sync(struct md_thread *thread)
return;
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)) {
desc = "data-check";
- else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ action = "check";
+ } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
desc = "requested-resync";
- else
+ action = "repair";
+ } else
desc = "resync";
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
desc = "reshape";
else
desc = "recovery";
+ mddev->last_sync_action = action ?: desc;
+
/* we overload curr_resync somewhat here.
* 0 == not engaged in resync at all
* 2 == checking that there is no conflict with another sync
@@ -7892,6 +7911,8 @@ void md_check_recovery(struct mddev *mddev)
md_new_event(mddev);
}
unlock:
+ wake_up(&mddev->sb_wait);
+
if (!mddev->sync_thread) {
clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
if (test_and_clear_bit(MD_RECOVERY_RECOVER,
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 653f992b687a..20f02c0b5f2d 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -268,6 +268,14 @@ struct mddev {
struct md_thread *thread; /* management thread */
struct md_thread *sync_thread; /* doing resync or reconstruct */
+
+ /* 'last_sync_action' is initialized to "none". It is set when a
+ * sync operation (i.e "data-check", "requested-resync", "resync",
+ * "recovery", or "reshape") is started. It holds this value even
+ * when the sync thread is "frozen" (interrupted) or "idle" (stopped
+ * or finished). It is overwritten when a new sync operation is begun.
+ */
+ char *last_sync_action;
sector_t curr_resync; /* last block scheduled */
/* As resync requests can complete out of order, we cannot easily track
* how much resync has been completed. So we occasionally pause until
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index fcf65e512cf5..c4d420b7d2f4 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -597,6 +597,7 @@ static void *raid0_takeover_raid45(struct mddev *mddev)
mdname(mddev));
return ERR_PTR(-EINVAL);
}
+ rdev->sectors = mddev->dev_sectors;
}
/* Set new parameters */
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 6e17f8181c4b..ec734588a1c6 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1519,8 +1519,9 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
p = conf->mirrors+mirror;
if (!p->rdev) {
- disk_stack_limits(mddev->gendisk, rdev->bdev,
- rdev->data_offset << 9);
+ if (mddev->gendisk)
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
p->head_position = 0;
rdev->raid_disk = mirror;
@@ -1559,7 +1560,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
clear_bit(Unmerged, &rdev->flags);
}
md_integrity_add_rdev(rdev, mddev);
- if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+ if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
print_conf(conf);
return err;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 6ddae2501b9a..cd066b63bdaf 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -97,7 +97,7 @@ static int max_queued_requests = 1024;
static void allow_barrier(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
-static int enough(struct r10conf *conf, int ignore);
+static int _enough(struct r10conf *conf, int previous, int ignore);
static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
int *skipped);
static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
@@ -392,11 +392,9 @@ static void raid10_end_read_request(struct bio *bio, int error)
* than fail the last device. Here we redefine
* "uptodate" to mean "Don't want to retry"
*/
- unsigned long flags;
- spin_lock_irqsave(&conf->device_lock, flags);
- if (!enough(conf, rdev->raid_disk))
+ if (!_enough(conf, test_bit(R10BIO_Previous, &r10_bio->state),
+ rdev->raid_disk))
uptodate = 1;
- spin_unlock_irqrestore(&conf->device_lock, flags);
}
if (uptodate) {
raid_end_bio_io(r10_bio);
@@ -1632,37 +1630,58 @@ static void status(struct seq_file *seq, struct mddev *mddev)
* Don't consider the device numbered 'ignore'
* as we might be about to remove it.
*/
-static int _enough(struct r10conf *conf, struct geom *geo, int ignore)
+static int _enough(struct r10conf *conf, int previous, int ignore)
{
int first = 0;
+ int has_enough = 0;
+ int disks, ncopies;
+ if (previous) {
+ disks = conf->prev.raid_disks;
+ ncopies = conf->prev.near_copies;
+ } else {
+ disks = conf->geo.raid_disks;
+ ncopies = conf->geo.near_copies;
+ }
+ rcu_read_lock();
do {
int n = conf->copies;
int cnt = 0;
int this = first;
while (n--) {
- if (conf->mirrors[this].rdev &&
- this != ignore)
+ struct md_rdev *rdev;
+ if (this != ignore &&
+ (rdev = rcu_dereference(conf->mirrors[this].rdev)) &&
+ test_bit(In_sync, &rdev->flags))
cnt++;
- this = (this+1) % geo->raid_disks;
+ this = (this+1) % disks;
}
if (cnt == 0)
- return 0;
- first = (first + geo->near_copies) % geo->raid_disks;
+ goto out;
+ first = (first + ncopies) % disks;
} while (first != 0);
- return 1;
+ has_enough = 1;
+out:
+ rcu_read_unlock();
+ return has_enough;
}
static int enough(struct r10conf *conf, int ignore)
{
- return _enough(conf, &conf->geo, ignore) &&
- _enough(conf, &conf->prev, ignore);
+ /* when calling 'enough', both 'prev' and 'geo' must
+ * be stable.
+ * This is ensured if ->reconfig_mutex or ->device_lock
+ * is held.
+ */
+ return _enough(conf, 0, ignore) &&
+ _enough(conf, 1, ignore);
}
static void error(struct mddev *mddev, struct md_rdev *rdev)
{
char b[BDEVNAME_SIZE];
struct r10conf *conf = mddev->private;
+ unsigned long flags;
/*
* If it is not operational, then we have already marked it as dead
@@ -1670,18 +1689,18 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
* next level up know.
* else mark the drive as failed
*/
+ spin_lock_irqsave(&conf->device_lock, flags);
if (test_bit(In_sync, &rdev->flags)
- && !enough(conf, rdev->raid_disk))
+ && !enough(conf, rdev->raid_disk)) {
/*
* Don't fail the drive, just return an IO error.
*/
+ spin_unlock_irqrestore(&conf->device_lock, flags);
return;
+ }
if (test_and_clear_bit(In_sync, &rdev->flags)) {
- unsigned long flags;
- spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded++;
- spin_unlock_irqrestore(&conf->device_lock, flags);
- /*
+ /*
* if recovery is running, make sure it aborts.
*/
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
@@ -1689,6 +1708,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
set_bit(Blocked, &rdev->flags);
set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
printk(KERN_ALERT
"md/raid10:%s: Disk failure on %s, disabling device.\n"
"md/raid10:%s: Operation continuing on %d devices.\n",
@@ -1791,7 +1811,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* very different from resync
*/
return -EBUSY;
- if (rdev->saved_raid_disk < 0 && !_enough(conf, &conf->prev, -1))
+ if (rdev->saved_raid_disk < 0 && !_enough(conf, 1, -1))
return -EINVAL;
if (rdev->raid_disk >= 0)
@@ -1819,15 +1839,17 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
set_bit(Replacement, &rdev->flags);
rdev->raid_disk = mirror;
err = 0;
- disk_stack_limits(mddev->gendisk, rdev->bdev,
- rdev->data_offset << 9);
+ if (mddev->gendisk)
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
conf->fullsync = 1;
rcu_assign_pointer(p->replacement, rdev);
break;
}
- disk_stack_limits(mddev->gendisk, rdev->bdev,
- rdev->data_offset << 9);
+ if (mddev->gendisk)
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
p->head_position = 0;
p->recovery_disabled = mddev->recovery_disabled - 1;
@@ -2909,14 +2931,13 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
*/
if (mddev->bitmap == NULL &&
mddev->recovery_cp == MaxSector &&
+ mddev->reshape_position == MaxSector &&
+ !test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
+ !test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
conf->fullsync == 0) {
*skipped = 1;
- max_sector = mddev->dev_sectors;
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
- test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
- max_sector = mddev->resync_max_sectors;
- return max_sector - sector_nr;
+ return mddev->dev_sectors - sector_nr;
}
skipped:
@@ -3532,7 +3553,7 @@ static struct r10conf *setup_conf(struct mddev *mddev)
/* FIXME calc properly */
conf->mirrors = kzalloc(sizeof(struct raid10_info)*(mddev->raid_disks +
- max(0,mddev->delta_disks)),
+ max(0,-mddev->delta_disks)),
GFP_KERNEL);
if (!conf->mirrors)
goto out;
@@ -3691,7 +3712,7 @@ static int run(struct mddev *mddev)
conf->geo.far_offset == 0)
goto out_free_conf;
if (conf->prev.far_copies != 1 &&
- conf->geo.far_offset == 0)
+ conf->prev.far_offset == 0)
goto out_free_conf;
}
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 05e4a105b9c7..2bf094a587cb 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -4924,7 +4924,7 @@ raid5_store_stripe_cache_size(struct mddev *mddev, const char *page, size_t len)
if (!conf)
return -ENODEV;
- if (strict_strtoul(page, 10, &new))
+ if (kstrtoul(page, 10, &new))
return -EINVAL;
err = raid5_set_cache_size(mddev, new);
if (err)
@@ -4957,7 +4957,7 @@ raid5_store_preread_threshold(struct mddev *mddev, const char *page, size_t len)
if (!conf)
return -ENODEV;
- if (strict_strtoul(page, 10, &new))
+ if (kstrtoul(page, 10, &new))
return -EINVAL;
if (new > conf->max_nr_stripes)
return -EINVAL;
@@ -5914,7 +5914,7 @@ static int check_reshape(struct mddev *mddev)
return 0; /* nothing to do */
if (has_failed(conf))
return -EINVAL;
- if (mddev->delta_disks < 0) {
+ if (mddev->delta_disks < 0 && mddev->reshape_position == MaxSector) {
/* We might be able to shrink, but the devices must
* be made bigger first.
* For raid6, 4 is the minimum size.
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 0c8e45949b11..7b6dba3ce55e 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -2919,7 +2919,7 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state,
if (tuner_lock == 0)
return FE_367CAB_NOTUNER;
#endif
- /* Relase the TRL to start demodulator acquisition */
+ /* Release the TRL to start demodulator acquisition */
/* Wait for QAM lock */
LockTime = 0;
stv0367_writereg(state, R367CAB_CTRL_1, 0x00);
diff --git a/drivers/media/firewire/firedtv-fw.c b/drivers/media/firewire/firedtv-fw.c
index e24ec539a5fd..247f0e7cb5f7 100644
--- a/drivers/media/firewire/firedtv-fw.c
+++ b/drivers/media/firewire/firedtv-fw.c
@@ -248,7 +248,7 @@ static const char * const model_names[] = {
/* Adjust the template string if models with longer names appear. */
#define MAX_MODEL_NAME_LEN sizeof("FireDTV ????")
-static int node_probe(struct device *dev)
+static int node_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
{
struct firedtv *fdtv;
char name[MAX_MODEL_NAME_LEN];
@@ -258,8 +258,8 @@ static int node_probe(struct device *dev)
if (!fdtv)
return -ENOMEM;
- dev_set_drvdata(dev, fdtv);
- fdtv->device = dev;
+ dev_set_drvdata(&unit->device, fdtv);
+ fdtv->device = &unit->device;
fdtv->isochannel = -1;
fdtv->voltage = 0xff;
fdtv->tone = 0xff;
@@ -269,7 +269,7 @@ static int node_probe(struct device *dev)
mutex_init(&fdtv->demux_mutex);
INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
- name_len = fw_csr_string(fw_unit(dev)->directory, CSR_MODEL,
+ name_len = fw_csr_string(unit->directory, CSR_MODEL,
name, sizeof(name));
for (i = ARRAY_SIZE(model_names); --i; )
if (strlen(model_names[i]) <= name_len &&
@@ -277,7 +277,7 @@ static int node_probe(struct device *dev)
break;
fdtv->type = i;
- err = fdtv_register_rc(fdtv, dev);
+ err = fdtv_register_rc(fdtv, &unit->device);
if (err)
goto fail_free;
@@ -307,9 +307,9 @@ fail_free:
return err;
}
-static int node_remove(struct device *dev)
+static void node_remove(struct fw_unit *unit)
{
- struct firedtv *fdtv = dev_get_drvdata(dev);
+ struct firedtv *fdtv = dev_get_drvdata(&unit->device);
fdtv_dvb_unregister(fdtv);
@@ -320,7 +320,6 @@ static int node_remove(struct device *dev)
fdtv_unregister_rc(fdtv);
kfree(fdtv);
- return 0;
}
static void node_update(struct fw_unit *unit)
@@ -391,10 +390,10 @@ static struct fw_driver fdtv_driver = {
.owner = THIS_MODULE,
.name = "firedtv",
.bus = &fw_bus_type,
- .probe = node_probe,
- .remove = node_remove,
},
+ .probe = node_probe,
.update = node_update,
+ .remove = node_remove,
.id_table = fdtv_id_table,
};
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index b72a59d3216a..e0634c8b7e0b 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -2020,7 +2020,8 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
/* start async thread */
chip->wt.function = chip_thread_wake;
chip->wt.data = (unsigned long)chip;
- chip->thread = kthread_run(chip_thread, chip, client->name);
+ chip->thread = kthread_run(chip_thread, chip, "%s",
+ client->name);
if (IS_ERR(chip->thread)) {
v4l2_warn(sd, "failed to create kthread\n");
chip->thread = NULL;
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
index 67b61cf3e03a..004d8ace5019 100644
--- a/drivers/media/pci/cx18/cx18-driver.c
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -695,7 +695,7 @@ static int cx18_create_in_workq(struct cx18 *cx)
{
snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
cx->v4l2_dev.name);
- cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
+ cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name);
if (cx->in_work_queue == NULL) {
CX18_ERR("Unable to create incoming mailbox handler thread\n");
return -ENOMEM;
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index 07b8460953b6..b809bc868a9f 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -753,7 +753,7 @@ static int ivtv_init_struct1(struct ivtv *itv)
init_kthread_worker(&itv->irq_worker);
itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker,
- itv->v4l2_dev.name);
+ "%s", itv->v4l2_dev.name);
if (IS_ERR(itv->irq_worker_task)) {
IVTV_ERR("Could not create ivtv task\n");
return -1;
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index bce695d42f10..25eaf61b98b4 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -220,7 +220,7 @@ if V4L_TEST_DRIVERS
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
- depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
+ select FONT_SUPPORT
select FONT_8x16
select VIDEOBUF2_VMALLOC
default n
diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig
index 004fd0b4e9df..436a62a995ee 100644
--- a/drivers/media/platform/exynos4-is/Kconfig
+++ b/drivers/media/platform/exynos4-is/Kconfig
@@ -59,4 +59,4 @@ config VIDEO_EXYNOS4_FIMC_IS
To compile this driver as a module, choose M here: the
module will be called exynos4-fimc-is.
-endif # VIDEO_SAMSUNG_S5P_FIMC
+endif # VIDEO_SAMSUNG_EXYNOS4_IS
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 00b07032f4f0..5296385153d5 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -954,7 +954,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
psize[0] = ctx->dec_src_buf_size;
allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
} else {
- mfc_err("This video node is dedicated to decoding. Decoding not initalised\n");
+ mfc_err("This video node is dedicated to decoding. Decoding not initialized\n");
return -EINVAL;
}
return 0;
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 85bc314382d3..1d3f11965196 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -768,7 +768,8 @@ static int vivi_start_generating(struct vivi_dev *dev)
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
- dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
+ dma_q->kthread = kthread_run(vivi_thread, dev, "%s",
+ dev->v4l2_dev.name);
if (IS_ERR(dma_q->kthread)) {
v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
diff --git a/drivers/memstick/host/jmb38x_ms.c b/drivers/memstick/host/jmb38x_ms.c
index c37d3756d8d2..aeabaa5aedf7 100644
--- a/drivers/memstick/host/jmb38x_ms.c
+++ b/drivers/memstick/host/jmb38x_ms.c
@@ -1046,20 +1046,9 @@ static struct pci_driver jmb38x_ms_driver = {
.resume = jmb38x_ms_resume
};
-static int __init jmb38x_ms_init(void)
-{
- return pci_register_driver(&jmb38x_ms_driver);
-}
-
-static void __exit jmb38x_ms_exit(void)
-{
- pci_unregister_driver(&jmb38x_ms_driver);
-}
+module_pci_driver(jmb38x_ms_driver);
MODULE_AUTHOR("Alex Dubov");
MODULE_DESCRIPTION("JMicron jmb38x MemoryStick driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, jmb38x_ms_id_tbl);
-
-module_init(jmb38x_ms_init);
-module_exit(jmb38x_ms_exit);
diff --git a/drivers/memstick/host/r592.c b/drivers/memstick/host/r592.c
index 9718661c1fb6..1b6e91345222 100644
--- a/drivers/memstick/host/r592.c
+++ b/drivers/memstick/host/r592.c
@@ -884,18 +884,7 @@ static struct pci_driver r852_pci_driver = {
.driver.pm = &r592_pm_ops,
};
-static __init int r592_module_init(void)
-{
- return pci_register_driver(&r852_pci_driver);
-}
-
-static void __exit r592_module_exit(void)
-{
- pci_unregister_driver(&r852_pci_driver);
-}
-
-module_init(r592_module_init);
-module_exit(r592_module_exit);
+module_pci_driver(r852_pci_driver);
module_param_named(enable_dma, r592_enable_dma, bool, S_IRUGO);
MODULE_PARM_DESC(enable_dma, "Enable usage of the DMA (default)");
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c
index 8a5b2d8f4daf..813eaa33fa14 100644
--- a/drivers/message/i2o/driver.c
+++ b/drivers/message/i2o/driver.c
@@ -84,8 +84,8 @@ int i2o_driver_register(struct i2o_driver *drv)
osm_debug("Register driver %s\n", drv->name);
if (drv->event) {
- drv->event_queue = alloc_workqueue(drv->name,
- WQ_MEM_RECLAIM, 1);
+ drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1,
+ drv->name);
if (!drv->event_queue) {
osm_err("Could not initialize event queue for driver "
"%s\n", drv->name);
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
index 582bda543520..6c954835d61e 100644
--- a/drivers/mfd/88pm800.c
+++ b/drivers/mfd/88pm800.c
@@ -22,13 +22,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm80x.h>
#include <linux/slab.h>
-#define PM800_CHIP_ID (0x00)
-
/* Interrupt Registers */
#define PM800_INT_STATUS1 (0x05)
#define PM800_ONKEY_INT_STS1 (1 << 0)
@@ -113,20 +112,11 @@ enum {
PM800_MAX_IRQ,
};
-enum {
- /* Procida */
- PM800_CHIP_A0 = 0x60,
- PM800_CHIP_A1 = 0x61,
- PM800_CHIP_B0 = 0x62,
- PM800_CHIP_C0 = 0x63,
- PM800_CHIP_END = PM800_CHIP_C0,
-
- /* Make sure to update this to the last stepping */
- PM8XXX_CHIP_END = PM800_CHIP_END
-};
+/* PM800: generation identification number */
+#define PM800_CHIP_GEN_ID_NUM 0x3
static const struct i2c_device_id pm80x_id_table[] = {
- {"88PM800", CHIP_PM800},
+ {"88PM800", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@@ -167,6 +157,13 @@ static struct mfd_cell onkey_devs[] = {
},
};
+static struct mfd_cell regulator_devs[] = {
+ {
+ .name = "88pm80x-regulator",
+ .id = -1,
+ },
+};
+
static const struct regmap_irq pm800_irqs[] = {
/* INT0 */
[PM800_IRQ_ONKEY] = {
@@ -315,10 +312,59 @@ out:
return ret;
}
+static int device_onkey_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ int ret;
+
+ ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+ ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
+ NULL);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add onkey subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int device_rtc_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ int ret;
+
+ rtc_devs[0].platform_data = pdata->rtc;
+ rtc_devs[0].pdata_size =
+ pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0;
+ ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+ ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int device_regulator_init(struct pm80x_chip *chip,
+ struct pm80x_platform_data *pdata)
+{
+ int ret;
+
+ ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
+ ARRAY_SIZE(regulator_devs), NULL, 0, NULL);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int device_irq_init_800(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
- unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ unsigned long flags = IRQF_ONESHOT;
int data, mask, ret = -EINVAL;
if (!map || !chip->irq) {
@@ -362,6 +408,7 @@ static struct regmap_irq_chip pm800_irq_chip = {
.status_base = PM800_INT_STATUS1,
.mask_base = PM800_INT_ENA_1,
.ack_base = PM800_INT_STATUS1,
+ .mask_invert = 1,
};
static int pm800_pages_init(struct pm80x_chip *chip)
@@ -369,77 +416,72 @@ static int pm800_pages_init(struct pm80x_chip *chip)
struct pm80x_subchip *subchip;
struct i2c_client *client = chip->client;
+ int ret = 0;
+
subchip = chip->subchip;
- /* PM800 block power: i2c addr 0x31 */
- if (subchip->power_page_addr) {
- subchip->power_page =
- i2c_new_dummy(client->adapter, subchip->power_page_addr);
- subchip->regmap_power =
- devm_regmap_init_i2c(subchip->power_page,
- &pm80x_regmap_config);
- i2c_set_clientdata(subchip->power_page, chip);
- } else
- dev_info(chip->dev,
- "PM800 block power 0x31: No power_page_addr\n");
-
- /* PM800 block GPADC: i2c addr 0x32 */
- if (subchip->gpadc_page_addr) {
- subchip->gpadc_page = i2c_new_dummy(client->adapter,
- subchip->gpadc_page_addr);
- subchip->regmap_gpadc =
- devm_regmap_init_i2c(subchip->gpadc_page,
- &pm80x_regmap_config);
- i2c_set_clientdata(subchip->gpadc_page, chip);
- } else
- dev_info(chip->dev,
- "PM800 block GPADC 0x32: No gpadc_page_addr\n");
+ if (!subchip || !subchip->power_page_addr || !subchip->gpadc_page_addr)
+ return -ENODEV;
+
+ /* PM800 block power page */
+ subchip->power_page = i2c_new_dummy(client->adapter,
+ subchip->power_page_addr);
+ if (subchip->power_page == NULL) {
+ ret = -ENODEV;
+ goto out;
+ }
- return 0;
+ subchip->regmap_power = devm_regmap_init_i2c(subchip->power_page,
+ &pm80x_regmap_config);
+ if (IS_ERR(subchip->regmap_power)) {
+ ret = PTR_ERR(subchip->regmap_power);
+ dev_err(chip->dev,
+ "Failed to allocate regmap_power: %d\n", ret);
+ goto out;
+ }
+
+ i2c_set_clientdata(subchip->power_page, chip);
+
+ /* PM800 block GPADC */
+ subchip->gpadc_page = i2c_new_dummy(client->adapter,
+ subchip->gpadc_page_addr);
+ if (subchip->gpadc_page == NULL) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ subchip->regmap_gpadc = devm_regmap_init_i2c(subchip->gpadc_page,
+ &pm80x_regmap_config);
+ if (IS_ERR(subchip->regmap_gpadc)) {
+ ret = PTR_ERR(subchip->regmap_gpadc);
+ dev_err(chip->dev,
+ "Failed to allocate regmap_gpadc: %d\n", ret);
+ goto out;
+ }
+ i2c_set_clientdata(subchip->gpadc_page, chip);
+
+out:
+ return ret;
}
static void pm800_pages_exit(struct pm80x_chip *chip)
{
struct pm80x_subchip *subchip;
- regmap_exit(chip->regmap);
- i2c_unregister_device(chip->client);
-
subchip = chip->subchip;
- if (subchip->power_page) {
- regmap_exit(subchip->regmap_power);
+
+ if (subchip && subchip->power_page)
i2c_unregister_device(subchip->power_page);
- }
- if (subchip->gpadc_page) {
- regmap_exit(subchip->regmap_gpadc);
+
+ if (subchip && subchip->gpadc_page)
i2c_unregister_device(subchip->gpadc_page);
- }
}
static int device_800_init(struct pm80x_chip *chip,
struct pm80x_platform_data *pdata)
{
- int ret, pmic_id;
+ int ret;
unsigned int val;
- ret = regmap_read(chip->regmap, PM800_CHIP_ID, &val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
- goto out;
- }
-
- pmic_id = val & PM80X_VERSION_MASK;
-
- if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
- chip->version = val;
- dev_info(chip->dev,
- "88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", val);
- } else {
- dev_err(chip->dev,
- "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
- ret = -EINVAL;
- goto out;
- }
-
/*
* alarm wake up bit will be clear in device_irq_init(),
* read before that
@@ -468,27 +510,22 @@ static int device_800_init(struct pm80x_chip *chip,
goto out;
}
- ret =
- mfd_add_devices(chip->dev, 0, &onkey_devs[0],
- ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0,
- NULL);
- if (ret < 0) {
+ ret = device_onkey_init(chip, pdata);
+ if (ret) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
- } else
- dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
-
- if (pdata && pdata->rtc) {
- rtc_devs[0].platform_data = pdata->rtc;
- rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
- ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
- ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add rtc subdev\n");
- goto out_dev;
- } else
- dev_info(chip->dev,
- "[%s]:Added mfd rtc_devs\n", __func__);
+ }
+
+ ret = device_rtc_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+ goto out;
+ }
+
+ ret = device_regulator_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "Failed to add regulators subdev\n");
+ goto out;
}
return 0;
@@ -507,7 +544,7 @@ static int pm800_probe(struct i2c_client *client,
struct pm80x_platform_data *pdata = client->dev.platform_data;
struct pm80x_subchip *subchip;
- ret = pm80x_init(client, id);
+ ret = pm80x_init(client);
if (ret) {
dev_err(&client->dev, "pm800_init fail\n");
goto out_init;
@@ -524,28 +561,31 @@ static int pm800_probe(struct i2c_client *client,
goto err_subchip_alloc;
}
- subchip->power_page_addr = pdata->power_page_addr;
- subchip->gpadc_page_addr = pdata->gpadc_page_addr;
+ /* pm800 has 2 addtional pages to support power and gpadc. */
+ subchip->power_page_addr = client->addr + 1;
+ subchip->gpadc_page_addr = client->addr + 2;
chip->subchip = subchip;
- ret = device_800_init(chip, pdata);
- if (ret) {
- dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
- goto err_subchip_alloc;
- }
-
ret = pm800_pages_init(chip);
if (ret) {
dev_err(&client->dev, "pm800_pages_init failed!\n");
goto err_page_init;
}
+ ret = device_800_init(chip, pdata);
+ if (ret) {
+ dev_err(chip->dev, "Failed to initialize 88pm800 devices\n");
+ goto err_device_init;
+ }
+
if (pdata->plat_config)
pdata->plat_config(chip, pdata);
+ return 0;
+
+err_device_init:
+ pm800_pages_exit(chip);
err_page_init:
- mfd_remove_devices(chip->dev);
- device_irq_exit_800(chip);
err_subchip_alloc:
pm80x_deinit();
out_init:
@@ -567,7 +607,7 @@ static int pm800_remove(struct i2c_client *client)
static struct i2c_driver pm800_driver = {
.driver = {
- .name = "88PM80X",
+ .name = "88PM800",
.owner = THIS_MODULE,
.pm = &pm80x_pm_ops,
},
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c
index 65d7ac099b20..521602231c7b 100644
--- a/drivers/mfd/88pm805.c
+++ b/drivers/mfd/88pm805.c
@@ -29,10 +29,8 @@
#include <linux/slab.h>
#include <linux/delay.h>
-#define PM805_CHIP_ID (0x00)
-
static const struct i2c_device_id pm80x_id_table[] = {
- {"88PM805", CHIP_PM805},
+ {"88PM805", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
@@ -138,7 +136,7 @@ static struct regmap_irq pm805_irqs[] = {
static int device_irq_init_805(struct pm80x_chip *chip)
{
struct regmap *map = chip->regmap;
- unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
+ unsigned long flags = IRQF_ONESHOT;
int data, mask, ret = -EINVAL;
if (!map || !chip->irq) {
@@ -192,7 +190,6 @@ static struct regmap_irq_chip pm805_irq_chip = {
static int device_805_init(struct pm80x_chip *chip)
{
int ret = 0;
- unsigned int val;
struct regmap *map = chip->regmap;
if (!map) {
@@ -200,13 +197,6 @@ static int device_805_init(struct pm80x_chip *chip)
return -EINVAL;
}
- ret = regmap_read(map, PM805_CHIP_ID, &val);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
- goto out_irq_init;
- }
- chip->version = val;
-
chip->regmap_irq_chip = &pm805_irq_chip;
ret = device_irq_init_805(chip);
@@ -239,7 +229,7 @@ static int pm805_probe(struct i2c_client *client,
struct pm80x_chip *chip;
struct pm80x_platform_data *pdata = client->dev.platform_data;
- ret = pm80x_init(client, id);
+ ret = pm80x_init(client);
if (ret) {
dev_err(&client->dev, "pm805_init fail!\n");
goto out_init;
@@ -249,7 +239,7 @@ static int pm805_probe(struct i2c_client *client,
ret = device_805_init(chip);
if (ret) {
- dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
+ dev_err(chip->dev, "Failed to initialize 88pm805 devices\n");
goto err_805_init;
}
@@ -276,7 +266,7 @@ static int pm805_remove(struct i2c_client *client)
static struct i2c_driver pm805_driver = {
.driver = {
- .name = "88PM80X",
+ .name = "88PM805",
.owner = THIS_MODULE,
.pm = &pm80x_pm_ops,
},
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c
index f736a46eb8c0..5e72f65ef94c 100644
--- a/drivers/mfd/88pm80x.c
+++ b/drivers/mfd/88pm80x.c
@@ -18,6 +18,23 @@
#include <linux/uaccess.h>
#include <linux/err.h>
+/* 88pm80x chips have same definition for chip id register. */
+#define PM80X_CHIP_ID (0x00)
+#define PM80X_CHIP_ID_NUM(x) (((x) >> 5) & 0x7)
+#define PM80X_CHIP_ID_REVISION(x) ((x) & 0x1F)
+
+struct pm80x_chip_mapping {
+ unsigned int id;
+ int type;
+};
+
+static struct pm80x_chip_mapping chip_mapping[] = {
+ /* 88PM800 chip id number */
+ {0x3, CHIP_PM800},
+ /* 88PM805 chip id number */
+ {0x0, CHIP_PM805},
+};
+
/*
* workaround: some registers needed by pm805 are defined in pm800, so
* need to use this global variable to maintain the relation between
@@ -31,12 +48,13 @@ const struct regmap_config pm80x_regmap_config = {
};
EXPORT_SYMBOL_GPL(pm80x_regmap_config);
-int pm80x_init(struct i2c_client *client,
- const struct i2c_device_id *id)
+
+int pm80x_init(struct i2c_client *client)
{
struct pm80x_chip *chip;
struct regmap *map;
- int ret = 0;
+ unsigned int val;
+ int i, ret = 0;
chip =
devm_kzalloc(&client->dev, sizeof(struct pm80x_chip), GFP_KERNEL);
@@ -51,10 +69,6 @@ int pm80x_init(struct i2c_client *client,
return ret;
}
- chip->id = id->driver_data;
- if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805)
- return -EINVAL;
-
chip->client = client;
chip->regmap = map;
@@ -64,6 +78,25 @@ int pm80x_init(struct i2c_client *client,
dev_set_drvdata(chip->dev, chip);
i2c_set_clientdata(chip->client, chip);
+ ret = regmap_read(chip->regmap, PM80X_CHIP_ID, &val);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(chip_mapping); i++) {
+ if (chip_mapping[i].id == PM80X_CHIP_ID_NUM(val)) {
+ chip->type = chip_mapping[i].type;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(chip_mapping)) {
+ dev_err(chip->dev,
+ "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", val);
+ return -EINVAL;
+ }
+
device_init_wakeup(&client->dev, 1);
/*
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 31ca55548ef9..eeb481d426b5 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -1150,17 +1150,17 @@ static int pm860x_probe(struct i2c_client *client,
return -EINVAL;
}
- chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct pm860x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->id = verify_addr(client);
- chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
+ chip->regmap = devm_regmap_init_i2c(client, &pm860x_regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
- kfree(chip);
return ret;
}
chip->client = client;
@@ -1203,8 +1203,6 @@ static int pm860x_remove(struct i2c_client *client)
regmap_exit(chip->regmap_companion);
i2c_unregister_device(chip->companion);
}
- regmap_exit(chip->regmap);
- kfree(chip);
return 0;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d54e985748b7..aecd6ddcbbbf 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -53,7 +53,7 @@ config MFD_CROS_EC
help
If you say Y here you get support for the ChromeOS Embedded
Controller (EC) providing keyboard, battery and power services.
- You also ned to enable the driver for the bus you are using. The
+ You also need to enable the driver for the bus you are using. The
protocol for talking to the EC is defined by the bus driver.
config MFD_CROS_EC_I2C
@@ -242,6 +242,27 @@ config MFD_JZ4740_ADC
Say yes here if you want support for the ADC unit in the JZ4740 SoC.
This driver is necessary for jz4740-battery and jz4740-hwmon driver.
+config MFD_KEMPLD
+ tristate "Kontron module PLD device"
+ select MFD_CORE
+ help
+ This is the core driver for the PLD (Programmable Logic Device) found
+ on some Kontron ETX and COMexpress (ETXexpress) modules. The PLD
+ device may provide functions like watchdog, GPIO, UART and I2C bus.
+
+ The following modules are supported:
+ * COMe-bIP#
+ * COMe-bPC2 (ETXexpress-PC)
+ * COMe-bSC# (ETXexpress-SC T#)
+ * COMe-cCT6
+ * COMe-cDC2 (microETXexpress-DC)
+ * COMe-cPC2 (microETXexpress-PC)
+ * COMe-mCT10
+ * ETX-OH
+
+ This driver can also be built as a module. If so, the module
+ will be called kempld-core.
+
config MFD_88PM800
tristate "Marvell 88PM800"
depends on I2C=y && GENERIC_HARDIRQS
@@ -342,6 +363,7 @@ config MFD_MAX8998
bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
+ select IRQ_DOMAIN
help
Say yes here to support for Maxim Semiconductor MAX8998 and
National Semiconductor LP3974. This is a Power Management IC.
@@ -419,7 +441,8 @@ config MFD_PM8XXX
config MFD_PM8921_CORE
tristate "Qualcomm PM8921 PMIC chip"
- depends on SSBI && BROKEN
+ depends on (ARCH_MSM || HEXAGON)
+ depends on BROKEN
select MFD_CORE
select MFD_PM8XXX
help
@@ -1046,6 +1069,12 @@ config MFD_WM5110
help
Support for Wolfson Microelectronics WM5110 low power audio SoC
+config MFD_WM8997
+ bool "Support Wolfson Microelectronics WM8997"
+ depends on MFD_ARIZONA
+ help
+ Support for Wolfson Microelectronics WM8997 low power audio SoC
+
config MFD_WM8400
bool "Wolfson Microelectronics WM8400"
select MFD_CORE
@@ -1144,7 +1173,8 @@ config MCP_UCB1200_TS
endmenu
config VEXPRESS_CONFIG
- bool
+ bool "ARM Versatile Express platform infrastructure"
+ depends on ARM || ARM64
help
Platform configuration infrastructure for the ARM Ltd.
Versatile Express.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 718e94a2a9a7..3c90051ffa5a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -43,6 +43,9 @@ endif
ifneq ($(CONFIG_MFD_WM5110),n)
obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o
endif
+ifneq ($(CONFIG_MFD_WM8997),n)
+obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o
+endif
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
wm831x-objs += wm831x-auxadc.o
@@ -126,6 +129,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
+obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
obj-$(CONFIG_LPC_ICH) += lpc_ich.o
obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
@@ -140,7 +144,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
-obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
+obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
index dfdb0a2b6835..d4f594517521 100644
--- a/drivers/mfd/aat2870-core.c
+++ b/drivers/mfd/aat2870-core.c
@@ -312,8 +312,9 @@ static ssize_t aat2870_reg_write_file(struct file *file,
while (*start == ' ')
start++;
- if (strict_strtoul(start, 16, &val))
- return -EINVAL;
+ ret = kstrtoul(start, 16, &val);
+ if (ret)
+ return ret;
ret = aat2870->write(aat2870, (u8)addr, (u8)val);
if (ret)
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index a9bb140bc86b..ddc669d19530 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -491,7 +491,7 @@ static ssize_t ab3100_get_set_reg(struct file *file,
char buf[32];
ssize_t buf_size;
int regp;
- unsigned long user_reg;
+ u8 user_reg;
int err;
int i = 0;
@@ -514,34 +514,29 @@ static ssize_t ab3100_get_set_reg(struct file *file,
/*
* Advance pointer to end of string then terminate
* the register string. This is needed to satisfy
- * the strict_strtoul() function.
+ * the kstrtou8() function.
*/
while ((i < buf_size) && (buf[i] != ' '))
i++;
buf[i] = '\0';
- err = strict_strtoul(&buf[regp], 16, &user_reg);
+ err = kstrtou8(&buf[regp], 16, &user_reg);
if (err)
return err;
- if (user_reg > 0xff)
- return -EINVAL;
/* Either we read or we write a register here */
if (!priv->mode) {
/* Reading */
- u8 reg = (u8) user_reg;
u8 regvalue;
- ab3100_get_register_interruptible(ab3100, reg, &regvalue);
+ ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
dev_info(ab3100->dev,
"debug read AB3100 reg[0x%02x]: 0x%02x\n",
- reg, regvalue);
+ user_reg, regvalue);
} else {
int valp;
- unsigned long user_value;
- u8 reg = (u8) user_reg;
- u8 value;
+ u8 user_value;
u8 regvalue;
/*
@@ -557,20 +552,17 @@ static ssize_t ab3100_get_set_reg(struct file *file,
i++;
buf[i] = '\0';
- err = strict_strtoul(&buf[valp], 16, &user_value);
+ err = kstrtou8(&buf[valp], 16, &user_value);
if (err)
return err;
- if (user_reg > 0xff)
- return -EINVAL;
- value = (u8) user_value;
- ab3100_set_register_interruptible(ab3100, reg, value);
- ab3100_get_register_interruptible(ab3100, reg, &regvalue);
+ ab3100_set_register_interruptible(ab3100, user_reg, user_value);
+ ab3100_get_register_interruptible(ab3100, user_reg, &regvalue);
dev_info(ab3100->dev,
"debug write reg[0x%02x] with 0x%02x, "
"after readback: 0x%02x\n",
- reg, value, regvalue);
+ user_reg, user_value, regvalue);
}
return buf_size;
}
diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c
index d7ce016029fa..c9af16cc7310 100644
--- a/drivers/mfd/ab3100-otp.c
+++ b/drivers/mfd/ab3100-otp.c
@@ -187,7 +187,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
int err = 0;
int i;
- otp = kzalloc(sizeof(struct ab3100_otp), GFP_KERNEL);
+ otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL);
if (!otp) {
dev_err(&pdev->dev, "could not allocate AB3100 OTP device\n");
return -ENOMEM;
@@ -199,7 +199,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = ab3100_otp_read(otp);
if (err)
- goto err_otp_read;
+ return err;
dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
@@ -208,22 +208,19 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = device_create_file(&pdev->dev,
&ab3100_otp_attrs[i]);
if (err)
- goto err_create_file;
+ goto err;
}
/* debugfs entries */
err = ab3100_otp_init_debugfs(&pdev->dev, otp);
if (err)
- goto err_init_debugfs;
+ goto err;
return 0;
-err_init_debugfs:
-err_create_file:
+err:
while (--i >= 0)
device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
-err_otp_read:
- kfree(otp);
return err;
}
@@ -236,7 +233,6 @@ static int __exit ab3100_otp_remove(struct platform_device *pdev)
device_remove_file(&pdev->dev,
&ab3100_otp_attrs[i]);
ab3100_otp_exit_debugfs(otp);
- kfree(otp);
return 0;
}
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 258b367e3989..b6c2cdc76091 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -650,6 +650,21 @@ static struct resource ab8500_rtc_resources[] = {
},
};
+static struct resource ab8540_rtc_resources[] = {
+ {
+ .name = "1S",
+ .start = AB8540_INT_RTC_1S,
+ .end = AB8540_INT_RTC_1S,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "ALARM",
+ .start = AB8500_INT_RTC_ALARM,
+ .end = AB8500_INT_RTC_ALARM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct resource ab8500_poweronkey_db_resources[] = {
{
.name = "ONKEY_DBF",
@@ -1051,6 +1066,10 @@ static struct mfd_cell ab8500_devs[] = {
.of_compatible = "stericsson,ab8500-sysctrl",
},
{
+ .name = "ab8500-ext-regulator",
+ .of_compatible = "stericsson,ab8500-ext-regulator",
+ },
+ {
.name = "ab8500-regulator",
.of_compatible = "stericsson,ab8500-regulator",
},
@@ -1099,10 +1118,6 @@ static struct mfd_cell ab8500_devs[] = {
.id = 3,
},
{
- .name = "ab8500-leds",
- .of_compatible = "stericsson,ab8500-leds",
- },
- {
.name = "ab8500-denc",
.of_compatible = "stericsson,ab8500-denc",
},
@@ -1124,6 +1139,7 @@ static struct mfd_cell ab8500_devs[] = {
},
{
.name = "ab8500-codec",
+ .of_compatible = "stericsson,ab8500-codec",
},
};
@@ -1139,6 +1155,9 @@ static struct mfd_cell ab9540_devs[] = {
.name = "ab8500-sysctrl",
},
{
+ .name = "ab8500-ext-regulator",
+ },
+ {
.name = "ab8500-regulator",
},
{
@@ -1171,9 +1190,6 @@ static struct mfd_cell ab9540_devs[] = {
.id = 1,
},
{
- .name = "ab8500-leds",
- },
- {
.name = "abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
.resources = ab8500_temp_resources,
@@ -1242,9 +1258,6 @@ static struct mfd_cell ab8505_devs[] = {
.id = 1,
},
{
- .name = "ab8500-leds",
- },
- {
.name = "pinctrl-ab8505",
},
{
@@ -1274,6 +1287,9 @@ static struct mfd_cell ab8540_devs[] = {
.name = "ab8500-sysctrl",
},
{
+ .name = "ab8500-ext-regulator",
+ },
+ {
.name = "ab8500-regulator",
},
{
@@ -1287,11 +1303,6 @@ static struct mfd_cell ab8540_devs[] = {
.resources = ab8505_gpadc_resources,
},
{
- .name = "ab8500-rtc",
- .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
- .resources = ab8500_rtc_resources,
- },
- {
.name = "ab8500-acc-det",
.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
.resources = ab8500_av_acc_detect_resources,
@@ -1306,9 +1317,6 @@ static struct mfd_cell ab8540_devs[] = {
.id = 1,
},
{
- .name = "ab8500-leds",
- },
- {
.name = "abx500-temp",
.num_resources = ARRAY_SIZE(ab8500_temp_resources),
.resources = ab8500_temp_resources,
@@ -1331,6 +1339,24 @@ static struct mfd_cell ab8540_devs[] = {
},
};
+static struct mfd_cell ab8540_cut1_devs[] = {
+ {
+ .name = "ab8500-rtc",
+ .of_compatible = "stericsson,ab8500-rtc",
+ .num_resources = ARRAY_SIZE(ab8500_rtc_resources),
+ .resources = ab8500_rtc_resources,
+ },
+};
+
+static struct mfd_cell ab8540_cut2_devs[] = {
+ {
+ .name = "ab8540-rtc",
+ .of_compatible = "stericsson,ab8540-rtc",
+ .num_resources = ARRAY_SIZE(ab8540_rtc_resources),
+ .resources = ab8540_rtc_resources,
+ },
+};
+
static ssize_t show_chip_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1734,11 +1760,22 @@ static int ab8500_probe(struct platform_device *pdev)
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base, ab8500->domain);
- else if (is_ab8540(ab8500))
+ else if (is_ab8540(ab8500)) {
ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs,
ARRAY_SIZE(ab8540_devs), NULL,
- ab8500->irq_base, ab8500->domain);
- else if (is_ab8505(ab8500))
+ ab8500->irq_base, NULL);
+ if (ret)
+ return ret;
+
+ if (is_ab8540_1p2_or_earlier(ab8500))
+ ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs,
+ ARRAY_SIZE(ab8540_cut1_devs), NULL,
+ ab8500->irq_base, NULL);
+ else /* ab8540 >= cut2 */
+ ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs,
+ ARRAY_SIZE(ab8540_cut2_devs), NULL,
+ ab8500->irq_base, NULL);
+ } else if (is_ab8505(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs,
ARRAY_SIZE(ab8505_devs), NULL,
ab8500->irq_base, ab8500->domain);
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index 37b7ce4c7c3b..7d1f1b08fc4b 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -2757,7 +2757,7 @@ static ssize_t show_irq(struct device *dev,
unsigned int irq_index;
int err;
- err = strict_strtoul(attr->attr.name, 0, &name);
+ err = kstrtoul(attr->attr.name, 0, &name);
if (err)
return err;
@@ -2937,7 +2937,6 @@ static struct dentry *ab8500_gpadc_dir;
static int ab8500_debug_probe(struct platform_device *plf)
{
struct dentry *file;
- int ret = -ENOMEM;
struct ab8500 *ab8500;
struct resource *res;
debug_bank = AB8500_MISC;
@@ -2946,24 +2945,26 @@ static int ab8500_debug_probe(struct platform_device *plf)
ab8500 = dev_get_drvdata(plf->dev.parent);
num_irqs = ab8500->mask_size;
- irq_count = kzalloc(sizeof(*irq_count)*num_irqs, GFP_KERNEL);
+ irq_count = devm_kzalloc(&plf->dev,
+ sizeof(*irq_count)*num_irqs, GFP_KERNEL);
if (!irq_count)
return -ENOMEM;
- dev_attr = kzalloc(sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
+ dev_attr = devm_kzalloc(&plf->dev,
+ sizeof(*dev_attr)*num_irqs,GFP_KERNEL);
if (!dev_attr)
- goto out_freeirq_count;
+ return -ENOMEM;
- event_name = kzalloc(sizeof(*event_name)*num_irqs, GFP_KERNEL);
+ event_name = devm_kzalloc(&plf->dev,
+ sizeof(*event_name)*num_irqs, GFP_KERNEL);
if (!event_name)
- goto out_freedev_attr;
+ return -ENOMEM;
res = platform_get_resource_byname(plf, 0, "IRQ_AB8500");
if (!res) {
dev_err(&plf->dev, "AB8500 irq not found, err %d\n",
irq_first);
- ret = -ENXIO;
- goto out_freeevent_name;
+ return ENXIO;
}
irq_ab8500 = res->start;
@@ -2971,16 +2972,14 @@ static int ab8500_debug_probe(struct platform_device *plf)
if (irq_first < 0) {
dev_err(&plf->dev, "First irq not found, err %d\n",
irq_first);
- ret = irq_first;
- goto out_freeevent_name;
+ return irq_first;
}
irq_last = platform_get_irq_byname(plf, "IRQ_LAST");
if (irq_last < 0) {
dev_err(&plf->dev, "Last irq not found, err %d\n",
irq_last);
- ret = irq_last;
- goto out_freeevent_name;
+ return irq_last;
}
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
@@ -3189,22 +3188,13 @@ err:
if (ab8500_dir)
debugfs_remove_recursive(ab8500_dir);
dev_err(&plf->dev, "failed to create debugfs entries.\n");
-out_freeevent_name:
- kfree(event_name);
-out_freedev_attr:
- kfree(dev_attr);
-out_freeirq_count:
- kfree(irq_count);
- return ret;
+ return -ENOMEM;
}
static int ab8500_debug_remove(struct platform_device *plf)
{
debugfs_remove_recursive(ab8500_dir);
- kfree(event_name);
- kfree(dev_attr);
- kfree(irq_count);
return 0;
}
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 13f7866de46e..7623e9123828 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -886,12 +886,6 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
return ret;
}
-static int ab8500_gpadc_runtime_idle(struct device *dev)
-{
- pm_runtime_suspend(dev);
- return 0;
-}
-
static int ab8500_gpadc_suspend(struct device *dev)
{
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
@@ -925,7 +919,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev)
int ret = 0;
struct ab8500_gpadc *gpadc;
- gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL);
+ gpadc = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_gpadc), GFP_KERNEL);
if (!gpadc) {
dev_err(&pdev->dev, "Error: No memory\n");
return -ENOMEM;
@@ -1005,8 +999,6 @@ fail_irq:
free_irq(gpadc->irq_sw, gpadc);
free_irq(gpadc->irq_hw, gpadc);
fail:
- kfree(gpadc);
- gpadc = NULL;
return ret;
}
@@ -1031,15 +1023,13 @@ static int ab8500_gpadc_remove(struct platform_device *pdev)
pm_runtime_put_noidle(gpadc->dev);
- kfree(gpadc);
- gpadc = NULL;
return 0;
}
static const struct dev_pm_ops ab8500_gpadc_pm_ops = {
SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend,
ab8500_gpadc_runtime_resume,
- ab8500_gpadc_runtime_idle)
+ NULL)
SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend,
ab8500_gpadc_resume)
diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c
index 3714acb61458..f3a15aa54d7b 100644
--- a/drivers/mfd/abx500-core.c
+++ b/drivers/mfd/abx500-core.c
@@ -36,7 +36,9 @@ int abx500_register_ops(struct device *dev, struct abx500_ops *ops)
{
struct abx500_device_entry *dev_entry;
- dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL);
+ dev_entry = devm_kzalloc(dev,
+ sizeof(struct abx500_device_entry),
+ GFP_KERNEL);
if (!dev_entry) {
dev_err(dev, "register_ops kzalloc failed");
return -ENOMEM;
@@ -54,12 +56,8 @@ void abx500_remove_ops(struct device *dev)
struct abx500_device_entry *dev_entry, *tmp;
list_for_each_entry_safe(dev_entry, tmp, &abx500_list, list)
- {
- if (dev_entry->dev == dev) {
+ if (dev_entry->dev == dev)
list_del(&dev_entry->list);
- kfree(dev_entry);
- }
- }
}
EXPORT_SYMBOL(abx500_remove_ops);
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
index 0d2eba023439..28346ad0b4a6 100644
--- a/drivers/mfd/adp5520.c
+++ b/drivers/mfd/adp5520.c
@@ -223,7 +223,7 @@ static int adp5520_probe(struct i2c_client *client,
return -ENODEV;
}
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -244,7 +244,7 @@ static int adp5520_probe(struct i2c_client *client,
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
chip->irq);
- goto out_free_chip;
+ return ret;
}
}
@@ -302,9 +302,6 @@ out_free_irq:
if (chip->irq)
free_irq(chip->irq, chip);
-out_free_chip:
- kfree(chip);
-
return ret;
}
@@ -317,7 +314,6 @@ static int adp5520_remove(struct i2c_client *client)
adp5520_remove_subdevs(chip);
adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
- kfree(chip);
return 0;
}
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 6ab03043fd60..89a115301a0c 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -16,9 +16,13 @@
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
#include <linux/slab.h>
#include <linux/mfd/arizona/core.h>
@@ -344,6 +348,17 @@ static int arizona_runtime_resume(struct device *dev)
switch (arizona->type) {
case WM5102:
+ if (arizona->external_dcvdd) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ISOLATION_CONTROL,
+ ARIZONA_ISOLATE_DCVDD1, 0);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to connect DCVDD: %d\n", ret);
+ goto err;
+ }
+ }
+
ret = wm5102_patch(arizona);
if (ret != 0) {
dev_err(arizona->dev, "Failed to apply patch: %d\n",
@@ -365,6 +380,28 @@ static int arizona_runtime_resume(struct device *dev)
goto err;
}
+ if (arizona->external_dcvdd) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ISOLATION_CONTROL,
+ ARIZONA_ISOLATE_DCVDD1, 0);
+ if (ret != 0) {
+ dev_err(arizona->dev,
+ "Failed to connect DCVDD: %d\n", ret);
+ goto err;
+ }
+ }
+ break;
+ }
+
+ switch (arizona->type) {
+ case WM5102:
+ ret = wm5102_patch(arizona);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to apply patch: %d\n",
+ ret);
+ goto err;
+ }
+ default:
break;
}
@@ -385,9 +422,22 @@ err:
static int arizona_runtime_suspend(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
+ int ret;
dev_dbg(arizona->dev, "Entering AoD mode\n");
+ if (arizona->external_dcvdd) {
+ ret = regmap_update_bits(arizona->regmap,
+ ARIZONA_ISOLATION_CONTROL,
+ ARIZONA_ISOLATE_DCVDD1,
+ ARIZONA_ISOLATE_DCVDD1);
+ if (ret != 0) {
+ dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
regulator_disable(arizona->dcvdd);
regcache_cache_only(arizona->regmap, true);
regcache_mark_dirty(arizona->regmap);
@@ -397,6 +447,26 @@ static int arizona_runtime_suspend(struct device *dev)
#endif
#ifdef CONFIG_PM_SLEEP
+static int arizona_suspend(struct device *dev)
+{
+ struct arizona *arizona = dev_get_drvdata(dev);
+
+ dev_dbg(arizona->dev, "Suspend, disabling IRQ\n");
+ disable_irq(arizona->irq);
+
+ return 0;
+}
+
+static int arizona_suspend_late(struct device *dev)
+{
+ struct arizona *arizona = dev_get_drvdata(dev);
+
+ dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n");
+ enable_irq(arizona->irq);
+
+ return 0;
+}
+
static int arizona_resume_noirq(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
@@ -422,13 +492,79 @@ const struct dev_pm_ops arizona_pm_ops = {
SET_RUNTIME_PM_OPS(arizona_runtime_suspend,
arizona_runtime_resume,
NULL)
- SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
#ifdef CONFIG_PM_SLEEP
+ .suspend_late = arizona_suspend_late,
.resume_noirq = arizona_resume_noirq,
#endif
};
EXPORT_SYMBOL_GPL(arizona_pm_ops);
+#ifdef CONFIG_OF
+int arizona_of_get_type(struct device *dev)
+{
+ const struct of_device_id *id = of_match_device(arizona_of_match, dev);
+
+ if (id)
+ return (int)id->data;
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_of_get_type);
+
+static int arizona_of_get_core_pdata(struct arizona *arizona)
+{
+ int ret, i;
+
+ arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node,
+ "wlf,reset", 0);
+ if (arizona->pdata.reset < 0)
+ arizona->pdata.reset = 0;
+
+ arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node,
+ "wlf,ldoena", 0);
+ if (arizona->pdata.ldoena < 0)
+ arizona->pdata.ldoena = 0;
+
+ ret = of_property_read_u32_array(arizona->dev->of_node,
+ "wlf,gpio-defaults",
+ arizona->pdata.gpio_defaults,
+ ARRAY_SIZE(arizona->pdata.gpio_defaults));
+ if (ret >= 0) {
+ /*
+ * All values are literal except out of range values
+ * which are chip default, translate into platform
+ * data which uses 0 as chip default and out of range
+ * as zero.
+ */
+ for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+ if (arizona->pdata.gpio_defaults[i] > 0xffff)
+ arizona->pdata.gpio_defaults[i] = 0;
+ if (arizona->pdata.gpio_defaults[i] == 0)
+ arizona->pdata.gpio_defaults[i] = 0x10000;
+ }
+ } else {
+ dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n",
+ ret);
+ }
+
+ return 0;
+}
+
+const struct of_device_id arizona_of_match[] = {
+ { .compatible = "wlf,wm5102", .data = (void *)WM5102 },
+ { .compatible = "wlf,wm5110", .data = (void *)WM5110 },
+ { .compatible = "wlf,wm8997", .data = (void *)WM8997 },
+ {},
+};
+EXPORT_SYMBOL_GPL(arizona_of_match);
+#else
+static inline int arizona_of_get_core_pdata(struct arizona *arizona)
+{
+ return 0;
+}
+#endif
+
static struct mfd_cell early_devs[] = {
{ .name = "arizona-ldo1" },
};
@@ -451,6 +587,15 @@ static struct mfd_cell wm5110_devs[] = {
{ .name = "wm5110-codec" },
};
+static struct mfd_cell wm8997_devs[] = {
+ { .name = "arizona-micsupp" },
+ { .name = "arizona-extcon" },
+ { .name = "arizona-gpio" },
+ { .name = "arizona-haptics" },
+ { .name = "arizona-pwm" },
+ { .name = "wm8997-codec" },
+};
+
int arizona_dev_init(struct arizona *arizona)
{
struct device *dev = arizona->dev;
@@ -462,6 +607,8 @@ int arizona_dev_init(struct arizona *arizona)
dev_set_drvdata(arizona->dev, arizona);
mutex_init(&arizona->clk_lock);
+ arizona_of_get_core_pdata(arizona);
+
if (dev_get_platdata(arizona->dev))
memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
sizeof(arizona->pdata));
@@ -471,6 +618,7 @@ int arizona_dev_init(struct arizona *arizona)
switch (arizona->type) {
case WM5102:
case WM5110:
+ case WM8997:
for (i = 0; i < ARRAY_SIZE(wm5102_core_supplies); i++)
arizona->core_supplies[i].supply
= wm5102_core_supplies[i];
@@ -536,51 +684,23 @@ int arizona_dev_init(struct arizona *arizona)
regcache_cache_only(arizona->regmap, false);
+ /* Verify that this is a chip we know about */
ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
if (ret != 0) {
dev_err(dev, "Failed to read ID register: %d\n", ret);
goto err_reset;
}
- ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
- &arizona->rev);
- if (ret != 0) {
- dev_err(dev, "Failed to read revision register: %d\n", ret);
- goto err_reset;
- }
- arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
-
switch (reg) {
-#ifdef CONFIG_MFD_WM5102
case 0x5102:
- type_name = "WM5102";
- if (arizona->type != WM5102) {
- dev_err(arizona->dev, "WM5102 registered as %d\n",
- arizona->type);
- arizona->type = WM5102;
- }
- apply_patch = wm5102_patch;
- arizona->rev &= 0x7;
- break;
-#endif
-#ifdef CONFIG_MFD_WM5110
case 0x5110:
- type_name = "WM5110";
- if (arizona->type != WM5110) {
- dev_err(arizona->dev, "WM5110 registered as %d\n",
- arizona->type);
- arizona->type = WM5110;
- }
- apply_patch = wm5110_patch;
+ case 0x8997:
break;
-#endif
default:
- dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+ dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
goto err_reset;
}
- dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
-
/* If we have a /RESET GPIO we'll already be reset */
if (!arizona->pdata.reset) {
regcache_mark_dirty(arizona->regmap);
@@ -600,6 +720,7 @@ int arizona_dev_init(struct arizona *arizona)
}
}
+ /* Ensure device startup is complete */
switch (arizona->type) {
case WM5102:
ret = regmap_read(arizona->regmap, 0x19, &val);
@@ -620,6 +741,63 @@ int arizona_dev_init(struct arizona *arizona)
break;
}
+ /* Read the device ID information & do device specific stuff */
+ ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, &reg);
+ if (ret != 0) {
+ dev_err(dev, "Failed to read ID register: %d\n", ret);
+ goto err_reset;
+ }
+
+ ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION,
+ &arizona->rev);
+ if (ret != 0) {
+ dev_err(dev, "Failed to read revision register: %d\n", ret);
+ goto err_reset;
+ }
+ arizona->rev &= ARIZONA_DEVICE_REVISION_MASK;
+
+ switch (reg) {
+#ifdef CONFIG_MFD_WM5102
+ case 0x5102:
+ type_name = "WM5102";
+ if (arizona->type != WM5102) {
+ dev_err(arizona->dev, "WM5102 registered as %d\n",
+ arizona->type);
+ arizona->type = WM5102;
+ }
+ apply_patch = wm5102_patch;
+ arizona->rev &= 0x7;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM5110
+ case 0x5110:
+ type_name = "WM5110";
+ if (arizona->type != WM5110) {
+ dev_err(arizona->dev, "WM5110 registered as %d\n",
+ arizona->type);
+ arizona->type = WM5110;
+ }
+ apply_patch = wm5110_patch;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8997
+ case 0x8997:
+ type_name = "WM8997";
+ if (arizona->type != WM8997) {
+ dev_err(arizona->dev, "WM8997 registered as %d\n",
+ arizona->type);
+ arizona->type = WM8997;
+ }
+ apply_patch = wm8997_patch;
+ break;
+#endif
+ default:
+ dev_err(arizona->dev, "Unknown device ID %x\n", reg);
+ goto err_reset;
+ }
+
+ dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A');
+
if (apply_patch) {
ret = apply_patch(arizona);
if (ret != 0) {
@@ -651,6 +829,14 @@ int arizona_dev_init(struct arizona *arizona)
arizona->pdata.gpio_defaults[i]);
}
+ /*
+ * LDO1 can only be used to supply DCVDD so if it has no
+ * consumers then DCVDD is supplied externally.
+ */
+ if (arizona->pdata.ldo1 &&
+ arizona->pdata.ldo1->num_consumer_supplies == 0)
+ arizona->external_dcvdd = true;
+
pm_runtime_set_autosuspend_delay(arizona->dev, 100);
pm_runtime_use_autosuspend(arizona->dev);
pm_runtime_enable(arizona->dev);
@@ -697,7 +883,7 @@ int arizona_dev_init(struct arizona *arizona)
if (arizona->pdata.micbias[i].discharge)
val |= ARIZONA_MICB1_DISCH;
- if (arizona->pdata.micbias[i].fast_start)
+ if (arizona->pdata.micbias[i].soft_start)
val |= ARIZONA_MICB1_RATE;
if (arizona->pdata.micbias[i].bypass)
@@ -771,6 +957,10 @@ int arizona_dev_init(struct arizona *arizona)
ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
ARRAY_SIZE(wm5110_devs), NULL, 0, NULL);
break;
+ case WM8997:
+ ret = mfd_add_devices(arizona->dev, -1, wm8997_devs,
+ ARRAY_SIZE(wm8997_devs), NULL, 0, NULL);
+ break;
}
if (ret != 0) {
@@ -809,6 +999,11 @@ int arizona_dev_exit(struct arizona *arizona)
arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona);
pm_runtime_disable(arizona->dev);
arizona_irq_exit(arizona);
+ if (arizona->pdata.reset)
+ gpio_set_value_cansleep(arizona->pdata.reset, 0);
+ regulator_disable(arizona->dcvdd);
+ regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies),
+ arizona->core_supplies);
return 0;
}
EXPORT_SYMBOL_GPL(arizona_dev_exit);
diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c
index 44a1bb969841..51dbabf7c021 100644
--- a/drivers/mfd/arizona-i2c.c
+++ b/drivers/mfd/arizona-i2c.c
@@ -27,9 +27,14 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
{
struct arizona *arizona;
const struct regmap_config *regmap_config;
- int ret;
+ int ret, type;
- switch (id->driver_data) {
+ if (i2c->dev.of_node)
+ type = arizona_of_get_type(&i2c->dev);
+ else
+ type = id->driver_data;
+
+ switch (type) {
#ifdef CONFIG_MFD_WM5102
case WM5102:
regmap_config = &wm5102_i2c_regmap;
@@ -40,6 +45,11 @@ static int arizona_i2c_probe(struct i2c_client *i2c,
regmap_config = &wm5110_i2c_regmap;
break;
#endif
+#ifdef CONFIG_MFD_WM8997
+ case WM8997:
+ regmap_config = &wm8997_i2c_regmap;
+ break;
+#endif
default:
dev_err(&i2c->dev, "Unknown device type %ld\n",
id->driver_data);
@@ -75,6 +85,7 @@ static int arizona_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id arizona_i2c_id[] = {
{ "wm5102", WM5102 },
{ "wm5110", WM5110 },
+ { "wm8997", WM8997 },
{ }
};
MODULE_DEVICE_TABLE(i2c, arizona_i2c_id);
@@ -84,6 +95,7 @@ static struct i2c_driver arizona_i2c_driver = {
.name = "arizona",
.owner = THIS_MODULE,
.pm = &arizona_pm_ops,
+ .of_match_table = of_match_ptr(arizona_of_match),
},
.probe = arizona_i2c_probe,
.remove = arizona_i2c_remove,
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index 64cd9b6dac92..88758ab9402b 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -208,6 +208,14 @@ int arizona_irq_init(struct arizona *arizona)
ctrlif_error = false;
break;
#endif
+#ifdef CONFIG_MFD_WM8997
+ case WM8997:
+ aod = &wm8997_aod;
+ irq = &wm8997_irq;
+
+ ctrlif_error = false;
+ break;
+#endif
default:
BUG_ON("Unknown Arizona class device" == NULL);
return -EINVAL;
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index b57e642d2b4a..47be7b35b5c5 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -27,9 +27,14 @@ static int arizona_spi_probe(struct spi_device *spi)
const struct spi_device_id *id = spi_get_device_id(spi);
struct arizona *arizona;
const struct regmap_config *regmap_config;
- int ret;
+ int ret, type;
- switch (id->driver_data) {
+ if (spi->dev.of_node)
+ type = arizona_of_get_type(&spi->dev);
+ else
+ type = id->driver_data;
+
+ switch (type) {
#ifdef CONFIG_MFD_WM5102
case WM5102:
regmap_config = &wm5102_spi_regmap;
@@ -84,6 +89,7 @@ static struct spi_driver arizona_spi_driver = {
.name = "arizona",
.owner = THIS_MODULE,
.pm = &arizona_pm_ops,
+ .of_match_table = of_match_ptr(arizona_of_match),
},
.probe = arizona_spi_probe,
.remove = arizona_spi_remove,
diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h
index 9798ae5da67b..b4cef777df73 100644
--- a/drivers/mfd/arizona.h
+++ b/drivers/mfd/arizona.h
@@ -13,6 +13,7 @@
#ifndef _WM5102_H
#define _WM5102_H
+#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/pm.h>
@@ -24,17 +25,33 @@ extern const struct regmap_config wm5102_spi_regmap;
extern const struct regmap_config wm5110_i2c_regmap;
extern const struct regmap_config wm5110_spi_regmap;
+extern const struct regmap_config wm8997_i2c_regmap;
+
extern const struct dev_pm_ops arizona_pm_ops;
+extern const struct of_device_id arizona_of_match[];
+
extern const struct regmap_irq_chip wm5102_aod;
extern const struct regmap_irq_chip wm5102_irq;
extern const struct regmap_irq_chip wm5110_aod;
extern const struct regmap_irq_chip wm5110_irq;
+extern const struct regmap_irq_chip wm8997_aod;
+extern const struct regmap_irq_chip wm8997_irq;
+
int arizona_dev_init(struct arizona *arizona);
int arizona_dev_exit(struct arizona *arizona);
int arizona_irq_init(struct arizona *arizona);
int arizona_irq_exit(struct arizona *arizona);
+#ifdef CONFIG_OF
+int arizona_of_get_type(struct device *dev);
+#else
+static inline int arizona_of_get_type(struct device *dev)
+{
+ return 0;
+}
+#endif
+
#endif
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 1b15986c01e1..9532f749412f 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -958,7 +958,8 @@ static int __init asic3_probe(struct platform_device *pdev)
unsigned long clksel;
int ret = 0;
- asic = kzalloc(sizeof(struct asic3), GFP_KERNEL);
+ asic = devm_kzalloc(&pdev->dev,
+ sizeof(struct asic3), GFP_KERNEL);
if (asic == NULL) {
printk(KERN_ERR "kzalloc failed\n");
return -ENOMEM;
@@ -970,16 +971,14 @@ static int __init asic3_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
- ret = -ENOMEM;
dev_err(asic->dev, "no MEM resource\n");
- goto out_free;
+ return -ENOMEM;
}
asic->mapping = ioremap(mem->start, resource_size(mem));
if (!asic->mapping) {
- ret = -ENOMEM;
dev_err(asic->dev, "Couldn't ioremap\n");
- goto out_free;
+ return -ENOMEM;
}
asic->irq_base = pdata->irq_base;
@@ -1033,9 +1032,6 @@ static int __init asic3_probe(struct platform_device *pdev)
out_unmap:
iounmap(asic->mapping);
- out_free:
- kfree(asic);
-
return ret;
}
@@ -1058,8 +1054,6 @@ static int asic3_remove(struct platform_device *pdev)
iounmap(asic->mapping);
- kfree(asic);
-
return 0;
}
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index 10cd14e35eb0..1f36885d674b 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -104,23 +104,19 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
ec_dev->command_sendrecv = cros_ec_command_sendrecv;
if (ec_dev->din_size) {
- ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL);
- if (!ec_dev->din) {
- err = -ENOMEM;
- goto fail_din;
- }
+ ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL);
+ if (!ec_dev->din)
+ return -ENOMEM;
}
if (ec_dev->dout_size) {
- ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL);
- if (!ec_dev->dout) {
- err = -ENOMEM;
- goto fail_dout;
- }
+ ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL);
+ if (!ec_dev->dout)
+ return -ENOMEM;
}
if (!ec_dev->irq) {
dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq);
- goto fail_irq;
+ return err;
}
err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
@@ -128,7 +124,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
"chromeos-ec", ec_dev);
if (err) {
dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err);
- goto fail_irq;
+ return err;
}
err = mfd_add_devices(dev, 0, cros_devs,
@@ -145,11 +141,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
fail_mfd:
free_irq(ec_dev->irq, ec_dev);
-fail_irq:
- kfree(ec_dev->dout);
-fail_dout:
- kfree(ec_dev->din);
-fail_din:
+
return err;
}
EXPORT_SYMBOL(cros_ec_register);
@@ -158,8 +150,6 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
{
mfd_remove_devices(ec_dev->dev);
free_irq(ec_dev->irq, ec_dev);
- kfree(ec_dev->dout);
- kfree(ec_dev->din);
return 0;
}
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index c60ab0c3c4db..fb64398506e9 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -46,56 +46,39 @@ void davinci_vc_write(struct davinci_vc *davinci_vc,
static int __init davinci_vc_probe(struct platform_device *pdev)
{
struct davinci_vc *davinci_vc;
- struct resource *res, *mem;
+ struct resource *res;
struct mfd_cell *cell = NULL;
int ret;
- davinci_vc = kzalloc(sizeof(struct davinci_vc), GFP_KERNEL);
+ davinci_vc = devm_kzalloc(&pdev->dev,
+ sizeof(struct davinci_vc), GFP_KERNEL);
if (!davinci_vc) {
dev_dbg(&pdev->dev,
"could not allocate memory for private data\n");
return -ENOMEM;
}
- davinci_vc->clk = clk_get(&pdev->dev, NULL);
+ davinci_vc->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(davinci_vc->clk)) {
dev_dbg(&pdev->dev,
"could not get the clock for voice codec\n");
- ret = -ENODEV;
- goto fail1;
+ return -ENODEV;
}
clk_enable(davinci_vc->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no mem resource\n");
- ret = -ENODEV;
- goto fail2;
- }
- davinci_vc->pbase = res->start;
- davinci_vc->base_size = resource_size(res);
-
- mem = request_mem_region(davinci_vc->pbase, davinci_vc->base_size,
- pdev->name);
- if (!mem) {
- dev_err(&pdev->dev, "VCIF region already claimed\n");
- ret = -EBUSY;
- goto fail2;
- }
-
- davinci_vc->base = ioremap(davinci_vc->pbase, davinci_vc->base_size);
- if (!davinci_vc->base) {
- dev_err(&pdev->dev, "can't ioremap mem resource.\n");
- ret = -ENOMEM;
- goto fail3;
+ davinci_vc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(davinci_vc->base)) {
+ ret = PTR_ERR(davinci_vc->base);
+ goto fail;
}
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENXIO;
- goto fail4;
+ goto fail;
}
davinci_vc->davinci_vcif.dma_tx_channel = res->start;
@@ -106,7 +89,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
ret = -ENXIO;
- goto fail4;
+ goto fail;
}
davinci_vc->davinci_vcif.dma_rx_channel = res->start;
@@ -132,21 +115,13 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
DAVINCI_VC_CELLS, NULL, 0, NULL);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register client devices\n");
- goto fail4;
+ goto fail;
}
return 0;
-fail4:
- iounmap(davinci_vc->base);
-fail3:
- release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
-fail2:
+fail:
clk_disable(davinci_vc->clk);
- clk_put(davinci_vc->clk);
- davinci_vc->clk = NULL;
-fail1:
- kfree(davinci_vc);
return ret;
}
@@ -157,14 +132,7 @@ static int davinci_vc_remove(struct platform_device *pdev)
mfd_remove_devices(&pdev->dev);
- iounmap(davinci_vc->base);
- release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
-
clk_disable(davinci_vc->clk);
- clk_put(davinci_vc->clk);
- davinci_vc->clk = NULL;
-
- kfree(davinci_vc);
return 0;
}
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 66f80973596b..3c157faee645 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -480,6 +480,7 @@ struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
+ CLK_MGT_ENTRY(BML8580CLK, PLL_DIV, true),
CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),
@@ -1724,9 +1725,9 @@ static long round_clock_rate(u8 clock, unsigned long rate)
/* CPU FREQ table, may be changed due to if MAX_OPP is supported. */
static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
- { .frequency = 200000, .index = ARM_EXTCLK,},
- { .frequency = 400000, .index = ARM_50_OPP,},
- { .frequency = 800000, .index = ARM_100_OPP,},
+ { .frequency = 200000, .driver_data = ARM_EXTCLK,},
+ { .frequency = 400000, .driver_data = ARM_50_OPP,},
+ { .frequency = 800000, .driver_data = ARM_100_OPP,},
{ .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */
{ .frequency = CPUFREQ_TABLE_END,},
};
@@ -1901,7 +1902,7 @@ static int set_armss_rate(unsigned long rate)
return -EINVAL;
/* Set the new arm opp. */
- return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].index);
+ return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data);
}
static int set_plldsi_rate(unsigned long rate)
@@ -3105,7 +3106,7 @@ static void db8500_prcmu_update_cpufreq(void)
{
if (prcmu_has_arm_maxopp()) {
db8500_cpufreq_table[3].frequency = 1000000;
- db8500_cpufreq_table[3].index = ARM_MAX_OPP;
+ db8500_cpufreq_table[3].driver_data = ARM_MAX_OPP;
}
}
diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h
index d14836ed2114..4f6f0fa5d3b7 100644
--- a/drivers/mfd/dbx500-prcmu-regs.h
+++ b/drivers/mfd/dbx500-prcmu-regs.h
@@ -16,8 +16,8 @@
#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
#define PRCM_ACLK_MGT (0x004)
-#define PRCM_SVACLK_MGT (0x008)
-#define PRCM_SIACLK_MGT (0x00C)
+#define PRCM_SVAMMCSPCLK_MGT (0x008)
+#define PRCM_SIAMMDSPCLK_MGT (0x00C)
#define PRCM_SGACLK_MGT (0x014)
#define PRCM_UARTCLK_MGT (0x018)
#define PRCM_MSP02CLK_MGT (0x01C)
@@ -32,6 +32,7 @@
#define PRCM_PER7CLK_MGT (0x040)
#define PRCM_LCDCLK_MGT (0x044)
#define PRCM_BMLCLK_MGT (0x04C)
+#define PRCM_BML8580CLK_MGT (0x108)
#define PRCM_HSITXCLK_MGT (0x050)
#define PRCM_HSIRXCLK_MGT (0x054)
#define PRCM_HDMICLK_MGT (0x058)
diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c
index bbaec0ccba8f..26aca545084b 100644
--- a/drivers/mfd/htc-egpio.c
+++ b/drivers/mfd/htc-egpio.c
@@ -270,7 +270,7 @@ static int __init egpio_probe(struct platform_device *pdev)
int ret;
/* Initialize ei data structure. */
- ei = kzalloc(sizeof(*ei), GFP_KERNEL);
+ ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL);
if (!ei)
return -ENOMEM;
@@ -286,7 +286,8 @@ static int __init egpio_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
goto fail;
- ei->base_addr = ioremap_nocache(res->start, resource_size(res));
+ ei->base_addr = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
if (!ei->base_addr)
goto fail;
pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
@@ -306,7 +307,9 @@ static int __init egpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ei);
ei->nchips = pdata->num_chips;
- ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL);
+ ei->chip = devm_kzalloc(&pdev->dev,
+ sizeof(struct egpio_chip) * ei->nchips,
+ GFP_KERNEL);
if (!ei->chip) {
ret = -ENOMEM;
goto fail;
@@ -361,7 +364,6 @@ static int __init egpio_probe(struct platform_device *pdev)
fail:
printk(KERN_ERR "EGPIO failed to setup\n");
- kfree(ei);
return ret;
}
@@ -379,9 +381,6 @@ static int __exit egpio_remove(struct platform_device *pdev)
irq_set_chained_handler(ei->chained_irq, NULL);
device_init_wakeup(&pdev->dev, 0);
}
- iounmap(ei->base_addr);
- kfree(ei->chip);
- kfree(ei);
return 0;
}
diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c
index 324187c0c124..c9dfce6ae0c2 100644
--- a/drivers/mfd/htc-i2cpld.c
+++ b/drivers/mfd/htc-i2cpld.c
@@ -514,8 +514,8 @@ static int htcpld_setup_chips(struct platform_device *pdev)
/* Setup each chip's output GPIOs */
htcpld->nchips = pdata->num_chip;
- htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips,
- GFP_KERNEL);
+ htcpld->chip = devm_kzalloc(dev, sizeof(struct htcpld_chip) * htcpld->nchips,
+ GFP_KERNEL);
if (!htcpld->chip) {
dev_warn(dev, "Unable to allocate memory for chips\n");
return -ENOMEM;
@@ -580,12 +580,11 @@ static int htcpld_core_probe(struct platform_device *pdev)
return -ENXIO;
}
- htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL);
+ htcpld = devm_kzalloc(dev, sizeof(struct htcpld_data), GFP_KERNEL);
if (!htcpld)
return -ENOMEM;
/* Find chained irq */
- ret = -EINVAL;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
int flags;
@@ -598,7 +597,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
flags, pdev->name, htcpld);
if (ret) {
dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret);
- goto fail;
+ return ret;
} else
device_init_wakeup(dev, 0);
}
@@ -609,7 +608,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
/* Setup the htcpld chips */
ret = htcpld_setup_chips(pdev);
if (ret)
- goto fail;
+ return ret;
/* Request the GPIO(s) for the int reset and set them up */
if (pdata->int_reset_gpio_hi) {
@@ -644,10 +643,6 @@ static int htcpld_core_probe(struct platform_device *pdev)
dev_info(dev, "Initialized successfully\n");
return 0;
-
-fail:
- kfree(htcpld);
- return ret;
}
/* The I2C Driver -- used internally */
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index 0285fceb99a6..0a5e85fd8517 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -147,7 +147,7 @@ static int __init pasic3_probe(struct platform_device *pdev)
if (!request_mem_region(r->start, resource_size(r), "pasic3"))
return -EBUSY;
- asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL);
+ asic = devm_kzalloc(dev, sizeof(struct pasic3_data), GFP_KERNEL);
if (!asic)
return -ENOMEM;
@@ -156,7 +156,6 @@ static int __init pasic3_probe(struct platform_device *pdev)
asic->mapping = ioremap(r->start, resource_size(r));
if (!asic->mapping) {
dev_err(dev, "couldn't ioremap PASIC3\n");
- kfree(asic);
return -ENOMEM;
}
@@ -195,7 +194,6 @@ static int pasic3_remove(struct platform_device *pdev)
iounmap(asic->mapping);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, resource_size(r));
- kfree(asic);
return 0;
}
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index d8d5137f9717..4f2462f0963e 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -438,7 +438,6 @@ static int intel_msic_remove(struct platform_device *pdev)
struct intel_msic *msic = platform_get_drvdata(pdev);
intel_msic_remove_devices(msic);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
index 45ece11cc27c..fcbb2e9dfd37 100644
--- a/drivers/mfd/janz-cmodio.c
+++ b/drivers/mfd/janz-cmodio.c
@@ -183,11 +183,10 @@ static int cmodio_pci_probe(struct pci_dev *dev,
struct cmodio_device *priv;
int ret;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&dev->dev, "unable to allocate private data\n");
- ret = -ENOMEM;
- goto out_return;
+ return -ENOMEM;
}
pci_set_drvdata(dev, priv);
@@ -197,7 +196,7 @@ static int cmodio_pci_probe(struct pci_dev *dev,
ret = pci_enable_device(dev);
if (ret) {
dev_err(&dev->dev, "unable to enable device\n");
- goto out_free_priv;
+ return ret;
}
pci_set_master(dev);
@@ -248,9 +247,7 @@ out_pci_release_regions:
pci_release_regions(dev);
out_pci_disable_device:
pci_disable_device(dev);
-out_free_priv:
- kfree(priv);
-out_return:
+
return ret;
}
@@ -263,7 +260,6 @@ static void cmodio_pci_remove(struct pci_dev *dev)
iounmap(priv->ctrl);
pci_release_regions(dev);
pci_disable_device(dev);
- kfree(priv);
}
#define PCI_VENDOR_ID_JANZ 0x13c3
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index e80587f1a792..3c0e8cf6916b 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -86,13 +86,13 @@ static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc)
{
if (atomic_inc_return(&adc->clk_ref) == 1)
- clk_enable(adc->clk);
+ clk_prepare_enable(adc->clk);
}
static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc)
{
if (atomic_dec_return(&adc->clk_ref) == 0)
- clk_disable(adc->clk);
+ clk_disable_unprepare(adc->clk);
}
static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
@@ -294,7 +294,6 @@ static int jz4740_adc_probe(struct platform_device *pdev)
err_clk_put:
clk_put(adc->clk);
err_iounmap:
- platform_set_drvdata(pdev, NULL);
iounmap(adc->base);
err_release_mem_region:
release_mem_region(adc->mem->start, resource_size(adc->mem));
@@ -317,8 +316,6 @@ static int jz4740_adc_remove(struct platform_device *pdev)
clk_put(adc->clk);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c
new file mode 100644
index 000000000000..686a4565acb6
--- /dev/null
+++ b/drivers/mfd/kempld-core.c
@@ -0,0 +1,641 @@
+/*
+ * Kontron PLD MFD core driver
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/kempld.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define MAX_ID_LEN 4
+static char force_device_id[MAX_ID_LEN + 1] = "";
+module_param_string(force_device_id, force_device_id, sizeof(force_device_id), 0);
+MODULE_PARM_DESC(force_device_id, "Override detected product");
+
+/*
+ * Get hardware mutex to block firmware from accessing the pld.
+ * It is possible for the firmware may hold the mutex for an extended length of
+ * time. This function will block until access has been granted.
+ */
+static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
+{
+ /* The mutex bit will read 1 until access has been granted */
+ while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
+ msleep(1);
+}
+
+static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
+{
+ /* The harware mutex is released when 1 is written to the mutex bit. */
+ iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
+}
+
+static int kempld_get_info_generic(struct kempld_device_data *pld)
+{
+ u16 version;
+ u8 spec;
+
+ kempld_get_mutex(pld);
+
+ version = kempld_read16(pld, KEMPLD_VERSION);
+ spec = kempld_read8(pld, KEMPLD_SPEC);
+ pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
+
+ pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
+ pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
+ pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
+ pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
+
+ if (spec == 0xff) {
+ pld->info.spec_minor = 0;
+ pld->info.spec_major = 1;
+ } else {
+ pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
+ pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
+ }
+
+ if (pld->info.spec_major > 0)
+ pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
+ else
+ pld->feature_mask = 0;
+
+ kempld_release_mutex(pld);
+
+ return 0;
+}
+
+enum kempld_cells {
+ KEMPLD_I2C = 0,
+ KEMPLD_WDT,
+ KEMPLD_GPIO,
+ KEMPLD_UART,
+};
+
+static struct mfd_cell kempld_devs[] = {
+ [KEMPLD_I2C] = {
+ .name = "kempld-i2c",
+ },
+ [KEMPLD_WDT] = {
+ .name = "kempld-wdt",
+ },
+ [KEMPLD_GPIO] = {
+ .name = "kempld-gpio",
+ },
+ [KEMPLD_UART] = {
+ .name = "kempld-uart",
+ },
+};
+
+#define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_devs)
+
+static int kempld_register_cells_generic(struct kempld_device_data *pld)
+{
+ struct mfd_cell devs[KEMPLD_MAX_DEVS];
+ int i = 0;
+
+ if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
+ devs[i++] = kempld_devs[KEMPLD_I2C];
+
+ if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
+ devs[i++] = kempld_devs[KEMPLD_WDT];
+
+ if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
+ devs[i++] = kempld_devs[KEMPLD_GPIO];
+
+ if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
+ devs[i++] = kempld_devs[KEMPLD_UART];
+
+ return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
+}
+
+static struct resource kempld_ioresource = {
+ .start = KEMPLD_IOINDEX,
+ .end = KEMPLD_IODATA,
+ .flags = IORESOURCE_IO,
+};
+
+static const struct kempld_platform_data kempld_platform_data_generic = {
+ .pld_clock = KEMPLD_CLK,
+ .ioresource = &kempld_ioresource,
+ .get_hardware_mutex = kempld_get_hardware_mutex,
+ .release_hardware_mutex = kempld_release_hardware_mutex,
+ .get_info = kempld_get_info_generic,
+ .register_cells = kempld_register_cells_generic,
+};
+
+static struct platform_device *kempld_pdev;
+
+static int kempld_create_platform_device(const struct dmi_system_id *id)
+{
+ struct kempld_platform_data *pdata = id->driver_data;
+ int ret;
+
+ kempld_pdev = platform_device_alloc("kempld", -1);
+ if (!kempld_pdev)
+ return -ENOMEM;
+
+ ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
+ if (ret)
+ goto err;
+
+ ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
+ if (ret)
+ goto err;
+
+ ret = platform_device_add(kempld_pdev);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ platform_device_put(kempld_pdev);
+ return ret;
+}
+
+/**
+ * kempld_read8 - read 8 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+u8 kempld_read8(struct kempld_device_data *pld, u8 index)
+{
+ iowrite8(index, pld->io_index);
+ return ioread8(pld->io_data);
+}
+EXPORT_SYMBOL_GPL(kempld_read8);
+
+/**
+ * kempld_write8 - write 8 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ * @data: new register value
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
+{
+ iowrite8(index, pld->io_index);
+ iowrite8(data, pld->io_data);
+}
+EXPORT_SYMBOL_GPL(kempld_write8);
+
+/**
+ * kempld_read16 - read 16 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+u16 kempld_read16(struct kempld_device_data *pld, u8 index)
+{
+ return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
+}
+EXPORT_SYMBOL_GPL(kempld_read16);
+
+/**
+ * kempld_write16 - write 16 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ * @data: new register value
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
+{
+ kempld_write8(pld, index, (u8)data);
+ kempld_write8(pld, index + 1, (u8)(data >> 8));
+}
+EXPORT_SYMBOL_GPL(kempld_write16);
+
+/**
+ * kempld_read32 - read 32 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+u32 kempld_read32(struct kempld_device_data *pld, u8 index)
+{
+ return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
+}
+EXPORT_SYMBOL_GPL(kempld_read32);
+
+/**
+ * kempld_write32 - write 32 bit register
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ * @data: new register value
+ *
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
+{
+ kempld_write16(pld, index, (u16)data);
+ kempld_write16(pld, index + 2, (u16)(data >> 16));
+}
+EXPORT_SYMBOL_GPL(kempld_write32);
+
+/**
+ * kempld_get_mutex - acquire PLD mutex
+ * @pld: kempld_device_data structure describing the PLD
+ */
+void kempld_get_mutex(struct kempld_device_data *pld)
+{
+ struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+ mutex_lock(&pld->lock);
+ pdata->get_hardware_mutex(pld);
+}
+EXPORT_SYMBOL_GPL(kempld_get_mutex);
+
+/**
+ * kempld_release_mutex - release PLD mutex
+ * @pld: kempld_device_data structure describing the PLD
+ */
+void kempld_release_mutex(struct kempld_device_data *pld)
+{
+ struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+ pdata->release_hardware_mutex(pld);
+ mutex_unlock(&pld->lock);
+}
+EXPORT_SYMBOL_GPL(kempld_release_mutex);
+
+/**
+ * kempld_get_info - update device specific information
+ * @pld: kempld_device_data structure describing the PLD
+ *
+ * This function calls the configured board specific kempld_get_info_XXXX
+ * function which is responsible for gathering information about the specific
+ * hardware. The information is then stored within the pld structure.
+ */
+static int kempld_get_info(struct kempld_device_data *pld)
+{
+ struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+ return pdata->get_info(pld);
+}
+
+/*
+ * kempld_register_cells - register cell drivers
+ *
+ * This function registers cell drivers for the detected hardware by calling
+ * the configured kempld_register_cells_XXXX function which is responsible
+ * to detect and register the needed cell drivers.
+ */
+static int kempld_register_cells(struct kempld_device_data *pld)
+{
+ struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+ return pdata->register_cells(pld);
+}
+
+static int kempld_detect_device(struct kempld_device_data *pld)
+{
+ char *version_type;
+ u8 index_reg;
+ int ret;
+
+ mutex_lock(&pld->lock);
+
+ /* Check for empty IO space */
+ index_reg = ioread8(pld->io_index);
+ if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
+ mutex_unlock(&pld->lock);
+ return -ENODEV;
+ }
+
+ /* Release hardware mutex if aquired */
+ if (!(index_reg & KEMPLD_MUTEX_KEY))
+ iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
+
+ mutex_unlock(&pld->lock);
+
+ ret = kempld_get_info(pld);
+ if (ret)
+ return ret;
+
+ switch (pld->info.type) {
+ case 0:
+ version_type = "release";
+ break;
+ case 1:
+ version_type = "debug";
+ break;
+ case 2:
+ version_type = "custom";
+ break;
+ default:
+ version_type = "unspecified";
+ }
+
+ dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number);
+ dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n",
+ version_type, pld->info.major, pld->info.minor,
+ pld->info.buildnr, pld->info.spec_major,
+ pld->info.spec_minor);
+
+ return kempld_register_cells(pld);
+}
+
+static int kempld_probe(struct platform_device *pdev)
+{
+ struct kempld_platform_data *pdata = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct kempld_device_data *pld;
+ struct resource *ioport;
+ int ret;
+
+ pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
+ if (!pld)
+ return -ENOMEM;
+
+ ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!ioport)
+ return -EINVAL;
+
+ pld->io_base = devm_ioport_map(dev, ioport->start,
+ ioport->end - ioport->start);
+ if (!pld->io_base)
+ return -ENOMEM;
+
+ pld->io_index = pld->io_base;
+ pld->io_data = pld->io_base + 1;
+ pld->pld_clock = pdata->pld_clock;
+ pld->dev = dev;
+
+ mutex_init(&pld->lock);
+ platform_set_drvdata(pdev, pld);
+
+ ret = kempld_detect_device(pld);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int kempld_remove(struct platform_device *pdev)
+{
+ struct kempld_device_data *pld = platform_get_drvdata(pdev);
+ struct kempld_platform_data *pdata = pld->dev->platform_data;
+
+ mfd_remove_devices(&pdev->dev);
+ pdata->release_hardware_mutex(pld);
+
+ return 0;
+}
+
+static struct platform_driver kempld_driver = {
+ .driver = {
+ .name = "kempld",
+ .owner = THIS_MODULE,
+ },
+ .probe = kempld_probe,
+ .remove = kempld_remove,
+};
+
+static struct dmi_system_id __initdata kempld_dmi_table[] = {
+ {
+ .ident = "CCR2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CCR6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CHR2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CHR2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CHR2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CHR6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CHR6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CHR6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CNTG",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CNTG",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "CNTX",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "PXT"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "FRI2",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "FRI2",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "MBR1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "NTC1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "NTC1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "NTC1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "NUP1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "UNP1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "UNP1",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "UNTG",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "UNTG",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ }, {
+ .ident = "UUP6",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+ DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
+ },
+ .driver_data = (void *)&kempld_platform_data_generic,
+ .callback = kempld_create_platform_device,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
+
+static int __init kempld_init(void)
+{
+ const struct dmi_system_id *id;
+ int ret;
+
+ if (force_device_id[0]) {
+ for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++)
+ if (strstr(id->ident, force_device_id))
+ if (id->callback && id->callback(id))
+ break;
+ if (id->matches[0].slot == DMI_NONE)
+ return -ENODEV;
+ } else {
+ if (!dmi_check_system(kempld_dmi_table))
+ return -ENODEV;
+ }
+
+ ret = platform_driver_register(&kempld_driver);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void __exit kempld_exit(void)
+{
+ if (kempld_pdev)
+ platform_device_unregister(kempld_pdev);
+
+ platform_driver_unregister(&kempld_driver);
+}
+
+module_init(kempld_init);
+module_exit(kempld_exit);
+
+MODULE_DESCRIPTION("KEM PLD Core Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld-core");
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
index 9f12f91d6296..24033324c17a 100644
--- a/drivers/mfd/lpc_ich.c
+++ b/drivers/mfd/lpc_ich.c
@@ -51,6 +51,8 @@
* document number TBD : Lynx Point
* document number TBD : Lynx Point-LP
* document number TBD : Wellsburg
+ * document number TBD : Avoton SoC
+ * document number TBD : Coleto Creek
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -207,6 +209,8 @@ enum lpc_chipsets {
LPC_LPT, /* Lynx Point */
LPC_LPT_LP, /* Lynx Point-LP */
LPC_WBG, /* Wellsburg */
+ LPC_AVN, /* Avoton SoC */
+ LPC_COLETO, /* Coleto Creek */
};
struct lpc_ich_info lpc_chipset_info[] = {
@@ -491,6 +495,14 @@ struct lpc_ich_info lpc_chipset_info[] = {
.name = "Wellsburg",
.iTCO_version = 2,
},
+ [LPC_AVN] = {
+ .name = "Avoton SoC",
+ .iTCO_version = 1,
+ },
+ [LPC_COLETO] = {
+ .name = "Coleto Creek",
+ .iTCO_version = 2,
+ },
};
/*
@@ -704,6 +716,11 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
{ PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG},
{ PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG},
+ { PCI_VDEVICE(INTEL, 0x1f38), LPC_AVN},
+ { PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN},
+ { PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN},
+ { PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN},
+ { PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO},
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
@@ -973,18 +990,7 @@ static struct pci_driver lpc_ich_driver = {
.remove = lpc_ich_remove,
};
-static int __init lpc_ich_init(void)
-{
- return pci_register_driver(&lpc_ich_driver);
-}
-
-static void __exit lpc_ich_exit(void)
-{
- pci_unregister_driver(&lpc_ich_driver);
-}
-
-module_init(lpc_ich_init);
-module_exit(lpc_ich_exit);
+module_pci_driver(lpc_ich_driver);
MODULE_AUTHOR("Aaron Sierra <asierra@xes-inc.com>");
MODULE_DESCRIPTION("LPC interface for Intel ICH");
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index 1cbb17609c8b..f27a21831583 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -37,6 +37,7 @@
static struct mfd_cell max77686_devs[] = {
{ .name = "max77686-pmic", },
{ .name = "max77686-rtc", },
+ { .name = "max77686-clk", },
};
static struct regmap_config max77686_regmap_config = {
@@ -84,12 +85,12 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
pdata = max77686_i2c_parse_dt_pdata(&i2c->dev);
if (!pdata) {
- ret = -EIO;
dev_err(&i2c->dev, "No platform data found.\n");
- goto err;
+ return -EIO;
}
- max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL);
+ max77686 = devm_kzalloc(&i2c->dev,
+ sizeof(struct max77686_dev), GFP_KERNEL);
if (max77686 == NULL)
return -ENOMEM;
@@ -107,7 +108,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(max77686->regmap);
dev_err(max77686->dev, "Failed to allocate register map: %d\n",
ret);
- kfree(max77686);
return ret;
}
@@ -115,8 +115,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
MAX77686_REG_DEVICE_ID, &data) < 0) {
dev_err(max77686->dev,
"device not found on this channel (this is not an error)\n");
- ret = -ENODEV;
- goto err;
+ return -ENODEV;
} else
dev_info(max77686->dev, "device found\n");
@@ -127,17 +126,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
ret = mfd_add_devices(max77686->dev, -1, max77686_devs,
ARRAY_SIZE(max77686_devs), NULL, 0, NULL);
+ if (ret < 0) {
+ mfd_remove_devices(max77686->dev);
+ i2c_unregister_device(max77686->rtc);
+ }
- if (ret < 0)
- goto err_mfd;
-
- return ret;
-
-err_mfd:
- mfd_remove_devices(max77686->dev);
- i2c_unregister_device(max77686->rtc);
-err:
- kfree(max77686);
return ret;
}
@@ -147,7 +140,6 @@ static int max77686_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(max77686->dev);
i2c_unregister_device(max77686->rtc);
- kfree(max77686);
return 0;
}
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 92bbebd31598..8042b3205eaa 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -170,7 +170,8 @@ static int max8925_probe(struct i2c_client *client,
return -EINVAL;
}
- chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev,
+ sizeof(struct max8925_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->i2c = client;
@@ -199,7 +200,6 @@ static int max8925_remove(struct i2c_client *client)
max8925_device_exit(chip);
i2c_unregister_device(chip->adc);
i2c_unregister_device(chip->rtc);
- kfree(chip);
return 0;
}
diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c
index 5919710dc9ed..c469477eb778 100644
--- a/drivers/mfd/max8998-irq.c
+++ b/drivers/mfd/max8998-irq.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/mfd/max8998-private.h>
struct max8998_irq_data {
@@ -99,7 +100,8 @@ static struct max8998_irq_data max8998_irqs[] = {
static inline struct max8998_irq_data *
irq_to_max8998_irq(struct max8998_dev *max8998, int irq)
{
- return &max8998_irqs[irq - max8998->irq_base];
+ struct irq_data *data = irq_get_irq_data(irq);
+ return &max8998_irqs[data->hwirq];
}
static void max8998_irq_lock(struct irq_data *data)
@@ -176,8 +178,14 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
/* Report */
for (i = 0; i < MAX8998_IRQ_NR; i++) {
- if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask)
- handle_nested_irq(max8998->irq_base + i);
+ if (irq_reg[max8998_irqs[i].reg - 1] & max8998_irqs[i].mask) {
+ irq = irq_find_mapping(max8998->irq_domain, i);
+ if (WARN_ON(!irq)) {
+ disable_irq_nosync(max8998->irq);
+ return IRQ_NONE;
+ }
+ handle_nested_irq(irq);
+ }
}
return IRQ_HANDLED;
@@ -185,27 +193,40 @@ static irqreturn_t max8998_irq_thread(int irq, void *data)
int max8998_irq_resume(struct max8998_dev *max8998)
{
- if (max8998->irq && max8998->irq_base)
- max8998_irq_thread(max8998->irq_base, max8998);
+ if (max8998->irq && max8998->irq_domain)
+ max8998_irq_thread(max8998->irq, max8998);
+ return 0;
+}
+
+static int max8998_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ struct max8997_dev *max8998 = d->host_data;
+
+ irq_set_chip_data(irq, max8998);
+ irq_set_chip_and_handler(irq, &max8998_irq_chip, handle_edge_irq);
+ irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
return 0;
}
+static struct irq_domain_ops max8998_irq_domain_ops = {
+ .map = max8998_irq_domain_map,
+};
+
int max8998_irq_init(struct max8998_dev *max8998)
{
int i;
- int cur_irq;
int ret;
+ struct irq_domain *domain;
if (!max8998->irq) {
dev_warn(max8998->dev,
"No interrupt specified, no interrupts\n");
- max8998->irq_base = 0;
- return 0;
- }
-
- if (!max8998->irq_base) {
- dev_err(max8998->dev,
- "No interrupt base specified, no interrupts\n");
return 0;
}
@@ -221,19 +242,13 @@ int max8998_irq_init(struct max8998_dev *max8998)
max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff);
max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff);
- /* register with genirq */
- for (i = 0; i < MAX8998_IRQ_NR; i++) {
- cur_irq = i + max8998->irq_base;
- irq_set_chip_data(cur_irq, max8998);
- irq_set_chip_and_handler(cur_irq, &max8998_irq_chip,
- handle_edge_irq);
- irq_set_nested_thread(cur_irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
-#else
- irq_set_noprobe(cur_irq);
-#endif
+ domain = irq_domain_add_simple(NULL, MAX8998_IRQ_NR,
+ max8998->irq_base, &max8998_irq_domain_ops, max8998);
+ if (!domain) {
+ dev_err(max8998->dev, "could not create irq domain\n");
+ return -ENODEV;
}
+ max8998->irq_domain = domain;
ret = request_threaded_irq(max8998->irq, NULL, max8998_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index d7218cc90945..21af51a499f4 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -20,12 +20,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
@@ -128,6 +131,56 @@ int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask)
}
EXPORT_SYMBOL(max8998_update_reg);
+#ifdef CONFIG_OF
+static struct of_device_id max8998_dt_match[] = {
+ { .compatible = "maxim,max8998", .data = (void *)TYPE_MAX8998 },
+ { .compatible = "national,lp3974", .data = (void *)TYPE_LP3974 },
+ { .compatible = "ti,lp3974", .data = (void *)TYPE_LP3974 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, max8998_dt_match);
+#endif
+
+/*
+ * Only the common platform data elements for max8998 are parsed here from the
+ * device tree. Other sub-modules of max8998 such as pmic, rtc and others have
+ * to parse their own platform data elements from device tree.
+ *
+ * The max8998 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct max8998_platform_data *max8998_i2c_parse_dt_pdata(
+ struct device *dev)
+{
+ struct max8998_platform_data *pd;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ pd->ono = irq_of_parse_and_map(dev->of_node, 1);
+
+ /*
+ * ToDo: the 'wakeup' member in the platform data is more of a linux
+ * specfic information. Hence, there is no binding for that yet and
+ * not parsed here.
+ */
+ return pd;
+}
+
+static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
+ const struct of_device_id *match;
+ match = of_match_node(max8998_dt_match, i2c->dev.of_node);
+ return (int)match->data;
+ }
+
+ return (int)id->driver_data;
+}
+
static int max8998_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -139,11 +192,20 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (max8998 == NULL)
return -ENOMEM;
+ if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) {
+ pdata = max8998_i2c_parse_dt_pdata(&i2c->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ goto err;
+ }
+ }
+
i2c_set_clientdata(i2c, max8998);
max8998->dev = &i2c->dev;
max8998->i2c = i2c;
max8998->irq = i2c->irq;
- max8998->type = id->driver_data;
+ max8998->type = max8998_i2c_get_driver_data(i2c, id);
+ max8998->pdata = pdata;
if (pdata) {
max8998->ono = pdata->ono;
max8998->irq_base = pdata->irq_base;
@@ -158,7 +220,7 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
pm_runtime_set_active(max8998->dev);
- switch (id->driver_data) {
+ switch (max8998->type) {
case TYPE_LP3974:
ret = mfd_add_devices(max8998->dev, -1,
lp3974_devs, ARRAY_SIZE(lp3974_devs),
@@ -314,6 +376,7 @@ static struct i2c_driver max8998_i2c_driver = {
.name = "max8998",
.owner = THIS_MODULE,
.pm = &max8998_pm,
+ .of_match_table = of_match_ptr(max8998_dt_match),
},
.probe = max8998_i2c_probe,
.remove = max8998_i2c_remove,
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index f99d6299ec24..13198d937e36 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -225,8 +225,6 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
if (ret == 0)
return 0;
- platform_set_drvdata(dev, NULL);
-
err_ioremap:
iounmap(m->base1);
iounmap(m->base0);
@@ -252,7 +250,6 @@ static int mcp_sa11x0_remove(struct platform_device *dev)
mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1);
- platform_set_drvdata(dev, NULL);
mcp_host_del(mcp);
iounmap(m->base1);
iounmap(m->base0);
diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c
index 53e9fe638d32..e4d1c706df8b 100644
--- a/drivers/mfd/palmas.c
+++ b/drivers/mfd/palmas.c
@@ -23,78 +23,7 @@
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/palmas.h>
-#include <linux/of_platform.h>
-
-enum palmas_ids {
- PALMAS_PMIC_ID,
- PALMAS_GPIO_ID,
- PALMAS_LEDS_ID,
- PALMAS_WDT_ID,
- PALMAS_RTC_ID,
- PALMAS_PWRBUTTON_ID,
- PALMAS_GPADC_ID,
- PALMAS_RESOURCE_ID,
- PALMAS_CLK_ID,
- PALMAS_PWM_ID,
- PALMAS_USB_ID,
-};
-
-static struct resource palmas_rtc_resources[] = {
- {
- .start = PALMAS_RTC_ALARM_IRQ,
- .end = PALMAS_RTC_ALARM_IRQ,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static const struct mfd_cell palmas_children[] = {
- {
- .name = "palmas-pmic",
- .id = PALMAS_PMIC_ID,
- },
- {
- .name = "palmas-gpio",
- .id = PALMAS_GPIO_ID,
- },
- {
- .name = "palmas-leds",
- .id = PALMAS_LEDS_ID,
- },
- {
- .name = "palmas-wdt",
- .id = PALMAS_WDT_ID,
- },
- {
- .name = "palmas-rtc",
- .id = PALMAS_RTC_ID,
- .resources = &palmas_rtc_resources[0],
- .num_resources = ARRAY_SIZE(palmas_rtc_resources),
- },
- {
- .name = "palmas-pwrbutton",
- .id = PALMAS_PWRBUTTON_ID,
- },
- {
- .name = "palmas-gpadc",
- .id = PALMAS_GPADC_ID,
- },
- {
- .name = "palmas-resource",
- .id = PALMAS_RESOURCE_ID,
- },
- {
- .name = "palmas-clk",
- .id = PALMAS_CLK_ID,
- },
- {
- .name = "palmas-pwm",
- .id = PALMAS_PWM_ID,
- },
- {
- .name = "palmas-usb",
- .id = PALMAS_USB_ID,
- }
-};
+#include <linux/of_device.h>
static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
{
@@ -302,6 +231,21 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c,
palmas_set_pdata_irq_flag(i2c, pdata);
}
+static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST;
+static unsigned int tps659038_features;
+
+static const struct of_device_id of_palmas_match_tbl[] = {
+ {
+ .compatible = "ti,palmas",
+ .data = &palmas_features,
+ },
+ {
+ .compatible = "ti,tps659038",
+ .data = &tps659038_features,
+ },
+ { },
+};
+
static int palmas_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -309,9 +253,9 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
struct palmas_platform_data *pdata;
struct device_node *node = i2c->dev.of_node;
int ret = 0, i;
- unsigned int reg, addr;
+ unsigned int reg, addr, *features;
int slave;
- struct mfd_cell *children;
+ const struct of_device_id *match;
pdata = dev_get_platdata(&i2c->dev);
@@ -333,9 +277,16 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, palmas);
palmas->dev = &i2c->dev;
- palmas->id = id->driver_data;
palmas->irq = i2c->irq;
+ match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev);
+
+ if (!match)
+ return -ENODATA;
+
+ features = (unsigned int *)match->data;
+ palmas->features = *features;
+
for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
if (i == 0)
palmas->i2c_clients[i] = i2c;
@@ -362,6 +313,11 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
}
}
+ if (!palmas->irq) {
+ dev_warn(palmas->dev, "IRQ missing: skipping irq request\n");
+ goto no_irq;
+ }
+
/* Change interrupt line output polarity */
if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH)
reg = PALMAS_POLARITY_CTRL_INT_POLARITY;
@@ -388,6 +344,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
goto err;
+no_irq:
slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
PALMAS_PRIMARY_SECONDARY_PAD1);
@@ -472,42 +429,8 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
return ret;
}
- children = kmemdup(palmas_children, sizeof(palmas_children),
- GFP_KERNEL);
- if (!children) {
- ret = -ENOMEM;
- goto err_irq;
- }
-
- children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata;
- children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata);
-
- children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata;
- children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata);
-
- children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata;
- children[PALMAS_RESOURCE_ID].pdata_size =
- sizeof(*pdata->resource_pdata);
-
- children[PALMAS_USB_ID].platform_data = pdata->usb_pdata;
- children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata);
-
- children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata;
- children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata);
-
- ret = mfd_add_devices(palmas->dev, -1,
- children, ARRAY_SIZE(palmas_children),
- NULL, 0,
- regmap_irq_get_domain(palmas->irq_data));
- kfree(children);
-
- if (ret < 0)
- goto err_devices;
-
return ret;
-err_devices:
- mfd_remove_devices(palmas->dev);
err_irq:
regmap_del_irq_chip(palmas->irq, palmas->irq_data);
err:
@@ -533,11 +456,6 @@ static const struct i2c_device_id palmas_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
-static struct of_device_id of_palmas_match_tbl[] = {
- { .compatible = "ti,palmas", },
- { /* end */ }
-};
-
static struct i2c_driver palmas_i2c_driver = {
.driver = {
.name = "palmas",
diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c
index 2a2d31687b72..c436bf27e78d 100644
--- a/drivers/mfd/rtl8411.c
+++ b/drivers/mfd/rtl8411.c
@@ -35,12 +35,33 @@ static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr)
return val & 0x0F;
}
+static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
+{
+ u8 val = 0;
+
+ rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val);
+
+ if (val & 0x2)
+ return 1;
+ else
+ return 0;
+}
+
static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, CD_PAD_CTL,
CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
}
+static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
+{
+ if (rtl8411b_is_qfn48(pcr))
+ rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5);
+
+ return rtsx_pci_write_register(pcr, CD_PAD_CTL,
+ CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
+}
+
static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00);
@@ -214,6 +235,20 @@ static const struct pcr_ops rtl8411_pcr_ops = {
.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
};
+static const struct pcr_ops rtl8411b_pcr_ops = {
+ .extra_init_hw = rtl8411b_extra_init_hw,
+ .optimize_phy = NULL,
+ .turn_on_led = rtl8411_turn_on_led,
+ .turn_off_led = rtl8411_turn_off_led,
+ .enable_auto_blink = rtl8411_enable_auto_blink,
+ .disable_auto_blink = rtl8411_disable_auto_blink,
+ .card_power_on = rtl8411_card_power_on,
+ .card_power_off = rtl8411_card_power_off,
+ .switch_output_voltage = rtl8411_switch_output_voltage,
+ .cd_deglitch = rtl8411_cd_deglitch,
+ .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+};
+
/* SD Pull Control Enable:
* SD_DAT[3:0] ==> pull up
* SD_CD ==> pull up
@@ -276,6 +311,74 @@ static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = {
0,
};
+static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA),
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0),
+ RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+ RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+ RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65),
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0),
+ RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
+static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = {
+ RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
+ RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90),
+ RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11),
+ 0,
+};
+
void rtl8411_init_params(struct rtsx_pcr *pcr)
{
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
@@ -288,3 +391,32 @@ void rtl8411_init_params(struct rtsx_pcr *pcr)
pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl;
pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl;
}
+
+void rtl8411b_init_params(struct rtsx_pcr *pcr)
+{
+ pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
+ pcr->num_slots = 2;
+ pcr->ops = &rtl8411b_pcr_ops;
+
+ pcr->ic_version = rtl8411_get_ic_version(pcr);
+
+ if (rtl8411b_is_qfn48(pcr)) {
+ pcr->sd_pull_ctl_enable_tbl =
+ rtl8411b_qfn48_sd_pull_ctl_enable_tbl;
+ pcr->sd_pull_ctl_disable_tbl =
+ rtl8411b_qfn48_sd_pull_ctl_disable_tbl;
+ pcr->ms_pull_ctl_enable_tbl =
+ rtl8411b_qfn48_ms_pull_ctl_enable_tbl;
+ pcr->ms_pull_ctl_disable_tbl =
+ rtl8411b_qfn48_ms_pull_ctl_disable_tbl;
+ } else {
+ pcr->sd_pull_ctl_enable_tbl =
+ rtl8411b_qfn64_sd_pull_ctl_enable_tbl;
+ pcr->sd_pull_ctl_disable_tbl =
+ rtl8411b_qfn64_sd_pull_ctl_disable_tbl;
+ pcr->ms_pull_ctl_enable_tbl =
+ rtl8411b_qfn64_ms_pull_ctl_enable_tbl;
+ pcr->ms_pull_ctl_disable_tbl =
+ rtl8411b_qfn64_ms_pull_ctl_disable_tbl;
+ }
+}
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index e968c01ca2ac..dd186c4103c1 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -57,6 +57,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+ { PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, }
};
@@ -1038,6 +1039,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
case 0x5249:
rts5249_init_params(pcr);
break;
+
+ case 0x5287:
+ rtl8411b_init_params(pcr);
+ break;
}
dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
index 55fcfc25c4e4..c0cac7e8972f 100644
--- a/drivers/mfd/rtsx_pcr.h
+++ b/drivers/mfd/rtsx_pcr.h
@@ -33,5 +33,6 @@ void rts5229_init_params(struct rtsx_pcr *pcr);
void rtl8411_init_params(struct rtsx_pcr *pcr);
void rts5227_init_params(struct rtsx_pcr *pcr);
void rts5249_init_params(struct rtsx_pcr *pcr);
+void rtl8411b_init_params(struct rtsx_pcr *pcr);
#endif
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index 77ee26ef5941..79767681483a 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -25,6 +25,9 @@
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s5m8763.h>
+#include <linux/mfd/samsung/s5m8767.h>
#include <linux/regmap.h>
static struct mfd_cell s5m8751_devs[] = {
@@ -105,6 +108,26 @@ static struct regmap_config sec_regmap_config = {
.val_bits = 8,
};
+static struct regmap_config s2mps11_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS11_REG_L38CTRL,
+};
+
+static struct regmap_config s5m8763_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S5M8763_REG_LBCNFG2,
+};
+
+static struct regmap_config s5m8767_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S5M8767_REG_LDO28CTRL,
+};
#ifdef CONFIG_OF
/*
@@ -160,6 +183,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct sec_platform_data *pdata = i2c->dev.platform_data;
+ const struct regmap_config *regmap;
struct sec_pmic_dev *sec_pmic;
int ret;
@@ -190,7 +214,22 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_pmic->pdata = pdata;
}
- sec_pmic->regmap = devm_regmap_init_i2c(i2c, &sec_regmap_config);
+ switch (sec_pmic->device_type) {
+ case S2MPS11X:
+ regmap = &s2mps11_regmap_config;
+ break;
+ case S5M8763X:
+ regmap = &s5m8763_regmap_config;
+ break;
+ case S5M8767X:
+ regmap = &s5m8767_regmap_config;
+ break;
+ default:
+ regmap = &sec_regmap_config;
+ break;
+ }
+
+ sec_pmic->regmap = devm_regmap_init_i2c(i2c, regmap);
if (IS_ERR(sec_pmic->regmap)) {
ret = PTR_ERR(sec_pmic->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -230,13 +269,12 @@ static int sec_pmic_probe(struct i2c_client *i2c,
BUG();
}
- if (ret < 0)
+ if (ret)
goto err;
return ret;
err:
- mfd_remove_devices(sec_pmic->dev);
sec_irq_exit(sec_pmic);
i2c_unregister_device(sec_pmic->rtc);
return ret;
diff --git a/drivers/ssbi/ssbi.c b/drivers/mfd/ssbi.c
index 102a22844297..102a22844297 100644
--- a/drivers/ssbi/ssbi.c
+++ b/drivers/mfd/ssbi.c
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index b32940ec9034..a21bff283a98 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -422,7 +422,6 @@ static int t7l66xb_remove(struct platform_device *dev)
iounmap(t7l66xb->scr);
release_resource(&t7l66xb->rscr);
mfd_remove_devices(&dev->dev);
- platform_set_drvdata(dev, NULL);
kfree(t7l66xb);
return ret;
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 366f7b906278..65c425a517c5 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -217,7 +217,6 @@ static int tc6387xb_remove(struct platform_device *dev)
release_resource(&tc6387xb->rscr);
clk_disable(tc6387xb->clk32k);
clk_put(tc6387xb->clk32k);
- platform_set_drvdata(dev, NULL);
kfree(tc6387xb);
return 0;
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 15e1463e5e13..a563dfa3cf87 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -756,7 +756,6 @@ static int tc6393xb_remove(struct platform_device *dev)
clk_disable(tc6393xb->clk);
iounmap(tc6393xb->scr);
release_resource(&tc6393xb->rscr);
- platform_set_drvdata(dev, NULL);
clk_put(tc6393xb->clk);
kfree(tc6393xb);
diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c
index e9f3fb510b44..b003a16ba227 100644
--- a/drivers/mfd/ti_am335x_tscadc.c
+++ b/drivers/mfd/ti_am335x_tscadc.c
@@ -22,10 +22,10 @@
#include <linux/regmap.h>
#include <linux/mfd/core.h>
#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/mfd/ti_am335x_tscadc.h>
-#include <linux/input/ti_am335x_tsc.h>
-#include <linux/platform_data/ti_am335x_adc.h>
static unsigned int tscadc_readl(struct ti_tscadc_dev *tsadc, unsigned int reg)
{
@@ -48,6 +48,32 @@ static const struct regmap_config tscadc_regmap_config = {
.val_bits = 32,
};
+void am335x_tsc_se_update(struct ti_tscadc_dev *tsadc)
+{
+ tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache);
+}
+EXPORT_SYMBOL_GPL(am335x_tsc_se_update);
+
+void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val)
+{
+ spin_lock(&tsadc->reg_lock);
+ tsadc->reg_se_cache |= val;
+ spin_unlock(&tsadc->reg_lock);
+
+ am335x_tsc_se_update(tsadc);
+}
+EXPORT_SYMBOL_GPL(am335x_tsc_se_set);
+
+void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val)
+{
+ spin_lock(&tsadc->reg_lock);
+ tsadc->reg_se_cache &= ~val;
+ spin_unlock(&tsadc->reg_lock);
+
+ am335x_tsc_se_update(tsadc);
+}
+EXPORT_SYMBOL_GPL(am335x_tsc_se_clr);
+
static void tscadc_idle_config(struct ti_tscadc_dev *config)
{
unsigned int idleconfig;
@@ -63,27 +89,48 @@ static int ti_tscadc_probe(struct platform_device *pdev)
struct ti_tscadc_dev *tscadc;
struct resource *res;
struct clk *clk;
- struct mfd_tscadc_board *pdata = pdev->dev.platform_data;
+ struct device_node *node = pdev->dev.of_node;
struct mfd_cell *cell;
+ struct property *prop;
+ const __be32 *cur;
+ u32 val;
int err, ctrl;
int clk_value, clock_rate;
- int tsc_wires, adc_channels = 0, total_channels;
+ int tsc_wires = 0, adc_channels = 0, total_channels;
+ int readouts = 0;
- if (!pdata) {
- dev_err(&pdev->dev, "Could not find platform data\n");
+ if (!pdev->dev.of_node) {
+ dev_err(&pdev->dev, "Could not find valid DT data.\n");
return -EINVAL;
}
- if (pdata->adc_init)
- adc_channels = pdata->adc_init->adc_channels;
-
- tsc_wires = pdata->tsc_init->wires;
+ node = of_get_child_by_name(pdev->dev.of_node, "tsc");
+ of_property_read_u32(node, "ti,wires", &tsc_wires);
+ of_property_read_u32(node, "ti,coordiante-readouts", &readouts);
+
+ node = of_get_child_by_name(pdev->dev.of_node, "adc");
+ of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) {
+ adc_channels++;
+ if (val > 7) {
+ dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n",
+ val);
+ return -EINVAL;
+ }
+ }
total_channels = tsc_wires + adc_channels;
-
if (total_channels > 8) {
dev_err(&pdev->dev, "Number of i/p channels more than 8\n");
return -EINVAL;
}
+ if (total_channels == 0) {
+ dev_err(&pdev->dev, "Need atleast one channel.\n");
+ return -EINVAL;
+ }
+
+ if (readouts * 2 + 2 + adc_channels > 16) {
+ dev_err(&pdev->dev, "Too many step configurations requested\n");
+ return -EINVAL;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -129,6 +176,7 @@ static int ti_tscadc_probe(struct platform_device *pdev)
goto ret;
}
+ spin_lock_init(&tscadc->reg_lock);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@@ -173,26 +221,37 @@ static int ti_tscadc_probe(struct platform_device *pdev)
ctrl |= CNTRLREG_TSCSSENB;
tscadc_writel(tscadc, REG_CTRL, ctrl);
+ tscadc->used_cells = 0;
+ tscadc->tsc_cell = -1;
+ tscadc->adc_cell = -1;
+
/* TSC Cell */
- cell = &tscadc->cells[TSC_CELL];
- cell->name = "tsc";
- cell->platform_data = tscadc;
- cell->pdata_size = sizeof(*tscadc);
+ if (tsc_wires > 0) {
+ tscadc->tsc_cell = tscadc->used_cells;
+ cell = &tscadc->cells[tscadc->used_cells++];
+ cell->name = "TI-am335x-tsc";
+ cell->of_compatible = "ti,am3359-tsc";
+ cell->platform_data = &tscadc;
+ cell->pdata_size = sizeof(tscadc);
+ }
/* ADC Cell */
- cell = &tscadc->cells[ADC_CELL];
- cell->name = "tiadc";
- cell->platform_data = tscadc;
- cell->pdata_size = sizeof(*tscadc);
+ if (adc_channels > 0) {
+ tscadc->adc_cell = tscadc->used_cells;
+ cell = &tscadc->cells[tscadc->used_cells++];
+ cell->name = "TI-am335x-adc";
+ cell->of_compatible = "ti,am3359-adc";
+ cell->platform_data = &tscadc;
+ cell->pdata_size = sizeof(tscadc);
+ }
err = mfd_add_devices(&pdev->dev, pdev->id, tscadc->cells,
- TSCADC_CELLS, NULL, 0, NULL);
+ tscadc->used_cells, NULL, 0, NULL);
if (err < 0)
goto err_disable_clk;
device_init_wakeup(&pdev->dev, true);
platform_set_drvdata(pdev, tscadc);
-
return 0;
err_disable_clk:
@@ -239,7 +298,7 @@ static int tscadc_resume(struct device *dev)
CNTRLREG_STEPID | CNTRLREG_4WIRE;
tscadc_writel(tscadc_dev, REG_CTRL, ctrl);
tscadc_idle_config(tscadc_dev);
- tscadc_writel(tscadc_dev, REG_SE, STPENB_STEPENB);
+ am335x_tsc_se_update(tscadc_dev);
restore = tscadc_readl(tscadc_dev, REG_CTRL);
tscadc_writel(tscadc_dev, REG_CTRL,
(restore | CNTRLREG_TSCSSENB));
@@ -256,11 +315,18 @@ static const struct dev_pm_ops tscadc_pm_ops = {
#define TSCADC_PM_OPS NULL
#endif
+static const struct of_device_id ti_tscadc_dt_ids[] = {
+ { .compatible = "ti,am3359-tscadc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids);
+
static struct platform_driver ti_tscadc_driver = {
.driver = {
- .name = "ti_tscadc",
+ .name = "ti_am3359-tscadc",
.owner = THIS_MODULE,
.pm = TSCADC_PM_OPS,
+ .of_match_table = of_match_ptr(ti_tscadc_dt_ids),
},
.probe = ti_tscadc_probe,
.remove = ti_tscadc_remove,
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index 59e0ee247e86..0c1fcbc23d04 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -145,7 +145,6 @@ static struct spi_board_info timberdale_spi_8bit_board_info[] = {
static struct xspi_platform_data timberdale_xspi_platform_data = {
.num_chipselect = 3,
- .little_endian = true,
/* bits per word and devices will be filled in runtime depending
* on the HW config
*/
diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c
index aeb8e40ab424..479886a4cf80 100644
--- a/drivers/mfd/tps65912-core.c
+++ b/drivers/mfd/tps65912-core.c
@@ -162,7 +162,6 @@ int tps65912_device_init(struct tps65912 *tps65912)
err:
kfree(init_data);
mfd_remove_devices(tps65912->dev);
- kfree(tps65912);
return ret;
}
@@ -170,7 +169,6 @@ void tps65912_device_exit(struct tps65912 *tps65912)
{
mfd_remove_devices(tps65912->dev);
tps65912_irq_exit(tps65912);
- kfree(tps65912);
}
MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>");
diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c
index c041f2c3d2bd..6a6343ee95fe 100644
--- a/drivers/mfd/tps65912-i2c.c
+++ b/drivers/mfd/tps65912-i2c.c
@@ -77,7 +77,8 @@ static int tps65912_i2c_probe(struct i2c_client *i2c,
{
struct tps65912 *tps65912;
- tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+ tps65912 = devm_kzalloc(&i2c->dev,
+ sizeof(struct tps65912), GFP_KERNEL);
if (tps65912 == NULL)
return -ENOMEM;
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
index b45f460d299f..69a5178bf152 100644
--- a/drivers/mfd/tps65912-spi.c
+++ b/drivers/mfd/tps65912-spi.c
@@ -85,7 +85,8 @@ static int tps65912_spi_probe(struct spi_device *spi)
{
struct tps65912 *tps65912;
- tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL);
+ tps65912 = devm_kzalloc(&spi->dev,
+ sizeof(struct tps65912), GFP_KERNEL);
if (tps65912 == NULL)
return -ENOMEM;
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 89ab4d970643..7f150d94d295 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -118,7 +118,7 @@
#define TWL6030_BASEADD_GASGAUGE 0x00C0
#define TWL6030_BASEADD_PIH 0x00D0
#define TWL6030_BASEADD_CHARGER 0x00E0
-#define TWL6025_BASEADD_CHARGER 0x00DA
+#define TWL6032_BASEADD_CHARGER 0x00DA
#define TWL6030_BASEADD_LED 0x00F4
/* subchip/slave 2 0x4A - DFT */
@@ -718,9 +718,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
| REGULATOR_CHANGE_STATUS,
};
- if (features & TWL6025_SUBCLASS) {
+ if (features & TWL6032_SUBCLASS) {
usb3v3.supply = "ldousb";
- regulator = TWL6025_REG_LDOUSB;
+ regulator = TWL6032_REG_LDOUSB;
} else {
usb3v3.supply = "vusb";
regulator = TWL6030_REG_VUSB;
@@ -747,8 +747,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
usb3v3.dev_name = dev_name(child);
} else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) &&
twl_class_is_6030()) {
- if (features & TWL6025_SUBCLASS)
- child = add_regulator(TWL6025_REG_LDOUSB,
+ if (features & TWL6032_SUBCLASS)
+ child = add_regulator(TWL6032_REG_LDOUSB,
pdata->ldousb, features);
else
child = add_regulator(TWL6030_REG_VUSB,
@@ -872,7 +872,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
/* twl6030 regulators */
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
- !(features & TWL6025_SUBCLASS)) {
+ !(features & TWL6032_SUBCLASS)) {
child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1,
features);
if (IS_ERR(child))
@@ -952,60 +952,60 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
return PTR_ERR(child);
}
- /* twl6025 regulators */
+ /* twl6032 regulators */
if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() &&
- (features & TWL6025_SUBCLASS)) {
- child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
+ (features & TWL6032_SUBCLASS)) {
+ child = add_regulator(TWL6032_REG_LDO5, pdata->ldo5,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
+ child = add_regulator(TWL6032_REG_LDO1, pdata->ldo1,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
+ child = add_regulator(TWL6032_REG_LDO7, pdata->ldo7,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
+ child = add_regulator(TWL6032_REG_LDO6, pdata->ldo6,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
+ child = add_regulator(TWL6032_REG_LDOLN, pdata->ldoln,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
+ child = add_regulator(TWL6032_REG_LDO2, pdata->ldo2,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
+ child = add_regulator(TWL6032_REG_LDO4, pdata->ldo4,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
+ child = add_regulator(TWL6032_REG_LDO3, pdata->ldo3,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
+ child = add_regulator(TWL6032_REG_SMPS3, pdata->smps3,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
+ child = add_regulator(TWL6032_REG_SMPS4, pdata->smps4,
features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
+ child = add_regulator(TWL6032_REG_VIO, pdata->vio6025,
features);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -1023,6 +1023,14 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
return PTR_ERR(child);
}
+ if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
+ child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
+ pdata->power, sizeof(*pdata->power), false,
+ 0, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
return 0;
}
@@ -1176,10 +1184,10 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
if ((id->driver_data) & TWL6030_CLASS) {
twl_priv->twl_id = TWL6030_CLASS_ID;
twl_priv->twl_map = &twl6030_map[0];
- /* The charger base address is different in twl6025 */
- if ((id->driver_data) & TWL6025_SUBCLASS)
+ /* The charger base address is different in twl6032 */
+ if ((id->driver_data) & TWL6032_SUBCLASS)
twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
- TWL6025_BASEADD_CHARGER;
+ TWL6032_BASEADD_CHARGER;
twl_regmap_config = twl6030_regmap_config;
} else {
twl_priv->twl_id = TWL4030_CLASS_ID;
@@ -1234,10 +1242,6 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
WARN(status < 0, "Error: reading twl_idcode register value\n");
}
- /* load power event scripts */
- if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata && pdata->power)
- twl4030_power_init(pdata->power);
-
/* Maybe init the T2 Interrupt subsystem */
if (client->irq) {
if (twl_class_is_4030()) {
@@ -1292,7 +1296,7 @@ static const struct i2c_device_id twl_ids[] = {
{ "tps65921", TPS_SUBSET }, /* fewer LDOs; no codec, no LED
and vibrator. Charger in USB module*/
{ "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */
- { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
+ { "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(i2c, twl_ids);
@@ -1305,17 +1309,7 @@ static struct i2c_driver twl_driver = {
.remove = twl_remove,
};
-static int __init twl_init(void)
-{
- return i2c_add_driver(&twl_driver);
-}
-subsys_initcall(twl_init);
-
-static void __exit twl_exit(void)
-{
- i2c_del_driver(&twl_driver);
-}
-module_exit(twl_exit);
+module_i2c_driver(twl_driver);
MODULE_AUTHOR("Texas Instruments, Inc.");
MODULE_DESCRIPTION("I2C Core interface for TWL");
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c
index d2ab222138c2..a31fba96ef43 100644
--- a/drivers/mfd/twl4030-audio.c
+++ b/drivers/mfd/twl4030-audio.c
@@ -261,10 +261,8 @@ static int twl4030_audio_probe(struct platform_device *pdev)
ret = -ENODEV;
}
- if (ret) {
- platform_set_drvdata(pdev, NULL);
+ if (ret)
twl4030_audio_dev = NULL;
- }
return ret;
}
@@ -272,7 +270,6 @@ static int twl4030_audio_probe(struct platform_device *pdev)
static int twl4030_audio_remove(struct platform_device *pdev)
{
mfd_remove_devices(&pdev->dev);
- platform_set_drvdata(pdev, NULL);
twl4030_audio_dev = NULL;
return 0;
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index 9d2d1bad6780..9aa6d1efa241 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -570,6 +570,7 @@ static struct irq_chip twl4030_sih_irq_chip = {
.irq_set_type = twl4030_sih_set_type,
.irq_bus_lock = twl4030_sih_bus_lock,
.irq_bus_sync_unlock = twl4030_sih_bus_sync_unlock,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
};
/*----------------------------------------------------------------------*/
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index 42bd3ea5df3c..1ea54d4d003a 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -775,12 +775,10 @@ static int twl4030_madc_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
if (ret) {
dev_dbg(&pdev->dev, "could not request irq\n");
- goto err_irq;
+ goto err_i2c;
}
twl4030_madc = madc;
return 0;
-err_irq:
- platform_set_drvdata(pdev, NULL);
err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
@@ -796,7 +794,6 @@ static int twl4030_madc_remove(struct platform_device *pdev)
struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
free_irq(platform_get_irq(pdev, 0), madc);
- platform_set_drvdata(pdev, NULL);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
kfree(madc);
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index dd362c1078e1..a5fd3c738211 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -28,6 +28,7 @@
#include <linux/pm.h>
#include <linux/i2c/twl.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <asm/mach-types.h>
@@ -492,6 +493,39 @@ int twl4030_remove_script(u8 flags)
return err;
}
+int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
+{
+ int err;
+ int i;
+ u8 address = twl4030_start_script_address;
+
+ for (i = 0; i < pdata->num; i++) {
+ err = load_twl4030_script(pdata->scripts[i], address);
+ if (err)
+ return err;
+ address += pdata->scripts[i]->size;
+ }
+
+ return 0;
+}
+
+int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
+{
+ struct twl4030_resconfig *resconfig = pdata->resource_config;
+ int err;
+
+ if (resconfig) {
+ while (resconfig->resource) {
+ err = twl4030_configure_resource(resconfig);
+ if (err)
+ return err;
+ resconfig++;
+ }
+ }
+
+ return 0;
+}
+
/*
* In master mode, start the power off sequence.
* After a successful execution, TWL shuts down the power to the SoC
@@ -507,43 +541,58 @@ void twl4030_power_off(void)
pr_err("TWL4030 Unable to power off\n");
}
-void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
+static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
+ struct device_node *node)
{
+ if (pdata && pdata->use_poweroff)
+ return true;
+
+ if (of_property_read_bool(node, "ti,use_poweroff"))
+ return true;
+
+ return false;
+}
+
+int twl4030_power_probe(struct platform_device *pdev)
+{
+ struct twl4030_power_data *pdata = pdev->dev.platform_data;
+ struct device_node *node = pdev->dev.of_node;
int err = 0;
- int i;
- struct twl4030_resconfig *resconfig;
- u8 val, address = twl4030_start_script_address;
+ int err2 = 0;
+ u8 val;
+
+ if (!pdata && !node) {
+ dev_err(&pdev->dev, "Platform data is missing\n");
+ return -EINVAL;
+ }
err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
TWL4030_PM_MASTER_PROTECT_KEY);
- if (err)
- goto unlock;
-
- err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
+ err |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
+ TWL4030_PM_MASTER_KEY_CFG2,
TWL4030_PM_MASTER_PROTECT_KEY);
- if (err)
- goto unlock;
- for (i = 0; i < twl4030_scripts->num; i++) {
- err = load_twl4030_script(twl4030_scripts->scripts[i], address);
- if (err)
- goto load;
- address += twl4030_scripts->scripts[i]->size;
+ if (err) {
+ pr_err("TWL4030 Unable to unlock registers\n");
+ return err;
}
- resconfig = twl4030_scripts->resource_config;
- if (resconfig) {
- while (resconfig->resource) {
- err = twl4030_configure_resource(resconfig);
- if (err)
- goto resource;
- resconfig++;
-
+ if (pdata) {
+ /* TODO: convert to device tree */
+ err = twl4030_power_configure_scripts(pdata);
+ if (err) {
+ pr_err("TWL4030 failed to load scripts\n");
+ goto relock;
+ }
+ err = twl4030_power_configure_resources(pdata);
+ if (err) {
+ pr_err("TWL4030 failed to configure resource\n");
+ goto relock;
}
}
/* Board has to be wired properly to use this feature */
- if (twl4030_scripts->use_poweroff && !pm_power_off) {
+ if (twl4030_power_use_poweroff(pdata, node) && !pm_power_off) {
/* Default for SEQ_OFFSYNC is set, lets ensure this */
err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
@@ -564,22 +613,43 @@ void twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
}
relock:
- err = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
+ err2 = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
TWL4030_PM_MASTER_PROTECT_KEY);
- if (err)
+ if (err2) {
pr_err("TWL4030 Unable to relock registers\n");
- return;
+ return err2;
+ }
-unlock:
- if (err)
- pr_err("TWL4030 Unable to unlock registers\n");
- return;
-load:
- if (err)
- pr_err("TWL4030 failed to load scripts\n");
- return;
-resource:
- if (err)
- pr_err("TWL4030 failed to configure resource\n");
- return;
+ return err;
}
+
+static int twl4030_power_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id twl4030_power_of_match[] = {
+ {.compatible = "ti,twl4030-power", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, twl4030_power_of_match);
+#endif
+
+static struct platform_driver twl4030_power_driver = {
+ .driver = {
+ .name = "twl4030_power",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(twl4030_power_of_match),
+ },
+ .probe = twl4030_power_probe,
+ .remove = twl4030_power_remove,
+};
+
+module_platform_driver(twl4030_power_driver);
+
+MODULE_AUTHOR("Nokia Corporation");
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("Power management for TWL4030");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:twl4030_power");
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index 96a020b1dcd1..981bef4b7ebc 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -351,6 +351,8 @@ void __init vexpress_sysreg_of_early_init(void)
}
+#ifdef CONFIG_GPIOLIB
+
#define VEXPRESS_SYSREG_GPIO(_name, _reg, _value) \
[VEXPRESS_GPIO_##_name] = { \
.reg = _reg, \
@@ -445,6 +447,8 @@ struct gpio_led_platform_data vexpress_sysreg_leds_pdata = {
.leds = vexpress_sysreg_leds,
};
+#endif
+
static ssize_t vexpress_sysreg_sys_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -480,6 +484,9 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
setup_timer(&vexpress_sysreg_config_timer,
vexpress_sysreg_config_complete, 0);
+ vexpress_sysreg_dev = &pdev->dev;
+
+#ifdef CONFIG_GPIOLIB
vexpress_sysreg_gpio_chip.dev = &pdev->dev;
err = gpiochip_add(&vexpress_sysreg_gpio_chip);
if (err) {
@@ -490,11 +497,10 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
return err;
}
- vexpress_sysreg_dev = &pdev->dev;
-
platform_device_register_data(vexpress_sysreg_dev, "leds-gpio",
PLATFORM_DEVID_AUTO, &vexpress_sysreg_leds_pdata,
sizeof(vexpress_sysreg_leds_pdata));
+#endif
device_create_file(vexpress_sysreg_dev, &dev_attr_sys_id);
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 155c4a1a6a99..802dd3cb18cf 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -65,7 +65,8 @@ static const struct reg_default wm5102_revb_patch[] = {
{ 0x418, 0xa080 },
{ 0x420, 0xa080 },
{ 0x428, 0xe000 },
- { 0x443, 0xDC1A },
+ { 0x442, 0x3F0A },
+ { 0x443, 0xDC1F },
{ 0x4B0, 0x0066 },
{ 0x458, 0x000b },
{ 0x212, 0x0000 },
@@ -424,6 +425,9 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */
{ 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */
{ 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
+ { 0x00000440, 0x8FFF }, /* R1088 - DRE Enable */
+ { 0x00000442, 0x3F0A }, /* R1090 - DRE Control 2 */
+ { 0x00000443, 0xDC1F }, /* R1090 - DRE Control 3 */
{ 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
{ 0x00000458, 0x000B }, /* R1112 - Noise Gate Control */
{ 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */
@@ -1197,6 +1201,9 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_DAC_DIGITAL_VOLUME_5R:
case ARIZONA_DAC_VOLUME_LIMIT_5R:
case ARIZONA_NOISE_GATE_SELECT_5R:
+ case ARIZONA_DRE_ENABLE:
+ case ARIZONA_DRE_CONTROL_2:
+ case ARIZONA_DRE_CONTROL_3:
case ARIZONA_DAC_AEC_CONTROL_1:
case ARIZONA_NOISE_GATE_CONTROL:
case ARIZONA_PDM_SPK1_CTRL_1:
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index c41599815299..2a7972349159 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -2273,18 +2273,22 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_CLOCKING_1:
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
+ case ARIZONA_DSP1_STATUS_3:
case ARIZONA_DSP2_CONTROL_1:
case ARIZONA_DSP2_CLOCKING_1:
case ARIZONA_DSP2_STATUS_1:
case ARIZONA_DSP2_STATUS_2:
+ case ARIZONA_DSP2_STATUS_3:
case ARIZONA_DSP3_CONTROL_1:
case ARIZONA_DSP3_CLOCKING_1:
case ARIZONA_DSP3_STATUS_1:
case ARIZONA_DSP3_STATUS_2:
+ case ARIZONA_DSP3_STATUS_3:
case ARIZONA_DSP4_CONTROL_1:
case ARIZONA_DSP4_CLOCKING_1:
case ARIZONA_DSP4_STATUS_1:
case ARIZONA_DSP4_STATUS_2:
+ case ARIZONA_DSP4_STATUS_3:
return true;
default:
return false;
@@ -2334,12 +2338,16 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_CLOCKING_1:
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
+ case ARIZONA_DSP1_STATUS_3:
case ARIZONA_DSP2_STATUS_1:
case ARIZONA_DSP2_STATUS_2:
+ case ARIZONA_DSP2_STATUS_3:
case ARIZONA_DSP3_STATUS_1:
case ARIZONA_DSP3_STATUS_2:
+ case ARIZONA_DSP3_STATUS_3:
case ARIZONA_DSP4_STATUS_1:
case ARIZONA_DSP4_STATUS_2:
+ case ARIZONA_DSP4_STATUS_3:
return true;
default:
return false;
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 00e4fe2f3c75..781115e8dca9 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -259,20 +259,6 @@ static int wm8994_suspend(struct device *dev)
break;
}
- switch (wm8994->type) {
- case WM1811:
- ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
- if (ret < 0) {
- dev_err(dev, "Failed to read jackdet: %d\n", ret);
- } else if (ret & WM1811_JACKDET_MODE_MASK) {
- dev_dbg(dev, "CODEC still active, ignoring suspend\n");
- return 0;
- }
- break;
- default:
- break;
- }
-
/* Disable LDO pulldowns while the device is suspended if we
* don't know that something will be driving them. */
if (!wm8994->ldo_ena_always_driven)
@@ -652,6 +638,17 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
return ret;
}
+ /* Explicitly put the device into reset in case regulators
+ * don't get disabled in order to ensure we know the device
+ * state.
+ */
+ ret = wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
+ wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to reset device: %d\n", ret);
+ return ret;
+ }
+
if (regmap_patch) {
ret = regmap_register_patch(wm8994->regmap, regmap_patch,
patch_regs);
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index a050e56a9bbd..d3a184a240f5 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -14,10 +14,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
#include <linux/regmap.h>
#include <linux/mfd/wm8994/core.h>
@@ -138,6 +140,55 @@ static struct regmap_irq_chip wm8994_irq_chip = {
.runtime_pm = true,
};
+static void wm8994_edge_irq_enable(struct irq_data *data)
+{
+}
+
+static void wm8994_edge_irq_disable(struct irq_data *data)
+{
+}
+
+static struct irq_chip wm8994_edge_irq_chip = {
+ .name = "wm8994_edge",
+ .irq_disable = wm8994_edge_irq_disable,
+ .irq_enable = wm8994_edge_irq_enable,
+};
+
+static irqreturn_t wm8994_edge_irq(int irq, void *data)
+{
+ struct wm8994 *wm8994 = data;
+
+ while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio))
+ handle_nested_irq(irq_create_mapping(wm8994->edge_irq, 0));
+
+ return IRQ_HANDLED;
+}
+
+static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct wm8994 *wm8994 = h->host_data;
+
+ irq_set_chip_data(virq, wm8994);
+ irq_set_chip_and_handler(virq, &wm8994_edge_irq_chip, handle_edge_irq);
+ 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 wm8994_edge_irq_ops = {
+ .map = wm8994_edge_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
int wm8994_irq_init(struct wm8994 *wm8994)
{
int ret;
@@ -156,10 +207,51 @@ int wm8994_irq_init(struct wm8994 *wm8994)
if (pdata->irq_flags)
irqflags = pdata->irq_flags;
- ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
- irqflags,
- wm8994->irq_base, &wm8994_irq_chip,
- &wm8994->irq_data);
+ /* use a GPIO for edge triggered controllers */
+ if (irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ if (gpio_to_irq(pdata->irq_gpio) != wm8994->irq) {
+ dev_warn(wm8994->dev, "IRQ %d is not GPIO %d (%d)\n",
+ wm8994->irq, pdata->irq_gpio,
+ gpio_to_irq(pdata->irq_gpio));
+ wm8994->irq = gpio_to_irq(pdata->irq_gpio);
+ }
+
+ ret = devm_gpio_request_one(wm8994->dev, pdata->irq_gpio,
+ GPIOF_IN, "WM8994 IRQ");
+
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to get IRQ GPIO: %d\n",
+ ret);
+ return ret;
+ }
+
+ wm8994->edge_irq = irq_domain_add_linear(NULL, 1,
+ &wm8994_edge_irq_ops,
+ wm8994);
+
+ ret = regmap_add_irq_chip(wm8994->regmap,
+ irq_create_mapping(wm8994->edge_irq,
+ 0),
+ IRQF_ONESHOT,
+ wm8994->irq_base, &wm8994_irq_chip,
+ &wm8994->irq_data);
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to get IRQ: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = request_threaded_irq(wm8994->irq,
+ NULL, wm8994_edge_irq,
+ irqflags,
+ "WM8994 edge", wm8994);
+ } else {
+ ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
+ irqflags,
+ wm8994->irq_base, &wm8994_irq_chip,
+ &wm8994->irq_data);
+ }
+
if (ret != 0) {
dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
return ret;
diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c
new file mode 100644
index 000000000000..5aa807687777
--- /dev/null
+++ b/drivers/mfd/wm8997-tables.c
@@ -0,0 +1,1525 @@
+/*
+ * wm8997-tables.c -- WM8997 data tables
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+
+static const struct reg_default wm8997_reva_patch[] = {
+ { 0x80, 0x0003 },
+ { 0x214, 0x0008 },
+ { 0x458, 0x0000 },
+ { 0x0081, 0xE022 },
+ { 0x294, 0x0000 },
+ { 0x80, 0x0000 },
+ { 0x171, 0x0000 },
+};
+
+/* We use a function so we can use ARRAY_SIZE() */
+int wm8997_patch(struct arizona *arizona)
+{
+ switch (arizona->rev) {
+ case 0:
+ return regmap_register_patch(arizona->regmap,
+ wm8997_reva_patch,
+ ARRAY_SIZE(wm8997_reva_patch));
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(wm8997_patch);
+
+static const struct regmap_irq wm8997_aod_irqs[ARIZONA_NUM_IRQ] = {
+ [ARIZONA_IRQ_GP5_FALL] = { .mask = ARIZONA_GP5_FALL_EINT1 },
+ [ARIZONA_IRQ_GP5_RISE] = { .mask = ARIZONA_GP5_RISE_EINT1 },
+ [ARIZONA_IRQ_JD_FALL] = { .mask = ARIZONA_JD1_FALL_EINT1 },
+ [ARIZONA_IRQ_JD_RISE] = { .mask = ARIZONA_JD1_RISE_EINT1 },
+};
+
+const struct regmap_irq_chip wm8997_aod = {
+ .name = "wm8997 AOD",
+ .status_base = ARIZONA_AOD_IRQ1,
+ .mask_base = ARIZONA_AOD_IRQ_MASK_IRQ1,
+ .ack_base = ARIZONA_AOD_IRQ1,
+ .num_regs = 1,
+ .irqs = wm8997_aod_irqs,
+ .num_irqs = ARRAY_SIZE(wm8997_aod_irqs),
+};
+EXPORT_SYMBOL_GPL(wm8997_aod);
+
+static const struct regmap_irq wm8997_irqs[ARIZONA_NUM_IRQ] = {
+ [ARIZONA_IRQ_GP4] = { .reg_offset = 0, .mask = ARIZONA_GP4_EINT1 },
+ [ARIZONA_IRQ_GP3] = { .reg_offset = 0, .mask = ARIZONA_GP3_EINT1 },
+ [ARIZONA_IRQ_GP2] = { .reg_offset = 0, .mask = ARIZONA_GP2_EINT1 },
+ [ARIZONA_IRQ_GP1] = { .reg_offset = 0, .mask = ARIZONA_GP1_EINT1 },
+
+ [ARIZONA_IRQ_SPK_SHUTDOWN_WARN] = {
+ .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_WARN_EINT1
+ },
+ [ARIZONA_IRQ_SPK_SHUTDOWN] = {
+ .reg_offset = 2, .mask = ARIZONA_SPK_SHUTDOWN_EINT1
+ },
+ [ARIZONA_IRQ_HPDET] = {
+ .reg_offset = 2, .mask = ARIZONA_HPDET_EINT1
+ },
+ [ARIZONA_IRQ_MICDET] = {
+ .reg_offset = 2, .mask = ARIZONA_MICDET_EINT1
+ },
+ [ARIZONA_IRQ_WSEQ_DONE] = {
+ .reg_offset = 2, .mask = ARIZONA_WSEQ_DONE_EINT1
+ },
+ [ARIZONA_IRQ_DRC1_SIG_DET] = {
+ .reg_offset = 2, .mask = ARIZONA_DRC1_SIG_DET_EINT1
+ },
+ [ARIZONA_IRQ_UNDERCLOCKED] = {
+ .reg_offset = 2, .mask = ARIZONA_UNDERCLOCKED_EINT1
+ },
+ [ARIZONA_IRQ_OVERCLOCKED] = {
+ .reg_offset = 2, .mask = ARIZONA_OVERCLOCKED_EINT1
+ },
+ [ARIZONA_IRQ_FLL2_LOCK] = {
+ .reg_offset = 2, .mask = ARIZONA_FLL2_LOCK_EINT1
+ },
+ [ARIZONA_IRQ_FLL1_LOCK] = {
+ .reg_offset = 2, .mask = ARIZONA_FLL1_LOCK_EINT1
+ },
+ [ARIZONA_IRQ_CLKGEN_ERR] = {
+ .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_EINT1
+ },
+ [ARIZONA_IRQ_CLKGEN_ERR_ASYNC] = {
+ .reg_offset = 2, .mask = ARIZONA_CLKGEN_ERR_ASYNC_EINT1
+ },
+
+ [ARIZONA_IRQ_AIF2_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_AIF2_ERR_EINT1
+ },
+ [ARIZONA_IRQ_AIF1_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_AIF1_ERR_EINT1
+ },
+ [ARIZONA_IRQ_CTRLIF_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_CTRLIF_ERR_EINT1
+ },
+ [ARIZONA_IRQ_MIXER_DROPPED_SAMPLES] = {
+ .reg_offset = 3, .mask = ARIZONA_MIXER_DROPPED_SAMPLE_EINT1
+ },
+ [ARIZONA_IRQ_ASYNC_CLK_ENA_LOW] = {
+ .reg_offset = 3, .mask = ARIZONA_ASYNC_CLK_ENA_LOW_EINT1
+ },
+ [ARIZONA_IRQ_SYSCLK_ENA_LOW] = {
+ .reg_offset = 3, .mask = ARIZONA_SYSCLK_ENA_LOW_EINT1
+ },
+ [ARIZONA_IRQ_ISRC1_CFG_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_ISRC1_CFG_ERR_EINT1
+ },
+ [ARIZONA_IRQ_ISRC2_CFG_ERR] = {
+ .reg_offset = 3, .mask = ARIZONA_ISRC2_CFG_ERR_EINT1
+ },
+
+ [ARIZONA_IRQ_BOOT_DONE] = {
+ .reg_offset = 4, .mask = ARIZONA_BOOT_DONE_EINT1
+ },
+ [ARIZONA_IRQ_DCS_DAC_DONE] = {
+ .reg_offset = 4, .mask = ARIZONA_DCS_DAC_DONE_EINT1
+ },
+ [ARIZONA_IRQ_DCS_HP_DONE] = {
+ .reg_offset = 4, .mask = ARIZONA_DCS_HP_DONE_EINT1
+ },
+ [ARIZONA_IRQ_FLL2_CLOCK_OK] = {
+ .reg_offset = 4, .mask = ARIZONA_FLL2_CLOCK_OK_EINT1
+ },
+ [ARIZONA_IRQ_FLL1_CLOCK_OK] = {
+ .reg_offset = 4, .mask = ARIZONA_FLL1_CLOCK_OK_EINT1
+ },
+};
+
+const struct regmap_irq_chip wm8997_irq = {
+ .name = "wm8997 IRQ",
+ .status_base = ARIZONA_INTERRUPT_STATUS_1,
+ .mask_base = ARIZONA_INTERRUPT_STATUS_1_MASK,
+ .ack_base = ARIZONA_INTERRUPT_STATUS_1,
+ .num_regs = 5,
+ .irqs = wm8997_irqs,
+ .num_irqs = ARRAY_SIZE(wm8997_irqs),
+};
+EXPORT_SYMBOL_GPL(wm8997_irq);
+
+static const struct reg_default wm8997_reg_default[] = {
+ { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */
+ { 0x00000016, 0x0000 }, /* R22 - Write Sequencer Ctrl 0 */
+ { 0x00000017, 0x0000 }, /* R23 - Write Sequencer Ctrl 1 */
+ { 0x00000018, 0x0000 }, /* R24 - Write Sequencer Ctrl 2 */
+ { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */
+ { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */
+ { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */
+ { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */
+ { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */
+ { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */
+ { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */
+ { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */
+ { 0x00000040, 0x0000 }, /* R64 - Wake control */
+ { 0x00000041, 0x0000 }, /* R65 - Sequence control */
+ { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */
+ { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */
+ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */
+ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */
+ { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */
+ { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */
+ { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */
+ { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */
+ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */
+ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */
+ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */
+ { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */
+ { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */
+ { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */
+ { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */
+ { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */
+ { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */
+ { 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */
+ { 0x00000101, 0x0304 }, /* R257 - System Clock 1 */
+ { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */
+ { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */
+ { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */
+ { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */
+ { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */
+ { 0x00000149, 0x0000 }, /* R329 - Output system clock */
+ { 0x0000014A, 0x0000 }, /* R330 - Output async clock */
+ { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */
+ { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */
+ { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */
+ { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */
+ { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */
+ { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */
+ { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */
+ { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */
+ { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */
+ { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */
+ { 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */
+ { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */
+ { 0x00000177, 0x0181 }, /* R375 - FLL1 Loop Filter Test 1 */
+ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */
+ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */
+ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */
+ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */
+ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */
+ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */
+ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */
+ { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */
+ { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */
+ { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */
+ { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */
+ { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */
+ { 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */
+ { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */
+ { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */
+ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */
+ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */
+ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */
+ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */
+ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */
+ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */
+ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */
+ { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */
+ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */
+ { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */
+ { 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */
+ { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */
+ { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
+ { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
+ { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
+ { 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
+ { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
+ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */
+ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */
+ { 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */
+ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */
+ { 0x000002CB, 0x0000 }, /* R715 - Isolation control */
+ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */
+ { 0x00000300, 0x0000 }, /* R768 - Input Enables */
+ { 0x00000308, 0x0000 }, /* R776 - Input Rate */
+ { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */
+ { 0x00000310, 0x2080 }, /* R784 - IN1L Control */
+ { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */
+ { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */
+ { 0x00000314, 0x0080 }, /* R788 - IN1R Control */
+ { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */
+ { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */
+ { 0x00000318, 0x2080 }, /* R792 - IN2L Control */
+ { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */
+ { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */
+ { 0x0000031C, 0x0080 }, /* R796 - IN2R Control */
+ { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */
+ { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */
+ { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */
+ { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */
+ { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */
+ { 0x00000410, 0x0080 }, /* R1040 - Output Path Config 1L */
+ { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */
+ { 0x00000412, 0x0080 }, /* R1042 - DAC Volume Limit 1L */
+ { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */
+ { 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */
+ { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */
+ { 0x00000416, 0x0080 }, /* R1046 - DAC Volume Limit 1R */
+ { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */
+ { 0x00000420, 0x0080 }, /* R1056 - Output Path Config 3L */
+ { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */
+ { 0x00000422, 0x0080 }, /* R1058 - DAC Volume Limit 3L */
+ { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */
+ { 0x00000428, 0x0000 }, /* R1064 - Output Path Config 4L */
+ { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */
+ { 0x0000042A, 0x0080 }, /* R1066 - Out Volume 4L */
+ { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */
+ { 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */
+ { 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */
+ { 0x00000432, 0x0080 }, /* R1074 - DAC Volume Limit 5L */
+ { 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */
+ { 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */
+ { 0x00000436, 0x0080 }, /* R1078 - DAC Volume Limit 5R */
+ { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */
+ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */
+ { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */
+ { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */
+ { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */
+ { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */
+ { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */
+ { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */
+ { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */
+ { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */
+ { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */
+ { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */
+ { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */
+ { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */
+ { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */
+ { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */
+ { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */
+ { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */
+ { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */
+ { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */
+ { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */
+ { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */
+ { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */
+ { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */
+ { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */
+ { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */
+ { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */
+ { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */
+ { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */
+ { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */
+ { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */
+ { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */
+ { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */
+ { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */
+ { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */
+ { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */
+ { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */
+ { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */
+ { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */
+ { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */
+ { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
+ { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
+ { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
+ { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
+ { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
+ { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
+ { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
+ { 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */
+ { 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */
+ { 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */
+ { 0x000005E7, 0x0000 }, /* R1511 - SLIMbus Rates 3 */
+ { 0x000005E8, 0x0000 }, /* R1512 - SLIMbus Rates 4 */
+ { 0x000005E9, 0x0000 }, /* R1513 - SLIMbus Rates 5 */
+ { 0x000005EA, 0x0000 }, /* R1514 - SLIMbus Rates 6 */
+ { 0x000005EB, 0x0000 }, /* R1515 - SLIMbus Rates 7 */
+ { 0x000005EC, 0x0000 }, /* R1516 - SLIMbus Rates 8 */
+ { 0x000005F5, 0x0000 }, /* R1525 - SLIMbus RX Channel Enable */
+ { 0x000005F6, 0x0000 }, /* R1526 - SLIMbus TX Channel Enable */
+ { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */
+ { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */
+ { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */
+ { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */
+ { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */
+ { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */
+ { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */
+ { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */
+ { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */
+ { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */
+ { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */
+ { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */
+ { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */
+ { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */
+ { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */
+ { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */
+ { 0x00000660, 0x0000 }, /* R1632 - MICMIX Input 1 Source */
+ { 0x00000661, 0x0080 }, /* R1633 - MICMIX Input 1 Volume */
+ { 0x00000662, 0x0000 }, /* R1634 - MICMIX Input 2 Source */
+ { 0x00000663, 0x0080 }, /* R1635 - MICMIX Input 2 Volume */
+ { 0x00000664, 0x0000 }, /* R1636 - MICMIX Input 3 Source */
+ { 0x00000665, 0x0080 }, /* R1637 - MICMIX Input 3 Volume */
+ { 0x00000666, 0x0000 }, /* R1638 - MICMIX Input 4 Source */
+ { 0x00000667, 0x0080 }, /* R1639 - MICMIX Input 4 Volume */
+ { 0x00000668, 0x0000 }, /* R1640 - NOISEMIX Input 1 Source */
+ { 0x00000669, 0x0080 }, /* R1641 - NOISEMIX Input 1 Volume */
+ { 0x0000066A, 0x0000 }, /* R1642 - NOISEMIX Input 2 Source */
+ { 0x0000066B, 0x0080 }, /* R1643 - NOISEMIX Input 2 Volume */
+ { 0x0000066C, 0x0000 }, /* R1644 - NOISEMIX Input 3 Source */
+ { 0x0000066D, 0x0080 }, /* R1645 - NOISEMIX Input 3 Volume */
+ { 0x0000066E, 0x0000 }, /* R1646 - NOISEMIX Input 4 Source */
+ { 0x0000066F, 0x0080 }, /* R1647 - NOISEMIX Input 4 Volume */
+ { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */
+ { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */
+ { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */
+ { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */
+ { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */
+ { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */
+ { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */
+ { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */
+ { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */
+ { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */
+ { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */
+ { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */
+ { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */
+ { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */
+ { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */
+ { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */
+ { 0x000006A0, 0x0000 }, /* R1696 - OUT3LMIX Input 1 Source */
+ { 0x000006A1, 0x0080 }, /* R1697 - OUT3LMIX Input 1 Volume */
+ { 0x000006A2, 0x0000 }, /* R1698 - OUT3LMIX Input 2 Source */
+ { 0x000006A3, 0x0080 }, /* R1699 - OUT3LMIX Input 2 Volume */
+ { 0x000006A4, 0x0000 }, /* R1700 - OUT3LMIX Input 3 Source */
+ { 0x000006A5, 0x0080 }, /* R1701 - OUT3LMIX Input 3 Volume */
+ { 0x000006A6, 0x0000 }, /* R1702 - OUT3LMIX Input 4 Source */
+ { 0x000006A7, 0x0080 }, /* R1703 - OUT3LMIX Input 4 Volume */
+ { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */
+ { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */
+ { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */
+ { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */
+ { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */
+ { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */
+ { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */
+ { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */
+ { 0x000006C0, 0x0000 }, /* R1728 - OUT5LMIX Input 1 Source */
+ { 0x000006C1, 0x0080 }, /* R1729 - OUT5LMIX Input 1 Volume */
+ { 0x000006C2, 0x0000 }, /* R1730 - OUT5LMIX Input 2 Source */
+ { 0x000006C3, 0x0080 }, /* R1731 - OUT5LMIX Input 2 Volume */
+ { 0x000006C4, 0x0000 }, /* R1732 - OUT5LMIX Input 3 Source */
+ { 0x000006C5, 0x0080 }, /* R1733 - OUT5LMIX Input 3 Volume */
+ { 0x000006C6, 0x0000 }, /* R1734 - OUT5LMIX Input 4 Source */
+ { 0x000006C7, 0x0080 }, /* R1735 - OUT5LMIX Input 4 Volume */
+ { 0x000006C8, 0x0000 }, /* R1736 - OUT5RMIX Input 1 Source */
+ { 0x000006C9, 0x0080 }, /* R1737 - OUT5RMIX Input 1 Volume */
+ { 0x000006CA, 0x0000 }, /* R1738 - OUT5RMIX Input 2 Source */
+ { 0x000006CB, 0x0080 }, /* R1739 - OUT5RMIX Input 2 Volume */
+ { 0x000006CC, 0x0000 }, /* R1740 - OUT5RMIX Input 3 Source */
+ { 0x000006CD, 0x0080 }, /* R1741 - OUT5RMIX Input 3 Volume */
+ { 0x000006CE, 0x0000 }, /* R1742 - OUT5RMIX Input 4 Source */
+ { 0x000006CF, 0x0080 }, /* R1743 - OUT5RMIX Input 4 Volume */
+ { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */
+ { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */
+ { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */
+ { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */
+ { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */
+ { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */
+ { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */
+ { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */
+ { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */
+ { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */
+ { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */
+ { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */
+ { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */
+ { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */
+ { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */
+ { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */
+ { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */
+ { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */
+ { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */
+ { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */
+ { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */
+ { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */
+ { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */
+ { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */
+ { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */
+ { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */
+ { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */
+ { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */
+ { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */
+ { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */
+ { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */
+ { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */
+ { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */
+ { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */
+ { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */
+ { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */
+ { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */
+ { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */
+ { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */
+ { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */
+ { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */
+ { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */
+ { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */
+ { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */
+ { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */
+ { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */
+ { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */
+ { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */
+ { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */
+ { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */
+ { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */
+ { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */
+ { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */
+ { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */
+ { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */
+ { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */
+ { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */
+ { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */
+ { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */
+ { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */
+ { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */
+ { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */
+ { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */
+ { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */
+ { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */
+ { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */
+ { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */
+ { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */
+ { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */
+ { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */
+ { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */
+ { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */
+ { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */
+ { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */
+ { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */
+ { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */
+ { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */
+ { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */
+ { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */
+ { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */
+ { 0x000007C0, 0x0000 }, /* R1984 - SLIMTX1MIX Input 1 Source */
+ { 0x000007C1, 0x0080 }, /* R1985 - SLIMTX1MIX Input 1 Volume */
+ { 0x000007C2, 0x0000 }, /* R1986 - SLIMTX1MIX Input 2 Source */
+ { 0x000007C3, 0x0080 }, /* R1987 - SLIMTX1MIX Input 2 Volume */
+ { 0x000007C4, 0x0000 }, /* R1988 - SLIMTX1MIX Input 3 Source */
+ { 0x000007C5, 0x0080 }, /* R1989 - SLIMTX1MIX Input 3 Volume */
+ { 0x000007C6, 0x0000 }, /* R1990 - SLIMTX1MIX Input 4 Source */
+ { 0x000007C7, 0x0080 }, /* R1991 - SLIMTX1MIX Input 4 Volume */
+ { 0x000007C8, 0x0000 }, /* R1992 - SLIMTX2MIX Input 1 Source */
+ { 0x000007C9, 0x0080 }, /* R1993 - SLIMTX2MIX Input 1 Volume */
+ { 0x000007CA, 0x0000 }, /* R1994 - SLIMTX2MIX Input 2 Source */
+ { 0x000007CB, 0x0080 }, /* R1995 - SLIMTX2MIX Input 2 Volume */
+ { 0x000007CC, 0x0000 }, /* R1996 - SLIMTX2MIX Input 3 Source */
+ { 0x000007CD, 0x0080 }, /* R1997 - SLIMTX2MIX Input 3 Volume */
+ { 0x000007CE, 0x0000 }, /* R1998 - SLIMTX2MIX Input 4 Source */
+ { 0x000007CF, 0x0080 }, /* R1999 - SLIMTX2MIX Input 4 Volume */
+ { 0x000007D0, 0x0000 }, /* R2000 - SLIMTX3MIX Input 1 Source */
+ { 0x000007D1, 0x0080 }, /* R2001 - SLIMTX3MIX Input 1 Volume */
+ { 0x000007D2, 0x0000 }, /* R2002 - SLIMTX3MIX Input 2 Source */
+ { 0x000007D3, 0x0080 }, /* R2003 - SLIMTX3MIX Input 2 Volume */
+ { 0x000007D4, 0x0000 }, /* R2004 - SLIMTX3MIX Input 3 Source */
+ { 0x000007D5, 0x0080 }, /* R2005 - SLIMTX3MIX Input 3 Volume */
+ { 0x000007D6, 0x0000 }, /* R2006 - SLIMTX3MIX Input 4 Source */
+ { 0x000007D7, 0x0080 }, /* R2007 - SLIMTX3MIX Input 4 Volume */
+ { 0x000007D8, 0x0000 }, /* R2008 - SLIMTX4MIX Input 1 Source */
+ { 0x000007D9, 0x0080 }, /* R2009 - SLIMTX4MIX Input 1 Volume */
+ { 0x000007DA, 0x0000 }, /* R2010 - SLIMTX4MIX Input 2 Source */
+ { 0x000007DB, 0x0080 }, /* R2011 - SLIMTX4MIX Input 2 Volume */
+ { 0x000007DC, 0x0000 }, /* R2012 - SLIMTX4MIX Input 3 Source */
+ { 0x000007DD, 0x0080 }, /* R2013 - SLIMTX4MIX Input 3 Volume */
+ { 0x000007DE, 0x0000 }, /* R2014 - SLIMTX4MIX Input 4 Source */
+ { 0x000007DF, 0x0080 }, /* R2015 - SLIMTX4MIX Input 4 Volume */
+ { 0x000007E0, 0x0000 }, /* R2016 - SLIMTX5MIX Input 1 Source */
+ { 0x000007E1, 0x0080 }, /* R2017 - SLIMTX5MIX Input 1 Volume */
+ { 0x000007E2, 0x0000 }, /* R2018 - SLIMTX5MIX Input 2 Source */
+ { 0x000007E3, 0x0080 }, /* R2019 - SLIMTX5MIX Input 2 Volume */
+ { 0x000007E4, 0x0000 }, /* R2020 - SLIMTX5MIX Input 3 Source */
+ { 0x000007E5, 0x0080 }, /* R2021 - SLIMTX5MIX Input 3 Volume */
+ { 0x000007E6, 0x0000 }, /* R2022 - SLIMTX5MIX Input 4 Source */
+ { 0x000007E7, 0x0080 }, /* R2023 - SLIMTX5MIX Input 4 Volume */
+ { 0x000007E8, 0x0000 }, /* R2024 - SLIMTX6MIX Input 1 Source */
+ { 0x000007E9, 0x0080 }, /* R2025 - SLIMTX6MIX Input 1 Volume */
+ { 0x000007EA, 0x0000 }, /* R2026 - SLIMTX6MIX Input 2 Source */
+ { 0x000007EB, 0x0080 }, /* R2027 - SLIMTX6MIX Input 2 Volume */
+ { 0x000007EC, 0x0000 }, /* R2028 - SLIMTX6MIX Input 3 Source */
+ { 0x000007ED, 0x0080 }, /* R2029 - SLIMTX6MIX Input 3 Volume */
+ { 0x000007EE, 0x0000 }, /* R2030 - SLIMTX6MIX Input 4 Source */
+ { 0x000007EF, 0x0080 }, /* R2031 - SLIMTX6MIX Input 4 Volume */
+ { 0x000007F0, 0x0000 }, /* R2032 - SLIMTX7MIX Input 1 Source */
+ { 0x000007F1, 0x0080 }, /* R2033 - SLIMTX7MIX Input 1 Volume */
+ { 0x000007F2, 0x0000 }, /* R2034 - SLIMTX7MIX Input 2 Source */
+ { 0x000007F3, 0x0080 }, /* R2035 - SLIMTX7MIX Input 2 Volume */
+ { 0x000007F4, 0x0000 }, /* R2036 - SLIMTX7MIX Input 3 Source */
+ { 0x000007F5, 0x0080 }, /* R2037 - SLIMTX7MIX Input 3 Volume */
+ { 0x000007F6, 0x0000 }, /* R2038 - SLIMTX7MIX Input 4 Source */
+ { 0x000007F7, 0x0080 }, /* R2039 - SLIMTX7MIX Input 4 Volume */
+ { 0x000007F8, 0x0000 }, /* R2040 - SLIMTX8MIX Input 1 Source */
+ { 0x000007F9, 0x0080 }, /* R2041 - SLIMTX8MIX Input 1 Volume */
+ { 0x000007FA, 0x0000 }, /* R2042 - SLIMTX8MIX Input 2 Source */
+ { 0x000007FB, 0x0080 }, /* R2043 - SLIMTX8MIX Input 2 Volume */
+ { 0x000007FC, 0x0000 }, /* R2044 - SLIMTX8MIX Input 3 Source */
+ { 0x000007FD, 0x0080 }, /* R2045 - SLIMTX8MIX Input 3 Volume */
+ { 0x000007FE, 0x0000 }, /* R2046 - SLIMTX8MIX Input 4 Source */
+ { 0x000007FF, 0x0080 }, /* R2047 - SLIMTX8MIX Input 4 Volume */
+ { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */
+ { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */
+ { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */
+ { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */
+ { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */
+ { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */
+ { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */
+ { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */
+ { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */
+ { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */
+ { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */
+ { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */
+ { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */
+ { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */
+ { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */
+ { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */
+ { 0x00000890, 0x0000 }, /* R2192 - EQ3MIX Input 1 Source */
+ { 0x00000891, 0x0080 }, /* R2193 - EQ3MIX Input 1 Volume */
+ { 0x00000892, 0x0000 }, /* R2194 - EQ3MIX Input 2 Source */
+ { 0x00000893, 0x0080 }, /* R2195 - EQ3MIX Input 2 Volume */
+ { 0x00000894, 0x0000 }, /* R2196 - EQ3MIX Input 3 Source */
+ { 0x00000895, 0x0080 }, /* R2197 - EQ3MIX Input 3 Volume */
+ { 0x00000896, 0x0000 }, /* R2198 - EQ3MIX Input 4 Source */
+ { 0x00000897, 0x0080 }, /* R2199 - EQ3MIX Input 4 Volume */
+ { 0x00000898, 0x0000 }, /* R2200 - EQ4MIX Input 1 Source */
+ { 0x00000899, 0x0080 }, /* R2201 - EQ4MIX Input 1 Volume */
+ { 0x0000089A, 0x0000 }, /* R2202 - EQ4MIX Input 2 Source */
+ { 0x0000089B, 0x0080 }, /* R2203 - EQ4MIX Input 2 Volume */
+ { 0x0000089C, 0x0000 }, /* R2204 - EQ4MIX Input 3 Source */
+ { 0x0000089D, 0x0080 }, /* R2205 - EQ4MIX Input 3 Volume */
+ { 0x0000089E, 0x0000 }, /* R2206 - EQ4MIX Input 4 Source */
+ { 0x0000089F, 0x0080 }, /* R2207 - EQ4MIX Input 4 Volume */
+ { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */
+ { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */
+ { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */
+ { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */
+ { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */
+ { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */
+ { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */
+ { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */
+ { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */
+ { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */
+ { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */
+ { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */
+ { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */
+ { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */
+ { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */
+ { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */
+ { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */
+ { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */
+ { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */
+ { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */
+ { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */
+ { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */
+ { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */
+ { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */
+ { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */
+ { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */
+ { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */
+ { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */
+ { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */
+ { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */
+ { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */
+ { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */
+ { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */
+ { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */
+ { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */
+ { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */
+ { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */
+ { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */
+ { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */
+ { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */
+ { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */
+ { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */
+ { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */
+ { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */
+ { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */
+ { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */
+ { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */
+ { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */
+ { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */
+ { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */
+ { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */
+ { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */
+ { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */
+ { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */
+ { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */
+ { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */
+ { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */
+ { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */
+ { 0x00000C02, 0xA101 }, /* R3074 - GPIO3 CTRL */
+ { 0x00000C03, 0xA101 }, /* R3075 - GPIO4 CTRL */
+ { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */
+ { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */
+ { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */
+ { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */
+ { 0x00000C21, 0x0001 }, /* R3105 - Misc Pad Ctrl 2 */
+ { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */
+ { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
+ { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
+ { 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */
+ { 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */
+ { 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */
+ { 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */
+ { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */
+ { 0x00000D18, 0xFFFF }, /* R3352 - IRQ2 Status 1 Mask */
+ { 0x00000D1A, 0xFFFF }, /* R3354 - IRQ2 Status 3 Mask */
+ { 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */
+ { 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */
+ { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */
+ { 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */
+ { 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */
+ { 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */
+ { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */
+ { 0x00000E01, 0x0000 }, /* R3585 - FX_Ctrl2 */
+ { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */
+ { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */
+ { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */
+ { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */
+ { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */
+ { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */
+ { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */
+ { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */
+ { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */
+ { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */
+ { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */
+ { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */
+ { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */
+ { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */
+ { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */
+ { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */
+ { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */
+ { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */
+ { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */
+ { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */
+ { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */
+ { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */
+ { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */
+ { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */
+ { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */
+ { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */
+ { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */
+ { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */
+ { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */
+ { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */
+ { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */
+ { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */
+ { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */
+ { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */
+ { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */
+ { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */
+ { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */
+ { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */
+ { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */
+ { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */
+ { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */
+ { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */
+ { 0x00000E3C, 0x6318 }, /* R3644 - EQ3_1 */
+ { 0x00000E3D, 0x6300 }, /* R3645 - EQ3_2 */
+ { 0x00000E3E, 0x0FC8 }, /* R3646 - EQ3_3 */
+ { 0x00000E3F, 0x03FE }, /* R3647 - EQ3_4 */
+ { 0x00000E40, 0x00E0 }, /* R3648 - EQ3_5 */
+ { 0x00000E41, 0x1EC4 }, /* R3649 - EQ3_6 */
+ { 0x00000E42, 0xF136 }, /* R3650 - EQ3_7 */
+ { 0x00000E43, 0x0409 }, /* R3651 - EQ3_8 */
+ { 0x00000E44, 0x04CC }, /* R3652 - EQ3_9 */
+ { 0x00000E45, 0x1C9B }, /* R3653 - EQ3_10 */
+ { 0x00000E46, 0xF337 }, /* R3654 - EQ3_11 */
+ { 0x00000E47, 0x040B }, /* R3655 - EQ3_12 */
+ { 0x00000E48, 0x0CBB }, /* R3656 - EQ3_13 */
+ { 0x00000E49, 0x16F8 }, /* R3657 - EQ3_14 */
+ { 0x00000E4A, 0xF7D9 }, /* R3658 - EQ3_15 */
+ { 0x00000E4B, 0x040A }, /* R3659 - EQ3_16 */
+ { 0x00000E4C, 0x1F14 }, /* R3660 - EQ3_17 */
+ { 0x00000E4D, 0x058C }, /* R3661 - EQ3_18 */
+ { 0x00000E4E, 0x0563 }, /* R3662 - EQ3_19 */
+ { 0x00000E4F, 0x4000 }, /* R3663 - EQ3_20 */
+ { 0x00000E50, 0x0B75 }, /* R3664 - EQ3_21 */
+ { 0x00000E52, 0x6318 }, /* R3666 - EQ4_1 */
+ { 0x00000E53, 0x6300 }, /* R3667 - EQ4_2 */
+ { 0x00000E54, 0x0FC8 }, /* R3668 - EQ4_3 */
+ { 0x00000E55, 0x03FE }, /* R3669 - EQ4_4 */
+ { 0x00000E56, 0x00E0 }, /* R3670 - EQ4_5 */
+ { 0x00000E57, 0x1EC4 }, /* R3671 - EQ4_6 */
+ { 0x00000E58, 0xF136 }, /* R3672 - EQ4_7 */
+ { 0x00000E59, 0x0409 }, /* R3673 - EQ4_8 */
+ { 0x00000E5A, 0x04CC }, /* R3674 - EQ4_9 */
+ { 0x00000E5B, 0x1C9B }, /* R3675 - EQ4_10 */
+ { 0x00000E5C, 0xF337 }, /* R3676 - EQ4_11 */
+ { 0x00000E5D, 0x040B }, /* R3677 - EQ4_12 */
+ { 0x00000E5E, 0x0CBB }, /* R3678 - EQ4_13 */
+ { 0x00000E5F, 0x16F8 }, /* R3679 - EQ4_14 */
+ { 0x00000E60, 0xF7D9 }, /* R3680 - EQ4_15 */
+ { 0x00000E61, 0x040A }, /* R3681 - EQ4_16 */
+ { 0x00000E62, 0x1F14 }, /* R3682 - EQ4_17 */
+ { 0x00000E63, 0x058C }, /* R3683 - EQ4_18 */
+ { 0x00000E64, 0x0563 }, /* R3684 - EQ4_19 */
+ { 0x00000E65, 0x4000 }, /* R3685 - EQ4_20 */
+ { 0x00000E66, 0x0B75 }, /* R3686 - EQ4_21 */
+ { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */
+ { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */
+ { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */
+ { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */
+ { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */
+ { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */
+ { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */
+ { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */
+ { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */
+ { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */
+ { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */
+ { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */
+ { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
+ { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */
+ { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */
+ { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */
+ { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */
+ { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */
+ { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */
+ { 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */
+ { 0x00001101, 0x0000 }, /* R4353 - DSP1 Clocking 1 */
+};
+
+static bool wm8997_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ARIZONA_SOFTWARE_RESET:
+ case ARIZONA_DEVICE_REVISION:
+ case ARIZONA_CTRL_IF_I2C1_CFG_1:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_0:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_1:
+ case ARIZONA_WRITE_SEQUENCER_CTRL_2:
+ case ARIZONA_TONE_GENERATOR_1:
+ case ARIZONA_TONE_GENERATOR_2:
+ case ARIZONA_TONE_GENERATOR_3:
+ case ARIZONA_TONE_GENERATOR_4:
+ case ARIZONA_TONE_GENERATOR_5:
+ case ARIZONA_PWM_DRIVE_1:
+ case ARIZONA_PWM_DRIVE_2:
+ case ARIZONA_PWM_DRIVE_3:
+ case ARIZONA_WAKE_CONTROL:
+ case ARIZONA_SEQUENCE_CONTROL:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3:
+ case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4:
+ case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1:
+ case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2:
+ case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3:
+ case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4:
+ case ARIZONA_COMFORT_NOISE_GENERATOR:
+ case ARIZONA_HAPTICS_CONTROL_1:
+ case ARIZONA_HAPTICS_CONTROL_2:
+ case ARIZONA_HAPTICS_PHASE_1_INTENSITY:
+ case ARIZONA_HAPTICS_PHASE_1_DURATION:
+ case ARIZONA_HAPTICS_PHASE_2_INTENSITY:
+ case ARIZONA_HAPTICS_PHASE_2_DURATION:
+ case ARIZONA_HAPTICS_PHASE_3_INTENSITY:
+ case ARIZONA_HAPTICS_PHASE_3_DURATION:
+ case ARIZONA_HAPTICS_STATUS:
+ case ARIZONA_CLOCK_32K_1:
+ case ARIZONA_SYSTEM_CLOCK_1:
+ case ARIZONA_SAMPLE_RATE_1:
+ case ARIZONA_SAMPLE_RATE_2:
+ case ARIZONA_SAMPLE_RATE_3:
+ case ARIZONA_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_SAMPLE_RATE_2_STATUS:
+ case ARIZONA_SAMPLE_RATE_3_STATUS:
+ case ARIZONA_ASYNC_CLOCK_1:
+ case ARIZONA_ASYNC_SAMPLE_RATE_1:
+ case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_OUTPUT_SYSTEM_CLOCK:
+ case ARIZONA_OUTPUT_ASYNC_CLOCK:
+ case ARIZONA_RATE_ESTIMATOR_1:
+ case ARIZONA_RATE_ESTIMATOR_2:
+ case ARIZONA_RATE_ESTIMATOR_3:
+ case ARIZONA_RATE_ESTIMATOR_4:
+ case ARIZONA_RATE_ESTIMATOR_5:
+ case ARIZONA_FLL1_CONTROL_1:
+ case ARIZONA_FLL1_CONTROL_2:
+ case ARIZONA_FLL1_CONTROL_3:
+ case ARIZONA_FLL1_CONTROL_4:
+ case ARIZONA_FLL1_CONTROL_5:
+ case ARIZONA_FLL1_CONTROL_6:
+ case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
+ case ARIZONA_FLL1_NCO_TEST_0:
+ case ARIZONA_FLL1_SYNCHRONISER_1:
+ case ARIZONA_FLL1_SYNCHRONISER_2:
+ case ARIZONA_FLL1_SYNCHRONISER_3:
+ case ARIZONA_FLL1_SYNCHRONISER_4:
+ case ARIZONA_FLL1_SYNCHRONISER_5:
+ case ARIZONA_FLL1_SYNCHRONISER_6:
+ case ARIZONA_FLL1_SPREAD_SPECTRUM:
+ case ARIZONA_FLL1_GPIO_CLOCK:
+ case ARIZONA_FLL2_CONTROL_1:
+ case ARIZONA_FLL2_CONTROL_2:
+ case ARIZONA_FLL2_CONTROL_3:
+ case ARIZONA_FLL2_CONTROL_4:
+ case ARIZONA_FLL2_CONTROL_5:
+ case ARIZONA_FLL2_CONTROL_6:
+ case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
+ case ARIZONA_FLL2_NCO_TEST_0:
+ case ARIZONA_FLL2_SYNCHRONISER_1:
+ case ARIZONA_FLL2_SYNCHRONISER_2:
+ case ARIZONA_FLL2_SYNCHRONISER_3:
+ case ARIZONA_FLL2_SYNCHRONISER_4:
+ case ARIZONA_FLL2_SYNCHRONISER_5:
+ case ARIZONA_FLL2_SYNCHRONISER_6:
+ case ARIZONA_FLL2_SPREAD_SPECTRUM:
+ case ARIZONA_FLL2_GPIO_CLOCK:
+ case ARIZONA_MIC_CHARGE_PUMP_1:
+ case ARIZONA_LDO1_CONTROL_1:
+ case ARIZONA_LDO2_CONTROL_1:
+ case ARIZONA_MIC_BIAS_CTRL_1:
+ case ARIZONA_MIC_BIAS_CTRL_2:
+ case ARIZONA_MIC_BIAS_CTRL_3:
+ case ARIZONA_ACCESSORY_DETECT_MODE_1:
+ case ARIZONA_HEADPHONE_DETECT_1:
+ case ARIZONA_HEADPHONE_DETECT_2:
+ case ARIZONA_MIC_DETECT_1:
+ case ARIZONA_MIC_DETECT_2:
+ case ARIZONA_MIC_DETECT_3:
+ case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
+ case ARIZONA_ISOLATION_CONTROL:
+ case ARIZONA_JACK_DETECT_ANALOGUE:
+ case ARIZONA_INPUT_ENABLES:
+ case ARIZONA_INPUT_ENABLES_STATUS:
+ case ARIZONA_INPUT_RATE:
+ case ARIZONA_INPUT_VOLUME_RAMP:
+ case ARIZONA_IN1L_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_1L:
+ case ARIZONA_DMIC1L_CONTROL:
+ case ARIZONA_IN1R_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_1R:
+ case ARIZONA_DMIC1R_CONTROL:
+ case ARIZONA_IN2L_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_2L:
+ case ARIZONA_DMIC2L_CONTROL:
+ case ARIZONA_IN2R_CONTROL:
+ case ARIZONA_ADC_DIGITAL_VOLUME_2R:
+ case ARIZONA_DMIC2R_CONTROL:
+ case ARIZONA_OUTPUT_ENABLES_1:
+ case ARIZONA_OUTPUT_STATUS_1:
+ case ARIZONA_RAW_OUTPUT_STATUS_1:
+ case ARIZONA_OUTPUT_RATE_1:
+ case ARIZONA_OUTPUT_VOLUME_RAMP:
+ case ARIZONA_OUTPUT_PATH_CONFIG_1L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_1L:
+ case ARIZONA_DAC_VOLUME_LIMIT_1L:
+ case ARIZONA_NOISE_GATE_SELECT_1L:
+ case ARIZONA_OUTPUT_PATH_CONFIG_1R:
+ case ARIZONA_DAC_DIGITAL_VOLUME_1R:
+ case ARIZONA_DAC_VOLUME_LIMIT_1R:
+ case ARIZONA_NOISE_GATE_SELECT_1R:
+ case ARIZONA_OUTPUT_PATH_CONFIG_3L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_3L:
+ case ARIZONA_DAC_VOLUME_LIMIT_3L:
+ case ARIZONA_NOISE_GATE_SELECT_3L:
+ case ARIZONA_OUTPUT_PATH_CONFIG_4L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_4L:
+ case ARIZONA_OUT_VOLUME_4L:
+ case ARIZONA_NOISE_GATE_SELECT_4L:
+ case ARIZONA_OUTPUT_PATH_CONFIG_5L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_5L:
+ case ARIZONA_DAC_VOLUME_LIMIT_5L:
+ case ARIZONA_NOISE_GATE_SELECT_5L:
+ case ARIZONA_DAC_DIGITAL_VOLUME_5R:
+ case ARIZONA_DAC_VOLUME_LIMIT_5R:
+ case ARIZONA_NOISE_GATE_SELECT_5R:
+ case ARIZONA_DAC_AEC_CONTROL_1:
+ case ARIZONA_NOISE_GATE_CONTROL:
+ case ARIZONA_PDM_SPK1_CTRL_1:
+ case ARIZONA_PDM_SPK1_CTRL_2:
+ case ARIZONA_AIF1_BCLK_CTRL:
+ case ARIZONA_AIF1_TX_PIN_CTRL:
+ case ARIZONA_AIF1_RX_PIN_CTRL:
+ case ARIZONA_AIF1_RATE_CTRL:
+ case ARIZONA_AIF1_FORMAT:
+ case ARIZONA_AIF1_TX_BCLK_RATE:
+ case ARIZONA_AIF1_RX_BCLK_RATE:
+ case ARIZONA_AIF1_FRAME_CTRL_1:
+ case ARIZONA_AIF1_FRAME_CTRL_2:
+ case ARIZONA_AIF1_FRAME_CTRL_3:
+ case ARIZONA_AIF1_FRAME_CTRL_4:
+ case ARIZONA_AIF1_FRAME_CTRL_5:
+ case ARIZONA_AIF1_FRAME_CTRL_6:
+ case ARIZONA_AIF1_FRAME_CTRL_7:
+ case ARIZONA_AIF1_FRAME_CTRL_8:
+ case ARIZONA_AIF1_FRAME_CTRL_9:
+ case ARIZONA_AIF1_FRAME_CTRL_10:
+ case ARIZONA_AIF1_FRAME_CTRL_11:
+ case ARIZONA_AIF1_FRAME_CTRL_12:
+ case ARIZONA_AIF1_FRAME_CTRL_13:
+ case ARIZONA_AIF1_FRAME_CTRL_14:
+ case ARIZONA_AIF1_FRAME_CTRL_15:
+ case ARIZONA_AIF1_FRAME_CTRL_16:
+ case ARIZONA_AIF1_FRAME_CTRL_17:
+ case ARIZONA_AIF1_FRAME_CTRL_18:
+ case ARIZONA_AIF1_TX_ENABLES:
+ case ARIZONA_AIF1_RX_ENABLES:
+ case ARIZONA_AIF2_BCLK_CTRL:
+ case ARIZONA_AIF2_TX_PIN_CTRL:
+ case ARIZONA_AIF2_RX_PIN_CTRL:
+ case ARIZONA_AIF2_RATE_CTRL:
+ case ARIZONA_AIF2_FORMAT:
+ case ARIZONA_AIF2_TX_BCLK_RATE:
+ case ARIZONA_AIF2_RX_BCLK_RATE:
+ case ARIZONA_AIF2_FRAME_CTRL_1:
+ case ARIZONA_AIF2_FRAME_CTRL_2:
+ case ARIZONA_AIF2_FRAME_CTRL_3:
+ case ARIZONA_AIF2_FRAME_CTRL_4:
+ case ARIZONA_AIF2_FRAME_CTRL_11:
+ case ARIZONA_AIF2_FRAME_CTRL_12:
+ case ARIZONA_AIF2_TX_ENABLES:
+ case ARIZONA_AIF2_RX_ENABLES:
+ case ARIZONA_SLIMBUS_FRAMER_REF_GEAR:
+ case ARIZONA_SLIMBUS_RATES_1:
+ case ARIZONA_SLIMBUS_RATES_2:
+ case ARIZONA_SLIMBUS_RATES_3:
+ case ARIZONA_SLIMBUS_RATES_4:
+ case ARIZONA_SLIMBUS_RATES_5:
+ case ARIZONA_SLIMBUS_RATES_6:
+ case ARIZONA_SLIMBUS_RATES_7:
+ case ARIZONA_SLIMBUS_RATES_8:
+ case ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE:
+ case ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE:
+ case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+ case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+ case ARIZONA_PWM1MIX_INPUT_1_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_1_VOLUME:
+ case ARIZONA_PWM1MIX_INPUT_2_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_2_VOLUME:
+ case ARIZONA_PWM1MIX_INPUT_3_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_3_VOLUME:
+ case ARIZONA_PWM1MIX_INPUT_4_SOURCE:
+ case ARIZONA_PWM1MIX_INPUT_4_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_1_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_1_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_2_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_2_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_3_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_3_VOLUME:
+ case ARIZONA_PWM2MIX_INPUT_4_SOURCE:
+ case ARIZONA_PWM2MIX_INPUT_4_VOLUME:
+ case ARIZONA_MICMIX_INPUT_1_SOURCE:
+ case ARIZONA_MICMIX_INPUT_1_VOLUME:
+ case ARIZONA_MICMIX_INPUT_2_SOURCE:
+ case ARIZONA_MICMIX_INPUT_2_VOLUME:
+ case ARIZONA_MICMIX_INPUT_3_SOURCE:
+ case ARIZONA_MICMIX_INPUT_3_VOLUME:
+ case ARIZONA_MICMIX_INPUT_4_SOURCE:
+ case ARIZONA_MICMIX_INPUT_4_VOLUME:
+ case ARIZONA_NOISEMIX_INPUT_1_SOURCE:
+ case ARIZONA_NOISEMIX_INPUT_1_VOLUME:
+ case ARIZONA_NOISEMIX_INPUT_2_SOURCE:
+ case ARIZONA_NOISEMIX_INPUT_2_VOLUME:
+ case ARIZONA_NOISEMIX_INPUT_3_SOURCE:
+ case ARIZONA_NOISEMIX_INPUT_3_VOLUME:
+ case ARIZONA_NOISEMIX_INPUT_4_SOURCE:
+ case ARIZONA_NOISEMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT1LMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT1LMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT1RMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT1RMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT3LMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT3LMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT3LMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT3LMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT3LMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT3LMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT3LMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT3LMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT4LMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT4LMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT5LMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT5LMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT5LMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT5LMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT5LMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT5LMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT5LMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT5LMIX_INPUT_4_VOLUME:
+ case ARIZONA_OUT5RMIX_INPUT_1_SOURCE:
+ case ARIZONA_OUT5RMIX_INPUT_1_VOLUME:
+ case ARIZONA_OUT5RMIX_INPUT_2_SOURCE:
+ case ARIZONA_OUT5RMIX_INPUT_2_VOLUME:
+ case ARIZONA_OUT5RMIX_INPUT_3_SOURCE:
+ case ARIZONA_OUT5RMIX_INPUT_3_VOLUME:
+ case ARIZONA_OUT5RMIX_INPUT_4_SOURCE:
+ case ARIZONA_OUT5RMIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX1MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX1MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX2MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX2MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX3MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX3MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX4MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX4MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX5MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX5MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX6MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX6MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX7MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX7MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF1TX8MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF1TX8MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX1MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX1MIX_INPUT_4_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_1_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_2_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_2_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_3_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME:
+ case ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE:
+ case ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX1MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX1MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX1MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX1MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX1MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX1MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX1MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX2MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX2MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX2MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX2MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX2MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX2MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX2MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX3MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX3MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX3MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX3MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX3MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX3MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX3MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX4MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX4MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX4MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX4MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX4MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX4MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX4MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX5MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX5MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX5MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX5MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX5MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX5MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX5MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX6MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX6MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX6MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX6MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX6MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX6MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX6MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX7MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX7MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX7MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX7MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX7MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX7MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX7MIX_INPUT_4_VOLUME:
+ case ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE:
+ case ARIZONA_SLIMTX8MIX_INPUT_1_VOLUME:
+ case ARIZONA_SLIMTX8MIX_INPUT_2_SOURCE:
+ case ARIZONA_SLIMTX8MIX_INPUT_2_VOLUME:
+ case ARIZONA_SLIMTX8MIX_INPUT_3_SOURCE:
+ case ARIZONA_SLIMTX8MIX_INPUT_3_VOLUME:
+ case ARIZONA_SLIMTX8MIX_INPUT_4_SOURCE:
+ case ARIZONA_SLIMTX8MIX_INPUT_4_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_1_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_1_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_2_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_2_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_3_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_3_VOLUME:
+ case ARIZONA_EQ1MIX_INPUT_4_SOURCE:
+ case ARIZONA_EQ1MIX_INPUT_4_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_1_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_1_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_2_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_2_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_3_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_3_VOLUME:
+ case ARIZONA_EQ2MIX_INPUT_4_SOURCE:
+ case ARIZONA_EQ2MIX_INPUT_4_VOLUME:
+ case ARIZONA_EQ3MIX_INPUT_1_SOURCE:
+ case ARIZONA_EQ3MIX_INPUT_1_VOLUME:
+ case ARIZONA_EQ3MIX_INPUT_2_SOURCE:
+ case ARIZONA_EQ3MIX_INPUT_2_VOLUME:
+ case ARIZONA_EQ3MIX_INPUT_3_SOURCE:
+ case ARIZONA_EQ3MIX_INPUT_3_VOLUME:
+ case ARIZONA_EQ3MIX_INPUT_4_SOURCE:
+ case ARIZONA_EQ3MIX_INPUT_4_VOLUME:
+ case ARIZONA_EQ4MIX_INPUT_1_SOURCE:
+ case ARIZONA_EQ4MIX_INPUT_1_VOLUME:
+ case ARIZONA_EQ4MIX_INPUT_2_SOURCE:
+ case ARIZONA_EQ4MIX_INPUT_2_VOLUME:
+ case ARIZONA_EQ4MIX_INPUT_3_SOURCE:
+ case ARIZONA_EQ4MIX_INPUT_3_VOLUME:
+ case ARIZONA_EQ4MIX_INPUT_4_SOURCE:
+ case ARIZONA_EQ4MIX_INPUT_4_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_1_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_1_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_2_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_2_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_3_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_3_VOLUME:
+ case ARIZONA_DRC1LMIX_INPUT_4_SOURCE:
+ case ARIZONA_DRC1LMIX_INPUT_4_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_1_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_1_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_2_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_2_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_3_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_3_VOLUME:
+ case ARIZONA_DRC1RMIX_INPUT_4_SOURCE:
+ case ARIZONA_DRC1RMIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP1MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP1MIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP2MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP2MIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP3MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP3MIX_INPUT_4_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_1_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_1_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_2_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_2_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_3_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_3_VOLUME:
+ case ARIZONA_HPLP4MIX_INPUT_4_SOURCE:
+ case ARIZONA_HPLP4MIX_INPUT_4_VOLUME:
+ case ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE:
+ case ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE:
+ case ARIZONA_GPIO1_CTRL:
+ case ARIZONA_GPIO2_CTRL:
+ case ARIZONA_GPIO3_CTRL:
+ case ARIZONA_GPIO4_CTRL:
+ case ARIZONA_GPIO5_CTRL:
+ case ARIZONA_IRQ_CTRL_1:
+ case ARIZONA_GPIO_DEBOUNCE_CONFIG:
+ case ARIZONA_MISC_PAD_CTRL_1:
+ case ARIZONA_MISC_PAD_CTRL_2:
+ case ARIZONA_MISC_PAD_CTRL_3:
+ case ARIZONA_MISC_PAD_CTRL_4:
+ case ARIZONA_MISC_PAD_CTRL_5:
+ case ARIZONA_INTERRUPT_STATUS_1:
+ case ARIZONA_INTERRUPT_STATUS_2:
+ case ARIZONA_INTERRUPT_STATUS_3:
+ case ARIZONA_INTERRUPT_STATUS_4:
+ case ARIZONA_INTERRUPT_STATUS_5:
+ case ARIZONA_INTERRUPT_STATUS_1_MASK:
+ case ARIZONA_INTERRUPT_STATUS_3_MASK:
+ case ARIZONA_INTERRUPT_STATUS_4_MASK:
+ case ARIZONA_INTERRUPT_STATUS_5_MASK:
+ case ARIZONA_INTERRUPT_CONTROL:
+ case ARIZONA_IRQ2_STATUS_1:
+ case ARIZONA_IRQ2_STATUS_3:
+ case ARIZONA_IRQ2_STATUS_4:
+ case ARIZONA_IRQ2_STATUS_5:
+ case ARIZONA_IRQ2_STATUS_1_MASK:
+ case ARIZONA_IRQ2_STATUS_3_MASK:
+ case ARIZONA_IRQ2_STATUS_4_MASK:
+ case ARIZONA_IRQ2_STATUS_5_MASK:
+ case ARIZONA_IRQ2_CONTROL:
+ case ARIZONA_INTERRUPT_RAW_STATUS_3:
+ case ARIZONA_INTERRUPT_RAW_STATUS_4:
+ case ARIZONA_INTERRUPT_RAW_STATUS_5:
+ case ARIZONA_INTERRUPT_RAW_STATUS_6:
+ case ARIZONA_INTERRUPT_RAW_STATUS_7:
+ case ARIZONA_INTERRUPT_RAW_STATUS_8:
+ case ARIZONA_IRQ_PIN_STATUS:
+ case ARIZONA_AOD_WKUP_AND_TRIG:
+ case ARIZONA_AOD_IRQ1:
+ case ARIZONA_AOD_IRQ2:
+ case ARIZONA_AOD_IRQ_MASK_IRQ1:
+ case ARIZONA_AOD_IRQ_MASK_IRQ2:
+ case ARIZONA_AOD_IRQ_RAW_STATUS:
+ case ARIZONA_JACK_DETECT_DEBOUNCE:
+ case ARIZONA_FX_CTRL1:
+ case ARIZONA_FX_CTRL2:
+ case ARIZONA_EQ1_1:
+ case ARIZONA_EQ1_2:
+ case ARIZONA_EQ1_3:
+ case ARIZONA_EQ1_4:
+ case ARIZONA_EQ1_5:
+ case ARIZONA_EQ1_6:
+ case ARIZONA_EQ1_7:
+ case ARIZONA_EQ1_8:
+ case ARIZONA_EQ1_9:
+ case ARIZONA_EQ1_10:
+ case ARIZONA_EQ1_11:
+ case ARIZONA_EQ1_12:
+ case ARIZONA_EQ1_13:
+ case ARIZONA_EQ1_14:
+ case ARIZONA_EQ1_15:
+ case ARIZONA_EQ1_16:
+ case ARIZONA_EQ1_17:
+ case ARIZONA_EQ1_18:
+ case ARIZONA_EQ1_19:
+ case ARIZONA_EQ1_20:
+ case ARIZONA_EQ1_21:
+ case ARIZONA_EQ2_1:
+ case ARIZONA_EQ2_2:
+ case ARIZONA_EQ2_3:
+ case ARIZONA_EQ2_4:
+ case ARIZONA_EQ2_5:
+ case ARIZONA_EQ2_6:
+ case ARIZONA_EQ2_7:
+ case ARIZONA_EQ2_8:
+ case ARIZONA_EQ2_9:
+ case ARIZONA_EQ2_10:
+ case ARIZONA_EQ2_11:
+ case ARIZONA_EQ2_12:
+ case ARIZONA_EQ2_13:
+ case ARIZONA_EQ2_14:
+ case ARIZONA_EQ2_15:
+ case ARIZONA_EQ2_16:
+ case ARIZONA_EQ2_17:
+ case ARIZONA_EQ2_18:
+ case ARIZONA_EQ2_19:
+ case ARIZONA_EQ2_20:
+ case ARIZONA_EQ2_21:
+ case ARIZONA_EQ3_1:
+ case ARIZONA_EQ3_2:
+ case ARIZONA_EQ3_3:
+ case ARIZONA_EQ3_4:
+ case ARIZONA_EQ3_5:
+ case ARIZONA_EQ3_6:
+ case ARIZONA_EQ3_7:
+ case ARIZONA_EQ3_8:
+ case ARIZONA_EQ3_9:
+ case ARIZONA_EQ3_10:
+ case ARIZONA_EQ3_11:
+ case ARIZONA_EQ3_12:
+ case ARIZONA_EQ3_13:
+ case ARIZONA_EQ3_14:
+ case ARIZONA_EQ3_15:
+ case ARIZONA_EQ3_16:
+ case ARIZONA_EQ3_17:
+ case ARIZONA_EQ3_18:
+ case ARIZONA_EQ3_19:
+ case ARIZONA_EQ3_20:
+ case ARIZONA_EQ3_21:
+ case ARIZONA_EQ4_1:
+ case ARIZONA_EQ4_2:
+ case ARIZONA_EQ4_3:
+ case ARIZONA_EQ4_4:
+ case ARIZONA_EQ4_5:
+ case ARIZONA_EQ4_6:
+ case ARIZONA_EQ4_7:
+ case ARIZONA_EQ4_8:
+ case ARIZONA_EQ4_9:
+ case ARIZONA_EQ4_10:
+ case ARIZONA_EQ4_11:
+ case ARIZONA_EQ4_12:
+ case ARIZONA_EQ4_13:
+ case ARIZONA_EQ4_14:
+ case ARIZONA_EQ4_15:
+ case ARIZONA_EQ4_16:
+ case ARIZONA_EQ4_17:
+ case ARIZONA_EQ4_18:
+ case ARIZONA_EQ4_19:
+ case ARIZONA_EQ4_20:
+ case ARIZONA_EQ4_21:
+ case ARIZONA_DRC1_CTRL1:
+ case ARIZONA_DRC1_CTRL2:
+ case ARIZONA_DRC1_CTRL3:
+ case ARIZONA_DRC1_CTRL4:
+ case ARIZONA_DRC1_CTRL5:
+ case ARIZONA_HPLPF1_1:
+ case ARIZONA_HPLPF1_2:
+ case ARIZONA_HPLPF2_1:
+ case ARIZONA_HPLPF2_2:
+ case ARIZONA_HPLPF3_1:
+ case ARIZONA_HPLPF3_2:
+ case ARIZONA_HPLPF4_1:
+ case ARIZONA_HPLPF4_2:
+ case ARIZONA_ISRC_1_CTRL_1:
+ case ARIZONA_ISRC_1_CTRL_2:
+ case ARIZONA_ISRC_1_CTRL_3:
+ case ARIZONA_ISRC_2_CTRL_1:
+ case ARIZONA_ISRC_2_CTRL_2:
+ case ARIZONA_ISRC_2_CTRL_3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wm8997_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ARIZONA_SOFTWARE_RESET:
+ case ARIZONA_DEVICE_REVISION:
+ case ARIZONA_HAPTICS_STATUS:
+ case ARIZONA_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_SAMPLE_RATE_2_STATUS:
+ case ARIZONA_SAMPLE_RATE_3_STATUS:
+ case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
+ case ARIZONA_MIC_DETECT_3:
+ case ARIZONA_HEADPHONE_DETECT_2:
+ case ARIZONA_INPUT_ENABLES_STATUS:
+ case ARIZONA_OUTPUT_STATUS_1:
+ case ARIZONA_RAW_OUTPUT_STATUS_1:
+ case ARIZONA_SLIMBUS_RX_PORT_STATUS:
+ case ARIZONA_SLIMBUS_TX_PORT_STATUS:
+ case ARIZONA_INTERRUPT_STATUS_1:
+ case ARIZONA_INTERRUPT_STATUS_2:
+ case ARIZONA_INTERRUPT_STATUS_3:
+ case ARIZONA_INTERRUPT_STATUS_4:
+ case ARIZONA_INTERRUPT_STATUS_5:
+ case ARIZONA_IRQ2_STATUS_1:
+ case ARIZONA_IRQ2_STATUS_3:
+ case ARIZONA_IRQ2_STATUS_4:
+ case ARIZONA_IRQ2_STATUS_5:
+ case ARIZONA_INTERRUPT_RAW_STATUS_3:
+ case ARIZONA_INTERRUPT_RAW_STATUS_4:
+ case ARIZONA_INTERRUPT_RAW_STATUS_5:
+ case ARIZONA_INTERRUPT_RAW_STATUS_6:
+ case ARIZONA_INTERRUPT_RAW_STATUS_7:
+ case ARIZONA_INTERRUPT_RAW_STATUS_8:
+ case ARIZONA_IRQ_PIN_STATUS:
+ case ARIZONA_AOD_WKUP_AND_TRIG:
+ case ARIZONA_AOD_IRQ1:
+ case ARIZONA_AOD_IRQ2:
+ case ARIZONA_AOD_IRQ_RAW_STATUS:
+ case ARIZONA_FX_CTRL2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+#define WM8997_MAX_REGISTER 0x31ff
+
+const struct regmap_config wm8997_i2c_regmap = {
+ .reg_bits = 32,
+ .val_bits = 16,
+
+ .max_register = WM8997_MAX_REGISTER,
+ .readable_reg = wm8997_readable_register,
+ .volatile_reg = wm8997_volatile_register,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = wm8997_reg_default,
+ .num_reg_defaults = ARRAY_SIZE(wm8997_reg_default),
+};
+EXPORT_SYMBOL_GPL(wm8997_i2c_regmap);
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index 1abd5ad59925..f7b90661e321 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -58,7 +58,7 @@ struct ssc_device *ssc_request(unsigned int ssc_num)
ssc->user++;
spin_unlock(&user_lock);
- clk_enable(ssc->clk);
+ clk_prepare_enable(ssc->clk);
return ssc;
}
@@ -69,7 +69,7 @@ void ssc_free(struct ssc_device *ssc)
spin_lock(&user_lock);
if (ssc->user) {
ssc->user--;
- clk_disable(ssc->clk);
+ clk_disable_unprepare(ssc->clk);
} else {
dev_dbg(&ssc->pdev->dev, "device already free\n");
}
@@ -167,10 +167,10 @@ static int ssc_probe(struct platform_device *pdev)
}
/* disable all interrupts */
- clk_enable(ssc->clk);
+ clk_prepare_enable(ssc->clk);
ssc_writel(ssc->regs, IDR, -1);
ssc_readl(ssc->regs, SR);
- clk_disable(ssc->clk);
+ clk_disable_unprepare(ssc->clk);
ssc->irq = platform_get_irq(pdev, 0);
if (!ssc->irq) {
diff --git a/drivers/misc/dummy-irq.c b/drivers/misc/dummy-irq.c
index c37eeedfe215..4d0db15df115 100644
--- a/drivers/misc/dummy-irq.c
+++ b/drivers/misc/dummy-irq.c
@@ -26,7 +26,7 @@ static irqreturn_t dummy_interrupt(int irq, void *dev_id)
static int count = 0;
if (count == 0) {
- printk(KERN_INFO "dummy-irq: interrupt occured on IRQ %d\n",
+ printk(KERN_INFO "dummy-irq: interrupt occurred on IRQ %d\n",
irq);
count++;
}
diff --git a/drivers/misc/lattice-ecp3-config.c b/drivers/misc/lattice-ecp3-config.c
index bb26f086bd8b..61fbe6acabef 100644
--- a/drivers/misc/lattice-ecp3-config.c
+++ b/drivers/misc/lattice-ecp3-config.c
@@ -170,7 +170,7 @@ static void firmware_load(const struct firmware *fw, void *context)
/* Check result */
if (status & FPGA_STATUS_DONE)
- dev_info(&spi->dev, "FPGA succesfully configured!\n");
+ dev_info(&spi->dev, "FPGA successfully configured!\n");
else
dev_info(&spi->dev, "FPGA not configured (DONE not set)\n");
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 565027b1bc73..f9296abcf02a 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -139,7 +139,7 @@ int mei_hbm_start_wait(struct mei_device *dev)
if (ret <= 0 && (dev->hbm_state <= MEI_HBM_START)) {
dev->hbm_state = MEI_HBM_IDLE;
- dev_err(&dev->pdev->dev, "wating for mei start failed\n");
+ dev_err(&dev->pdev->dev, "waiting for mei start failed\n");
return -ETIMEDOUT;
}
return 0;
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c
index 6fc573cef178..ed1d75203af6 100644
--- a/drivers/misc/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -38,7 +38,7 @@ const char *mei_dev_state_str(int state)
MEI_DEV_STATE(POWER_DOWN);
MEI_DEV_STATE(POWER_UP);
default:
- return "unkown";
+ return "unknown";
}
#undef MEI_DEV_STATE
}
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index c4acac74725c..f74fc0ca2ef9 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -876,8 +876,9 @@ int gru_set_context_option(unsigned long arg)
switch (req.op) {
case sco_blade_chiplet:
/* Select blade/chiplet for GRU context */
- if (req.val1 < -1 || req.val1 >= GRU_MAX_BLADES || !gru_base[req.val1] ||
- req.val0 < -1 || req.val0 >= GRU_CHIPLETS_PER_HUB) {
+ if (req.val0 < -1 || req.val0 >= GRU_CHIPLETS_PER_HUB ||
+ req.val1 < -1 || req.val1 >= GRU_MAX_BLADES ||
+ (req.val1 >= 0 && !gru_base[req.val1])) {
ret = -EINVAL;
} else {
gts->ts_user_blade_id = req.val1;
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index d971817182f7..82dc5748f873 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -92,7 +92,7 @@ int xpc_disengage_timelimit = XPC_DISENGAGE_DEFAULT_TIMELIMIT;
static int xpc_disengage_min_timelimit; /* = 0 */
static int xpc_disengage_max_timelimit = 120;
-static ctl_table xpc_sys_xpc_hb_dir[] = {
+static struct ctl_table xpc_sys_xpc_hb_dir[] = {
{
.procname = "hb_interval",
.data = &xpc_hb_interval,
@@ -111,7 +111,7 @@ static ctl_table xpc_sys_xpc_hb_dir[] = {
.extra2 = &xpc_hb_check_max_interval},
{}
};
-static ctl_table xpc_sys_xpc_dir[] = {
+static struct ctl_table xpc_sys_xpc_dir[] = {
{
.procname = "hb",
.mode = 0555,
@@ -126,7 +126,7 @@ static ctl_table xpc_sys_xpc_dir[] = {
.extra2 = &xpc_disengage_max_timelimit},
{}
};
-static ctl_table xpc_sys_dir[] = {
+static struct ctl_table xpc_sys_dir[] = {
{
.procname = "xpc",
.mode = 0555,
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index dd27b0783d52..cd0b7f4a1ff2 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/capability.h>
#include <linux/compat.h>
+#include <linux/pm_runtime.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@@ -58,6 +59,8 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+#define MMC_SANITIZE_REQ_TIMEOUT 240000
+#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
(req->cmd_flags & REQ_META)) && \
@@ -222,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
- mmc_claim_host(card->host);
+ mmc_get_card(card);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
card->ext_csd.boot_ro_lock |
@@ -233,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
else
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
- mmc_release_host(card->host);
+ mmc_put_card(card);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -408,6 +411,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
return err;
}
+static int ioctl_do_sanitize(struct mmc_card *card)
+{
+ int err;
+
+ if (!(mmc_can_sanitize(card) &&
+ (card->host->caps2 & MMC_CAP2_SANITIZE))) {
+ pr_warn("%s: %s - SANITIZE is not supported\n",
+ mmc_hostname(card->host), __func__);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
+ mmc_hostname(card->host), __func__);
+
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_SANITIZE_START, 1,
+ MMC_SANITIZE_REQ_TIMEOUT);
+
+ if (err)
+ pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
+ mmc_hostname(card->host), __func__, err);
+
+ pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
+ __func__);
+out:
+ return err;
+}
+
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@@ -491,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mrq.cmd = &cmd;
- mmc_claim_host(card->host);
+ mmc_get_card(card);
err = mmc_blk_part_switch(card, md);
if (err)
@@ -510,6 +542,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_rel_host;
}
+ if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
+ (cmd.opcode == MMC_SWITCH)) {
+ err = ioctl_do_sanitize(card);
+
+ if (err)
+ pr_err("%s: ioctl_do_sanitize() failed. err = %d",
+ __func__, err);
+
+ goto cmd_rel_host;
+ }
+
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@@ -558,7 +601,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
cmd_rel_host:
- mmc_release_host(card->host);
+ mmc_put_card(card);
cmd_done:
mmc_blk_put(md);
@@ -939,10 +982,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
- unsigned int from, nr, arg, trim_arg, erase_arg;
+ unsigned int from, nr, arg;
int err = 0, type = MMC_BLK_SECDISCARD;
- if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
+ if (!(mmc_can_secure_erase_trim(card))) {
err = -EOPNOTSUPP;
goto out;
}
@@ -950,23 +993,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
- /* The sanitize operation is supported at v4.5 only */
- if (mmc_can_sanitize(card)) {
- erase_arg = MMC_ERASE_ARG;
- trim_arg = MMC_TRIM_ARG;
- } else {
- erase_arg = MMC_SECURE_ERASE_ARG;
- trim_arg = MMC_SECURE_TRIM1_ARG;
- }
+ if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
+ arg = MMC_SECURE_TRIM1_ARG;
+ else
+ arg = MMC_SECURE_ERASE_ARG;
- if (mmc_erase_group_aligned(card, from, nr))
- arg = erase_arg;
- else if (mmc_can_trim(card))
- arg = trim_arg;
- else {
- err = -EINVAL;
- goto out;
- }
retry:
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1002,9 +1033,6 @@ retry:
goto out;
}
- if (mmc_can_sanitize(card))
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_SANITIZE_START, 1, 0);
out_retry:
if (err && !mmc_blk_reset(md, card->host, type))
goto retry;
@@ -1895,7 +1923,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (req && !mq->mqrq_prev->req)
/* claim host only for the first request */
- mmc_claim_host(card->host);
+ mmc_get_card(card);
ret = mmc_blk_part_switch(card, md);
if (ret) {
@@ -1939,7 +1967,7 @@ out:
* In case sepecial request, there is no reentry to
* the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
*/
- mmc_release_host(card->host);
+ mmc_put_card(card);
return ret;
}
@@ -2158,6 +2186,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
struct mmc_card *card;
if (md) {
+ /*
+ * Flush remaining requests and free queues. It
+ * is freeing the queue that stops new requests
+ * from being accepted.
+ */
+ mmc_cleanup_queue(&md->queue);
+ if (md->flags & MMC_BLK_PACKED_CMD)
+ mmc_packed_clean(&md->queue);
card = md->queue.card;
if (md->disk->flags & GENHD_FL_UP) {
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
@@ -2166,14 +2202,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
device_remove_file(disk_to_dev(md->disk),
&md->power_ro_lock);
- /* Stop new requests from getting into the queue */
del_gendisk(md->disk);
}
-
- /* Then flush out any already in there */
- mmc_cleanup_queue(&md->queue);
- if (md->flags & MMC_BLK_PACKED_CMD)
- mmc_packed_clean(&md->queue);
mmc_blk_put(md);
}
}
@@ -2336,6 +2366,19 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_add_disk(part_md))
goto out;
}
+
+ pm_runtime_set_autosuspend_delay(&card->dev, 3000);
+ pm_runtime_use_autosuspend(&card->dev);
+
+ /*
+ * Don't enable runtime PM for SD-combo cards here. Leave that
+ * decision to be taken during the SDIO init sequence instead.
+ */
+ if (card->type != MMC_TYPE_SD_COMBO) {
+ pm_runtime_set_active(&card->dev);
+ pm_runtime_enable(&card->dev);
+ }
+
return 0;
out:
@@ -2349,20 +2392,24 @@ static void mmc_blk_remove(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card);
mmc_blk_remove_parts(card, md);
+ pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
mmc_blk_part_switch(card, md);
mmc_release_host(card->host);
+ if (card->type != MMC_TYPE_SD_COMBO)
+ pm_runtime_disable(&card->dev);
+ pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
mmc_set_drvdata(card, NULL);
}
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card)
+static int _mmc_blk_suspend(struct mmc_card *card)
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
+ pm_runtime_get_sync(&card->dev);
mmc_queue_suspend(&md->queue);
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_suspend(&part_md->queue);
@@ -2371,6 +2418,17 @@ static int mmc_blk_suspend(struct mmc_card *card)
return 0;
}
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+ _mmc_blk_suspend(card);
+}
+
+#ifdef CONFIG_PM
+static int mmc_blk_suspend(struct mmc_card *card)
+{
+ return _mmc_blk_suspend(card);
+}
+
static int mmc_blk_resume(struct mmc_card *card)
{
struct mmc_blk_data *part_md;
@@ -2386,6 +2444,7 @@ static int mmc_blk_resume(struct mmc_card *card)
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_resume(&part_md->queue);
}
+ pm_runtime_put(&card->dev);
}
return 0;
}
@@ -2402,6 +2461,7 @@ static struct mmc_driver mmc_driver = {
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
+ .shutdown = mmc_blk_shutdown,
};
static int __init mmc_blk_init(void)
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 759714ed6bee..a69df5216274 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -3025,12 +3025,17 @@ static void mmc_test_remove(struct mmc_card *card)
mmc_test_free_dbgfs_file(card);
}
+static void mmc_test_shutdown(struct mmc_card *card)
+{
+}
+
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmc_test",
},
.probe = mmc_test_probe,
.remove = mmc_test_remove,
+ .shutdown = mmc_test_shutdown,
};
static int __init mmc_test_init(void)
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 9447a0e970d1..fa9632eb63f1 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
/* granularity must not be greater than max. discard */
if (card->pref_erase > max_discard)
q->limits.discard_granularity = 0;
- if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+ if (mmc_can_secure_erase_trim(card))
queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index e219c97a02a4..704bf66f5873 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -122,15 +122,39 @@ static int mmc_bus_remove(struct device *dev)
return 0;
}
+static void mmc_bus_shutdown(struct device *dev)
+{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret;
+
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(card);
+
+ if (host->bus_ops->shutdown) {
+ ret = host->bus_ops->shutdown(host);
+ if (ret)
+ pr_warn("%s: error %d during shutdown\n",
+ mmc_hostname(host), ret);
+ }
+}
+
#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
- int ret = 0;
+ struct mmc_host *host = card->host;
+ int ret;
- if (dev->driver && drv->suspend)
+ if (dev->driver && drv->suspend) {
ret = drv->suspend(card);
+ if (ret)
+ return ret;
+ }
+
+ ret = host->bus_ops->suspend(host);
return ret;
}
@@ -138,10 +162,17 @@ static int mmc_bus_resume(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
- int ret = 0;
+ struct mmc_host *host = card->host;
+ int ret;
+
+ ret = host->bus_ops->resume(host);
+ if (ret)
+ pr_warn("%s: error %d during resume (card was removed?)\n",
+ mmc_hostname(host), ret);
if (dev->driver && drv->resume)
ret = drv->resume(card);
+
return ret;
}
#endif
@@ -151,20 +182,30 @@ static int mmc_bus_resume(struct device *dev)
static int mmc_runtime_suspend(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret = 0;
- return mmc_power_save_host(card->host);
+ if (host->bus_ops->runtime_suspend)
+ ret = host->bus_ops->runtime_suspend(host);
+
+ return ret;
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_host *host = card->host;
+ int ret = 0;
- return mmc_power_restore_host(card->host);
+ if (host->bus_ops->runtime_resume)
+ ret = host->bus_ops->runtime_resume(host);
+
+ return ret;
}
static int mmc_runtime_idle(struct device *dev)
{
- return pm_runtime_suspend(dev);
+ return 0;
}
#endif /* !CONFIG_PM_RUNTIME */
@@ -182,6 +223,7 @@ static struct bus_type mmc_bus_type = {
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
+ .shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index c40396f23202..49a5bca418bd 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -402,6 +402,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
context_info->is_done_rcv = false;
context_info->is_new_req = false;
cmd = mrq->cmd;
+
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) {
err = host->areq->err_check(host->card,
@@ -436,6 +437,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
wait_for_completion(&mrq->completion);
cmd = mrq->cmd;
+
+ /*
+ * If host has timed out waiting for the sanitize
+ * to complete, card might be still in programming state
+ * so let's try to bring the card out of programming
+ * state.
+ */
+ if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
+ if (!mmc_interrupt_hpi(host->card)) {
+ pr_warning("%s: %s: Interrupted sanitize\n",
+ mmc_hostname(host), __func__);
+ cmd->error = 0;
+ break;
+ } else {
+ pr_err("%s: %s: Failed to interrupt sanitize\n",
+ mmc_hostname(host), __func__);
+ }
+ }
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
break;
@@ -952,6 +971,29 @@ void mmc_release_host(struct mmc_host *host)
EXPORT_SYMBOL(mmc_release_host);
/*
+ * This is a helper function, which fetches a runtime pm reference for the
+ * card device and also claims the host.
+ */
+void mmc_get_card(struct mmc_card *card)
+{
+ pm_runtime_get_sync(&card->dev);
+ mmc_claim_host(card->host);
+}
+EXPORT_SYMBOL(mmc_get_card);
+
+/*
+ * This is a helper function, which releases the host and drops the runtime
+ * pm reference for the card device.
+ */
+void mmc_put_card(struct mmc_card *card)
+{
+ mmc_release_host(card->host);
+ pm_runtime_mark_last_busy(&card->dev);
+ pm_runtime_put_autosuspend(&card->dev);
+}
+EXPORT_SYMBOL(mmc_put_card);
+
+/*
* Internal function that does the actual ios call to the host driver,
* optionally printing some debug output.
*/
@@ -1459,7 +1501,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
* If a host does all the power sequencing itself, ignore the
* initial MMC_POWER_UP stage.
*/
-static void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host)
{
int bit;
@@ -2325,14 +2367,13 @@ int mmc_detect_card_removed(struct mmc_host *host)
* The card will be considered unchanged unless we have been asked to
* detect a change or host requires polling to provide card detection.
*/
- if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
- !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+ if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
return ret;
host->detect_change = 0;
if (!ret) {
ret = _mmc_detect_card_removed(host);
- if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+ if (ret && (host->caps & MMC_CAP_NEEDS_POLL)) {
/*
* Schedule a detect work as soon as possible to let a
* rescan handle the card removal.
@@ -2442,9 +2483,7 @@ void mmc_stop_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
/* Calling bus_ops->remove() with a claimed host can deadlock */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
-
+ host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
@@ -2509,52 +2548,6 @@ int mmc_power_restore_host(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_power_restore_host);
-int mmc_card_awake(struct mmc_host *host)
-{
- int err = -ENOSYS;
-
- if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
- return 0;
-
- mmc_bus_get(host);
-
- if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
- err = host->bus_ops->awake(host);
-
- mmc_bus_put(host);
-
- return err;
-}
-EXPORT_SYMBOL(mmc_card_awake);
-
-int mmc_card_sleep(struct mmc_host *host)
-{
- int err = -ENOSYS;
-
- if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
- return 0;
-
- mmc_bus_get(host);
-
- if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
- err = host->bus_ops->sleep(host);
-
- mmc_bus_put(host);
-
- return err;
-}
-EXPORT_SYMBOL(mmc_card_sleep);
-
-int mmc_card_can_sleep(struct mmc_host *host)
-{
- struct mmc_card *card = host->card;
-
- if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
- return 1;
- return 0;
-}
-EXPORT_SYMBOL(mmc_card_can_sleep);
-
/*
* Flush the cache to the non-volatile storage.
*/
@@ -2626,48 +2619,9 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
*/
int mmc_suspend_host(struct mmc_host *host)
{
- int err = 0;
-
- cancel_delayed_work(&host->detect);
- mmc_flush_scheduled_work();
-
- mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead) {
- if (host->bus_ops->suspend) {
- if (mmc_card_doing_bkops(host->card)) {
- err = mmc_stop_bkops(host->card);
- if (err)
- goto out;
- }
- err = host->bus_ops->suspend(host);
- }
-
- if (err == -ENOSYS || !host->bus_ops->resume) {
- /*
- * We simply "remove" the card in this case.
- * It will be redetected on resume. (Calling
- * bus_ops->remove() with a claimed host can
- * deadlock.)
- */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- err = 0;
- }
- }
- mmc_bus_put(host);
-
- if (!err && !mmc_card_keep_power(host))
- mmc_power_off(host);
-
-out:
- return err;
+ /* This function is deprecated */
+ return 0;
}
-
EXPORT_SYMBOL(mmc_suspend_host);
/**
@@ -2676,39 +2630,8 @@ EXPORT_SYMBOL(mmc_suspend_host);
*/
int mmc_resume_host(struct mmc_host *host)
{
- int err = 0;
-
- mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead) {
- if (!mmc_card_keep_power(host)) {
- mmc_power_up(host);
- mmc_select_voltage(host, host->ocr);
- /*
- * Tell runtime PM core we just powered up the card,
- * since it still believes the card is powered off.
- * Note that currently runtime PM is only enabled
- * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
- */
- if (mmc_card_sdio(host->card) &&
- (host->caps & MMC_CAP_POWER_OFF_CARD)) {
- pm_runtime_disable(&host->card->dev);
- pm_runtime_set_active(&host->card->dev);
- pm_runtime_enable(&host->card->dev);
- }
- }
- BUG_ON(!host->bus_ops->resume);
- err = host->bus_ops->resume(host);
- if (err) {
- pr_warning("%s: error %d during resume "
- "(card was removed?)\n",
- mmc_hostname(host), err);
- err = 0;
- }
- }
- host->pm_flags &= ~MMC_PM_KEEP_POWER;
- mmc_bus_put(host);
-
- return err;
+ /* This function is deprecated */
+ return 0;
}
EXPORT_SYMBOL(mmc_resume_host);
@@ -2727,29 +2650,22 @@ int mmc_pm_notify(struct notifier_block *notify_block,
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
- if (host->card && mmc_card_mmc(host->card) &&
- mmc_card_doing_bkops(host->card)) {
- err = mmc_stop_bkops(host->card);
- if (err) {
- pr_err("%s: didn't stop bkops\n",
- mmc_hostname(host));
- return err;
- }
- mmc_card_clr_doing_bkops(host->card);
- }
-
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
cancel_delayed_work_sync(&host->detect);
- if (!host->bus_ops || host->bus_ops->suspend)
+ if (!host->bus_ops)
break;
- /* Calling bus_ops->remove() with a claimed host can deadlock */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
+ /* Validate prerequisites for suspend */
+ if (host->bus_ops->pre_suspend)
+ err = host->bus_ops->pre_suspend(host);
+ if (!err && host->bus_ops->suspend)
+ break;
+ /* Calling bus_ops->remove() with a claimed host can deadlock */
+ host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index b9f18a2a8874..5345d156493e 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -16,15 +16,17 @@
#define MMC_CMD_RETRIES 3
struct mmc_bus_ops {
- int (*awake)(struct mmc_host *);
- int (*sleep)(struct mmc_host *);
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
+ int (*pre_suspend)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
+ int (*runtime_suspend)(struct mmc_host *);
+ int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
+ int (*shutdown)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -44,6 +46,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+void mmc_power_up(struct mmc_host *host);
void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 35c2f85b1956..54829c0ed000 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
u32 status;
int ret;
- mmc_claim_host(card->host);
+ mmc_get_card(card);
ret = mmc_send_status(data, &status);
if (!ret)
*val = status;
- mmc_release_host(card->host);
+ mmc_put_card(card);
return ret;
}
@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
goto out_free;
}
- mmc_claim_host(card->host);
+ mmc_get_card(card);
err = mmc_send_ext_csd(card, ext_csd);
- mmc_release_host(card->host);
+ mmc_put_card(card);
if (err)
goto out_free;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 2a3593d9f87d..6fb6f77450cb 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -306,7 +306,7 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
* parse the properties and set respective generic mmc-host flags and
* parameters.
*/
-void mmc_of_parse(struct mmc_host *host)
+int mmc_of_parse(struct mmc_host *host)
{
struct device_node *np;
u32 bus_width;
@@ -315,7 +315,7 @@ void mmc_of_parse(struct mmc_host *host)
int len, ret, gpio;
if (!host->parent || !host->parent->of_node)
- return;
+ return 0;
np = host->parent->of_node;
@@ -338,6 +338,7 @@ void mmc_of_parse(struct mmc_host *host)
default:
dev_err(host->parent,
"Invalid \"bus-width\" value %ud!\n", bus_width);
+ return -EINVAL;
}
/* f_max is obtained from the optional "max-frequency" property */
@@ -367,18 +368,22 @@ void mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_NEEDS_POLL;
gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
+ if (gpio == -EPROBE_DEFER)
+ return gpio;
if (gpio_is_valid(gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
gpio_inv_cd = true;
ret = mmc_gpio_request_cd(host, gpio);
- if (ret < 0)
+ if (ret < 0) {
dev_err(host->parent,
"Failed to request CD GPIO #%d: %d!\n",
gpio, ret);
- else
+ return ret;
+ } else {
dev_info(host->parent, "Got CD GPIO #%d.\n",
gpio);
+ }
}
if (explicit_inv_cd ^ gpio_inv_cd)
@@ -389,14 +394,23 @@ void mmc_of_parse(struct mmc_host *host)
explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+ if (gpio == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
if (gpio_is_valid(gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
gpio_inv_wp = true;
ret = mmc_gpio_request_ro(host, gpio);
- if (ret < 0)
+ if (ret < 0) {
dev_err(host->parent,
"Failed to request WP GPIO: %d!\n", ret);
+ goto out;
+ } else {
+ dev_info(host->parent, "Got WP GPIO #%d.\n",
+ gpio);
+ }
}
if (explicit_inv_wp ^ gpio_inv_wp)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
@@ -409,10 +423,18 @@ void mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_POWER_OFF_CARD;
if (of_find_property(np, "cap-sdio-irq", &len))
host->caps |= MMC_CAP_SDIO_IRQ;
+ if (of_find_property(np, "full-pwr-cycle", &len))
+ host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
if (of_find_property(np, "keep-power-in-suspend", &len))
host->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", &len))
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
+ return 0;
+
+out:
+ mmc_gpio_free_cd(host);
+ return ret;
}
EXPORT_SYMBOL(mmc_of_parse);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0cbd1effe960..6d02012a1d0b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -293,7 +293,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
- if (card->ext_csd.rev > 6) {
+ if (card->ext_csd.rev > 7) {
pr_err("%s: unrecognised EXT_CSD revision %d\n",
mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
@@ -461,9 +461,31 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
*/
card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
card->ext_csd.boot_ro_lockable = true;
+
+ /* Save power class values */
+ card->ext_csd.raw_pwr_cl_52_195 =
+ ext_csd[EXT_CSD_PWR_CL_52_195];
+ card->ext_csd.raw_pwr_cl_26_195 =
+ ext_csd[EXT_CSD_PWR_CL_26_195];
+ card->ext_csd.raw_pwr_cl_52_360 =
+ ext_csd[EXT_CSD_PWR_CL_52_360];
+ card->ext_csd.raw_pwr_cl_26_360 =
+ ext_csd[EXT_CSD_PWR_CL_26_360];
+ card->ext_csd.raw_pwr_cl_200_195 =
+ ext_csd[EXT_CSD_PWR_CL_200_195];
+ card->ext_csd.raw_pwr_cl_200_360 =
+ ext_csd[EXT_CSD_PWR_CL_200_360];
+ card->ext_csd.raw_pwr_cl_ddr_52_195 =
+ ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
+ card->ext_csd.raw_pwr_cl_ddr_52_360 =
+ ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
}
if (card->ext_csd.rev >= 5) {
+ /* Adjust production date as per JEDEC JESD84-B451 */
+ if (card->cid.year < 2010)
+ card->cid.year += 16;
+
/* check whether the eMMC card supports BKOPS */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
@@ -607,7 +629,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
(card->ext_csd.raw_sectors[2] ==
bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
(card->ext_csd.raw_sectors[3] ==
- bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
+ bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
+ (card->ext_csd.raw_pwr_cl_52_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
+ (card->ext_csd.raw_pwr_cl_26_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
+ (card->ext_csd.raw_pwr_cl_52_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
+ (card->ext_csd.raw_pwr_cl_26_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
+ (card->ext_csd.raw_pwr_cl_200_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
+ (card->ext_csd.raw_pwr_cl_200_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
+ (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
+ (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
+ bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
if (err)
err = -EINVAL;
@@ -676,11 +714,10 @@ static struct device_type mmc_type = {
* mmc_switch command.
*/
static int mmc_select_powerclass(struct mmc_card *card,
- unsigned int bus_width, u8 *ext_csd)
+ unsigned int bus_width)
{
int err = 0;
- unsigned int pwrclass_val;
- unsigned int index = 0;
+ unsigned int pwrclass_val = 0;
struct mmc_host *host;
BUG_ON(!card);
@@ -688,9 +725,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
host = card->host;
BUG_ON(!host);
- if (ext_csd == NULL)
- return 0;
-
/* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
@@ -702,13 +736,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
switch (1 << host->ios.vdd) {
case MMC_VDD_165_195:
if (host->ios.clock <= 26000000)
- index = EXT_CSD_PWR_CL_26_195;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
else if (host->ios.clock <= 52000000)
- index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
- EXT_CSD_PWR_CL_52_195 :
- EXT_CSD_PWR_CL_DDR_52_195;
+ pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ card->ext_csd.raw_pwr_cl_52_195 :
+ card->ext_csd.raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= 200000000)
- index = EXT_CSD_PWR_CL_200_195;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
break;
case MMC_VDD_27_28:
case MMC_VDD_28_29:
@@ -720,13 +754,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
case MMC_VDD_34_35:
case MMC_VDD_35_36:
if (host->ios.clock <= 26000000)
- index = EXT_CSD_PWR_CL_26_360;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
else if (host->ios.clock <= 52000000)
- index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
- EXT_CSD_PWR_CL_52_360 :
- EXT_CSD_PWR_CL_DDR_52_360;
+ pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
+ card->ext_csd.raw_pwr_cl_52_360 :
+ card->ext_csd.raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= 200000000)
- index = EXT_CSD_PWR_CL_200_360;
+ pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
break;
default:
pr_warning("%s: Voltage range not supported "
@@ -734,8 +768,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
return -EINVAL;
}
- pwrclass_val = ext_csd[index];
-
if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
EXT_CSD_PWR_CL_8BIT_SHIFT;
@@ -1013,11 +1045,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
- * If the host supports the power_off_notify capability then
- * set the notification byte in the ext_csd register of device
+ * Enable power_off_notification byte in the ext_csd register
*/
- if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
- (card->ext_csd.rev >= 6)) {
+ if (card->ext_csd.rev >= 6) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
EXT_CSD_POWER_ON,
@@ -1131,7 +1161,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
- err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+ err = mmc_select_powerclass(card, ext_csd_bits);
if (err)
pr_warning("%s: power class selection to bus width %d"
" failed\n", mmc_hostname(card->host),
@@ -1164,8 +1194,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
bus_width = bus_widths[idx];
if (bus_width == MMC_BUS_WIDTH_1)
ddr = 0; /* no DDR for 1-bit width */
- err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
- ext_csd);
+ err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d failed\n",
@@ -1195,8 +1224,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
if (!err && ddr) {
- err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
- ext_csd);
+ err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d ddr %d failed\n",
@@ -1321,6 +1349,45 @@ err:
return err;
}
+static int mmc_can_sleep(struct mmc_card *card)
+{
+ return (card && card->ext_csd.rev >= 3);
+}
+
+static int mmc_sleep(struct mmc_host *host)
+{
+ struct mmc_command cmd = {0};
+ struct mmc_card *card = host->card;
+ int err;
+
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ return 0;
+
+ err = mmc_deselect_cards(host);
+ if (err)
+ return err;
+
+ cmd.opcode = MMC_SLEEP_AWAKE;
+ cmd.arg = card->rca << 16;
+ cmd.arg |= 1 << 15;
+
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ /*
+ * If the host does not wait while the card signals busy, then we will
+ * will have to wait the sleep/awake timeout. Note, we cannot use the
+ * SEND_STATUS command to poll the status because that command (and most
+ * others) is invalid while the card sleeps.
+ */
+ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
+
+ return err;
+}
+
static int mmc_can_poweroff_notify(const struct mmc_card *card)
{
return card &&
@@ -1380,14 +1447,14 @@ static void mmc_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
- mmc_claim_host(host);
+ mmc_get_card(host->card);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
- mmc_release_host(host);
+ mmc_put_card(host->card);
if (err) {
mmc_remove(host);
@@ -1399,36 +1466,60 @@ static void mmc_detect(struct mmc_host *host)
}
}
-/*
- * Suspend callback from host.
- */
-static int mmc_suspend(struct mmc_host *host)
+static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
{
int err = 0;
+ unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
+ EXT_CSD_POWER_OFF_LONG;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
+ if (mmc_card_doing_bkops(host->card)) {
+ err = mmc_stop_bkops(host->card);
+ if (err)
+ goto out;
+ }
+
err = mmc_cache_ctrl(host, 0);
if (err)
goto out;
- if (mmc_can_poweroff_notify(host->card))
- err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
- else if (mmc_card_can_sleep(host))
- err = mmc_card_sleep(host);
+ if (mmc_can_poweroff_notify(host->card) &&
+ ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
+ err = mmc_poweroff_notify(host->card, notify_type);
+ else if (mmc_can_sleep(host->card))
+ err = mmc_sleep(host);
else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+ if (!err)
+ mmc_power_off(host);
out:
mmc_release_host(host);
return err;
}
/*
+ * Suspend callback from host.
+ */
+static int mmc_suspend(struct mmc_host *host)
+{
+ return _mmc_suspend(host, true);
+}
+
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+ return _mmc_suspend(host, false);
+}
+
+/*
* Resume callback from host.
*
* This function tries to determine if the same card is still present
@@ -1442,74 +1533,94 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
}
-static int mmc_power_restore(struct mmc_host *host)
+
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_runtime_suspend(struct mmc_host *host)
{
- int ret;
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
- host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host);
- ret = mmc_init_card(host, host->ocr, host->card);
- mmc_release_host(host);
- return ret;
+ err = mmc_suspend(host);
+ if (err) {
+ pr_err("%s: error %d doing aggessive suspend\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+ mmc_power_off(host);
+
+out:
+ mmc_release_host(host);
+ return err;
}
-static int mmc_sleep(struct mmc_host *host)
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_runtime_resume(struct mmc_host *host)
{
- struct mmc_card *card = host->card;
- int err = -ENOSYS;
+ int err;
- if (card && card->ext_csd.rev >= 3) {
- err = mmc_card_sleepawake(host, 1);
- if (err < 0)
- pr_debug("%s: Error %d while putting card into sleep",
- mmc_hostname(host), err);
- }
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
- return err;
+ mmc_claim_host(host);
+
+ mmc_power_up(host);
+ err = mmc_resume(host);
+ if (err)
+ pr_err("%s: error %d doing aggessive resume\n",
+ mmc_hostname(host), err);
+
+ mmc_release_host(host);
+ return 0;
}
-static int mmc_awake(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
{
- struct mmc_card *card = host->card;
- int err = -ENOSYS;
+ int ret;
- if (card && card->ext_csd.rev >= 3) {
- err = mmc_card_sleepawake(host, 0);
- if (err < 0)
- pr_debug("%s: Error %d while awaking sleeping card",
- mmc_hostname(host), err);
- }
+ host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+ mmc_claim_host(host);
+ ret = mmc_init_card(host, host->ocr, host->card);
+ mmc_release_host(host);
- return err;
+ return ret;
}
static const struct mmc_bus_ops mmc_ops = {
- .awake = mmc_awake,
- .sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
+ .shutdown = mmc_shutdown,
};
static const struct mmc_bus_ops mmc_ops_unsafe = {
- .awake = mmc_awake,
- .sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
+ .runtime_suspend = mmc_runtime_suspend,
+ .runtime_resume = mmc_runtime_resume,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
+ .shutdown = mmc_shutdown,
};
static void mmc_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 49f04bc9d0eb..837fc7386e23 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -59,40 +59,6 @@ int mmc_deselect_cards(struct mmc_host *host)
return _mmc_select_card(host, NULL);
}
-int mmc_card_sleepawake(struct mmc_host *host, int sleep)
-{
- struct mmc_command cmd = {0};
- struct mmc_card *card = host->card;
- int err;
-
- if (sleep)
- mmc_deselect_cards(host);
-
- cmd.opcode = MMC_SLEEP_AWAKE;
- cmd.arg = card->rca << 16;
- if (sleep)
- cmd.arg |= 1 << 15;
-
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
-
- /*
- * If the host does not wait while the card signals busy, then we will
- * will have to wait the sleep/awake timeout. Note, we cannot use the
- * SEND_STATUS command to poll the status because that command (and most
- * others) is invalid while the card sleeps.
- */
- if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
- mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
-
- if (!sleep)
- err = mmc_select_card(card);
-
- return err;
-}
-
int mmc_go_idle(struct mmc_host *host)
{
int err;
@@ -431,6 +397,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
cmd.cmd_timeout_ms = timeout_ms;
+ if (index == EXT_CSD_SANITIZE_START)
+ cmd.sanitize_busy = true;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 3dd8941c2980..80ae9f4e0293 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -24,7 +24,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
-int mmc_card_sleepawake(struct mmc_host *host, int sleep);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 9e645e19cec6..176d125f5b57 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -646,8 +646,13 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
if (err)
goto out;
- /* SPI mode doesn't define CMD19 */
- if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
+ /*
+ * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+ * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+ */
+ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
+ (card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
+ card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);
@@ -1037,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
- mmc_claim_host(host);
+ mmc_get_card(host->card);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
- mmc_release_host(host);
+ mmc_put_card(host->card);
if (err) {
mmc_sd_remove(host);
@@ -1070,6 +1075,8 @@ static int mmc_sd_suspend(struct mmc_host *host)
if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
+ if (!err)
+ mmc_power_off(host);
mmc_release_host(host);
return err;
@@ -1089,12 +1096,61 @@ static int mmc_sd_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
err = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
}
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_sd_runtime_suspend(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ mmc_claim_host(host);
+
+ err = mmc_sd_suspend(host);
+ if (err) {
+ pr_err("%s: error %d doing aggessive suspend\n",
+ mmc_hostname(host), err);
+ goto out;
+ }
+ mmc_power_off(host);
+
+out:
+ mmc_release_host(host);
+ return err;
+}
+
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_sd_runtime_resume(struct mmc_host *host)
+{
+ int err;
+
+ if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+ return 0;
+
+ mmc_claim_host(host);
+
+ mmc_power_up(host);
+ err = mmc_sd_resume(host);
+ if (err)
+ pr_err("%s: error %d doing aggessive resume\n",
+ mmc_hostname(host), err);
+
+ mmc_release_host(host);
+ return 0;
+}
+
static int mmc_sd_power_restore(struct mmc_host *host)
{
int ret;
@@ -1114,15 +1170,19 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.resume = NULL,
.power_restore = mmc_sd_power_restore,
.alive = mmc_sd_alive,
+ .shutdown = mmc_sd_suspend,
};
static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
+ .runtime_suspend = mmc_sd_runtime_suspend,
+ .runtime_resume = mmc_sd_runtime_resume,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
.power_restore = mmc_sd_power_restore,
.alive = mmc_sd_alive,
+ .shutdown = mmc_sd_suspend,
};
static void mmc_sd_attach_bus_ops(struct mmc_host *host)
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 6889a821c1da..80d89cff7306 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -563,10 +563,18 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
if (err)
goto out;
- /* Initialize and start re-tuning timer */
- if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+ /*
+ * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+ * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+ */
+ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
+ ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) {
+ mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);
+ mmc_host_clk_release(card->host);
+ }
out:
@@ -902,11 +910,11 @@ out:
}
/*
- * SDIO suspend. We need to suspend all functions separately.
+ * SDIO pre_suspend. We need to suspend all functions separately.
* Therefore all registered functions must have drivers with suspend
* and resume methods. Failing that we simply remove the whole card.
*/
-static int mmc_sdio_suspend(struct mmc_host *host)
+static int mmc_sdio_pre_suspend(struct mmc_host *host)
{
int i, err = 0;
@@ -917,8 +925,26 @@ static int mmc_sdio_suspend(struct mmc_host *host)
if (!pmops || !pmops->suspend || !pmops->resume) {
/* force removal of entire card in that case */
err = -ENOSYS;
- } else
- err = pmops->suspend(&func->dev);
+ break;
+ }
+ }
+ }
+
+ return err;
+}
+
+/*
+ * SDIO suspend. Suspend all functions separately.
+ */
+static int mmc_sdio_suspend(struct mmc_host *host)
+{
+ int i, err = 0;
+
+ for (i = 0; i < host->card->sdio_funcs; i++) {
+ struct sdio_func *func = host->card->sdio_func[i];
+ if (func && sdio_func_present(func) && func->dev.driver) {
+ const struct dev_pm_ops *pmops = func->dev.driver->pm;
+ err = pmops->suspend(&func->dev);
if (err)
break;
}
@@ -937,6 +963,9 @@ static int mmc_sdio_suspend(struct mmc_host *host)
mmc_release_host(host);
}
+ if (!err && !mmc_card_keep_power(host))
+ mmc_power_off(host);
+
return err;
}
@@ -950,6 +979,23 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
+ /* Restore power if needed */
+ if (!mmc_card_keep_power(host)) {
+ mmc_power_up(host);
+ mmc_select_voltage(host, host->ocr);
+ /*
+ * Tell runtime PM core we just powered up the card,
+ * since it still believes the card is powered off.
+ * Note that currently runtime PM is only enabled
+ * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
+ */
+ if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+ pm_runtime_disable(&host->card->dev);
+ pm_runtime_set_active(&host->card->dev);
+ pm_runtime_enable(&host->card->dev);
+ }
+ }
+
/* No need to reinitialize powered-resumed nonremovable cards */
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
sdio_reset(host);
@@ -987,6 +1033,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
}
}
+ host->pm_flags &= ~MMC_PM_KEEP_POWER;
return err;
}
@@ -1051,11 +1098,28 @@ out:
return ret;
}
+static int mmc_sdio_runtime_suspend(struct mmc_host *host)
+{
+ /* No references to the card, cut the power to it. */
+ mmc_power_off(host);
+ return 0;
+}
+
+static int mmc_sdio_runtime_resume(struct mmc_host *host)
+{
+ /* Restore power and re-initialize. */
+ mmc_power_up(host);
+ return mmc_sdio_power_restore(host);
+}
+
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
+ .pre_suspend = mmc_sdio_pre_suspend,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
+ .runtime_suspend = mmc_sdio_runtime_suspend,
+ .runtime_resume = mmc_sdio_runtime_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
};
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 546c67c2bbbf..6d67492a9247 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -211,7 +211,7 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
- pm_generic_runtime_idle
+ NULL
)
};
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9ab8f8dee942..8a4c066787d7 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -249,6 +249,17 @@ config MMC_SDHCI_S3C_DMA
YMMV.
+config MMC_SDHCI_BCM_KONA
+ tristate "SDHCI support on Broadcom KONA platform"
+ depends on ARCH_BCM
+ select MMC_SDHCI_PLTFM
+ help
+ This selects the Broadcom Kona Secure Digital Host Controller
+ Interface(SDHCI) support.
+ This is used in Broadcom mobile SoCs.
+
+ If you have a controller with this interface, say Y or M here.
+
config MMC_SDHCI_BCM2835
tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
depends on ARCH_BCM2835
@@ -556,6 +567,14 @@ config MMC_DW_EXYNOS
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on Exynos4 and Exynos5 SoC's.
+config MMC_DW_SOCFPGA
+ tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
+ depends on MMC_DW
+ select MMC_DW_PLTFM
+ help
+ This selects support for Altera SoCFPGA specific extensions to the
+ Synopsys DesignWare Memory Card Interface driver.
+
config MMC_DW_PCI
tristate "Synopsys Designware MCI support on PCI bus"
depends on MMC_DW && PCI
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index cd3228075553..d422e2167e19 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
+obj-$(CONFIG_MMC_DW_SOCFPGA) += dw_mmc-socfpga.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
@@ -60,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
ifeq ($(CONFIG_CB710_DEBUG),y)
diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c
index 7780c14704c4..8b4e20a3f16c 100644
--- a/drivers/mmc/host/android-goldfish.c
+++ b/drivers/mmc/host/android-goldfish.c
@@ -546,8 +546,6 @@ static int goldfish_mmc_remove(struct platform_device *pdev)
{
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
-
BUG_ON(host == NULL);
mmc_remove_host(host->mmc);
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index aca59d93d5a9..bdb84da74952 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -40,8 +40,6 @@
#include <asm/io.h>
#include <asm/unaligned.h>
-#include <mach/cpu.h>
-
#include "atmel-mci-regs.h"
#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
@@ -2475,8 +2473,6 @@ static int __exit atmci_remove(struct platform_device *pdev)
struct atmel_mci *host = platform_get_drvdata(pdev);
unsigned int i;
- platform_set_drvdata(pdev, NULL);
-
if (host->buffer)
dma_free_coherent(&pdev->dev, host->buf_size,
host->buffer, host->buf_phys_addr);
@@ -2504,7 +2500,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int atmci_suspend(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
@@ -2559,17 +2555,15 @@ static int atmci_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
-#define ATMCI_PM_OPS (&atmci_pm)
-#else
-#define ATMCI_PM_OPS NULL
#endif
+static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
+
static struct platform_driver atmci_driver = {
.remove = __exit_p(atmci_remove),
.driver = {
.name = "atmel_mci",
- .pm = ATMCI_PM_OPS,
+ .pm = &atmci_pm,
.of_match_table = of_match_ptr(atmci_dt_ids),
},
};
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 127a8fade4da..df9becdd2e99